dahdi-linux-2.5.0.1/0000755000175000017500000000000011631523354014012 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/include/0000755000175000017500000000000011631523354015435 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/include/dahdi/0000755000175000017500000000000011631523354016506 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/include/dahdi/user.h0000644000175000017500000011320411602642630017633 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface * * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001 - 2008 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU Lesser General Public License Version 2.1 as published * by the Free Software Foundation. See the LICENSE.LGPL file * included with this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _DAHDI_USER_H #define _DAHDI_USER_H #include #include #include #ifndef ELAST #define ELAST 500 #endif /* Per-span configuration values */ #define DAHDI_CONFIG_TXLEVEL 7 /* bits 0-2 are tx level */ /* Line configuration */ /* These apply to T1 */ #define DAHDI_CONFIG_D4 (1 << 4) #define DAHDI_CONFIG_ESF (1 << 5) #define DAHDI_CONFIG_AMI (1 << 6) #define DAHDI_CONFIG_B8ZS (1 << 7) /* These apply to E1 */ #define DAHDI_CONFIG_CCS (1 << 8) /* CCS (ISDN) instead of CAS (Robbed Bit) */ #define DAHDI_CONFIG_HDB3 (1 << 9) /* HDB3 instead of AMI (line coding) */ #define DAHDI_CONFIG_CRC4 (1 << 10) /* CRC4 framing */ #define DAHDI_CONFIG_NOTOPEN (1 << 16) /* These apply to BRI */ #define DAHDI_CONFIG_NTTE (1 << 11) /* To enable NT mode, set this bit to 1, for TE this should be 0 */ #define DAHDI_CONFIG_TERM (1 << 12) /* To enable Termination resistance set this bit to 1 */ /* Signalling types */ #define DAHDI_SIG_BROKEN (1 << 31) /* The port is broken and/or failed initialization */ #define __DAHDI_SIG_FXO (1 << 12) /* Never use directly */ #define __DAHDI_SIG_FXS (1 << 13) /* Never use directly */ #define DAHDI_SIG_NONE (0) /* Channel not configured */ #define DAHDI_SIG_FXSLS ((1 << 0) | __DAHDI_SIG_FXS) /* FXS, Loopstart */ #define DAHDI_SIG_FXSGS ((1 << 1) | __DAHDI_SIG_FXS) /* FXS, Groundstart */ #define DAHDI_SIG_FXSKS ((1 << 2) | __DAHDI_SIG_FXS) /* FXS, Kewlstart */ #define DAHDI_SIG_FXOLS ((1 << 3) | __DAHDI_SIG_FXO) /* FXO, Loopstart */ #define DAHDI_SIG_FXOGS ((1 << 4) | __DAHDI_SIG_FXO) /* FXO, Groupstart */ #define DAHDI_SIG_FXOKS ((1 << 5) | __DAHDI_SIG_FXO) /* FXO, Kewlstart */ #define DAHDI_SIG_EM (1 << 6) /* Ear & Mouth (E&M) */ /* The following are all variations on clear channel */ #define __DAHDI_SIG_DACS (1 << 16) #define DAHDI_SIG_CLEAR (1 << 7) /* Clear channel */ #define DAHDI_SIG_HDLCRAW ((1 << 8) | DAHDI_SIG_CLEAR) /* Raw unchecked HDLC */ #define DAHDI_SIG_HDLCFCS ((1 << 9) | DAHDI_SIG_HDLCRAW) /* HDLC with FCS calculation */ #define DAHDI_SIG_HDLCNET ((1 << 10) | DAHDI_SIG_HDLCFCS) /* HDLC Network */ #define DAHDI_SIG_SLAVE (1 << 11) /* Slave to another channel */ #define DAHDI_SIG_SF (1 << 14) /* Single Freq. tone only, no sig bits */ #define DAHDI_SIG_CAS (1 << 15) /* Just get bits */ #define DAHDI_SIG_DACS (__DAHDI_SIG_DACS | DAHDI_SIG_CLEAR) /* Cross connect */ #define DAHDI_SIG_EM_E1 (1 << 17) /* E1 E&M Variation */ #define DAHDI_SIG_DACS_RBS ((1 << 18) | __DAHDI_SIG_DACS) /* Cross connect w/ RBS */ #define DAHDI_SIG_HARDHDLC ((1 << 19) | DAHDI_SIG_CLEAR) #define DAHDI_SIG_MTP2 ((1 << 20) | DAHDI_SIG_HDLCFCS) /* MTP2 support Need HDLC bitstuff and FCS calcuation too */ /* tone flag values */ #define DAHDI_REVERSE_RXTONE 1 /* reverse polarity rx tone logic */ #define DAHDI_REVERSE_TXTONE 2 /* reverse polarity tx tone logic */ #define DAHDI_ABIT (1 << 3) #define DAHDI_BBIT (1 << 2) #define DAHDI_CBIT (1 << 1) #define DAHDI_DBIT (1 << 0) #define DAHDI_BITS_ABCD (DAHDI_ABIT | DAHDI_BBIT | DAHDI_CBIT | DAHDI_DBIT) #define DAHDI_BITS_ABD (DAHDI_ABIT | DAHDI_BBIT | DAHDI_DBIT) #define DAHDI_BITS_ACD (DAHDI_ABIT | DAHDI_CBIT | DAHDI_DBIT) #define DAHDI_BITS_BCD (DAHDI_BBIT | DAHDI_CBIT | DAHDI_DBIT) #define DAHDI_BITS_AC (DAHDI_ABIT | DAHDI_CBIT) #define DAHDI_BITS_BD (DAHDI_BBIT | DAHDI_DBIT) #define DAHDI_MAJOR 196 #define DAHDI_MAX_BLOCKSIZE 8192 #define DAHDI_DEFAULT_NUM_BUFS 2 #define DAHDI_MAX_NUM_BUFS 32 #define DAHDI_MAX_BUF_SPACE 32768 #define DAHDI_DEFAULT_BLOCKSIZE 1024 #define DAHDI_DEFAULT_MTR_MRU 2048 /*! Define the default network block size */ #define DAHDI_DEFAULT_MTU_MRU 2048 #define DAHDI_POLICY_IMMEDIATE 0 /* Start play/record immediately */ #define DAHDI_POLICY_WHEN_FULL 1 /* Start play/record when buffer is full */ #define DAHDI_POLICY_HALF_FULL 2 /* Start play/record when buffer is half full. Note -- This policy only works on tx buffers */ #define DAHDI_GET_PARAMS_RETURN_MASTER 0x40000000 #define DAHDI_TONE_ZONE_MAX 128 #define DAHDI_TONE_ZONE_DEFAULT -1 /* To restore default */ #define DAHDI_TONE_STOP -1 #define DAHDI_TONE_DIALTONE 0 #define DAHDI_TONE_BUSY 1 #define DAHDI_TONE_RINGTONE 2 #define DAHDI_TONE_CONGESTION 3 #define DAHDI_TONE_CALLWAIT 4 #define DAHDI_TONE_DIALRECALL 5 #define DAHDI_TONE_RECORDTONE 6 #define DAHDI_TONE_INFO 7 #define DAHDI_TONE_CUST1 8 #define DAHDI_TONE_CUST2 9 #define DAHDI_TONE_STUTTER 10 #define DAHDI_TONE_MAX 16 #define DAHDI_TONE_DTMF_BASE 64 #define DAHDI_TONE_MFR1_BASE 80 #define DAHDI_TONE_MFR2_FWD_BASE 96 #define DAHDI_TONE_MFR2_REV_BASE 112 enum { DAHDI_TONE_DTMF_0 = DAHDI_TONE_DTMF_BASE, DAHDI_TONE_DTMF_1, DAHDI_TONE_DTMF_2, DAHDI_TONE_DTMF_3, DAHDI_TONE_DTMF_4, DAHDI_TONE_DTMF_5, DAHDI_TONE_DTMF_6, DAHDI_TONE_DTMF_7, DAHDI_TONE_DTMF_8, DAHDI_TONE_DTMF_9, DAHDI_TONE_DTMF_s, DAHDI_TONE_DTMF_p, DAHDI_TONE_DTMF_A, DAHDI_TONE_DTMF_B, DAHDI_TONE_DTMF_C, DAHDI_TONE_DTMF_D }; #define DAHDI_TONE_DTMF_MAX DAHDI_TONE_DTMF_D enum { DAHDI_TONE_MFR1_0 = DAHDI_TONE_MFR1_BASE, DAHDI_TONE_MFR1_1, DAHDI_TONE_MFR1_2, DAHDI_TONE_MFR1_3, DAHDI_TONE_MFR1_4, DAHDI_TONE_MFR1_5, DAHDI_TONE_MFR1_6, DAHDI_TONE_MFR1_7, DAHDI_TONE_MFR1_8, DAHDI_TONE_MFR1_9, DAHDI_TONE_MFR1_KP, DAHDI_TONE_MFR1_ST, DAHDI_TONE_MFR1_STP, DAHDI_TONE_MFR1_ST2P, DAHDI_TONE_MFR1_ST3P, }; #define DAHDI_TONE_MFR1_MAX DAHDI_TONE_MFR1_ST3P enum { DAHDI_TONE_MFR2_FWD_1 = DAHDI_TONE_MFR2_FWD_BASE, DAHDI_TONE_MFR2_FWD_2, DAHDI_TONE_MFR2_FWD_3, DAHDI_TONE_MFR2_FWD_4, DAHDI_TONE_MFR2_FWD_5, DAHDI_TONE_MFR2_FWD_6, DAHDI_TONE_MFR2_FWD_7, DAHDI_TONE_MFR2_FWD_8, DAHDI_TONE_MFR2_FWD_9, DAHDI_TONE_MFR2_FWD_10, DAHDI_TONE_MFR2_FWD_11, DAHDI_TONE_MFR2_FWD_12, DAHDI_TONE_MFR2_FWD_13, DAHDI_TONE_MFR2_FWD_14, DAHDI_TONE_MFR2_FWD_15, }; #define DAHDI_TONE_MFR2_FWD_MAX DAHDI_TONE_MFR2_FWD_15 enum { DAHDI_TONE_MFR2_REV_1 = DAHDI_TONE_MFR2_REV_BASE, DAHDI_TONE_MFR2_REV_2, DAHDI_TONE_MFR2_REV_3, DAHDI_TONE_MFR2_REV_4, DAHDI_TONE_MFR2_REV_5, DAHDI_TONE_MFR2_REV_6, DAHDI_TONE_MFR2_REV_7, DAHDI_TONE_MFR2_REV_8, DAHDI_TONE_MFR2_REV_9, DAHDI_TONE_MFR2_REV_10, DAHDI_TONE_MFR2_REV_11, DAHDI_TONE_MFR2_REV_12, DAHDI_TONE_MFR2_REV_13, DAHDI_TONE_MFR2_REV_14, DAHDI_TONE_MFR2_REV_15, }; #define DAHDI_TONE_MFR2_REV_MAX DAHDI_TONE_MFR2_REV_15 #define DAHDI_LAW_DEFAULT 0 /* Default law for span */ #define DAHDI_LAW_MULAW 1 /* Mu-law */ #define DAHDI_LAW_ALAW 2 /* A-law */ #define DAHDI_DIAL_OP_APPEND 1 #define DAHDI_DIAL_OP_REPLACE 2 #define DAHDI_DIAL_OP_CANCEL 3 #define DAHDI_MAX_CADENCE 16 #define DAHDI_TONEDETECT_ON (1 << 0) /* Detect tones */ #define DAHDI_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */ /* Define the max # of outgoing DTMF, MFR1 or MFR2 digits to queue */ #define DAHDI_MAX_DTMF_BUF 256 #define DAHDI_MAX_EVENTSIZE 64 /* 64 events max in buffer */ /* Value for DAHDI_HOOK, set to ON hook */ #define DAHDI_ONHOOK 0 /* Value for DAHDI_HOOK, set to OFF hook */ #define DAHDI_OFFHOOK 1 /* Value for DAHDI_HOOK, wink (off hook momentarily) */ #define DAHDI_WINK 2 /* Value for DAHDI_HOOK, flash (on hook momentarily) */ #define DAHDI_FLASH 3 /* Value for DAHDI_HOOK, start line */ #define DAHDI_START 4 /* Value for DAHDI_HOOK, ring line (same as start line) */ #define DAHDI_RING 5 /* Value for DAHDI_HOOK, turn ringer off */ #define DAHDI_RINGOFF 6 /* Flush and stop the read (input) process */ #define DAHDI_FLUSH_READ 1 /* Flush and stop the write (output) process */ #define DAHDI_FLUSH_WRITE 2 /* Flush and stop both (input and output) processes */ #define DAHDI_FLUSH_BOTH (DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE) /* Flush the event queue */ #define DAHDI_FLUSH_EVENT 4 /* Flush everything */ #define DAHDI_FLUSH_ALL (DAHDI_FLUSH_BOTH | DAHDI_FLUSH_EVENT) #define DAHDI_MAX_SPANS 128 /* Max, 128 spans */ #define DAHDI_MAX_CHANNELS 1024 /* Max, 1024 channels */ #define DAHDI_MAX_CONF 1024 /* Max, 1024 conferences */ /* Conference modes */ #define DAHDI_CONF_MODE_MASK 0xFF /* mask for modes */ #define DAHDI_CONF_NORMAL 0 /* normal mode */ #define DAHDI_CONF_MONITOR 1 /* monitor mode (rx of other chan) */ #define DAHDI_CONF_MONITORTX 2 /* monitor mode (tx of other chan) */ #define DAHDI_CONF_MONITORBOTH 3 /* monitor mode (rx & tx of other chan) */ #define DAHDI_CONF_CONF 4 /* conference mode */ #define DAHDI_CONF_CONFANN 5 /* conference announce mode */ #define DAHDI_CONF_CONFMON 6 /* conference monitor mode */ #define DAHDI_CONF_CONFANNMON 7 /* conference announce/monitor mode */ #define DAHDI_CONF_REALANDPSEUDO 8 /* real and pseudo port both on conf */ #define DAHDI_CONF_DIGITALMON 9 /* Do not decode or interpret */ #define DAHDI_CONF_MONITOR_RX_PREECHO 10 /* monitor mode (rx of other chan) - before echo can is done */ #define DAHDI_CONF_MONITOR_TX_PREECHO 11 /* monitor mode (tx of other chan) - before echo can is done */ #define DAHDI_CONF_MONITORBOTH_PREECHO 12 /* monitor mode (rx & tx of other chan) - before echo can is done */ #define DAHDI_CONF_FLAG_MASK 0xFF00 /* mask for flags */ #define DAHDI_CONF_LISTENER 0x100 /* is a listener on the conference */ #define DAHDI_CONF_TALKER 0x200 /* is a talker on the conference */ #define DAHDI_CONF_PSEUDO_LISTENER 0x400 /* pseudo is a listener on the conference */ #define DAHDI_CONF_PSEUDO_TALKER 0x800 /* pseudo is a talker on the conference */ /* Alarm Condition bits */ #define DAHDI_ALARM_NONE 0 /* No alarms */ #define DAHDI_ALARM_RECOVER (1 << 0) /* Recovering from alarm */ #define DAHDI_ALARM_LOOPBACK (1 << 1) /* In loopback */ #define DAHDI_ALARM_YELLOW (1 << 2) /* Yellow Alarm */ #define DAHDI_ALARM_RED (1 << 3) /* Red Alarm */ #define DAHDI_ALARM_BLUE (1 << 4) /* Blue Alarm */ #define DAHDI_ALARM_NOTOPEN (1 << 5) /* Verbose alarm states (upper byte) */ #define DAHDI_ALARM_LOS (1 << 8) /* Loss of Signal */ #define DAHDI_ALARM_LFA (1 << 9) /* Loss of Frame Alignment */ #define DAHDI_ALARM_LMFA (1 << 10)/* Loss of Multi-Frame Align */ /* Maintenance modes */ #define DAHDI_MAINT_NONE 0 /* Normal Mode */ #define DAHDI_MAINT_LOCALLOOP 1 /* Local Loopback */ #define DAHDI_MAINT_REMOTELOOP 2 /* Remote Loopback */ #define DAHDI_MAINT_NETWORKLINELOOP 2 /* Remote Loopback */ #define DAHDI_MAINT_LOOPUP 3 /* send loopup code */ #define DAHDI_MAINT_LOOPDOWN 4 /* send loopdown code */ #define DAHDI_MAINT_FAS_DEFECT 6 /* insert a FAS defect */ #define DAHDI_MAINT_MULTI_DEFECT 7 /* insert a Multiframe defect */ #define DAHDI_MAINT_CRC_DEFECT 8 /* insert a FAS defect */ #define DAHDI_MAINT_CAS_DEFECT 9 /* insert a FAS defect */ #define DAHDI_MAINT_PRBS_DEFECT 10 /* insert a FAS defect */ #define DAHDI_MAINT_BIPOLAR_DEFECT 11 /* insert a FAS defect */ #define DAHDI_MAINT_PRBS 12 /* enable the PRBS gen/mon */ #define DAHDI_MAINT_NETWORKPAYLOADLOOP 13 /* Remote Loopback */ #define DAHDI_RESET_COUNTERS 14 /* Clear the error counters */ #define DAHDI_MAINT_ALARM_SIM 15 /* Simulate alarms */ /* Flag Value for IOMUX, read avail */ #define DAHDI_IOMUX_READ 1 /* Flag Value for IOMUX, write avail */ #define DAHDI_IOMUX_WRITE 2 /* Flag Value for IOMUX, write done */ #define DAHDI_IOMUX_WRITEEMPTY 4 /* Flag Value for IOMUX, signalling event avail */ #define DAHDI_IOMUX_SIGEVENT 8 /* Flag Value for IOMUX, Do Not Wait if nothing to report */ #define DAHDI_IOMUX_NOWAIT 0x100 /* Ret. Value for GET/WAIT Event, no event */ #define DAHDI_EVENT_NONE 0 /* Ret. Value for GET/WAIT Event, Went Onhook */ #define DAHDI_EVENT_ONHOOK 1 /* Ret. Value for GET/WAIT Event, Went Offhook or got Ring */ #define DAHDI_EVENT_RINGOFFHOOK 2 /* Ret. Value for GET/WAIT Event, Got Wink or Flash */ #define DAHDI_EVENT_WINKFLASH 3 /* Ret. Value for GET/WAIT Event, Got Alarm */ #define DAHDI_EVENT_ALARM 4 /* Ret. Value for GET/WAIT Event, Got No Alarm (after alarm) */ #define DAHDI_EVENT_NOALARM 5 /* Ret. Value for GET/WAIT Event, HDLC Abort frame */ #define DAHDI_EVENT_ABORT 6 /* Ret. Value for GET/WAIT Event, HDLC Frame overrun */ #define DAHDI_EVENT_OVERRUN 7 /* Ret. Value for GET/WAIT Event, Bad FCS */ #define DAHDI_EVENT_BADFCS 8 /* Ret. Value for dial complete */ #define DAHDI_EVENT_DIALCOMPLETE 9 /* Ret Value for ringer going on */ #define DAHDI_EVENT_RINGERON 10 /* Ret Value for ringer going off */ #define DAHDI_EVENT_RINGEROFF 11 /* Ret Value for hook change complete */ #define DAHDI_EVENT_HOOKCOMPLETE 12 /* Ret Value for bits changing on a CAS / User channel */ #define DAHDI_EVENT_BITSCHANGED 13 /* Ret value for the beginning of a pulse coming on its way */ #define DAHDI_EVENT_PULSE_START 14 /* Timer event -- timer expired */ #define DAHDI_EVENT_TIMER_EXPIRED 15 /* Timer event -- ping ready */ #define DAHDI_EVENT_TIMER_PING 16 /* Polarity reversal event */ #define DAHDI_EVENT_POLARITY 17 /* Ring Begin event */ #define DAHDI_EVENT_RINGBEGIN 18 /* Echo can disabled event */ #define DAHDI_EVENT_EC_DISABLED 19 /* Channel was disconnected. Hint user to close channel */ #define DAHDI_EVENT_REMOVED 20 /* A neon MWI pulse was detected */ #define DAHDI_EVENT_NEONMWI_ACTIVE 21 /* No neon MWI pulses were detected over some period of time */ #define DAHDI_EVENT_NEONMWI_INACTIVE 22 /* A CED tone was detected on the channel in the transmit direction */ #define DAHDI_EVENT_TX_CED_DETECTED 23 /* A CED tone was detected on the channel in the receive direction */ #define DAHDI_EVENT_RX_CED_DETECTED 24 /* A CNG tone was detected on the channel in the transmit direction */ #define DAHDI_EVENT_TX_CNG_DETECTED 25 /* A CNG tone was detected on the channel in the receive direction */ #define DAHDI_EVENT_RX_CNG_DETECTED 26 /* The echo canceler's NLP (only) was disabled */ #define DAHDI_EVENT_EC_NLP_DISABLED 27 /* The echo canceler's NLP (only) was enabled */ #define DAHDI_EVENT_EC_NLP_ENABLED 28 /* The channel's read buffer encountered an overrun condition */ #define DAHDI_EVENT_READ_OVERRUN 29 /* The channel's write buffer encountered an underrun condition */ #define DAHDI_EVENT_WRITE_UNDERRUN 30 #define DAHDI_EVENT_PULSEDIGIT (1 << 16) /* This is OR'd with the digit received */ #define DAHDI_EVENT_DTMFDOWN (1 << 17) /* Ditto for DTMF key down event */ #define DAHDI_EVENT_DTMFUP (1 << 18) /* Ditto for DTMF key up event */ /* Transcoder related definitions */ struct dahdi_transcoder_formats { __u32 srcfmt; __u32 dstfmt; }; struct dahdi_transcoder_info { __u32 tcnum; char name[80]; __u32 numchannels; __u32 dstfmts; __u32 srcfmts; }; #define DAHDI_MAX_ECHOCANPARAMS 8 /* ioctl definitions */ #define DAHDI_CODE 0xDA /* * Get/Set Transfer Block Size. */ #define DAHDI_GET_BLOCKSIZE _IOR(DAHDI_CODE, 1, int) #define DAHDI_SET_BLOCKSIZE _IOW(DAHDI_CODE, 1, int) /* * Flush Buffer(s) and stop I/O */ #define DAHDI_FLUSH _IOW(DAHDI_CODE, 3, int) /* * Wait for Write to Finish */ #define DAHDI_SYNC _IO(DAHDI_CODE, 4) /* * Get/set channel parameters */ struct dahdi_params { int channo; /* Channel number */ int spanno; /* Span itself */ int chanpos; /* Channel number in span */ int sigtype; /* read-only */ int sigcap; /* read-only */ int rxisoffhook; /* read-only */ int rxbits; /* read-only */ int txbits; /* read-only */ int txhooksig; /* read-only */ int rxhooksig; /* read-only */ int curlaw; /* read-only -- one of DAHDI_LAW_MULAW or DAHDI_LAW_ALAW */ int idlebits; /* read-only -- What is considered the idle state */ char name[40]; /* Name of channel */ int prewinktime; int preflashtime; int winktime; int flashtime; int starttime; int rxwinktime; int rxflashtime; int debouncetime; int pulsebreaktime; int pulsemaketime; int pulseaftertime; __u32 chan_alarms; /* alarms on this channel */ }; #define DAHDI_GET_PARAMS_V1 _IOR(DAHDI_CODE, 5, struct dahdi_params) #define DAHDI_GET_PARAMS _IOWR(DAHDI_CODE, 5, struct dahdi_params) #define DAHDI_SET_PARAMS _IOW(DAHDI_CODE, 5, struct dahdi_params) /* * Set Hookswitch Status */ #define DAHDI_HOOK _IOW(DAHDI_CODE, 7, int) /* * Get Signalling Event */ #define DAHDI_GETEVENT _IOR(DAHDI_CODE, 8, int) /* * Wait for something to happen (IO Mux) */ #define DAHDI_IOMUX _IOWR(DAHDI_CODE, 9, int) /* * Get Span Status */ struct dahdi_spaninfo { int spanno; /* span number */ char name[20]; /* Name */ char desc[40]; /* Description */ int alarms; /* alarms status */ int txlevel; /* what TX level is set to */ int rxlevel; /* current RX level */ int bpvcount; /* current BPV count */ int crc4count; /* current CRC4 error count */ int ebitcount; /* current E-bit error count */ int fascount; /* current FAS error count */ __u32 fecount; /* Framing error counter */ __u32 cvcount; /* Coding violations counter */ __u32 becount; /* current bit error count */ __u32 prbs; /* current PRBS detected pattern */ __u32 errsec; /* errored seconds */ int irqmisses; /* current IRQ misses */ int syncsrc; /* span # of current sync source, or 0 for free run */ int numchans; /* number of configured channels on this span */ int totalchans; /* total number of channels on the span */ int totalspans; /* total number of spans in entire system */ int lbo; /* line build out */ int lineconfig; /* framing/coding */ char lboname[40]; /* line build out in text form */ char location[40]; /* span's device location in system */ char manufacturer[40]; /* manufacturer of span's device */ char devicetype[40]; /* span's device type */ int irq; /* span's device IRQ */ int linecompat; /* span global signaling or 0 for analog spans.*/ char spantype[6]; /* type of span in text form */ } __attribute__((packed)); struct dahdi_spaninfo_v1 { int spanno; /* span number */ char name[20]; /* Name */ char desc[40]; /* Description */ int alarms; /* alarms status */ int txlevel; /* what TX level is set to */ int rxlevel; /* current RX level */ int bpvcount; /* current BPV count */ int crc4count; /* current CRC4 error count */ int ebitcount; /* current E-bit error count */ int fascount; /* current FAS error count */ int irqmisses; /* current IRQ misses */ int syncsrc; /* span # of current sync source, or 0 for free run */ int numchans; /* number of configured channels on this span */ int totalchans; /* total number of channels on the span */ int totalspans; /* total number of spans in entire system */ int lbo; /* line build out */ int lineconfig; /* framing/coding */ char lboname[40]; /* line build out in text form */ char location[40]; /* span's device location in system */ char manufacturer[40]; /* manufacturer of span's device */ char devicetype[40]; /* span's device type */ int irq; /* span's device IRQ */ int linecompat; /* signaling modes possible on this span */ char spantype[6]; /* type of span in text form */ }; #define DAHDI_SPANSTAT _IOWR(DAHDI_CODE, 10, struct dahdi_spaninfo) #define DAHDI_SPANSTAT_V1 _IOWR(DAHDI_CODE, 10, struct dahdi_spaninfo_v1) /* * Set Maintenance Mode */ struct dahdi_maintinfo { int spanno; /* span number */ int command; /* command */ }; #define DAHDI_MAINT _IOW(DAHDI_CODE, 11, struct dahdi_maintinfo) /* * Get/Set Conference Mode */ struct dahdi_confinfo { int chan; /* channel number, 0 for current */ int confno; /* conference number */ int confmode; /* conferencing mode */ }; #define DAHDI_GETCONF_V1 _IOR(DAHDI_CODE, 12, struct dahdi_confinfo) #define DAHDI_GETCONF _IOWR(DAHDI_CODE, 12, struct dahdi_confinfo) #define DAHDI_SETCONF_V1 _IOW(DAHDI_CODE, 12, struct dahdi_confinfo) #define DAHDI_SETCONF _IOWR(DAHDI_CODE, 13, struct dahdi_confinfo) /* * Display Conference Diagnostic Information on Console */ #define DAHDI_CONFDIAG_V1 _IOR(DAHDI_CODE, 15, int) #define DAHDI_CONFDIAG _IOW(DAHDI_CODE, 15, int) /* * Get/Set Channel audio gains */ struct dahdi_gains { int chan; /* channel number, 0 for current */ unsigned char rxgain[256]; /* Receive gain table */ unsigned char txgain[256]; /* Transmit gain table */ }; #define DAHDI_GETGAINS_V1 _IOR(DAHDI_CODE, 16, struct dahdi_gains) #define DAHDI_GETGAINS _IOWR(DAHDI_CODE, 16, struct dahdi_gains) #define DAHDI_SETGAINS _IOW(DAHDI_CODE, 16, struct dahdi_gains) /* * Set Line (T1) Configurations */ struct dahdi_lineconfig { int span; /* Which span number (0 to use name) */ char name[20]; /* Name of span to use */ int lbo; /* line build-outs */ int lineconfig; /* line config parameters (framing, coding) */ int sync; /* what level of sync source we are */ }; #define DAHDI_SPANCONFIG _IOW(DAHDI_CODE, 18, struct dahdi_lineconfig) /* * Set Channel Configuration */ struct dahdi_chanconfig { int chan; /* Channel we're applying this to (0 to use name) */ char name[40]; /* Name of channel to use */ int sigtype; /* Signal type */ int deflaw; /* Default law (DAHDI_LAW_DEFAULT, DAHDI_LAW_MULAW, or DAHDI_LAW_ALAW) */ int master; /* Master channel if sigtype is DAHDI_SLAVE */ int idlebits; /* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */ char netdev_name[16];/* name for the hdlc network device*/ }; #define DAHDI_CHANCONFIG _IOW(DAHDI_CODE, 19, struct dahdi_chanconfig) /* * Set Conference to mute mode */ #define DAHDI_CONFMUTE _IOW(DAHDI_CODE, 20, int) /* * Send a particular tone (see DAHDI_TONE_*) */ #define DAHDI_SENDTONE _IOW(DAHDI_CODE, 21, int) /* * Get/Set your region for tones */ #define DAHDI_GETTONEZONE _IOR(DAHDI_CODE, 22, int) #define DAHDI_SETTONEZONE _IOW(DAHDI_CODE, 22, int) /* * Master unit only -- set default zone (see DAHDI_TONE_ZONE_*) */ #define DAHDI_DEFAULTZONE _IOW(DAHDI_CODE, 24, int) /* * Load a tone zone from a dahdi_tone_def_header */ struct dahdi_tone_def { int tone; /* See DAHDI_TONE_* */ int next; /* What the next position in the cadence is (They're numbered by the order the appear here) */ int samples; /* How many samples to play for this cadence */ int shift; /* How much to scale down the volume (2 is nice) */ /* Now come the constants we need to make tones */ /* Calculate the next 6 factors using the following equations: l = , f1 = , f2 = gain = pow(10.0, (l - 3.14) / 20.0) * 65536.0 / 2.0; // Frequency factor 1 fac_1 = 2.0 * cos(2.0 * M_PI * (f1/8000.0)) * 32768.0; // Last previous two samples init_v2_1 = sin(-4.0 * M_PI * (f1/8000.0)) * gain; init_v3_1 = sin(-2.0 * M_PI * (f1/8000.0)) * gain; // Frequency factor 2 fac_2 = 2.0 * cos(2.0 * M_PI * (f2/8000.0)) * 32768.0; // Last previous two samples init_v2_2 = sin(-4.0 * M_PI * (f2/8000.0)) * gain; init_v3_2 = sin(-2.0 * M_PI * (f2/8000.0)) * gain; */ int fac1; int init_v2_1; int init_v3_1; int fac2; int init_v2_2; int init_v3_2; int modulate; }; struct dahdi_tone_def_header { int count; /* How many samples follow */ int zone; /* Which zone we are loading */ int ringcadence[DAHDI_MAX_CADENCE]; /* Ring cadence in ms (0=on, 1=off, ends with 0 value) */ char name[40]; /* Informational name of zone */ /* immediately follow this structure with dahdi_tone_def structures */ struct dahdi_tone_def tones[0]; }; #define DAHDI_LOADZONE _IOW(DAHDI_CODE, 25, struct dahdi_tone_def_header) /* * Free a tone zone */ #define DAHDI_FREEZONE _IOW(DAHDI_CODE, 26, int) /* * Get/Set buffer policy */ struct dahdi_bufferinfo { int txbufpolicy; /* Policy for handling receive buffers */ int rxbufpolicy; /* Policy for handling receive buffers */ int numbufs; /* How many buffers to use */ int bufsize; /* How big each buffer is */ int readbufs; /* How many read buffers are full (read-only) */ int writebufs; /* How many write buffers are full (read-only) */ }; #define DAHDI_GET_BUFINFO _IOR(DAHDI_CODE, 27, struct dahdi_bufferinfo) #define DAHDI_SET_BUFINFO _IOW(DAHDI_CODE, 27, struct dahdi_bufferinfo) /* * Get/Set dialing parameters */ struct dahdi_dialparams { int mfv1_tonelen; /* MF R1 tone length for digits */ int dtmf_tonelen; /* DTMF tone length */ int mfr2_tonelen; /* MF R2 tone length */ int reserved[3]; /* Reserved for future expansion -- always set to 0 */ }; #define DAHDI_GET_DIALPARAMS _IOR(DAHDI_CODE, 29, struct dahdi_dialparams) #define DAHDI_SET_DIALPARAMS _IOW(DAHDI_CODE, 29, struct dahdi_dialparams) /* * Append, replace, or cancel a dial string */ struct dahdi_dialoperation { int op; char dialstr[DAHDI_MAX_DTMF_BUF]; }; #define DAHDI_DIAL _IOW(DAHDI_CODE, 31, struct dahdi_dialoperation) /* * Set a clear channel into audio mode */ #define DAHDI_AUDIOMODE _IOW(DAHDI_CODE, 32, int) /* * Enable or disable echo cancellation on a channel * * For ECHOCANCEL: * The number is zero to disable echo cancellation and non-zero * to enable echo cancellation. If the number is between 32 * and 1024, it will also set the number of taps in the echo canceller * * For ECHOCANCEL_PARAMS: * The structure contains parameters that should be passed to the * echo canceler instance for the selected channel. */ #define DAHDI_ECHOCANCEL _IOW(DAHDI_CODE, 33, int) struct dahdi_echocanparam { char name[16]; __s32 value; }; struct dahdi_echocanparams { /* 8 taps per millisecond */ __u32 tap_length; /* number of parameters supplied */ __u32 param_count; /* immediately follow this structure with dahdi_echocanparam structures */ struct dahdi_echocanparam params[0]; }; #define DAHDI_ECHOCANCEL_PARAMS _IOW(DAHDI_CODE, 33, struct dahdi_echocanparams) /* * Return a channel's channel number */ #define DAHDI_CHANNO _IOR(DAHDI_CODE, 34, int) /* * Return a flag indicating whether channel is currently dialing */ #define DAHDI_DIALING _IOR(DAHDI_CODE, 35, int) /* * Set a clear channel into HDLC w/out FCS checking/calculation mode */ #define DAHDI_HDLCRAWMODE _IOW(DAHDI_CODE, 36, int) /* * Set a clear channel into HDLC w/ FCS mode */ #define DAHDI_HDLCFCSMODE _IOW(DAHDI_CODE, 37, int) /* * Specify a channel on generic channel selector - must be done before * performing any other ioctls */ #define DAHDI_SPECIFY _IOW(DAHDI_CODE, 38, int) /* * Temporarily set the law on a channel to * DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. */ #define DAHDI_SETLAW _IOW(DAHDI_CODE, 39, int) /* * Temporarily set the channel to operate in linear mode when non-zero * or default law if 0 */ #define DAHDI_SETLINEAR _IOW(DAHDI_CODE, 40, int) /* * Set a clear channel into HDLC w/ PPP interface mode */ #define DAHDI_HDLCPPP _IOW(DAHDI_CODE, 41, int) /* * Set the ring cadence for FXS interfaces */ struct dahdi_ring_cadence { int ringcadence[DAHDI_MAX_CADENCE]; }; #define DAHDI_SETCADENCE _IOW(DAHDI_CODE, 42, struct dahdi_ring_cadence) /* * Get/Set the signaling bits for CAS interface */ #define DAHDI_GETRXBITS _IOR(DAHDI_CODE, 43, int) #define DAHDI_SETTXBITS _IOW(DAHDI_CODE, 43, int) /* * Display Channel Diagnostic Information on Console */ #define DAHDI_CHANDIAG_V1 _IOR(DAHDI_CODE, 44, int) #define DAHDI_CHANDIAG _IOW(DAHDI_CODE, 44, int) /* * Set Channel's SF Tone Configuration */ struct dahdi_sfconfig { int chan; /* Channel we're applying this to (0 to use name) */ char name[40]; /* Name of channel to use */ long rxp1; /* receive tone det. p1 */ long rxp2; /* receive tone det. p2 */ long rxp3; /* receive tone det. p3 */ int txtone; /* Tx tone factor */ int tx_v2; /* initial v2 value */ int tx_v3; /* initial v3 value */ int toneflag; /* Tone flags */ }; #define DAHDI_SFCONFIG _IOW(DAHDI_CODE, 46, struct dahdi_sfconfig) /* * Set timer expiration (in samples) */ #define DAHDI_TIMERCONFIG _IOW(DAHDI_CODE, 47, int) /* * Acknowledge timer expiration (number to acknowledge, or -1 for all) */ #define DAHDI_TIMERACK _IOW(DAHDI_CODE, 48, int) /* * Get Conference to mute mode */ #define DAHDI_GETCONFMUTE _IOR(DAHDI_CODE, 49, int) /* * Request echo training in some number of ms (with muting in the mean time) */ #define DAHDI_ECHOTRAIN _IOW(DAHDI_CODE, 50, int) /* * Set on hook transfer for n number of ms -- implemented by low level driver */ #define DAHDI_ONHOOKTRANSFER _IOW(DAHDI_CODE, 51, int) /* * Queue Ping */ #define DAHDI_TIMERPING _IO(DAHDI_CODE, 52) /* * Acknowledge ping */ #define DAHDI_TIMERPONG _IO(DAHDI_CODE, 53) /* * Get/set signalling freeze */ #define DAHDI_GETSIGFREEZE _IOR(DAHDI_CODE, 54, int) #define DAHDI_SETSIGFREEZE _IOW(DAHDI_CODE, 54, int) /* * Perform an indirect ioctl (on a specified channel via master interface) */ struct dahdi_indirect_data { int chan; int op; void *data; }; #define DAHDI_INDIRECT _IOWR(DAHDI_CODE, 56, struct dahdi_indirect_data) /* * Get the version of DAHDI that is running, and a description * of the compiled-in echo cancellers (if any) */ struct dahdi_versioninfo { char version[80]; char echo_canceller[80]; }; #define DAHDI_GETVERSION _IOR(DAHDI_CODE, 57, struct dahdi_versioninfo) /* * Put the channel in loopback mode (receive from the channel is * transmitted back on the interface) */ #define DAHDI_LOOPBACK _IOW(DAHDI_CODE, 58, int) /* Attach the desired echo canceler module (or none) to a channel in an audio-supporting mode, so that when the channel needs an echo canceler that module will be used to supply one. */ struct dahdi_attach_echocan { int chan; /* Channel we're applying this to */ char echocan[16]; /* Name of echo canceler to attach to this channel (leave empty to have no echocan attached */ }; #define DAHDI_ATTACH_ECHOCAN _IOW(DAHDI_CODE, 59, struct dahdi_attach_echocan) /* * 60-80 are reserved for private drivers * 80-85 are reserved for dynamic span stuff */ /* * Create a dynamic span */ struct dahdi_dynamic_span { char driver[20]; /* Which low-level driver to use */ char addr[40]; /* Destination address */ int numchans; /* Number of channels */ int timing; /* Timing source preference */ int spanno; /* Span number (filled in by DAHDI) */ }; #define DAHDI_DYNAMIC_CREATE _IOWR(DAHDI_CODE, 80, struct dahdi_dynamic_span) /* * Destroy a dynamic span */ #define DAHDI_DYNAMIC_DESTROY _IOW(DAHDI_CODE, 81, struct dahdi_dynamic_span) /* * Set the HW gain for a device */ struct dahdi_hwgain { __s32 newgain; /* desired gain in dB but x10. -3.5dB would be -35 */ __u32 tx:1; /* 0=rx; 1=tx */ }; #define DAHDI_SET_HWGAIN _IOW(DAHDI_CODE, 86, struct dahdi_hwgain) /* * Enable tone detection -- implemented by low level driver */ #define DAHDI_TONEDETECT _IOW(DAHDI_CODE, 91, int) /* * Set polarity -- implemented by individual driver. 0 = forward, 1 = reverse */ #define DAHDI_SETPOLARITY _IOW(DAHDI_CODE, 92, int) /* * Transcoder operations */ /* DAHDI_TRANSCODE_OP is an older interface that is deprecated and no longer * supported. */ #define DAHDI_TRANSCODE_OP _IOWR(DAHDI_CODE, 93, int) #define DAHDI_TC_CODE 'T' #define DAHDI_TC_ALLOCATE _IOW(DAHDI_TC_CODE, 1, struct dahdi_transcoder_formats) #define DAHDI_TC_GETINFO _IOWR(DAHDI_TC_CODE, 2, struct dahdi_transcoder_info) /* * VMWI Specification */ struct dahdi_vmwi_info { unsigned int vmwi_type; }; #define DAHDI_VMWI_LREV (1 << 0) /* Line Reversal */ #define DAHDI_VMWI_HVDC (1 << 1) /* HV 90VDC */ #define DAHDI_VMWI_HVAC (1 << 2) /* HV 90VAC Neon lamp */ /* * VoiceMail Waiting Indication (VMWI) -- implemented by low-level driver. * Value: number of waiting messages (hence 0: switch messages off). */ #define DAHDI_VMWI _IOWR(DAHDI_CODE, 94, int) #define DAHDI_VMWI_CONFIG _IOW(DAHDI_CODE, 95, struct dahdi_vmwi_info) /* * Startup or Shutdown a span */ #define DAHDI_STARTUP _IOW(DAHDI_CODE, 99, int) #define DAHDI_SHUTDOWN _IOW(DAHDI_CODE, 100, int) #define DAHDI_HDLC_RATE _IOW(DAHDI_CODE, 101, int) /* Put a channel's echo canceller into 'FAX mode' if possible */ #define DAHDI_ECHOCANCEL_FAX_MODE _IOW(DAHDI_CODE, 102, int) /* * Defines which channel to receive mirrored traffic from */ #ifdef CONFIG_DAHDI_MIRROR #define DAHDI_RXMIRROR _IOW(DAHDI_CODE, 103, int) #define DAHDI_TXMIRROR _IOW(DAHDI_CODE, 104, int) #endif /* CONFIG_DAHDI_MIRROR */ /* Set the desired state for channel buffer event generation which is disabled by default to allow for backwards compatibility for dumb users of channels such as pattern utilities. */ #define DAHDI_BUFFER_EVENTS _IOW(DAHDI_CODE, 105, int) /* Get current status IOCTL */ /* Defines for Radio Status (dahdi_radio_stat.radstat) bits */ #define DAHDI_RADSTAT_RX 1 /* currently "receiving " */ #define DAHDI_RADSTAT_TX 2 /* currently "transmitting" */ #define DAHDI_RADSTAT_RXCT 4 /* currently receiving continuous tone with current settings */ #define DAHDI_RADSTAT_RXCOR 8 /* currently receiving COR (irrelevant of COR ignore) */ #define DAHDI_RADSTAT_IGNCOR 16 /* currently ignoring COR */ #define DAHDI_RADSTAT_IGNCT 32 /* currently ignoring CTCSS/DCS decode */ #define DAHDI_RADSTAT_NOENCODE 64 /* currently blocking CTCSS/DCS encode */ struct dahdi_radio_stat { unsigned short ctcode_rx; /* code of currently received CTCSS or DCS, 0 for none */ unsigned short ctclass; /* class of currently received CTCSS or DCS code */ unsigned short ctcode_tx; /* code of currently encoded CTCSS or DCS, 0 for none */ unsigned char radstat; /* status bits of radio */ }; #define DAHDI_RADIO_GETSTAT _IOR(DAHDI_CODE, 57, struct dahdi_radio_stat) /* Get/Set a radio channel parameter */ /* Defines for Radio Parameters (dahdi_radio_param.radpar) */ #define DAHDI_RADPAR_INVERTCOR 1 /* invert the COR signal (0/1) */ #define DAHDI_RADPAR_IGNORECOR 2 /* ignore the COR signal (0/1) */ #define DAHDI_RADPAR_IGNORECT 3 /* ignore the CTCSS/DCS decode (0/1) */ #define DAHDI_RADPAR_NOENCODE 4 /* block the CTCSS/DCS encode (0/1) */ #define DAHDI_RADPAR_CORTHRESH 5 /* COR trigger threshold (0-7) */ #define DAHDI_RADPAR_EXTRXTONE 6 /* 0 means use internal decoder, 1 means UIOA logic true is CT decode, 2 means UIOA logic false is CT decode */ #define DAHDI_RADPAR_NUMTONES 7 /* returns maximum tone index (curently 15) */ #define DAHDI_RADPAR_INITTONE 8 /* init all tone indexes to 0 (no tones) */ #define DAHDI_RADPAR_RXTONE 9 /* CTCSS tone, (1-32) or DCS tone (1-777), or 0 meaning no tone, set index also (1-15) */ #define DAHDI_RADPAR_RXTONECLASS 10 /* Tone class (0-65535), set index also (1-15) */ #define DAHDI_RADPAR_TXTONE 11 /* CTCSS tone (1-32) or DCS tone (1-777) or 0 to indicate no tone, to transmit for this tone index (0-32, 0 disables transmit CTCSS), set index also (0-15) */ #define DAHDI_RADPAR_DEBOUNCETIME 12 /* receive indication debounce time, milliseconds (1-999) */ #define DAHDI_RADPAR_BURSTTIME 13 /* end of transmit with no CT tone in milliseconds (0-999) */ #define DAHDI_RADPAR_UIODATA 14 /* read/write UIOA and UIOB data. Bit 0 is UIOA, bit 1 is UIOB */ #define DAHDI_RADPAR_UIOMODE 15 /* 0 means UIOA and UIOB are both outputs, 1 means UIOA is input, UIOB is output, 2 means UIOB is input and UIOA is output, 3 means both UIOA and UIOB are inputs. Note mode for UIOA is overridden when in EXTRXTONE mode. */ #define DAHDI_RADPAR_REMMODE 16 /* Remote control data mode */ #define DAHDI_RADPAR_REM_NONE 0 /* no remote control data mode */ #define DAHDI_RADPAR_REM_RBI1 1 /* Doug Hall RBI-1 data mode */ #define DAHDI_RADPAR_REM_SERIAL 2 /* Serial Data, 9600 BPS */ #define DAHDI_RADPAR_REM_SERIAL_ASCII 3 /* Serial Ascii Data, 9600 BPS */ #define DAHDI_RADPAR_REMCOMMAND 17 /* Remote conrtol write data block & do cmd */ #define DAHDI_RADPAR_DEEMP 18 /* Audio De-empahsis (on or off) */ #define DAHDI_RADPAR_PREEMP 19 /* Audio Pre-empahsis (on or off) */ #define DAHDI_RADPAR_RXGAIN 20 /* Audio (In to system) Rx Gain */ #define DAHDI_RADPAR_TXGAIN 21 /* Audio (Out from system) Tx Gain */ #define RAD_SERIAL_BUFLEN 128 struct dahdi_radio_param { unsigned short radpar; /* param identifier */ unsigned short index; /* tone number */ int data; /* param */ int data2; /* param 2 */ unsigned char buf[RAD_SERIAL_BUFLEN]; }; #define DAHDI_RADIO_GETPARAM _IOR(DAHDI_CODE, 58, struct dahdi_radio_param) #define DAHDI_RADIO_SETPARAM _IOW(DAHDI_CODE, 58, struct dahdi_radio_param) /*! \brief Size-limited null-terminating string copy. \param dst The destination buffer \param src The source string \param size The size of the destination buffer \return Nothing. This is similar to \a strncpy, with two important differences: - the destination buffer will \b always be null-terminated - the destination buffer is not filled with zeros past the copied string length These differences make it slightly more efficient, and safer to use since it will not leave the destination buffer unterminated. There is no need to pass an artificially reduced buffer size to this function (unlike \a strncpy), and the buffer does not need to be initialized to zeroes prior to calling this function. */ static inline void dahdi_copy_string(char *dst, const char *src, unsigned int size) { while (*src && size) { *dst++ = *src++; size--; } if (__builtin_expect(!size, 0)) dst--; *dst = '\0'; } #endif /* _DAHDI_USER_H */ dahdi-linux-2.5.0.1/include/dahdi/wctdm_user.h0000644000175000017500000000316511046164220021031 0ustar tzafrirtzafrir/* * Wildcard S100P FXS Interface Driver for DAHDI Telephony interface * * Written by Mark Spencer * * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _WCTDM_H #define _WCTDM_H #include #define NUM_REGS 109 #define NUM_INDIRECT_REGS 105 struct wctdm_stats { int tipvolt; /* TIP voltage (mV) */ int ringvolt; /* RING voltage (mV) */ int batvolt; /* VBAT voltage (mV) */ }; struct wctdm_regs { unsigned char direct[NUM_REGS]; unsigned short indirect[NUM_INDIRECT_REGS]; }; struct wctdm_regop { int indirect; unsigned char reg; unsigned short val; }; struct wctdm_echo_coefs { unsigned char acim; unsigned char coef1; unsigned char coef2; unsigned char coef3; unsigned char coef4; unsigned char coef5; unsigned char coef6; unsigned char coef7; unsigned char coef8; }; #define WCTDM_GET_STATS _IOR (DAHDI_CODE, 60, struct wctdm_stats) #define WCTDM_GET_REGS _IOR (DAHDI_CODE, 61, struct wctdm_regs) #define WCTDM_SET_REG _IOW (DAHDI_CODE, 62, struct wctdm_regop) #define WCTDM_SET_ECHOTUNE _IOW (DAHDI_CODE, 63, struct wctdm_echo_coefs) #endif /* _WCTDM_H */ dahdi-linux-2.5.0.1/include/dahdi/fasthdlc.h0000644000175000017500000003057111341774613020461 0ustar tzafrirtzafrir/* * Mark's Mythical Table-based raw HDLC implementation * * This is designed to be a very fast, but memory efficient * implementation of standard HDLC protocol. * * This table based HDLC technology is PATENT PENDING, but will always be * remain freely distributable under the terms of the GPL version 2. * * For non-GPL licensing, please contact Mark Spencer at * the below e-mail address. * * Copyright (C) 2001-2008, Digium, Inc. * * Written by Mark Spencer * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _FASTHDLC_H #define _FASTHDLC_H enum fasthdlc_mode { FASTHDLC_MODE_64 = 0, FASTHDLC_MODE_56, FASTHDLC_MODE_16, }; struct fasthdlc_state { int state; /* What state we are in */ unsigned int data; /* Our current data queue */ int bits; /* Number of bits in our data queue */ int ones; /* Number of ones */ enum fasthdlc_mode mode; unsigned int minbits; }; #ifdef FAST_HDLC_NEED_TABLES #define RETURN_COMPLETE_FLAG (0x1000) #define RETURN_DISCARD_FLAG (0x2000) #define RETURN_EMPTY_FLAG (0x4000) /* Unlike most HDLC implementations, we define only two states, when we are in a valid frame, and when we are searching for a frame header */ #define FRAME_SEARCH 0 #define PROCESS_FRAME 1 /* HDLC Search State table -- Look for a frame header. The return value of this table is as follows: |---8---|---7---|---6---|---5---|---4---|---3---|---2---|---1---| | Z E R O E S | Next | Bits Consumed | |-------|-------|-------|-------|-------|-------|-------|-------| The indexes for this table are the state (0 or 1) and the next 8 bits of the stream. Note that this table is only used for state 0 and 1. The user should discard the top "bits consumed" bits of data before the next call. "Next state" represents the actual next state for decoding. */ static unsigned char hdlc_search[256]; /* HDLC Data Table The indexes to this table are the number of one's we've seen so far (0-5) and the next 10 bits of input (which is enough to guarantee us that we will retrieve at least one byte of data (or frame or whatever). The format for the return value is: Bits 15: Status (1=Valid Data, 0=Control Frame (see bits 7-0 for type)) Bits 14-12: Number of ones in a row, so far Bits 11-8: The number of bits consumed (0-10) Bits 7-0: The return data (if appropriate) The next state is simply bit #15 */ #define CONTROL_COMPLETE 1 #define CONTROL_ABORT 2 #define STATUS_MASK (1 << 15) #define STATUS_VALID (1 << 15) #define STATUS_CONTROL (0 << 15) #define STATE_MASK (1 << 15) #define ONES_MASK (7 << 12) #define DATA_MASK (0xff) static unsigned short hdlc_frame[6][1024]; static unsigned int minbits[2] = { 8, 10 }; /* Last, but not least, we have the encoder table. It takes as its indices the number of ones so far and a byte of data and returns an int composed of the following fields: Bots 31-22: Actual Data Bits 21-16: Unused Bits 15-8: Number of ones Bits 3-0: Number of bits of output (13-4) to use Of course we could optimize by reducing to two tables, but I don't really think it's worth the trouble at this point. */ static unsigned int hdlc_encode[6][256]; static inline char hdlc_search_precalc(unsigned char c) { int x, p=0; /* Look for a flag. If this isn't a flag, line us up for the next possible shot at a flag */ /* If it's a flag, we go to state 1, and have consumed 8 bits */ if (c == 0x7e) return 0x10 | 8; /* If it's an abort, we stay in the same state and have consumed 8 bits */ if (c == 0x7f) return 0x00 | 8; /* If it's all 1's, we state in the same state and have consumed 8 bits */ if (c == 0xff) return 0x00 | 8; /* If we get here, we must have at least one zero in us but we're not the flag. So, start at the end (LSB) and work our way to the top (MSB) looking for a zero. The position of that 0 is most optimistic start of a real frame header */ x=1; p=7; while(p && (c & x)) { x <<= 1; p--; } return p; } #ifdef DEBUG_PRECALC static inline void hdlc_search_print(char c, char r) { int x=0x80; while(x) { printf("%s", c & x ? "1" : "0"); x >>= 1; } printf(" => State %d, Consume %d\n", (r & 0x10) >> 4, r & 0xf); } #endif #define HFP(status, ones, bits, data) \ ((status) | ((ones) << 12) | ((bits) << 8) | (data)) static inline unsigned int hdlc_frame_precalc(unsigned char x, unsigned short c) { /* Assume we have seen 'x' one's so far, and have read the bottom 10 bytes of c (MSB first). Now, we HAVE to have a byte of data or a frame or something. We are assumed to be at the beginning of a byte of data or something */ unsigned char ones = x; unsigned char data=0; int bits=0; int consumed=0; while(bits < 8) { data >>=1; consumed++; if (ones == 5) { /* We've seen five ones */ if (c & 0x0200) { /* Another one -- Some sort of signal frame */ if ((!(c & 0x0100)) && (bits == 6)) { /* This is a frame terminator (10) */ return HFP(0, 0, 8, CONTROL_COMPLETE); } else { /* Yuck! It's something else... Abort this entire frame, and start looking for a good frame */ return HFP(0, 0, consumed+1, CONTROL_ABORT); } } else { /* It's an inserted zero, just skip it */ ones = 0; data <<= 1; } } else { /* Add it to our bit list, LSB to MSB */ if (c & 0x0200) { data |= 0x80; ones++; } else ones=0; bits++; } c <<= 1; } /* Consume the extra 0 now rather than later. */ if (ones == 5) { ones = 0; consumed++; } return HFP(STATUS_VALID, ones, consumed, data); } #ifdef DEBUG_PRECALC static inline void hdlc_frame_print(unsigned char x, unsigned short c, unsigned int res) { int z=0x0200; char *status[] = { "Control", "Valid", }; printf("%d one's then ", x); while(z) { printf("%s", c & z ? "1" : "0"); z >>= 1; } printf(" => Status %s, ", res & STATUS_MASK ? "1" : "0"); printf("Consumed: %d, ", (res & 0x0f00) >> 8); printf("Status: %s, ", status[(res & STATUS_MASK) >> 15]); printf("Ones: %d, ", (res & ONES_MASK) >> 12); printf("Data: %02x\n", res & 0xff); } #endif static inline unsigned int hdlc_encode_precalc(int x, unsigned char y) { int bits=0; int ones=x; unsigned short data=0; int z; for (z=0;z<8;z++) { /* Zero-stuff if needed */ if (ones == 5) { /* Stuff a zero */ data <<= 1; ones=0; bits++; } if (y & 0x01) { /* There's a one */ data <<= 1; data |= 0x1; ones++; bits++; } else { data <<= 1; ones = 0; bits++; } y >>= 1; } /* Special case -- Stuff the zero at the end if appropriate */ if (ones == 5) { /* Stuff a zero */ data <<= 1; ones=0; bits++; } data <<= (10-bits); return (data << 22) | (ones << 8) | (bits); } #ifdef DEBUG_PRECALC static inline void hdlc_encode_print(int x, unsigned char y, unsigned int val) { unsigned int z; unsigned short c; printf("%d ones, %02x (", x, y); z = 0x80; while(z) { printf("%s", y & z ? "1" : "0"); z >>= 1; } printf(") encoded as "); z = 1 << 31; for (x=0;x<(val & 0xf);x++) { printf("%s", val & z ? "1" : "0"); z >>= 1; } printf(" with %d ones now, %d bits in len\n", (val & 0xf00) >> 8, val & 0xf); } #endif static inline void fasthdlc_precalc(void) { int x; int y; /* First the easy part -- the searching */ for (x=0;x<256;x++) { hdlc_search[x] = hdlc_search_precalc(x); #ifdef DEBUG_PRECALC hdlc_search_print(x, hdlc_search[x]); #endif } /* Now the hard part -- the frame tables */ for (x=0;x<6;x++) { /* Given the # of preceeding ones, process the next byte of input (up to 10 actual bits) */ for (y=0;y<1024;y++) { hdlc_frame[x][y] = hdlc_frame_precalc(x, y); #ifdef DEBUG_PRECALC hdlc_frame_print(x, y, hdlc_frame[x][y]); #endif } } /* Now another not-so-hard part, the encoding table */ for (x=0;x<6;x++) { for (y=0;y<256;y++) { hdlc_encode[x][y] = hdlc_encode_precalc(x,y); #ifdef DEBUG_PRECALC hdlc_encode_print(x,y,hdlc_encode[x][y]); #endif } } } static inline void fasthdlc_init(struct fasthdlc_state *h, enum fasthdlc_mode mode) { /* Initializes all states appropriately */ h->mode = mode; h->state = 0; h->bits = 0; h->data = 0; h->ones = 0; switch (mode) { case FASTHDLC_MODE_64: h->minbits = 8; break; case FASTHDLC_MODE_56: h->minbits = 7; break; case FASTHDLC_MODE_16: h->minbits = 2; break; } } static inline int fasthdlc_tx_load_nocheck(struct fasthdlc_state *h, unsigned char c) { unsigned int res; res = hdlc_encode[h->ones][c]; h->ones = (res & 0xf00) >> 8; h->data |= (res & 0xffc00000) >> h->bits; h->bits += (res & 0xf); return 0; } static inline int fasthdlc_tx_load(struct fasthdlc_state *h, unsigned char c) { /* Gotta have at least 10 bits left */ if (h->bits > 22) return -1; return fasthdlc_tx_load_nocheck(h, c); } static inline int fasthdlc_tx_frame_nocheck(struct fasthdlc_state *h) { h->ones = 0; h->data |= ( 0x7e000000 >> h->bits); h->bits += 8; return 0; } static inline int fasthdlc_tx_frame(struct fasthdlc_state *h) { if (h->bits > 24) return -1; return fasthdlc_tx_frame_nocheck(h); } static inline int fasthdlc_tx_need_data(struct fasthdlc_state *h) { if (h->mode == FASTHDLC_MODE_56) { if (h->bits < 7) return 1; } else if (h->mode == FASTHDLC_MODE_16) { if (h->bits < 2) return 1; } else { if (h->bits < 8) return 1; } return 0; } static inline int fasthdlc_tx_run_nocheck(struct fasthdlc_state *h) { unsigned char b; if (h->mode == FASTHDLC_MODE_16) { b = h->data >> 30; h->bits -= 2; h->data <<= 2; return (b & 3) << 6; } else if (h->mode == FASTHDLC_MODE_56) { b = h->data >> 25; h->bits -= 7; h->data <<= 7; return ((b & 0x7f) << 1) | 1; } else { b = h->data >> 24; h->bits -= 8; h->data <<= 8; return b; } } static inline int fasthdlc_tx_run(struct fasthdlc_state *h) { if (h->bits < h->minbits) return -1; return fasthdlc_tx_run_nocheck(h); } static inline int fasthdlc_rx_load_nocheck(struct fasthdlc_state *h, unsigned char b) { if (h->mode == FASTHDLC_MODE_16) { h->data |= (b >> 6) << (30-h->bits); h->bits += 2; } else if (h->mode == FASTHDLC_MODE_56) { h->data |= (b >> 1) << (25-h->bits); h->bits += 7; } else { /* Put the new byte in the data stream */ h->data |= b << (24-h->bits); h->bits += 8; } return 0; } static inline int fasthdlc_rx_load(struct fasthdlc_state *h, unsigned char b) { /* Make sure we have enough space */ if (h->bits > 24) return -1; return fasthdlc_rx_load_nocheck(h, b); } /* Returns a data character if available, logical OR'd with zero or more of RETURN_COMPLETE_FLAG, RETURN_DISCARD_FLAG, and RETURN_EMPTY_FLAG, signifying a complete frame, a discarded frame, or there is nothing to return. */ static inline int fasthdlc_rx_run(struct fasthdlc_state *h) { unsigned short next; int retval=RETURN_EMPTY_FLAG; while ((h->bits >= minbits[h->state]) && (retval == RETURN_EMPTY_FLAG)) { /* Run until we can no longer be assured that we will have enough bits to continue */ switch(h->state) { case FRAME_SEARCH: /* Look for an HDLC frame, keying from the top byte. */ next = hdlc_search[h->data >> 24]; h->bits -= next & 0x0f; h->data <<= next & 0x0f; h->state = next >> 4; h->ones = 0; break; case PROCESS_FRAME: /* Process as much as the next ten bits */ next = hdlc_frame[h->ones][h->data >> 22]; h->bits -= ((next & 0x0f00) >> 8); h->data <<= ((next & 0x0f00) >> 8); h->state = (next & STATE_MASK) >> 15; h->ones = (next & ONES_MASK) >> 12; switch(next & STATUS_MASK) { case STATUS_CONTROL: if (next & CONTROL_COMPLETE) { /* A complete, valid frame received */ retval = (RETURN_COMPLETE_FLAG); /* Stay in this state */ h->state = 1; } else { /* An abort (either out of sync of explicit) */ retval = (RETURN_DISCARD_FLAG); } break; case STATUS_VALID: retval = (next & DATA_MASK); } } } return retval; } #endif /* FAST_HDLC_NEED_TABLES */ #endif dahdi-linux-2.5.0.1/include/dahdi/kernel.h0000644000175000017500000013626111621031746020146 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface * * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001 - 2010 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /*! * \file * \brief DAHDI kernel interface definitions */ #ifndef _DAHDI_KERNEL_H #define _DAHDI_KERNEL_H #include #include #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #include #endif #include #include #include #ifdef CONFIG_DAHDI_NET #include #endif #ifdef CONFIG_DAHDI_PPP #include #include #include #endif #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) #define dahdi_pci_module pci_register_driver #else #define dahdi_pci_module pci_module_init #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) #define DAHDI_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id) #else #define DAHDI_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id, struct pt_regs *regs) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) #define HAVE_NET_DEVICE_OPS #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) #define DAHDI_IRQ_SHARED IRQF_SHARED #define DAHDI_IRQ_DISABLED IRQF_DISABLED #define DAHDI_IRQ_SHARED_DISABLED IRQF_SHARED | IRQF_DISABLED #else #define DAHDI_IRQ_SHARED SA_SHIRQ #define DAHDI_IRQ_DISABLED SA_INTERRUPT #define DAHDI_IRQ_SHARED_DISABLED SA_SHIRQ | SA_INTERRUPT #endif #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) #ifndef dev_notice #define dev_notice(dev, format, arg...) \ dev_printk(KERN_NOTICE , dev , format , ## arg) #endif #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) # ifdef RHEL_RELEASE_VERSION # if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5, 6) #define dev_name(dev) ((dev)->bus_id) # endif # else #define dev_name(dev) ((dev)->bus_id) # endif #define dev_set_name(dev, format, ...) \ snprintf((dev)->bus_id, BUS_ID_SIZE, format, ## __VA_ARGS__); #endif /*! Default chunk size for conferences and such -- static right now, might make variable sometime. 8 samples = 1 ms = most frequent service interval possible for a USB device */ #define DAHDI_CHUNKSIZE 8 #define DAHDI_MIN_CHUNKSIZE DAHDI_CHUNKSIZE #define DAHDI_DEFAULT_CHUNKSIZE DAHDI_CHUNKSIZE #define DAHDI_MAX_CHUNKSIZE DAHDI_CHUNKSIZE #define DAHDI_CB_SIZE 2 /* DAHDI operates at 8Khz by default */ #define DAHDI_MS_TO_SAMPLES(ms) ((ms) * 8) #define DAHDI_MSECS_PER_CHUNK (DAHDI_CHUNKSIZE/DAHDI_MS_TO_SAMPLES(1)) #define RING_DEBOUNCE_TIME 2000 /*!< 2000 ms ring debounce time */ typedef struct { int32_t gain; int32_t a1; int32_t a2; int32_t b1; int32_t b2; int32_t z1; int32_t z2; } biquad2_state_t; typedef struct { biquad2_state_t notch; int notch_level; int channel_level; int tone_present; int tone_cycle_duration; int good_cycles; int hit; } echo_can_disable_detector_state_t; struct sf_detect_state { long x1; long x2; long y1; long y2; long e1; long e2; int samps; int lastdetect; }; struct dahdi_tone_state { int v1_1; int v2_1; int v3_1; int v1_2; int v2_2; int v3_2; int modulate; }; /*! \brief Conference queue structure */ struct confq { u_char buffer[DAHDI_CHUNKSIZE * DAHDI_CB_SIZE]; u_char *buf[DAHDI_CB_SIZE]; int inbuf; int outbuf; }; struct dahdi_chan; struct dahdi_echocan_state; /*! Features a DAHDI echo canceler (software or hardware) can provide to the DAHDI core. */ struct dahdi_echocan_features { /*! Able to detect CED tone (2100 Hz with phase reversals) in the transmit direction. * If the echocan can detect this tone, it may report it it as an event (see * the events.CED_tx_detected field of dahdi_echocan_state), and if it will automatically * disable itself or its non-linear processor, then the NLP_automatic feature flag should also * be set so that the DAHDI core doesn't bother trying to do so. */ u32 CED_tx_detect:1; /*! Able to detect CED tone (2100 Hz with phase reversals) in the receive direction. * If the echocan can detect this tone, it may report it it as an event (see * the events.CED_rx_detected field of dahdi_echocan_state), and if it will automatically * disable itself or its non-linear processor, then the NLP_automatic flag feature should also * be set so that the DAHDI core doesn't bother trying to do so. */ u32 CED_rx_detect:1; /*! Able to detect CNG tone (1100 Hz) in the transmit direction. */ u32 CNG_tx_detect:1; /*! Able to detect CNG tone (1100 Hz) in the receive direction. */ u32 CNG_rx_detect:1; /*! If the echocan's NLP can be enabled and disabled without requiring destruction * and recreation of the state structure, this feature flag should be set and the * echocan_NLP_toggle field of the dahdi_echocan_ops structure should be filled with a * pointer to the function to perform that operation. */ u32 NLP_toggle:1; /*! If the echocan will automatically disable itself (or even just its NLP) based on * detection of a CED tone in either direction, this feature flag should be set (along * with the tone detection feature flags). */ u32 NLP_automatic:1; }; /*! Operations (methods) that can be performed on a DAHDI echo canceler instance (state * structure) after it has been created, by either a software or hardware echo canceller. * The echo canceler must populate the owner field of the dahdi_echocan_state structure * with a pointer to the relevant operations structure for that instance. */ struct dahdi_echocan_ops { /*! \brief Free an echocan state structure. * \param[in,out] ec Pointer to the state structure to free. * * \return Nothing. */ void (*echocan_free)(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); /*! \brief Process an array of audio samples through the echocan. * \param[in,out] ec Pointer to the state structure. * \param[in,out] isig The receive direction data (will be modified). * \param[in] iref The transmit direction data. * \param[in] size The number of elements in the isig and iref arrays. * * Note: This function can also return events in the events field of the * dahdi_echocan_state structure. If it can do so, then the echocan does * not need to provide the echocan_events function. * * \return Nothing. */ void (*echocan_process)(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); /*! \brief Retrieve events from the echocan. * \param[in,out] ec Pointer to the state structure. * * * If any events have occurred, the events field of the dahdi_echocan_state * structure should be updated to include them. * * \return Nothing. */ void (*echocan_events)(struct dahdi_echocan_state *ec); /*! \brief Feed a sample (and its position) for echocan training. * \param[in,out] ec Pointer to the state structure. * \param[in] pos The tap position to be 'trained'. * \param[in] val The receive direction sample for the specified tap position. * * \retval Zero if training should continue. * \retval Non-zero if training is complete. */ int (*echocan_traintap)(struct dahdi_echocan_state *ec, int pos, short val); /*! \brief Enable or disable non-linear processing (NLP) in the echocan. * \param[in,out] ec Pointer to the state structure. * \param[in] enable Zero to disable, non-zero to enable. * * \return Nothing. */ void (*echocan_NLP_toggle)(struct dahdi_echocan_state *ec, unsigned int enable); #ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX /*! \brief Process an array of TX audio samples. * * \return Nothing. */ void (*echocan_process_tx)(struct dahdi_echocan_state *ec, short *tx, u32 size); #endif }; /*! A factory for creating instances of software echo cancelers to be used on DAHDI channels. */ struct dahdi_echocan_factory { /*! Get the name of the factory. */ const char *(*get_name)(const struct dahdi_chan *chan); /*! Pointer to the module that owns this factory; the module's reference count will be * incremented/decremented by the DAHDI core as needed. */ struct module *owner; /*! \brief Function to create an instance of the echocan. * \param[in] ecp Structure defining parameters to be used for the instance creation. * \param[in] p Pointer to the beginning of an (optional) array of user-defined parameters. * \param[out] ec Pointer to the state structure that is created, if any. * * \retval Zero on success. * \retval Non-zero on failure (return value will be returned to userspace so it should be a * standard error number). */ int (*echocan_create)(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); }; /*! \brief Register an echo canceler factory with the DAHDI core. * \param[in] ec Pointer to the dahdi_echocan_factory structure to be registered. * * \retval Zero on success. * \retval Non-zero on failure (return value will be a standard error number). */ int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec); /*! \brief Unregister a previously-registered echo canceler factory from the DAHDI core. * \param[in] ec Pointer to the dahdi_echocan_factory structure to be unregistered. * * \return Nothing. */ void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec); enum dahdi_echocan_mode { __ECHO_MODE_MUTE = 1 << 8, ECHO_MODE_IDLE = 0, ECHO_MODE_PRETRAINING = 1 | __ECHO_MODE_MUTE, ECHO_MODE_STARTTRAINING = 2 | __ECHO_MODE_MUTE, ECHO_MODE_AWAITINGECHO = 3 | __ECHO_MODE_MUTE, ECHO_MODE_TRAINING = 4 | __ECHO_MODE_MUTE, ECHO_MODE_ACTIVE = 5, ECHO_MODE_FAX = 6, }; /*! An instance of a DAHDI echo canceler (software or hardware). */ struct dahdi_echocan_state { /*! Pointer to a dahdi_echocan_ops structure of operations that can be * performed on this instance. */ const struct dahdi_echocan_ops *ops; /*! State data used by the DAHDI core's CED detector for the transmit * direction, if needed. */ echo_can_disable_detector_state_t txecdis; /*! State data used by the DAHDI core's CED detector for the receive * direction, if needed. */ echo_can_disable_detector_state_t rxecdis; /*! Features offered by the echo canceler that provided this instance. */ struct dahdi_echocan_features features; struct { /*! The mode the echocan is currently in. */ enum dahdi_echocan_mode mode; /*! The last tap position that was fed to the echocan's training function. */ u32 last_train_tap; /*! How many samples to wait before beginning the training operation. */ u32 pretrain_timer; } status; /*! This structure contains event flags, allowing the echocan to report * events that occurred as it processed the transmit and receive streams * of samples. Each call to the echocan_process operation for this * instance may report events, so the structure should be cleared before * calling that operation. */ union dahdi_echocan_events { u32 all; struct { /*! CED tone was detected in the transmit direction. If the * echocan automatically disables its NLP when this occurs, * it must also signal the NLP_auto_disabled event during the *same* * call to echocan_process that reports the CED detection. */ u32 CED_tx_detected:1; /*! CED tone was detected in the receive direction. If the * echocan automatically disables its NLP when this occurs, * it must also signal the NLP_auto_disabled event during the *same* * call to echocan_process that reports the CED detection. */ u32 CED_rx_detected:1; /*! CNG tone was detected in the transmit direction. */ u32 CNG_tx_detected:1; /*! CNG tone was detected in the receive direction. */ u32 CNG_rx_detected:1; /*! The echocan disabled its NLP automatically. */ u32 NLP_auto_disabled:1; /*! The echocan enabled its NLP automatically. */ u32 NLP_auto_enabled:1; } bit; } events; }; struct dahdi_chan { #ifdef CONFIG_DAHDI_NET /*! \note Must be first */ struct dahdi_hdlc *hdlcnetdev; #endif #ifdef CONFIG_DAHDI_PPP struct ppp_channel *ppp; struct tasklet_struct ppp_calls; int do_ppp_wakeup; int do_ppp_error; struct sk_buff_head ppp_rq; #endif #ifdef BUFFER_DEBUG int statcount; int lastnumbufs; #endif spinlock_t lock; char name[40]; /* Specified by DAHDI */ /*! \brief DAHDI channel number */ int channo; int chanpos; unsigned long flags; long rxp1; long rxp2; long rxp3; int txtone; int tx_v2; int tx_v3; int v1_1; int v2_1; int v3_1; int toneflags; struct sf_detect_state rd; struct dahdi_chan *master; /*!< Our Master channel (could be us) */ /*! \brief Next slave (if appropriate) */ struct dahdi_chan *nextslave; u_char *writechunk; /*!< Actual place to write to */ u_char swritechunk[DAHDI_MAX_CHUNKSIZE]; /*!< Buffer to be written */ u_char *readchunk; /*!< Actual place to read from */ u_char sreadchunk[DAHDI_MAX_CHUNKSIZE]; /*!< Preallocated static area */ short *readchunkpreec; /* Channel from which to read when DACSed. */ struct dahdi_chan *dacs_chan; /*! Pointer to tx and rx gain tables */ const u_char *rxgain; const u_char *txgain; /* Specified by driver, readable by DAHDI */ void *pvt; /*!< Private channel data */ struct file *file; /*!< File structure */ #ifdef CONFIG_DAHDI_MIRROR struct dahdi_chan *rxmirror; /*!< channel we mirror reads to */ struct dahdi_chan *txmirror; /*!< channel we mirror writes to */ struct dahdi_chan *srcmirror; /*!< channel we mirror from */ #endif /* CONFIG_DAHDI_MIRROR */ struct dahdi_span *span; /*!< Span we're a member of */ int sig; /*!< Signalling */ int sigcap; /*!< Capability for signalling */ __u32 chan_alarms; /*!< alarms status */ wait_queue_head_t waitq; /* Used only by DAHDI -- NO DRIVER SERVICEABLE PARTS BELOW */ /* Buffer declarations */ u_char *readbuf[DAHDI_MAX_NUM_BUFS]; /*!< read buffer */ int inreadbuf; int outreadbuf; u_char *writebuf[DAHDI_MAX_NUM_BUFS]; /*!< write buffers */ int inwritebuf; int outwritebuf; int blocksize; /*!< Block size */ int eventinidx; /*!< out index in event buf (circular) */ int eventoutidx; /*!< in index in event buf (circular) */ unsigned int eventbuf[DAHDI_MAX_EVENTSIZE]; /*!< event circ. buffer */ int readn[DAHDI_MAX_NUM_BUFS]; /*!< # of bytes ready in read buf */ int readidx[DAHDI_MAX_NUM_BUFS]; /*!< current read pointer */ int writen[DAHDI_MAX_NUM_BUFS]; /*!< # of bytes ready in write buf */ int writeidx[DAHDI_MAX_NUM_BUFS]; /*!< current write pointer */ int numbufs; /*!< How many buffers in channel */ int txbufpolicy; /*!< Buffer policy */ int rxbufpolicy; /*!< Buffer policy */ int txdisable; /*!< Disable transmitter */ int rxdisable; /*!< Disable receiver */ /* Tone zone stuff */ struct dahdi_zone *curzone; /*!< Zone for selecting tones */ struct dahdi_tone *curtone; /*!< Current tone we're playing (if any) */ int tonep; /*!< Current position in tone */ struct dahdi_tone_state ts; /*!< Tone state */ /* Pulse dial stuff */ int pdialcount; /*!< pulse dial count */ /*! Ring cadence */ int ringcadence[DAHDI_MAX_CADENCE]; int firstcadencepos; /*!< Where to restart ring cadence */ /* Digit string dialing stuff */ int digitmode; /*!< What kind of tones are we sending? */ char txdialbuf[DAHDI_MAX_DTMF_BUF]; int dialing; int afterdialingtimer; int cadencepos; /*!< Where in the cadence we are */ /* I/O Mask */ unsigned int iomask; /*! I/O Mux signal mask */ /* HDLC state machines */ struct fasthdlc_state txhdlc; struct fasthdlc_state rxhdlc; int infcs; /* Conferencing stuff */ int confna; /*! conference number (alias) */ int _confn; /*! Actual conference number */ int confmode; /*! conference mode */ int confmute; /*! conference mute mode */ struct dahdi_chan *conf_chan; /* Incoming and outgoing conference chunk queues for communicating between DAHDI master time and other boards */ struct confq confin; struct confq confout; short getlin[DAHDI_MAX_CHUNKSIZE]; /*!< Last transmitted samples */ unsigned char getraw[DAHDI_MAX_CHUNKSIZE]; /*!< Last received raw data */ short getlin_lastchunk[DAHDI_MAX_CHUNKSIZE]; /*!< Last transmitted samples from last chunk */ short putlin[DAHDI_MAX_CHUNKSIZE]; /*!< Last received samples */ unsigned char putraw[DAHDI_MAX_CHUNKSIZE]; /*!< Last received raw data */ short conflast[DAHDI_MAX_CHUNKSIZE]; /*!< Last conference sample -- base part of channel */ short conflast1[DAHDI_MAX_CHUNKSIZE]; /*!< Last conference sample -- pseudo part of channel */ short conflast2[DAHDI_MAX_CHUNKSIZE]; /*!< Previous last conference sample -- pseudo part of channel */ /*! The echo canceler module that should be used to create an instance when this channel needs one */ const struct dahdi_echocan_factory *ec_factory; /*! The echo canceler module that owns the instance currently on this channel, if one is present */ const struct dahdi_echocan_factory *ec_current; /*! The state data of the echo canceler instance in use */ struct dahdi_echocan_state *ec_state; /* RBS timings */ int prewinktime; /*!< pre-wink time (ms) */ int preflashtime; /*!< pre-flash time (ms) */ int winktime; /*!< wink time (ms) */ int flashtime; /*!< flash time (ms) */ int starttime; /*!< start time (ms) */ int rxwinktime; /*!< rx wink time (ms) */ int rxflashtime; /*!< rx flash time (ms) */ int debouncetime; /*!< FXS GS sig debounce time (ms) */ int pulsebreaktime; /*!< pulse line open time (ms) */ int pulsemaketime; /*!< pulse line closed time (ms) */ int pulseaftertime; /*!< pulse time between digits (ms) */ /*! RING debounce timer */ int ringdebtimer; /*! RING trailing detector to make sure a RING is really over */ int ringtrailer; /* PULSE digit receiver stuff */ int pulsecount; int pulsetimer; /* RBS timers */ int itimerset; /*!< what the itimer was set to last */ int itimer; int otimer; /* RBS state */ int gotgs; int txstate; int rxsig; int txsig; int rxsigstate; /* non-RBS rx state */ int rxhooksig; int txhooksig; int kewlonhook; /*! Idle signalling if CAS signalling */ int idlebits; int deflaw; /*! 1 = mulaw, 2=alaw, 0=undefined */ short *xlaw; #ifdef OPTIMIZE_CHANMUTE int chanmute; /*!< no need for PCM data */ #endif #ifdef CONFIG_CALC_XLAW unsigned char (*lineartoxlaw)(short a); #else unsigned char *lin2x; #endif }; #ifdef CONFIG_DAHDI_NET struct dahdi_hdlc { struct net_device *netdev; struct dahdi_chan *chan; }; #endif /*! Define the maximum block size */ #define DAHDI_MAX_BLOCKSIZE 8192 #define DAHDI_DEFAULT_WINKTIME 150 /*!< 150 ms default wink time */ #define DAHDI_DEFAULT_FLASHTIME 750 /*!< 750 ms default flash time */ #define DAHDI_DEFAULT_PREWINKTIME 50 /*!< 50 ms before wink */ #define DAHDI_DEFAULT_PREFLASHTIME 50 /*!< 50 ms before flash */ #define DAHDI_DEFAULT_STARTTIME 1500 /*!< 1500 ms of start */ #define DAHDI_DEFAULT_RINGTIME 2000 /*!< 2000 ms of ring on (start, FXO) */ #if 0 #define DAHDI_DEFAULT_RXWINKTIME 250 /*!< 250ms longest rx wink */ #endif #define DAHDI_DEFAULT_RXWINKTIME 300 /*!< 300ms longest rx wink (to work with the Atlas) */ #define DAHDI_DEFAULT_RXFLASHTIME 1250 /*!< 1250ms longest rx flash */ #define DAHDI_DEFAULT_DEBOUNCETIME 600 /*!< 600ms of FXS GS signalling debounce */ #define DAHDI_DEFAULT_PULSEMAKETIME 50 /*!< 50 ms of line closed when dial pulsing */ #define DAHDI_DEFAULT_PULSEBREAKTIME 50 /*!< 50 ms of line open when dial pulsing */ #define DAHDI_DEFAULT_PULSEAFTERTIME 750 /*!< 750ms between dial pulse digits */ #define DAHDI_MINPULSETIME (15 * 8) /*!< 15 ms minimum */ #ifdef SHORT_FLASH_TIME #define DAHDI_MAXPULSETIME (80 * 8) /*!< we need 80 ms, not 200ms, as we have a short flash */ #else #define DAHDI_MAXPULSETIME (200 * 8) /*!< 200 ms maximum */ #endif #define DAHDI_PULSETIMEOUT ((DAHDI_MAXPULSETIME / 8) + 50) #define DAHDI_RINGTRAILER (50 * 8) /*!< Don't consider a ring "over" until it's been gone at least this much time */ #define DAHDI_LOOPCODE_TIME 10000 /*!< send loop codes for 10 secs */ #define DAHDI_ALARMSETTLE_TIME 5000 /*!< allow alarms to settle for 5 secs */ #define DAHDI_AFTERSTART_TIME 500 /*!< 500ms after start */ #define DAHDI_RINGOFFTIME 4000 /*!< Turn off ringer for 4000 ms */ #define DAHDI_KEWLTIME 500 /*!< 500ms for kewl pulse */ #define DAHDI_AFTERKEWLTIME 300 /*!< 300ms after kewl pulse */ #define DAHDI_MAX_PRETRAINING 1000 /*!< 1000ms max pretraining time */ #ifdef FXSFLASH #define DAHDI_FXSFLASHMINTIME 450 /*!< min 450ms */ #define DAHDI_FXSFLASHMAXTIME 550 /*!< max 550ms */ #endif struct dahdi_chardev { const char *name; __u8 minor; }; int dahdi_register_chardev(struct dahdi_chardev *dev); int dahdi_unregister_chardev(struct dahdi_chardev *dev); /*! \brief defines for transmit signalling */ enum dahdi_txsig { DAHDI_TXSIG_ONHOOK, /*!< On hook */ DAHDI_TXSIG_OFFHOOK, /*!< Off hook */ DAHDI_TXSIG_START, /*!< Start / Ring */ DAHDI_TXSIG_KEWL, /*!< Drop battery if possible */ /*! Leave this as the last entry */ DAHDI_TXSIG_TOTAL, }; enum dahdi_rxsig { DAHDI_RXSIG_ONHOOK, DAHDI_RXSIG_OFFHOOK, DAHDI_RXSIG_START, DAHDI_RXSIG_RING, DAHDI_RXSIG_INITIAL }; enum { /* Span flags */ DAHDI_FLAGBIT_REGISTERED= 0, DAHDI_FLAGBIT_RUNNING = 1, DAHDI_FLAGBIT_RBS = 12, /*!< Span uses RBS signalling */ /* Channel flags */ DAHDI_FLAGBIT_DTMFDECODE= 2, /*!< Channel supports native DTMF decode */ DAHDI_FLAGBIT_MFDECODE = 3, /*!< Channel supports native MFr2 decode */ DAHDI_FLAGBIT_ECHOCANCEL= 4, /*!< Channel supports native echo cancellation */ DAHDI_FLAGBIT_HDLC = 5, /*!< Perform HDLC */ #ifdef CONFIG_DAHDI_NET DAHDI_FLAGBIT_NETDEV = 6, /*!< Send to network */ #endif DAHDI_FLAGBIT_CLEAR = 8, /*!< Clear channel */ DAHDI_FLAGBIT_AUDIO = 9, /*!< Audio mode channel */ DAHDI_FLAGBIT_OPEN = 10, /*!< Channel is open */ DAHDI_FLAGBIT_FCS = 11, /*!< Calculate FCS */ /* Reserve 12 for uniqueness with span flags */ DAHDI_FLAGBIT_LINEAR = 13, /*!< Talk to user space in linear */ DAHDI_FLAGBIT_PPP = 14, /*!< PPP is available */ DAHDI_FLAGBIT_T1PPP = 15, DAHDI_FLAGBIT_SIGFREEZE = 16, /*!< Freeze signalling */ DAHDI_FLAGBIT_NOSTDTXRX = 17, /*!< Do NOT do standard transmit and receive on every interrupt */ DAHDI_FLAGBIT_LOOPED = 18, /*!< Loopback the receive data from the channel to the transmit */ DAHDI_FLAGBIT_MTP2 = 19, /*!< Repeats last message in buffer and also discards repeating messages sent to us */ DAHDI_FLAGBIT_HDLC56 = 20, /*!< Sets the given channel (if in HDLC mode) to use 56K HDLC instead of 64K */ DAHDI_FLAGBIT_BUFEVENTS = 21, /*!< Report buffer events */ DAHDI_FLAGBIT_TXUNDERRUN = 22, /*!< Transmit underrun condition */ DAHDI_FLAGBIT_RXOVERRUN = 23, /*!< Receive overrun condition */ DAHDI_FLAGBIT_DEVFILE = 25, /*!< Channel has a sysfs dev file */ }; #ifdef CONFIG_DAHDI_NET /** * have_netdev() - Return true if a channel has an associated network device. * @chan: Then channel to check. * */ static inline int dahdi_have_netdev(const struct dahdi_chan *chan) { return test_bit(DAHDI_FLAGBIT_NETDEV, &chan->flags); } #else static inline int dahdi_have_netdev(const struct dahdi_chan *chan) { return 0; } #endif struct dahdi_count { __u32 fe; /*!< Framing error counter */ __u32 cv; /*!< Coding violations counter */ __u32 bpv; /*!< Bipolar Violation counter */ __u32 crc4; /*!< CRC4 error counter */ __u32 ebit; /*!< current E-bit error count */ __u32 fas; /*!< current FAS error count */ __u32 be; /*!< current bit error count */ __u32 prbs; /*!< current PRBS detected pattern */ __u32 errsec; /*!< errored seconds */ }; /* map flagbits to flag masks */ #define DAHDI_FLAG(x) (1 << (DAHDI_FLAGBIT_ ## x)) /*! This is a redefinition of the flags from above to allow use of the * legacy drivers that do not use the kernel atomic bit testing and * changing routines. * * See the above descriptions for DAHDI_FLAGBIT_.... for documentation * about function. */ /* Span flags */ #define DAHDI_FLAG_REGISTERED DAHDI_FLAG(REGISTERED) #define DAHDI_FLAG_RUNNING DAHDI_FLAG(RUNNING) #define DAHDI_FLAG_RBS DAHDI_FLAG(RBS) /* Channel flags */ #define DAHDI_FLAG_DTMFDECODE DAHDI_FLAG(DTMFDECODE) #define DAHDI_FLAG_MFDECODE DAHDI_FLAG(MFDECODE) #define DAHDI_FLAG_ECHOCANCEL DAHDI_FLAG(ECHOCANCEL) #define DAHDI_FLAG_HDLC DAHDI_FLAG(HDLC) /* #define DAHDI_FLAG_NETDEV DAHDI_FLAG(NETDEV) */ #define DAHDI_FLAG_CLEAR DAHDI_FLAG(CLEAR) #define DAHDI_FLAG_AUDIO DAHDI_FLAG(AUDIO) #define DAHDI_FLAG_OPEN DAHDI_FLAG(OPEN) #define DAHDI_FLAG_FCS DAHDI_FLAG(FCS) /* Reserve 12 for uniqueness with span flags */ #define DAHDI_FLAG_LINEAR DAHDI_FLAG(LINEAR) #define DAHDI_FLAG_PPP DAHDI_FLAG(PPP) #define DAHDI_FLAG_T1PPP DAHDI_FLAG(T1PPP) #define DAHDI_FLAG_SIGFREEZE DAHDI_FLAG(SIGFREEZE) #define DAHDI_FLAG_NOSTDTXRX DAHDI_FLAG(NOSTDTXRX) #define DAHDI_FLAG_LOOPED DAHDI_FLAG(LOOPED) #define DAHDI_FLAG_MTP2 DAHDI_FLAG(MTP2) #define DAHDI_FLAG_HDLC56 DAHDI_FLAG(HDLC56) #define DAHDI_FLAG_BUFEVENTS DAHDI_FLAG(BUFEVENTS) #define DAHDI_FLAG_TXUNDERRUN DAHDI_FLAG(TXUNDERRUN) #define DAHDI_FLAG_RXOVERRUN DAHDI_FLAG(RXOVERRUN) struct file; struct dahdi_span_ops { struct module *owner; /*!< Which module is exporting this span. */ /* ==== Span Callback Operations ==== */ /*! Req: Set the requested chunk size. This is the unit in which you must report results for conferencing, etc */ int (*setchunksize)(struct dahdi_span *span, int chunksize); /*! Opt: Configure the span (if appropriate) */ int (*spanconfig)(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc); /*! Opt: Start the span */ int (*startup)(struct file *file, struct dahdi_span *span); /*! Opt: Shutdown the span */ int (*shutdown)(struct dahdi_span *span); /*! Opt: Enable maintenance modes */ int (*maint)(struct dahdi_span *span, int mode); #ifdef DAHDI_SYNC_TICK /*! Opt: send sync to spans. Called in hard_irq context with chan_lock * held.*/ void (*sync_tick)(struct dahdi_span *span, int is_master); #endif /* ==== Channel Callback Operations ==== */ /*! Opt: Set signalling type (if appropriate) */ int (*chanconfig)(struct file *file, struct dahdi_chan *chan, int sigtype); /*! Opt: Prepare a channel for I/O */ int (*open)(struct dahdi_chan *chan); /*! Opt: Close channel for I/O */ int (*close)(struct dahdi_chan *chan); /*! Opt: IOCTL */ int (*ioctl)(struct dahdi_chan *chan, unsigned int cmd, unsigned long data); /* Okay, now we get to the signalling. You have several options: */ /* Option 1: If you're a T1 like interface, you can just provide a rbsbits function and we'll assert robbed bits for you. Be sure to set the DAHDI_FLAG_RBS in this case. */ /*! Opt: If the span uses A/B bits, set them here */ int (*rbsbits)(struct dahdi_chan *chan, int bits); /*! Option 2: If you don't know about sig bits, but do have their equivalents (i.e. you can disconnect battery, detect off hook, generate ring, etc directly) then you can just specify a sethook function, and we'll call you with appropriate hook states to set. Still set the DAHDI_FLAG_RBS in this case as well */ int (*hooksig)(struct dahdi_chan *chan, enum dahdi_txsig hookstate); /*! Option 3: If you can't use sig bits, you can write a function which handles the individual hook states */ int (*sethook)(struct dahdi_chan *chan, int hookstate); /*! Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */ void (*hdlc_hard_xmit)(struct dahdi_chan *chan); /*! If the watchdog detects no received data, it will call the watchdog routine */ int (*watchdog)(struct dahdi_span *span, int cause); #ifdef DAHDI_AUDIO_NOTIFY /*! Opt: audio is used, don't optimize out */ int (*audio_notify)(struct dahdi_chan *chan, int yes); #endif /*! Opt: Enable preechocan stream from inline HW echocanceler. */ int (*enable_hw_preechocan)(struct dahdi_chan *chan); /*! Opt: Disable preechocan stream from inline HW echocanceler. */ void (*disable_hw_preechocan)(struct dahdi_chan *chan); /*! Opt: Dacs the contents of chan2 into chan1 if possible */ int (*dacs)(struct dahdi_chan *chan1, struct dahdi_chan *chan2); /*! Opt: Provide echo cancellation on a channel */ int (*echocan_create)(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); /*! Opt: Provide the name of the echo canceller on a channel */ const char *(*echocan_name)(const struct dahdi_chan *chan); }; struct dahdi_span { spinlock_t lock; char name[40]; /*!< Span name */ char desc[80]; /*!< Span description */ const char *spantype; /*!< span type in text form */ const char *manufacturer; /*!< span's device manufacturer */ char devicetype[80]; /*!< span's device type */ char location[40]; /*!< span device's location in system */ int deflaw; /*!< Default law (DAHDI_MULAW or DAHDI_ALAW) */ int alarms; /*!< Pending alarms on span */ unsigned long flags; u8 cannot_provide_timing:1; int irq; /*!< IRQ for this span's hardware */ int lbo; /*!< Span Line-Buildout */ int lineconfig; /*!< Span line configuration */ int linecompat; /*!< Span line compatibility (0 for analog spans)*/ int channels; /*!< Number of channels in span */ int txlevel; /*!< Tx level */ int rxlevel; /*!< Rx level */ int syncsrc; /*!< current sync src (gets copied here) */ struct dahdi_count count; /*!< Performance and Error counters */ int maintstat; /*!< Maintenance state */ int mainttimer; /*!< Maintenance timer */ int irqmisses; /*!< Interrupt misses */ int timingslips; /*!< Clock slips */ struct dahdi_chan **chans; /*!< Member channel structures */ const struct dahdi_span_ops *ops; /*!< span callbacks. */ /* Used by DAHDI only -- no user servicable parts inside */ int spanno; /*!< Span number for DAHDI */ int offset; /*!< Offset within a given card */ int lastalarms; /*!< Previous alarms */ #ifdef CONFIG_DAHDI_WATCHDOG int watchcounter; int watchstate; #endif #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; #endif struct list_head node; }; struct dahdi_transcoder_channel { void *pvt; struct dahdi_transcoder *parent; wait_queue_head_t ready; __u32 built_fmts; #define DAHDI_TC_FLAG_BUSY 1 #define DAHDI_TC_FLAG_CHAN_BUILT 2 #define DAHDI_TC_FLAG_NONBLOCK 3 #define DAHDI_TC_FLAG_DATA_WAITING 4 unsigned long flags; u32 dstfmt; u32 srcfmt; }; static inline int dahdi_tc_is_built(struct dahdi_transcoder_channel *dtc) { return test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); } static inline void dahdi_tc_set_built(struct dahdi_transcoder_channel *dtc) { set_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); } static inline void dahdi_tc_clear_built(struct dahdi_transcoder_channel *dtc) { clear_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); } static inline int dahdi_tc_is_nonblock(struct dahdi_transcoder_channel *dtc) { return test_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); } static inline void dahdi_tc_set_nonblock(struct dahdi_transcoder_channel *dtc) { set_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); } static inline void dahdi_tc_clear_nonblock(struct dahdi_transcoder_channel *dtc) { clear_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); } static inline int dahdi_tc_is_data_waiting(struct dahdi_transcoder_channel *dtc) { return test_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); } static inline int dahdi_tc_is_busy(struct dahdi_transcoder_channel *dtc) { return test_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); } static inline void dahdi_tc_set_busy(struct dahdi_transcoder_channel *dtc) { set_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); } static inline void dahdi_tc_clear_busy(struct dahdi_transcoder_channel *dtc) { clear_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); } static inline void dahdi_tc_set_data_waiting(struct dahdi_transcoder_channel *dtc) { set_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); } static inline void dahdi_tc_clear_data_waiting(struct dahdi_transcoder_channel *dtc) { clear_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); } struct dahdi_transcoder { struct list_head active_list_node; struct list_head registration_list_node; char name[80]; int numchannels; unsigned int srcfmts; unsigned int dstfmts; struct file_operations fops; int (*allocate)(struct dahdi_transcoder_channel *channel); int (*release)(struct dahdi_transcoder_channel *channel); /* Transcoder channels */ struct dahdi_transcoder_channel channels[0]; }; #define DAHDI_WATCHDOG_NOINTS (1 << 0) #define DAHDI_WATCHDOG_INIT 1000 #define DAHDI_WATCHSTATE_UNKNOWN 0 #define DAHDI_WATCHSTATE_OK 1 #define DAHDI_WATCHSTATE_RECOVERING 2 #define DAHDI_WATCHSTATE_FAILED 3 struct dahdi_dynamic { char addr[40]; char dname[20]; int err; struct kref kref; long rxjif; unsigned short txcnt; unsigned short rxcnt; struct dahdi_span span; struct dahdi_chan *chans[256]; struct dahdi_dynamic_driver *driver; void *pvt; int timing; int master; unsigned char *msgbuf; struct list_head list; }; struct dahdi_dynamic_driver { /*! Driver name (e.g. Eth) */ const char *name; /*! Driver description */ const char *desc; /*! Create a new transmission pipe */ int (*create)(struct dahdi_dynamic *d, const char *address); /*! Destroy a created transmission pipe */ void (*destroy)(struct dahdi_dynamic *d); /*! Transmit a given message */ void (*transmit)(struct dahdi_dynamic *d, u8 *msg, size_t msglen); /*! Flush any pending messages */ int (*flush)(void); struct list_head list; struct module *owner; }; /*! \brief Receive a dynamic span message */ void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen); /*! \brief Register a dynamic driver */ int dahdi_dynamic_register_driver(struct dahdi_dynamic_driver *driver); /*! \brief Unregister a dynamic driver */ void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *driver); int _dahdi_receive(struct dahdi_span *span); /*! Receive on a span. The DAHDI interface will handle all the calculations for all member channels of the span, pulling the data from the readchunk buffer */ static inline int dahdi_receive(struct dahdi_span *span) { unsigned long flags; int ret; local_irq_save(flags); ret = _dahdi_receive(span); local_irq_restore(flags); return ret; } int _dahdi_transmit(struct dahdi_span *span); /*! Prepare writechunk buffers on all channels for this span */ static inline int dahdi_transmit(struct dahdi_span *span) { unsigned long flags; int ret; local_irq_save(flags); ret = _dahdi_transmit(span); local_irq_restore(flags); return ret; } /*! Abort the buffer currently being receive with event "event" */ void dahdi_hdlc_abort(struct dahdi_chan *ss, int event); /*! Indicate to DAHDI that the end of frame was received and rotate buffers */ void dahdi_hdlc_finish(struct dahdi_chan *ss); /*! Put a chunk of data into the current receive buffer */ void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes); /*! Get a chunk of data from the current transmit buffer. Returns -1 if no data * is left to send, 0 if there is data remaining in the current message to be sent * and 1 if the currently transmitted message is now done */ int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size); /*! Register a span. Returns 0 on success, -1 on failure. Pref-master is non-zero if we should have preference in being the master device */ int dahdi_register(struct dahdi_span *span, int prefmaster); /*! Allocate / free memory for a transcoder */ struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans); void dahdi_transcoder_free(struct dahdi_transcoder *ztc); /*! \brief Register a transcoder */ int dahdi_transcoder_register(struct dahdi_transcoder *tc); /*! \brief Unregister a transcoder */ int dahdi_transcoder_unregister(struct dahdi_transcoder *tc); /*! \brief Alert a transcoder */ int dahdi_transcoder_alert(struct dahdi_transcoder_channel *ztc); /*! \brief Unregister a span */ int dahdi_unregister(struct dahdi_span *span); /*! \brief Gives a name to an LBO */ const char *dahdi_lboname(int lbo); /*! \brief Tell DAHDI about changes in received rbs bits */ void dahdi_rbsbits(struct dahdi_chan *chan, int bits); /*! \brief Tell DAHDI abou changes in received signalling */ void dahdi_hooksig(struct dahdi_chan *chan, enum dahdi_rxsig rxsig); /*! \brief Queue an event on a channel */ void dahdi_qevent_nolock(struct dahdi_chan *chan, int event); /*! \brief Queue an event on a channel, locking it first */ void dahdi_qevent_lock(struct dahdi_chan *chan, int event); /*! \brief Notify a change possible change in alarm status on a channel */ void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms); /*! \brief Notify a change possible change in alarm status on a span */ void dahdi_alarm_notify(struct dahdi_span *span); /*! \brief Initialize a tone state */ void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt); /*! \brief Get a given MF tone struct, suitable for dahdi_tone_nextsample. */ struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode); /* Echo cancel a receive and transmit chunk for a given channel. This should be called by the low-level driver as close to the interface as possible. ECHO CANCELLATION IS NO LONGER AUTOMATICALLY DONE AT THE DAHDI LEVEL. dahdi_ec_chunk will not echo cancel if it should not be doing so. rxchunk is modified in-place */ void __dahdi_ec_chunk(struct dahdi_chan *ss, u8 *rxchunk, const u8 *preecchunk, const u8 *txchunk); static inline void _dahdi_ec_chunk(struct dahdi_chan *chan, u8 *rxchunk, const u8 *txchunk) { __dahdi_ec_chunk(chan, rxchunk, rxchunk, txchunk); } static inline void dahdi_ec_chunk(struct dahdi_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk) { unsigned long flags; local_irq_save(flags); _dahdi_ec_chunk(ss, rxchunk, txchunk); local_irq_restore(flags); } void _dahdi_ec_span(struct dahdi_span *span); static inline void dahdi_ec_span(struct dahdi_span *span) { unsigned long flags; local_irq_save(flags); _dahdi_ec_span(span); local_irq_restore(flags); } extern struct file_operations *dahdi_transcode_fops; /* Don't use these directly -- they're not guaranteed to be there. */ extern short __dahdi_mulaw[256]; extern short __dahdi_alaw[256]; #ifdef CONFIG_CALC_XLAW u_char __dahdi_lineartoulaw(short a); u_char __dahdi_lineartoalaw(short a); #else extern u_char __dahdi_lin2mu[16384]; extern u_char __dahdi_lin2a[16384]; #endif /*! \brief Used by dynamic DAHDI -- don't use directly */ void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)); /*! \brief Used by DAHDI HPEC module -- don't use directly */ void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data)); /*! \brief Used privately by DAHDI. Avoid touching directly */ struct dahdi_tone { int fac1; int init_v2_1; int init_v3_1; int fac2; int init_v2_2; int init_v3_2; int tonesamples; /*!< How long to play this tone before going to the next (in samples) */ struct dahdi_tone *next; /* Next tone in this sequence */ int modulate; }; static inline short dahdi_tone_nextsample(struct dahdi_tone_state *ts, struct dahdi_tone *zt) { /* follow the curves, return the sum */ int p; ts->v1_1 = ts->v2_1; ts->v2_1 = ts->v3_1; ts->v3_1 = (zt->fac1 * ts->v2_1 >> 15) - ts->v1_1; ts->v1_2 = ts->v2_2; ts->v2_2 = ts->v3_2; ts->v3_2 = (zt->fac2 * ts->v2_2 >> 15) - ts->v1_2; /* Return top 16 bits */ if (!ts->modulate) return ts->v3_1 + ts->v3_2; /* we are modulating */ p = ts->v3_2 - 32768; if (p < 0) p = -p; p = ((p * 9) / 10) + 1; return (ts->v3_1 * p) >> 15; } static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss) { /* follow the curves, return the sum */ ss->v1_1 = ss->v2_1; ss->v2_1 = ss->v3_1; ss->v3_1 = (ss->txtone * ss->v2_1 >> 15) - ss->v1_1; return ss->v3_1; } /* These are the right functions to use. */ #define DAHDI_MULAW(a) (__dahdi_mulaw[(a)]) #define DAHDI_ALAW(a) (__dahdi_alaw[(a)]) #define DAHDI_XLAW(a,c) (c->xlaw[(a)]) #ifdef CONFIG_CALC_XLAW #define DAHDI_LIN2MU(a) (__dahdi_lineartoulaw((a))) #define DAHDI_LIN2A(a) (__dahdi_lineartoalaw((a))) #define DAHDI_LIN2X(a,c) ((c)->lineartoxlaw((a))) #else /* Use tables */ #define DAHDI_LIN2MU(a) (__dahdi_lin2mu[((unsigned short)(a)) >> 2]) #define DAHDI_LIN2A(a) (__dahdi_lin2a[((unsigned short)(a)) >> 2]) /* Manipulate as appropriate for x-law */ #define DAHDI_LIN2X(a,c) ((c)->lin2x[((unsigned short)(a)) >> 2]) #endif /* CONFIG_CALC_XLAW */ /* Data formats for capabilities and frames alike (from Asterisk) */ /*! G.723.1 compression */ #define DAHDI_FORMAT_G723_1 (1 << 0) /*! GSM compression */ #define DAHDI_FORMAT_GSM (1 << 1) /*! Raw mu-law data (G.711) */ #define DAHDI_FORMAT_ULAW (1 << 2) /*! Raw A-law data (G.711) */ #define DAHDI_FORMAT_ALAW (1 << 3) /*! ADPCM (G.726, 32kbps) */ #define DAHDI_FORMAT_G726 (1 << 4) /*! ADPCM (IMA) */ #define DAHDI_FORMAT_ADPCM (1 << 5) /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ #define DAHDI_FORMAT_SLINEAR (1 << 6) /*! LPC10, 180 samples/frame */ #define DAHDI_FORMAT_LPC10 (1 << 7) /*! G.729A audio */ #define DAHDI_FORMAT_G729A (1 << 8) /*! SpeeX Free Compression */ #define DAHDI_FORMAT_SPEEX (1 << 9) /*! iLBC Free Compression */ #define DAHDI_FORMAT_ILBC (1 << 10) /*! Maximum audio format */ #define DAHDI_FORMAT_MAX_AUDIO (1 << 15) /*! Maximum audio mask */ #define DAHDI_FORMAT_AUDIO_MASK ((1 << 16) - 1) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) #define KERN_CONT "" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) #ifndef clamp #define clamp(x, low, high) min(max(low, x), high) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) /* Some distributions backported fatal_signal_pending so we'll use a macro to * override the inline function definition. */ #define fatal_signal_pending(p) \ (signal_pending((p)) && sigismember(&(p)->pending.signal, SIGKILL)) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) #ifndef __packed #define __packed __attribute__((packed)) #endif #include /* A define of 'clamp_val' happened to be added in the patch * linux-2.6-sata-prep-work-for-rhel5-3.patch kernel-2.6.spec that also * backported support for strcasecmp to some later RHEL/Centos kernels. * If you have an older kernel that breaks because strcasecmp is already * defined, somebody out-smarted us. In that case, replace the line below * with '#if 0' to get the code building, and file a bug report at * https://issues.asterisk.org/ . */ #ifndef clamp_val static inline int strcasecmp(const char *s1, const char *s2) { int c1, c2; do { c1 = tolower(*s1++); c2 = tolower(*s2++); } while (c1 == c2 && c1 != 0); return c1 - c2; } #endif /* clamp_val */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) #define kzalloc(a, b) kcalloc(1, a, b) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) #define synchronize_rcu() synchronize_kernel() #define kasprintf dahdi_kasprintf char *dahdi_kasprintf(gfp_t gfp, const char *fmt, ...); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) #if !defined(HAVE_WAIT_FOR_COMPLETION_TIMEOUT) static inline unsigned long wait_for_completion_interruptible_timeout(struct completion *x, unsigned long timeout) { /* There is a race condition here. If x->done is reset to 0 * before the call to wait_for_completion after this thread wakes. */ timeout = wait_event_interruptible_timeout(x->wait, x->done, timeout); if (timeout) wait_for_completion(x); return timeout; } #endif typedef u32 __bitwise pm_message_t; #endif /* 2.6.11 */ #endif /* 2.6.12 */ #endif /* 2.6.14 */ #endif /* 2.6.18 */ #endif /* 2.6.22 */ #endif /* 2.6.25 */ #endif /* 2.6.26 */ #endif /* 2.6.31 */ #ifndef DEFINE_SPINLOCK #define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED #endif #ifndef DEFINE_SEMAPHORE #define DEFINE_SEMAPHORE(name) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) #endif #ifndef DEFINE_MUTEX struct mutex { struct semaphore sem; }; #define DEFINE_MUTEX(name) \ struct mutex name = { \ .sem = __SEMAPHORE_INITIALIZER((name).sem, 1), \ } #define mutex_lock(_x) down(&(_x)->sem) #define mutex_unlock(_x) up(&(_x)->sem) #define mutex_init(_x) sema_init(&(_x)->sem, 1) #endif #ifndef DEFINE_PCI_DEVICE_TABLE #define DEFINE_PCI_DEVICE_TABLE(_x) \ const struct pci_device_id _x[] __devinitdata #endif #ifndef DMA_BIT_MASK #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) #endif /* WARN_ONCE first showed up in the kernel in 2.6.27 but it may have been * backported. */ #ifndef WARN_ONCE #define WARN_ONCE(condition, format...) WARN_ON_ONCE(condition) #endif #define DAHDI_CTL 0 #define DAHDI_TRANSCODE 250 #define DAHDI_TIMER 253 #define DAHDI_CHANNEL 254 #define DAHDI_PSEUDO 255 /* prink-wrapper macros */ #define DAHDI_PRINTK(level, category, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: " fmt, #level, category, \ THIS_MODULE->name, ## __VA_ARGS__) #define span_printk(level, category, span, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: span-%d: " fmt, #level, \ category, THIS_MODULE->name, (span)->spanno, ## __VA_ARGS__) #define chan_printk(level, category, chan, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: %d: " fmt, #level, \ category, THIS_MODULE->name, (chan)->channo, ## __VA_ARGS__) #define dahdi_err(fmt, ...) DAHDI_PRINTK(ERR, "", fmt, ## __VA_ARGS__) #define span_info(span, fmt, ...) span_printk(INFO, "", span, fmt, \ ## __VA_ARGS__) #define span_notice(span, fmt, ...) span_printk(NOTICE, "", span, fmt, \ ## __VA_ARGS__) #define span_err(span, fmt, ...) span_printk(ERR, "", span, fmt, \ ## __VA_ARGS__) #define chan_notice(chan, fmt, ...) chan_printk(NOTICE, "", chan, fmt, \ ## __VA_ARGS__) #define chan_err(chan, fmt, ...) chan_printk(ERR, "", chan, fmt, \ ## __VA_ARGS__) /* The dbg_* ones use a magical variable 'debug' and the user should be * aware of that. */ #ifdef DAHDI_PRINK_MACROS_USE_debug #ifndef BIT /* added in 2.6.24 */ #define BIT(i) (1UL << (i)) #endif /* Standard debug bit values. Any module may define others. They must * be of the form DAHDI_DBG_* */ #define DAHDI_DBG_GENERAL BIT(0) #define DAHDI_DBG_DEVICES BIT(7) /* instantiation/destruction etc. */ #define dahdi_dbg(bits, fmt, ...) \ ((void)((debug & (DAHDI_DBG_ ## bits)) && DAHDI_PRINTK(DEBUG, \ "-" #bits, "%s: " fmt, __func__, ## __VA_ARGS__))) #define span_dbg(bits, span, fmt, ...) \ ((void)((debug & (DAHDI_DBG_ ## bits)) && \ span_printk(DEBUG, "-" #bits, span, "%s: " \ fmt, __func__, ## __VA_ARGS__))) #define chan_dbg(bits, chan, fmt, ...) \ ((void)((debug & (DAHDI_DBG_ ## bits)) && \ chan_printk(DEBUG, "-" #bits, chan, \ "%s: " fmt, __func__, ## __VA_ARGS__))) #endif /* DAHDI_PRINK_MACROS_USE_debug */ #endif /* _DAHDI_KERNEL_H */ dahdi-linux-2.5.0.1/include/dahdi/Kbuild0000644000175000017500000000012711026016414017633 0ustar tzafrirtzafrirheader-y += kernel.h header-y += user.h header-y += wctdm_user.h header-y += version.h dahdi-linux-2.5.0.1/include/dahdi/dahdi_config.h0000644000175000017500000001215711511111643021252 0ustar tzafrirtzafrir/* * DAHDI configuration options * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _DAHDI_CONFIG_H #define _DAHDI_CONFIG_H #ifdef __KERNEL__ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #include #endif #endif /* DAHDI compile time options */ /* These default tone lengths are in units of milliseconds. */ #define DAHDI_CONFIG_DEFAULT_DTMF_LENGTH 100 #define DAHDI_CONFIG_DEFAULT_MFR1_LENGTH 68 #define DAHDI_CONFIG_DEFAULT_MFR2_LENGTH 100 #define DAHDI_CONFIG_PAUSE_LENGTH 500 /* * Uncomment if you have a European phone, or any other phone with a * short flash time. * This will stop the flash being mis-detected as a pulse dial "1" on * phones with short flashes */ /* #define SHORT_FLASH_TIME */ /* * Uncomment to disable calibration and/or DC/DC converter tests * (not generally recommended) */ /* #define NO_CALIBRATION */ /* #define NO_DCDC */ /* * Boost ring voltage (Higher ring voltage, takes more power) * Note: this only affects the wcfxsusb and wcusb drivers; all other * drivers have a 'boostringer' module parameter. */ /* #define BOOST_RINGER */ /* * Define CONFIG_CALC_XLAW if you have a small number of channels and/or * a small level 2 cache, to optimize for few channels * */ /* #define CONFIG_CALC_XLAW */ /* * Define if you want MMX optimizations in DAHDI * * Note: CONFIG_DAHDI_MMX is generally incompatible with AMD * processors and can cause system instability! * */ /* #define CONFIG_DAHDI_MMX */ /* We now use the linux kernel config to detect which options to use */ /* You can still override them below */ #if defined(CONFIG_HDLC) || defined(CONFIG_HDLC_MODULE) #define DAHDI_HDLC_TYPE_TRANS #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3) #define HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT #endif #endif /* * Uncomment CONFIG_DAHDI_NET to enable SyncPPP, CiscoHDLC, and Frame Relay * support. */ /* #define CONFIG_DAHDI_NET */ /* * Uncomment for Generic PPP support (i.e. DAHDIRAS) */ #if defined(CONFIG_PPP) || defined(CONFIG_PPP_MODULE) /* #define CONFIG_DAHDI_PPP */ #endif /* * Uncomment to enable "watchdog" to monitor if interfaces * stop taking interrupts or otherwise misbehave */ /* #define CONFIG_DAHDI_WATCHDOG */ /* * Uncomment the following to include extra debugging output. */ /* #define CONFIG_DAHDI_DEBUG */ /* * Uncomment for Non-standard FXS groundstart start state (A=Low, B=Low) * particularly for CAC channel bank groundstart FXO ports. */ /* #define CONFIG_CAC_GROUNDSTART */ /* * Define CONFIG_DAHDI_CORE_TIMER if you would like dahdi to always provide a * timing source regardless of which spans / drivers are configured. */ #define CONFIG_DAHDI_CORE_TIMER /* * Define CONFIG_DAHDI_NO_ECHOCAN_DISABLE to prevent the 2100Hz tone detector * from disabling any installed software echocan. * */ /* #define CONFIG_DAHDI_NO_ECHOCAN_DISABLE */ /* * Define if you would like to allow software echocans to process the tx audio * in addition to the rx audio. Used for things like DC removal. * */ /* #define CONFIG_DAHDI_ECHOCAN_PROCESS_TX */ /* * Uncomment if you happen have an early TDM400P Rev H which * sometimes forgets its PCI ID to have wcfxs match essentially all * subvendor ID's */ /* #define TDM_REVH_MATCHALL */ /* * Uncomment the following if you want to support E&M trunks being * able to "flash" after going off-hook (dont ask why, just nod :-) ). * * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!! * */ /* #define EMFLASH */ /* * Uncomment the following if you want to support E&M trunks being * able to recognize Dial Pulse digits. This can validly be enabled * so that either Dial Pulse or DTMF/MF tones will be recognized, but * the drawback is that the ONHOOK will take an extra {rxwinktime} * to be recognized. * * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!! * */ /* #define EMPULSE */ /* * Comment out the following if you dont want events to indicate the * beginning of an incoming ring. Most non-Asterisk applications will * want this commented out. */ #define RINGBEGIN /* * Uncomment the following if you need to support FXS Flash events. * Most applications will want this commented out. */ /* #define FXSFLASH */ /* * Enable sync_tick() calls. Allows low-level drivers to synchronize * their internal clocks to the DAHDI master clock. */ #define DAHDI_SYNC_TICK /* * Skip processing PCM if low-level driver won't use it anyway */ /* #define OPTIMIZE_CHANMUTE */ /* * Pass DAHDI_AUDIOMODE to channel driver as well */ /* #define DAHDI_AUDIO_NOTIFY */ /* * Creates an interface for mirroring the raw channel data out to a pseudo-chan */ /* #define CONFIG_DAHDI_MIRROR */ #endif dahdi-linux-2.5.0.1/build_tools/0000755000175000017500000000000011631523354016331 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/build_tools/genmodconf0000755000175000017500000000533311032514730020373 0ustar tzafrirtzafrir#!/bin/sh # this script makes an attempt to build a proper set of rules # for loading the DAHDI modules and automatically running dahdi_xcfg # # it accepts two parameters: # the root prefix to be used for finding/creating the files # the list of module names being installed # # the process is as follows: # # the file can be located at /etc/modprobe.conf (combined with all # other rules), /etc/modprobe.d/dahdi (DAHDI only) or /etc/modules.d/dahdi # (DAHDI only) # # when the file is DAHDI rules only, then we don't preserve the existing # contents of the file; the system administrator can put desired options and # overrides in a separate file with a name that appears earlier in the sort # order, so there is no need to edit the file produced by this script # # when the file is combined with all other rules, then we make a backup # of it and remove all the old DAHDI rules we can find, replacing them with # new ones # # in addition, versions of module-init-tools 3.2.0 and later # have the ability to pass module parameters specified on the modprobe command # line to commands in 'install' rules, thus keeping them from being lost, so # we try to determine what version is installed and take advantage of that toolver=`/sbin/modprobe --version 2>/dev/null| awk '{print $3}' | cut -d. -f2 | cut -d- -f1` if [ ${toolver} -ge 2 ]; then cmdopts=\$CMDLINE_OPTS fi if [ -d ${1}/etc/modprobe.d ]; then target=${1}/etc/modprobe.d/dahdi elif [ -d ${1}/etc/modules.d ]; then target=${1}/etc/modules.d/dahdi elif [ -f ${1}/etc/modprobe.conf ]; then target=${1}/etc/modprobe.conf combined=1 elif [ -f ${1}/etc/conf.modules ]; then target=${1}/etc/conf.modules combined=1 else echo No suitable location for module rules can be found... exiting. exit 1 fi if [ -n "${combined}" ]; then if [ -f ${target} ]; then mv ${target} ${target}.bak cat ${target}.bak | grep -v "alias char-major-250" | grep -v "alias char-major-196" > ${target} fi else if [ -f ${target} ]; then mv ${target} ${target}.bak fi echo "# automatically generated file; do not edit" > ${target} fi echo Building ${target}... for mod in ${2}; do if ! grep -q "install ${mod} " ${target}; then echo "install ${mod} /sbin/modprobe --ignore-install ${mod} ${cmdopts} && /sbin/ztcfg" >> ${target} fi done if [ -z "${combined}" ]; then echo "***" echo "*** WARNING:" echo "*** If you had custom settings in ${target}," echo "*** they have been moved to ${target}.bak." echo "***" echo "*** In the future, do not edit ${target}, but" echo "*** instead put your changes in another file" echo "*** in the same directory so that they will not" echo "*** be overwritten by future DAHDI updates." echo "***" fi dahdi-linux-2.5.0.1/build_tools/make_version_h0000755000175000017500000000016211015052402021232 0ustar tzafrirtzafrir#!/bin/sh cat << END /* * version.h * Automatically generated */ #define DAHDI_VERSION "${DAHDIVERSION}" END dahdi-linux-2.5.0.1/build_tools/kernel-doc0000755000175000017500000000325011264421321020273 0ustar tzafrirtzafrir#!/bin/sh # a wrapper to kernel-doc from the kernel source tree # # Copyright (C) 2009 by Xorcom # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # For 'man' version: build_tools/kernel-doc -f man | man -l - files="drivers/dahdi/dahdi-base.c" format="html" kernel="/lib/modules/`uname -r`/build" usage() { me=`basename $0` cat <&2 "Terminating..." ; exit 1 ; fi eval set -- "$options" while true ; do case "$1" in -f|--format) format="$2"; shift ;; -h|--help) usage; exit 0;; -k|--kernel) kernel="$2"; shift ;; --) shift ; break ;; esac shift; done if [ "$*" != '' ]; then files="$*" #FIXME: spaces fi script="$kernel/scripts/kernel-doc" $script -$format $files dahdi-linux-2.5.0.1/build_tools/make_version0000755000175000017500000000543611467042352020752 0ustar tzafrirtzafrir#!/bin/sh if [ -f ${1}/.version ]; then cat ${1}.version elif [ -f ${1}/.svnrevision ]; then echo SVN-`cat ${1}/.svnbranch`-r`cat ${1}/.svnrevision` elif [ -d ${1}/.svn ]; then PARTS=`LANG=C svn info ${1} | grep URL | awk '{print $2;}' | sed -e s:^.*/svn/${2}/:: | sed -e 's:/: :g'` BRANCH=0 TEAM=0 REV=`svnversion -c ${1} | cut -d: -f2` if [ "${PARTS}" = "trunk" ] then echo SVN-'trunk'-r${REV} exit 0 fi for PART in $PARTS do if [ ${BRANCH} != 0 ] then RESULT="${RESULT}-${PART}" break fi if [ ${TEAM} != 0 ] then RESULT="${RESULT}-${PART}" continue fi if [ "${PART}" = "branches" ] then BRANCH=1 RESULT="branch" continue fi if [ "${PART}" = "tags" ] then BRANCH=1 RESULT="tag" continue fi if [ "${PART}" = "team" ] then TEAM=1 continue fi done echo SVN-${RESULT##-}-r${REV} elif [ -d ${1}/.git ]; then # If the first log commit messages indicates that this is checked into # subversion, we'll just use the SVN- form of the revision. MODIFIED="" SVN_REV=`git log --pretty=full -1 | grep -F "git-svn-id:" | sed -e "s/.*\@\([^\s]*\)\s.*/\1/g"` if [ -z "$SVN_REV" ]; then VERSION=`git describe --long --always --tags --dirty=M 2> /dev/null` if [ $? -ne 0 ]; then if [ "`git ls-files -m | wc -l`" != "0" ]; then MODIFIED="M" fi # Some older versions of git do not support all the above # options. VERSION=GIT-`git rev-parse --short --verify HEAD`${MODIFIED} fi echo ${VERSION} else PARTS=`LANG=C git log --pretty=full | grep -F "git-svn-id:" | head -1 | awk '{print $2;}' | sed -e s:^.*/svn/$2/:: | sed -e 's:/: :g' | sed -e 's/@.*$//g'` BRANCH=0 TEAM=0 if [ "`git ls-files -m | wc -l`" != "0" ]; then MODIFIED="M" fi if [ "${PARTS}" = "trunk" ]; then echo SVN-'trunk'-r${SVN_REV}${MODIFIED} exit 0 fi for PART in $PARTS do if [ ${BRANCH} != 0 ]; then RESULT="${RESULT}-${PART}" break fi if [ ${TEAM} != 0 ]; then RESULT="${RESULT}-${PART}" continue fi if [ "${PART}" = "branches" ]; then BRANCH=1 RESULT="branch" continue fi if [ "${PART}" = "tags" ]; then BRANCH=1 RESULT="tag" continue fi if [ "${PART}" = "team" ]; then TEAM=1 continue fi done echo SVN-${RESULT##-}-r${SVN_REV}${MODIFIED} fi fi dahdi-linux-2.5.0.1/build_tools/make_static_devs0000755000175000017500000000370411336203217021563 0ustar tzafrirtzafrir#!/bin/sh set -e # make_static_devs: create static device files for DAHDI # Copyright (C) 2010 by Xorcom # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # In most cases DAHDI device files are generated by udev, # but there would be cases where you'd want to just have static device # files. Note that if you do use udev, that static device files will be # essentially deleted. BASE_DIR="/dev/dahdi" usage() { me=`basename $0` echo "$me: Generate static DAHDI device files" echo "" echo "Usage:" echo " $me [-h] [-d base_dir]" echo " -d base_dir: create under base_dir (default: $BASE_DIR)" echo " -h: this help message." } mknod_safe() { if [ -c $1 ]; then return; fi mknod "$@" } while getopts 'd:h' opt; do case "$opt" in h) usage; exit 0;; d) BASE_DIR="$OPTARG";; \?) usage; exit 1;; esac done mkdir -p "$BASE_DIR" mknod_safe "${BASE_DIR}/ctl" c 196 0 mknod_safe "${BASE_DIR}/transcode" c 196 250 mknod_safe "${BASE_DIR}/timer" c 196 253 mknod_safe "${BASE_DIR}/channel" c 196 254 mknod_safe "${BASE_DIR}/pseudo" c 196 255 # The following are not used by Asterisk itself nowadays. Some DAHDI # users still find it simpler to open them directly rather than using # /dev/dahdi/channel and the DAHDI_SPECIFY ioctl . for i in `seq 249`; do mknod_safe ${BASE_DIR}/$i c 196 $i done dahdi-linux-2.5.0.1/build_tools/builder0000755000175000017500000001126211031532363017701 0ustar tzafrirtzafrir#!/bin/sh # build_test - a build testing script # # Copyright (C) 2008 by Xorcom # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Setup: # # 0. Copy this script under build_tools/ and # # chmod +x build_tools/builder # # 1. Make sure you have git and sqlite3 installed. If the sqlite3 binary # is called differently, fix the line "SQLITE=" in the script or in # build_tools/test_build.conf . # # 2. Run: # # ./build_tools/test_kernel_git init /path/to/some/dir # # /path/to/some/dir must exist . This will download a recent kernel # git repository to /path/to/some/dir/linux-2.6 . Use # './build_tools/test_kernel_git update' to pull a fresh update there. # # 3. Run: # # ./build_tools/builder init # # # Usage: # # ./build_tools build # # The past results are in a sqlite database in the logs subdirectory. For # a simple list of results: # # ./build_tools report # # You can also look at the build log for a specific build in the logs # directory. BIN_DIR=`dirname $0` BASE_DIR=`dirname $BIN_DIR` SQLITE=sqlite3 HOSTS="localhost" LOGS_DIR="$BASE_DIR/logs" DB=$LOGS_DIR/builds.db BUILD_SCRIPT=$BIN_DIR/test_kernel_git KERNELS_localhost="2.6.12 2.6.18 2.6.25" usage() { me=`basename $0` echo "$me: test building Zaptel/DAHDI with various kernels" echo "" echo "Usage: $0 command " echo " init Create results directory and database." echo " build [] Run the test builds. The default list: " echo " $KERNELS_localhost" echo " report [] Print all results [matching ]" echo " Default is to print all the resaults." echo "" echo "Filters:" echo " failed: Only failed tests." echo " fail_type Where fail_type matches ." echo " 2.6* Only builds for a matching kernel version." echo " Else: Match a string from the build name, which " echo " is essentially the time it started." echo "" } set -e if [ -r $BIN_DIR/test_build.conf ]; then . $BIN_DIR/test_build.conf; fi # Runs the test script, logs the result, and fails if the test command # has failed. build_and_check() { test_name="$1" test_cmd="$2" log_file="$3" results_str="$4" fail_type='' set +e $BUILD_SCRIPT $test_cmd >$log_file 2>&1 rc=$? set -e if [ $rc != 0 ]; then fail_type="$test_name" echo "$results_str, $rc, '$fail_type', '$log_file');" | $SQLITE $DB fi return $rc } build_zaptel() { build_name="$1" host="$2" kvers="$3" log_base="build__${build_name}__${host}__${kvers}" log_base_full="$LOGS_DIR/$log_base" log_file="$log_base_full.log" results_str="INSERT INTO results VALUES ('$build_name', '$host', '$kvers'" # Due to 'set -e' a failed test exists the script. build_and_check setver "setver $kvers" "$log_file" "$results_str" build_and_check clean "test clean" "$log_file" "$results_str" build_and_check build "build" "$log_file" "$results_str" # If we got here, all was well. echo "$results_str, 0, 'complete', '$log_file');" | $SQLITE $DB } case "$1" in init) mkdir -p $LOGS_DIR cat <&2 "$0: Unknown command '$1'. Aborting." exit 1 esac dahdi-linux-2.5.0.1/build_tools/test_kernel_git0000755000175000017500000000452611031532363021442 0ustar tzafrirtzafrir#!/bin/sh set -e GIT_URL=git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git CONF_FILE=build_tools/git_test.conf usage() { me=`basename $0` echo "$me: test building DAHDI vs. kernel from git" echo "Usage:" echo " $me checkout Pull a kernel version into " echo " $me update Update (pull) the kernel tree." echo " $me setver Set the kernel version" echo " $me versions Print available versions" echo " $me version Print current (kernel) version" echo " $me version_driver Print the version of DAHDI" echo " $me build Test-build" echo " $me git Run " echo "" echo " $me versions [pattern] List available versions." } # Set a variable in $CONF_FILE # The format of CONF_FILE is assumed to be: # VAR=value # in shell syntax. "value" may be quoted. # "value should not contain a '|' character. set_var() { var="$1" val="$2" if grep -q "^$var=" $CONF_FILE 2>/dev/null; then sed -i -e "s|^$var=.*|$var=\"$val\"|" $CONF_FILE else echo "$var=\"$val\"" >>$CONF_FILE fi } if [ -r "$CONF_FILE" ]; then . "$CONF_FILE"; fi if echo "$CONF_FILE" | grep -qv '^/'; then # make CONF_FILE an absolute path: CONF_FILE="$PWD/$CONF_FILE" fi command="$1" case "$command" in checkout) kernel_dir="$2" cd "$kernel_dir" git clone $GIT_URL set_var kernel_dir "$kernel_dir/linux-2.6" ;; update) cd "$kernel_dir" git pull ;; git) cd "$kernel_dir" shift git "$@" ;; versions) cd "$kernel_dir" git tag -l $2 | cut -c2- ;; version) cd "$kernel_dir" echo "Configured: $kernel_ver" echo -n "Actual: " git describe | cut -c2- ;; version_driver) version_h=include/dahdi/version.h make $version_h >/dev/null awk -F'"' '/DAHDI_VERSION/{print $2}' $version_h ;; setver) kernel_ver="$2" tag="v$kernel_ver" cd "$kernel_dir" git-reset --hard "$tag" make distclean make defconfig modules_prepare set_var kernel_ver "$kernel_ver" ;; test|build) # you can pass extra parameters to the make command in # two ways: # 1. Set the value of MAKE_PARAMS in git_test.conf . # 2. Any extra command-line parameter. shift make KSRC="$kernel_dir" KVERS=$kernel_ver $MAKE_PARAMS "$@" ;; *) echo "$0: no such command $command. Aborting." usage exit 1 ;; esac dahdi-linux-2.5.0.1/build_tools/uninstall-modules0000755000175000017500000000310211034745636021740 0ustar tzafrirtzafrir#!/bin/sh # This script takes two arguments: a top-level module name, and a kernel version string # # It will search the entire /lib/modules directory tree for the given kernel version, # and find all modules that are dependent (even indirectly) on the specified module. # After producing that list, it will remove all those modules. base="${1}" deptree="${base}" rmlist="" founddep=1 checkmod() { SAVEIFS="${IFS}" IFS="," modname=`basename ${1}` modname=${modname%.ko} if test "${modname}" = "${base}"; then rmlist="${rmlist} ${1}" IFS="${SAVEIFS}" return fi for dep in `modinfo -F depends ${1}`; do for mod in ${deptree}; do if test "${dep}" = "${mod}"; then addit=1 for checkmod in ${deptree}; do if test "${checkmod}" = "${modname}"; then addit=0 break fi done if test "${addit}" = "1"; then deptree="${deptree},${modname%.ko}" rmlist="${rmlist} ${1}" founddep=1 fi fi done done IFS="${SAVEIFS}" } while test "${founddep}" = "1"; do founddep=0 find /lib/modules/${2}/misc -name \*.ko -print > /tmp/modlist.$$ 2> /dev/null find /lib/modules/${2}/extra -name \*.ko -print >> /tmp/modlist.$$ 2> /dev/null find /lib/modules/${2}/zaptel -name \*.ko -print >> /tmp/modlist.$$ 2> /dev/null find /lib/modules/${2}/dahdi -name \*.ko -print >> /tmp/modlist.$$ 2> /dev/null exec 9<&0 < /tmp/modlist.$$ while read mod; do checkmod ${mod} done exec 0<&9 9<&- rm /tmp/modlist.$$ done if test -n "${rmlist}"; then for mod in ${rmlist}; do rm -f ${mod} done fi dahdi-linux-2.5.0.1/build_tools/genudevrules0000755000175000017500000000225411077672705021003 0ustar tzafrirtzafrir#!/bin/sh ver=`udevinfo -V | cut -f3 -d" "` if [ -z "${ver}" ]; then # Not found - try udevadm ver=`udevadm info -V | cut -f3 -d" "` if [ -z "${ver}" ]; then # nobody has that old version, anyway. ver=54 fi fi # udev versions prior to 055 use a single '=' for matching key values # udev versions 055 and later support '==' for that purpose, and versions # beyond 092 will probably make it mandatory # # very old versions of udev required naming rules and permissions rules to be # in separate files, but it's not clear at what version number that changed if [ ${ver} -gt 54 ]; then match="==" else match="=" fi cat <&2 "$0:dahdi-linux dir '$LINUX_DIR' does not exits. Aborting". exit 1 fi set -e LINUX_DIR_FULL=`(cd $LINUX_DIR; pwd)` set_tools_dir() { if [ ! -d "$TOOLS_DIR" ]; then echo >&2 "$0:dahdi-tools dir '$TOOLS_DIR' does not exits. Aborting". exit 1 fi TOOLS_DIR_FULL=`(cd $TOOLS_DIR; pwd)` } # Give priority to our installed binaries: PATH=$DESTDIR/sbin:$DESTDIR/usr/sbin:$PATH export PATH # TODO: If you already use PERL5DIR, please fix this part: PERL5LIB="$DESTDIR/$PERLLIBDIR" export PERL5LIB # used in xpp_fxloader: FIRMWARE_DIR="$DESTDIR/usr/share/dahdi" export FIRMWARE_DIR ASTRIBANK_TOOL="$DESTDIR/usr/sbin/astribank_tool" export ASTRIBANK_TOOL ASTRIBANK_HEXLOAD="$DESTDIR/usr/sbin/astribank_hexload" export ASTRIBANK_HEXLOAD # make sure Astribank initialization scripts are from our tree. xpp_ARGS="$xpp_ARGS initdir=$FIRMWARE_DIR" #dahdi_ARGS="$dahdi_ARGS initdir=$FIRMWARE_DIR" if [ "$DYNAMIC_LOC" = 'yes' ]; then MODULES_LOAD="$MODULES_LOAD dahdi_dynamic dahdi_dynamic_loc" fi # the same as xpp/utils/dahdi_drivers . # With the remote mode, I can't rely on files in the source directory. dahdi_drivers() { perl -MDahdi::Hardware -e ' my @drivers = Dahdi::Hardware->drivers; print join(" ", @drivers); ' } # Add modules for existing hardware on the system for the list of # modules to load. # # As module loading is manual with insmod, some manual fixes are needed. set_modules_to_load() { for mod in `dahdi_drivers`; do case "$mod" in xpp_usb) MODULES_LOAD="$MODULES_LOAD xpp/xpp xpp/xpd_fxs" MODULES_LOAD="$MODULES_LOAD xpp/xpd_fxo xpp/xpd_pri" if [ -r "$MODULES_DIR/xpp/xpd_bri.ko" ]; then MODULES_LOAD="$MODULES_LOAD xpp/xpd_bri" fi if [ -r "$MODULES_DIR/xpp/xpd_echo.ko" ]; then MODULES_LOAD="$MODULES_LOAD xpp/xpd_echo" fi MODULES_LOAD="$MODULES_LOAD xpp/xpp_usb" ;; wctdm24xxp | wcte12xp) # FIXME: better automation of the voicebus # dependency: MODULES_LOAD="$MODULES_LOAD voicebus/dahdi_voicebus $mod/$mod" EXTRA_MODS="$EXTRA_MODS firmware_class" ;; wct4xxp | wcte12xp | wctc4xp | wcb4xxp) MODULES_LOAD="$MODULES_LOAD $mod/$mod" ;; wanpipe) : # requires different handling ;; *) MODULES_LOAD="$MODULES_LOAD $mod" ;; esac done } # Initialize the Xorcom Astribank (xpp/) using perl utiliites: # intended to replace all the the three functions below if user has # installed the dahdi-perl utilities. xpp_startup() { # do nothing if there are no astribank devices: if ! grep -q connected /proc/xpp/xbuses 2>/dev/null; then return 0; fi echo "Waiting for Astribank devices to initialize:" "$FIRMWARE_DIR/waitfor_xpds" # Asusmes a recent dahdi-tools # overriding locales for the above two, as perl can be noisy # when locales are missing. # No register all the devices if they didn't auto-register: LC_ALL=C dahdi_registration on # this one could actually be run after dahdi_cfg: LC_ALL=C xpp_sync "$XPP_SYNC" } # recursively unload a module and its dependencies, if possible. # where's modprobe -r when you need it? # inputs: module to unload. # returns: the result from unload_module() { module="$1" line=`lsmod 2>/dev/null | grep "^$1 " || :` if [ "$line" = '' ]; then return; fi # module was not loaded set -- $line # $1: the original module, $2: size, $3: refcount, $4: deps list mods=`echo $4 | tr , ' '` ec_modules="" # xpp_usb keeps the xpds below busy if an xpp hardware is # connected. Hence must be removed before them: case "$module" in xpd_*) mods="xpp_usb $mods";; esac for mod in $mods; do case "$mod" in dahdi_echocan_*) ec_modules="$mod $ec_modules" ;; *) # run in a subshell, so it won't step over our vars: (unload_module $mod) ;; esac done # Now that all the other dependencies are unloaded, we can unload the # dahdi_echocan modules. The drivers that register spans may keep # references on the echocan modules before they are unloaded. for mod in $ec_modules; do (unload_module $mod) done rmmod $module } load_dynamic() { if [ "$DYNAMIC_LOC" != yes ]; then return; fi local conf_file="$DESTDIR/etc/dahdi/dynamic.conf" if [ ! -r "$conf_file" ]; then cat <"$conf_file" dynamic=loc,1:0,5,0 dynamic=loc,1:1,5,0 EOF fi dahdi_cfg -c "$conf_file" } unload_dynamic() { if [ "$DYNAMIC_LOC" != yes ]; then return; fi local conf_file="$DESTDIR/etc/dahdi/dynamic.conf" if [ ! -r "$conf_file" ]; then return; fi dahdi_cfg -c "$conf_file" -s || : } genconf() { GENCONF_PARAMETERS=$DESTDIR/etc/dahdi/genconf_parameters \ DAHDI_CONF_FILE=$DESTDIR/etc/dahdi/system.conf \ DAHDI_MODS_FILE=$DESTDIR/etc/dahdi/modules \ CHAN_DAHDI_CHANNELS_FILE=$DESTDIR/etc/asterisk/dahdi-channels.conf \ dahdi_genconf if [ "$DYNAMIC_LOC" = yes ]; then cat "$DESTDIR/etc/dahdi/dynamic.conf" >>"$DESTDIR/etc/dahdi/system.conf" fi dahdi_cfg -c $DESTDIR/etc/dahdi/system.conf # TODO: fxotune, hpec } run_asterisk() { $AST_SCRIPT start } usage() { me=`basename $0` echo "$me: Run DAHDI in a test environment" echo 'Version: $Id: live_dahdi 10057 2011-07-20 16:50:34Z tzafrir $' echo '' echo "Usage: equivalent of:" echo "$me configure ./configure" echo "$me install make install" echo "$me config make config" echo "$me unload /etc/init.d/dahdi stop" echo "$me load /etc/init.d/dahdi start" echo "$me reload /etc/init.d/dahdi restart" echo "$me xpp-firm (Reset and load xpp firmware)" echo "$me genconf dahdi_genconf; dahdi_cfg" echo "$me asterisk /etc/init.d/asterisk start" echo "$me symlink_ast symlink dahdi-channels.conf" echo "$me rsync TARGET (copy filea to /tmp/live in host TARGET)" echo "$me exec COMMAND (Run COMMAND in 'live' environment)" echo "" echo "dahdi-linux: $LINUX_DIR" echo "dahdi-tools: $TOOLS_DIR" } case "$1" in configure) shift set_tools_dir cd "$TOOLS_DIR"; ./configure --with-dahdi="$LINUX_DIR_FULL" "$@" ;; install) shift set_tools_dir cd "$LINUX_DIR"; make install DESTDIR=$DESTDIR "$@" cd "$TOOLS_DIR_FULL"; make install DESTDIR=$DESTDIR DYNFS=yes "$@" ;; config) shift set_tools_dir cd "$TOOLS_DIR"; make config DESTDIR=$DESTDIR "$@" mkdir -p $DESTDIR/etc/asterisk cat >"$FIRMWARE_DIR/live-init.conf" <&2 "$0: Error: rsync requires a target parameter". exit 1 fi # copy the script itself and the installed directory to the # target host: rsync -ai "$0" $DESTDIR "$2:$LIVE_DAHDI_RSYNC_DIR" ;; unload) # OK for Asterisk not to be running. TODO: a better test? $AST_SCRIPT stop || : unload_dynamic for mod in $REMOVE_MODULES; do unload_module $mod done ;; load) # TODO: Find a way to use modprobe. # Or implement a way to pass arguments to modules here (yuck) set_modules_to_load for mod in $EXTRA_MODS; do modprobe $mod || : # FIXME: Make this optional? done for module in $MODULES_LOAD; do eval module_args="\$`basename ${module}`_ARGS" insmod $MODULES_DIR/$module.ko $module_args done xpp_startup load_dynamic genconf # or find a way to reuse init.d start sequence. # TODO: A local copy of Asterisk, configured with dahdi_gnconf. # doable, but trickier. run_asterisk ;; genconf) genconf ;; asterisk) run_asterisk ;; symlink_ast) ln -sf "$DESTDIR/etc/asterisk/dahdi-channels.conf" /etc/asterisk/ ;; reload) $0 unload $0 load ;; exec) if [ $# -lt 2 ]; then # No command given: start a subshell in the environemnt # of the "live" system: echo >&2 "$0: Error: exec requires a command to run" exit 1 fi # Command given: run it: shift "$@" ;; xpp-firm) # Still broken. Needs to be run several times. # set XPP_HOTPLUG_DISABLED=yes in /etc/dahdi/init.conf XPP_FIRMWARE_DIR=$FIRMWARE_DIR \ "$FIRMWARE_DIR/xpp_fxloader" reset sleep 5 XPP_FIRMWARE_DIR=$FIRMWARE_DIR \ XPP_CONFIG="$DESTDIR/etc/dahdi/xpp.conf" \ "$FIRMWARE_DIR/xpp_fxloader" load ;; help|'') usage ;; *) echo >&2 "$0: Error: incorrect command \"$1\". Aborting" usage exit 1 esac dahdi-linux-2.5.0.1/build_tools/kernel-cp0000755000175000017500000000215411367477674020164 0ustar tzafrirtzafrir#!/bin/sh # A simple wrapper to the kernel.org script checkpatch.pl # Usage: # # svn diff | ./build_tools/kernel-cp - # ./build_tools/kernel-cp my.diff # ./build_tools/kernel-cp --file drivers/dahdi/wctdm.c mydir=`dirname $0` check_patch_dir="$mydir/cp" rel_path="scripts/checkpatch.pl" check_patch="$mydir/checkpatch.pl" URL='http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=scripts/checkpatch.pl;hb=HEAD' # Required files in directories in the tree SUBDIRS="fs ipc lib arch init scripts drivers kernel Documentation include" set -e if [ "$1" = 'download' ]; then if [ -x "$check_patch" ]; then exit 0 fi wget -O "$check_patch" "$URL" if [ `wc -c <"$check_patch"` -lt 1000 ]; then # already downloaded # FIXME: redirection fails on downloading and you get a # short HTML file as your "script". echo >&2 "$0: Error: Download failed". exit 1 fi chmod +x "$check_patch" exit 0 fi if [ ! -x "$check_patch" ]; then echo >&2 "Script $check_patch not found. Download it?" echo >&2 "" echo >&2 " $0 download" exit 1 fi exec $check_patch --no-tree --no-signoff "$@" dahdi-linux-2.5.0.1/.version0000644000175000017500000000001011631523343015465 0ustar tzafrirtzafrir2.5.0.1 dahdi-linux-2.5.0.1/README0000644000175000017500000011071111611603556014674 0ustar tzafrirtzafrirDAHDI Telephony Interface Driver ================================= Asterisk Development Team $Revision: 10058 $, $Date: 2011-07-20 11:50:54 -0500 (Wed, 20 Jul 2011) $ DAHDI stands for Digium Asterisk Hardware Device Interface. This package contains the kernel modules for DAHDI. For the required userspace tools see the package dahdi-tools. Supported Hardware ------------------ Digital Cards ~~~~~~~~~~~~~ - wct4xxp: * Digium TE205P/TE207P/TE210P/TE212P: PCI dual-port T1/E1/J1 * Digium TE405P/TE407P/TE410P/TE412P: PCI quad-port T1/E1/J1 * Digium TE220: PCI-Express dual-port T1/E1/J1 * Digium TE420: PCI-Express quad-port T1/E1/J1 - wcte12xp: * Digium TE120P: PCI single-port T1/E1/J1 * Digium TE121: PCI-Express single-port T1/E1/J1 * Digium TE122: PCI single-port T1/E1/J1 - wcte11xp: * Digium TE110P: PCI single-port T1/E1/J1 - wct1xxp: * Digium T100P: PCI single-port T1 * Digium E100P: PCI single-port E1 - wcb4xxp: * Digium B410: PCI quad-port BRI - tor2: Tormenta quad-span T1/E1 card from the Zapata Telephony project Analog Cards ~~~~~~~~~~~~ - wctdm24xxp: * Digium TDM2400P/AEX2400: up to 24 analog ports * Digium TDM800P/AEX800: up to 8 analog ports * Digium TDM410P/AEX410: up to 4 analog ports * Digium Hx8 Series: Up to 8 analog or BRI ports - wctdm: * Digium TDM400P: up to 4 analog ports - xpp: Xorcom Astribank: a USB connected unit of up to 32 ports (including the digital BRI and E1/T1 modules) - wcfxo: X100P, similar and clones. A simple single-port FXO card Other Drivers ~~~~~~~~~~~~~ - pciradio: Zapata Telephony PCI Quad Radio Interface - wctc4xxp: Digium hardware transcoder cards (also need dahdi_transcode) - dahdi_dynamic_eth: TDM over Ethernet (TDMoE) driver. Requires dahdi_dynamic - dahdi_dynamic_loc: Mirror a local span. Requires dahdi_dynamic Installation ------------ If all is well, you just need to run the following: make make install You'll need the utilities provided in the package dahdi-tools to configure DAHDI devices on your system. If using `sudo` to build/install, you may need to add /sbin to your PATH. If you still have problems, read further. Build Requirements ~~~~~~~~~~~~~~~~~~ gcc and friends. Generally you will need to install the package gcc. There may be cases where you will need a specific version of gcc to build kernel modules. Kernel Source / "Headers" ^^^^^^^^^^^^^^^^^^^^^^^^^ - Building DAHDI-linux requires a kernel build tree. - This should basically be at least a partial kernel source tree and most importantly, the exact kernel .config file used for the build as well as several files generated at kernel build time. - KERNEL_VERSION is the output of the command `uname -r` - If you build your own kernel, you need to point to the exact kernel build tree. Luckily for you, this will typically be pointed by the symbolic link /lib/modules/KERNEL_VERSION/build which is the location zaptel checks by default. - If you use a kernel from your distribution you will typically have a package with all the files required to build a kernel modules for your kernel image. * On Debian and Ubuntu this is +++ linux-headers-`uname -r` +++ * On Fedora, RHEL and compatibles (e.g. CentOS) and SUSE this is the kernel-devel package. Or if you run kernel-smp or kernel-xen, you need kernel-smp-devel or kernel-xen-devel, respectively. * In some distributions (e.g.: in RHEL/CentOS, Fedora, Ubuntu) the installation of the kernel-devel / kernel-headers package will be of a version that is newer than the one you currently run. In such a case you may need to upgrade the kernel package itself as well and reboot. - To point explicitly to a different build tree: set KSRC to the kernel source tree or KVERS to the exact kernel version (if "headers" are available for a different version). This parameter must be run on every calls to 'make' (e.g.: 'make clean', 'make install'). make KVERS=2.6.18.Custom make KSRC=/home/tzafrir/kernels/linus Kernel Configuration ^^^^^^^^^^^^^^^^^^^^ If you build a custom kernel, note the following configuration items: - CONFIG_CRC_CCITT must be enabled ('y' or 'm'). On 2.6 kernels this can be selected These can be selected from the "Library Routines" submenu during kernel configuration via "make menuconfig". - DAHDI will work if you disable module unloading. But you may need extra reboots. - DAHDI needs the BKL (Big Kernel Lock). This may be annoying in >=2.6.37 kernels. Make sure you enable CONFIG_BKL on those kernels. Installing to a Subtree ~~~~~~~~~~~~~~~~~~~~~~~ The following may be useful when testing the package or when preparing a package for a binary distribution (such as an rpm package) installing onto a subtree rather than on the real system. make install DESTDIR=targetdir This can be useful for any partial install target of the above (e.g: install-modules or install-programs). the targetdir must be an absolute path, at least if you install the modules. To install to a relative path you can use something like: make install-modules DESTDIR=$PWD/target Extra Modules ~~~~~~~~~~~~~ To build extra modules / modules directory not included in the DAHDI distribution, use the optional variables MODULES_EXTRA and SUBDIRS_EXTRA: make MODULES_EXTRA="mod1 mod2" make MODULES_EXTRA="mod1 mod2" SUBDIRS_EXTRA="subdir1/ subdir1/" Static Device Files ~~~~~~~~~~~~~~~~~~~ Userspace programs communicate with the DAHDI modules through special device files under /dev/dahdi . Those are normally created by udev, but if you use an embedded-type system and don't wish to use udev, you can generate them with the following script, from the source directory: ./build_tools/make_static_devs This will generate the device files under /dev/dahdi . If you need to generate them elsewhere (e.g. `tmp/newroot/dev/dahdi`) use the option -d to the script: ./build_tools/make_static_devs -d tmp/newroot/dev/dahdi Installing the B410P drivers with mISDN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DAHDI includes the wcb4xxp driver for the B410P, however, support for the B410P was historically provided by mISDN. If you would like to use the mISDN driver with the B410P, please comment out the wcb4xxp line in /etc/dahdi/modules. This will prevent DAHDI from loading wcb4xxp which will conflict with the mISDN driver. To install the mISDN driver for the B410P, please see http://www.misdn.org for more information, but the following sequence of steps is roughly equivalent to 'make b410p' from previous releases. wget http://www.misdn.org/downloads/releases/mISDN-1_1_8.tar.gz wget http://www.misdn.org/downloads/releases/mISDNuser-1_1_8.tar.gz tar xfz mISDN-1_1_8.tar.gz tar xfz mISDNuser-1_1_8.tar.gz pushd mISDN-1_1_8 make install popd pushd mISDNuser-1_1_8 make install popd /usr/sbin/misdn-init config You will then also want to make sure /etc/init.d/misdn-init is started automatically with either 'chkconfig --add misdn-init' or 'update-rc.d misdn-init defaults 15 30' depending on your distribution. NOTE: At the time this was written, misdn-1.1.8 is not compatible the 2.6.25 kernel. Please use a kernel version 2.6.25 or earlier. OSLEC ~~~~~ http://www.rowetel.com/ucasterisk/oslec.html[OSLEC] is an Open Source Line Echo Canceller. It is currently in the staging subtree of the mainline kernel and will hopefully be fully merged at around version 2.6.29. The echo canceller module dahdi_echocan_oslec provides a DAHDI echo canceller module that uses the code from OSLEC. As OSLEC has not been accepted into mainline yet, its interface is not set in stone and thus this driver may need to change. Thus it is not built by default. Luckily the structure of the dahdi-linux tree matches that of the kernel tree. Hence you can basically copy drivers/staging/echo and place it under driver/staging/echo . In fact, dahdi_echocan_oslec assumes that this is where the oslec code lies. If it is elsewhere you'll need to fix the #include line. Thus for the moment, the simplest way to build OSLEC with dahdi is: 1. Copy the directory `drivers/staging/echo` from a recent kernel tree (at least 2.6.28-rc1) to the a subdirectory with the same name in the dahdi-linux tree. 2. Edit drivers/dahdi/Kbuild and uncomment the two lines related to OSLEC. After doing that, you'll see the following when building (running 'make') ... CC [M] /home/tzafrir/dahdi-linux/drivers/dahdi/dahdi_echocan_oslec.o CC [M] /home/tzafrir/dahdi-linux/drivers/dahdi/../staging/echo/echo.o ... As this is an experimental driver, problems building and using it should be reported on the https://lists.sourceforge.net/lists/listinfo/freetel-oslec[OSLEC mailing list]. Live Install ~~~~~~~~~~~~ In many cases you already have DAHDI installed on your system but would like to try a different version. E.g. in order to check if the latest version fixes a bug that your current system happens to have. DAHDI-linux includes a script to automate the task of installing DAHDI to a subtree and using it instead of the system copy. Module loading through modprobe cannot be used. Thus the script pre-loads the required modules with insmod (which requires some quesswork as for which modules to load). It also sets PATH and other environment variables to make all the commands do the right thing. There is an extra mode of operation to copy all the required files to a remote host and run things there, for those who don't like to test code on thir build system. Live Install: The Basics ^^^^^^^^^^^^^^^^^^^^^^^^ Basic operation is through running ./build_tools/live_dahdi from the root directory of the dahdi-linux tree. Using DAHDI requires dahdi-tools as well, and the script builds and installs dahdi-tools. By default it assumes the tree of dahdi-tools is in the directory 'dahdi-tools' alongside the dahdi-linux tree. If you want to checkout the trunks from SVN, use: svn checkout http://svn.asterisk.org/svn/dahdi/linux/trunk dahdi-linux svn checkout http://svn.asterisk.org/svn/dahdi/tools/trunk dahdi-tools cd dahdi-linux If the tools directory resides elsewhere, you'll need to edit live/live.conf (see later on). The usage message of live_dahdi: Usage: equivalent of: live_dahdi configure ./configure live_dahdi install make install live_dahdi config make config live_dahdi unload /etc/init.d/dahdi stop live_dahdi load /etc/init.d/dahdi start live_dahdi reload /etc/init.d/dahdi restart live_dahdi xpp-firm (Reset and load xpp firmware) live_dahdi rsync TARGET (copy filea to /tmp/live in host TARGET) live_dahdi exec COMMAND (Run COMMAND in 'live' environment) Normally you should run: ./build_tools/live_dahdi configure ./build_tools/live_dahdi install ./build_tools/live_dahdi config to build and install everything. Up until now no real change was done. This could actually be run by a non-root user. All files are installed under the subdirectory live/ . Reloading the modules (and restarting Asterisk) is done by: ./build_tools/live_dahdi reload Note: this stops Asterisk, unloads the DAHDI modules, loads the DAHDI modules from the live/ subdirectory, configures the system and re-starts Asterisk. This *can* do damage to your system. Furthermore, the DAHDI configuration is generated by dahdi_genconf. It can be influenced by a genconf_parameters file. But it may or may not be what you want. If you want to run a command in the environment of the live system, use the command 'exec': ./build_tools/live_dahdi lsdahdi ./build_tools/live_dahdi dahdi_hardware -v Note however: ./build_tools/live_dahdi dahdi_cfg -c live/etc/dahdi/system.conf Live Install Remote ^^^^^^^^^^^^^^^^^^^ As mentioned above, live_dahdi can also copy all the live system files to a remote system and run from there. This requires rsync installed on both system and assumes you can connect to the remove system through ssh. tzafrir@hilbert $ ./build_tools/live_dahdi rsync root@david root@david's password: /sys/module/dahdi/parameters/debug pungenday:~# cat /sys/module/dahdi/parameters/debug 1 Viewing and setting parameters that way is possible as of kernel 2.6 . In kernels older than 2.6.10, the sysfs "files" for the parameters reside directly under /sys/module/'module_name' . Useful module parameters: debug (most modules):: Sets debug mode / debug level. With most modules 'debug' can be either disabled (0, the default value) or enabled (any other value). + + wctdm and wcte1xp print several extra debugging messages if the value of debug is more than 1. + + Some modules have "debugging flags" bits - the value of debug is a bitmask and several messages are printed if some bits are set: - wctdm24xxp: * 1: DEBUG_CARD * 2: DEBUG_ECHOCAN - wct4xxp: * 1: DEBUG_MAIN * 2: DEBUG_DTMF * 4: DEBUG_REGS * 8: DEBUG_TSI * 16: DEBUG_ECHOCAN * 32: DEBUG_RBS * 64: DEBUG_FRAMER - xpp: See also README.Astribank: * 1: GENERAL - General debug comments. * 2: PCM - PCM-related messages. Tend to flood logs. * 4: LEDS - Anything related to the LEDs status control. The driver produces a lot of messages when the option is enabled. * 8: SYNC - Synchronization related messages. * 16: SIGNAL - DAHDI signalling related messages. * 32: PROC - Messages related to the procfs interface. * 64: REGS - Reading and writing to chip registers. Tends to flood logs. * 128: DEVICES - Device instantiation, destruction and such. * 256 - COMMANDS - Protocol commands. Tends to flood logs. deftaps (dahdi):: The default size for the echo canceller. The number is in "taps", that is "samples", 1/8 ms. The default is 64 - for a tail size of 8 ms. + + Asterisk's chan_dahdi tends to pass its own value anyway, with a different default size. So normally setting this doesn't change anything. max_pseudo_channels (dahdi):: The maximum number of pseudo channels that dahdi will allow userspace to create. Pseudo channels are used when conferencing channels together. The default is 512. To get a list of parameters supported by a module, use modinfo module_name Or, for a module you have just built: modinfo ./module_name.ko For the xpp modules this will also include the description and default value of the module. You can find a list of useful xpp module parameters in README.Astribank . Internals --------- DAHDI Device Files ~~~~~~~~~~~~~~~~~~ Userspace programs will usually interact with DAHDI through device files under the /dev/dahdi directory (pedantically: character device files with major number 196) . Those device files can be generated statically or dynamically through the udev system. * /dev/dahdi/ctl (196:0) - a general device file for various information and control operations on the DAHDI channels. * /dev/dahdi/NNN (196:NNN) - for NNN in the range 1-249. A device file for DAHDI channel NNN. It can be used to read data from the channel and write data to the channel. * /dev/dahdi/transcode (196:250) - Used to connect to a DAHDI transcoding device. * /dev/dahdi/timer (196:253) - Allows setting timers. Used anywhere? * /dev/dahdi/channel (196:254) - Can be used to open an arbitrary DAHDI channel. This is an alternative to /dev/dahdi/NNN that is not limited to 249 channels. * /dev/dahdi/pseudo (196:255) - A timing-only device. Every time you open it, a new DAHDI channel is created. That DAHDI channel is "pseudo" - DAHDI receives no data in it, and only sends garbage data with the same timing as the DAHDI timing master device. DAHDI Timing ~~~~~~~~~~~~ A PBX system should generally have a single clock. If you are connected to a telephony provider via a digital interface (e.g: E1, T1) you should also typically use the provider's clock (as you get through the interface). Hence one important job of Asterisk is to provide timing to the PBX. DAHDI "ticks" once per millisecond (1000 times per second). On each tick every active DAHDI channel reads and 8 bytes of data. Asterisk also uses this for timing, through a DAHDI pseudo channel it opens. However, not all PBX systems are connected to a telephony provider via a T1 or similar connection. With an analog connection you are not synced to the other party. And some systems don't have DAHDI hardware at all. Even a digital card may be used for other uses or is simply not connected to a provider. DAHDI cards are also capable of providing timing from a clock on card. Cheap x100P clone cards are sometimes used for that purpose. If a hardware timing source either cannot be found or stops providing timing during runtime, DAHDI will automatically use the host timer in order provide timing. You can check the DAHDI timing source with dahdi_test, which is a small utility that is included with DAHDI. It runs in cycles. In each such cycle it tries to read 8192 bytes, and sees how long it takes. If DAHDI is not loaded or you don't have the device files, it will fail immediately. If you lack a timing device it will hang forever in the first cycle. Otherwise it will just give you in each cycle the percent of how close it was. Also try running it with the option -v for a verbose output. Spans and Channels ~~~~~~~~~~~~~~~~~~ DAHDI provides telephony *channels* to the userspace applications. Those channels are channels are incorporated into logical units called *spans*. With digital telephony adapters (e.g: E1 or T1), a span normally represents a single port. With analog telephony a span typically represents a PCI adapter or a similar logical unit. Both channels and spans are identified by enumerating numbers (beginning with 1). The number of the channel is the lowest unused one when it is generated, and ditto for spans. There are up to 128 spans and 1024 channels. This is a hard-wired limit (see dahdi/user.h . Several places throuout the code assume a channel number fits in a 16 bits number). Channel and span numbers start at 1. Dynamic Spans ~~~~~~~~~~~~~ Dynamic spans are spans that are not represented by real hardware. Currently there are two types of them: tdmoe:: TDM over Ethernet. A remote span is identified by an ethernet (MAC) address. local:: Generates a span that is actually a loopback to a different local span. Modules that support the dynamic spans are typically loaded at the time the ioctl DAHDI_DYNAMIC_CREATE is called. This is typically called by dahdi_cfg when it has a line such as: dynamic,somename,params in /etc/dahdi/system.conf . In that case it will typically try to load (through modprobe) the modules dahdi_dynamic and dahdi_dynamic_'somename'. It will then pass 'params' to it. Dynamic spans are known to be tricky and are some of the least-tested parts of DAHDI. Echo Cancellers ~~~~~~~~~~~~~~~ (To be documented later) Tone Zones ~~~~~~~~~~ (To be documented later) PROCFS Interface: /proc/dahdi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A simple way to get the current list of spans and channels each span contains is the files under /proc/dahdi . /proc/dahdi is generated by DAHDI as it loads. As each span registers to DAHDI, a file under /proc/dahdi is created for it. The name of that file is the number of that span. Each file has a 1-line title for the span followed by a few optional general counter lines, an empty line and then a line for each channel of the span. The title line shows the number of the span, its name and title, and (potentially) the alarms in which it is. The title shows the span number and name, followed by any alarms the span may have: For example, here is the first span in my system (with no alarms): Span 1: XBUS-00/XPD-00 "Xorcom XPD #0/0: FXS" There are several extra optional keywords that may be added there: (Master):: This span is the master span. See <<_dahdi_timing,DAHDI Timing>>. ClockSource:: The clock source among several spans that belong to a single E1/J1/T1 card. RED/YELLOW/RED/NOTOPEN/LOOP/RECOVERING:: The span is in alarm Following that line there may be some optional lines about IRQ misses, timing slips and such, if there are any. The channel line for each channel shows its channel number, name and the actual signalling assigned to it through dahdi_cfg. Before being configured by dahdi_cfg: This is DAHDI channel 2, whose name is 'XPP_FXS/0/0/1'. 2 XPP_FXS/0/0/1 After being configured by dahdi_cfg: the signalling 'FXOLS' was added. FXS channels have FXO signalling and vice versa: 2 XPP_FXS/0/0/1 FXOLS If the channel is in use (typically opened by Asterisk) then you will see an extra '(In use)': 2 XPP_FXS/0/0/1 FXOLS (In use) User-space Interface ~~~~~~~~~~~~~~~~~~~~ User-space programs can only work with DAHDI channels. The basic operation is 'read()' to read audio from the device and write() to write audio to it. Audio can be encoded as either alaw (G.711a) or (m)ulaw (G.711u). See the ioctl DAHDI_SETLAW. While it is technically possible to use /dev/dahdi/NUMBER directly, this will only work for channel numbers up to 249. Generally you should use: int channo = CHAN_NUMBER_TO_OPEN; int rc; int fd = open("/dev/dahdi/channel", O_RDRW, 0600); // Make sure fd >= 0 rc = ioctl(fd, DAHDI_SPECIFY, &channo) < 0); // Make sure this rc >= 0 FIXME: there's more to tell about the user-space interface. Configuration ~~~~~~~~~~~~~ Most of the configuration is applied from userspace using the tool 'dahdi_cfg' in the package dahdi_tools. This section will not cover the specifics of that file. Rather it will cover the way configuration from this file is applied. Also note that there are other methods to configure DAHDI drivers: there are <<_module_parameters,Module Parameters>>. The xpp driver have their own separate initialization scripts and xpp.conf that arecovered in README.Astribank. When a span is registered, it is considered "unconfigured". Only after dahdi_cfg has been run to apply configuration, the span is ready to run. Some of the configuration is handled by the DAHDI core. Some of it is handled by callbacks, which are function pointers in the `struct dahdi_span': 'spanconfig', 'chanconfig' and (in a way) 'startup'. Dahdi_cfg starts by reading the configuration from the configuration file ('/etc/dahdi/system.conf', by default), and creating a local configuration to apply. If you use -v, at this stage it will pront the configuration that is "about to be configured". Then it will start to actually apply the configuration. Before actually applying configuration, it destroys any existing <<_dynamic_spans,dynamic spans>> and generates new ones (if so configured. FIXME: what about running DAHDI_SPANCONFIG for new dynamic spans?). Next thing it will do is apply the parameters from *span* lines using the ioctl DAHDI_SPANCONFIG. Some generic processing of parameters passed in DAHDI_SPANCONFIG is done in the DAHDI core, in the callback function spanconfig in , but most of it is left to 'spanconfig' callback of the span (if it exists. This one typically does not exists on analog cards). Now dahdi_cfg will ask each existing channel for its existing configuration and apply configuration if configuration changes are needed. Configuration is applied to the channels using the ioctl call DAHDI_CHANCONFIG ioctl. As in the case of the span configuration, part of it is applied by the DAHDI core, and then it is handed over to the span's chanconfig callback. Typically all spans will have such a callback. <<_echo_cancellers,Echo cancellers>> and <<_tone_zones,tone-zones>> are handled separately later. Once everything is done, the ioctl DAHDI_STARTUP is called for every span. This is also translated to a call to the optional span callback 'startup'. Finally the ioctl DAHDI_HDLC_RATE is called for every channel (that is: if '56k' is not set for the channel, it will be explicitly set to the standard HDLC rate of 64k). Low-Level Drivers ~~~~~~~~~~~~~~~~~ Low-level drivers create spans ('struct dahdi_span'). They register the spans with the DAHDI core using 'dahdi_register()'. 'struct dahdi_span' has a number of informative members that are updated solely by the low-level driver: name:: A concise span name. E.g.: Foo/1 desc:: A slightly longer span name. spantype:: Span type in text form. manufacturer:: Span's device manufacturer devicetype:: Span's device type location:: span device's location in system irq:: IRQ for this span's hardware irqmisses:: Interrupt misses timingslips:: Clock slips There are various function pointers in the struct 'dahdi_span' which are used by the DAHDI core to call the low-level driver. Most of them are optional. The following apply to a span: setchunksize:: FIXME: seems to be unused. spanconfig:: Basic span configuration (called from dahdi_cfg). startup:: Last minute initialization after the configuration was applied. shutdown:: Explicit shutdown (e.g. for dynamic spans). Normally not needed. maint:: Enable/disable maintinance mode (FIXME: document). sync_tick:: Get notified that the master span has ticked. The following apply to a single channel. chanconfig:: Configure the channel (called from dahdi_cfg). open:: Channel was opened for read/write from user-space. close:: Channel was closed by user-space. ioctl:: Handle extra ioctls. Should return -ENOTTY if ioctl is not known to the channel echocan_create:: Create a custom echo canceller. Normally used for providing a hardware echo canceller. If NULL, the standard DAHDI echo canceller modules will be used. rbsbits:: Copy signalling bits to device. See below on signalling. hooksig:: Implement RBS-like signalling-handling. See below on signalling. sethook:: Handle signalling yourself. See below on signalling. hdlc_hard_xmit:: Used to tell an onboard HDLC controller that there is data ready to transmit. audio_notify:: (if DAHDI_AUDIO_NOTIFY is set) - be notified when the channel is (or isn't) in audio mode. Which may mean (for an ISDN B-channel) that its data need not be sent. There are several alternative methods for a span to use for signalling. One of them should be used. Signalling: rbsbits ^^^^^^^^^^^^^^^^^^^ If the device is a CAS interface, the driver should copy the signalling bits to and from the other side, and DAHDI will handle the signalling. The driver just need to provide a 'rbsbits' and set DAHDI_FLAG_RBS in the span->flags. Note that 'rbs' (Robed Bits Signalling) here merely refers to the (up to) 4 signalling bits of the channel. In T1 they are transmitted by "robbing" bits from the channels and hence the name. In E1 they are transmitted in a timeframe of their own. The driver should then signal a change in the signalling bits in a channel using dahdi_rbsbits(). Signalling: hooksig ^^^^^^^^^^^^^^^^^^^ If the device does not know about signalling bits, but has their equivalents (i.e. can disconnect battery, detect off hook, generate ring, etc directly) then the driver can specify a 'sethook' function and set DAHDI_FLAG_RBS in span->flags. In that case DAHDI will call that function whenever the signalling state changes. The hooksig function is only used if the rbsbits function is not set. The span should notify DAHDI of a change of signalling in a channel using dahdi_hooksig(). Signalling: sethook ^^^^^^^^^^^^^^^^^^^ Alternatively, if DAHDI_FLAG_RBS is not set in the flags of the span (to use either rbsbits or hooksig), the DAHDI core will try to call the 'sethook' function of the span (if it exists) to handle individual hook states. The span should then notify DAHDI of a change in the signalling state using dahdi_sethook(). FIXME: anybody using this one? ABI Compatibility ~~~~~~~~~~~~~~~~~ Like any other kernel code, DAHDI strives to maintain a stable interface to userspace programs. The API of DAHDI to userspace programs, dahdi/user.h, has remained backward-compatible for a long time and is expected to remain so in the future. With the ABI (the bits themselves) things are slightly trickier. DAHDI's interface to userspace is mostly ioctl(3) calls. Ioctl calls are identified by a number that stems from various things, one of which is the size of the data structure passed between the kernel and userspace. Many of the DAHDI ioctl-s use some specific structs to pass information between kernel and userspace. In some cases the need arose to pass a few more data members in each call. Simply adding a new member to the struct would have meant a new number for the ioctl, as its number depends on the size of the data passed. Thus we would add a new ioctl with the same base number and with the original struct. So suppose we had the following ioctl: ---------------------------------- struct dahdi_example { int sample; } #define DAHDI_EXAMPLE _IOWR (DAHDI_CODE, 62, struct dahdi_example) ---------------------------------- And we want to add the field 'int onemore', we won't just add it to the struct. We will do something that is more complex: ------------------------------------ /* The original, unchanged: */ struct dahdi_example_v1 { int sample; } /* The new struct: */ struct dahdi_example { int sample; int onemore; } #define DAHDI_EXAMPLE_V1 _IOWR(DAHDI_CODE, 62, struct dahdi_example_v1) #define DAHDI_EXAMPLE _IOWR(DAHDI_CODE, 62, struct dahdi_example) ------------------------------------ We actually have here two different ioctls: the old DAHDI_EXAMPLE would be 0xC004DA3E . DAHDI_EXAMPLE_V1 would have the same value. But the new value of DAHDI_EXAMPLE would be 0xC008DA3E . Programs built with the original dahdi/user.h (before the change) use the original ioctl, whether or not the kernel code is actually of the newer version. Thus in most cases there are no compatibility issues. When can we have compatibility issues? If we have code built with the new dahdi/user.h, but the loaded kernel code (modules) are of the older version. Thus the userspace program will try to use the newer DAHDI_EXAMPLE (0xC008DA3E). But the kernel code has no handler for that ioctl. The result: the error 25, ENOTTY, which means "Inappropriate ioctl for device". As a by-product of that method, for each interface change a new #define is added. That definition is for the old version and thus it might appear slightly confusing in the code, but it is useful for writing code that works with all versions of DAHDI. Past Incompatibilities ^^^^^^^^^^^^^^^^^^^^^^ .DAHDI 2.3: DAHDI_SPANINFO_V1 (extra members added). This will typically only be used on ISDN (PRI/BRI) spans in Asterisk. .DAHDI 2.2: * DAHDI_GET_PARAMS_V1, DAHDI_GETCONF_V1, DAHDI_SETCONF_V1, DAHDI_GETGAINS_V1 ('direction' changed from 'R' to 'RW' to fix FreeBSD support). * DAHDI_CONFDIAG_V1, DAHDI_CHANDIAG_V1 (fixed direction). Alarm Types ~~~~~~~~~~~ An alarm indicates that a port is not available for some reason. Thus it is probably not a good idea to try to call out through it. Red Alarm ^^^^^^^^^ Your T1/E1 port will go into red alarm when it cannot maintain synchronization with the remote switch. A red alarm typically indicates either a physical wiring problem, loss of connectivity, or a framing and/or line-coding mismatch with the remote switch. When your T1/E1 port loses sync, it will transmit a yellow alarm to the remote switch to indicate that it's having a problem receiving signal from the remote switch. The easy way to remember this is that the R in red stands for "right here" and "receive"... indicating that we're having a problem right here receiving the signal from the remote switch. Yellow Alarm ^^^^^^^^^^^^ (RAI -- Remote Alarm Indication) Your T1/E1 port will go into yellow alarm when it receives a signal from the remote switch that the port on that remote switch is in red alarm. This essentially means that the remote switch is not able to maintain sync with you, or is not receiving your transmission. The easy way to remember this is that the Y in yellow stands for "yonder"... indicating that the remote switch (over yonder) isn't able to see what you're sending. Blue Alarm ^^^^^^^^^^ (AIS -- Alarm Indication Signal) Your T1/E1 port will go into blue alarm when it receives all unframed 1s on all timeslots from the remote switch. This is a special signal to indicate that the remote switch is having problems with its upstream connection. dahdi_tool and Asterisk don't correctly indicate a blue alarm at this time. The easy way to remember this is that streams are blue, so a blue alarm indicates a problem upstream from the switch you're connected to. Recovering from Alarm ^^^^^^^^^^^^^^^^^^^^^ TODO: explain. Loopback ^^^^^^^^ Not really an alarm. Indicates that a span is not available, as the port is in either a local or remote loopback mode. Not Open ^^^^^^^^ Something is not connected. Used by e.g. the drivers of the Astribank to indicate a span that belongs to a device that has been disconnected but is still being used by userspace programs and thus can't e destroyed. License ------- This package is distributed under the terms of the GNU General Public License Version 2, except for some components which are distributed under the terms of the GNU Lesser General Public License Version 2.1. Both licenses are included in this directory, and each file is clearly marked as to which license applies. If you wish to use the DAHDI drivers in an application for which the license terms are not appropriate (e.g. a proprietary embedded system), licenses under more flexible terms can be readily obtained through Digium, Inc. at reasonable cost. Known Issues ------------ KB1 does not function when echocancel > 128 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ KB1 was not designed to function at greater than 128 taps, and if configured this way, will result in the destruction of audio. Ideally DAHDI would return an error when a KB1 echocanceller is configured with greater than 128 taps. Reporting Bugs -------------- Please report bug and patches to the Asterisk bug tracker at http://issues.asterisk.org in the "DAHDI-linux" category. Links ----- - http://asterisk.org/[] - The Asterisk PBX - http://voip-info.org/[] - http://voip-info.org/wiki/view/DAHDI[] - http://docs.tzafrir.org.il/dahdi-linux/README.html[Up-to-date HTML version of this file] dahdi-linux-2.5.0.1/LICENSE.LGPL0000644000175000017500000006346711046164220015565 0ustar tzafrirtzafrir GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! dahdi-linux-2.5.0.1/ChangeLog0000644000175000017500000071307611631523343015600 0ustar tzafrirtzafrir2011-09-06 Shaun Ruffell * dahdi-linux 2.5.0.1 released. 2011-09-05 10:29 +0000 [r10180] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_2.hex, drivers/dahdi/xpp/firmwares/FPGA_1161.hex: xpp: firmware to detect the new 2+6 module New firmwares to handle the new 2FXS/6FXO module. FPGA_1161.hex, PIC_TYPE_1.hex, PIC_TYPE_2.hex of internal rev. 9732 Signed-off-by: Tzafrir Cohen 2011-08-30 21:06 +0000 [r10173] Shaun Ruffell * drivers/dahdi/firmware/Makefile: wcte12xp, wctdm24xxp: Update VPMOCT032 firmware to 1.11.0. Firmware version 1.11.0 resolves an issue where the driver fails to detect certain VPMOCT032 modules after a cold boot. Signed-off-by: Doug Bailey Acked-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10172 2011-08-28 09:45 +0000 [r10157] Tzafrir Cohen * drivers/dahdi/xpp/card_fxs.c: xpp: FXS: new 2+6 module has no digital I/O ports This module is recognized via subtype==4 Signed-off-by: Tzafrir Cohen 2011-08-19 22:53 +0000 [r10149-10150] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Set 'fastoffhook' counter to 8ms and turn off calibration delay. r10006 "wctdm24xxp: Add 'fastpick' module parameter." copied the fast-off hook module parameter from the wctdm.c driver, but the setting in that driver does not match the data sheet. The previous commit did not actually change any of the significant bits in that register. Also, that commit changed the timer, but did not disable the callibration delay which is necessary for Type-II callerid. The fastpickup option in the wctdm24xxp driver should now match the fastpickup option in the wctdm driver. DAHDI-224. Reported-By: Kinnith Wallace Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10148 * drivers/dahdi/wctdm.c: wctdm: Set 'fastpickup' counter to 8ms This fixes what looks like a typo in r1055 [1]. [1] http://svnview.digium.com/svn/dahdi?view=revision&revision=1055 Reported-by: Kinnith Wallace Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10147 2011-08-18 19:35 +0000 [r10145-10146] Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Use our own free list for IRQ commands. Really only *necessary* when SLAB debugging is enabled, but in that case, can reduce the chance of latency bumps when first loading the driver. Otherwise the constant slab poisoning / checking in interrupt context from the kmalloc / kfrees is too much. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10144 * drivers/dahdi/wct4xxp/base.c: wct4xxp: Bug in timing cable with different span density cards The logic loops through the static cards[] array to determine timing, but the subloop was based off the current card's numspans member. This could cause a null dereference in the case where two cards of different span densities were connected via timing cables. Reported-by: Doug Bailey Signed-off-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10140 2011-08-15 21:55 +0000 [r10139] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Fix lock imbalance in wctc4xxp_watchdog. r10082 "wctc4xxp: Cleanup in-flight commands when halting due to hardware error." introduced a lock imblance on the error path where the cmd_list_lock would be unlocked twice when the board is halted due to a hardware error. Thanks sparse. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10138 2011-08-12 16:06 +0000 [r10115-10119] Shaun Ruffell * drivers/dahdi/voicebus/voicebus.c: wcte12xp, wctdm24xxp: Force local interrupts off in the interrupt handler. r10066 "wctdm24xxp, wcte12xp: Run the ISR with interrupts disabled." requested that the interrupt handler be run in "fast" mode (disabled) but this isn't necessarily guaranteed. This patch makes the interrupt handler itself disable all the interrupts. Linux commit 470c66239ef0336429b35345f3f615d47341e13b [1] contains a comment about why this is necessary. [1] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=470c66239ef03364 (closes issue DAHLIN-248) Reported-and-Tested-by: Vladimir Mikhelson Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10118 * include/dahdi/kernel.h: dahdi: Define HAVE_NET_DEVICE_OPS on kernels > 2.6.29 HAVE_NET_DEVICE_OPS was defined in the mainline kernel in commit 47fd5b83 which was first released in 2.6.29. Any kernels after that will have those fields defined. Mainline commit e2270ea62ae4d7a removed the feature test macros, so the easiest thing to do is define HAVE_NET_DEVICE_OPS ourselves on the kernels since it was committed. This change is needed to compile against the 3.1 kernel. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10109 * drivers/dahdi/dahdi_dynamic.c: dahdi_dynamic: Call dahdi_receive in rx packet handler. Currently dahdi_receive is called on all channels in the context of the master dynamic span. If one span (not the master) receive two packets before the master span received a packet, the older packet on the dynamic span would end up lost because the "readchunk" for the channels would be overwritten by the new packet. DAHLIN-245 Signed-off-by: Wagner Gegler (License #6268) Changed dahdi_ec_chunk to dahdi_ec_span. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10110 * drivers/dahdi/voicebus/voicebus_net.c, drivers/dahdi/wctc4xxp/base.c: wctc4xxp, wcte12xp, wctdm24xxp: Remove check for HAVE_NETDEV_PRIV DAHDI currently supports kernels >= 2.6.9. netdev_priv() has been in the mainline kernel since versions 2.6.6 so it's available in all the supported kernels. This change is needed to compile against the 3.1 kernel. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10096 2011-08-09 12:26 +0000 [r10098-10100] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/FPGA_1161.hex: FPGA_1161 rev 9605: EC related bug fixes Astribank II FPGA firmware rev 9605. Includes two bug fixes: * Error in checking EC licenses when the license was for exactly 64 or 128 channels. * Proper handling of a slave FXO Astribank (in line with the quirks handling from r10019). Signed-off-by: Tzafrir Cohen * / (added): A stable branch for DAHDI-linux 2.5 2011-08-05 Shaun Ruffell * dahdi-linux 2.5.0 released. 2011-07-26 20:19 +0000 [r10082] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Cleanup in-flight commands when halting due to hardware error. On one system I was seeing the board reset in the middle of a transaction. Any commands that were on the response list when this would happen would never be completed and the process would then be stuck in an uninterruptible sleep. This change also prevents the driver from sleeping in timer context, which would result in a kernel panic. This change at least lets an error message propogate back to the user. DAHDI-880 Signed-off-by: Shaun Ruffell 2011-07-22 17:56 +0000 [r10079] Russ Meyerriecks * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Prevent null pointer dereference on spanconfig In the rare case where spanconfig is called while there is pending data on the hdlc channel, the hdlc_getbuf interrupt could try to read from the hdlc buffer before the channel was fully setup. This could potentially result in a null pointer dereference. This condition has existed since the creation of the wcb4xxp driver. Signed-off-by: Russ Meyerriecks Signed-off-by: Shaun Ruffell 2011-07-21 Shaun Ruffell * dahdi-linux version 2.5.0-rc2 released. 2011-07-21 16:26 +0000 [r10066-10070] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi: Drivers that do not support hwec should not report hwec is available. When attaching software echocans to a channel, if there is a hardware echocan available always give preference to them. Revision 9995 "dahdi: Always attach hwec to a channel if available" had an error where if a driver did not even support an option of hardware echocan, dahdi-base would take that to mean there always was a hardware echocan available on the channel. DAHLIN-246 Reported-by: Michael L. Young Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Run the ISR with interrupts disabled. Revision 9886, "wcte12xp: Use the in-hardirq versions of dahdi_receive/dahdi_transmit", changed the call into dahdi_receive and dahdi_transmit to use versions that assume local interrupts are already disabled. Not all versions of the kernel run interrupt service routines with all interrupts disabled and therefore it was possible to lock up a CPU with a recursive grab of the chan_lock. When LOCKDEP was enabled (on debug kernels) interrupt handlers were run atomically so this problem would only occur on pre 2.6.35 kernels that did not have lockdep enabled. Signed-off-by: Shaun Ruffell 2011-07-20 21:32 +0000 [r10063-10064] Russ Meyerriecks * drivers/dahdi/wcte12xp/base.c: wcte12xp: Fix bug when not recognizing loopup codes The wcte12xp wasn't recognizing loopup/loopdown signals. The debounce was so long that it was preventing the loopup/loopdown signals from being registered properly. Removed the debounce entirely as it was unnecessary to the operation. Signed-off-by: Russ Meyerriecks Acked-by: Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: wct4xxp: Fixed a bug where it sent loopdown signals forever The wct4xxp driver was resetting it's maint state to NONE prematurely. Signed-off-by: Russ Meyerriecks Acked-by: Shaun Ruffell 2011-07-20 17:24 +0000 [r10060-10061] Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: wct4xxp: Fix compilation when VPM_SUPPORT is not defined. Signed-off-by: Shaun Ruffell * drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_inst.h: oct612x: Increase the size of some of the instance variables. Revision 9750 "wct4xxp: Reduce the memory footprint of the hardware echocanceler" reduced the number of bits used to store some structure members. Some of the new field lengths were unable to store all the possible values the API as used assigned to the fields, resulting in channels never entering power down mode when they were disabled like they were previously. The change for byEchoOperationMode was found in testing the operation of the VPMOCT032 which currently uses the same code. The others were done via a review of the API doc. This change represents negligable risk and contains no logic changes. It only increases the memory footprint of the API instance in the kernel. Signed-off-by: Doug Bailey Acked-by: Shaun Ruffell Acked-by: Tzafrir Cohen 2011-07-20 16:50 +0000 [r10050-10058] Tzafrir Cohen * README: README: KVERS, KSRC in live.conf Signed-off-by: Tzafrir Cohen * build_tools/live_dahdi: live_dahdi: symlink_ast live_dahdi: Add a new command: symlink_ast, to make the system's /etc/asterisk/dahdi-channels.conf a symlink to the one generated by 'reload' / 'genconf'. If the system dahdi-channels.conf is a generated one and has not edited, there's no real harm with running this. Signed-off-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: get registration_mutex at free_pseudo Make sure that the call to dahdi_chan_unreg() in free_pseudo() is protected by the registration_mutex, like the other calls to that function. Signed-off-by: Tzafrir Cohen Acked-By: Oron Peled Acked-by: Shaun Ruffell * drivers/dahdi/xpp/xbus-core.c: xpp: increase command queue lenge to 1000 Required by CAS in latest (2.5) DAHDI versions. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/xbus-core.h: xpp: make quirk bit flags unsigned This avoids a nag about a meaningless single-bit signed int. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c: xpp: PRI_timing_priority can be static. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/xframe_queue.c: xpp: rate limit queue overflow messages If the CPU becomes overly busy, merely printing the "Overflow in the recieve_queue" messages becomes CPU-intensive on its own right. Signed-off-by: Tzafrir Cohen * build_tools/live_dahdi: live_dahdi: xpp_fxloader: use live xpp.conf xpp_fxloader also reads /etc/dahdi/xpp.conf in one specific case. Make it use the live copy. * build_tools/live_dahdi: live_dahdi: no need to create asterisk at genconf /etc/asterisk already gets generated at config. No need to re-create it at genconf time. Signed-off-by: Tzafrir Cohen 2011-07-18 23:32 +0000 [r10047] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Close a potential race on driver unload. The shutdown logic requires that all CPUs see that the INITIALIZED bit has been cleared. Otherwise it may be possible for the workqueue to run after the hardware resources have been released. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks 2011-07-12 18:15 +0000 [r10036-10038] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/Makefile: xpp: install Octasic frmware if it's there If the OCT6104E-256D.ima Octasic firmware was downloaded to the build directory, install it over with the rest of the firmware files. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/xpp_dahdi.c: xpp: Demote notices for HWEC create/free to debug Signed-off-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: Add dynamic dahdi parameter hwec_overrides_swec. If set to true (default) a HWEC, if available on the channel, takes priority over any software echocan configured in /etc/dahdi/system.conf. This has historically been the default behavior in all released versions of DAHDI that support module echocans. Otherwise, hwec_overrides_swec is set to false, HWEC is chosen only via the "echocanceller=hwec" directive. Signed-off-by: Shaun Ruffell Signed-off-By: Tzafrir Cohen Acked-By: Oron Peled 2011-07-07 13:43 +0000 [r10028] Tzafrir Cohen * build_tools/live_dahdi: live_dahdi: create asterisk in the live tree Make sure you have etc/asterisk in the live tree before generating configuration. Signed-off-by: Tzafrir Cohen 2011-07-05 17:23 +0000 [r10024] Shaun Ruffell * drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c: oct612x: Eliminate some compiler warnings. Eliminate "large integer implicitly truncated to unsigned type" warnings from r10010. Signed-off-by: Shaun Ruffell Acked-by: Doug Bailey Acked-by: Tzafrir Cohen 2011-07-04 14:05 +0000 [r10019-10022] Tzafrir Cohen * drivers/dahdi/xpp/card_fxs.c: xpp: xpd_fxs: ring_trapez parameter This adds module parameter 'ring_trapez'. When set, the wave form of the ring tone is set to be a trapezoid, rather than sine. Thus making the ring stronger. This is a boolean parameter of the module xpd_fxs. Takes effect at the beginning of the next ring. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_bri.c: A number of cases of testing for unsigned int < 0 Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_echo.c: xpp: Eliminate "set but unused" compiler warnings. gcc 4.6 complains about variables that are assigned values but then never used. Signed-off-by: Shaun Ruffell Acked-By: Tzafrir Cohen * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h: xpp: add FXO HWEC quirks handling In some cases the hardware echo canceller cannot be used. Mostly related to an FXO module. * FXO module if the first module is BRI or PRI * FXS module if the Astribank has another FXO, no PRI/BRI, and is a sync slave. Signed-off-by: Oron Peled Acked-By: Tzafrir Cohen 2011-07-01 15:45 +0000 [r10016-10017] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Return NULL if there is not a hardware EC on installed. r9943 enabled the presence of hardware EC to be probed on a card. That change did not account for wcb4xxp based cards that did not have a hardware echocan on board. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/wct4xxp/base.c: wct4xxp: Add module parameter to ignore rotary switch settings. The dual and quad span cards have a rotary switch onboard which controls the order that cards serviced by this driver are registered with the core of DAHDI. This commit adds a module parameter 'ignore_rotary' which, when set to 1, causes the driver to ignore the position of the rotary switch and only consider the physical slot when registering with DAHDI. Ignoring the rotary switch settings also permits the PCI device to be bound and unbound from the driver at runtime since registration with DAHDI no longer only happens when the module is first initialized. By default, the rotary switch will still be used to determine registration order. This commit does not change the default behavior. Signed-off-by: Shaun Ruffell 2011-06-30 22:02 +0000 [r10010-10014] Tzafrir Cohen * build_tools/live_dahdi: Also loca xpd_echo in live_dahdi, if available Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/firmwares/FPGA_1161.hex, drivers/dahdi/xpp/firmwares/USB_FW.hex: xpp: FPGA_1161 rev 9252, USB_FW rev 8826: HWEC New Astribank II FPGA firmware and USB firmwares that add support for the hardware echo canceller module. Note that due to a bug in previous FPGA firmwares, an Astribank with such older firmware and with a hardware echo canceller module will not have any functioning audio at all. Signed-off-by: Tzafrir Cohen * drivers/dahdi/xpp/init_card_5_30 (added), drivers/dahdi/xpp/firmwares/Makefile: xpp: also install init (non)script for xpd_echo * drivers/dahdi/oct612x/include/oct6100api/oct6100_defines.h, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c, drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_inst.h: oct612x: Fixes for Octasic user space compilation: * Don't assume a pointer diff is 16 bits only. * cOCT6100_INVALID_VALUE should be used against 32 unsigned values * Make 3 constants adjustable via '-Dmacro=value': - cOCT6100_INTERNAL_SUPER_ARRAY_SIZE - cOCT6100_MAX_ECHO_CHANNELS - cOCT6100_MAX_MIXER_EVENTS Signed-off-by: Oron Peled Signed-off-by: Tzafrir Cohen Acked-by: Doug Bailey Acked-by: Shaun Ruffell 2011-06-29 22:15 +0000 [r10000-10008] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Fix typo in previous commit for fastpickup mode. I failed to compile the commit exactly as it was committed. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Add 'fastpick' module parameter. When true / 1 the FXO port will use a shorter off-hook calibration delay. This is sometimes necessary in order to properly decode Type-II Caller ID information which is sent shortly after an FXO port goes off hook. Defaults to 0 unless opermode is "JAPAN" then it will default to 1. This functionality was ported from the wctdm.c driver. DAHDI-854. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Ensure battery drops on FXS hangups honor the channel otimer. If an FXS port is configured to use kewl start signalling, when the FXS port is "hungup" it should drop battery for 500ms so that any attached devices can detect that the remote side has disconnected. The wctdm24xxp driver since version 2.4.0 was only dropping battery for ~5-10 ms because it would set "open" on the line, but then the next time it read the line feed register state, it was setting the LINE feed register to the idle state. This change checks if the line is forced open before setting the FXS port back "onhook" so as to not turn on battery prematurely. This fixes a regression introduced in r9070 "wctdm24xxp: Prevent FXS Proslic staying in "Forward/Reverse OnHookTransfer...". DAHDI-849. Checking for open on the line feed registered was originally suggested by Alec Davis. Signed-off-by: Shaun Ruffell * include/dahdi/user.h, include/dahdi/kernel.h: Revert "dahdi: Use enumeration for maintenance modes." This reverts commit r9879. Asterisk commit r264249 [1], which was committed after the switch to enumerations, requires the maintenance modes to be Changing the test in configure.ac from: AST_C_DEFINE_CHECK([DAHDI], [DAHDI_RESET_COUNTERS], [dahdi/user.h], [230]) to: AST_C_COMPILE_CHECK([DAHDI], [int foo = DAHDI_RESET_COUNTERS], [dahdi/user.h]) Would allow the maintenance modes to stand as enumerations but the potential for users to run incompatible versions does not seem worth it at this point. [1] http://svnview.digium.com/svn/asterisk?view=revision&revision=264249 Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks 2011-06-28 22:29 +0000 [r9997-9998] Russ Meyerriecks * drivers/dahdi/voicebus/vpmoct.c, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/voicebus/vpmoct.h, drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp, wctdm24xxp: Load VPMOCT032 firmware in background. The firmware load has been moved into a workqueue to prevent the module load from blocking for the duration of the firmware upload. This could be up to 40 seconds. Driver prevents configuration until firmware load is finished and is_initialized() returns true. Signed-off-by: Russ Meyerriecks Signed-off-by: Shaun Ruffell * drivers/dahdi/voicebus/vpmoct.c (added), drivers/dahdi/wcte12xp/base.c, drivers/dahdi/firmware/Makefile, drivers/dahdi/voicebus/Kbuild, drivers/dahdi/voicebus/vpmoct.h (added), drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp, wctdm24xxp: Add support for the VPMOCT032 hardware echocanceler. Support enabled for the vpmoct032 echo cancellation module for the wctdm24xxp and wcte12xp drivers. Signed-off-by: Russ Meyerriecks Signed-off-by: Shaun Ruffell 2011-06-28 21:29 +0000 [r9995] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi: Always attach hwec to a channel if available. In previous releases of DAHDI if dahdi_cfg attached a software echocan to a channel and a hardware echocan was available, the hardware echocan would be used instead of the software echocan. Since the 2.4 branch was created a new feature was merged into dahdi-linux where it was possible to mix software echocan and hardware echocan on a channel. This required using "hwec" as the echocan in the /etc/dahdi/system.conf file so that what was specified in the configuration file is what was actually used. This has resulted in users upgrading to the trunk of dahdi without updating their /etc/dahdi/system.conf file and just suddenly not using any hardware echocans any longer. The capability to mix software and hardware echocans on a span will be revisted when running dahdi_cfg on any preexisting configuration files doesn't just silently turn off hardware echocan. Signed-off-by: Shaun Ruffell 2011-06-28 18:23 +0000 [r9993] Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/Kbuild, drivers/dahdi/xpp/xproto.c, drivers/dahdi/xpp/xpp_debug, drivers/dahdi/xpp/xbus-pcm.c, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/xbus-pcm.h, drivers/dahdi/xpp/xpp_dahdi.h, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_echo.c (added), drivers/dahdi/xpp/card_echo.h (added), drivers/dahdi/xpp/xbus-core.h: xpd_echo: XPP Octasic echo canceler module * xpd_echo (card_echo.c) - a module to handle an Astribank hardware echo canceller module. * All other XPDs are now of type 'telephony_device'. Only a telephony device XPD provides a span to register. * The EC module will typically show up as XPD-40 and will always show up as Unregistered in 'dahdi_hardware -v' Signed-off-by: Oron Peled Signed-off-by: Tzafrir Cohen 2011-06-28 15:55 +0000 [r9989-9991] Shaun Ruffell * drivers/dahdi/dahdi-base.c: Revert "dahdi: Group dahdi timers into "rates" for improved CPU utilization." This reverts commit r9891 and is part of two commits to revert all the timer changes. Grouping the timer into rates did not allow a timers rate to be changed after another thread is already blocked on the poll call The problem that was reported was if a sip call was made to a DAHDI channel and the sip call was disconnected before answer, the DAHDI channel would never stop rining. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks * drivers/dahdi/dahdi-base.c: Revert "dahdi: If a timer is not configured then we should block indefinitely." This reverts commit r9937 and is part of two commits to revert all the timer changes. Grouping the timer into rates did not allow a timers rate to be changed after another thread is already blocked on the poll call Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks * include/dahdi/kernel.h: kernel.h: Define __packed if not already defined. Linux kernel v2.6.22 introduced the __packed macro to allow the gcc specific __attribute__((packed)) extension to be overridden if required and checkpatch.pl will complain if you don't use it. For some strange reason gcc doesn't complain when you use non-existant decorators. Signed-off-by: Shaun Ruffell Signed-off-by: Russ Meyerriecks 2011-06-20 16:01 +0000 [r9981] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Start alarm timer after marking board initialized. r9946, "wcte12xp: Move the VPMADT032 test/configuration to module load time." introduced a race condition where it was possible for the timer that initiates the check for the alarms to fire before the board was marked initialized. This would result in a board that would never again check it's alarm state since the first time the timer runs INITIALIZED may not be set and it will not reschedule a check since it believes the driver is unloading. This happened because the check for the VPM was moved between when the timer was first setup and when INITIALIZED was then set. Now we make sure INITIALIZED is set before the timer is first setup, and move those two operations together. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks 2011-06-11 01:58 +0000 [r9977] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Do not read extra register when test for FXO module fails. In commit r9968 "wctdm24xxp: Allow more than one outstanding read at a time" I introduced a regression where the transmit FIFO on the data channel of a B400M could get locked up. The result would be constant HDLC overflows when writing to the data channel. This regression did not make it into any releases and did not exhibit itself when crossing spans on a single B400M module. This is a partial revert of commit r9968. Signed-off-by: Shaun Ruffell 2011-06-02 20:04 +0000 [r9928-9971] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Do not export board number in the device description. The board number dupliates the information that is available in the location field. Exporting it as part of the description makes the name dependent on the driver bind order which is not desirable. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Calculate the SPI offsets ahead of time. Updates the CMD_BYTE macro to use precalculated offsets. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Shorten up some of the sleeps/waits. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Allow more than one outstanding read at a time. Since every read needs to go through the complete voicebus pipeline, if we know we're going to read multiple bytes we can queue them all up. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: reglock can be used to protect the txhookstate. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Use lists for SPI commands to the modules. Saves time in the interrupt handler by eliminating the need to scan through all of the slots in the cmd arrays. Also allows the reads from ISR context to automatically grow as the latency grows. This ensures that battery and hook state is actually checked every frame like originally intended. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Cleanup in wctdm_identify_modules. Trivial reformatting that preps it for some parallelizing the module loads. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Remove 'pos' member from 'struct wctdm'. The card position is only used during startup so we don't need to carry it around in the strucuture. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Drop 'flags' from 'struct wctdm_module'. The voicebus cards only support the S110M FXS modules which are based on the 3215. The module flags member was only used to hold whether we were dealing with a 3210 or 3215 SLIC, so we can drop it since we always know we'll have a 3215 based SLIC. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.h: wctdm24xxp: Hold the reglock longer in the interrupt handler. Cuts down on the overhead of constantly saving and restoring the interrupt registers. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wctdm24xxp/xhfc.h: wctdm24xxp: Pass the pointer to struct wctdm_module directly instead of index. This change gets all the easy places and saves on array dereferences when we already have the address of the module that we are interested in. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Use pointer to "struct fxs" in POLARITY_XOR. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Trivial. Reduce the indentation level in wctdm_proslic_oppending. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Use enumeration for module types. This change is to primarily to clarify that the types are always mutually exclusive. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Group the QRV members together. This also allows us to add them to the union with the other module types so they do not add to the memory usage if there aren't any QRV modules installed. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Group the per-module information together Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Dynamically allocate the board_name. Move the data backing the mostly unused string away from the active members of 'struct wctdm'. The location where some of the other members of 'struct wctdm' are initialized were moved so that wctdm_back_out_gracefully always has a fully formed structure to work on. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Remove modmap member from 'struct wctdm'. We can already use the module type to determine presence of a module to check. This also moves the background polling of the modules until after the board is completely initialized because the module type may change while the different types are being probed. This also means that we need to preset the shadow registers for the FXS because otherwise the shadow register will not have been read before the first time it's checked for a power alarm. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp: Limit how many consecutive times to reset the VPMADT032 module. Both limit the amount of junk in the kernel log and also prevent dahdi_cfg from running indefinitely if there is a module with a hardware problem which prevents it from completing the startup sequence. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp: Remove unused vpm100 member from 'struct t1' Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp, wctdm24xxp: Separate test for VPMADT032 and initialization. Part of increasing system startup speed. Splitting these two operations facilitate checking if there is a module present synchronously on driver load from the actual load of the firmware and configuration of the channels. This will allow the presence of the VPM module to be flagged on the span before registration, but load and configuration can happen in the background. When the modules are eventually loaded via udev, there will be enough time from the time the drivers are loaded to when dahdi_cfg will run to complete the firmware load, eliminating the need to block the driver here. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp, wctdm24xxp: Use a constant string for the VPM workqueue name. In my opinion naming the VPM workqueues for each board is not worth the extra complexity. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Set the t1.vpmadt032 pointer under the reglock. Ensures that a single run of the interrupt service routine is consistent about whether there are VPMADT032 commands to process or not. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Put "Span configured" message behind debug flag. This message also duplicates what is in the /etc/dahdi/system.conf file and should only be necessary when troubleshooting problems. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: kmalloc/memset -> kzalloc. This is trivial cleanup. Fixing up a couple of places that followed a kmalloc with a memset to 0 and also sneaked in one ARRAY_SIZE usage change. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Move the VPMADT032 test/configuration to module load time. The firmware load of the VPMADT032 was moved to startspan because a quad-span card in the same system would would lock interrupts for several seconds to load VPMOCT064/128 firmware. Now that the wct4xxp driver no longer locks interrupts while loading its VPM module this driver can move the VPMADT032 check/load back to module load time. This is also required so that the presence of a hardware echo canceler is marked on the span before it is registered with dahdi-base.c. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp: Force spanconfig/chanconfig to wait for ready. This is always true currently but will not necessarily be in the future. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Block chanconfig and spanconfig until board is ready. Currently the board will always be ready if the module initialization function is complete but this change will facilitate allowing some of the more time consuming configuration steps to happen in parallel on system start. Signed-off-by: Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/dahdi-base.c: dahdi: Do not allow 'hwec' to be attached to channels that do not have one. This defines a NULL value for the name of an echocan as invalid. This will allow dahdi_genconf to probe for the presence of a hardware echocan on a channel by trying to attach one. If there is not a hardware echocan available DAHDI_ATTACH_ECHOCAN ioctl will return -EINVAL if 'hwec' was specified as the name of the echo canceler now. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * include/dahdi/kernel.h, drivers/dahdi/dahdi-base.c: dahdi: Provide notification when preechocan buffer is created and destroyed. Not quite ideal, but this seems to be the most straightforward way to know when someone is trying to monitor the preec stream on a channel. This callback allows the board driver providing the span an opportunity to setup the hardware preecho monitoring as needed. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * include/dahdi/kernel.h, drivers/dahdi/dahdi-base.c: dahdi: Update the dahdi_ec_chunk interface to support preec streams. dahdi_ec_chunk is the function that saves the received audio and places a signed linear copy of it in the pre echocanceled buffer on the channel. By splitting the input and output of this function into two parameters, a driver that can provide separate pre and post ec streams can pass them independently to DAHDI, without worrying about DAHDI overwriting a stream that may have already been echocanceled by the hardware. Previously, the dahdi_ec_chunk interface took a received audio buffer and overwrote it after canceling the echo. Now the input and output from the function are broken up in order to support hardware echocans that have a different preechocan stream. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/tor2.c, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/xpp/card_pri.c, include/dahdi/kernel.h, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/dahdi_dynamic.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/wctdm24xxp/xhfc.h: dahdi: Allow dahdi_span_ops.[chan|span]config and startup to block. This change ensures that the dahdi_span_ops callbacks are not called with any spinlocks held, and that the module is pinned in memory, and also passes the struct file * pointer to the callbacks. Passing the file pointer to the callbacks allows the board drivers to check any flags on the file descriptor used to configure the span/channel. The intent here is to allow dahdi_config to open the /dev/dahdi/ctl file in a non-blocking mode in case there is a lengthy processes that needs to happen as part of configuration. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: Do not release the echocan under lock. This allows any echocan cleanup to block if necessary. Especially useful for hardware echocans that may need to wait for hardware to complete the cleanup process. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * include/dahdi/kernel.h: dahdi: Support "struct mutex" on pre 2.6.16 kernels. 'struct mutex' was introduced in 2.6.16. While DAHDI previously allowed statically allocated mutexes, this change is required in order to allow mutexes to be embedded in dynamically allocated structures on older kernels. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: If a timer is not configured then we should block indefinitely. Some older Asterisk versions do not handle well the error message when poll is called on an unconfigured channel. The result would be constant __ast_read: No/unknown event '0' on timer for 'DAHDI/1-1'? messages from Asterisk. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: Make tone zone registration messages debug only. This duplicates information that is already in the /etc/dahdi/system.conf file and should normally only be necessary for the user when debugging problems. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: Propagate shutdown returncode to user space. This change fixes a condition where 'dahdi_cfg -s' would always return success regardless of whether a board driver was able to complete the shutdown. Only impacts board drivers that implemented the shutdown span callback. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/dahdi-base.c: dahdi: Fix compilation on Linux 2.6.26 w/CONFIG_DAHDI_NET. The hdlc_stats function was removed from the mainline kernel in commit 198191c4a7ce4daba379608fb38b9bc5a4eedc61 [1] which was first released in linux 2.6.27. [1] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=198191c4a7ce4 (closes issue #19354) Reported by: biohumanoid Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/wct4xxp/base.c: wct4xxp: Move the check for the VPM to module load time. This allows dahdi-base to know whether or not there is a VPM attached to the module as soon as it's registered as opposed to waiting for start span. This will simplify dahdi_genconf's task of creating a valid configuration file. Signed-off-by: Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: wct4xxp: Do not set maintstat in t4_clear_maint. If we always set maintstat to DAHDI_MAINT_NONE, dahdi_base will lose track of what it thinks the current state of the span is. For example, if you run $ dahdi_maint -s 1 --loopback localhost When t4_clear_maint is called, the current maintenance mode state, 'maintstat', is set to DAHDI_MAINT_NONE. So the next time you call: $ dahdi_maint -s 1 --loopback off dahdi-base.c will believe that the user is trying to set the maintenance state from DAHDI_MAINT_NONE to DAHDI_MAINT_NONE and will not actually do anything. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks * drivers/dahdi/wct4xxp/base.c: wct4xxp: Atomically set framer bits for maintenance modes. Do not allow the interrupt handler or another CPU to change the value between when we get the initial value and when we write the modified value. Also includes a minor formatting fix where braces were not aligned, and remove 'inline' from t4_framer_in and t4_framer_out definitions. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks * drivers/dahdi/wct4xxp/Kbuild: wct4xxp: Set -Wno-unused-but-set-variable compiler option if available. Turn this option on for the entire wct4xxp driver in order to quiet the warnings in the oct612x source files. These files are from a vendor drop and the goal is to limit the deviations from the vendor if possible. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * drivers/dahdi/tor2.c, drivers/dahdi/xpp/xpp_usb.c, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/vpm450m.c, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/wctdm.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/dahdi-base.c: Remove unused variables. gcc-4.6 now warns about variables that are set but never used. Clean up unused variables everywhere except the oct612x subdirectory. The oct612x should go in a separate patch in case that needs to be pulled out into a separate project again. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen * include/dahdi/kernel.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Check if the FXS signaling setting is valid. Signed-off-by: Shaun Ruffell 2011-05-31 13:11 +0000 [r9925] Tzafrir Cohen * drivers/dahdi/xpp/xbus-core.c: xpp: empty labels are not duplicate Some older Asttribanks had an empty label string. They should be ignored when testing for a duplicate label at device probe time. While we're at it, reduce panic level in the notice. Signed-off-by: Tzafrir Cohen 2011-05-23 13:38 +0000 [r9916-9917] Tzafrir Cohen * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xpp_log.h (removed): xpp: Remove obsolete XPP_DEBUGFS code XPP_DEBUGFS code was some code used to send BRI D-Channel data through debugfs for, well, debugging. Unused in recent years. Time to remove. * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/Kbuild, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/card_global.h, drivers/dahdi/xpp/xbus-pcm.c: xpp: Remove obsolete and unused OLD_PROC code OLD_PROC marked old and unused code that was used for writing to procfs. It has long ago been replaced with different sysfs interfaces. Time to remove it. 2011-05-19 21:53 +0000 [r9914] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Fix regression preventing VPMADT032 from loading. Commit r9781, "wcte12xp, wctdm24xxp: Remove unused support for booting VPMADT032 from SPI", introduced a bug that would prevent the VPMADT032 from ever being able to complete its startup. This regression did not make it to any releases. Signed-off-by: Shaun Ruffell 2011-04-25 14:22 +0000 [r9911-9912] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi: Enable DTMF A,B,C, and D digits. This appears to be an old regression from zaptel r4063 [1] that would prevent DAHDI from generating the A,B,C, and D digits due to unintentional drop through on a case statement. [1] http://svn.asterisk.org/view/zaptel?view=revision&revision=4063 Signed-off-by: Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Updating copyright. The wcb4xxp driver was edited this year. Signed-off-by: Shaun Ruffell 2011-04-15 18:42 +0000 [r9905-9907] Kinsey Moore * drivers/dahdi/dahdi-base.c: dahdi: Bug fix for enabling buffer events Introduced in rev 9905, this bug could cause buffer events to become disabled if the kernel was unable to access userland data. * include/dahdi/user.h, include/dahdi/kernel.h, drivers/dahdi/dahdi-base.c: dahdi: Add capability to generate events on buffer underruns and overruns Add BUFFEVENTS and individual buffer event channel flags so that DAHDI can notify userspace processes when it is dropping data. This can be useful when trouble shooting fax problems since DAHDI currently silently discards data becasuse of scheduling latency. With this change, Asterisk could log an event as opposed to just leaving it up to the tone detectors to figure out there was some unexpected phase shift. Acked-by: Shaun Ruffell (original patch by Matt Fredrickson) 2011-04-14 19:11 +0000 [r9902] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: If we cannot read the mode selection pins fail the module load. Alexandre reported that on a particular server he would get a server crash when loading the wcte12xp driver after receiving a line about a timeout when trying to read the mode selection jumpers. If the driver times out when trying to read the mode selection bits there is a serious problem and it should not try to continue on with configuration / registration. Reported-and-Tested-by: Alexandre Abreu Signed-off-by: Shaun Ruffell 2011-04-11 Shaun Ruffell * dahdi-linux version 2.4.1.2 released. 2011-04-11 18:45 +0000 [r9895] Shaun Ruffell * include/dahdi/kernel.h: dahdi: Do not define dev_name if already backported. RHEL 5.6 has backported dev_name in include/dahdi/devices.h. We now need to check for a back ported definition before defining our own version on pre 2.6.26 kernels. (closes issue #18992) Reported by: ndupeux, AlexCeli Tested by: elguero Signed-off-by: Tzafrir Cohen Acked-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9894 2011-03-31 Shaun Ruffell * dahdi-linux version 2.4.1.1 released. 2011-03-15 19:15 +0000 [r9828] Shaun Ruffell * wctdm24xxp: Fix regression with LEDS on TDM410. 2011-03-03 Shaun Ruffell * dahdi-linux version 2.4.1 released. 2011-02-11 17:52 +0000 [r9757-9760] Shaun Ruffell * build_tools/make_version: make_version: Use 'git rev-parse' if only looking for a sha5. Different versions of git have variability in how the log output looks. Instead of git log, we can use git rev-parse directly. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9475 * build_tools/make_version: make_version: svn and git metadata directory not checked properly. (closes issue #16143) Reported by: Max Khon Signed-off-by: Kinsey Moore Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9418 * build_tools/make_version: make_version: '[[' -> '[' since it's not a bash script. '[[' is a bash construct specifically, yet #!/bin/sh is at the top of the file. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-by: Russ Meyerriecks Acked-by: Tzafrir Cohen Review: https://reviewboard.asterisk.org/r/940/ Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9408 * Makefile, build_tools/make_version: dahdi: Generate include/dahdi/version.h when building in a git repository. If building within a git repository search the last log message for a 'git-svn-id'. If found, the commit has a corresponding svn revision number and we will use the SVN-xxx-rxxx revision form. Otherwise use the output of 'git describe --long --always --tags --dirty=M' as the version. Signed-off-by: Shaun Ruffell Acked-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9396 2011-02-10 16:29 +0000 [r9746-9755] Shaun Ruffell * drivers/dahdi/wct4xxp/vpm450m.c: wct4xxp: Do not lock interrupts while loading the VPM firmware. Since the oct6100 API consumes less stack there is no longer a danger of overflowing our stack during load. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9752 * drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tlv.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_phasing_tsst.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_playout_buf.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_interrupts.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_stats.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_conf_bridge.c, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_miscellaneous_priv.h, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c: wct4xxp: Reduce stack usage in oct612x API. Reduce the stack usage by replacing the mOCT6100_RETRIEVE_NLP_CONF_DWORD and mOCT6100_SAVE_NLP_CONF_DWORD macros with functions. Some compilers do a better job of optimizing the local variables declared in those macros than others. For example, with gcc 4.3.0, running ]# make stackcheck | grep Oct6100 | head -n 20 | sed -e 's/^0\S* //g' | uniq Before: Oct6100ApiWriteVqeNlpMemory [wct4xxp]: 1112 Oct6100ApiInvalidateChanPlayoutStructs [wct4xxp]:520 Oct6100ApiSetChannelLevelControl [wct4xxp]: 392 Oct6100ApiBridgeEventRemove [wct4xxp]: 344 Oct6100ApiDebugChannelOpen [wct4xxp]: 312 Oct6100ApiWriteVqeAfMemory [wct4xxp]: 296 Oct6100ApiSetChannelTailConfiguration [wct4xxp]:264 Oct6100ApiRandomMemoryWrite [wct4xxp]: 248 Oct6100ApiTransferToneEvents [wct4xxp]: 248 Oct6100ApiModifyChannelStructs [wct4xxp]: 232 After: Oct6100ApiBridgeEventRemove [wct4xxp]: 344 Oct6100ApiDebugChannelOpen [wct4xxp]: 312 Oct6100ApiRandomMemoryWrite [wct4xxp]: 248 Oct6100ApiTransferToneEvents [wct4xxp]: 248 Oct6100ApiInvalidateChanPlayoutStructs [wct4xxp]:248 Oct6100ApiModifyChannelStructs [wct4xxp]: 232 Oct6100ApiBridgeRemoveParticipantFromChannel [wct4xxp]:216 Oct6100ApiWriteVqeNlpMemory [wct4xxp]: 200 Oct6100ApiInitChannels [wct4xxp]: 168 Oct6100ApiProgramNLP [wct4xxp]: 168 Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9751 * drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_open_inst.h, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c, drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_inst.h, drivers/dahdi/wct4xxp/vpm450m.c, drivers/dahdi/oct612x/include/oct6100api/oct6100_defines.h, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_miscellaneous_priv.h, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.c: wct4xxp: Reduce the memory footprint of the hardware echocanceler. This saves ~300K of kernel memory for each quad or dual span VPM. Due to the fact that this change disables caching of the NLP words (among other things), the time to disable the echocans appears to have increased by ~1ms. Before this change: ======================================================================= 0) ! 356.498 us | vpm450m_setecmode(); <--- disable 0) ! 387.762 us | vpm450m_setecmode(); <--- enable 0) ! 429.839 us | vpm450m_setecmode(); <--- disable ]# echo 1 > /proc/sys/vm/drop_caches && free -k total used free shared buffers cached Mem: 2005352 228368 1776984 0 132 5540 -/+ buffers/cache: 222696 1782656 Swap: 983036 0 983036 After this change: ======================================================================= 0) ! 1109.515 us | vpm450m_setecmode(); <--- disable 0) ! 339.017 us | vpm450m_setecmode(); <--- enable 0) ! 1431.460 us | vpm450m_setecmode(); <--- disable ]# echo 1 > /proc/sys/vm/drop_caches && free -k total used free shared buffers cached Mem: 2005352 228080 1777272 0 112 5484 -/+ buffers/cache: 222484 1782868 Swap: 983036 0 983036 Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9750 * include/dahdi/kernel.h: dahdi: Add '#include ' in dahdi/kernel.h linux/kobject.h was removed from linux/fs.h in upstream commit 57cc721. Add it back in in order to pick up the linux/kref.h include. Reported-by: Raoul Bönisch Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9697 2011-02-09 12:45 +0000 [r9745] Tzafrir Cohen * build_tools/live_dahdi: live_dahdi: Fix regression from r9508 Signed-off-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9532 2011-01-31 18:09 +0000 [r9723-9726] Shaun Ruffell * /: syncing svnmerge-integrated. * drivers/dahdi/dahdi-base.c: dahdi: Experimentally remove dependency on the Big Kernel Lock. With the release of Linux 2.6.37, the Big Kernel Lock is now a compile time option. This change adds a mutex around the one place in the code that we already knew was dependent on the lock_kernel/unlock_kernel calls for serialization and drops the other calls to lock_kernel/unlock_kernel if CONFIG_BKL is not defined. This is *mostly* the dahdi-no-bkl.patch with a few minor whitespace changes, the global_dialparmslock made static, and a warning added to let people know they are running an experimental configuration. (issue #18604) Reported by: jkroon Patches: dahdi-no-bkl.patch uploaded by jkroon (license 714) Signed-off-by: Jaco Kroon Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9721 * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Remove code for unsupported modules. The VPM100 and S100M modules are no longer supported. Analog cards supported by the wctdm24xxp are still compatible with the S110 and VPMADT032 modules. DAHDI-302 Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9720 * Makefile: dahdi: Add '+' on KMAKE definition to enable parallel make. Now 'make -j 5' works the way it's supposed to on multi core machines. On one test machine build times went from ~33 seconds to ~11 seconds. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-by: Russ Meyerriecks Acked-by: Tzafrir Cohen Review: https://reviewboard.asterisk.org/r/940/ Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9409 2011-01-27 21:09 +0000 [r9702] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Fix for bugs in timing selection when B410P card is not the first configured card in system. 2011-01-21 05:35 +0000 [r9652-9696] Shaun Ruffell * /: Updating the svnmerge-integrated information. * drivers/dahdi/wct4xxp/base.c: wct4xxp: Perform an extended reset on PCI-Express cards by default. Extended reset is needed primarily with the PCI express version of the dual and quad-span cards. Enable it by default for those cards and allow it to be forced on or off globally for the driver as a compile time option. The options to force it should be able to come out if there aren't any further reports that the compile time option needs to be set. DAHDI-773 Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9635 * README: README: clarify required kernel configuration Signed-off-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9619 * drivers/dahdi/dahdi-base.c: dahdi: Add error if CONFIG_BKL is not defined Might help when someone wonders why they are now getting errors about "lock_kernel" being undefined. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9592 * drivers/dahdi/wcte12xp/base.c: wcte12xp: Remove unused functions from t1_span_ops. 'open' and 'close' were already empty. 't1xxp_shutdown' only cleared DAHDI_FLAGBIT_RUNNING which is already done in dahdi-base.c after calling shutdown. Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9318 * drivers/dahdi/wcfxo.c, drivers/dahdi/tor2-hw.h, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/pciradio.c, include/dahdi/kernel.h, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/wctdm.c, drivers/dahdi/wctdm24xxp/base.c: "struct pci_device_id[]" -> "DEFINE_PCI_DEVICE_TABLE" 2.6.25 added the DEFINE_PCI_DEVICE_TABLE macro to make sure that the pci_device_id tables are put into the correct section in the binary. Convert all the places where the tables were defined to use them. This is linux-2.6 commit where the change went in along with the rationale: 90a1ba0c5e39eeea278f263c28ae02166c5911c8 Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9584 * include/dahdi/kernel.h: dahdi: If mutexes are not available use semaphores instead. Mutexes were added in 2.6.16. This will allow future changes to use the mutex API without breaking on pre 2.6.16 kernels. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9579 * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: HDLC packets do not pass over D-channel. dahdi/wcb4xxp driver used with Digium Wildcard B410 quad-BRI PCI card unable to communicate with another ISDN device (ISDN phone, another port of B410). It appears that B-channels are capable to transport data, but D-channel is not. Debug output added into the driver shows that packets are transmitted to the D-channel, but no packets are received. Further investigation shows that no interrupts received from Rx FIFO associated with D-channel, although packets are delivered to the FIFO. I've found that problem is in improper usage of chan->chanpos while indexing the fifo index (bspan->fifos): chanpos starts from 1 and fifos starts from 0. Therefore, garbage read instead of fifo number. (closes issue #14834) Reported by: vvv Patches: dahdi-linux-complete-2.2.0-rc1.patch uploaded by vvv (license 741) Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9555 * drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c: wcte12xp, wctdm24xxp: Do not call pci_set_drvdata after device initialization. Instead of using pci_set_drvdata embed the 'struct voicebus_operations' directly in the context so we can use container_of to find the context. This resolves a problem where the 'remove_one' callback gets an invalid pointer to 'struct t1' if the VPMADT032 is in the middle of a reload when the module is unloading. DAHDI-783. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9554 * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Disable PCI read-line multiple command. There are some platforms where the read-line multiple transaction causes packets to be dropped in the voicebus pipeline. The only observable behavior is that packets just go "missing" in the pipeline. This also only appears to affect PCI cards. A typical 'symptom' of this problem is you may see IRQ misses increasing without any corresponding "bumps" in latency in the kernel message log. Normally, IRQ misses are correlated to latency bumps since that is an indication that the host was not able to service the card interrupt in a timely fashion. DAHDI-510 DAHDI-774 Signed-off-by: Shaun Ruffell Signed-off-by: Russ Meyerriecks Acked-by: Kinsey Moore Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9542 * drivers/dahdi/wct4xxp/vpm450m.c: wct4xxp: Close a memory leak in the VPM450 error path. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-By: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9539 * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Lock interrupts when recovering from an underrun. This reduces the chance that another interrupt will interfere with the recovery process. Otherwise it is possible that the hardware advances past the position that we think it is currently at. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-By: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9535 * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Add more descriptive message on a failed reset. Reading 0xffffffff from the registers is a different error than just not coming out of reset. Add a little extra debugging information. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-By: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9534 * drivers/dahdi/wcte12xp/base.c, include/dahdi/kernel.h: wcte12xp: Use interruptible waits to decrease impact on load average. The wcte12xp does all the checking for alarm in a user space workqueue. Most of this time is spent sleeping waiting for reads from the framer to complete. Tasks in uninterruptible sleeps are added to running tasks for the purposes of calculating load average. This change makes the sleeps interruptible so as to not affect the load average as much. For example, the following command will load and configure the driver and then print the load average every 10 seconds. ]# modprobe wcte12xp && dahdi_cfg && ((x=12)); while [[ $x -gt 0 ]]; do cat /proc/loadavg; sleep 10; let x=$x-1; done With this change: 0.29 0.10 0.02 1/101 29945 0.24 0.10 0.02 1/101 29967 0.20 0.09 0.02 1/101 30019 0.17 0.09 0.02 1/101 30041 0.15 0.09 0.02 1/101 30062 0.12 0.08 0.02 1/101 30085 0.10 0.08 0.02 1/101 30107 0.09 0.08 0.02 1/101 30129 0.07 0.08 0.02 1/101 30151 0.14 0.09 0.02 1/101 30173 0.12 0.09 0.02 1/101 30195 0.10 0.08 0.02 1/101 30217 (and I've seen it get down to 0.0) Before this change: 0.57 0.22 0.07 1/101 31920 0.48 0.21 0.07 1/101 31942 0.48 0.22 0.07 1/101 31964 0.48 0.23 0.08 1/101 31986 0.41 0.22 0.07 1/101 32008 0.42 0.23 0.08 1/101 32030 0.43 0.24 0.08 1/101 32054 0.45 0.25 0.09 1/101 32076 0.45 0.25 0.09 1/101 32098 0.46 0.26 0.10 1/101 32120 0.47 0.27 0.10 1/101 32172 0.39 0.26 0.10 1/101 32194 (closes issue #18142) Reported by: foxfire Tested by: foxfire Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9512 * drivers/dahdi/dahdi-base.c: dahdi: Prevent unloadable module on failed open. If chan->span->ops->open() fails then the reference count of the module implementing the board driver will not be decremented. The result is a module that would always be "in use" and unloadable. This change makes sure to release that reference when open failed. (closes issue #18422) Reported by: avarvit Signed-off-by: Shaun Ruffell Acked-by: Angelos Varvitsiotis Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9510 * build_tools/live_dahdi: live_dahdi: fix usage of xpp.conf Link live/usr/share/dahdi/xpp.conf from live/etc/dahdi/xpp.conf in 'config'. This makes the 'live' xpp.conf used rather than the global xpp.conf . Signed-off-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9508 * drivers/dahdi/xpp/card_pri.c: xpd_pri: Remove pointless hooksig span op If the span reports that it supports hooksig, DAHDI may fail to use RBS. So remove a call to that stub function. Signed-off-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9506 * drivers/dahdi/xpp/card_pri.c: xpd_pri: ignore DAHDI_VMWI and DAHDIVMWI_CONFIG This fixes an annoying, though harmless issue: if Asterisk decides to send voicemail messages to a channel (CAS, configured as FXS), We can't do anything useful with them. So ignore them to avoid scary-looking messages (from report_bad_ioctl()). Signed-off-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9505 * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Close a few potential resource assignment leaks. There were some routes through the failure paths in __voicebus_init() where a registered memory region was not subsequently released. This change closes those paths. The result would be on subsequent loads of the driver after hitting the failure condition you would see "IO Registers are in use by another module." in dmesg. request_mem_region/release_mem_region should most likely be converted to devm_request_region and devm_release_region introduced in 2.6.20 (commit 9ac7849e35f705830f7b016ff272b0ff1f7ff759) which was introduced for reasons just such as this. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9503 * build_tools/live_dahdi: live_dahdi: only check for TOOLS_DIR when used Only check that TOOLD_DIR is valid when it is actually needed (configure, install, config). This allows not checking for it with *load on a rsync-ed copy. Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9479 * drivers/dahdi/hpec/dahdi_echocan_hpec.c, drivers/dahdi/xpp/xpp_usb.c, include/dahdi/kernel.h, drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/xpp/xbus-core.c: Remove mutex emulation Using semaphores as mutexes was removed from the kernel in 4882720b267b. Just use straight semaphores now. 'DECLARE_MUTEX()' -> 'DEFINE_SEMAPHORE()' and 'init_MUTEX()' -> 'sema_init()'. Signed-off-by: Shaun Ruffell LKML-Reference: <20100907125057.562399240@linutronix.de> Acked-by: Tzafrir Cohen Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9464 * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Detect FXS modules based on the 3210 SLIC. Fixes a regression introduced in revision 5916 where FXS modules based on the 3210 were not properly detected. (closes issue #18184) Reported by: bsexton Patches: dahdi-fxo-detect.diff uploaded by bsexton (license 1133) Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9456 * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Leave FXO (DAA) always in full-wave ring detect mode. In zaptel commit 4096 [1], all the debouncing of ring signals were moved into software as opposed to using the ring validation circuit in DAA. That commit failed to remove the initial check and set of the ring validation circuit. [1] http://svn.digium.com/view/zaptel?view=revision&revision=4096 (closes issue #16894) Reported by: rde42 Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9441 * drivers/dahdi/firmware/Makefile: dahdi: '-o' -> '--no-same-owner' in drivers/dahdi/firmware/Makefile It appears that in Centos 4, the version of tar doesn't like the -o flag, but will honor the --no-same-owner flag. (closes issue #16063) Reported by: tzafrir Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9434 * drivers/dahdi/voicebus/voicebus.c: wcte12xp, wctdm24xxp: Do not rely on polling main memory. The voicebus library by default configures the PCI interface to poll the descriptor ring for available buffers. There are some platforms like the Intel SG3420P motherboard where this does not appear to be sufficient. Writing to the transmit demand poll register resolves this problem on these troublesome platforms. DAHDI-700 DAHDI-702. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9397 * drivers/dahdi/wct4xxp/base.c: wct4xxp: Drop usage of 'volatile' qualifier. The registers on the device are already accessed with readl/writel and the readchunk and writechunk are mapped into coherent DMA region. The contents of those buffers should not be changing in the middle of any transmit/receive prep call. Signed-off-by: Shaun Ruffell Acked-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9400 * include/dahdi/dahdi_config.h: dahdi: Make CONFIG_DAHDI_PPP off by default. Before CONFIG_DAHDI_PPP can be on by default, some more work needs to be done to ensure that the ppp_generic module is not always loaded and that all channels do not carry around all the PPP members unnecessarily. (issue #17990) Signed-off-by: Shaun Ruffell Acked-by: Kevin P. Fleming Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9392 * include/dahdi/dahdi_config.h: dahdi: Fix for when PPP support is compiled as a kernel module. When compiling dahdi-linux I expect ppp support to be compiled in even if the kernel config has PPP configured as a module. (closes issue #17990) Reported by: jkroon Patches: dahdi-config-ppp.diff uploaded by jkroon (license 714) Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9328 * drivers/dahdi/voicebus/GpakCust.c: vpmadt032: Remove potential endless waits when resetting. It is possible to softlock if the board stops delivering interrupts in the middle of a reset. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9332 * drivers/dahdi/voicebus/GpakCust.c: vpmadt032: Honor the CONFIG_DAHDI_NO_ECHOCAN_DISABLE flag. Setting this configuration option would not have had any impact when a hardware echo canceler was in use. Signed-off-by: Shaun Ruffell Acked-by: Kinsey Moore Acked-by: Russ Meyerriecks Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9432 * drivers/dahdi/xpp/init_card_4_30: xpp: Fixes init error for PRI devices with < 4 ports Fixes a regression singce r8873: if pri_protocol is not explicitly set (in /etc/dahdi/xpp.conf) and the device has (licences for) less than 4 "PRI" (E1/T1) ports, the initialization script will attempt to read from a non-existing SysFS file, and bail out, resulting in a the device failing to initialize. For those non-existing ports we can just skip that part of the initialization. So we just skip it. Work around: explicitly set pri_protocol to E1 or T1, as needed. Xorcom Rev: 8047. Ticket: 1334. Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9430 * drivers/dahdi/dahdi-base.c, include/dahdi/kernel.h: dahdi: Anonymous member in dahdi_echocan_events union. Make explicit what part of the union is being accessed. (closes issue #15908) Reported by: ys Patches: dahdi-dahdi_echocan_events.diff uploaded by ys (license 281) Signed-off-by: Kinsey Moore Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9421 * drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_echocan_kb1.c, drivers/dahdi/dahdi_echocan_mg2.c: dahdi: Fix 'void *' pointer arithmetic warnings. (closes issue #15927) Reported by: Max Khon Patches: dahdi_echocan2.diff uploaded by Max Khon (license 884) void2.diff uploaded by Max Khon (license 884) Signed-off-by: Kinsey Moore Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9420 * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Add optional FXO digital loopback if DEBUG is defined. This module parameter will allow patgen/pattest to be used only on FXO ports. *ALL* FXO ports will be placed in digital loopback mode when set. The current intent is for this to be removed as an optional module parameter when there is a channel by channel representation in sysfs. Otherwise, a new IOCTL would have to be defined and a tool written in order to support this. DAHDI-696. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9391 * drivers/dahdi/dahdi-base.c: dahdi: Be more tolerant of surprise removal of channels. Enable DAHDI to detect if an operation on a file handle refers to a channel that may have been unregistered. This can occur, for example, when a board driver is hot-swapped out in a live system. This patch ensures that file->private_data is always properly set for any open channel, and it's set back to NULL when a channel is unregistered. This way file->private_data can be used to check whether it's valid to perform an operation on the channel. (NOTE: There is still a race condition here if the driver was unbound on one processor during the window of time between when file->private_data was checked and the system call finishes). Also, since DAHDI should only return -ENODEV on read or write when there was a surprise device removal on a running system this sleep can prevent the system from becoming unresponsive if the userspace application does not check for the -ENODEV error and constantly tries to call read with elevated privileges. (issue #17669) Reported by: tzafrir Tested by: sruffell Review: https://reviewboard.asterisk.org/r/905/ Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9353 * drivers/dahdi/voicebus/voicebus.c: wcte12xp, wctdm24xxp: Add call to 'pci_set_mwi' on initialization. I have yet to personally come across a system where this actually changes the observable behavior, but it certainly seems like the sane thing to do and I would rather not let this float around as a patch when I can just merge it in. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9326 * drivers/dahdi/voicebus/voicebus.c: wcte12xp, wctdm24xxp: Remove redundant vb_enable_io_access. These three bits are already set by 'pci_enable_device' and 'pci_set_master' calls. Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9325 * drivers/dahdi/dahdi-base.c: dahdi-base: All channels for a span are now unconfigured on shutdown Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9317 * drivers/dahdi/dahdi_dummy.c: dahdi_dummy: #include for kzalloc and friends. Fix the same issue as in r8550 for dahdi_dummy.c (closes issue #17959) Reported by: glen201 Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9307 * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte11xp.c: wcte11xp, wcte12xp: Fix a long-standing issue with shutdown Upon shutdown, both drivers would attempt to power down external interfaces, but never attempted to bring them back up when the span was restarted. Removing that code allows the driver to work properly until a better solution can be found. Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9316 * README: README: Remove references to dahdi_dummy. Since dahdi_dummy is no longer required remove the references from README. (issue #17959) Reported by: glen201 Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9308 * drivers/dahdi/dahdi-base.c: dahdi: Fix compilation error when CONFIG_DAHDI_NET is defined. Kernel interface for network devices changed. This is the patch from issue plus a few trivial checkpatch.pl formatting changes (minus the >80 column warnings). (closes issue #17857) Reported by: msink Patches: dahdi_net-v2.patch uploaded by msink (license 1103) Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9247 * drivers/dahdi/wct4xxp/base.c: wct4xxp: Update span-local struct with timing info dahdi_tool was incorrectly reporting all spans to be in local timing mode. This is because the driver tracks which span it's timing syncs to, within the card local struct "wc". We have to manually go through and copy timing updates to the span local structs because this is what dahdi_tool actually reads. dahdi-526 Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9312 * /: Turning on merge tracking. * / (added): Creating 2.4 branch. 2010-08-31 Shaun Ruffell * dahdi-linux version 2.4.0 released. 2010-08-27 21:59 +0000 [r9204-9205] Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: wct4xxp: Moving the transmit short detection behind debug module param. This needs some more testing before it's on by default. If the card is otherwise functioning, these messages may be confusing to the user. If the card is not functioning, the driver can be reloaded with debug to check for this condition. Signed-off-by: Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: wct4xxp: Removed transmit line open fault detection The transmit line open detection was pretty weak in that it trips upon receiving 32 consecutive zeroes. We were getting false positives from looping and other miscellaneous functions. Removing this feature, but leaving the transmit line short detector as it actually detects physical shorts. From: Russ Meyerriecks 2010-08-24 18:44 +0000 [r9188] Russ Meyerriecks * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Added card level timing information in sysfs For kernels >= 2.6.18, each individual card has it's local timing hung off the pci device in the sysfs tree. dahdi-626 2010-08-20 01:12 +0000 [r9168] Russ Meyerriecks * drivers/dahdi/dahdi-base.c: dahdi: Uncross dest if dacs is not supported between two different chans. This removes a confusing message introduced in 9120 when bridging channels on two differnt cards. i.e. "dahdi: unable to cross connect 'TE4/0/2/2' with 'WCTDM/0/0'" "dahdi: unable to cross connect 'WCTDM/0/0' with 'TE4/0/2/2'" 2010-08-19 18:03 +0000 [r9167] Shaun Ruffell * include/dahdi/kernel.h, drivers/dahdi/wctdm24xxp/base.c: dahdi: move 'dahdi_is_digital_span' back into wctdm24xp driver. Older kernels do not like the 'bool' type and I cannot just add it into include/dahdi/kernel.h without compile messages in the xpp driver where bool is defined directly. Since the wctdm24xxp driver is the only place using that function, I just moved it back there for now. This fixes a regression introduced in 9130. 2010-08-18 16:56 +0000 [r9162-9163] Tzafrir Cohen * build_tools/live_dahdi: live_dahdi: shutdown dynamic spans to to avoid panic If we fail to shutdown the dynamic spans, we may get a panic on the next load. This attempts to guess when we need to unload spans at unload. * build_tools/live_dahdi: live_dahdi: allow testing dynamic local spans Adds support for configuring dynamic spans through live_dahdi. To enable, set in live/live.conf: DYNAMIC_LOC="yes" It will generate an extra live/etc/dahdi/dynamic.conf (if one does not exist) and use it to configure extra dynamic spans in the system. Note that ATM this will make the system hang pretty easily at 'load' time. 2010-08-18 Shaun Ruffell * dahdi-linux version 2.4.0-rc1 released. 2010-08-17 17:15 +0000 [r9144-9145] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Clean up -vpm workqueue if there is not a VPMADT032 installed. DAHDI-681. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h, drivers/dahdi/voicebus/voicebus.h: wcte12xp, wctdm24xxp: Add compile time option CONFIG_VOICEBUS_ECREFERENCE. Add compile time option to improve the reference signal provided to software echo cancelers. The intent here is for this functionality to become the default behavior but more testing and work on the edge cases is needed. It's being brought in now as a compile time option since there have been reports that it helps in some environments. Instead of using two buffers, which means that at best we're two milliseconds behind, use a circular buffer where audio data is written on the transmit side and read on the receive path. In this way high latency values will not interfere with the operation of software echo cancelers. DAHDI-291. DAHDI-387. This work was originally on: http://svn.asterisk.org/svn/dahdi/linux/team/sruffell/improved_ecreference@9143 and includes a generic kfifo replacement by Matt Fredrickson. 2010-08-16 21:43 +0000 [r9143] Russ Meyerriecks * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Set the companding mode on the analog ports in fixup. Fixes a regression from 9101 'wctdm24xxp: Added "auto" companding option' where the analog modules were not defaulted to alaw properly when a digital module is on an Hx8. This could result in very poor audio since the modules were providing ulaw data, but dahdi-base believed the audio was in alaw when converting to signed linear. 2010-08-16 18:43 +0000 [r9142] Shaun Ruffell * drivers/dahdi/dahdi_transcode.c: dahdi_transcode: No need for ioctl when unlocked_ioctl is available More work to kill the BKL (Big Kernel Lock) http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=10041d2d14688e207d0d829095147aa82c1f211b 2010-08-13 19:38 +0000 [r9130-9138] Shaun Ruffell * drivers/dahdi/oct612x/include/oct6100api/oct6100_mixer_pub.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tsst_inst.h (added), drivers/dahdi/oct612x/apilib/bt (added), drivers/dahdi/oct612x/include/apilib/octapi_largmath.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tone_detection.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_miscellaneous.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_playout_buf_pub.h (added), drivers/dahdi/oct612x/include/digium_unused.h (added), drivers/dahdi/oct612x/include/apilib/octapi_llman.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tlv.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_events_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_debug_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_phasing_tsst.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tlv_inst.h (added), drivers/dahdi/oct612x/include/octtypewin.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_phasing_tsst_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_memory.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_playout_buf_priv.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_stats_pub.h (added), drivers/dahdi/oct612x/include/octosdependant.h (added), drivers/dahdi/oct612x/include/octrpc/oct6100_rpc_protocol.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_open_pub.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_adpcm_chan_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_interrupts.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_phasing_tsst_pub.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_chip_stats_priv.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_pub.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tone_detection_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_mixer.c (added), drivers/dahdi/oct612x/get_discards (added), drivers/dahdi/oct612x/include/apilib/octapi_bt0.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_apimi (added), drivers/dahdi/oct612x/apilib/llman (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tsst.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_interrupts_priv.h (added), drivers/dahdi/oct612x/apilib/bt/octapi_bt0_private.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_apimi.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.c (added), drivers/dahdi/oct612x/include/octdef.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tsi_cnct.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tsi_cnct_inst.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_api_inst.h (added), drivers/dahdi/oct612x/include (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tsst_priv.h (added), drivers/dahdi/oct612x/apilib/llman/octapi_llman.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tsi_cnct_pub.h (added), drivers/dahdi, drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_miscellaneous_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_events_priv.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_mixer_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tlv_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_phasing_tsst_priv.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_adpcm_chan_pub.h (added), drivers/dahdi/oct612x/octdeviceapi (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_memory_priv.h (added), drivers/dahdi/oct612x (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_adpcm_chan_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_conf_bridge.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_stats.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_conf_bridge_inst.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_remote_debug_inst.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_open_inst.h (added), drivers/dahdi/oct612x/include/octrpc (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_inst.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tone_detection_pub.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_events_pub.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_errors.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_apimi/oct6100_mask_interrupts.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tsi_cnct_priv.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_debug_inst.h (added), drivers/dahdi/oct612x/apilib/largmath (added), drivers/dahdi/oct612x/apilib (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_interrupts_pub.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_playout_buf.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_playout_buf_inst.h (added), drivers/dahdi/oct612x/octasic-helper (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_debug_pub.h (added), drivers/dahdi/oct612x/include/octrpc/rpc_protocol.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_remote_debug.c (added), drivers/dahdi/oct612x/include/oct6100api (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_stats_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api (added), drivers/dahdi/oct612x/apilib/bt/octapi_bt0.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_tone_detection_inst.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_mixer_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_version.h (added), drivers/dahdi/oct612x/Makefile (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h (added), drivers/dahdi/oct612x/include/octtypevx.h (added), drivers/dahdi/oct612x/apilib/largmath/octapi_largmath.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c (added), drivers/dahdi/oct612x/include/octmac.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_remote_debug_pub.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_conf_bridge_pub.h (added), drivers/dahdi/oct612x/include/apilib (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_adpcm_chan.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_api.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api (added), drivers/dahdi/oct612x/apilib/llman/octapi_llman_private.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_user.c (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_interrupts_inst.h (added), drivers/dahdi/oct612x/include/oct6100api/oct6100_defines.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_conf_bridge_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_remote_debug_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_chip_open_priv.h (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_debug.c (added), drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_channel_priv.h (added), drivers/dahdi/oct612x/include/octtype.h (added), drivers/dahdi/oct612x/test.c (added): wct4xxp: Move 'oct612x' from an svn:external directly into dahdi-linux. From http://svn.digium.com/svn/octasic_api/oct612x/tags/PR49-03/software@44 This is only currently maintained as part of DAHDI linux so it makes sense to have it directly in DAHDI linux. This obliterates any chance of having 0 checkpatch.pl errors between the 2.3.0 and 2.4.0 releases. Oh well... Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Set the 'spantype' for the digital spans. Defaults to "TE" but can be set by software to "NT" by dahdi_cfg. Signed-off-by: Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: 'is_span_digital' -> 'dahdi_is_span_digital' Signed-off-by: Shaun Ruffell * include/dahdi/user.h, include/dahdi/kernel.h: dahdi: Make it clear that 'linecompat' can be used to identify analog spans. The linecompat member can be used by a span to identify the global-to-the-span signalling types supported. Analog spans do not support any span-global signalling and therefore linecompat should always be 0. Signed-off-by: Shaun Ruffell 2010-08-12 19:38 +0000 [r9127] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Timing fix where handling math in find_sync_src() would return -2 instead of -1 in cases where automatic timing sync was specified. 2010-08-11 05:21 +0000 [r9120-9124] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi: Do not error when uncrossing a channel if there is no 'dacs' callback. The previous commit was making all chan configs fail on a span that did not have a dacs callback. Also add some documentation for 'dahdi_chan_dacs' and make it more explicit when we're disabling cross connect. * drivers/dahdi/dahdi-base.c: dahdi: "Unable" -> "Unable to". Proper sentences are always preferred. Thanks kpfleming :) * drivers/dahdi/dahdi-base.c: dahdi: Fix oops when trying to dacs channels with a null dacs function. 2010-08-09 14:43 +0000 [r9117] Tzafrir Cohen * include/dahdi/kernel.h: work around RHEL backport of strcasecmp RHEL/Centos 5.4 kernels broke after the latest strcasecmp backport. So skip them. 2010-08-06 22:12 +0000 [r9097-9105] Russ Meyerriecks * drivers/dahdi/wct4xxp/base.c: wct4xxp: minor checkpatch changes * drivers/dahdi/wct4xxp/base.c: wct4xxp: Added card level timing information in sysfs For kernels >= 2.6.18, each individual card has it's local timing hung off the pci device in the sysfs tree. dahdi-626 * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Added "auto" companding option Added the "auto" option for the module parameter "companding". In auto mode its left up to each card to decide what companding mode it should be in. If a BRI module is installed, it set everything to alaw; ulaw is selected if no BRI module is installed. Also fixed a bug where forcing companding one way or the other wasn't affecting the BRI modules. dahdi-673 * drivers/dahdi/wctdm24xxp/base.c: wctdm24xp: Replaced alawoverride with companding Added the module parameter "companding" to eventually replace the current alawoverride parameter. Added some deprecated messages so current users will know to move over before we remove it entirely. dahdi-673 * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Renamed module parameter "alawoverride" to "companding" Renamed the module parameter "alawoverride" to "companding". The valid values for "companding" are now the strings "alaw" or "ulaw", instead of integers. dahdi-673 * drivers/dahdi/wct4xxp/base.c: wct4xxp: module param "extendedreset" now a compile option Due to the very small number of affected customers we have removed the module parameter "extendedreset" in favor of a compile time option "CONFIG_EXTENDED_RESET". dahdi-673 * include/dahdi/kernel.h: dahdi: Backport strcasecmp for kernels < 2.6.22 strcasecmp was brought into the kernel at v2.6.22 2010-08-06 18:27 +0000 [r9094] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi: Trivial spelling change. 2010-08-05 21:05 +0000 [r9090] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: don't crash on disconnecting of AB This is a regression from r8985 . The temporary 'module' was there because the pointer 'chan' may become invalid after the close function. 2010-08-04 00:18 +0000 [r9087] Shaun Ruffell * drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wctdm24xxp/xhfc.h: wctdm24xxp: 'struct dahdi_span' is already embedded in the 'struct wctdm_span'. We cannot also embed it in struct b400m_span structure and expect container_of to work. This fixes a regression introduced in r8984. 2010-08-03 13:16 +0000 [r9082] Tzafrir Cohen * README: Proper Mantis category to use 2010-07-31 04:00 +0000 [r9059-9073] Alec L Davis * drivers/dahdi/wctdm.c: wctdm: Prevent FXS Proslic staying in "Forward/Reverse OnHookTransfer" during call Since the 3 second click after answering the call on an FXS port has been fixed issue# 15352, the side effect is that the Proslic during a call, still has the audio signal paths still powered on. Reading the Si3215 specs it reads that an extra ~20mA is consumed while in OHT mode. (issue #17764) Reported by: alecdavis Patches: wctdm_fxs_offhook.diff.txt uploaded by alecdavis (license 585) Tested by: alecdavis * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Prevent FXS Proslic staying in "Forward/Reverse OnHookTransfer" during call [One-liner summary of changes] Now that the 3 second click after answering the call on an FXS port has been fixed, the side effect is that the Proslic during a call, still has the audio signal paths still powered on. Reading the Si3215 specs it reads that an extra ~20mA is consumed while in OHT mode. (closes issue #17764) Reported by: alecdavis Patches: wctdm24xxp_fxs_offhook.diff.txt uploaded by alecdavis (license 585) Tested by: alecdavis * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: SLIC_LF_OPPENDING confict between wctdm_proslic_recheck_sanity() and set_lasttxhook_interruptible() Problem: 'wctdm_proslic_recheck_sanity()' is executed (4 times??) every ~256ms which monitors and clears the SLIC_LF_OPPENDING on fxs->lasttxhook when the LF state has been reached. 'set_lasttxhook_interruptible()' times out after 100ms waiting from the previous write to the SLIC_LF register, by waiting for SLIC_LF_OPPENDING to be cleared, thus the write will fail. Solution: adds wctdm_proslic_check_oppending which does the monitoring and clearing of SLIC_LF_OPPENDING, which is execute every 1ms. It also if the correct state is not reached within 100ms, resends the lasttxhook state. (closes issue #17724) Reported by: alecdavis Patches: wctdm24xxp_fxs_answer.diff4.txt uploaded by alecdavis (license 585) Tested by: alecdavis, sruffell * drivers/dahdi/wcb4xxp/Makefile, drivers/dahdi/wctdm.c: reverting: add curly braces to _write_8bits Against Kernel Coding Guidelines * drivers/dahdi/wctdm.c: add curly braces to _write_8bits 2010-07-29 21:51 +0000 [r9049-9056] Kinsey Moore * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/base.c: wct4xxp, wcte12xp: restrict signaling and line combinations to what actually works * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: reference B400Ms as BRI, correct a module alias, make the module description more accurate * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: only allow B400M modules on hybrid cards * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: correct references to "wildcard" and display the number of BRI spans and analog channels after detection * drivers/dahdi/dahdi-base.c: dahdi-base: display Reserved when a channel is unusable (has a sigcap of 0) * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/base.c: wct4xxp, wcte12xp: remove loobpack parameter, functionality provided by dahdi_maint * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: don't report about VPM100s if none are present and warn the user when flashing firmware * drivers/dahdi/wct4xxp/base.c: wct4xxp: increase consistency and decrease verbosity of kernel logging 2010-07-28 15:32 +0000 [r9034-9046] Shaun Ruffell * drivers/dahdi/voicebus/GpakApi.c: wcte12xp, wctdm24xxp: Minor cleanup 0 -> NULL * drivers/dahdi/tor2.c: tor2: Do not directly dereference I/O memory. Mainly to quiet a sparse warning, but this could be a real problem on some non x86 platforms. * drivers/dahdi/wctdm.c: wctdm: Fix signed one-bit fields. Thanks sparse. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Add __user annotation in copy_to_user call. Quiets sparse. * drivers/dahdi/wct4xxp/base.c: wct4xxp: Several minor changes to make sparse/checkpatch.pl happy. Make setup_chunks static, eliminate a dynamic array in the interrupt handler, don't cast away a memory region specifier, and don't initialize statics to 0. * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Trivial removal of some whitespace at the end of a line. Fixing formatting errors that have snuck in since the 2.3.0 release. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Trival formatting changes. Fixing up some of the formatting errors that crept in since the 2.3.0 release. * README: README: Trivial removal of whitespace at the end of lines. * drivers/dahdi/dahdi-base.c: dahdi: Unlock the dahdi_span.lock when passed an invalid DAHDI_MAINT command. Fixes the following sparse warning "warning: context imbalance in 'dahdi_ctl_ioctl' - different lock contexts for basic block". Thank you sparse! * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Add compile-time option to always poll the interface. Added as a workaround for a system which was not routing interrupts properly and therefore is off by default. Candidate for reversion in a couple of years. DAHDI-627. * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Move from I/O space to memory-mapped registers. Certain platforms have trouble with the registers mapped from I/O space. DAHDI-627. * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Do not ACK response packets without a corresponding request. Closes a small window of opportunity where system conditions prevent the driver from servicing it's receive ring within the timeout period of a request, and then in the middle of retrying the request (after the request was already removed from the "waiting_for_response" list) the driver process the response, it's possible for the driver to ACK the response without ever pairing it up with the original request. The result being that the DTE will then ignore our attempts to retry the original request. DAHDI-430. * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Allow read to return more than one packet of data. As of this writing codec_dahdi (Asterisk module) will not call 'read' on a transcoder channel more often than it calls 'write'. When a translation path is setup that will transcode from g723 to g729, write is called every 30ms and each 'read' returns only 20ms of data. The end result is audio that slowly becomes increasing delayed. Since codec_dahdi calls the system read function with a buffer large enough to hold more than one packet this can prevents packets from backing up on the channel. DAHDI-582 2010-07-28 10:30 +0000 [r9025-9028] Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c: Ignore Reg. 0x70 messages at E1. * drivers/dahdi/xpp/card_pri.c: demote a notice that will happen at registration We might as well ignore this, as we will get this at span registration time anyway. 2010-07-27 01:31 +0000 [r8997-9019] Russ Meyerriecks * drivers/dahdi/wct4xxp/base.c: wct4xxp: Enabled network facing looping for E1 Added the abililty to loop the line back towards the network for E1 modes. This supports both network loop and network payload loop. * drivers/dahdi/wct4xxp/base.c: wct4xxp: Fixed error injection bug * drivers/dahdi/wct4xxp/base.c: wct4xxp: Error counter injection for E1 mode Added support for error counter injection for E1 mode * include/dahdi/user.h, drivers/dahdi/wct4xxp/base.c: wct4xxp: Removed card level event handler Upon review the event introduced in r8998 seemed to be redundant, as the same information was already available. Performance issues were also a concern. This reverts r8998. * include/dahdi/user.h, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/dahdi-base.c: Added hardware transformer check QuadFalc has the ability to test if the transformer is performing correctly. If the components between the framer and the physical span interface are shorted out or opened for any reason we can now detect it. Possible causes for tripping this error could be a broken transformer from an electrical spike or a board manufacturing error. * include/dahdi/user.h, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/dahdi-base.c: Added card level event handler When a loss of syncronization signal occurs on one of the spans, it affects all spans on that card. Since we do not have a span or card level event system, we have to queue up a global event on all channels for that card The new event is DAHDI_EVENT_SYNC * drivers/dahdi/wct4xxp/wct4xxp.h, include/dahdi/user.h, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/dahdi-base.c: Added the ability to trigger alarm simulation states in the qfalc framer. Added some more verbose red alarm states in the upper byte of the alarm member of the dahdi_span structure Removed some unnecessary instrumentation regarding the enabling of the errored second and 1 second counters for performance collecting. Also added a couple comments. 2010-07-26 00:30 +0000 [r8979-8986] Shaun Ruffell * drivers/dahdi/tor2.c, drivers/dahdi/wcfxo.c, drivers/dahdi/wcte12xp/base.c, include/dahdi/kernel.h, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/pciradio.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/dahdi_dynamic.c, drivers/dahdi/wctdm.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_dummy.c: dahdi: Move the 'owner' field from dahdi_span to dahdi_span_ops. One more thing that can be moved out of the per-span structure. * drivers/dahdi/tor2.c, drivers/dahdi/wcfxo.c, drivers/dahdi/wcte12xp/base.c, include/dahdi/kernel.h, drivers/dahdi/pciradio.c, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/xpp_dahdi.h, drivers/dahdi/dahdi_dynamic.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/wctdm.c, drivers/dahdi/dahdi-base.c: dahdi: Move the callbacks in dahdi_span into its own structure. Part of preparation for adding additional callbacks to allow board drivers to advertise and support gathering pre-echocan data from hardware echocans. * drivers/dahdi/tor2.c, drivers/dahdi/wcfxo.c, drivers/dahdi/wcte12xp/base.c, include/dahdi/kernel.h, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/pciradio.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/xpp/xbus-pcm.c, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wctdm24xxp/xhfc.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/dahdi_dynamic.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/wctdm24xxp/xhfc.h, drivers/dahdi/dahdi_dummy.c: dahdi: Remove the 'pvt' member from dahdi_span. The vast majority of board drivers already keep the dahdi_span structure in a driver specific structure. The others were easily converted. This way board drivers can use the container_of macro to find what was previously pointed to by the "pvt" member of the span. One less thing to think about in the span structure. * drivers/dahdi/firmware/Makefile, drivers/dahdi/voicebus/GpakApi.c, drivers/dahdi/voicebus/gpakenum.h, drivers/dahdi/voicebus/GpakApi.h, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/gpakErrs.h: wcte12xp, wctdm24xxp: Updating VPMADT032 firmware to version to 1.25 The echo canceler will now monitor if the receive signal goes over a certain threshold, and if so, freezes its adaptation to prevent loss of convergence. I.e. Fixes conditions where blowing into your handset could result in echo. Additionally, 1.25 includes improvements for handling when line conditions change from echo free to containing echo. * drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/voicebus/voicebus.h: wcte12xp, wctdm24xxp: Return buffer processing to interrupt handler. In revision 8095, I had moved most of the buffer processing out of the interrupt handler and into a tasklet. The intended result was to enable multiple cards to interleave with one another. But once again I was bitten by the fact that there are some systems that for one reason or another do not process their tasklets in a timely enough manner for the real-time nature of TDM processing. This commit moves this processing back into the interrupt handler by default. It also limits the number of frames that the interrupt handler will process at any given time which appears to achieve the same intended result. (closes issue #17289) Tested by: alecdavis * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/voicebus.h: wcte12xp, wctdm24xxp: spin_lock_bh -> spin_lock_irqsave Will add an option to allow calling the deferred processing callback directly in the interrupt handler. It appears there are some systems which still are unable to process their tasklets in a timely fashion, especially if they get pushed out to the ksoftirqd daemon. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Do not call destory_workqueue if the workqueue was not yet created. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wctdm24xxp/base.c: wcte12xp, wctdm24xxp: Add shutdown handlers. Make the drivers a little more kexec friendly. 2010-07-25 16:43 +0000 [r8975] Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c: No need to worry about accidental "changes" in reg. 0x70 in E1 2010-07-22 15:28 +0000 [r8968-8969] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Make sure we also change the deflaw of the span to ulaw if alawoverride is disabled. * drivers/dahdi/wct4xxp/base.c: Make sure we check max_latency to see if it's greater than the minimum required latency for the board in question. 2010-07-19 13:49 +0000 [r8943-8944] Tzafrir Cohen * README: Copy README section of kernel sources from Zaptel. Still needs some simplifications. Anybody? * drivers/dahdi/xpp/card_fxs.c: FXS - fix VMWI compatibility mode: * If we have vmwi_ioctl=N, we should initialize the vmwi_type of all channels. We initialize it to HVAC * Fix a regression, where curly braces around empty if()'s were removed. * Also fix the VMWI_TYPE() macro, so it actually uses the 3'rd parameter. (this didn't cause damage yet, as we only used HVAC so far) 2010-07-16 16:25 +0000 [r8939] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Add alawoverride parameter to the wcb4xxp module to allow for ulaw and alaw mode. 2010-07-14 20:15 +0000 [r8935] Matthew Fredrickson * drivers/dahdi/wct4xxp/base.c: Make noburst parameter override burst flag. 2010-07-14 11:50 +0000 [r8872-8931] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/PIC_TYPE_4.hex: PIC 4 rev. 7381: fix T1 returning signaling register in non-CAS This is the second part of the partial fix in r8872, though each of the two should work independently. * drivers/dahdi/xpp/firmwares/USB_FW.hex: Allow reading caps when twinstar watchdog set Fixes reading capabilities when the watchdog is set. In that case most of the data, as seen, e.g. in output of 'astribank_allow', was 0xFF. Xorcom rev: 7809 * drivers/dahdi/xpp/init_card_4_30, drivers/dahdi/xpp/card_pri.c: Set Astribank PRI before initialization This avoids most cases of sending garbage at startup by setting each port to tristate mode at init time (in the init script) and enable it back at DAHDI_STARTUO (end of dahdi_cfg). Upgrade note: if you have upgraded the files (including init script) but old module is still loaded, you may end up with the port not getting ever enabled and the line practically dead. In such a case, reload the new module. * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xbus-pcm.c: start migrating from xbus_num() to get_xbus()/put_xbus() * Now get_xbus() receive and xbus number (not poiner) and uses xbus_num() internally to map it to an xbus pointer + refcount increment. (this is atomic) * Migrate all obvious places that used xbus_num() to map bus number into a pointer, so now they use get_xbus() + put_xbus() to aquire and release an xbus. * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/xbus-pcm.h, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xbus-pcm.c: PRI Astribanks always sync AB (and independent) * PRI devices always get SYNC-AB (never PLL, not even for NT) * Fix Timing priority calculation accordingly. * On PRI layer1 changes, elect_syncer() is called, so we have re-election. * drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xbus-core.h: prevent handling of duplicate Astribanks Don't let AB which are unplugged/replugged create duplicate XBUS's (if asterisk don't close the original channels). * drivers/dahdi/xpp/xbus-sysfs.c: Create /sys/devices/astribanks: * Astribank devices now reside under their own top-level device. * The USB device is still used as the 'transport'. * This means the astribanks parents are NOT the USB devices. * As a result, even after a USB disconnect, we have valid sysfs representation. * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h: Keep SYSFS objects after disconnect When the USB device disconnects, we keep references to them to make sure they don't disappear. * drivers/dahdi/xpp/card_pri.c: Don't reset span flag RBS on pri module Don't attempt to reset the span flag DAHDI_FLAG_RBS. At pre-registration we don't yet know if we're CAS or not. * drivers/dahdi/xpp/card_pri.c: don't send "duplicates" in E1 as in D4 Make sure we only consider T1-s to be potentially D4 (which requires sending the bits twice). This fixes occasional command-queue floods in E1 CAS. * drivers/dahdi/xpp/card_fxs.c: Put a space where it belongs * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/card_fxs.c: Basic support for DAHDI_VMWI_CONFIG * Supports only our current NEON notification. * No more global 'vmwineon' parameter: - We expect asterisk to tell us by channel. - If 'vmwi_ioctl' is not set (it is by default), that we revert to FSK searching (expensive) and call directly our NEON code (as before). * drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c: Solve race xbus_populate Fixes a crash resulting from a race between disconnecting and connecting Astribanks (on multi-core systems) * Use get_xbus()/put_xbus() arround xbus_populate(), so a disconnect in the middle won't release the xbus too early. * Aquire all XPDs before starting initialization and release them after it finishes (so we don't have up/down races among XPDs) * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xbus-core.h: put xbus->worker in xbus; wake_up_interruptible_all() * The worker member of 'struct xbus' is now an embedded struct xbus_workqueue. * Replace wake_up() to wake_up_interruptible_all(). * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.c: Cleanup: refcount_xpd() * Change refcount_xpd(): instead of returning a pointer to the atomic counter, return directly its value (just like refcount_xbus()) * Add a refcount_xbus and refcount_xpd attributes to sysfs (for debugging) * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xpp_usb.c, drivers/dahdi/xpp/xbus-pcm.h, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xbus-pcm.c: Fix building without CONFIG_PROC_FS defined This changeset should have no functional changes. * drivers/dahdi/xpp/init_card_4_30: Don't assume hardwired pri_protocol is E1 When initializing registers for the "PRI" (E1/T1) module, in the case the user has not explicitly asked for E1/T1 settings in xpp.conf (pri_protocol) fall back to the current value, which is the build-time fall-back. The value is read from sysfs. Previously we implicitly assumed this value is E1. * drivers/dahdi/xpp/init_card_4_30: partial fix of T1 returning signaling register in non-CAS mode 2010-07-12 18:45 +0000 [r8868] Shaun Ruffell * drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_dummy.c: dahdi: Explicitly ensure we don't schedule a timer for the current tick. As best as I can tell, when CONFIG_NO_HZ is set along with CONFIG_HZ < 250, it is possible for the system timer to exceed MAX_SOFTIRQ_RESTART. Tony Mountifield alluded that this might be a problem in the below mailing list posting, but when I was originally testing, I wasn't using CONFIG_NO_HZ and HZ < 250. http://www.mail-archive.com/asterisk-dev@lists.digium.com/msg37384.html (closes issue #17620) Reported by: seanbright 2010-07-06 17:49 +0000 [r8853] Tzafrir Cohen * drivers/dahdi/wcb4xxp/base.c: Extra PCI ID for Junghanns PCI-E cards. 2010-07-02 18:58 +0000 [r8849] Matthew Fredrickson * drivers/dahdi/wct4xxp/base.c: Add support for max_latency module parameter in wct4xxp 2010-06-30 20:23 +0000 [r8841] Matthew Fredrickson * drivers/dahdi/wct4xxp/base.c: Fix for circumstances where the framer needs extra help to reset itself. 2010-06-29 20:20 +0000 [r8831-8832] Shaun Ruffell * drivers/dahdi/voicebus/voicebus.c: wctdm24xxp, wcte12xp: Fix "operation on may be undefined" warning. gcc 4.5.0 generates a warning on the changed lines and http://gcc.gnu.org/ml/gcc/2004-10/msg00032.html explains why. Essentially, the only thing guaranteed with the preincrement operator is that the value will be incremented before the assignment. It's undefined where in the sequence the mask will be applied. * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Fix "operation on may be undefined" warning. gcc 4.5.0 was generating a warning on the changed line, and the discussion at http://gcc.gnu.org/ml/gcc/2004-10/msg00024.html explains why. Essentially, the only thing guaranteed with the preincrement operator is that the value will be incremented before the assignment. It's undefined where in the sequence the mask will be applied. 2010-06-29 12:39 +0000 [r8809-8823] Tzafrir Cohen * README: Document DAHDI 2.3 and 2.2 incompatibilities * README: Fix the README "_V1" ioctls examples zap->dahdi and such. * build_tools/live_dahdi: live_dahdi: properly unload EC modules Copy sruffel's fix to the init.d script from -tools. * build_tools/live_dahdi: live_dahdi: regen config or restart asterisk without full reload Adds commands 'genconf' (for basically: dahdi_genconf; dahdi_cfg) and 'asterisk' (start asterisk) so doing those should not require a full restart. * include/dahdi/kernel.h: chan_notice() now works Make chan_notice() and does not complain about undefined 'chan'. 2010-06-24 21:02 +0000 [r8801-8805] Mike Spiceland * drivers/dahdi/wct4xxp/base.c: Fix trailing whitespace and make last change more readible. (sruffell suggestion) * drivers/dahdi/wct4xxp/base.c: Impliments a workaround for an errata in the qfalc v3.1 chip which caused RBS modes to be broken when using AMI coding. DAHDI-647. 2010-06-18 10:57 +0000 [r8784] Tzafrir Cohen * include/dahdi/dahdi_config.h: Disable DAHDI_AUDIO_NOTIFY by default It's still not tested well-enough, if one enables OPTIMIZE_CHANMUTE. 2010-06-14 21:34 +0000 [r8768] Mike Spiceland * drivers/dahdi/wct4xxp/base.c: Expose some dynamic latency options as module parameters for the wct4xxp driver latency - the default number of ms of buffering to start off with ms_per_irq - how often the card interrupts 2010-06-08 19:46 +0000 [r8751-8762] Tzafrir Cohen * drivers/dahdi/xpp/xpp_usb.c: Use usb_{alloc,free}_coherent instead of usb_buffer_{alloc,free}. usb_buffer_alloc has been replaced with usb_alloc_coherent , and likewise usb_buffer_free has been replaced with usb_free_coherent. in kernels 2.6.34 the older names are proxies for the new ones, and in 2.6.35 the older names are gone. This patch defines the new names for the old ones, for older kernel versions. (closes issue #17383) Reported by: Chainsaw * drivers/dahdi/voicebus/GpakCust.h: include semaphore.h explicitly for newer kernels With kernel version >= 2.6.35-rc1, building failed with: drivers/dahdi/voicebus/GpakCust.h:114: error: field ‘sem’ has incomplete type (closes issue #17382) Reported by: Chainsaw Patches: 07-semaphore-include-not-optional.diff uploaded by Chainsaw (license 723) * build_tools/live_dahdi: live_dahdi: load firmware_class if required Modprobe firmware_class for modules that may need it (and that we insmod later) 2010-05-25 19:23 +0000 [r8689] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: Do not access memory after we free it. 2010-05-24 16:55 +0000 [r8680] Shaun Ruffell * drivers/dahdi/hpec/dahdi_echocan_hpec.c: hpec: #include Fix the same issue as in r8550 , for dahdi_echocan_hpec.c: With kernel 2.6.34 an explicit '#include ' is required for using kzalloc() and friends. 2010-05-23 12:17 +0000 [r8673-8674] Tzafrir Cohen * drivers/dahdi/dahdi_echocan_oslec.c: missing #include: fixes building with 2.6.34-rc5 Fix the same issue as in r8550 , for dahdi_echocan_oslec.c: With kernel 2.6.34-rc5 an explicit '#include ' is required for using kzalloc() and friends. * drivers/dahdi/dahdi_transcode.c: A typo (lintian) 2010-05-17 21:44 +0000 [r8653] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Merge in pulse mask improvement patch for B410P. 2010-05-17 14:45 +0000 [r8641-8642] Shaun Ruffell * drivers/dahdi/wctdm24xxp/base.c: wctdm24xxp: dev_notice -> dev_info Modules that aren't installed should show at the same level as modules that are installed. It could be confusing if the console log level is set to 3 and only messages about which ports do not have any modules installed show up on the console. * drivers/dahdi/Kbuild, include/dahdi/kernel.h: dahdi: Check if wait_for_completion_timeout is backported. CentOS4 has this backported in their 2.6.9 kernel. 2010-05-14 Shaun Ruffell * dahdi-linux version 2.3.0.1 released. 2010-05-14 16:02 +0000 [r8621] Shaun Ruffell * drivers/dahdi/voicebus/GpakCust.h, /, drivers/dahdi/voicebus/GpakApi.c, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/voicebus/GpakCust.c: Merged revisions 8560,8575-8576 via svnmerge from https://origsvn.digium.com/svn/dahdi/linux/trunk ........ r8560 | sruffell | 2010-04-22 16:36:16 -0500 (Thu, 22 Apr 2010) | 11 lines wcte12xp, wctdm24xxp: Ensure writes to I/O registers are flushed. In revision 8176 I changed register access from I/O space to memory mapped registers. Unfortunately, when I made that change, I didn't account for posted writes. This change makes sure all the registers are read back to ensure that they are posted through any intermediate bridges. The most readily observable symptom were cards that were taking 2000 interrupts/second. The card reported that it handled an interrupt but the write to silence the card wasn't flushed through until the second time the interrupt handler run. DAHDI-602. ........ r8575 | sruffell | 2010-04-26 18:29:16 -0500 (Mon, 26 Apr 2010) | 4 lines wcte12xp, wctdm24xxp: Do not allow interruptible sleep on VPM lock. If the sleep is ever interrupted, 'up' will still be called in the GpakApi, essentially making the lock useless after that point. ........ r8576 | sruffell | 2010-04-26 18:29:17 -0500 (Mon, 26 Apr 2010) | 9 lines wcte12xp, wctdm24xxp: Retry if the VPMADT032 reports not ready. CheckDspReset can return -1 if the DSP is not ready to process any new commands. In this case we should retry a few times to give the DSP a chance to become ready. While I'm not ready to say this definitely fixes recently reported cases when the wcte12xp driver constantly resets, it eliminated communication failures to the DSP module when under stress (via the vpm_firmware_version sysfs attribute). However, I haven't let it run long enough to say that the issue is resolved. DAHDI-603. ........ 2010-04-22 11:03 +0000 [r8551] Tzafrir Cohen * /, drivers/dahdi/dahdi_echocan_jpah.c: missing #include: fixes building with 2.6.34-rc5 With kernel 2.6.34-rc5 an explicit '#include ' is required for using kzalloc() and friends. Merged revisions 8550 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2010-04-19 19:42 +0000 [r8540-8545] Tzafrir Cohen * drivers/dahdi/xpp/xpp_debug, /, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/wcb4xxp/Makefile, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/dahdi-base.c: typos, mostly unkown Merged revisions 8539 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * Makefile, /: Remove generation of kernel-doc API docs It's not really useful, and it breaks building 'docs' without a kernel tree. Merged revisions 8538 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * /: initialize svnmerge 2010-04-12 Shaun Ruffell * dahdi-linux version 2.3.0 released. 2010-04-06 23:19 +0000 [r8473-8494] Shaun Ruffell * drivers/dahdi/voicebus/voicebus.c: voicebus: Change WARN_ON_ONCE to BUG_ON. WARN_ON_ONCE is not defined in 2.6.9, and this condition would be catastrophic anyway if it were to occur. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Load the VPM in startup, not spanconfig * drivers/dahdi/wcte12xp/base.c: wcte12xp: Check and dequeue/decipher the VPM commands atomically * drivers/dahdi/wcte12xp/base.c: wcte12xp: Make sure the interrupt is stopped before freeing the vpmadt032 * drivers/dahdi/wcte12xp/base.c: wcte12xp: Eliminate a trailing whitespace. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Do not reconfigure the VPMADT032 if shutting down. If we try to unload the driver soon after a high latency event, it is possible to get stuck for several seconds reloading the firmware. DAHDI-573. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Do not restart the timer on alarm poll if shutting down. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Expose the maximum latency as a module parameter * drivers/dahdi/wcte12xp/base.c: wcte12xp: Reprogram the VPM only when neccessary. Only program the VPM in spanconfig if it either is not setup, or if it fails a ping test. Also, if the channel config fails (but ping would otherwise work), force a reset / reconfiguration if the VPM module. DAHDI-573. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/voicebus/GpakCust.c: wcte12xp: Try to reconfigure the VPM if we fail to configure the channels. Also, fall back to any software echocan configured for this channel for new calls while we're in the middle of a recovery. 2010-04-04 16:14 +0000 [r8454-8468] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wcte12xp/wcte12xp.h, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp: Poll the VPM and reset it if necessary. When the transmit descriptor runs out completely, there (appears to be) a chance for a random command to be sent that results in the VPMADT032 to no longer respond, typically resulting in one way audio. This change introduces a poll of the VPM. If it fails the poll, it will be bypassed temporarily while the driver resets and reprograms it. Also, the VPM is initially programmed in the spanconfig callback instead of at driver load. This moves the potential for underruns until later in the boot process. DAHDI-573. * drivers/dahdi/voicebus/voicebus.c: wcte12xp, wctdm24xxp: If we're only one packet behind, just exit. This will make us two behind, which is fine, and eliminates a busy loop in atomic context. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Use ARRAY_SIZE in a couple more places * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp, wtdm24xxp: Make sure the writes are retried. r8454 and r8460 introduced a change where writes are not retried when other module/framer commands are retried. This was an error and wasn't what was actually under test. This commit restores the behavior in wctdm24xxp and makes sure the vpm writes are retried in the wcte12xp. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp, wctdm24xxp: Close a memory leak when processing VPM commands. Closes a memory leak when processing the VPM write commands introduced in r8454. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp: Use our own workqueue for the timer and maint events. When the latency is large and register reads can take 100s of milliseconds, the alarm polling function could tie up one of the global workqueue threads long enough to interfere with other system operations. Most noticeably the console. DAHDI-573 * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.h: wcte12xp: Resend both framer and VPM commands when reads may have been lost. Latency conditions could cause the driver to misconfigure the VPM which would result in one way audio. DAHDI-572. 2010-03-29 20:43 +0000 [r8443] Russ Meyerriecks * drivers/dahdi/dahdi-base.c: dahdi-base: Fix a bug preventing clobbering maint state Now the errror injection code prevents placing the driver into a loopback state in a less forceful way. 2010-03-25 16:23 +0000 [r8431] Shaun Ruffell * drivers/dahdi/voicebus/voicebus.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/voicebus.h: wctdm24xxp: Add an 'hx8' mode for buffer processing. The Hx8 series cards do not need any idle buffers and idle_buffers complicate processing when using the timing_cable. This change adds another mode of operation for the voicebus layer for the Hx8 cards that operates without the idle buffers. 2010-03-25 15:13 +0000 [r8421-8423] Tzafrir Cohen * drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcb4xxp/wcb4xxp.h: wcb4xxp - add Swyx 4xS0 SX2 QuadBri PCI IDs (closes issue #16493) Reported by: nic_bellamy Patches: wcb4xxp_swyx_sx2_quadbri_pci_ids.patch uploaded by nic bellamy (license 299) * drivers/dahdi/wcb4xxp/base.c: Some more wcb4xxp PCI IDs for Junghanns cards Resolve two open issues. One of them that accidentally wasn't closed. (closes issue #15446) (closes issue #16447) Reported by: lpistone Tested by: okrief 2010-03-24 15:56 +0000 [r8410-8416] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Fix typo in last commit. Wouldn't compile on kernels >= 2.6.20. * drivers/dahdi/wcte12xp/base.c: wcte12xp: t1xxp_maint is also called with interrupts disabled from dahdi_ioctl So just push all the maintenance mode processing off to the workqueue. * drivers/dahdi/wcte12xp/base.c: wcte12xp: t1xxp_maint can be called from interrupt context. Since t1xxp_maint can be called from interrupt context with the DAHDI_MAINT_LOOPSTOP cmd, push the processing of that command to a workqueue since it may sleep in the t1_getreg call. DAHDI-560. 2010-03-24 12:07 +0000 [r8405] Tzafrir Cohen * README: document the header line of /proc/dahdi/NN 2010-03-23 21:56 +0000 [r8399-8400] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Fix potential race on command handling. If we timeout a command, don't free it right away unless we are the one who removed it from whatever list it was on. Also, increase the timeout (2 seconds wasn't enough when the firmware for the VPMOCT was being loaded on a system with 4K stacks) and check the return value from t1_getreg in case there were timeouts. DAHDI-560. * include/dahdi/kernel.h: dahdi: 'clamp' may already be backported. 2010-03-23 13:41 +0000 Russ Meyerriecks * dahdi-linux version 2.2.1.1 released. 2010-03-10 17:04 +0000 Russ Meyerriecks * dahdi-linux version 2.2.1.1-rc1 released. * wct4xxp: Added support for for qfalc v3.1 framer. * wct4xxp: Added ID tags for generation 5 firmware updates 2010-01-11 Shaun Ruffell * dahdi-linux version 2.2.1 released. 2010-01-11 13:40 +0000 [r7844] Tzafrir Cohen * drivers/dahdi/xpp/xbus-pcm.c, /: xpp: demote a message that generates some false alarms. Merged revisions 7843 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2010-01-10 11:40 +0000 [r7806-7816] Tzafrir Cohen * /, drivers/dahdi/xpp/firmwares/USB_FW.hex: xpp: USB_FW rev 7578 Fixes various minor twinstar-related bugs. Merged revisions 7815 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * drivers/dahdi/xpp/xbus-pcm.c, /: xpp: fixes for drift calculation. Should help for the case of multiple quad-PRI Astribanks on a single system. xpp rev: 7666. Merged revisions 7807 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * drivers/dahdi/xpp/xbus-pcm.c, /, drivers/dahdi/xpp/xbus-pcm.h, drivers/dahdi/xpp/xbus-sysfs.c: xpp: Improved inter-Astribank drift calculation. Merged revisions 7625 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2009-12-28 19:16 +0000 [r7733] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi-base: change dahdi_kernel_fpu_end to kernel_fpu_end dahdi_kernel_fpu_end is part of the MMX changes in trunk that was not committed into the 2.2 branch. This change snuck in as part of revision 6864 with the master span processing changes. 2009-12-22 17:53 +0000 [r7723] Shaun Ruffell * voicebus, wcte12xp: Only define SLAB_STORE_USER when CONFIG_SLUB is defined. On 2.6.22, there is was a bug in the SLUB allocator that required defining SLAB_STORE_USER, however this setting is only valid when CONFIG_SLUB is defined and not when using the previous slab allocator. DAHDI-424. 2009-12-11 23:22 +0000 [r7683-7684] Shaun Ruffell * dahdi-linux version 2.2.1-rc2 released. * dahdi-base: Do not wait for impulse when echotraining. Waiting here for the impulse on the transmit can cause the echotraining logic to stick the channel into muted state. This is especially apparent on systems that regularly do not service the interrupts every millisecond. DAHDI-387. * dahdi-base: Reduce the max allocation size in dahdi_reallocbufs. Lower the maximum contiguous chunk that DAHDI asks for from DAHDI_MAX_BUFFER_SIZE*2 to DAHDI_MAX_BUFFER_SIZE. With 4K pages, this can allow the kernel to try a little harder to find the memory it needs since the request goes from order 4 to order 3. 2009-11-23 19:20 +0000 [r7636] Shaun Ruffell * dahdi-linux version 2.2.1-rc1 released. * Even if we are debouncing the LOS declaration, we still expect the LED to turn red as soon as we unplug the physical cable. This impliments this on the wcte12xp just as it already does on the wct4xxp. 2009-11-22 11:43 +0000 [r7616-7620] Tzafrir Cohen * xpp firmware: fix FXS indirect register reading. xpp rev: 7498 Merged revisions 7614 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2009-11-19 22:52 +0000 [r7610] Tzafrir Cohen * drivers/dahdi/xpp/xpp.rules, /: xpp: rules for loading USB firmware into 1163 devices as well Merged revisions 7595 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2009-11-12 23:45 +0000 [r7572-7584] Shaun Ruffell * voicebus: Fix race when enabling/disabling hardware echocan. This closes a race condition where it was possible for the driver to believe it has enabled the VPMADT032 when in fact, it really has not. This fixes a regression introduced in dahdi-linux 2.2.0. (issue #15724) 2009-11-10 15:47 +0000 [r7539-7550] Shaun Ruffell * wcte12xp: Export features and operations for VPMADT032. Fixes a regression in dahdi-linux 2.2.0 where it was impossible for userspace to reset the state of a channel in the VPM. (issue #15724) Patches: mantis-15724-2.patch uploaded by sruffell (license 456) Tested by: alecdavis * Use the same mutex lock for channel allocation and license checking in dahdi_echocan_hpec, so that channel allocation won't happen while the license is being checked (or rechecked) * dahdi_dynamic: Release the dlock before calling accross modules. Resolves a hard lock due to a recursive spinlock grab at startup. Reported by: mapacheco (closes issue #15210) * echocan: Properly keep the reference counts for the echocan modules. (closes issue #13504) (closes issue #15327) Reported by: sruffell, tzafrir * wcb4xxp: support for other HFC-xS cards (info, not code) This commit includes skeleton for the support of other HFC-[248]S-based cards. It still does not include all the different cases for different cards. * wcb4xxp: B410P differences: Clock and NT/TE. * The B410P reads the NT/TE switches the other way around from other cards. * Its clock is also 1/2 of that of other cards, which causes wierd PCM on an unmodified driver. * wcb4xxp: Fix PCM handling for various cards. HFC-8S cards behave quite differently than HFC-4S cards here. * wcb4xxp: Fix LED handling in OpenVox cards (maybe also others) This commit adds extra functions to handle LEDs in the non-B410P cards. Only tested on OpenVox cards. OpenVox cards are known to have slightly different LEDs so this is likely to be slightly broken for others. * wctdm: Change proslic linefeed register setting Insure that proslic linefeed register is not transitioned from Active to On-Hook Transmission while the channel is off-hook. Replaced magic numbers assigned to linefeed associated variables with more descriptive constants. (issue #15352) Reported by: alecdavis Patches: wctdm_prevent_ohttimer_click.diff3.txt uploaded by dbailey (license 819) Tested by: alecdavis, dbailey, vmikhelson * wctdm24xxp, wctdm: Detect if our hookstate has been set back to the initial state. Check if our hookstate has been set back to the initial state, typically the result of a chanconfig, and if so, if we're an FXO port, forget our current battery state. This allows the driver to determine and report again what the hook state of the port is. (related to issue #14577) (closes issue #15429) * wcfxo: Reset the DAA on module initialization. The X100p and clones will sometimes work and sometimes not depending on wether the DAA powers up in running state- this seems to be related to the power supply. This problem is caused by the driver not reseting the DAA and may be the source of a great many intermittent problems with this card. (closes issue #14232) Reported by: tallen8840 Patch by: tallen8840 Tested by: explidous, Flavio * Silence spurious warnings when trying to remove Zaptel directories during install. (closes issue #15479) Reported by: pprindeville Patches: dahdi-linux-rm.patch uploaded by pprindeville (license 347) * dahdi-base: Reduce the stack usage of dahdi_common_ioctl. Split the DAHDI_GETGAINS and DAHDI_SETGAINS ioctls into their own functions and dynamically allocate the 'struct dahdi_gains' structure to reduce the pressure on the stack. * Fixed issue where the clear channel flags were not being set at the appropriate time causing a channel re-configure to mis-set the last channel in each span * wctdm24xxp: Race condition in handling writes to proslic LINEFEED register (64) The wctdm24xxp driver has a problem where a VMWI IOCTL call followed immediately by a ONHOOKTRANSFER IOCTL call will cause the ONHOOK transfer request to be dropped. This occurs if the write to the proslic's LINEFEED register for the VMWI ICTL call is not completed when the ONHOOK transfer request IOCTL is processed. I also cleaned out some magic numbers used in setting the linefeed register. (closes issue #15875) Reported by: dbailey Patches: 15875-wctdm24xxp.diff uploaded by dbailey (license 819) Tested by: dbailey * wctdm: WCTDM SPI clock off state polarity and read timing Change the off state of the SPI clock to high and provide more time for data to settle out on SPI reads. (closes issue #15261) Reported by: alecdavis Patches: wctdm_spi_clocking.diff2.txt uploaded by alecdavis (license 585) Tested by: alecdavis, dbailey * wct4xxp: Check the alarm state if we're debouncing a red alarm. This fixes a problem where if you set the alarmdebounce module parameter on gen2+ cards, you never detect when you go into red alarm. * dahdi-base: dahdi_ioctl_[get|set]gains should return the res value. In function dahdi_ioctl_getgains() and dahdi_ioctl_setgains() return value assigned to res variable, but these function always return 0 which is an error. (closes issue #15916.) Patch by: ys * wctdm: Add missing break A break was missing that caused DAHDI_ONHOOKTRANSFER ioctl call to fall into DAHDI_SETPOLARITY ioctl call. (issue #14261) Reported by: alecdavis Patches: wctdm_fix_ONHOOKTRANSFER.diff.txt uploaded by alecdavis (license 585) Tested by: alecdavis * dahdi-base: Do not allow jumps in system time to lock up the system w/core_timer Since dahdi coretimer uses the number of milliseconds that has actually passed to determine how many times to call dahdi_receive, it is possible that if the system time shifts after dahdi is started, that the system can appear to lock up while the core timer attempts to catch up. This change prevents soft lock ups under these conditions. This is brings the dahdi_dummy changes in r6933 into dahdi-base. (related to issue #15647) * wcte12xp, wctdm24xxp: VPMADT032 firmware update to 1.20. * wct4xxp: Debounce alarms by default for wct4xxp per AT&T 54016. Also, the various alarm conditions can be debounced separately. * voicebus: Increase the NLP converged threshold to 18. Brings in the change from r7065 that was on the team/sruffell/dahdi-linux-vpm119 branch. * wcte12xp: Adding alarm debounce to single span driver (wcte12xp). Debounce yellow alarm also. Change check alarm frequency to 100ms for better debounce granularity. Fix lines over 80 cols from last alarm debounce commit. * voicebus: Send 'idle' buffers when the transmit descriptor underruns. Previously, when the host system fails to service the interrupt in a timely fashion, the transmit descriptor ring for the voicebus card would "go empty" since the interface wouldn't have another descriptor to read in. The driver only knows that it went empty, not how far behind it actually was. Therefore, the driver could just increase the latency by a millisecond and keep going waiting for another bump. Additionally, when the transmit descriptor actually goes empty, there are some cases where an in process SPI transaction to one of the modules is interrupted, which may result in corrupted module register writes on rare occassions. This now makes it possible for the voicebus drivers to coexist with some devices that periodically lock interrupts for longer than 25ms. Before this patch, the latency would constantly increase until either the modules received a corrupted frame. This patch preconfigures all the receive descriptors to send an "idle" packet that will be transmitted to the onboard modules when the host doesn't service the interrupt within (latency - 2)ms. There are now two kinds of underruns, softunderuns where the driver can detect that these idlebuffers have made it to the TX FIFO, and the normal hard underrun where the part signals a transmit descriptor unavailable interrupt. DAHDI-278. * voicebus: Add function to lock the latency. Now that increases in the latency produce less undefined behavior on the SPI busses, provide an interface for client drivers to inform the voicebus library to not increase the latency if underruns are detected. This can speed up loads of the driver since latency bumps do not trigger a restart of the driver initialization. DAHDI-278. * wctdm24xxp, wcte12xp: Lock latency when loading We no longer need to retry board initialization if the latency would have increased during the initialization. DAHDI-278 * voicebus, wctdm24xxp, wcte12xp: Move a print out of the interrupt handler. This can be handled just as well in process context and printing to a serial console from the interrupt handler has the potential to cause long latencies. * voicebus: Be just a little more graceful if we cannot grab our interrupt line. * wcte12xp: use the dev_xxx macro for the debounce messages. We want to know which device is reporting the debounce when there are more than one card in the system. 2009-11-05 12:06 +0000 [r7485-7493] Tzafrir Cohen * backport a number of build fixes from trunk to 2.2 Merged revisions 7226,7356,7392 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * xpp: Use proper get/set for device->driver_data 2.6.32-rc1 broke direct access to the member 'driver_data' of 'struct device'. However direct access to wasn't proper in the first place. This commit replaces direct access to dev->driver_data with dev_get_drvdata() and dev_set_drvdata(). * dahdi-base: Include linux/sched.h Commit a99bba to the mainline kernel removed sched.h from poll.h. So dahdi-base.c needs to include sched.h directly now. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a99bba * headers: sched.h was also removed from interrupts.h Commit d43c36 made it necessary to add sched.h to more of the board drivers. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d43c36 * xpp: Add sysfs xpd attribute 'timing_priority' Merged revisions 7237 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * T1 CAS support in the xpp "pri" module Merged revisions 7244-7245,7266,7276,7457 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk * xpp: make card_hooksig an optional card method. Done in preperation for T1 CAS support, as the PRI module will use RBS instead. * xpp: refactor pcm mask handling. * xpp: PRI PIC firmware: T1-CAS fixes * xpp: More E1/T1 CAS fixes. Mostly connect/disconnect xpp revs: mostly 7458, 7466 2009-08-19 16:44 +0000 [r7039] Kevin P. Fleming * Ensure that dahdi_scan correctly reports VPM presence. The wct4xxp driver (for the dual/quad span T1/E1 cards) and the wcte12xp driver (for the single span VoiceBus-based T1/E1 cards) did not properly update the 'devicetype' field reported by dahdi_scan when a VPM was found during the card startup process. As a result, dahdi_scan did not show that a VPM was present on the card, even if it was. 2009-08-13 22:04 +0000 [r7001] Tzafrir Cohen * xpp firmware: Fixes PCM issue with FXO that is not a timing source Fixes PCM issue with an Astribank2 (116x) FXO module that is installed alongside a PRI/BRI module. xpp: FPGA_1161.hex r7276 . Merged revisions 6938,6966 via svnmerge from http://svn.digium.com/svn/dahdi/linux/trunk 2009-08-06 17:35 +0000 [r6950] Shaun Ruffell * dahdi-base: Reduce the stack usage of ioctl_load_zone. * dahdi-base: Update formatting in ioctl_load_zone. Fixes checkpatch.pl formatting errors from the previous commit. 2009-08-04 16:38 +0000 [r6934-6937] Shaun Ruffell * wctc4xxp: Update to use struct net_device_ops. Accomodates a change in the linux kernel network device interface. * wctc4xxp: Make the wctc4xxp_netdev_ops structure static. * dahdi_dummy: Do not allow jumps in system time to lock up the system. Since dahdi_dummy uses the number of milliseconds that has actually passed to determine how many times to call dahdi_receive, it is possible that if the system time shifts after dahdi is started, that the system can appear to lock up while dahdi_dummy attempts to catch up. This change prevents soft lock ups under these conditions. (closes issue #15647) Reported by: missnebun 2009-07-21 18:11 +0000 [r6864] Shaun Ruffell * wcte12xp: Disable vpmadt032 companding by default. This fixes a regression in 2.2.0 where certain configurations will fail patloop test or have repeated HDLC aborts because the VPMADT032 is modifying the clear channel or d channel data streams. This restores the behavior to how it was in dahdi-linux 2.1.0.4. (closes issue #15498) Reported by: alecdavis Tested by: alecdavis * tor2: allow using port4 as timing source Fix a silly regression introduced when strict check on the timing parameter was added (sync-1 is the array index, not sync itself. And 0 is a special case). (closes issue #15408) Reported by: dferrer Patches: tor2-4th_sync.patch uploaded by dferrer (license 525) * Revert "wct4xxp, wcte11xp: Use the default configuration by default at startup." This reverts the change introduced by revision 6712. This change can cause problems when there is a VPM module installed on the quad-span digital cards. * dahdi-base: Add support for core timing. This essentially moves the function of dahdi_dummy into the core of DAHDI. It ensures that if DAHDI is loaded, it will always be able to provide timing, regardless of whether there are board drivers loaded, or if the board drivers are properly calling dahdi_receive. If there is a master span loaded which is calling dahdi_receive, then the behavior will be like it is normally. This functionality is off by default, uncomment CONFIG_DAHDI_CORE_TIMER in include/dahdi/config_dahdi.h in order to enable it. 2009-07-21 18:11 +0000 [r6858-6864] Shaun Ruffell * dahdi-linux version 2.2.0.2 released. * wcte12xp: Disable vpmadt032 companding by default. This fixes a regression in 2.2.0 where certain configurations will fail patloop test or have repeated HDLC aborts because the VPMADT032 is modifying the clear channel or d channel data streams. This restores the behavior to how it was in dahdi-linux 2.1.0.4. (closes issue #15498) Reported by: alecdavis Tested by: alecdavis * tor2: allow using port4 as timing source Fix a silly regression introduced when strict check on the timing parameter was added (sync-1 is the array index, not sync itself. And 0 is a special case). (closes issue #15408) Reported by: dferrer Patches: tor2-4th_sync.patch uploaded by dferrer (license 525) * Revert "wct4xxp, wcte11xp: Use the default configuration by default at startup." This reverts the change introduced by revision 6712. This change can cause problems when there is a VPM module installed on the quad-span digital cards. * dahdi-base: Add support for core timing. This essentially moves the function of dahdi_dummy into the core of DAHDI. It ensures that if DAHDI is loaded, it will always be able to provide timing, regardless of whether there are board drivers loaded, or if the board drivers are properly calling dahdi_receive. If there is a master span loaded which is calling dahdi_receive, then the behavior will be like it is normally. This functionality is off by default, uncomment CONFIG_DAHDI_CORE_TIMER in include/dahdi/config_dahdi.h in order to enable it. 2009-06-30 Shaun Ruffell * dahdi-linux version 2.2.0.1 released. * Fix for kernel panic when echotraining is enabled on echocan that does not support it. * Fix for kernel panic on RHEL4 when using VPMADT032. * Fix to allow wct4xxp, wcb4xxp, and wcte11xp to provide early timing. 2009-06-23 15:44 +0000 [r6695] Shaun Ruffell * dahdi-linux version 2.2.0 released. * README: Adding a known issues section to the README files. 2009-06-18 18:03 +0000 [r6692] Shaun Ruffell * drivers/dahdi/wcfxo.c, drivers/dahdi/wctdm.c, drivers/dahdi/wctdm24xxp/base.c: Fix calls to dahdi_hooksig. When JAPAN, AUDIO_RINGCHECK, or ZERO_BATT_RING compile time options are selected it is possible to get a kernel panic due to an invalid pointer passed to the dahdi_hooksig function. (closes issue #15350) Patch by: alecdavis 2009-06-12 22:30 +0000 [r6688] Jason Parker * drivers/dahdi/Kbuild: Make complex conditionals work with GNU make 3.80. Much uglier, but it works on RHEL4. 2009-06-04 21:14 +0000 [r6675] Shaun Ruffell * drivers/dahdi/dahdi-base.c: Fix bug in procfs handling. Fix bug in procfs handling where it was possible to get a warning in lib/vsprintf.c when reading from /proc/dahdi/x. Patch by: biohumanoid (closes issue #15252) 2009-05-27 Shaun Ruffell * dahdi-linux version 2.2.0-rc5 released. 2009-05-27 12:48 +0000 [r6659] Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/card_global.c: Fix more 'owner' for 2.6.30 to be happy. Finishing the work of r6642. Completely shut issue #14964. 2009-05-25 08:23 +0000 [r6651-6653] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/PIC_TYPE_3.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_4.hex, drivers/dahdi/xpp/firmwares/FPGA_1161.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_2.hex: xpp firmwares: fixes sync issues of FXO module in a BRI/PRI Astribank * Also fixes LED blinking issues in PRI modules * Various bugfixes in the PICs. * drivers/dahdi/xpp/firmwares/USB_FW.hex: USB_FW.hex: Allow setting caps. even when FPGA is loaded. Note that They will only take effect after a reset. Firmware rev. 7071. 2009-05-19 16:09 +0000 [r6635-6642] Tzafrir Cohen * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xpp_usb.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xdefs.h: xpp: 'owner' property of procfs was dropped in 2.6.30. This adds a compatibility macro for older versions that is a noop for kernels >= 2.6.30. (closes issue #14964) * drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xproto.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xbus-pcm.c: xpp: fix the Astribank state machine This generally is a case that would not happen in the wild, though. * drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/xdefs.h: xpp: report in sysfs if bri module uses hardhdlc support * drivers/dahdi/xpp/calibrate_slics (removed): xpp: remove obsolete script calibrate_slics * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/mmapbus.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/mmapdrv.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/Kbuild, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xdefs.h: Replaece member bus_id with dev_name() and set_dev_name() As of 2.6.26 the macros dev_name() and set_dev_name() are used to read and set (respectively) the bus_id member in sysfs. As of 2.6.30 bus_id is gone. This patch provides comaptiobility macros for older kernel versions and removes direct usage of bus_id. (closes issue #14965) Patches: xpp_2630_dev_name.diff uploaded by tzafrir (license 46) * drivers/dahdi/voicebus, drivers/dahdi/vpmadt032_loader: ignore generated files in voicebus and vpmadt032_loader 2009-05-15 23:37 +0000 [r6625-6628] Shaun Ruffell * drivers/dahdi/voicebus/GpakCust.c: voicebus: Use '&' not '|' when checking for a bit. * drivers/dahdi/voicebus/GpakCust.c: voicebus: Make the enable/disable echocan messages debug again. I accidentally changed to print everytime. They should only be printed if DEBUG_ECHOCAN is specified in the debug module parameter. 2009-05-14 14:49 +0000 [r6621] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: wcte12xp: Set the syncsrc in the span appropriately. Before this commit, dahdi_tool would report "Internally clocked" for boards supported by the wcte12xp driver both when receiving timing from the span and providing it to the span. Now it reports "Internally clocked" if providing timeing to the span, and the card if receiving timeing from the span. DAHDI-65. 2009-05-12 22:30 +0000 [r6606-6610] Kevin P. Fleming * drivers/dahdi/Kbuild: use proper case for variable name :-) * drivers/dahdi/Kbuild: Allow VPMADT032 and HPEC binary modules to be used on platforms where ARCH is set to the new 'generic' x86 flavor available in recent Linux kernel releases * drivers/dahdi/Kbuild: emit warning messages when DAHDI is being built on a CPU architecture that does not support HPEC or the VPMADT032 firmware loader, so the user will know why they are not included clean up the conditional logic for these items in the Kbuild file * Makefile: remove another unused variable 2009-05-11 17:48 +0000 [r6589-6590] Shaun Ruffell * dahdi-linux version 2.2.0-rc4 released. * drivers/dahdi/wcte12xp/base.c: wcte12xp: Expose vpm parameters as module parameters. Expose the vpmnlptype, vpmnlpthresh, and vpmnlpmaxsupp as module parameters like for the wctdm24xxp. DAHDI-261 * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakApi.h, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: voicebus: Update the default vpmadt032 parameters. Move the echo can channel parameters into a common location for both the wcte12xp and wctdm24xxp drivers that use the voicebus module. This is intended to make it clearer which differences are required between the clients. Additionally, update the default parameters to the new recommended values. VPMADT032-37 2009-05-07 19:42 +0000 [r6572] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: voicebus: Create workqueue for each vpmadt032 instance. Depending on the system latency, the deferred work for the vpmadt032 can take up to 200ms. This change allows each vpmadt032 to use its own workqueue, and not the global system workqueue. This prevents vpm operations from blocking the main system workqueue for extended periods. This restores the behavior to the way it was before the common vpmadt032 code was moved out of the wctdm24xxp and wcte12xp drivers. DAHDI-260 voicebus-squash: Adding the wq name. 2009-05-07 19:42 +0000 [r6568-6572] Shaun Ruffell * dahdi-linux version 2.2.0-rc3 released. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/voicebus/GpakCust.h: voicebus: Create workqueue for each vpmadt032 instance. Depending on the system latency, the deferred work for the vpmadt032 can take up to 200ms. This change allows each vpmadt032 to use its own workqueue, and not the global system workqueue. This prevents vpm operations from blocking the main system workqueue for extended periods. This restores the behavior to the way it was before the common vpmadt032 code was moved out of the wctdm24xxp and wcte12xp drivers. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus/GpakCust.h: voicebus: Changing default NLP type to 'suppression'. The 'suppression' default for the NLP provides better echo canceling performance. Also ensures that the wctdm24xxp and wcte12xp driver use the same default values. 2009-05-05 17:32 +0000 [r6564] Shaun Ruffell * drivers/dahdi/voicebus/GpakCust.c: voicebus: Use the companding type on the span when enabling echocan. 2009-05-04 20:36 +0000 [r6562] Doug Bailey * drivers/dahdi/voicebus/GpakCust.c: Insure that vpmnlptype, vpmnlpmaxsupp, and vpmnlpthresh are set back to module level defaults when echo can is freed. (Previously they were zero'd out) DAHDI-257 2009-05-02 07:53 +0000 [r6556] Kevin P. Fleming * Makefile: Remove explicit passing of ARCH to kernel build system There is no value in setting a value for ARCH and passing it to the kernel build system; the configured kernel headers/sources already have an architecture specified and can't be used for any other architecture anyway. 2009-05-01 16:43 +0000 [r6549-6554] Shaun Ruffell * drivers/dahdi/dahdi-base.c: dahdi-base: define __RW_LOCK_UNLOCKED() Linux 2.6.9 does not contain that definition, but the older definition is deprecated since it defeats lock state checking. DAHDI-253 * drivers/dahdi/voicebus/Makefile (added): voicebus: Need Makefile to build on 2.6.9 DAHDI-253 * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Define mmiowb if not already defined. Linux kernel 2.6.9 does not define mmiowb. DAHDI-253 * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: spin_trylock_irqsave is not defined on some kernels. DAHDI-253 * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Defined gfp_t for earlier kernels. This definition was just copied from the xpp driver. DAHDI-253 * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Fix inclusion of linux/io.h on 2.6.9 kernels. DAHDI-253 2009-04-30 20:59 +0000 [r6544-6546] Kevin P. Fleming * include/dahdi/user.h: Fix compilation of applications that use DAHDI ioctls Defining ioctl codes in this file requires that linux/ioctl.h be included first. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wctdm24xxp/base.c: Ensure that vpmsupport=0 module parameter takes proper effect For these drivers, when the vpmsupport module parameter is set to zero, don't even register the span as supporting echo cancellation. DAHDI-250 2009-04-30 13:59 +0000 [r6542] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/FPGA_1161.hex: xpp: A new FPGA firmware to hopefully help with BRI/FXO. 2009-04-29 18:24 +0000 [r6523-6529] Shaun Ruffell * dahdi-linux version 2.2.0-rc2 released. * drivers/dahdi/dahdi_echocan_kb1.c, drivers/dahdi/wcte12xp/base.c, include/dahdi/user.h, include/dahdi/kernel.h, drivers/dahdi/adt_lec.c, drivers/dahdi/dahdi_echocan_jpah.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/ecdis.h, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/dahdi_echocan_mg2.c, drivers/dahdi/wcte12xp/wcte12xp.h, drivers/dahdi/voicebus/GpakCust.c, drivers/dahdi/hpec/hpec.h, drivers/dahdi/wcb4xxp/wcb4xxp.h, drivers/dahdi/dahdi_echocan_sec2.c, drivers/dahdi/voicebus/GpakCust.h, drivers/dahdi/hpec/dahdi_echocan_hpec.c, include/dahdi/dahdi_config.h, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/dahdi_echocan_oslec.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_echocan_sec.c: echocan: Improve interface for echo cancelers. Echo cancelers are now able to report if they are able to automatically disable their NLP portions in the presence of tones in the audio stream. Also, the interface is changed to allow user space to just disable the NLP portion of the echo canceler. These changes improve fax and modem handling in DAHDI. This commit merges in the changes on http://svn.digium.com/svn/dahdi/linux/team/kpfleming/echocan_work Patch by: kpfleming Also contains improvements to CED tone detection. (closes issue #13286) Reported by: viniciusfontes * drivers/dahdi/wct4xxp/base.c: wct4xxp: Fix problem when timing source is via external cable. * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/voicebus.c (removed), drivers/dahdi/wcte12xp/vpmadt032.c (removed), drivers/dahdi/voicebus (added), drivers/dahdi/voicebus/voicebus.c (added), drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/Kconfig, drivers/dahdi/wcte12xp/wcte12xp.h, drivers/dahdi/wcte12xp/GpakErrs.h (removed), drivers/dahdi/wctdm24xxp/GpakApi.c (removed), drivers/dahdi/wcte12xp/vpmadt032.h (removed), drivers/dahdi/wctdm24xxp/voicebus.c (removed), drivers/dahdi/voicebus/voicebus.h (added), Makefile, drivers/dahdi/wctdm24xxp/GpakApi.h (removed), drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c (added), drivers/dahdi/wcte12xp/Kbuild, drivers/dahdi/voicebus/Kbuild (added), drivers/dahdi/wctdm24xxp/GpakHpi.h (removed), drivers/dahdi/wctdm24xxp/Kbuild, drivers/dahdi/voicebus.c (removed), drivers/dahdi/voicebus.h (removed), drivers/dahdi/vpmadt032_loader (added), drivers/dahdi/wcte12xp/GpakApi.c (removed), drivers/dahdi/wcte12xp/gpakenum.h (removed), drivers/dahdi/Kbuild, drivers/dahdi/voicebus/gpakenum.h (added), drivers/dahdi/voicebus/GpakApi.c (added), drivers/dahdi/adt_lec.c, drivers/dahdi/wcte12xp/GpakApi.h (removed), drivers/dahdi/voicebus/GpakApi.h (added), drivers/dahdi/voicebus/GpakCust.c (added), drivers/dahdi/wctdm24xxp/gpakenum.h (removed), drivers/dahdi/voicebus/gpakErrs.h (added), drivers/dahdi/wctdm24xxp/GpakCust.c (removed), drivers/dahdi/voicebus/GpakCust.h (added), drivers/dahdi/voicebus/GpakHpi.h (added), drivers/dahdi/wctdm24xxp/gpakErrs.h (removed), drivers/dahdi/firmware/Makefile, drivers/dahdi/voicebus/vpmadtreg.c (added), drivers/dahdi/wctdm24xxp/GpakCust.h (removed), drivers/dahdi/voicebus/vpmadtreg.h (added), drivers/dahdi/wctdm24xxp/wctdm24xxp.h: voicebus: Move common vpmadt032 interface into voicebus module. The voicebus library was previously linked into both the wcte12xp and wctdm24xxp drivers. It is now broken out into it's own module and the common parts of the vpmadt032 interface are now located in that module to reduce duplication between the wcte12xp and wctdm24xxp drivers. * drivers/dahdi/wctc4xxp/base.c: wctc4xxp: Change netif_rx_xxx to napi_xxx The netif_rx_xxx functions were dropped from the linux kernel source on 2009-01-21 in commit 288379f050284087578b77e04f040b57db3db3f8. (closes issue #14963) Reported by: tzafrir * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/vpmadt032.c, drivers/dahdi/wcte12xp/wcte12xp.h: wcte12xp: Update cmdqueue processing. The command queue for reading from the registers on the framer is now stored in a linked_list instead of an array. Allows for the locks to protect this structure to be held for shorter periods of time and reduces the need to cycle through all the elements in the array to decide if there is a command in the queue to process. Remove the usecount and dead members from struct t1 since the module reference count will allow us to know when it's safe to free up the memory. This change also moves alarm processing out of the interrupt handler and removes the need for special interrupt handling of commands. * drivers/dahdi/dahdi_dummy.c: dahdi_dummy: Remove real-time clock support. This removes support for using the real-time clock as a timing source in dahdi_dummy. Instead, the normal kernel timers method is now more accurate since it keeps track of how much real time has passed to determine how many times to call dahdi_receive and dahdi_transmit. This method was originally suggested by bmd. (closes issue #13930) (closes issue #14884) Reported by: tzafrir Tested by: dbackeberg, ask * drivers/dahdi/voicebus.c: voicebus: Removing unused code blocks and space in flag definitions. 2009-04-27 20:03 +0000 [r6513] Tzafrir Cohen * drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/Kbuild: xpp: hard_hdlc support for the BRI module. The BRI module will now use hardhdlc unless the DAHDI tree has been patched with the bri_dchan patch, in which case the old "bristuffed" code will be used. Thus it is now built by default. 2009-04-25 16:35 +0000 [r6487] Tzafrir Cohen * build_tools/live_dahdi: adapt live_dahdi to current xpp tools * More varibles to set through the environment * Different way to list drivers 2009-04-23 15:11 +0000 [r6457-6466] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/PIC_TYPE_3.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_4.hex, drivers/dahdi/xpp/firmwares/USB_FW.hex, drivers/dahdi/xpp/firmwares/FPGA_1161.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_2.hex: Don't set the Id keyword on firmwares; restore original ID The Id SVN keyword is set locally in Xorcom and used as an identifier. That Id should not be overriden by this SVN repository. * drivers/dahdi/xpp/firmwares/FPGA_1161.hex: xpp: FPGA_1161.hex: fix FXO PCM issues (new boards only) FPGA_1161.hex rev. 7024. 2009-04-22 12:53 +0000 [r6444] Kevin P. Fleming * drivers/dahdi/dahdi-base.c: don't refer to macros from dahdi_config.h until after it has been included use the proper type for the flags variable in dahdi_ppp_xmit() 2009-04-21 22:16 +0000 [r6430] Tzafrir Cohen * include/dahdi/user.h, include/dahdi/kernel.h: Move DAHDI_DEFAULT_MTU_MRU from kernel.h to user.h The macro DAHDI_DEFAULT_MTU_MRU needs to be exposed to userspace to build tools/ppp/dahdi.c . 2009-04-20 10:49 +0000 [r6407-6409] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/PIC_TYPE_3.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_4.hex, drivers/dahdi/xpp/firmwares/FPGA_1161.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex, drivers/dahdi/xpp/firmwares/PIC_TYPE_2.hex: xpp firmware: stability fixes for firmwares of new Astribanks FPGA_1161.hex: xpp rev 7007 PIC_TYPE_*.hex: xpp rev 7000 * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xpp_dahdi.h, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_fxs.c: xpp: Do use information about number of ports the Astribank provides * drivers/dahdi/xpp/init_card_1_30: xpp: Fix FXS calibration (dec rather than hex) 2009-04-16 19:35 +0000 [r6376-6393] Tzafrir Cohen * drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/init_card_1_30, drivers/dahdi/xpp/init_card_2_30: xpp fxs/fxo: PCM and DTMF fixes * drivers/dahdi/xpp/card_fxs.c: xpp fxs: Notify the user just one about wrong VMWI config From xpp rev. 6974. * drivers/dahdi/xpp/card_fxs.c: xpp fxs: Ignore registers of disabled SLICs From xpp rev. 6979 * drivers/dahdi/xpp/card_bri.c: xpp bri: explicitly turn off leds on startup If NT/TE was changed (e.g: happened because of firmware bug) We would be left with a lit led we don't know about. From xpp rev. 6990 2009-04-10 09:53 +0000 [r6344] Tzafrir Cohen * drivers/dahdi/xpp/astribank_hook.sample (removed): Move astribank_hook from linux to tools. Install it by default 2009-04-04 14:22 +0000 [r6325] Tzafrir Cohen * Makefile: Also install dahdi_config.h to /usr/include/dahdi 2009-04-02 20:34 +0000 [r6301-6312] Tzafrir Cohen * drivers/dahdi/xpp/astribank_hook.sample: Update the sample udev astribank_hook for TwinStar * drivers/dahdi/xpp/firmwares/PIC_TYPE_3.hex (added), drivers/dahdi/xpp/xpp.rules, drivers/dahdi/xpp/firmwares/PIC_TYPE_4.hex (added), drivers/dahdi/xpp/.version, drivers/dahdi/xpp/firmwares/FPGA_1161.hex (added), drivers/dahdi/xpp/firmwares/USB_FW.hex, drivers/dahdi/xpp/firmwares/Makefile, drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex (added), drivers/dahdi/xpp/firmwares/PIC_TYPE_2.hex (added): XPP: support for 116x Astribanks. * New software to load in the udev rules * New control protocol ("MPP") * More modular FPGA firmware From Xorcom rev. 6963. * drivers/dahdi/xpp/xbus-pcm.c: Reduce the rate for a potentially annoying message This message is used when an xpp span is a DAHDI sync master but also set to take timing from the DAHDI master. This means wrong settings: user is wasting CPU cycles. However notifying the user about it every second is still too much. 2009-04-02 17:27 +0000 [r6285-6294] Kevin P. Fleming * drivers/dahdi/dahdi-base.c: ensure that the structure being returned by DAHDI_GET_BUFINFO is completely initialized 2009-03-26 18:33 +0000 [r6262] Wendell Thompson * drivers/dahdi/voicebus.c: Fixes DAHDI-214 crash on driver unload. Affects wcte12xp and wctdm24xxp modules. 2009-03-24 19:08 +0000 [r6237-6246] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Eliminate unnecessary checks for NULL before freeing memory. * drivers/dahdi/wctc4xxp/base.c: Do not allocate more memory than is needed when sending packets. * drivers/dahdi/wctc4xxp/base.c: Block runt packets from the transcoder. Tested by: Walter Klomp * drivers/dahdi/wctc4xxp/base.c: Do not define the debug flags if CONFIG_SLUB is not set. Some versions of the kernel (2.6.18-92.1.22.el5) have patches in them to panic if a slab cache is created with unsupported flags. 2009-03-24 15:59 +0000 [r6236] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: Make sure the requested echo canceller name is NULL-terminated. Make sure that the that the name of the echo canceller requested in the DAHDI ioctl DAHDI_ATTACH_ECHOCAN is NULL-terminated. 2009-03-23 23:49 +0000 [r6217-6228] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Verify checksum on the RTP IP header before queueing. * drivers/dahdi/wctc4xxp/base.c: Poll the card in a kernel timer when several channels are open. Polling the driver increases overall system throughput when there are several transcoding channels open by reducing the number of interrupts the the TC400M generates. * drivers/dahdi/wctc4xxp/base.c: Optionally show total number of packets dropped when channel is closed. * drivers/dahdi/wctc4xxp/base.c: Do not handle duplicate reponses. It is possible for system activity to prevent the wctc4xxp driver from responding the the firmware on the TC400M for a period of time. If this occurs, the TC400M will resend a response to a command that we sent. This duplicate reponse will then sometimes confuse the driver. Normally this would manifest as an attempt to connect the same channel together in a transcoding session. * drivers/dahdi/wctc4xxp/base.c: Set TX_COMPLETE atomically with changes to the waiting_for_response_list. This change is to catch a condition where it is possible, for whatever reason, for a response to come in before the request is marked tx complete. If this happened, it was possible to leak the response packet and double complete the command. * drivers/dahdi/wctc4xxp/base.c: split send_trans_connect into a connect / disconnect pair. Trivial change that makes the code read more naturally. Also changes the order of members in the channel_pvt structure. For more natural alignment. Both non-functional changes. * drivers/dahdi/wctc4xxp/base.c: If the driver fails to register, make sure we cleanup the command cache. * drivers/dahdi/wctc4xxp/base.c: Setup the TC400M to poll the own bit on the descriptor ring. On certain systems having the hardware poll the descriptor ring provides more reliable operation that strobbing the transmit demand poll and receive demand poll register. * drivers/dahdi/wctc4xxp/base.c: Make sure that messages sitting in the outbound queue cause the timer to reschedule. * drivers/dahdi/wctc4xxp/base.c: Refactor channel command handling. Makes commands and reponses clearer and easier to trouble shoot, reduces pressure on the stack, and brings driver closer to kernel coding standards. 2009-03-18 18:48 +0000 [r6201] Jason Parker * drivers/dahdi/dahdi_dynamic_loc.c: Fix a typo 2009-03-17 17:59 +0000 [r6170-6191] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/USB_FW.hex: xpp USB_FW.hex rev 6885: fixes reading label from USB Previous USB_FW.hex, 6770, has failed to properly read the USB iSerial field ("Label" in xpp terms). This is fixed here. * include/dahdi/dahdi_config.h (added), include/dahdi/kernel.h, drivers/dahdi/xpp/Kbuild, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_config.h (removed): Move dahdi_config.h to be under include/dahdi/ This makes dahdi_config.h part of the "offcial" interface to external modules. Practically most of its configuration items are internal to dahdi-base. But some are intended for other drivers. * drivers/dahdi/biquad.h, include/dahdi/kernel.h, drivers/dahdi/ecdis.h, drivers/dahdi/dahdi-base.c: Make ecdis.h used by dahdi-base.h alone ecdis.h is no longer #include-d in kernel.h . it was there because of decleration of some structs that are part of struct dahdi_chan. The declerations of those structs were moved into kernel.h directly. 2009-03-13 10:21 +0000 [r6134-6147] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: Fix handling of 'w' in a pulse dial string Make the special "digit" 'w' work in pulse dialing as it works with tone dialing (a delay of 0.5 second till the next digit). Note that the digit gets uppercased before it gets to this function. (closes issue #13999) Reported by: IgorG Patches: dahdi-base.c.pulse2.diff uploaded by tzafrir (license 46) Tested by: litnimax * drivers/dahdi/xpp/xpp.conf: A better sample xpp.conf * drivers/dahdi/xpp/init_card_3_30, drivers/dahdi/xpp/init_card_4_30, drivers/dahdi/xpp/init_card_1_30, drivers/dahdi/xpp/init_card_2_30: xpp init_card_* scripts now less verbose * Demote some messages to be debug messages. * Rephrase the message about defaults for the PRI module (the driver's defaults are used, which is OK) * drivers/dahdi/dahdi-base.c: Fix handling of DAHDI_GETGAINS_V1 missing from r6124 . 2009-03-11 14:51 +0000 [r6113-6126] Shaun Ruffell * drivers/dahdi/voicebus.c: Allow 10ms for voicebus hardware to settle after reset. The voicebus hardware needs more time to settle after a reset. The short settle time explains why there was frequently one IRQ miss reported in the proc file for the spans. Reported by: jsloan * drivers/dahdi/wct4xxp/base.c: Relax ident wheel requirements. Do not require the first card to be set to 0 and allow skips in the ident wheel numbers. The ident wheel allows a user to determine the order that cards register there spans with DAHDI. (closes issue #13078) Reported by: opticron Patch by: opticron * include/dahdi/user.h, drivers/dahdi/dahdi-base.c: Fix direction bits on several ioctls. (related to issue #14499) Reported by: ys * include/dahdi/kernel.h, drivers/dahdi/dahdi_transcode.c: Keep transcoders on a list in registration order. This fixes a bug where it was possible for there to be a transcoder in position "1" but not in position "0" if a transcoder hardware driver was loaded, unloaded, and reloaded again without also reloading dahdi_transcode. The result is that codec_dahdi fails to enumerate all the transcoders in the system. (closes issue #14627) Reported by: xblurone * drivers/dahdi/dahdi-base.c: Eliminating an unused parameter to dahdi_specchan_open. 2009-03-06 21:43 +0000 [r6096] Wendell Thompson * drivers/dahdi/xpp/xpp_usb.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/voicebus.c: Workarounds for SLUB sysfs problems in kernel 2.6.22 with CONFIG_SLUB and CONFIG_SLUB_DEBUG, as in Fedora Core 6. Fixes kernel oops when loading/unloading dahdi modules. DAHDI-226 2009-03-05 18:53 +0000 [r6079] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/FPGA_1141.hex, drivers/dahdi/xpp/firmwares/FPGA_1151.hex, drivers/dahdi/xpp/firmwares/FPGA_FXS.hex: xpp: FPGA firmwares 6799 New FPGA firmware with a number of bug fixes. 2009-03-01 13:56 +0000 [r6046] Tzafrir Cohen * drivers/dahdi/xpp/init_card_3_30, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/.version, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xpp_dahdi.h, drivers/dahdi/xpp/firmwares/USB_FW.hex, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xframe_queue.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/Changelog_xpp, drivers/dahdi/xpp/card_global.h, drivers/dahdi/xpp/xbus-pcm.c: New XPP code: xpp rev 6795: * Fix cases where the command_queue overflowed during initialization. - Also add a 'command_queue_length' parameter to xpp.ko * More migrations to sysfs: - Add a 'transport' attribute to our astribank devices which points to the usb device we use. E.g: /sys/bus/astribanks/devices/xbus-00/transport is symlinked to ../../../../../../devices/pci0000:00/0000:00:10.4/usb5/5-4 - Move /proc/xpp/XBUS-??/XPD-??/span to /sys/bus/xpds/devices/??:?:?/span - Migrate from /proc/xpp/sync to: /sys/bus/astribanks/drivers/xppdrv/sync - New 'offhook' attribute in: /sys/bus/xpds/devices/??:?:?/offhook * PRI: change the "timing" priority to match the convention used by other PRI cards -- I.e: lower numbers (not 0) have higher priority. * FXO: - Power denial: create two module parameters instead of hard-coded constants (power_denial_safezone, power_denial_minlen). For sites that get non-standard power-denial signals from central office on offhook. - Don't hangup on power-denial, just notify Dahdi and wait for - Fix caller-id detection for the case central office sends it before first ring without any indication before. Asterisk's desicion. * USB_FW.hex: - Fixes cases where firmware loading would fail. 2009-02-11 05:41 +0000 [r6005] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Use the proper pci_device when handling dma buffers. 2009-02-10 14:07 +0000 [r5997] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Set default alarm debounce time to 500ms to debounce NT L1 deactivations 2009-02-09 06:03 +0000 [r5987] Tzafrir Cohen * drivers/dahdi/xpp/xproto.c: Fix building DAHDI with module unloading disabled As moduel_refcount is only used for debugging, disable it in this non-common case. (Closes issue #14402) 2009-02-02 14:13 +0000 [r5936] Kevin P. Fleming * drivers/dahdi/dahdi_echocan_kb1.c, drivers/dahdi/hpec/dahdi_echocan_hpec.c, include/dahdi/kernel.h, drivers/dahdi/dahdi_echocan_jpah.c, drivers/dahdi/dahdi_echocan_mg2.c, drivers/dahdi/dahdi_echocan_oslec.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_echocan_sec.c, drivers/dahdi/hpec/hpec.h, drivers/dahdi/dahdi_echocan_sec2.c: Array-style echo canceller updates first appeared in Zaptel, because HPEC only supports that mode. However, when the function for doing array-style updates was written, the argument names were reversed. In Zaptel this did no harm, because HPEC was the only module that used array-style updates. When DAHDI was created, non-array-style updates were removed, and the existing modules were converted to using array-style updates. Unfortunately the new code was written based on the argument names, which were incorrect. This caused all the echo cancellers to be broken (except HPEC, although we did not know that at the time), and it was corrected by reversing the order of the arguments passed when the array-style update function was called (leading to a confusing mismatch). This fixed all the non-HPEC modules, but left HPEC broken, which was just discovered. This commit corrects all these problems, so that the argument names and the data passed actually make sense, and all the modules work properly. 2009-01-30 23:42 +0000 [r5924] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Make sure that we pass alarm notification up the stack whenever alarms occur on the B410P 2009-01-30 16:53 +0000 [r5916] Mike Spiceland * drivers/dahdi/wctdm24xxp/base.c: Do a stricter test for FXS modules. FXO modules will be hi-z during this time and the value will be undefined. This test ensures that FXO modules will not falsely trigger during FXS probes. The value of 0x88 from register 1 has been confirmed during this stage on quad and single port modules. 2009-01-28 23:17 +0000 [r5895] Richard Mudgett * include/dahdi/user.h: Minor comment rearangement to avoid possible confusion. 2009-01-28 04:41 +0000 [r5870] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Ensure the teignorered parameter is exposed as a module parameter. Related to issue #14031 . 2009-01-27 Shaun Ruffell * dahdi-linux version 2.1.0.4 released. * Fix for a kernel panic regression when heavily using pseudo channels (issue #14183) (merged r5811 and r5819 from the trunk) * Fix the safety check in tor2 to be for SPANS_PER_CARD (issue #13954) (merged r5590 from the trunk). 2008-12-17 Shaun Ruffell * dahdi-linux version 2.1.0.3 released. 2008-12-17 15:57 +0000 [r5535-5576] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Do not propogate received HDLC frames on channels that are not configured. Issue: DAHDI-217 * drivers/dahdi/wcb4xxp/base.c: Use %p to print out pointer values. * drivers/dahdi/wcb4xxp/base.c: Remove an endless while loop. * drivers/dahdi/wcte12xp/base.c: Quiet some warnings about possible use of uninitialized variables. * build_tools/live_dahdi: live_dahdi: Use the nonrelative path for the dahdi-tools folder in live_dahdi. 2008-12-15 Shaun Ruffell * dahdi-linux version 2.1.0.2 released. 2008-12-15 20:31 +0000 [r5534-5535] Shaun Ruffell * build_tools/live_dahdi: live_dahdi: Use the nonrelative path for the dahdi-tools folder in live_dahdi. * drivers/dahdi/wcte12xp/base.c: wcte12xp: do not release a spinlock that we did not acquire. 2008-12-12 14:32 +0000 [r5523] Kevin P. Fleming * drivers/dahdi/dahdi-base.c: use a format string for request_module, so the compiler will do the right thing 2008-12-11 Shaun Ruffell * dahdi-linux version 2.1.0.1 released. 2008-12-11 21:46 +0000 [r5509] Shaun Ruffell * include/dahdi/kernel.h: Add definition of dev_notice for kernels < 2.6.17. 2008-12-11 21:03 +0000 [r5498-5504] Tzafrir Cohen * drivers/dahdi/xpp/xbus-sysfs.c: One more place whe old-but-not-ancient hotplug is used. * drivers/dahdi/dahdi_echocan_oslec.c: Send all samples to OSLEC, rather than just the first. (closes issue #14036) Reported by: marcotasto Patches: dahdi_echocan_oslec.patch uploaded by marcotasto (license 635) * drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xdefs.h: Add a separate case for hotplug of kernels <= 2.6.9 . 2008-12-11 20:19 +0000 [r5497] Shaun Ruffell * drivers/dahdi/dahdi_dummy.c: If we're using the system tick, don't use the hrtimer interface. 2008-12-11 18:57 +0000 [r5482-5492] Tzafrir Cohen * drivers/dahdi/xpp/xbus-sysfs.c: Fix the xpp OLD_HOTPLUG fix. * drivers/dahdi/dahdi_dummy.c: Fix building dahdi_dummy for kernels 2.6.13, 2.6.14: Those kernels don't have RTC yet. * drivers/dahdi/wcb4xxp: Yet Another directory in which to ignore modules.order * drivers/dahdi/wcb4xxp/base.c: Remove an include that is not available before 2.6.15 and is not needed * drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/xbus-core.h: A bit less maigc with OLD_HOTPLUG_SUPPORT * drivers/dahdi/dahdi-base.c: Fixed a typo that broke building dahdi-base with kernels < 2.6.13 2008-12-11 16:43 +0000 [r5481] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Fix compilation issues on 2.6.15 and below kernels. Thanks tzafrir. 2008-12-09 Shaun Ruffell * dahdi-linux version 2.1.0 released. 2008-12-09 18:49 +0000 [r5453] Tzafrir Cohen * live_dahdi (added): live_dahdi - test dahdi without fully installing it. 2008-12-06 22:23 +0000 [r5444] Tzafrir Cohen * drivers/dahdi/xpp, drivers/dahdi/wcte12xp, drivers/dahdi, drivers/dahdi/wct4xxp, drivers/dahdi/wctc4xxp, drivers/dahdi/wctdm24xxp: Ignore modules.order in modules directories. 2008-12-04 20:57 +0000 [r5433-5434] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Fix an erroneous warning and ensure that the sample size is set correctly when decoding G723 packets. Issue: DAHDI-198 * drivers/dahdi/dahdi_transcode.c: Do not use an already built channel if the source and destination formats do not match the formats we want. This fixes a regression introduced by the new transcoder interface where a translation path from one complex codec to another can result in garbled audio. 2008-12-01 17:58 +0000 [r5413-5420] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Service the transmit descriptor ring before the receive descriptor ring so that commands that are still sitting on the transmit descriptor ring are not completed twice. 2008-11-27 09:59 +0000 [r5397-5403] Tzafrir Cohen * Makefile: dahdi-linux: Remove README.Astribank.html generation. * drivers/dahdi/xpp/README.Astribank (removed): Moving README.Astribank to dahdi-tools . * drivers/dahdi/xpp/README.Astribank: Fixes and some work in progress on DAHDI Astribank README. 2008-11-25 20:00 +0000 [r5384] Shaun Ruffell * drivers/dahdi/wcte11xp.c, drivers/dahdi/wct1xxp.c: Validate the timing priority on the wcte11xp and wct1xxp driver. 2008-11-25 Shaun Ruffell * dahdi-linux version 2.1.0-rc5 released. 2008-11-25 20:00 +0000 [r5383-5384] Shaun Ruffell * drivers/dahdi/wcte11xp.c, drivers/dahdi/wct1xxp.c: Validate the timing priority on the wcte11xp and wct1xxp driver. * drivers/dahdi/tor2.c: Validate that the span priority is valid in the tor2 driver. Patch provided by tzafrir. 2008-11-24 05:32 +0000 [r5367-5374] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Additional debugging code. Patch provided by akohlsmith. Issue DAHDI-173. * drivers/dahdi/wcb4xxp/base.c: Add a 'spanfilter' module parameter in order to isolate debugging information to just the spans of interest. Patch provided by akohlsmith. Issue DAHDI-173. * drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcb4xxp/wcb4xxp.h: Use counter of pending HDLC frames in order to eliminate the need to send a zero-byte frame to kick start the transmission process. Patch provided by akohlsmith. Issue DAHDI-173. * drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcb4xxp/wcb4xxp.h: Do not make assumptions about the number of ready HDLC frames on HDLC RX interrupt. This prevents libpri from becoming confused when many HDLC frames arrive before the driver can service them or a false RX interrupt is received. Patch provided by akolsmith. Issue DAHDI-173. 2008-11-21 20:15 +0000 [r5360] Jason Parker * drivers/dahdi/dahdi-base.c: Fix a think-o in numeric comparison. Swap order to make it more clear. (closes issue #13813) Reported by: ys 2008-11-21 04:42 +0000 [r5350-5355] Shaun Ruffell * drivers/dahdi/dahdi-base.c: Convert some uses of sprintf to snprintf in dahdi_proc_read in order to eliminate a buffer overrun. Issue: DAHDI-209 * drivers/dahdi/wcb4xxp/base.c: Force the FIFO to reset when the file handle is closed. Patch provided by akohlsmith. Issue: DAHDI-178 2008-11-20 12:31 +0000 [r5340-5345] Tzafrir Cohen * drivers/dahdi/tor2.c: Make tor2 load properly. Seems to fix #13487. Thanks to heyuqi for the testing. * drivers/dahdi/xpp/README.Astribank: * Some extrra Zap->DAHDI (and Dahdi->DAHDI) fixes in the Astribank README. * Some extra asciidoc formatting fixes. 2008-11-19 21:25 +0000 [r5335] Kevin P. Fleming * drivers/dahdi/wcb4xxp/Makefile (added): support wcb4xxp build on kernels that don't directly use Kbuild 2008-11-17 18:17 +0000 [r5321] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: - Fix for race condition of encoder and decoder are allocated at the same time in the driver. This would result in -EBUSY returns from the DAHDI_TC_ALLOCATE ioctl. - Increase the length of the receive descriptor ring from 8 to 32 to reduce the probability of running out of receive descriptors. 2008-11-17 Shaun Ruffell * dahdi-linux version 2.1.0-rc4 released. 2008-11-17 18:17 +0000 [r5321] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: - Fix for race condition of encoder and decoder are allocated at the same time in the driver. This would result in -EBUSY returns from the DAHDI_TC_ALLOCATE ioctl. - Increase the length of the receive descriptor ring from 8 to 32 to reduce the probability of running out of receive descriptors. 2008-11-17 18:01 +0000 [r5320] Tzafrir Cohen * drivers/dahdi/xpp/init_card_4_30, drivers/dahdi/xpp/card_pri.c: xpp_pri: Fix T1 CRC initialization Clock synchronization when sync is not from first port. 2008-11-17 17:44 +0000 [r5315] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/wcb4xxp/wcb4xxp.h: A fix for an issue with corruption on the D-Channels. Patch provided by akohlsmith. Issue: DAHDI-173. 2008-11-16 19:30 +0000 [r5310] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/USB_FW.hex: Fixed USB firmware that caused some bad bioses to hang on boot. The BIOSes included in a number of motherboards could hang from an Astribank firmware newer than 1.2.20.1 / 1.4.5.1 . This was due to an some incorrect USB information in the firmware. This firmware fixes it. Merged Zaptel revisions 4580 via svnmerge from http://svn.digium.com/svn/zaptel/branches/1.2 2008-11-13 22:10 +0000 [r5303] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/voicebus.c, drivers/dahdi/voicebus.h: Make a message about the host cacheline size being unsupported a debug only message. The voicebus interface still works whether the cacheline size is supported or not, but the message is confusing to users. 2008-11-10 20:37 +0000 [r5288] Tzafrir Cohen * drivers/dahdi/xpp/init_card_2_30: xpp init_card_2_30: no need to check environment in verify mode. Fixes #13832 in Zaptel. 2008-11-10 Shaun Ruffell * dahdi-linux version 2.1.0-rc3 released. 2008-11-10 19:48 +0000 [r5275] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/dahdi-base.c: - Do not hold any locks while calling close_channel, which can result in calls to the echocan modules which do not necesarrily assume they are being called in atomic context. - Remove the bigzaplock around calls to psuedo_alloc and pseudo_free. The structures protected by this lock are already protected by the chan_lock in these two cases. - Remove calls to in_atomic() that were previously added to work around this, but did not cover all the cases. Issue: DAHDI-195, DAHDI-170 2008-11-09 00:33 +0000 [r5269-5270] Sean Bright * drivers/dahdi/dahdi-base.c: We only use print_debug_writebuf when CONFIG_DAHDI_NET or CONFIG_DAHDI_PPP are defined, so only define it in those cases as well. Reported & Tested by: KP7 via #asterisk-dev * drivers/dahdi/dahdi-base.c: Add missing semi-colon. Reported & Tested by: KP7 via #asterisk-dev 2008-11-05 23:45 +0000 [r5249-5257] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Whitespace changes for the coding standard. * drivers/dahdi/wcb4xxp/base.c: rate limiting a diagnostic printk. 2008-11-05 Shaun Ruffell * dahdi-linux version 2.1.0-rc2 released. 2008-11-05 20:17 +0000 [r5230-5237] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Fix warning messages in order to build on 2.6.27. (Closes issue #13757) Patch provided by tzafrir. * drivers/dahdi/wcte12xp/vpmadt032.c, drivers/dahdi/wctdm24xxp/GpakCust.c: Check the return value of the down_interruptible call in order to quiet a warning. This semaphore does not protect any host data structures, but only accesses to the VPMADT032 module. The worse thing that could happen is that the internal state of the VPM module is corrupted, and then would only happen on module loading because otherwise access because that is the only time this function is called in the context of a user process. In this case, the module would need to be reloaded again anyway. (Closes issue #13742) Reported by smurfix * drivers/dahdi/wcb4xxp/base.c: Remove the loopback module parameter since it's not implemented yet. * drivers/dahdi/wcb4xxp/base.c: Allow the wcb4xxp to take all the signalling types. 2008-11-03 Shaun Ruffell * dahdi-linux version 2.1.0-rc1 released. 2008-11-03 12:01 +0000 [r5203-5211] Tzafrir Cohen * drivers/dahdi/dahdi_dummy.c: Adjust DAHDI to the new timers interface of kernel 2.6.28 * drivers/dahdi/dahdi-base.c: dahdi-base: hw_echocancel_off: return 0 if no hardware EC If the span has no hardware EC, return 0, rather than a random uninitialized value (which was no harm, as that return value is always ignored anyway). * README: README: no need to generate Kbuild for OSLEC. No need to create a Kbuild file. staging/echo has a Makefile that works fine for us. 2008-10-31 22:23 +0000 [r5196] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Changing the spantype to indicate whether it is a TE or NT BRI port. 2008-10-31 21:33 +0000 [r5195] Matthew Fredrickson * drivers/dahdi/wcb4xxp/base.c: Fix the FIFO configuration to use the data from the EC correctly 2008-10-31 21:05 +0000 [r5190-5191] Tzafrir Cohen * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Set the spantype to "BRI" (to show e.g. in dahdi_scan) * drivers/dahdi/wcb4xxp/base.c: wcb4xxp: Claim to provide DACS for dahdi_scan dahdi_scan can tell that a span is digital if its first channel has DACS signalling capability. While this is probably not supported by the current driver, it is also harmless. Without this, dahdi_scan shows the spans of this card as analog. (Done after consulting with sruffel) 2008-10-31 17:11 +0000 [r5186] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: Fix for a case where a span might not always come back up after a disconnect. Patch provided by akohlsmith. Issue: DAHDI-174 2008-10-30 19:16 +0000 [r5179-5180] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: Use correct length for the, well, dahdi transcoder device name. * drivers/dahdi/dahdi-base.c: Use ! to hint udev about directory separator. Udev knows how to convert a '!' in the device name to a directory separator. Thus the name 'dahdi!ctl' will create the device /dev/dahdi/ctl . We still keep older udev rules in this release for compatibility, but eventually we'll only need them to set permissions. 2008-10-29 16:48 +0000 [r5171-5175] Shaun Ruffell * drivers/dahdi/wcb4xxp/base.c: The /proc/wcb4xxp should not be created once for each card but rather once for all cards. * drivers/dahdi/wcb4xxp/base.c: By default, do not create the procfs entry for the wcb4xxp driver. 2008-10-29 15:09 +0000 [r5167] Tzafrir Cohen * drivers/dahdi/xpp/xbus-core.c: xpp: Increase the maximal size of the command queue to 500 . Temporarily increase the maximal size of the command queue from 300 to 500 as a workaround of an issue at initialization time (mainly of BRI+FXS). 2008-10-28 21:59 +0000 [r5156-5163] Kevin P. Fleming * drivers/dahdi: update to latest octasic_api tag with NULL definition fix * drivers/dahdi/tor2.c, drivers/dahdi/wcfxo.c, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wcte12xp/GpakApi.c, drivers/dahdi/pciradio.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wcte12xp/vpmadt032.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/dahdi_echocan_mg2.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wctdm24xxp/GpakApi.c, drivers/dahdi/wcte12xp/vpmadt032.h, drivers/dahdi/wctdm24xxp/GpakCust.c, drivers/dahdi/wcb4xxp/base.c, drivers/dahdi/dahdi_dynamic_loc.c, drivers/dahdi/dahdi_transcode.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/dahdi_dynamic.c, drivers/dahdi/dahdi_dynamic_eth.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/wctdm.c, drivers/dahdi/wcb4xxp, drivers/dahdi/voicebus.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_dummy.c: fix a large number of warnings found by sparse, the kernel code sanity checking tool. some of these fixes are non-optimal (casting 'unsigned long' to '__user void *'), but are unavoidable in many cases. started from tzafrir's patch, did most of the work myself. (closes issue #13763) Reported by: tzafrir Patches: sparse_fixes_1.diff uploaded by tzafrir (license 46) * README: various cleanups, primarily proper capitalization 2008-10-28 18:26 +0000 [r5148-5150] Shaun Ruffell * drivers/dahdi/wcb4xxp/Kbuild (added), drivers/dahdi/Kbuild, drivers/dahdi/wcb4xxp/base.c (added), drivers/dahdi/wcb4xxp (added), drivers/dahdi/wcb4xxp/wcb4xxp.h (added), README: Adding the wcb4xxp driver, a native dahdi driver for the B410P module. 2008-10-27 19:27 +0000 [r5127-5138] Tzafrir Cohen * README: dahdi linux README: Clarify OSLEC EC build procedure. * drivers/dahdi/xpp/card_fxo.c: xpp fxo: Add sysfs battery attribute. * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h: xpp: remove an unused manual reference count field. * drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xbus-sysfs.c: xpp: Make some definitions static, as per sparse. Fixes the xpp warnings of #13763 (except some false alarms). * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xdefs.h: Fix xpp compile problems on kernel < 2.6.16 Support for kernels that use the older hotplug support rather than the newer uevent. Fixes the xpp issue from #13427. * include/dahdi/kernel.h: kernel.h: cleanup DAHDI_FLAG_* defines, no functional change. Define the DAHDI_FLAG_* using the DAHDI_FLAGBIT_* enum values. 2008-10-22 18:49 +0000 [r5121-5124] Jason Parker * build_tools/genudevrules: Need to make sure we check for udevadm in addition to udevinfo. Some silly person (or people) decided that it wasn't useful to have in their distro... *cough* * drivers/dahdi/wctdm.c: Fix building on big endian machines. (closes issue #13754) Reported by: shrift Patches: wctdm-powerpc.patch uploaded by irroot (license 52) Tested by: shrift 2008-10-22 11:44 +0000 [r5105-5118] Tzafrir Cohen * drivers/dahdi/wct1xxp.c: wct1xxp: fix error handling at device startup. And also give more useful error messages if things go bad. (closes issue #13607) Patches: wct1xxp_pci.diff uploaded by tzafrir (license 46) Tested by: klaus3000 * drivers/dahdi/xpp/init_card_1_30: xpp FXS init script: Do use high-pass filter. * drivers/dahdi/Kbuild, drivers/dahdi/dahdi_echocan_oslec.c (added), README: An experimental OSLEC echocan module. * /: dahdi-trunk: ignore the generated README.html . * README: dahdi-linux README: better place for build requirements. (We'll have to put a content there one of these days) * README: Fix headers numbering. 2008-10-16 17:40 +0000 [r5097] Tzafrir Cohen * drivers/dahdi/xpp/xpp.rules, drivers/dahdi/xpp/xpp_usb.c, drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_fxo.c, drivers/dahdi/xpp/xframe_queue.c, drivers/dahdi/xpp/xbus-sysfs.c, drivers/dahdi/xpp/Kbuild, drivers/dahdi/xpp/card_fxs.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xproto.c, drivers/dahdi/xpp/xframe_queue.h, drivers/dahdi/xpp/astribank_hook.sample (added), drivers/dahdi/xpp/init_card_1_30, drivers/dahdi/xpp/xbus-pcm.c, drivers/dahdi/xpp/init_card_2_30, drivers/dahdi/xpp/card_global.h, drivers/dahdi/xpp/init_card_3_30, drivers/dahdi/xpp/xproto.h, drivers/dahdi/xpp/xpp_dahdi.c, drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/init_card_4_30, drivers/dahdi/xpp/xpp_dahdi.h, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/mmapdrv.c, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/xbus-core.h, drivers/dahdi/xpp/xdefs.h: xpp: start migration from procfs to sysfs. * Sysfs representation for XPDs: /sys/bus/xpds/devices/:: * Astribanks sysfs directories now include the XPDs as subdirectories: e.g. /sys/bus/astribanks/devices/xbus-00/00:3:0 * procfs control interface deprecated: conditioned by OLD_PROC (defaults to off). Control functionality moved to sysfs: * xbus attributes: cls connector label status timing waitfor_xpds xbus_state * XPDs can have driver-specific attributes. Common attriubtes: blink chipregs span * PRI-specific attributes: pri_clocking pri_dchan pri_cas pri_alarms pri_layer1 pri_localloop pri_protocol * The Astribank attribute "xbus_state" is read/write. Reading it shows the current state of the Astribank. Writing "start" or "stop" allows a software equivalent of connect or disconnect respectively. * When an Astribank is ready it sends an "online" event. Whenever its not ready (e.g. at the time of disconnect) it sends an "offline" event. Use astribank_hook.sample to handle those. 2008-10-14 22:11 +0000 [r5090] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: If the vpmadt032 firmware needs to be reloaded, make sure we use the same slot in the ifaces array. 2008-10-10 22:38 +0000 [r5084] Shaun Ruffell * drivers/dahdi/dahdi_transcode.c, drivers/dahdi/wctc4xxp/base.c: - Ensure that the source format is considered when selecting a transcoder. - When a command is to be retried, turn off the TX_COMPLETE flag before resubmitting it to the hardware. This should elimate some of the warnings printed to the kernel log in the wctc4xxp_transmit_cmd function. 2008-10-09 02:54 +0000 [r5068] Kevin P. Fleming * drivers/dahdi/dahdi-base.c: a micro-optimization found while creslin and i spent four or five hours tracking down a very complex problem 2008-10-06 20:52 +0000 [r5064] Kevin P. Fleming * drivers/dahdi/dahdi-base.c: use the same logic here as elsewhere for releasing echocan module references 2008-10-06 17:48 +0000 [r5060] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Embed room for the complete packet to the DTE in the transcoder buffer structure. Simplifies alignment management at the cost of a little wasted memory, but the end results is that operation is more reliable on more systems. 2008-10-06 16:55 +0000 [r5056] Sean Bright * drivers/dahdi/dahdi-base.c: Fix a few compile errors that only show up when CONFIG_DAHDI_PPP is defined. (closes issue #13608) Reported by: Nik Soggia Fix suggested by: Nik Soggia Tested by: seanbright 2008-10-03 20:32 +0000 [r5046-5051] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: Fix building with CONFIG_DAHDI_NET in kernel 2.6.22 The leftovers of issues #13542 (which was mostly resolved in previous committ. This closes it. * drivers/dahdi/dahdi-base.c: Fix building with CONFIG_DAHDI_NET . It builds, but will it run? Patch dahdi-base.c.hdlc.patch by biohumanoid that fixes some aparant copy&paste errors. 2008-10-03 20:09 +0000 [r5045] Sean Bright * drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_config.h: Fix some compilation problems that show up when CONFIG_DAHDI_DEBUG is defined. 2008-10-03 15:39 +0000 [r5021-5034] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: There are two possible valid statues when booting the TC400M. * drivers/dahdi/wctc4xxp/base.c: Keep hold of the channel lock when setting the data_ready flag for the channel after writing to the receive queue. Prevents a warning that data was on the recieve queue but the data ready flag was not set. Issue: DAHDI-42 * drivers/dahdi/wctc4xxp/base.c: wctc4xxp_cleanup_channel_private needs a pointer to the zt_transcoder_channel and not just the private portion now in order to manage the data ready flag state. * drivers/dahdi/wctc4xxp/base.c: Mark that there is not any data waiting whenever we cleanup the private channel structures. Issue: DAHDI-42 * drivers/dahdi/dahdi-base.c: DAHDI should always make data received from the PSTN available to user mode immediately. Only allow the transmit buffering policy to be changed in order to reduce the chance of underruns to the PSTN. 2008-09-30 20:29 +0000 [r5017] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Removing references to setup_timer in pre 2.6.18 kernels. 2008-09-29 Shaun Ruffell * dahdi-linux 2.0.0 released. 2008-09-28 17:29 +0000 [r5002-5007] Shaun Ruffell * drivers/dahdi/wctdm.c: Improve reliablity of UK caller ID for the TDM400P by not allowing the ringdebounce to be decremented when it is at 0 already. Related to issue #12531. Reported mattbrown, fix suggested by benbrown. * drivers/dahdi/wcte12xp/base.c: Fixed type of flags parameter to spin_lock_irqsave functions. Fixes compilation issues on platforms where int and long do not have the same size. Closes Issues #0013575. Reported by Ulmo. * drivers/dahdi/dahdi_echocan_kb1.c, drivers/dahdi/dahdi_echocan_mg2.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/dahdi_echocan_sec.c, drivers/dahdi/dahdi_echocan_sec2.c: Fixes failure of modular echo cancelers in DAHDI. Reported by lots of people, fix suggested by mattf. 2008-09-26 03:20 +0000 [r4990] Shaun Ruffell * drivers/dahdi/dahdi-base.c: The channel master should not be set to 0, but rather should be 'cleared' by setting the channel to be it's own master. (related to issue 11611) 2008-09-25 16:50 +0000 [r4979-4986] Tzafrir Cohen * drivers/dahdi/xpp/firmwares/FPGA_1151.hex: XPP firmware: Only send out CAS D-channel messages when in CAS mode. * drivers/dahdi/xpp/init_card_3_30, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/init_card_1_30, drivers/dahdi/xpp/init_card_2_30: Fix display of indirect registers and streamline their setting. * This commit fixes display of indirect registers through the chipregs (formly "slics") procfs file. Only the low byte was displayed. * It also deprecates previous {RW}S in favour of {RW}I. The prevois style is still allowed but deprecated, and thus previous scripts will still work. * drivers/dahdi/xpp/card_fxo.c: XPP FXO: Add caller-id workaround for ESTI-DTMF (for #9096) * Also rename the CID_STYLE_* constants to formal names. 2008-09-24 06:15 +0000 [r4971] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Adding back in the mode module parameter for the wctc4xxp driver. This is primarily used to increase the number of channels available when only transcoding to/from g729 by setting it to 'g729'. 2008-09-18 21:23 +0000 [r4957] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c: Adding a needed header for the in_atomic call. 2008-09-18 21:23 +0000 [r4956-4957] Shaun Ruffell * drivers/dahdi/wcte12xp/base.c, drivers/dahdi/dahdi-base.c: close_channel is called with a spin_lock held, which means that GFP_KERNEL can not be used for the memory allocations down that call path. Have allocations in this call path check if they are in atomic context and use the appropriate flags. Issue: DAHDI-195 2008-09-17 19:07 +0000 [r4917-4930] Shaun Ruffell * README: Just moved a note into it's own paragraph so that asciidoc can make the appropriate callout. * README: Added a note about installing support for the B410P in the installation section of the README file. * drivers/dahdi/dahdi-base.c: Turn off reference counting on the echo canceller modules in order to prevent misconfigurations from preventing the drivers from unloading. NOTE: This is only a temporary workaround, since it also means that the echocanceller can be unloaded by an administrator while in use, which would most likely result in a kernel oops. Related to issue #13504. 2008-09-15 20:49 +0000 [r4905-4909] Shaun Ruffell * drivers/dahdi/wctdm.c, drivers/dahdi/dahdi-base.c: Edit some comments and error strings. Issue: DAHDI-13 * drivers/dahdi/wcte12xp/vpmadt032.c, drivers/dahdi/wctdm24xxp/base.c: Fixed two typos. 2008-09-11 23:00 +0000 [r4894-4900] Tzafrir Cohen * drivers/dahdi/dahdi-base.c: Fix a type used in nethdlc mode, as pointed out in #13427 . * drivers/dahdi/xpp/xpp.rules (added), Makefile: Move udev rules xpp.rules from dahdi-tools to dahdi-linux . 2008-09-08 Russell Bryant * dahdi-linux version 2.0.0-rc4 released. 2008-09-06 20:27 +0000 [r4868-4870] Matthew Fredrickson * drivers/dahdi/dahdi-base.c: Fix buglet in #define for 2.6.9 * drivers/dahdi/wct4xxp/base.c: Revert unnecessary default hardhdlc mode from 56K to 64K * drivers/dahdi/wct4xxp/base.c, drivers/dahdi/dahdi-base.c: Fix class_simple on old 2.6.9 kernels 2008-09-04 21:42 +0000 [r4865] Matthew Fredrickson * include/dahdi/fasthdlc.h: Some picky switches require the LSB to be 1 for 56k links 2008-09-04 21:29 +0000 [r4861-4864] Shaun Ruffell * drivers/dahdi/wct4xxp/base.c: Remove a couple of 'magic numbers' to make it clear all the ports of the framer should be configured. * drivers/dahdi/wct4xxp/base.c: Fixes an issue where the dual-span cards are not properly configured which can cause data loss. Fix provided by opticron and possibly related to issue #0013393. 2008-08-29 21:46 +0000 [r4856] Matthew Fredrickson * drivers/dahdi/dahdi-base.c: Remove useless kzalloc 2008-08-27 17:12 +0000 [r4848-4849] Kevin P. Fleming * drivers/dahdi/dahdi_dummy.c: remove some more ztdummy references * drivers/dahdi/wcfxo.c, drivers/dahdi/wcte12xp/base.c, drivers/dahdi/wct4xxp/base.c, drivers/dahdi/wcte11xp.c, drivers/dahdi/wct1xxp.c, drivers/dahdi/wctc4xxp/base.c, drivers/dahdi/wctdm.c, drivers/dahdi/wctdm24xxp/base.c, README: a bit of attribution cleanup 2008-08-27 16:48 +0000 [r4847] Jason Parker * Makefile: Set a list of headers to install/uninstall, so the lists don't get out of sync (note the previously missing fasthdlc.h in the uninstall-include target) 2008-08-26 13:04 +0000 [r4829-4841] Tzafrir Cohen * Makefile: "docs" target to generate documentation. Generate docs with asciidoc. * drivers/dahdi/xpp/README.Astribank: Fix asciidoc. * Makefile: Don't try to clean modules if there's no kernel source available (like in Zaptel). * README: Reverting unwanted changes in the README (from r4830) Also fixed ZT references in the ABI compatibility section. The numerical ioctl values need to be recalculated, though. * README: Make the README file more relevant to modules. * drivers/dahdi/Kbuild, Makefile: Support MODULES_EXTRA and SUBDIRS_EXTRA to add extra modules from the make command line. 2008-08-25 17:50 +0000 [r4828] Jason Parker * Makefile: Make sure we remove headers that we installed in install-include 2008-08-25 14:54 +0000 [r4823] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Remove this warning, which could occur if the driver is loaded on a system without a wctc4xxp, and then subsequently unloaded. 2008-08-24 05:53 +0000 [r4817] Matthew Fredrickson * include/dahdi/user.h, include/dahdi/kernel.h, drivers/dahdi/dahdi-base.c, include/dahdi/fasthdlc.h: Add support for 56 KB HDLC as well as selectable rate via ioctl 2008-08-20 22:20 +0000 [r4805] Kevin P. Fleming * drivers/dahdi/dahdi_dynamic.c: use the new separate allocation method for channel structures here too replace "ZTD" references in channel/span names with "DYN" (closes issue #13302) Reported by: KNK 2008-08-20 Kevin P. Fleming * dahdi-linux version 2.0.0-rc3 released. 2008-08-20 22:20 +0000 [r4801-4805] Kevin P. Fleming * drivers/dahdi/dahdi_dynamic.c: use the new separate allocation method for channel structures here too replace "ZTD" references in channel/span names with "DYN" (closes issue #13302) Reported by: KNK * drivers/dahdi/dahdi_dynamic.c: update code to match version in Zaptel * drivers/dahdi/xpp/xpd.h, drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wcte12xp/vpmadt032.c, drivers/dahdi/wctdm24xxp/base.c, drivers/dahdi/wctdm24xxp/GpakApi.c, drivers/dahdi/dahdi-base.c, drivers/dahdi/wctdm24xxp/GpakCust.c: improve compatibility with 2.6.26 and 2.6.27 kernels (closes issue #13253) Reported by: raiden Patches: zap-dev.patch uploaded by smurfix on issue #13277 (license 547) zap-sema.patch uploaded by smurfix on issue #13277 (license 547) 2008-08-20 19:31 +0000 [r4798] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Change to support both 5.3kbps and 6.3kbps bit rates when using the G723.1 codec. 2008-08-19 20:49 +0000 [r4795] Kevin P. Fleming * drivers/dahdi/firmware/Makefile: port over improvements to firmware Makefile from Zaptel 2008-08-19 20:25 +0000 [r4791-4794] Shaun Ruffell * drivers/dahdi/wctc4xxp/base.c: Fixed calculation of the timestamp. * include/dahdi/kernel.h, drivers/dahdi/dahdi_transcode.c, drivers/dahdi/wctc4xxp/base.c: Couple of fixes for the transcoder: - In dahdi_transcode.c, Embed the identifiation number, assigned sequentially when the transcoders are registered, in the transcoder structure. This allows DAHDI_TC_GETINFO to work as expected even though the transcoders are rotated on the list in order to spread the load. - In wctc4xxp, fix bug where all transcoders are named tc400b0. 2008-08-18 23:24 +0000 [r4788] Kevin P. Fleming * Makefile: minor cleanups, and allow DAHDI_BUILD_ALL to be overriden on the command line 2008-08-14 21:37 +0000 [r4776-4784] Tzafrir Cohen * drivers/dahdi/xpp/.version, drivers/dahdi/xpp/Changelog_xpp: Set xpp version to 6056 and reset XPP changelog. * drivers/dahdi/xpp/firmwares/Makefile (added), Makefile: Also install Astribank firmwares and init scripts to /usr/share/dahdi . * drivers/dahdi/xpp/card_fxo.c: xpp: FXO: display signed voltage values (from xpp r6055) This is only an issue with the displayed value. In case you wondered why you have battery voltage of more than 220V. 2008-08-14 01:09 +0000 [r4773] Kevin P. Fleming * drivers/dahdi/dahdi_transcode.c: remove devfs support, and use consistent include file path 2008-08-13 21:04 +0000 [r4770] Doug Bailey * drivers/dahdi/wctdm24xxp/wctdm24xxp.h, drivers/dahdi/wctdm24xxp/base.c: import the neon mwi detection 2008-08-11 16:22 +0000 [r4758-4761] Tzafrir Cohen * drivers/dahdi/xpp/card_pri.c, drivers/dahdi/xpp/card_bri.c, drivers/dahdi/xpp/firmwares/FPGA_1151.hex, drivers/dahdi/xpp/xbus-core.c, drivers/dahdi/xpp/card_global.c, drivers/dahdi/xpp/xbus-pcm.c: xpp: CAS/E1 support in the PRI module, and minor fixes. * Add support for CAS in the PRI module. Use firmware rev. 5975. * Debugging parameter pcmtx_chan now accepts a dahdi channel number. * Do initialize a reserved protocol field (card_global). * The name DAHDI as used in proc/xpp/sync has 5 (not 6) letters. * Fix DTMF "channel leak" regression in the FXS module. * drivers/dahdi/xpp/card_fxo.c: xpp: fxo: Fix support for CID_STYLE_PASS_ALWAYS * drivers/dahdi/xpp/Kbuild: A more robust test for bri_dchan support. * drivers/dahdi/xpp/xpd.h, drivers/dahdi/xpp/xpp_dahdi.c: xpp_blink is a bit mask of ports, and not boolean anymore. 2008-08-08 Kevin P. Fleming * dahdi-linux version 2.0.0-rc2 released. 2008-08-07 20:21 +0000 [r4742] Shaun Ruffell : * drivers/dahdi/dahdi_transcode.c: Make sure types are same size on 64-bit machines. 2008-08-06 Kevin P. Fleming * dahdi-linux version 2.0.0-rc1 released. dahdi-linux-2.5.0.1/UPGRADE.txt0000644000175000017500000000733411046420461015644 0ustar tzafrirtzafrir===================================================================== === Information for upgrading from Zaptel 1.2 or 1.4 to DAHDI 2.0 === ===================================================================== Upgrading from Zaptel to DAHDI is fairly straightforward; install this package using the installation instructions, and then reconfigure and rebuild Asterisk; Asterisk 1.4 releases later than 1.4.21, and all releases of Asterisk 1.6, will automatically use DAHDI in preference to Zaptel, even if Zaptel is still installed on the system. Important notes about upgrading: * The Zaptel package, which included both kernel modules and userspace tools for configuring and managing the modules, has been split into two packages: dahdi-linux: kernel modules dahdi-tools: userspace tools In addition, there is a dahdi-linux-complete package that contains both dahdi-linux and dahdi-tools for simplified installation. Note: The dahdi-linux and dahdi-tools packages have *separate* version numbers; they will not be released 'in sync', and it is perfectly acceptable to use (for example) dahdi-tools 2.0.6 with dahdi-linux 2.0.11. The dahdi-linux-complete package version number will always include *both* of these version numbers so that you will know what is included in it. Notes about the dahdi-linux package: * The primary kernel modules have changed names; the new names are: zaptel.ko -> dahdi.ko ztd-eth.ko -> dahdi_dynamic_eth.ko ztd-loc.ko -> dahdi_dynamic_loc.ko ztdummy.ko -> dahdi_dummy.ko ztdynamic.ko -> dahdi_dynamic.ko zttranscode.ko -> dahdi_transcode.ko * The kernel modules for card drivers have *not* changed names, although the wcusb and torisa drivers are no longer included. * This package no longer includes the 'menuselect' utility for choosing which modules to build; all modules that can be built are built automatically. * It is no longer possible to select a software echo canceler at compile time to build into dahdi.ko; all four included echo cancelers (MG2, KB1, SEC and SEC2) are built as loadable modules, and if the Digium HPEC binary object file has been placed into the proper directory the HPEC module will be built as well. Any or all of these modules can be loaded at the same time, and the echo canceler to be used on the system's channels can be configured using the dahdi_cfg tool from the dahdi-tools package. Note: It is *mandatory* to configure an echo canceler for the system's channels using dahdi_cfg unless the interface cards in use have echo canceler modules available and enabled. There is *no* default software echo canceler with DAHDI. Notes about the dahdi-tools package: * Many tool names have changed: ztcfg -> dahdi_cfg ztmonitor -> dahdi_monitor ztscan -> dahdi_scan ztspeed -> dahdi_speed zttest -> dahdi_test zttool -> dahdi_tool zapconf -> dahdi_genconf (deprecates genzaptelconf) * The system configuration file has moved from /etc/zaptel.conf to /etc/dahdi/system.conf. * The dahdi_cfg tool can now be used to select an echo canceler on a channel-by-channel basis in the system configuration file; see system.conf.sample for examples of how to do this. * The configuration for XPP init_card_* scripts is done now in /etc/dahdi/xpp.conf and uses a simple syntax (example included). For PRI modules, the 'pri_protocol' setting, determines how to configure it (E1/T1). * In Astribank PRI modules, the LED behaviour represents which ports are *CLOCK MASTER* (red color) and which are *CLOCK SLAVE* (green color). Usually (but not always), this corresponds to the NT/TE settings in Asterisk. dahdi-linux-2.5.0.1/LICENSE0000644000175000017500000004313011046164220015011 0ustar tzafrirtzafrir GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. dahdi-linux-2.5.0.1/Makefile0000644000175000017500000001414411447224735015464 0ustar tzafrirtzafrir# # Makefile for DAHDI Linux kernel modules # # Copyright (C) 2001-2010 Digium, Inc. # # PWD:=$(shell pwd) DAHDI_MODULES_EXTRA:=$(MODULES_EXTRA:%=%.o) $(SUBDIRS_EXTRA:%=%/) # If you want to build for a kernel other than the current kernel, set KVERS ifndef KVERS KVERS:=$(shell uname -r) endif ifndef KSRC ifneq (,$(wildcard /lib/modules/$(KVERS)/build)) KSRC:=/lib/modules/$(KVERS)/build else KSRC_SEARCH_PATH:=/usr/src/linux KSRC:=$(shell for dir in $(KSRC_SEARCH_PATH); do if [ -d $$dir ]; then echo $$dir; break; fi; done) endif endif KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2) KINCLUDES:=$(KSRC)/include # We use the kernel's .config file as an indication that the KSRC # directory is indeed a valid and configured kernel source (or partial # source) directory. # # We also source it, as it has the format of Makefile variables list. # Thus we will have many CONFIG_* variables from there. KCONFIG:=$(KSRC)/.config ifneq (,$(wildcard $(KCONFIG))) HAS_KSRC:=yes include $(KCONFIG) else HAS_KSRC:=no endif CHECKSTACK=$(KSRC)/scripts/checkstack.pl # Set HOTPLUG_FIRMWARE=no to override automatic building with hotplug support # if it is enabled in the kernel. ifeq (yes,$(HAS_KSRC)) HOTPLUG_FIRMWARE:=$(shell if grep -q '^CONFIG_FW_LOADER=[ym]' $(KCONFIG); then echo "yes"; else echo "no"; fi) endif UDEV_DIR:=/etc/udev/rules.d MODULE_ALIASES:=wcfxs wctdm8xxp wct2xxp INST_HEADERS:=kernel.h user.h fasthdlc.h wctdm_user.h dahdi_config.h DAHDI_BUILD_ALL:=m KMAKE=+$(MAKE) -C $(KSRC) SUBDIRS=$(PWD)/drivers/dahdi DAHDI_INCLUDE=$(PWD)/include DAHDI_MODULES_EXTRA="$(DAHDI_MODULES_EXTRA)" HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE) ROOT_PREFIX:= ASCIIDOC:=asciidoc ASCIIDOC_CMD:=$(ASCIIDOC) -n -a toc -a toclevels=4 GENERATED_DOCS:=README.html ifneq ($(wildcard .version),) DAHDIVERSION:=$(shell cat .version) else ifneq ($(wildcard .svn),) DAHDIVERSION:=$(shell build_tools/make_version . dahdi/linux) else ifneq ($(wildcard .git),) DAHDIVERSION:=$(shell build_tools/make_version . dahdi/linux) endif endif endif all: modules modules: prereq ifeq (no,$(HAS_KSRC)) @echo "You do not appear to have the sources for the $(KVERS) kernel installed." @exit 1 endif $(KMAKE) modules DAHDI_BUILD_ALL=$(DAHDI_BUILD_ALL) include/dahdi/version.h: FORCE @DAHDIVERSION="${DAHDIVERSION}" build_tools/make_version_h > $@.tmp @if cmp -s $@.tmp $@ ; then :; else \ mv $@.tmp $@ ; \ fi @rm -f $@.tmp prereq: include/dahdi/version.h firmware-loaders stackcheck: $(CHECKSTACK) modules objdump -d drivers/dahdi/*.ko drivers/dahdi/*/*.ko | $(CHECKSTACK) install: all install-modules install-devices install-include install-firmware install-xpp-firm @echo "###################################################" @echo "###" @echo "### DAHDI installed successfully." @echo "### If you have not done so before, install the package" @echo "### dahdi-tools." @echo "###" @echo "###################################################" uninstall: uninstall-modules uninstall-devices uninstall-include uninstall-firmware install-modconf: build_tools/genmodconf $(BUILDVER) "$(ROOT_PREFIX)" "$(filter-out dahdi dahdi_dummy xpp dahdi_transcode dahdi_dynamic,$(BUILD_MODULES)) $(MODULE_ALIASES)" @if [ -d /etc/modutils ]; then \ /sbin/update-modules ; \ fi install-xpp-firm: $(MAKE) -C drivers/dahdi/xpp/firmwares install install-firmware: ifeq ($(HOTPLUG_FIRMWARE),yes) $(MAKE) -C drivers/dahdi/firmware hotplug-install DESTDIR=$(DESTDIR) HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE) endif uninstall-firmware: $(MAKE) -C drivers/dahdi/firmware hotplug-uninstall DESTDIR=$(DESTDIR) firmware-loaders: $(MAKE) -C drivers/dahdi/firmware firmware-loaders install-include: for hdr in $(INST_HEADERS); do \ install -D -m 644 include/dahdi/$$hdr $(DESTDIR)/usr/include/dahdi/$$hdr; \ done @rm -rf $(DESTDIR)/usr/include/zaptel uninstall-include: for hdr in $(INST_HEADERS); do \ rm -f $(DESTDIR)/usr/include/dahdi/$$hdr; \ done -rmdir $(DESTDIR)/usr/include/dahdi install-devices: install -d $(DESTDIR)$(UDEV_DIR) build_tools/genudevrules > $(DESTDIR)$(UDEV_DIR)/dahdi.rules install -m 644 drivers/dahdi/xpp/xpp.rules $(DESTDIR)$(UDEV_DIR)/ uninstall-devices: rm -f $(DESTDIR)$(UDEV_DIR)/dahdi.rules install-modules: modules ifndef DESTDIR @if modinfo zaptel > /dev/null 2>&1; then \ echo -n "Removing Zaptel modules for kernel $(KVERS), please wait..."; \ build_tools/uninstall-modules zaptel $(KVERS); \ rm -rf /lib/modules/$(KVERS)/zaptel; \ echo "done."; \ fi build_tools/uninstall-modules dahdi $(KVERS) endif $(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=dahdi modules_install [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || : uninstall-modules: ifdef DESTDIR @echo "Uninstalling modules is not supported with a DESTDIR specified." @exit 1 else @if modinfo dahdi > /dev/null 2>&1 ; then \ echo -n "Removing DAHDI modules for kernel $(KVERS), please wait..."; \ build_tools/uninstall-modules dahdi $(KVERS); \ rm -rf /lib/modules/$(KVERS)/dahdi; \ echo "done."; \ fi [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || : endif update: @if [ -d .svn ]; then \ echo "Updating from Subversion..." ; \ svn update | tee update.out; \ rm -f .version; \ if [ `grep -c ^C update.out` -gt 0 ]; then \ echo ; echo "The following files have conflicts:" ; \ grep ^C update.out | cut -b4- ; \ fi ; \ rm -f update.out; \ else \ echo "Not under version control"; \ fi clean: ifneq (no,$(HAS_KSRC)) $(KMAKE) clean endif @rm -f $(GENERATED_DOCS) $(MAKE) -C drivers/dahdi/firmware clean distclean: dist-clean dist-clean: clean @rm -f include/dahdi/version.h @$(MAKE) -C drivers/dahdi/firmware dist-clean @rm -f drivers/dahdi/vpmadt032_loader/*.o_shipped firmware-download: @$(MAKE) -C drivers/dahdi/firmware all test: ./test-script $(DESTDIR)/lib/modules/$(KVERS) dahdi docs: $(GENERATED_DOCS) README.html: README $(ASCIIDOC_CMD) -o $@ $< dahdi-api.html: drivers/dahdi/dahdi-base.c build_tools/kernel-doc --kernel $(KSRC) $^ >$@ .PHONY: distclean dist-clean clean all install devices modules stackcheck install-udev update install-modules install-include uninstall-modules firmware-download install-xpp-firm firmware-loaders FORCE: dahdi-linux-2.5.0.1/doc/0000755000175000017500000000000011631523354014557 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/0000755000175000017500000000000011631523354015470 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/0000755000175000017500000000000011631523356016543 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/dahdi_dynamic_ethmf.c0000644000175000017500000005305611510412325022645 0ustar tzafrirtzafrir/* * Dynamic Span Interface for DAHDI (Multi-Span Ethernet Interface) * * Written by Joseph Benden * * Copyright (C) 2007-2010, Thralling Penguin LLC. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Undefine USE_PROC_FS, if you do not want the /proc/dahdi/dynamic-ethmf * support. Undefining this would give a slight performance increase. */ #define USE_PROC_FS #ifdef USE_PROC_FS # include # include #endif #ifdef CONFIG_DEVFS_FS # include #endif #include #include #define ETH_P_ZTDETH 0xd00d #define ETHMF_MAX_PER_SPAN_GROUP 8 #define ETHMF_MAX_GROUPS 16 #define ETHMF_FLAG_IGNORE_CHAN0 (1 << 3) #define ETHMF_MAX_SPANS 4 struct ztdeth_header { unsigned short subaddr; }; /* Timer for enabling spans - used to combat a lock problem */ static struct timer_list timer; /* Whether or not the timer has been deleted */ static atomic_t timer_deleted = ATOMIC_INIT(0); /* Global error counter */ static atomic_t errcount = ATOMIC_INIT(0); /* Whether or not we are in shutdown */ static atomic_t shutdown = ATOMIC_INIT(0); static struct sk_buff_head skbs; #ifdef USE_PROC_FS struct ethmf_group { unsigned int hash_addr; atomic_t spans; atomic_t rxframecount; atomic_t txframecount; atomic_t rxbytecount; atomic_t txbytecount; atomic_t devupcount; atomic_t devdowncount; }; static struct ethmf_group ethmf_groups[ETHMF_MAX_GROUPS]; #endif struct ztdeth { /* Destination MAC address */ unsigned char addr[ETH_ALEN]; /* Destination MAC address hash value */ unsigned int addr_hash; /* span sub-address, in network byte order */ unsigned short subaddr; /* DAHDI span associated with this TDMoE-mf span */ struct dahdi_span *span; /* Ethernet interface name */ char ethdev[IFNAMSIZ]; /* Ethernet device reference */ struct net_device *dev; /* trx buffer */ unsigned char *msgbuf; /* trx buffer length */ int msgbuf_len; /* wether or not this frame is ready for trx */ atomic_t ready; /* delay counter, to ensure all spans are added, prior to usage */ atomic_t delay; /* rvc buffer */ unsigned char *rcvbuf; /* the number of channels in this span */ int real_channels; /* use padding if 1, else no padding */ atomic_t no_front_padding; /* counter to pseudo lock the rcvbuf */ atomic_t refcnt; struct list_head list; }; /** * Lock for adding and removing items in ethmf_list */ static DEFINE_SPINLOCK(ethmf_lock); /** * The active list of all running spans */ static LIST_HEAD(ethmf_list); static inline void ethmf_errors_inc(void) { #ifdef USE_PROC_FS atomic_inc(&errcount); #endif } #ifdef USE_PROC_FS static inline int hashaddr_to_index(unsigned int hash_addr) { int i, z = -1; for (i = 0; i < ETHMF_MAX_GROUPS; ++i) { if (z == -1 && ethmf_groups[i].hash_addr == 0) z = i; if (ethmf_groups[i].hash_addr == hash_addr) return i; } if (z != -1) { ethmf_groups[z].hash_addr = hash_addr; } return z; } #endif /** * Find the Ztdeth Struct and DAHDI span for a given MAC address and subaddr. * * NOTE: RCU read lock must already be held. */ static inline void find_ethmf(const unsigned char *addr, const unsigned short subaddr, struct ztdeth **ze, struct dahdi_span **span) { struct ztdeth *z; list_for_each_entry_rcu(z, ðmf_list, list) { if (!atomic_read(&z->delay)) { if (!memcmp(addr, z->addr, ETH_ALEN) && z->subaddr == subaddr) { *ze = z; *span = z->span; return; } } } /* no results */ *ze = NULL; *span = NULL; } /** * Determines if all spans are ready for transmit. If all spans are ready, * we return the number of spans which indeed are ready and populate the * array of pointers to those spans.. * * NOTE: RCU read lock must already be held. */ static inline int ethmf_trx_spans_ready(unsigned int addr_hash, struct ztdeth *(*ready_spans)[ETHMF_MAX_PER_SPAN_GROUP]) { struct ztdeth *t; int span_count = 0, spans_ready = 0; list_for_each_entry_rcu(t, ðmf_list, list) { if (!atomic_read(&t->delay) && t->addr_hash == addr_hash) { ++span_count; if (atomic_read(&t->ready)) { short subaddr = ntohs(t->subaddr); if (subaddr < ETHMF_MAX_PER_SPAN_GROUP) { (*ready_spans)[subaddr] = t; ++spans_ready; } else { printk(KERN_ERR "More than %d spans per multi-frame group are not currently supported.", ETHMF_MAX_PER_SPAN_GROUP); } } } } if (span_count && spans_ready && span_count == spans_ready) { return spans_ready; } return 0; } /** * Ethernet receiving side processing function. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) static int ztdethmf_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) #else static int ztdethmf_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) #endif { int num_spans = 0, span_index = 0; unsigned char *data; struct dahdi_span *span; struct ztdeth *z = NULL; struct ztdeth_header *zh; unsigned int samples, channels, rbslen, flags; unsigned int skip = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) zh = (struct ztdeth_header *) skb_network_header(skb); #else zh = (struct ztdeth_header *) skb->nh.raw; #endif if (ntohs(zh->subaddr) & 0x8000) { /* got a multi-span frame */ num_spans = ntohs(zh->subaddr) & 0xFF; /* Currently max of 4 spans supported */ if (unlikely(num_spans > ETHMF_MAX_SPANS)) { kfree_skb(skb); return 0; } skb_pull(skb, sizeof(struct ztdeth_header)); #ifdef NEW_SKB_LINEARIZE if (skb_is_nonlinear(skb)) skb_linearize(skb); #else if (skb_is_nonlinear(skb)) skb_linearize(skb, GFP_KERNEL); #endif data = (unsigned char *) skb->data; rcu_read_lock(); do { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) find_ethmf(eth_hdr(skb)->h_source, htons(span_index), &z, &span); #else find_ethmf(skb->mac.ethernet->h_source, htons(span_index), &z, &span); #endif if (unlikely(!z || !span)) { /* The recv'd span does not belong to us */ /* ethmf_errors_inc(); */ ++span_index; continue; } samples = data[(span_index * 6)] & 0xFF; flags = data[((span_index * 6) + 1)] & 0xFF; channels = data[((span_index * 6) + 5)] & 0xFF; /* Precomputed defaults for most typical values */ if (channels == 24) rbslen = 12; else if (channels == 31) rbslen = 16; else rbslen = ((channels + 3) / 4) * 2; if (unlikely(samples != 8 || channels >= 32 || channels == 0)) { ethmf_errors_inc(); ++span_index; continue; } if (atomic_dec_and_test(&z->refcnt) == 0) { memcpy(z->rcvbuf, data + 6*span_index, 6); /* TDM Header */ /* * If we ignore channel zero we must skip the first eight bytes and * ensure that ztdynamic doesn't get confused by this new flag */ if (flags & ETHMF_FLAG_IGNORE_CHAN0) { skip = 8; /* Remove this flag since ztdynamic may not understand it */ z->rcvbuf[1] = flags & ~(ETHMF_FLAG_IGNORE_CHAN0); /* Additionally, now we will transmit with front padding */ atomic_set(&z->no_front_padding, 0); } else { /* Disable front padding if we recv'd a packet without it */ atomic_set(&z->no_front_padding, 1); } memcpy(z->rcvbuf + 6, data + 6*num_spans + 16 *span_index, rbslen); /* RBS Header */ /* 256 == 32*8; if padding lengths change, this must be modified */ memcpy(z->rcvbuf + 6 + rbslen, data + 6*num_spans + 16 *num_spans + (256)*span_index + skip, channels * 8); /* Payload */ dahdi_dynamic_receive(span, z->rcvbuf, 6 + rbslen + channels*8); } else { ethmf_errors_inc(); printk(KERN_INFO "TDMoE span overflow detected. Span %d was dropped.", span_index); } atomic_inc(&z->refcnt); #ifdef USE_PROC_FS if (span_index == 0) { atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].rxframecount)); atomic_add(skb->len + z->dev->hard_header_len + sizeof(struct ztdeth_header), &(ethmf_groups[hashaddr_to_index(z->addr_hash)].rxbytecount)); } #endif ++span_index; } while (!atomic_read(&shutdown) && span_index < num_spans); rcu_read_unlock(); } kfree_skb(skb); return 0; } static int ztdethmf_notifier(struct notifier_block *block, unsigned long event, void *ptr) { struct net_device *dev = ptr; struct ztdeth *z; switch (event) { case NETDEV_GOING_DOWN: case NETDEV_DOWN: rcu_read_lock(); list_for_each_entry_rcu(z, ðmf_list, list) { /* Note that the device no longer exists */ if (z->dev == dev) { z->dev = NULL; #ifdef USE_PROC_FS atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].devdowncount)); #endif } } rcu_read_unlock(); break; case NETDEV_UP: rcu_read_lock(); list_for_each_entry_rcu(z, ðmf_list, list) { /* Now that the device exists again, use it */ if (!strcmp(z->ethdev, dev->name)) { z->dev = dev; #ifdef USE_PROC_FS atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].devupcount)); #endif } } rcu_read_unlock(); break; } return 0; } static void ztdethmf_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) { struct ztdeth *z = dyn->pvt, *ready_spans[ETHMF_MAX_PER_SPAN_GROUP]; struct sk_buff *skb; struct ztdeth_header *zh; struct net_device *dev; unsigned char addr[ETH_ALEN]; int spans_ready = 0, index = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) static DEFINE_SPINLOCK(lock); unsigned long flags; #endif if (atomic_read(&shutdown)) return; rcu_read_lock(); if (unlikely(!z || !z->dev)) { rcu_read_unlock(); return; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) if (!atomic_read(&z->ready)) { spin_lock_irqsave(&lock, flags); atomic_inc(&z->ready); if (1 == atomic_read(&z->ready)) { memcpy(z->msgbuf, msg, msglen); z->msgbuf_len = msglen; } spin_unlock_irqrestore(&lock, flags); } #else if (!atomic_read(&z->ready)) { if (atomic_inc_return(&z->ready) == 1) { memcpy(z->msgbuf, msg, msglen); z->msgbuf_len = msglen; } } #endif spans_ready = ethmf_trx_spans_ready(z->addr_hash, &ready_spans); if (spans_ready) { int pad[ETHMF_MAX_SPANS], rbs[ETHMF_MAX_SPANS]; dev = z->dev; memcpy(addr, z->addr, sizeof(z->addr)); for (index = 0; index < spans_ready; index++) { int chan = ready_spans[index]->real_channels; /* By default we pad to 32 channels, but if * no_front_padding is false then we have a pad * in the front of 8 bytes, so this implies one * less channel */ if (atomic_read(&(ready_spans[index]->no_front_padding))) pad[index] = (32 - chan)*8; else pad[index] = (31 - chan)*8; if (chan == 24) rbs[index] = 12; else if (chan == 31) rbs[index] = 16; else /* Shouldn't this be index, not spans_ready? */ rbs[spans_ready] = ((chan + 3) / 4) * 2; } /* Allocate the standard size for a 32-chan frame */ skb = dev_alloc_skb(1112 + dev->hard_header_len + sizeof(struct ztdeth_header) + 32); if (unlikely(!skb)) { rcu_read_unlock(); ethmf_errors_inc(); return; } /* Reserve header space */ skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header)); /* copy each spans header */ for (index = 0; index < spans_ready; index++) { if (!atomic_read(&(ready_spans[index]->no_front_padding))) ready_spans[index]->msgbuf[1] |= ETHMF_FLAG_IGNORE_CHAN0; memcpy(skb_put(skb, 6), ready_spans[index]->msgbuf, 6); } /* copy each spans RBS payload */ for (index = 0; index < spans_ready; index++) { memcpy(skb_put(skb, 16), ready_spans[index]->msgbuf + 6, rbs[index]); } /* copy each spans data/voice payload */ for (index = 0; index < spans_ready; index++) { int chan = ready_spans[index]->real_channels; if (!atomic_read(&(ready_spans[index]->no_front_padding))) { /* This adds an additional (padded) channel to our total */ memset(skb_put(skb, 8), 0xA5, 8); /* ETHMF_IGNORE_CHAN0 */ } memcpy(skb_put(skb, chan*8), ready_spans[index]->msgbuf + (6 + rbs[index]), chan*8); if (pad[index] > 0) { memset(skb_put(skb, pad[index]), 0xDD, pad[index]); } /* mark span as ready for new data/voice */ atomic_set(&(ready_spans[index]->ready), 0); } /* Throw on header */ zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header)); zh->subaddr = htons((unsigned short)(0x8000 | (unsigned char)(spans_ready & 0xFF))); /* Setup protocol type */ skb->protocol = __constant_htons(ETH_P_ZTDETH); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) skb_set_network_header(skb, 0); #else skb->nh.raw = skb->data; #endif skb->dev = dev; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) dev_hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len); #else if (dev->hard_header) dev->hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len); #endif /* queue frame for delivery */ if (dev) { skb_queue_tail(&skbs, skb); } #ifdef USE_PROC_FS atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].txframecount)); atomic_add(skb->len, &(ethmf_groups[hashaddr_to_index(z->addr_hash)].txbytecount)); #endif } rcu_read_unlock(); return; } static int ztdethmf_flush(void) { struct sk_buff *skb; /* Handle all transmissions now */ while ((skb = skb_dequeue(&skbs))) { dev_queue_xmit(skb); } return 0; } static struct packet_type ztdethmf_ptype = { .type = __constant_htons(ETH_P_ZTDETH), /* Protocol */ .dev = NULL, /* Device (NULL = wildcard) */ .func = ztdethmf_rcv, /* Receiver */ }; static void ztdethmf_destroy(struct dahdi_dynamic *dyn) { struct ztdeth *z = dyn->pvt; unsigned long flags; atomic_set(&shutdown, 1); synchronize_rcu(); spin_lock_irqsave(ðmf_lock, flags); list_del_rcu(&z->list); spin_unlock_irqrestore(ðmf_lock, flags); synchronize_rcu(); atomic_dec(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans)); if (z) { /* Successfully removed */ printk(KERN_INFO "Removed interface for %s\n", z->span->name); kfree(z->msgbuf); kfree(z); } else { if (z && z->span && z->span->name) { printk(KERN_ERR "Cannot find interface for %s\n", z->span->name); } } } static int ztdethmf_create(struct dahdi_dynamic *dyn, const char *addr) { struct ztdeth *z; char src[256]; char *src_ptr; int x, bufsize, num_matched; unsigned long flags; struct dahdi_span *const span = &dyn->span; BUG_ON(!span); BUG_ON(!addr); z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL); if (!z) return -ENOMEM; /* Zero it out */ memset(z, 0, sizeof(struct ztdeth)); /* set a delay for xmit/recv to workaround Zaptel problems */ atomic_set(&z->delay, 4); /* create a msg buffer. MAX OF 31 CHANNELS!!!! */ bufsize = 31 * DAHDI_CHUNKSIZE + 31 / 4 + 48; z->msgbuf = kmalloc(bufsize, GFP_KERNEL); z->rcvbuf = kmalloc(bufsize, GFP_KERNEL); /* Address should be //subaddr */ strlcpy(src, addr, sizeof(src)); /* replace all / with space; otherwise kernel sscanf does not work */ src_ptr = src; while (*src_ptr) { if (*src_ptr == '/') *src_ptr = ' '; ++src_ptr; } num_matched = sscanf(src, "%16s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hu", z->ethdev, &z->addr[0], &z->addr[1], &z->addr[2], &z->addr[3], &z->addr[4], &z->addr[5], &z->subaddr); if (8 != num_matched) { printk(KERN_ERR "Only matched %d entries in '%s'\n", num_matched, src); printk(KERN_ERR "Invalid TDMoE Multiframe address: %s\n", addr); kfree(z); return -EINVAL; } z->dev = dev_get_by_name( #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) &init_net, #endif z->ethdev); if (!z->dev) { printk(KERN_ERR "TDMoE Multiframe: Invalid device '%s'\n", z->ethdev); kfree(z); return -EINVAL; } z->span = span; z->subaddr = htons(z->subaddr); z->addr_hash = crc32_le(0, z->addr, ETH_ALEN); z->real_channels = span->channels; src[0] = '\0'; for (x = 0; x < 5; x++) sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]); sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]); printk(KERN_INFO "TDMoEmf: Added new interface for %s at %s " "(addr=%s, src=%s, subaddr=%d)\n", span->name, z->dev->name, addr, src, ntohs(z->subaddr)); atomic_set(&z->ready, 0); atomic_set(&z->refcnt, 0); spin_lock_irqsave(ðmf_lock, flags); list_add_rcu(&z->list, ðmf_list); spin_unlock_irqrestore(ðmf_lock, flags); atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans)); /* enable the timer for enabling the spans */ mod_timer(&timer, jiffies + HZ); atomic_set(&shutdown, 0); dyn->pvt = z; return 0; } static struct dahdi_dynamic_driver ztd_ethmf = { .owner = THIS_MODULE, .name = "ethmf", .desc = "Ethernet", .create = ztdethmf_create, .destroy = ztdethmf_destroy, .transmit = ztdethmf_transmit, .flush = ztdethmf_flush, }; static struct notifier_block ztdethmf_nblock = { .notifier_call = ztdethmf_notifier, }; /** * Decrements each delay counter in the ethmf_list and returns the number of * delay counters that are not equal to zero. */ static int ethmf_delay_dec(void) { struct ztdeth *z; int count_nonzero = 0; rcu_read_lock(); list_for_each_entry_rcu(z, ðmf_list, list) { if (atomic_read(&z->delay)) { atomic_dec(&z->delay); ++count_nonzero; } else atomic_set(&z->delay, 0); } rcu_read_unlock(); return count_nonzero; } /** * Timer callback function to allow all spans to be added, prior to any of * them being used. */ static void timer_callback(unsigned long param) { if (ethmf_delay_dec()) { if (!atomic_read(&timer_deleted)) { timer.expires = jiffies + HZ; add_timer(&timer); } } else { printk(KERN_INFO "All TDMoE multiframe span groups are active.\n"); del_timer(&timer); } } #ifdef USE_PROC_FS static struct proc_dir_entry *proc_entry; static const char *ztdethmf_procname = "dahdi/dynamic-ethmf"; static int ztdethmf_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { struct ztdeth *z = NULL; int len = 0, i = 0; unsigned int group = 0, c = 0; rcu_read_lock(); len += sprintf(page + len, "Errors: %d\n\n", atomic_read(&errcount)); for (group = 0; group < ETHMF_MAX_GROUPS; ++group) { if (atomic_read(&(ethmf_groups[group].spans))) { len += sprintf(page + len, "Group #%d (0x%x)\n", i++, ethmf_groups[group].hash_addr); len += sprintf(page + len, " Spans: %d\n", atomic_read(&(ethmf_groups[group].spans))); c = 1; list_for_each_entry_rcu(z, ðmf_list, list) { if (z->addr_hash == ethmf_groups[group].hash_addr) { if (c == 1) { len += sprintf(page + len, " Device: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x)\n", z->ethdev, z->addr[0], z->addr[1], z->addr[2], z->addr[3], z->addr[4], z->addr[5]); } len += sprintf(page + len, " Span %d: subaddr=%u ready=%d delay=%d real_channels=%d no_front_padding=%d\n", c++, ntohs(z->subaddr), atomic_read(&z->ready), atomic_read(&z->delay), z->real_channels, atomic_read(&z->no_front_padding)); } } len += sprintf(page + len, " Device UPs: %u\n", atomic_read(&(ethmf_groups[group].devupcount))); len += sprintf(page + len, " Device DOWNs: %u\n", atomic_read(&(ethmf_groups[group].devdowncount))); len += sprintf(page + len, " Rx Frames: %u\n", atomic_read(&(ethmf_groups[group].rxframecount))); len += sprintf(page + len, " Tx Frames: %u\n", atomic_read(&(ethmf_groups[group].txframecount))); len += sprintf(page + len, " Rx Bytes: %u\n", atomic_read(&(ethmf_groups[group].rxbytecount))); len += sprintf(page + len, " Tx Bytes: %u\n", atomic_read(&(ethmf_groups[group].txbytecount))); if (len <= off) { off -= len; len = 0; } if (len > off+count) break; } } rcu_read_unlock(); if (len <= off) { off -= len; len = 0; } *start = page + off; len -= off; if (len > count) len = count; return len; } #endif static int __init ztdethmf_init(void) { init_timer(&timer); timer.expires = jiffies + HZ; timer.function = &timer_callback; if (!timer_pending(&timer)) add_timer(&timer); dev_add_pack(&ztdethmf_ptype); register_netdevice_notifier(&ztdethmf_nblock); dahdi_dynamic_register_driver(&ztd_ethmf); skb_queue_head_init(&skbs); #ifdef USE_PROC_FS proc_entry = create_proc_read_entry(ztdethmf_procname, 0444, NULL, ztdethmf_proc_read, NULL); if (!proc_entry) { printk(KERN_ALERT "create_proc_read_entry failed.\n"); } #endif return 0; } static void __exit ztdethmf_exit(void) { atomic_set(&timer_deleted, 1); del_timer_sync(&timer); dev_remove_pack(&ztdethmf_ptype); unregister_netdevice_notifier(&ztdethmf_nblock); dahdi_dynamic_unregister_driver(&ztd_ethmf); #ifdef USE_PROC_FS if (proc_entry) remove_proc_entry(ztdethmf_procname, NULL); #endif } MODULE_DESCRIPTION("DAHDI Dynamic TDMoEmf Support"); MODULE_AUTHOR("Joseph Benden "); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif module_init(ztdethmf_init); module_exit(ztdethmf_exit); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_dynamic_loc.c0000644000175000017500000001422611510412300022304 0ustar tzafrirtzafrir/* * Dynamic Span Interface for DAHDI (Local Interface) * * Written by Nicolas Bougues * * Copyright (C) 2004, Axialys Interactive * * All rights reserved. * * Note : a DAHDI timing source must exist prior to loading this driver * * Address syntax : * :[:] * * As of now, keys and ids are single digit only * * One span may have up to one "normal" peer, and one "monitor" peer * * Example : * * Say you have two spans cross connected, a third one monitoring RX on the * first one, a fourth one monitoring RX on the second one * * 1:0 * 1:1 * 1:2:0 * 1:3:1 * * Contrary to TDMoE, no frame loss can occur. * * See bug #2021 for more details * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include /** * struct dahdi_dynamic_loc - For local dynamic spans * @monitor_rx_peer: Indicates the peer span that monitors this span. * @peer: Indicates the rw peer for this span. * */ struct dahdi_dynamic_local { unsigned short key; unsigned short id; struct dahdi_dynamic_local *monitor_rx_peer; struct dahdi_dynamic_local *peer; struct dahdi_span *span; struct list_head node; }; static DEFINE_SPINLOCK(local_lock); static LIST_HEAD(dynamic_local_list); static void dahdi_dynamic_local_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) { struct dahdi_dynamic_local *const d = dyn->pvt; unsigned long flags; spin_lock_irqsave(&local_lock, flags); if (d && d->peer && d->peer->span) { if (test_bit(DAHDI_FLAGBIT_REGISTERED, &d->peer->span->flags)) dahdi_dynamic_receive(d->peer->span, msg, msglen); } if (d && d->monitor_rx_peer && d->monitor_rx_peer->span) { if (test_bit(DAHDI_FLAGBIT_REGISTERED, &d->monitor_rx_peer->span->flags)) { dahdi_dynamic_receive(d->monitor_rx_peer->span, msg, msglen); } } spin_unlock_irqrestore(&local_lock, flags); } static int digit2int(char d) { switch(d) { case 'F': case 'E': case 'D': case 'C': case 'B': case 'A': return d - 'A' + 10; case 'f': case 'e': case 'd': case 'c': case 'b': case 'a': return d - 'a' + 10; case '9': case '8': case '7': case '6': case '5': case '4': case '3': case '2': case '1': case '0': return d - '0'; } return -1; } static void dahdi_dynamic_local_destroy(struct dahdi_dynamic *dyn) { struct dahdi_dynamic_local *d = dyn->pvt; unsigned long flags; struct dahdi_dynamic_local *cur; spin_lock_irqsave(&local_lock, flags); list_for_each_entry(cur, &dynamic_local_list, node) { if (cur->peer == d) cur->peer = NULL; if (cur->monitor_rx_peer == d) cur->monitor_rx_peer = NULL; } list_del(&d->node); dyn->pvt = NULL; spin_unlock_irqrestore(&local_lock, flags); printk(KERN_INFO "TDMoL: Removed interface for %s, key %d " "id %d\n", d->span->name, d->key, d->id); kfree(d); } static int dahdi_dynamic_local_create(struct dahdi_dynamic *dyn, const char *address) { struct dahdi_dynamic_local *d, *l; unsigned long flags; int key = -1, id = -1, monitor = -1; struct dahdi_span *const span = &dyn->span; if (strlen(address) >= 3) { if (address[1] != ':') goto INVALID_ADDRESS; key = digit2int(address[0]); id = digit2int(address[2]); } if (strlen (address) == 5) { if (address[3] != ':') goto INVALID_ADDRESS; monitor = digit2int(address[4]); } if (key == -1 || id == -1) goto INVALID_ADDRESS; d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; d->key = key; d->id = id; d->span = span; spin_lock_irqsave(&local_lock, flags); /* Add this peer to any existing spans with same key And add them as peers to this one */ list_for_each_entry(l, &dynamic_local_list, node) { if (l->key != d->key) continue; if (l->id == d->id) { printk(KERN_DEBUG "TDMoL: Duplicate id (%d) for key " "%d\n", d->id, d->key); goto CLEAR_AND_DEL_FROM_PEERS; } if (monitor == -1) { if (l->peer) { printk(KERN_DEBUG "TDMoL: Span with key %d and " "id %d already has a R/W peer\n", d->key, d->id); goto CLEAR_AND_DEL_FROM_PEERS; } else { l->peer = d; d->peer = l; } } if (monitor == l->id) { if (l->monitor_rx_peer) { printk(KERN_DEBUG "TDMoL: Span with key %d and " "id %d already has a monitoring peer\n", d->key, d->id); goto CLEAR_AND_DEL_FROM_PEERS; } else { l->monitor_rx_peer = d; } } } list_add(&d->node, &dynamic_local_list); dyn->pvt = d; spin_unlock_irqrestore(&local_lock, flags); printk(KERN_INFO "TDMoL: Added new interface for %s, " "key %d id %d\n", span->name, d->key, d->id); span->cannot_provide_timing = 1; return 0; CLEAR_AND_DEL_FROM_PEERS: list_for_each_entry(l, &dynamic_local_list, node) { if (l->peer == d) l->peer = NULL; if (l->monitor_rx_peer == d) l->monitor_rx_peer = NULL; } kfree(d); spin_unlock_irqrestore(&local_lock, flags); return -EINVAL; INVALID_ADDRESS: printk (KERN_NOTICE "TDMoL: Invalid address %s\n", address); return -EINVAL; } static struct dahdi_dynamic_driver dahdi_dynamic_local = { .owner = THIS_MODULE, .name = "loc", .desc = "Local", .create = dahdi_dynamic_local_create, .destroy = dahdi_dynamic_local_destroy, .transmit = dahdi_dynamic_local_transmit, }; static int __init dahdi_dynamic_local_init(void) { dahdi_dynamic_register_driver(&dahdi_dynamic_local); return 0; } static void __exit dahdi_dynamic_local_exit(void) { dahdi_dynamic_unregister_driver(&dahdi_dynamic_local); } module_init(dahdi_dynamic_local_init); module_exit(dahdi_dynamic_local_exit); MODULE_LICENSE("GPL v2"); dahdi-linux-2.5.0.1/drivers/dahdi/wct4xxp/0000755000175000017500000000000011631523354020162 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/wct4xxp/base.c0000644000175000017500000043541511623264541021255 0ustar tzafrirtzafrir/* * TE410P Quad-T1/E1 PCI Driver version 0.1, 12/16/02 * * Written by Mark Spencer * Based on previous works, designs, and archetectures conceived and * written by Jim Dixon . * Further modified, optimized, and maintained by * Matthew Fredrickson and * Russ Meyerriecks * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2011, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wct4xxp.h" #include "vpm450m.h" /* Work queues are a way to better distribute load on SMP systems */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) /* * Work queues can significantly improve performance and scalability * on multi-processor machines, but requires bypassing some kernel * API's, so it's not guaranteed to be compatible with all kernels. */ /* #define ENABLE_WORKQUEUES */ #endif /* Enable prefetching may help performance */ #define ENABLE_PREFETCH /* Support first generation cards? */ #define SUPPORT_GEN1 /* Define to get more attention-grabbing but slightly more I/O using alarm status */ #define FANCY_ALARM /* Define to support Digium Voice Processing Module expansion card */ #define VPM_SUPPORT #define DEBUG_MAIN (1 << 0) #define DEBUG_DTMF (1 << 1) #define DEBUG_REGS (1 << 2) #define DEBUG_TSI (1 << 3) #define DEBUG_ECHOCAN (1 << 4) #define DEBUG_RBS (1 << 5) #define DEBUG_FRAMER (1 << 6) /* Maximum latency to be used with Gen 5 */ #define GEN5_MAX_LATENCY 127 #define T4_BASE_SIZE (DAHDI_MAX_CHUNKSIZE * 32 * 4) #ifdef ENABLE_WORKQUEUES #include /* XXX UGLY!!!! XXX We have to access the direct structures of the workqueue which are only defined within workqueue.c because they don't give us a routine to allow us to nail a work to a particular thread of the CPU. Nailing to threads gives us substantially higher scalability in multi-CPU environments though! */ /* * The per-CPU workqueue (if single thread, we always use cpu 0's). * * The sequence counters are for flush_scheduled_work(). It wants to wait * until until all currently-scheduled works are completed, but it doesn't * want to be livelocked by new, incoming ones. So it waits until * remove_sequence is >= the insert_sequence which pertained when * flush_scheduled_work() was called. */ struct cpu_workqueue_struct { spinlock_t lock; long remove_sequence; /* Least-recently added (next to run) */ long insert_sequence; /* Next to add */ struct list_head worklist; wait_queue_head_t more_work; wait_queue_head_t work_done; struct workqueue_struct *wq; task_t *thread; int run_depth; /* Detect run_workqueue() recursion depth */ } ____cacheline_aligned; /* * The externally visible workqueue abstraction is an array of * per-CPU workqueues: */ struct workqueue_struct { /* TODO: Find out exactly where the API changed */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) struct cpu_workqueue_struct *cpu_wq; #else struct cpu_workqueue_struct cpu_wq[NR_CPUS]; #endif const char *name; struct list_head list; /* Empty if single thread */ }; /* Preempt must be disabled. */ static void __t4_queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) { unsigned long flags; spin_lock_irqsave(&cwq->lock, flags); work->wq_data = cwq; list_add_tail(&work->entry, &cwq->worklist); cwq->insert_sequence++; wake_up(&cwq->more_work); spin_unlock_irqrestore(&cwq->lock, flags); } /* * Queue work on a workqueue. Return non-zero if it was successfully * added. * * We queue the work to the CPU it was submitted, but there is no * guarantee that it will be processed by that CPU. */ static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct *work, int cpu) { int ret = 0; get_cpu(); if (!test_and_set_bit(0, &work->pending)) { BUG_ON(!list_empty(&work->entry)); __t4_queue_work(wq->cpu_wq + cpu, work); ret = 1; } put_cpu(); return ret; } #endif /* * Define CONFIG_FORCE_EXTENDED_RESET to allow the qfalc framer extra time * to reset itself upon hardware initialization. This exits for rare * cases for customers who are seeing the qfalc returning unexpected * information at initialization */ /* #define CONFIG_FORCE_EXTENDED_RESET */ /* #define CONFIG_NOEXTENDED_RESET */ #if defined(CONFIG_FORCE_EXTENDED_RESET) && defined(CONFIG_NOEXTENDED_RESET) #error "You cannot define both CONFIG_FORCE_EXTENDED_RESET and " \ "CONFIG_NOEXTENDED_RESET." #endif static int pedanticpci = 1; static int debug=0; static int timingcable = 0; static int t1e1override = -1; /* 0xff for E1, 0x00 for T1 */ static int j1mode = 0; static int sigmode = FRMR_MODE_NO_ADDR_CMP; static int alarmdebounce = 2500; /* LOF/LFA def to 2.5s AT&T TR54016*/ static int losalarmdebounce = 2500;/* LOS def to 2.5s AT&T TR54016*/ static int aisalarmdebounce = 2500;/* AIS(blue) def to 2.5s AT&T TR54016*/ static int yelalarmdebounce = 500;/* RAI(yellow) def to 0.5s AT&T devguide */ static int max_latency = GEN5_MAX_LATENCY; /* Used to set a maximum latency (if you don't wish it to hard cap it at a certain value) in milliseconds */ #ifdef VPM_SUPPORT static int vpmsupport = 1; /* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */ static int vpmdtmfsupport = -1; /* -1=auto, 0=disabled, 1=enabled*/ static int vpmspans = 4; #define VPM_DEFAULT_DTMFTHRESHOLD 1000 static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD; static int lastdtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD; #endif /* Enabling bursting can more efficiently utilize PCI bus bandwidth, but can also cause PCI bus starvation, especially in combination with other aggressive cards. Please note that burst mode has no effect on CPU utilization / max number of calls / etc. */ static int noburst; /* For 56kbps links, set this module parameter to 0x7f */ static int hardhdlcmode = 0xff; static int latency = 1; static int ms_per_irq = 1; static int ignore_rotary; #ifdef FANCY_ALARM static int altab[] = { 0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, }; #endif #define MAX_SPANS 16 #define FLAG_STARTED (1 << 0) #define FLAG_NMF (1 << 1) #define FLAG_SENDINGYELLOW (1 << 2) #define TYPE_T1 1 /* is a T1 card */ #define TYPE_E1 2 /* is an E1 card */ #define TYPE_J1 3 /* is a running J1 */ #define FLAG_2NDGEN (1 << 3) #define FLAG_2PORT (1 << 4) #define FLAG_VPM2GEN (1 << 5) #define FLAG_OCTOPT (1 << 6) #define FLAG_3RDGEN (1 << 7) #define FLAG_BURST (1 << 8) #define FLAG_EXPRESS (1 << 9) #define FLAG_5THGEN (1 << 10) #define CANARY 0xc0de /* names of available HWEC modules */ #ifdef VPM_SUPPORT static const char *vpm400_name = "VPM400M"; static const char *vpmoct064_name = "VPMOCT064"; static const char *vpmoct128_name = "VPMOCT128"; #endif #define PORTS_PER_FRAMER 4 struct devtype { char *desc; unsigned int flags; }; static struct devtype wct420p5 = { "Wildcard TE420 (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS }; static struct devtype wct410p5 = { "Wildcard TE410P (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct405p5 = { "Wildcard TE405P (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct220p5 = { "Wildcard TE220 (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT | FLAG_EXPRESS }; static struct devtype wct210p5 = { "Wildcard TE210P (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct205p5 = { "Wildcard TE205P (5th Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct4xxp = { "Wildcard TE410P/TE405P (1st Gen)", 0 }; static struct devtype wct420p4 = { "Wildcard TE420 (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS }; static struct devtype wct410p4 = { "Wildcard TE410P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct410p3 = { "Wildcard TE410P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct405p4 = { "Wildcard TE405P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct405p3 = { "Wildcard TE405P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN }; static struct devtype wct410p2 = { "Wildcard TE410P (2nd Gen)", FLAG_2NDGEN }; static struct devtype wct405p2 = { "Wildcard TE405P (2nd Gen)", FLAG_2NDGEN }; static struct devtype wct220p4 = { "Wildcard TE220 (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT | FLAG_EXPRESS }; static struct devtype wct205p4 = { "Wildcard TE205P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct205p3 = { "Wildcard TE205P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct210p4 = { "Wildcard TE210P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct210p3 = { "Wildcard TE210P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT }; static struct devtype wct205 = { "Wildcard TE205P ", FLAG_2NDGEN | FLAG_2PORT }; static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT }; struct t4; struct t4_span { struct t4 *owner; u32 *writechunk; /* Double-word aligned write memory */ u32 *readchunk; /* Double-word aligned read memory */ int spantype; /* card type, T1 or E1 or J1 */ int sync; int psync; int alarmtimer; int redalarms; int notclear; int alarmcount; int losalarmcount; int aisalarmcount; int yelalarmcount; int spanflags; int syncpos; #ifdef SUPPORT_GEN1 int e1check; /* E1 check */ #endif struct dahdi_span span; unsigned char txsigs[16]; /* Transmit sigs */ int loopupcnt; int loopdowncnt; #ifdef SUPPORT_GEN1 unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; /* first EC chunk buffer */ unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; /* second EC chunk buffer */ #endif int irqmisses; /* HDLC controller fields */ struct dahdi_chan *sigchan; unsigned char sigmode; int sigactive; int frames_out; int frames_in; #ifdef VPM_SUPPORT unsigned long dtmfactive; unsigned long dtmfmask; unsigned long dtmfmutemask; short dtmfenergy[31]; short dtmfdigit[31]; #endif #ifdef ENABLE_WORKQUEUES struct work_struct swork; #endif struct dahdi_chan *chans[32]; /* Individual channels */ struct dahdi_echocan_state *ec[32]; /* Echocan state for each channel */ }; struct t4 { /* This structure exists one per card */ struct pci_dev *dev; /* Pointer to PCI device */ unsigned int intcount; int num; /* Which card we are */ int t1e1; /* T1/E1 select pins */ int globalconfig; /* Whether global setup has been done */ int syncsrc; /* active sync source */ struct t4_span *tspans[4]; /* Individual spans */ int numspans; /* Number of spans on the card */ int blinktimer; #ifdef FANCY_ALARM int alarmpos; #endif int irq; /* IRQ used by device */ int order; /* Order */ int flags; /* Device flags */ unsigned int falc31 : 1; /* are we falc v3.1 (atomic not necessary) */ int master; /* Are we master */ int ledreg; /* LED Register */ unsigned int gpio; unsigned int gpioctl; int e1recover; /* E1 recovery timer */ spinlock_t reglock; /* lock register access */ int spansstarted; /* number of spans started */ u32 *writechunk; /* Double-word aligned write memory */ u32 *readchunk; /* Double-word aligned read memory */ unsigned short canary; #ifdef ENABLE_WORKQUEUES atomic_t worklist; struct workqueue_struct *workq; #endif unsigned int passno; /* number of interrupt passes */ char *variety; int last0; /* for detecting double-missed IRQ */ /* DMA related fields */ unsigned int dmactrl; dma_addr_t readdma; dma_addr_t writedma; unsigned long memaddr; /* Base address of card */ unsigned long memlen; void __iomem *membase; /* Base address of card */ /* Add this for our softlockup protector */ unsigned int oct_rw_count; /* Flags for our bottom half */ unsigned long checkflag; struct tasklet_struct t4_tlet; unsigned int vpm400checkstatus; /* Latency related additions */ unsigned char rxident; unsigned char lastindex; int numbufs; int needed_latency; #ifdef VPM_SUPPORT struct vpm450m *vpm450m; int vpm; #endif }; #define T4_VPM_PRESENT (1 << 28) #ifdef VPM_SUPPORT static void t4_vpm400_init(struct t4 *wc); static void t4_vpm450_init(struct t4 *wc); static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold); static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static const struct dahdi_echocan_features vpm_ec_features = { .NLP_automatic = 1, .CED_tx_detect = 1, .CED_rx_detect = 1, }; static const struct dahdi_echocan_ops vpm_ec_ops = { .echocan_free = echocan_free, }; #endif static void __set_clear(struct t4 *wc, int span); static int t4_startup(struct file *file, struct dahdi_span *span); static int t4_shutdown(struct dahdi_span *span); static int t4_rbsbits(struct dahdi_chan *chan, int bits); static int t4_maint(struct dahdi_span *span, int cmd); static int t4_clear_maint(struct dahdi_span *span); static int t4_reset_counters(struct dahdi_span *span); #ifdef SUPPORT_GEN1 static int t4_reset_dma(struct t4 *wc); #endif static void t4_hdlc_hard_xmit(struct dahdi_chan *chan); static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data); static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan); static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan); static void __t4_set_rclk_src(struct t4 *wc, int span); static void __t4_set_sclk_src(struct t4 *wc, int mode, int master, int slave); static void t4_check_alarms(struct t4 *wc, int span); static void t4_check_sigbits(struct t4 *wc, int span); #define WC_RDADDR 0 #define WC_WRADDR 1 #define WC_COUNT 2 #define WC_DMACTRL 3 #define WC_INTR 4 /* #define WC_GPIO 5 */ #define WC_VERSION 6 #define WC_LEDS 7 #define WC_GPIOCTL 8 #define WC_GPIO 9 #define WC_LADDR 10 #define WC_LDATA 11 #define WC_LCS (1 << 11) #define WC_LCS2 (1 << 12) #define WC_LALE (1 << 13) #define WC_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */ #define WC_ACTIVATE (1 << 12) #define WC_LREAD (1 << 15) #define WC_LWRITE (1 << 16) #define WC_OFF (0) #define WC_RED (1) #define WC_GREEN (2) #define WC_YELLOW (3) #define WC_RECOVER 0 #define WC_SELF 1 #define LIM0_T 0x36 /* Line interface mode 0 register */ #define LIM0_LL (1 << 1) /* Local Loop */ #define LIM1_T 0x37 /* Line interface mode 1 register */ #define LIM1_RL (1 << 1) /* Remote Loop */ #define FMR0 0x1C /* Framer Mode Register 0 */ #define FMR0_SIM (1 << 0) /* Alarm Simulation */ #define FMR1_T 0x1D /* Framer Mode Register 1 */ #define FMR1_ECM (1 << 2) /* Error Counter 1sec Interrupt Enable */ #define FMR5 0x21 /* Framer Mode Register 5 */ #define FMR5_XLU (1 << 4) /* Transmit loopup code */ #define FMR5_XLD (1 << 5) /* Transmit loopdown code */ #define FMR5_EIBR (1 << 6) /* Internal Bit Robbing Access */ #define DEC_T 0x60 /* Diable Error Counter */ #define IERR_T 0x1B /* Single Bit Defect Insertion Register */ #define IBV 0 /* Bipolar violation */ #define IPE (1 << 1) /* PRBS defect */ #define ICASE (1 << 2) /* CAS defect */ #define ICRCE (1 << 3) /* CRC defect */ #define IMFE (1 << 4) /* Multiframe defect */ #define IFASE (1 << 5) /* FAS defect */ #define ISR3_SEC (1 << 6) /* Internal one-second interrupt bit mask */ #define ISR3_ES (1 << 7) /* Errored Second interrupt bit mask */ #define ESM 0x47 /* Errored Second mask register */ #define FMR2_T 0x1E /* Framer Mode Register 2 */ #define FMR2_PLB (1 << 2) /* Framer Mode Register 2 */ #define FECL_T 0x50 /* Framing Error Counter Lower Byte */ #define FECH_T 0x51 /* Framing Error Counter Higher Byte */ #define CVCL_T 0x52 /* Code Violation Counter Lower Byte */ #define CVCH_T 0x53 /* Code Violation Counter Higher Byte */ #define CEC1L_T 0x54 /* CRC Error Counter 1 Lower Byte */ #define CEC1H_T 0x55 /* CRC Error Counter 1 Higher Byte */ #define EBCL_T 0x56 /* E-Bit Error Counter Lower Byte */ #define EBCH_T 0x57 /* E-Bit Error Counter Higher Byte */ #define BECL_T 0x58 /* Bit Error Counter Lower Byte */ #define BECH_T 0x59 /* Bit Error Counter Higher Byte */ #define COEC_T 0x5A /* COFA Event Counter */ #define PRBSSTA_T 0xDA /* PRBS Status Register */ #define LCR1_T 0x3B /* Loop Code Register 1 */ #define EPRM (1 << 7) /* Enable PRBS rx */ #define XPRBS (1 << 6) /* Enable PRBS tx */ #define FLLB (1 << 1) /* Framed line loop/Invert */ #define LLBP (1 << 0) /* Line Loopback Pattern */ #define TPC0_T 0xA8 /* Test Pattern Control Register */ #define FRA (1 << 6) /* Framed/Unframed Selection */ #define PRBS23 (3 << 4) /* Pattern selection (23 poly) */ #define PRM (1 << 2) /* Non framed mode */ #define FRS1_T 0x4D /* Framer Receive Status Reg 1 */ #define LLBDD (1 << 4) #define LLBAD (1 << 3) #define MAX_T4_CARDS 64 static void t4_isr_bh(unsigned long data); static struct t4 *cards[MAX_T4_CARDS]; #define MAX_TDM_CHAN 32 #define MAX_DTMF_DET 16 #define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF) #if 0 #define HDLC_IMR1_MASK (FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR) #else #define HDLC_IMR1_MASK (FRMR_IMR1_XDU | FRMR_IMR1_XPR) #endif static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr) { unsigned int res = readl(wc->membase + (addr * sizeof(u32))); return res; } static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value) { unsigned int tmp; writel(value, wc->membase + (addr * sizeof(u32))); if (pedanticpci) { tmp = __t4_pci_in(wc, WC_VERSION); if ((tmp & 0xffff0000) != 0xc01a0000) dev_notice(&wc->dev->dev, "Version Synchronization Error!\n"); } #if 0 tmp = __t4_pci_in(wc, addr); if ((value != tmp) && (addr != WC_LEDS) && (addr != WC_LDATA) && (addr != WC_GPIO) && (addr != WC_INTR)) dev_info(&wc->dev->dev, "Tried to load %08x into %08x, " "but got %08x instead\n", value, addr, tmp); #endif } static inline void __t4_gpio_set(struct t4 *wc, unsigned bits, unsigned int val) { unsigned int newgpio; newgpio = wc->gpio & (~bits); newgpio |= val; if (newgpio != wc->gpio) { wc->gpio = newgpio; __t4_pci_out(wc, WC_GPIO, wc->gpio); } } static inline void __t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val) { unsigned int newgpioctl; newgpioctl = wc->gpioctl & (~bits); newgpioctl |= val; if (newgpioctl != wc->gpioctl) { wc->gpioctl = newgpioctl; __t4_pci_out(wc, WC_GPIOCTL, wc->gpioctl); } } static inline void t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_gpio_setdir(wc, bits, val); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void t4_gpio_set(struct t4 *wc, unsigned int bits, unsigned int val) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_gpio_set(wc, bits, val); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_pci_out(wc, addr, value); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void __t4_set_led(struct t4 *wc, int span, int color) { int oldreg = wc->ledreg; wc->ledreg &= ~(0x3 << (span << 1)); wc->ledreg |= (color << (span << 1)); if (oldreg != wc->ledreg) __t4_pci_out(wc, WC_LEDS, wc->ledreg); } static inline void t4_activate(struct t4 *wc) { wc->ledreg |= WC_ACTIVATE; t4_pci_out(wc, WC_LEDS, wc->ledreg); } static inline unsigned int t4_pci_in(struct t4 *wc, const unsigned int addr) { unsigned int ret; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); ret = __t4_pci_in(wc, addr); spin_unlock_irqrestore(&wc->reglock, flags); return ret; } static unsigned int __t4_framer_in(struct t4 *wc, int unit, const unsigned int addr) { unsigned int ret; unit &= 0x3; __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LREAD); if (!pedanticpci) { __t4_pci_in(wc, WC_VERSION); } else { __t4_pci_out(wc, WC_VERSION, 0); } ret = __t4_pci_in(wc, WC_LDATA); __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); if (unlikely(debug & DEBUG_REGS)) dev_info(&wc->dev->dev, "Reading unit %d address %02x is " "%02x\n", unit, addr, ret & 0xff); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); return ret & 0xff; } static unsigned int t4_framer_in(struct t4 *wc, int unit, const unsigned int addr) { unsigned long flags; unsigned int ret; spin_lock_irqsave(&wc->reglock, flags); ret = __t4_framer_in(wc, unit, addr); spin_unlock_irqrestore(&wc->reglock, flags); return ret; } static void __t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value) { unit &= 0x3; if (unlikely(debug & DEBUG_REGS)) dev_info(&wc->dev->dev, "Writing %02x to address %02x of " "unit %d\n", value, addr, unit); __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); __t4_pci_out(wc, WC_LDATA, value); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LWRITE); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); if (unlikely(debug & DEBUG_REGS)) dev_info(&wc->dev->dev, "Write complete\n"); #if 0 if ((addr != FRMR_TXFIFO) && (addr != FRMR_CMDR) && (addr != 0xbc)) { unsigned int tmp; tmp = __t4_framer_in(wc, unit, addr); if (tmp != value) { dev_notice(&wc->dev->dev, "Expected %d from unit %d " "register %d but got %d instead\n", value, unit, addr, tmp); } } #endif } static void t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_framer_out(wc, unit, addr, value); spin_unlock_irqrestore(&wc->reglock, flags); } #ifdef VPM_SUPPORT static inline void wait_a_little(void) { unsigned long newjiffies=jiffies+2; while(jiffies < newjiffies); } static inline unsigned int __t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr) { unsigned int ret; unit &= 0x7; __t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12)); __t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12) | (1 << 11) | WC_LREAD); ret = __t4_pci_in(wc, WC_LDATA); __t4_pci_out(wc, WC_LADDR, 0); return ret & 0xff; } static inline void __t4_raw_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value) { int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT; if (!octopt) __t4_gpio_set(wc, 0xff, (addr >> 8)); __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff)); if (!octopt) __t4_pci_out(wc, WC_LADDR, (WC_LWRITE)); __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); if (!octopt) __t4_gpio_set(wc, 0xff, (value >> 8)); __t4_pci_out(wc, WC_LDATA, (value & 0xffff)); __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE | WC_LCS)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, WC_LADDR, (0)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); } static inline unsigned int __t4_raw_oct_in(struct t4 *wc, const unsigned int addr) { unsigned int ret; int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT; if (!octopt) __t4_gpio_set(wc, 0xff, (addr >> 8)); __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff)); if (!octopt) __t4_pci_out(wc, WC_LADDR, (WC_LWRITE)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); #ifdef PEDANTIC_OCTASIC_CHECKING __t4_pci_out(wc, WC_LADDR, (WC_LALE)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); #endif if (!octopt) { __t4_gpio_setdir(wc, 0xff, 0x00); __t4_gpio_set(wc, 0xff, 0x00); } __t4_pci_out(wc, WC_LADDR, (WC_LREAD | WC_LALE | WC_LCS)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); if (octopt) { ret = __t4_pci_in(wc, WC_LDATA) & 0xffff; } else { ret = __t4_pci_in(wc, WC_LDATA) & 0xff; ret |= (__t4_pci_in(wc, WC_GPIO) & 0xff) << 8; } __t4_pci_out(wc, WC_LADDR, (0)); if (!pedanticpci) __t4_pci_in(wc, WC_VERSION); if (!octopt) __t4_gpio_setdir(wc, 0xff, 0xff); return ret & 0xffff; } static inline unsigned int __t4_oct_in(struct t4 *wc, unsigned int addr) { #ifdef PEDANTIC_OCTASIC_CHECKING int count = 1000; #endif __t4_raw_oct_out(wc, 0x0008, (addr >> 20)); __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1)); __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1)); #ifdef PEDANTIC_OCTASIC_CHECKING while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count); if (count != 1000) dev_notice(&wc->dev->dev, "Yah, read can be slow...\n"); if (!count) dev_notice(&wc->dev->dev, "Read timed out!\n"); #endif return __t4_raw_oct_in(wc, 0x0004); } static inline unsigned int t4_oct_in(struct t4 *wc, const unsigned int addr) { unsigned long flags; unsigned int ret; spin_lock_irqsave(&wc->reglock, flags); ret = __t4_oct_in(wc, addr); spin_unlock_irqrestore(&wc->reglock, flags); return ret; } static inline unsigned int t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr) { unsigned long flags; unsigned int ret; spin_lock_irqsave(&wc->reglock, flags); ret = __t4_vpm_in(wc, unit, addr); spin_unlock_irqrestore(&wc->reglock, flags); return ret; } static inline void __t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value) { unit &= 0x7; if (debug & DEBUG_REGS) dev_notice(&wc->dev->dev, "Writing %02x to address %02x of " "ec unit %d\n", value, addr, unit); __t4_pci_out(wc, WC_LADDR, (addr & 0xff)); __t4_pci_out(wc, WC_LDATA, value); __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11)); __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11) | WC_LWRITE); __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11)); __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff)); __t4_pci_out(wc, WC_LADDR, 0); if (debug & DEBUG_REGS) dev_notice(&wc->dev->dev, "Write complete\n"); #if 0 { unsigned int tmp; tmp = t4_vpm_in(wc, unit, addr); if (tmp != value) { dev_notice(&wc->dev->dev, "Expected %d from unit %d echo " "register %d but got %d instead\n", value, unit, addr, tmp); } } #endif } static inline void __t4_oct_out(struct t4 *wc, unsigned int addr, unsigned int value) { #ifdef PEDANTIC_OCTASIC_CHECKING int count = 1000; #endif __t4_raw_oct_out(wc, 0x0008, (addr >> 20)); __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1)); __t4_raw_oct_out(wc, 0x0004, value); __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1); #ifdef PEDANTIC_OCTASIC_CHECKING while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count); if (count != 1000) dev_notice(&wc->dev->dev, "Yah, write can be slow\n"); if (!count) dev_notice(&wc->dev->dev, "Write timed out!\n"); #endif } static inline void t4_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_oct_out(wc, addr, value); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __t4_vpm_out(wc, unit, addr, value); spin_unlock_irqrestore(&wc->reglock, flags); } static const char vpm_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', '*', '#'}; static void t4_check_vpm450(struct t4 *wc) { int channel, tone, start, span; if (vpm450m_checkirq(wc->vpm450m)) { while(vpm450m_getdtmf(wc->vpm450m, &channel, &tone, &start)) { span = channel & 0x3; channel >>= 2; if (!wc->t1e1) channel -= 5; else channel -= 1; if (unlikely(debug)) dev_info(&wc->dev->dev, "Got tone %s of '%c' " "on channel %d of span %d\n", (start ? "START" : "STOP"), tone, channel, span + 1); if (test_bit(channel, &wc->tspans[span]->dtmfmask) && (tone != 'u')) { if (start) { /* The octasic is supposed to mute us, but... Yah, you guessed it. */ if (test_bit(channel, &wc->tspans[span]->dtmfmutemask)) { unsigned long flags; struct dahdi_chan *chan = wc->tspans[span]->span.chans[channel]; int y; spin_lock_irqsave(&chan->lock, flags); for (y=0;ynumbufs;y++) { if ((chan->inreadbuf > -1) && (chan->readidx[y])) memset(chan->readbuf[chan->inreadbuf], DAHDI_XLAW(0, chan), chan->readidx[y]); } spin_unlock_irqrestore(&chan->lock, flags); } set_bit(channel, &wc->tspans[span]->dtmfactive); dahdi_qevent_lock(wc->tspans[span]->span.chans[channel], (DAHDI_EVENT_DTMFDOWN | tone)); } else { clear_bit(channel, &wc->tspans[span]->dtmfactive); dahdi_qevent_lock(wc->tspans[span]->span.chans[channel], (DAHDI_EVENT_DTMFUP | tone)); } } } } } static void t4_check_vpm400(struct t4 *wc, unsigned int newio) { unsigned int digit, regval = 0; unsigned int regbyte; int x, i; short energy=0; static unsigned int lastio = 0; struct t4_span *ts; if (debug && (newio != lastio)) dev_notice(&wc->dev->dev, "Last was %08x, new is %08x\n", lastio, newio); lastio = newio; for(x = 0; x < 8; x++) { if (newio & (1 << (7 - x))) continue; ts = wc->tspans[x%4]; /* Start of DTMF detection process */ regbyte = t4_vpm_in(wc, x, 0xb8); t4_vpm_out(wc, x, 0xb8, regbyte); /* Write 1 to clear */ regval = regbyte << 8; regbyte = t4_vpm_in(wc, x, 0xb9); t4_vpm_out(wc, x, 0xb9, regbyte); regval |= regbyte; for(i = 0; (i < MAX_DTMF_DET) && regval; i++) { if(regval & 0x0001) { int channel = (i << 1) + (x >> 2); int base = channel - 1; if (!wc->t1e1) base -= 4; regbyte = t4_vpm_in(wc, x, 0xa8 + i); digit = vpm_digits[regbyte]; if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) { energy = t4_vpm_in(wc, x, 0x58 + channel); energy = DAHDI_XLAW(energy, ts->chans[0]); ts->dtmfenergy[base] = energy; } set_bit(base, &ts->dtmfactive); if (ts->dtmfdigit[base]) { if (ts->dtmfmask & (1 << base)) dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFUP | ts->dtmfdigit[base])); } ts->dtmfdigit[base] = digit; if (test_bit(base, &ts->dtmfmask)) dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFDOWN | digit)); if (test_bit(base, &ts->dtmfmutemask)) { /* Mute active receive buffer*/ unsigned long flags; struct dahdi_chan *chan = ts->span.chans[base]; int y; spin_lock_irqsave(&chan->lock, flags); for (y=0;ynumbufs;y++) { if ((chan->inreadbuf > -1) && (chan->readidx[y])) memset(chan->readbuf[chan->inreadbuf], DAHDI_XLAW(0, chan), chan->readidx[y]); } spin_unlock_irqrestore(&chan->lock, flags); } if (debug) dev_notice(&wc->dev->dev, "Digit " "Seen: %d, Span: %d, channel:" " %d, energy: %02x, 'channel " "%d' chip %d\n", digit, x % 4, base + 1, energy, channel, x); } regval = regval >> 1; } if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) continue; /* Start of DTMF off detection process */ regbyte = t4_vpm_in(wc, x, 0xbc); t4_vpm_out(wc, x, 0xbc, regbyte); /* Write 1 to clear */ regval = regbyte << 8; regbyte = t4_vpm_in(wc, x, 0xbd); t4_vpm_out(wc, x, 0xbd, regbyte); regval |= regbyte; for(i = 0; (i < MAX_DTMF_DET) && regval; i++) { if(regval & 0x0001) { int channel = (i << 1) + (x >> 2); int base = channel - 1; if (!wc->t1e1) base -= 4; clear_bit(base, &ts->dtmfactive); if (ts->dtmfdigit[base]) { if (test_bit(base, &ts->dtmfmask)) dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFUP | ts->dtmfdigit[base])); } digit = ts->dtmfdigit[base]; ts->dtmfdigit[base] = 0; if (debug) dev_notice(&wc->dev->dev, "Digit " "Gone: %d, Span: %d, channel:" " %d, energy: %02x, 'channel " "%d' chip %d\n", digit, x % 4, base + 1, energy, channel, x); } regval = regval >> 1; } } } #endif static void hdlc_stop(struct t4 *wc, unsigned int span) { struct t4_span *t = wc->tspans[span]; unsigned char imr0, imr1, mode; int i = 0; if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Stopping HDLC controller on span " "%d\n", span+1); /* Clear receive and transmit timeslots */ for (i = 0; i < 4; i++) { t4_framer_out(wc, span, FRMR_RTR_BASE + i, 0x00); t4_framer_out(wc, span, FRMR_TTR_BASE + i, 0x00); } imr0 = t4_framer_in(wc, span, FRMR_IMR0); imr1 = t4_framer_in(wc, span, FRMR_IMR1); /* Disable HDLC interrupts */ imr0 |= HDLC_IMR0_MASK; t4_framer_out(wc, span, FRMR_IMR0, imr0); imr1 |= HDLC_IMR1_MASK; t4_framer_out(wc, span, FRMR_IMR1, imr1); mode = t4_framer_in(wc, span, FRMR_MODE); mode &= ~FRMR_MODE_HRAC; t4_framer_out(wc, span, FRMR_MODE, mode); t->sigactive = 0; } static inline void __t4_framer_cmd(struct t4 *wc, unsigned int span, int cmd) { __t4_framer_out(wc, span, FRMR_CMDR, cmd); } static inline void t4_framer_cmd_wait(struct t4 *wc, unsigned int span, int cmd) { int sis; int loops = 0; /* XXX could be time consuming XXX */ for (;;) { sis = t4_framer_in(wc, span, FRMR_SIS); if (!(sis & 0x04)) break; if (!loops++ && (debug & DEBUG_FRAMER)) { dev_notice(&wc->dev->dev, "!!!SIS Waiting before cmd " "%02x\n", cmd); } } if (loops && (debug & DEBUG_FRAMER)) dev_notice(&wc->dev->dev, "!!!SIS waited %d loops\n", loops); t4_framer_out(wc, span, FRMR_CMDR, cmd); } static int hdlc_start(struct t4 *wc, unsigned int span, struct dahdi_chan *chan, unsigned char mode) { struct t4_span *t = wc->tspans[span]; unsigned char imr0, imr1; int offset = chan->chanpos; unsigned long flags; if (debug & DEBUG_FRAMER) dev_info(&wc->dev->dev, "Starting HDLC controller for channel " "%d span %d\n", offset, span+1); if (mode != FRMR_MODE_NO_ADDR_CMP) return -1; mode |= FRMR_MODE_HRAC; /* Make sure we're in the right mode */ t4_framer_out(wc, span, FRMR_MODE, mode); t4_framer_out(wc, span, FRMR_TSEO, 0x00); t4_framer_out(wc, span, FRMR_TSBS1, hardhdlcmode); /* Set the interframe gaps, etc */ t4_framer_out(wc, span, FRMR_CCR1, FRMR_CCR1_ITF|FRMR_CCR1_EITS); t4_framer_out(wc, span, FRMR_CCR2, FRMR_CCR2_RCRC); /* Set up the time slot that we want to tx/rx on */ t4_framer_out(wc, span, FRMR_TTR_BASE + (offset / 8), (0x80 >> (offset % 8))); t4_framer_out(wc, span, FRMR_RTR_BASE + (offset / 8), (0x80 >> (offset % 8))); imr0 = t4_framer_in(wc, span, FRMR_IMR0); imr1 = t4_framer_in(wc, span, FRMR_IMR1); /* Enable our interrupts again */ imr0 &= ~HDLC_IMR0_MASK; t4_framer_out(wc, span, FRMR_IMR0, imr0); imr1 &= ~HDLC_IMR1_MASK; t4_framer_out(wc, span, FRMR_IMR1, imr1); /* Reset the signaling controller */ t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES); spin_lock_irqsave(&wc->reglock, flags); t->sigchan = chan; spin_unlock_irqrestore(&wc->reglock, flags); t->sigactive = 0; return 0; } static void __set_clear(struct t4 *wc, int span) { int i,j; int oldnotclear; unsigned short val=0; struct t4_span *ts = wc->tspans[span]; oldnotclear = ts->notclear; if ((ts->spantype == TYPE_T1) || (ts->spantype == TYPE_J1)) { for (i=0;i<24;i++) { j = (i/8); if (ts->span.chans[i]->flags & DAHDI_FLAG_CLEAR) { val |= 1 << (7 - (i % 8)); ts->notclear &= ~(1 << i); } else ts->notclear |= (1 << i); if ((i % 8)==7) { if (debug) dev_notice(&wc->dev->dev, "Putting %d " "in register %02x on span %d" "\n", val, 0x2f + j, span + 1); __t4_framer_out(wc, span, 0x2f + j, val); val = 0; } } } else { for (i=0;i<31;i++) { if (ts->span.chans[i]->flags & DAHDI_FLAG_CLEAR) ts->notclear &= ~(1 << i); else ts->notclear |= (1 << i); } } if (ts->notclear != oldnotclear) { unsigned char reg; reg = __t4_framer_in(wc, span, FRMR_IMR0); if (ts->notclear) reg &= ~0x08; else reg |= 0x08; __t4_framer_out(wc, span, FRMR_IMR0, reg); } } #if 0 static void set_clear(struct t4 *wc, int span) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __set_clear(wc, span); spin_unlock_irqrestore(&wc->reglock, flags); } #endif static int t4_dacs(struct dahdi_chan *dst, struct dahdi_chan *src) { struct t4 *wc; struct t4_span *ts; wc = dst->pvt; ts = wc->tspans[dst->span->offset]; if (src && (src->pvt != dst->pvt)) { if (ts->spanflags & FLAG_2NDGEN) t4_tsi_unassign(wc, dst->span->offset, dst->chanpos); wc = src->pvt; if (ts->spanflags & FLAG_2NDGEN) t4_tsi_unassign(wc, src->span->offset, src->chanpos); if (debug) dev_notice(&wc->dev->dev, "Unassigning %d/%d by " "default and...\n", src->span->offset, src->chanpos); if (debug) dev_notice(&wc->dev->dev, "Unassigning %d/%d by " "default\n", dst->span->offset, dst->chanpos); return -1; } if (src) { t4_tsi_assign(wc, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); if (debug) dev_notice(&wc->dev->dev, "Assigning channel %d/%d -> " "%d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos); } else { t4_tsi_unassign(wc, dst->span->offset, dst->chanpos); if (debug) dev_notice(&wc->dev->dev, "Unassigning channel %d/%d!" "\n", dst->span->offset, dst->chanpos); } return 0; } #ifdef VPM_SUPPORT void oct_set_reg(void *data, unsigned int reg, unsigned int val) { struct t4 *wc = data; t4_oct_out(wc, reg, val); } unsigned int oct_get_reg(void *data, unsigned int reg) { struct t4 *wc = data; unsigned int ret; ret = t4_oct_in(wc, reg); return ret; } static int t4_vpm_unit(int span, int channel) { int unit = 0; switch(vpmspans) { case 4: unit = span; unit += (channel & 1) << 2; break; case 2: unit = span; unit += (channel & 0x3) << 1; break; case 1: unit = span; unit += (channel & 0x7); } return unit; } static const char *t4_echocan_name(const struct dahdi_chan *chan) { struct t4 *wc = chan->pvt; if (wc->vpm == T4_VPM_PRESENT) { if (!wc->vpm450m) return vpm400_name; else if (wc->numspans == 2) return vpmoct064_name; else if (wc->numspans == 4) return vpmoct128_name; } return NULL; } static int t4_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct t4 *wc = chan->pvt; struct t4_span *tspan = container_of(chan->span, struct t4_span, span); int channel; const struct dahdi_echocan_ops *ops; const struct dahdi_echocan_features *features; if (!vpmsupport || !wc->vpm) return -ENODEV; if (chan->span->offset >= vpmspans) return -ENODEV; ops = &vpm_ec_ops; features = &vpm_ec_features; if (ecp->param_count > 0) { dev_warn(&wc->dev->dev, "%s echo canceller does not support " "parameters; failing request\n", chan->ec_factory->get_name(chan)); return -EINVAL; } *ec = tspan->ec[chan->chanpos - 1]; (*ec)->ops = ops; (*ec)->features = *features; channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4; if (wc->vpm450m) { channel = channel << 2; channel |= chan->span->offset; if (debug & DEBUG_ECHOCAN) dev_notice(&wc->dev->dev, "echocan: Card is %d, " "Channel is %d, Span is %d, offset is %d " "length %d\n", wc->num, chan->chanpos, chan->span->offset, channel, ecp->tap_length); vpm450m_setec(wc->vpm450m, channel, ecp->tap_length); } else { int unit = t4_vpm_unit(chan->span->offset, channel); if (debug & DEBUG_ECHOCAN) dev_notice(&wc->dev->dev, "echocan: Card is %d, " "Channel is %d, Span is %d, unit is %d, " "unit offset is %d length %d\n", wc->num, chan->chanpos, chan->span->offset, unit, channel, ecp->tap_length); t4_vpm_out(wc, unit, channel, 0x3e); } return 0; } static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct t4 *wc = chan->pvt; int channel; memset(ec, 0, sizeof(*ec)); channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4; if (wc->vpm450m) { channel = channel << 2; channel |= chan->span->offset; if (debug & DEBUG_ECHOCAN) dev_notice(&wc->dev->dev, "echocan: Card is %d, " "Channel is %d, Span is %d, offset is %d " "length 0\n", wc->num, chan->chanpos, chan->span->offset, channel); vpm450m_setec(wc->vpm450m, channel, 0); } else { int unit = t4_vpm_unit(chan->span->offset, channel); if (debug & DEBUG_ECHOCAN) dev_notice(&wc->dev->dev, "echocan: Card is %d, " "Channel is %d, Span is %d, unit is %d, " "unit offset is %d length 0\n", wc->num, chan->chanpos, chan->span->offset, unit, channel); t4_vpm_out(wc, unit, channel, 0x01); } } #endif static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { struct t4_regs regs; int x; struct t4 *wc = chan->pvt; #ifdef VPM_SUPPORT int j; int channel; struct t4_span *ts = wc->tspans[chan->span->offset]; #endif #ifdef VPM_SUPPORT if (dtmfthreshold == 0) dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD; if (lastdtmfthreshold != dtmfthreshold) { lastdtmfthreshold = dtmfthreshold; t4_vpm_set_dtmf_threshold(wc, dtmfthreshold); } #endif switch(cmd) { case WCT4_GET_REGS: for (x=0;xspan->offset, x); if (copy_to_user((__user void *) data, ®s, sizeof(regs))) return -EFAULT; break; #ifdef VPM_SUPPORT case DAHDI_TONEDETECT: if (get_user(j, (__user int *) data)) return -EFAULT; if (!wc->vpm) return -ENOSYS; if (j && (vpmdtmfsupport == 0)) return -ENOSYS; if (j & DAHDI_TONEDETECT_ON) set_bit(chan->chanpos - 1, &ts->dtmfmask); else clear_bit(chan->chanpos - 1, &ts->dtmfmask); if (j & DAHDI_TONEDETECT_MUTE) set_bit(chan->chanpos - 1, &ts->dtmfmutemask); else clear_bit(chan->chanpos - 1, &ts->dtmfmutemask); if (wc->vpm450m) { channel = (chan->chanpos) << 2; if (!wc->t1e1) channel += (4 << 2); channel |= chan->span->offset; vpm450m_setdtmf(wc->vpm450m, channel, j & DAHDI_TONEDETECT_ON, j & DAHDI_TONEDETECT_MUTE); } return 0; #endif default: return -ENOTTY; } return 0; } static void inline t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts) { int res, i; unsigned int size = 32; unsigned char buf[32]; res = dahdi_hdlc_getbuf(ts->sigchan, buf, &size); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Got buffer sized %d and res %d " "for %d\n", size, res, span); if (size > 0) { ts->sigactive = 1; if (debug & DEBUG_FRAMER) { dev_notice(&wc->dev->dev, "TX("); for (i = 0; i < size; i++) dev_notice(&wc->dev->dev, "%s%02x", (i ? " " : ""), buf[i]); dev_notice(&wc->dev->dev, ")\n"); } for (i = 0; i < size; i++) t4_framer_out(wc, span, FRMR_TXFIFO, buf[i]); if (res) /* End of message */ { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "transmiting XHF|XME\n"); t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF | FRMR_CMDR_XME); #if 0 ts->sigactive = (__t4_framer_in(wc, span, FRMR_SIS) & FRMR_SIS_XFW) ? 0 : 1; #endif ++ts->frames_out; if ((debug & DEBUG_FRAMER) && !(ts->frames_out & 0x0f)) dev_notice(&wc->dev->dev, "Transmitted %d " "frames on span %d\n", ts->frames_out, span); } else { /* Still more to transmit */ if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "transmiting XHF\n"); t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF); } } else if (res < 0) ts->sigactive = 0; } static void t4_hdlc_hard_xmit(struct dahdi_chan *chan) { struct t4 *wc = chan->pvt; int span = chan->span->offset; struct t4_span *ts = wc->tspans[span]; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); if (!ts->sigchan) { dev_notice(&wc->dev->dev, "t4_hdlc_hard_xmit: Invalid (NULL) " "signalling channel\n"); spin_unlock_irqrestore(&wc->reglock, flags); return; } spin_unlock_irqrestore(&wc->reglock, flags); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "t4_hdlc_hard_xmit on channel %s " "(sigchan %s), sigactive=%d\n", chan->name, ts->sigchan->name, ts->sigactive); if ((ts->sigchan == chan) && !ts->sigactive) t4_hdlc_xmit_fifo(wc, span, ts); } /** * t4_set_framer_bits - Atomically set bits in a framer register. */ static void t4_set_framer_bits(struct t4 *wc, unsigned int spanno, unsigned int const addr, u16 bits) { unsigned long flags; unsigned int reg; spin_lock_irqsave(&wc->reglock, flags); reg = __t4_framer_in(wc, spanno, addr); __t4_framer_out(wc, spanno, addr, (reg | bits)); spin_unlock_irqrestore(&wc->reglock, flags); } static int t4_maint(struct dahdi_span *span, int cmd) { struct t4_span *ts = container_of(span, struct t4_span, span); struct t4 *wc = ts->owner; unsigned int reg; unsigned long flags; if (ts->spantype == TYPE_E1) { switch(cmd) { case DAHDI_MAINT_NONE: dev_info(&wc->dev->dev, "Clearing all maint modes\n"); t4_clear_maint(span); break; case DAHDI_MAINT_LOCALLOOP: dev_info(&wc->dev->dev, "Turning on local loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); break; case DAHDI_MAINT_NETWORKLINELOOP: dev_info(&wc->dev->dev, "Turning on network line loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); break; case DAHDI_MAINT_NETWORKPAYLOADLOOP: dev_info(&wc->dev->dev, "Turning on network payload loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); break; case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: dev_info(&wc->dev->dev, "Loopup & loopdown not supported in E1 mode\n"); return -ENOSYS; case DAHDI_MAINT_FAS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IFASE); break; case DAHDI_MAINT_MULTI_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IMFE); break; case DAHDI_MAINT_CRC_DEFECT: t4_framer_out(wc, span->offset, IERR_T, ICRCE); break; case DAHDI_MAINT_CAS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, ICASE); break; case DAHDI_MAINT_PRBS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IPE); break; case DAHDI_MAINT_BIPOLAR_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IBV); break; case DAHDI_RESET_COUNTERS: t4_reset_counters(span); break; case DAHDI_MAINT_ALARM_SIM: dev_info(&wc->dev->dev, "Invoking alarm state"); t4_set_framer_bits(wc, span->offset, FMR0, FMR0_SIM); break; default: dev_info(&wc->dev->dev, "Unknown E1 maint command: %d\n", cmd); return -ENOSYS; } } else { switch(cmd) { case DAHDI_MAINT_NONE: dev_info(&wc->dev->dev, "Clearing all maint modes\n"); t4_clear_maint(span); break; case DAHDI_MAINT_LOCALLOOP: dev_info(&wc->dev->dev, "Turning on local loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); break; case DAHDI_MAINT_NETWORKLINELOOP: dev_info(&wc->dev->dev, "Turning on network line loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); break; case DAHDI_MAINT_NETWORKPAYLOADLOOP: dev_info(&wc->dev->dev, "Turning on network payload loopback\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); break; case DAHDI_MAINT_LOOPUP: dev_info(&wc->dev->dev, "Transmitting loopup code\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLU); ts->span.maintstat = DAHDI_MAINT_REMOTELOOP; break; case DAHDI_MAINT_LOOPDOWN: dev_info(&wc->dev->dev, "Transmitting loopdown code\n"); t4_clear_maint(span); t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLD); break; case DAHDI_MAINT_FAS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IFASE); break; case DAHDI_MAINT_MULTI_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IMFE); break; case DAHDI_MAINT_CRC_DEFECT: t4_framer_out(wc, span->offset, IERR_T, ICRCE); break; case DAHDI_MAINT_CAS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, ICASE); break; case DAHDI_MAINT_PRBS_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IPE); break; case DAHDI_MAINT_BIPOLAR_DEFECT: t4_framer_out(wc, span->offset, IERR_T, IBV); break; case DAHDI_MAINT_PRBS: dev_info(&wc->dev->dev, "PRBS not supported\n"); #if 0 dev_notice(&wc->dev->dev, "Enabling PRBS!\n"); span->mainttimer = 1; /* Enable PRBS monitor */ reg = t4_framer_in(wc, span->offset, LCR1_T); reg |= EPRM; /* Setup PRBS xmit */ t4_framer_out(wc, span->offset, TPC0_T, 0); /* Enable PRBS transmit */ reg |= XPRBS; reg &= ~LLBP; reg &= ~FLLB; t4_framer_out(wc, span->offset, LCR1_T, reg); #endif return -ENOSYS; case DAHDI_RESET_COUNTERS: t4_reset_counters(span); break; case DAHDI_MAINT_ALARM_SIM: spin_lock_irqsave(&wc->reglock, flags); reg = __t4_framer_in(wc, span->offset, FMR0); /* * The alarm simulation state machine requires us to * bring this bit up and down for at least 1 clock cycle */ __t4_framer_out(wc, span->offset, FMR0, (reg | FMR0_SIM)); udelay(1); __t4_framer_out(wc, span->offset, FMR0, (reg & ~FMR0_SIM)); udelay(1); spin_unlock_irqrestore(&wc->reglock, flags); reg = t4_framer_in(wc, span->offset, 0x4e); if (debug & DEBUG_MAIN) { dev_info(&wc->dev->dev, "FRS2(alarm state): %d\n", ((reg & 0xe0) >> 5)); } break; default: dev_info(&wc->dev->dev, "Unknown T1 maint command:%d\n", cmd); break; } } return 0; } static int t4_clear_maint(struct dahdi_span *span) { struct t4_span *ts = container_of(span, struct t4_span, span); struct t4 *wc = ts->owner; unsigned int reg; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); /* Clear local loop */ reg = __t4_framer_in(wc, span->offset, LIM0_T); __t4_framer_out(wc, span->offset, LIM0_T, (reg & ~LIM0_LL)); /* Clear Remote Loop */ reg = __t4_framer_in(wc, span->offset, LIM1_T); __t4_framer_out(wc, span->offset, LIM1_T, (reg & ~LIM1_RL)); /* Clear Remote Payload Loop */ reg = __t4_framer_in(wc, span->offset, FMR2_T); __t4_framer_out(wc, span->offset, FMR2_T, (reg & ~FMR2_PLB)); /* Clear PRBS */ reg = __t4_framer_in(wc, span->offset, LCR1_T); __t4_framer_out(wc, span->offset, LCR1_T, (reg & ~(XPRBS | EPRM))); /* Clear loopup/loopdown signals on the line */ reg = __t4_framer_in(wc, span->offset, FMR5); __t4_framer_out(wc, span->offset, FMR5, (reg & ~(FMR5_XLU | FMR5_XLD))); spin_unlock_irqrestore(&wc->reglock, flags); span->mainttimer = 0; return 0; } static int t4_reset_counters(struct dahdi_span *span) { struct t4_span *ts = container_of(span, struct t4_span, span); memset(&ts->span.count, 0, sizeof(ts->span.count)); return 0; } static int t4_rbsbits(struct dahdi_chan *chan, int bits) { u_char m,c; int k,n,b; struct t4 *wc = chan->pvt; struct t4_span *ts = wc->tspans[chan->span->offset]; unsigned long flags; if (debug & DEBUG_RBS) dev_notice(&wc->dev->dev, "Setting bits to %d on channel %s\n", bits, chan->name); spin_lock_irqsave(&wc->reglock, flags); k = chan->span->offset; if (ts->spantype == TYPE_E1) { /* do it E1 way */ if (chan->chanpos == 16) { spin_unlock_irqrestore(&wc->reglock, flags); return 0; } n = chan->chanpos - 1; if (chan->chanpos > 15) n--; b = (n % 15); c = ts->txsigs[b]; m = (n / 15) << 2; /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ ts->txsigs[b] = c; /* output them to the chip */ __t4_framer_out(wc,k,0x71 + b,c); } else if (ts->span.lineconfig & DAHDI_CONFIG_D4) { n = chan->chanpos - 1; b = (n/4); c = ts->txsigs[b]; m = ((3 - (n % 4)) << 1); /* nibble selector */ c &= ~(0x3 << m); /* keep the other nibble */ c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */ ts->txsigs[b] = c; /* output them to the chip */ __t4_framer_out(wc,k,0x70 + b,c); __t4_framer_out(wc,k,0x70 + b + 6,c); } else if (ts->span.lineconfig & DAHDI_CONFIG_ESF) { n = chan->chanpos - 1; b = (n/2); c = ts->txsigs[b]; m = ((n % 2) << 2); /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ ts->txsigs[b] = c; /* output them to the chip */ __t4_framer_out(wc,k,0x70 + b,c); } spin_unlock_irqrestore(&wc->reglock, flags); if (debug & DEBUG_RBS) dev_notice(&wc->dev->dev, "Finished setting RBS bits\n"); return 0; } static int t4_shutdown(struct dahdi_span *span) { int tspan; int wasrunning; unsigned long flags; struct t4_span *ts = container_of(span, struct t4_span, span); struct t4 *wc = ts->owner; tspan = span->offset + 1; if (tspan < 0) { dev_notice(&wc->dev->dev, "T%dXXP: Span '%d' isn't us?\n", wc->numspans, span->spanno); return -1; } if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "Shutting down span %d (%s)\n", span->spanno, span->name); /* Stop HDLC controller if runned */ if (ts->sigchan) hdlc_stop(wc, span->offset); spin_lock_irqsave(&wc->reglock, flags); wasrunning = span->flags & DAHDI_FLAG_RUNNING; span->flags &= ~DAHDI_FLAG_RUNNING; __t4_set_led(wc, span->offset, WC_OFF); if (((wc->numspans == 4) && (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)) && (!(wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)) && (!(wc->tspans[2]->span.flags & DAHDI_FLAG_RUNNING)) && (!(wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING))) || ((wc->numspans == 2) && (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)) && (!(wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)))) { /* No longer in use, disable interrupts */ dev_info(&wc->dev->dev, "TE%dXXP: Disabling interrupts since " "there are no active spans\n", wc->numspans); set_bit(T4_STOP_DMA, &wc->checkflag); } else set_bit(T4_CHECK_TIMING, &wc->checkflag); spin_unlock_irqrestore(&wc->reglock, flags); /* Wait for interrupt routine to shut itself down */ msleep(10); if (wasrunning) wc->spansstarted--; if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "Span %d (%s) shutdown\n", span->spanno, span->name); return 0; } static void t4_chan_set_sigcap(struct dahdi_span *span, int x) { struct t4_span *wc = container_of(span, struct t4_span, span); struct dahdi_chan *chan = wc->chans[x]; chan->sigcap = DAHDI_SIG_CLEAR; /* E&M variant supported depends on span type */ if (wc->spantype == TYPE_E1) { /* E1 sigcap setup */ if (span->lineconfig & DAHDI_CONFIG_CCS) { /* CCS setup */ chan->sigcap |= DAHDI_SIG_MTP2 | DAHDI_SIG_SF | DAHDI_SIG_HARDHDLC; return; } /* clear out sig and sigcap for channel 16 on E1 CAS * lines, otherwise, set it correctly */ if (x == 15) { /* CAS signaling channel setup */ wc->chans[15]->sigcap = 0; wc->chans[15]->sig = 0; return; } /* normal CAS setup */ chan->sigcap |= DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_SF | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS; } else { /* T1 sigcap setup */ chan->sigcap |= DAHDI_SIG_EM | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_MTP2 | DAHDI_SIG_SF | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS | DAHDI_SIG_HARDHDLC; } } static int t4_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { int i; struct t4_span *ts = container_of(span, struct t4_span, span); struct t4 *wc = ts->owner; if (debug) dev_info(&wc->dev->dev, "About to enter spanconfig!\n"); if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "TE%dXXP: Configuring span %d\n", wc->numspans, span->spanno); if (lc->sync < 0) lc->sync = 0; if (lc->sync > 4) lc->sync = 0; /* remove this span number from the current sync sources, if there */ for(i = 0; i < wc->numspans; i++) { if (wc->tspans[i]->sync == span->spanno) { wc->tspans[i]->sync = 0; wc->tspans[i]->psync = 0; } } wc->tspans[span->offset]->syncpos = lc->sync; /* if a sync src, put it in proper place */ if (lc->sync) { wc->tspans[lc->sync - 1]->sync = span->spanno; wc->tspans[lc->sync - 1]->psync = span->offset + 1; } set_bit(T4_CHECK_TIMING, &wc->checkflag); /* Make sure this is clear in case of multiple startup and shutdown * iterations */ clear_bit(T4_STOP_DMA, &wc->checkflag); /* make sure that sigcaps gets updated if necessary */ for (i = 0; i < span->channels; i++) t4_chan_set_sigcap(span, i); /* If we're already running, then go ahead and apply the changes */ if (span->flags & DAHDI_FLAG_RUNNING) return t4_startup(file, span); if (debug) dev_info(&wc->dev->dev, "Done with spanconfig!\n"); return 0; } static int t4_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { int alreadyrunning; unsigned long flags; struct t4 *wc = chan->pvt; struct t4_span *ts = wc->tspans[chan->span->offset]; alreadyrunning = ts->span.flags & DAHDI_FLAG_RUNNING; if (debug & DEBUG_MAIN) { if (alreadyrunning) dev_notice(&wc->dev->dev, "TE%dXXP: Reconfigured " "channel %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype); else dev_notice(&wc->dev->dev, "TE%dXXP: Configured channel" " %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype); } spin_lock_irqsave(&wc->reglock, flags); if (alreadyrunning) __set_clear(wc, chan->span->offset); spin_unlock_irqrestore(&wc->reglock, flags); /* (re)configure signalling channel */ if ((sigtype == DAHDI_SIG_HARDHDLC) || (ts->sigchan == chan)) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "%sonfiguring hardware HDLC " "on %s\n", ((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : "Unc"), chan->name); if (alreadyrunning) { if (ts->sigchan) hdlc_stop(wc, ts->sigchan->span->offset); if (sigtype == DAHDI_SIG_HARDHDLC) { if (hdlc_start(wc, chan->span->offset, chan, ts->sigmode)) { dev_notice(&wc->dev->dev, "Error " "initializing signalling " "controller\n"); return -1; } } else { spin_lock_irqsave(&wc->reglock, flags); ts->sigchan = NULL; spin_unlock_irqrestore(&wc->reglock, flags); } } else { spin_lock_irqsave(&wc->reglock, flags); ts->sigchan = (sigtype == DAHDI_SIG_HARDHDLC) ? chan : NULL; spin_unlock_irqrestore(&wc->reglock, flags); ts->sigactive = 0; } } return 0; } static int t4_open(struct dahdi_chan *chan) { return 0; } static int t4_close(struct dahdi_chan *chan) { return 0; } static void set_span_devicetype(struct t4 *wc) { int x; struct t4_span *ts; for (x = 0; x < wc->numspans; x++) { ts = wc->tspans[x]; strlcpy(ts->span.devicetype, wc->variety, sizeof(ts->span.devicetype)); #ifdef VPM_SUPPORT if (wc->vpm == T4_VPM_PRESENT) { if (!wc->vpm450m) strncat(ts->span.devicetype, " (VPM400M)", sizeof(ts->span.devicetype) - 1); else strncat(ts->span.devicetype, (wc->numspans > 2) ? " (VPMOCT128)" : " (VPMOCT064)", sizeof(ts->span.devicetype) - 1); } #endif } } /* The number of cards we have seen with each possible 'order' switch setting. */ static unsigned int order_index[16]; static void setup_chunks(struct t4 *wc, int which) { struct t4_span *ts; int offset = 1; int x, y; int gen2; if (!wc->t1e1) offset += 4; gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN); for (x = 0; x < wc->numspans; x++) { ts = wc->tspans[x]; ts->writechunk = (void *)(wc->writechunk + (x * 32 * 2) + (which * (1024 >> 2))); ts->readchunk = (void *)(wc->readchunk + (x * 32 * 2) + (which * (1024 >> 2))); for (y=0;ytspans[x]->span.channels;y++) { struct dahdi_chan *mychans = ts->chans[y]; if (gen2) { mychans->writechunk = (void *)(wc->writechunk + ((x * 32 + y + offset) * 2) + (which * (1024 >> 2))); mychans->readchunk = (void *)(wc->readchunk + ((x * 32 + y + offset) * 2) + (which * (1024 >> 2))); } } } } static const struct dahdi_span_ops t4_gen1_span_ops = { .owner = THIS_MODULE, .spanconfig = t4_spanconfig, .chanconfig = t4_chanconfig, .startup = t4_startup, .shutdown = t4_shutdown, .rbsbits = t4_rbsbits, .maint = t4_maint, .open = t4_open, .close = t4_close, .ioctl = t4_ioctl, .hdlc_hard_xmit = t4_hdlc_hard_xmit, }; static const struct dahdi_span_ops t4_gen2_span_ops = { .owner = THIS_MODULE, .spanconfig = t4_spanconfig, .chanconfig = t4_chanconfig, .startup = t4_startup, .shutdown = t4_shutdown, .rbsbits = t4_rbsbits, .maint = t4_maint, .open = t4_open, .close = t4_close, .ioctl = t4_ioctl, .hdlc_hard_xmit = t4_hdlc_hard_xmit, .dacs = t4_dacs, #ifdef VPM_SUPPORT .echocan_create = t4_echocan_create, .echocan_name = t4_echocan_name, #endif }; static void init_spans(struct t4 *wc) { int x,y; int gen2; struct t4_span *ts; unsigned int reg; gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN); for (x = 0; x < wc->numspans; x++) { ts = wc->tspans[x]; sprintf(ts->span.name, "TE%d/%d/%d", wc->numspans, wc->num, x + 1); snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num, x+1); ts->span.manufacturer = "Digium"; if (!ignore_rotary && (1 == order_index[wc->order])) snprintf(ts->span.location, sizeof(ts->span.location) - 1, "Board ID Switch %d", wc->order); else snprintf(ts->span.location, sizeof(ts->span.location) - 1, "PCI%s Bus %02d Slot %02d", (ts->spanflags & FLAG_EXPRESS) ? " Express" : " ", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); switch (ts->spantype) { case TYPE_T1: ts->span.spantype = "T1"; break; case TYPE_E1: ts->span.spantype = "E1"; break; case TYPE_J1: ts->span.spantype = "J1"; break; } ts->span.irq = wc->dev->irq; /* HDLC Specific init */ ts->sigchan = NULL; ts->sigmode = sigmode; ts->sigactive = 0; if (ts->spantype == TYPE_T1 || ts->spantype == TYPE_J1) { ts->span.channels = 24; ts->span.deflaw = DAHDI_LAW_MULAW; ts->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; } else { ts->span.channels = 31; ts->span.deflaw = DAHDI_LAW_ALAW; ts->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; } ts->span.chans = ts->chans; ts->span.flags = DAHDI_FLAG_RBS; ts->owner = wc; ts->span.offset = x; ts->writechunk = (void *)(wc->writechunk + x * 32 * 2); ts->readchunk = (void *)(wc->readchunk + x * 32 * 2); if (gen2) { ts->span.ops = &t4_gen2_span_ops; } else { ts->span.ops = &t4_gen1_span_ops; } for (y=0;ytspans[x]->span.channels;y++) { struct dahdi_chan *mychans = ts->chans[y]; sprintf(mychans->name, "TE%d/%d/%d/%d", wc->numspans, wc->num, x + 1, y + 1); t4_chan_set_sigcap(&ts->span, x); mychans->pvt = wc; mychans->chanpos = y + 1; } /* Enable 1sec timer interrupt */ reg = t4_framer_in(wc, x, FMR1_T); t4_framer_out(wc, x, FMR1_T, (reg | FMR1_ECM)); /* Enable Errored Second interrupt */ t4_framer_out(wc, x, ESM, 0); t4_reset_counters(&ts->span); } set_span_devicetype(wc); setup_chunks(wc, 0); wc->lastindex = 0; } static void t4_serial_setup(struct t4 *wc, int unit) { if (!wc->globalconfig) { wc->globalconfig = 1; if (debug) dev_info(&wc->dev->dev, "TE%dXXP: Setting up global " "serial parameters\n", wc->numspans); t4_framer_out(wc, 0, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */ t4_framer_out(wc, 0, 0x08, 0x01); /* IPC: Interrupt push/pull active low */ /* Global clocks (8.192 Mhz CLK) */ t4_framer_out(wc, 0, 0x92, 0x00); t4_framer_out(wc, 0, 0x93, 0x18); t4_framer_out(wc, 0, 0x94, 0xfb); t4_framer_out(wc, 0, 0x95, 0x0b); t4_framer_out(wc, 0, 0x96, 0x00); t4_framer_out(wc, 0, 0x97, 0x0b); t4_framer_out(wc, 0, 0x98, 0xdb); t4_framer_out(wc, 0, 0x99, 0xdf); } /* Configure interrupts */ t4_framer_out(wc, unit, FRMR_GCR, 0x00); /* GCR: Interrupt on Activation/Deactivation of each */ /* Configure system interface */ t4_framer_out(wc, unit, FRMR_SIC1, 0xc2); /* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */ t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); /* SIC2: No FFS, no center receive eliastic buffer, phase */ t4_framer_out(wc, unit, FRMR_SIC3, 0x04); /* SIC3: Edges for capture */ t4_framer_out(wc, unit, FRMR_CMR2, 0x00); /* CMR2: We provide sync and clock for tx and rx. */ if (!wc->t1e1) { /* T1 mode */ t4_framer_out(wc, unit, FRMR_XC0, 0x03); /* XC0: Normal operation of Sa-bits */ t4_framer_out(wc, unit, FRMR_XC1, 0x84); /* XC1: 0 offset */ if (wc->tspans[unit]->spantype == TYPE_J1) t4_framer_out(wc, unit, FRMR_RC0, 0x83); /* RC0: Just shy of 1023 */ else t4_framer_out(wc, unit, FRMR_RC0, 0x03); /* RC0: Just shy of 1023 */ t4_framer_out(wc, unit, FRMR_RC1, 0x84); /* RC1: The rest of RC0 */ } else { /* E1 mode */ t4_framer_out(wc, unit, FRMR_XC0, 0x00); /* XC0: Normal operation of Sa-bits */ t4_framer_out(wc, unit, FRMR_XC1, 0x04); /* XC1: 0 offset */ t4_framer_out(wc, unit, FRMR_RC0, 0x04); /* RC0: Just shy of 1023 */ t4_framer_out(wc, unit, FRMR_RC1, 0x04); /* RC1: The rest of RC0 */ } /* Configure ports */ t4_framer_out(wc, unit, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */ if (wc->falc31) { t4_framer_out(wc, unit, 0x81, 0xBB); /* PC2: RMFB/XSIG output/input on RPB/XPB */ t4_framer_out(wc, unit, 0x82, 0xBB); /* PC3: Some unused stuff */ t4_framer_out(wc, unit, 0x83, 0xBB); /* PC4: Some more unused stuff */ } else { t4_framer_out(wc, unit, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */ t4_framer_out(wc, unit, 0x82, 0x65); /* PC3: Some unused stuff */ t4_framer_out(wc, unit, 0x83, 0x35); /* PC4: Some more unused stuff */ } t4_framer_out(wc, unit, 0x84, 0x01); /* PC5: XMFS active low, SCLKR is input, RCLK is output */ if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "Successfully initialized serial " "bus for unit %d\n", unit); } static int syncsrc = 0; static int syncnum = 0 /* -1 */; static int syncspan = 0; static DEFINE_SPINLOCK(synclock); static void __t4_set_rclk_src(struct t4 *wc, int span) { int cmr1 = 0x38; /* Clock Mode: RCLK sourced by DCO-R1 by default, Disable Clock-Switching */ cmr1 |= (span << 6); __t4_framer_out(wc, 0, 0x44, cmr1); dev_info(&wc->dev->dev, "RCLK source set to span %d\n", span+1); } static void __t4_set_sclk_src(struct t4 *wc, int mode, int master, int slave) { if (slave) { wc->dmactrl |= (1 << 25); dev_info(&wc->dev->dev, "SCLK is slaved to timing cable\n"); } else { wc->dmactrl &= ~(1 << 25); } if (master) { wc->dmactrl |= (1 << 24); dev_info(&wc->dev->dev, "SCLK is master to timing cable\n"); } else { wc->dmactrl &= ~(1 << 24); } if (mode == WC_RECOVER) wc->dmactrl |= (1 << 29); /* Recover timing from RCLK */ if (mode == WC_SELF) wc->dmactrl &= ~(1 << 29);/* Provide timing from MCLK */ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) static ssize_t t4_timing_master_show(struct device *dev, struct device_attribute *attr, char *buf) { struct t4 *wc = dev_get_drvdata(dev); if (wc->dmactrl & (1 << 29)) return sprintf(buf, "%d\n", wc->syncsrc); else return sprintf(buf, "%d\n", -1); } static DEVICE_ATTR(timing_master, 0400, t4_timing_master_show, NULL); static void create_sysfs_files(struct t4 *wc) { int ret; ret = device_create_file(&wc->dev->dev, &dev_attr_timing_master); if (ret) { dev_info(&wc->dev->dev, "Failed to create device attributes.\n"); } } static void remove_sysfs_files(struct t4 *wc) { device_remove_file(&wc->dev->dev, &dev_attr_timing_master); } #else static inline void create_sysfs_files(struct t4 *wc) { return; } static inline void remove_sysfs_files(struct t4 *wc) { return; } #endif /* LINUX_KERNEL > 2.6.18 */ static inline void __t4_update_timing(struct t4 *wc) { int i; /* update sync src info */ if (wc->syncsrc != syncsrc) { dev_info(&wc->dev->dev, "Swapping card %d from %d to %d\n", wc->num, wc->syncsrc, syncsrc); wc->syncsrc = syncsrc; /* Update sync sources */ for (i = 0; i < wc->numspans; i++) { wc->tspans[i]->span.syncsrc = wc->syncsrc; } if (syncnum == wc->num) { __t4_set_rclk_src(wc, syncspan-1); __t4_set_sclk_src(wc, WC_RECOVER, 1, 0); if (debug) dev_notice(&wc->dev->dev, "Card %d, using sync " "span %d, master\n", wc->num, syncspan); } else { __t4_set_sclk_src(wc, WC_RECOVER, 0, 1); if (debug) dev_notice(&wc->dev->dev, "Card %d, using " "Timing Bus, NOT master\n", wc->num); } } } static int __t4_findsync(struct t4 *wc) { int i; int x; unsigned long flags; int p; int nonzero; int newsyncsrc = 0; /* DAHDI span number */ int newsyncnum = 0; /* wct4xxp card number */ int newsyncspan = 0; /* span on given wct4xxp card */ spin_lock_irqsave(&synclock, flags); #if 1 if (!wc->num) { /* If we're the first card, go through all the motions, up to 8 levels of sync source */ p = 1; while (p < 8) { nonzero = 0; for (x=0;cards[x];x++) { for (i = 0; i < cards[x]->numspans; i++) { if (cards[x]->tspans[i]->syncpos) { nonzero = 1; if ((cards[x]->tspans[i]->syncpos == p) && !(cards[x]->tspans[i]->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK)) && (cards[x]->tspans[i]->span.flags & DAHDI_FLAG_RUNNING)) { /* This makes a good sync source */ newsyncsrc = cards[x]->tspans[i]->span.spanno; newsyncnum = x; newsyncspan = i + 1; /* Jump out */ goto found; } } } } if (nonzero) p++; else break; } found: if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) { if (debug) dev_notice(&wc->dev->dev, "New syncnum: %d " "(was %d), syncsrc: %d (was %d), " "syncspan: %d (was %d)\n", newsyncnum, syncnum, newsyncsrc, syncsrc, newsyncspan, syncspan); syncnum = newsyncnum; syncsrc = newsyncsrc; syncspan = newsyncspan; for (x=0;cards[x];x++) { __t4_update_timing(cards[x]); } } } __t4_update_timing(wc); #endif spin_unlock_irqrestore(&synclock, flags); return 0; } static void __t4_set_timing_source_auto(struct t4 *wc) { int x, i; int firstprio, secondprio; firstprio = secondprio = 4; if (debug) dev_info(&wc->dev->dev, "timing source auto\n"); clear_bit(T4_CHECK_TIMING, &wc->checkflag); if (timingcable) { __t4_findsync(wc); } else { if (debug) dev_info(&wc->dev->dev, "Evaluating spans for timing " "source\n"); for (x=0;xnumspans;x++) { if ((wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) && !(wc->tspans[x]->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE))) { if (debug) dev_info(&wc->dev->dev, "span %d is " "green : syncpos %d\n", x+1, wc->tspans[x]->syncpos); if (wc->tspans[x]->syncpos) { /* Valid rsync source in recovered timing mode */ if (firstprio == 4) firstprio = x; else if (wc->tspans[x]->syncpos < wc->tspans[firstprio]->syncpos) firstprio = x; } else { /* Valid rsync source in system timing mode */ if (secondprio == 4) secondprio = x; } } } if (firstprio != 4) { wc->syncsrc = firstprio; __t4_set_rclk_src(wc, firstprio); __t4_set_sclk_src(wc, WC_RECOVER, 0, 0); dev_info(&wc->dev->dev, "Recovered timing mode, "\ "RCLK set to span %d\n", firstprio+1); } else if (secondprio != 4) { wc->syncsrc = -1; __t4_set_rclk_src(wc, secondprio); __t4_set_sclk_src(wc, WC_SELF, 0, 0); dev_info(&wc->dev->dev, "System timing mode, "\ "RCLK set to span %d\n", secondprio+1); } else { wc->syncsrc = -1; dev_info(&wc->dev->dev, "All spans in alarm : No valid"\ "span to source RCLK from\n"); /* Default rclk to lock with span 1 */ __t4_set_rclk_src(wc, 0); __t4_set_sclk_src(wc, WC_SELF, 0, 0); } /* Propagate sync selection to dahdi_span struct * this is read by dahdi_tool to display the span's * master/slave sync information */ for (i = 0; i < wc->numspans; i++) { wc->tspans[i]->span.syncsrc = wc->syncsrc + 1; } } } static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlevel) { unsigned int fmr4, fmr2, fmr1, fmr0, lim2; char *framing, *line; int mytxlevel; if ((txlevel > 7) || (txlevel < 4)) mytxlevel = 0; else mytxlevel = txlevel - 4; fmr1 = 0x9c; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */ fmr2 = 0x20; /* FMR2: no payload loopback, don't auto yellow */ fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */ lim2 = 0x21; /* LIM2: 50% peak is a "1", Advanced Loss recovery */ lim2 |= (mytxlevel << 6); /* LIM2: Add line buildout */ __t4_framer_out(wc, unit, 0x1d, fmr1); __t4_framer_out(wc, unit, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; /* workaround for errata #2 in ES v3 09-10-16 */ fmr0 = (wc->falc31) ? 0xb0 : 0xa0; } else { line = "B8ZS"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_D4) { framing = "D4"; } else { framing = "ESF"; fmr4 |= 0x2; fmr2 |= 0xc0; } __t4_framer_out(wc, unit, 0x1c, fmr0); __t4_framer_out(wc, unit, 0x20, fmr4); __t4_framer_out(wc, unit, FMR5, FMR5_EIBR); /* FMR5: Enable RBS mode */ __t4_framer_out(wc, unit, 0x37, 0xf0 ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ __t4_framer_out(wc, unit, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ __t4_framer_out(wc, unit, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ __t4_framer_out(wc, unit, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ if (wc->falc31) { if (debug) dev_info(&wc->dev->dev, "card %d span %d: setting Rtx " "to 0ohm for T1\n", wc->num, unit); __t4_framer_out(wc, unit, 0x86, 0x00); /* PC6: set Rtx to 0ohm for T1 */ // Hitting the bugfix register to fix errata #3 __t4_framer_out(wc, unit, 0xbd, 0x05); } __t4_framer_out(wc, unit, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */ __t4_framer_out(wc, unit, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ __t4_framer_out(wc, unit, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ /* Generate pulse mask for T1 */ switch(mytxlevel) { case 3: __t4_framer_out(wc, unit, 0x26, 0x07); /* XPM0 */ __t4_framer_out(wc, unit, 0x27, 0x01); /* XPM1 */ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */ break; case 2: __t4_framer_out(wc, unit, 0x26, 0x8c); /* XPM0 */ __t4_framer_out(wc, unit, 0x27, 0x11); /* XPM1 */ __t4_framer_out(wc, unit, 0x28, 0x01); /* XPM2 */ break; case 1: __t4_framer_out(wc, unit, 0x26, 0x8c); /* XPM0 */ __t4_framer_out(wc, unit, 0x27, 0x01); /* XPM1 */ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */ break; case 0: default: __t4_framer_out(wc, unit, 0x26, 0xd7); /* XPM0 */ __t4_framer_out(wc, unit, 0x27, 0x22); /* XPM1 */ __t4_framer_out(wc, unit, 0x28, 0x01); /* XPM2 */ break; } /* Don't mask framer interrupts if hardware HDLC is in use */ __t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0)); /* IMR0: We care about CAS changes, etc */ __t4_framer_out(wc, unit, FRMR_IMR1, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0)); /* IMR1: We care about nothing */ __t4_framer_out(wc, unit, 0x16, 0x00); /* IMR2: All the alarm stuff! */ __t4_framer_out(wc, unit, 0x17, 0x34); /* IMR3: AIS and friends */ __t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: Slips on transmit */ dev_info(&wc->dev->dev, "Span %d configured for %s/%s\n", unit + 1, framing, line); } static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig) { unsigned int fmr2, fmr1, fmr0; unsigned int cas = 0; unsigned int imr3extra=0; char *crc4 = ""; char *framing, *line; fmr1 = 0x44; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ fmr2 = 0x03; /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, no payload loopback */ if (lineconfig & DAHDI_CONFIG_CRC4) { fmr1 |= 0x08; /* CRC4 transmit */ fmr2 |= 0xc0; /* CRC4 receive */ crc4 = "/CRC4"; } __t4_framer_out(wc, unit, 0x1d, fmr1); __t4_framer_out(wc, unit, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; /* workaround for errata #2 in ES v3 09-10-16 */ fmr0 = (wc->falc31) ? 0xb0 : 0xa0; } else { line = "HDB3"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_CCS) { framing = "CCS"; imr3extra = 0x28; } else { framing = "CAS"; cas = 0x40; } __t4_framer_out(wc, unit, 0x1c, fmr0); __t4_framer_out(wc, unit, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ __t4_framer_out(wc, unit, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ __t4_framer_out(wc, unit, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ __t4_framer_out(wc, unit, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ if (wc->falc31) { if (debug) dev_info(&wc->dev->dev, "setting Rtx to 7.5ohm for E1\n"); __t4_framer_out(wc, unit, 0x86, 0x40); /* PC6: turn on 7.5ohm Rtx for E1 */ } /* Condition receive line interface for E1 after reset */ __t4_framer_out(wc, unit, 0xbb, 0x17); __t4_framer_out(wc, unit, 0xbc, 0x55); __t4_framer_out(wc, unit, 0xbb, 0x97); __t4_framer_out(wc, unit, 0xbb, 0x11); __t4_framer_out(wc, unit, 0xbc, 0xaa); __t4_framer_out(wc, unit, 0xbb, 0x91); __t4_framer_out(wc, unit, 0xbb, 0x12); __t4_framer_out(wc, unit, 0xbc, 0x55); __t4_framer_out(wc, unit, 0xbb, 0x92); __t4_framer_out(wc, unit, 0xbb, 0x0c); __t4_framer_out(wc, unit, 0xbb, 0x00); __t4_framer_out(wc, unit, 0xbb, 0x8c); __t4_framer_out(wc, unit, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */ __t4_framer_out(wc, unit, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ __t4_framer_out(wc, unit, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ __t4_framer_out(wc, unit, 0x20, 0x9f); /* XSW: Spare bits all to 1 */ __t4_framer_out(wc, unit, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */ /* Generate pulse mask for E1 */ __t4_framer_out(wc, unit, 0x26, 0x54); /* XPM0 */ __t4_framer_out(wc, unit, 0x27, 0x02); /* XPM1 */ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */ /* Don't mask framer interrupts if hardware HDLC is in use */ __t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0)); /* IMR0: We care about CRC errors, CAS changes, etc */ __t4_framer_out(wc, unit, FRMR_IMR1, 0x3f & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0)); /* IMR1: We care about loopup / loopdown */ __t4_framer_out(wc, unit, 0x16, 0x00); /* IMR2: We care about all the alarm stuff! */ __t4_framer_out(wc, unit, 0x17, 0x04 | imr3extra); /* IMR3: AIS */ __t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */ dev_info(&wc->dev->dev, "TE%dXXP: Span %d configured for %s/%s%s\n", wc->numspans, unit + 1, framing, line, crc4); } static int t4_startup(struct file *file, struct dahdi_span *span) { #ifdef SUPPORT_GEN1 int i; #endif int tspan; unsigned long flags; int alreadyrunning; struct t4_span *ts = container_of(span, struct t4_span, span); struct t4 *wc = ts->owner; set_bit(T4_IGNORE_LATENCY, &wc->checkflag); if (debug) dev_info(&wc->dev->dev, "About to enter startup!\n"); tspan = span->offset + 1; if (tspan < 0) { dev_info(&wc->dev->dev, "TE%dXXP: Span '%d' isn't us?\n", wc->numspans, span->spanno); return -1; } spin_lock_irqsave(&wc->reglock, flags); alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; #ifdef SUPPORT_GEN1 /* initialize the start value for the entire chunk of last ec buffer */ for(i = 0; i < span->channels; i++) { memset(ts->ec_chunk1[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); memset(ts->ec_chunk2[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); } #endif /* Force re-evaluation of timing source */ wc->syncsrc = -1; set_bit(T4_CHECK_TIMING, &wc->checkflag); if (ts->spantype == TYPE_E1) { /* if this is an E1 card */ __t4_configure_e1(wc, span->offset, span->lineconfig); } else { /* is a T1 card */ __t4_configure_t1(wc, span->offset, span->lineconfig, span->txlevel); } /* Note clear channel status */ wc->tspans[span->offset]->notclear = 0; __set_clear(wc, span->offset); if (!alreadyrunning) { span->flags |= DAHDI_FLAG_RUNNING; wc->spansstarted++; if (wc->flags & FLAG_5THGEN) __t4_pci_out(wc, 5, (ms_per_irq << 16) | wc->numbufs); /* enable interrupts */ /* Start DMA, enabling DMA interrupts on read only */ #if 0 /* Enable framer only interrupts */ wc->dmactrl |= 1 << 27; #endif wc->dmactrl |= (ts->spanflags & FLAG_2NDGEN) ? 0xc0000000 : 0xc0000003; #ifdef VPM_SUPPORT wc->dmactrl |= wc->vpm; #endif /* Seed interrupt register */ __t4_pci_out(wc, WC_INTR, 0x0c); if (noburst || !(ts->spanflags & FLAG_BURST)) wc->dmactrl |= (1 << 26); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); /* Startup HDLC controller too */ } if (ts->sigchan) { struct dahdi_chan *sigchan = ts->sigchan; spin_unlock_irqrestore(&wc->reglock, flags); if (hdlc_start(wc, span->offset, sigchan, ts->sigmode)) { dev_notice(&wc->dev->dev, "Error initializing " "signalling controller\n"); return -1; } spin_lock_irqsave(&wc->reglock, flags); } spin_unlock_irqrestore(&wc->reglock, flags); t4_check_alarms(wc, span->offset); t4_check_sigbits(wc, span->offset); if (wc->tspans[0]->sync == span->spanno) dev_info(&wc->dev->dev, "SPAN %d: Primary Sync Source\n", span->spanno); if (wc->tspans[1]->sync == span->spanno) dev_info(&wc->dev->dev, "SPAN %d: Secondary Sync Source\n", span->spanno); if (wc->numspans == 4) { if (wc->tspans[2]->sync == span->spanno) dev_info(&wc->dev->dev, "SPAN %d: Tertiary Sync Source" "\n", span->spanno); if (wc->tspans[3]->sync == span->spanno) dev_info(&wc->dev->dev, "SPAN %d: Quaternary Sync " "Source\n", span->spanno); } if (debug) dev_info(&wc->dev->dev, "Completed startup!\n"); clear_bit(T4_IGNORE_LATENCY, &wc->checkflag); return 0; } #ifdef SUPPORT_GEN1 static inline void e1_check(struct t4 *wc, int span, int val) { struct t4_span *ts = wc->tspans[span]; if ((ts->span.channels > 24) && (ts->span.flags & DAHDI_FLAG_RUNNING) && !(ts->span.alarms) && (!wc->e1recover)) { if (val != 0x1b) { ts->e1check++; } else ts->e1check = 0; if (ts->e1check > 100) { /* Wait 1000 ms */ wc->e1recover = 1000 * 8; wc->tspans[0]->e1check = wc->tspans[1]->e1check = 0; if (wc->numspans == 4) wc->tspans[2]->e1check = wc->tspans[3]->e1check = 0; if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "Detected loss of " "E1 alignment on span %d!\n", span); t4_reset_dma(wc); } } } static void t4_receiveprep(struct t4 *wc, int irq) { unsigned int *readchunk; int dbl = 0; int x,y,z; unsigned int tmp; int offset=0; if (!wc->t1e1) offset = 4; if (irq & 1) { /* First part */ readchunk = wc->readchunk; if (!wc->last0) dbl = 1; wc->last0 = 0; } else { readchunk = wc->readchunk + DAHDI_CHUNKSIZE * 32; if (wc->last0) dbl = 1; wc->last0 = 1; } if (dbl) { for (x=0;xnumspans;x++) wc->tspans[x]->irqmisses++; if (debug & DEBUG_MAIN) dev_notice(&wc->dev->dev, "TE%dXXP: Double/missed " "interrupt detected\n", wc->numspans); } for (x=0;xnumspans == 4) { wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; } wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24; } if (wc->t1e1) { if (wc->e1recover > 0) wc->e1recover--; tmp = readchunk[0]; if (wc->numspans == 4) { e1_check(wc, 3, (tmp & 0x7f)); e1_check(wc, 2, (tmp & 0x7f00) >> 8); } e1_check(wc, 1, (tmp & 0x7f0000) >> 16); e1_check(wc, 0, (tmp & 0x7f000000) >> 24); for (z=24;z<31;z++) { /* Only E1 channels now */ tmp = readchunk[z+1]; if (wc->numspans == 4) { if (wc->tspans[3]->span.channels > 24) wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; if (wc->tspans[2]->span.channels > 24) wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; } if (wc->tspans[1]->span.channels > 24) wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; if (wc->tspans[0]->span.channels > 24) wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24; } } /* Advance pointer by 4 TDM frame lengths */ readchunk += 32; } for (x=0;xnumspans;x++) { if (wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) { for (y=0;ytspans[x]->span.channels;y++) { /* Echo cancel double buffered data */ dahdi_ec_chunk(wc->tspans[x]->span.chans[y], wc->tspans[x]->span.chans[y]->readchunk, wc->tspans[x]->ec_chunk2[y]); memcpy(wc->tspans[x]->ec_chunk2[y],wc->tspans[x]->ec_chunk1[y], DAHDI_CHUNKSIZE); memcpy(wc->tspans[x]->ec_chunk1[y], wc->tspans[x]->span.chans[y]->writechunk, DAHDI_CHUNKSIZE); } dahdi_receive(&wc->tspans[x]->span); } } } #endif #if (DAHDI_CHUNKSIZE != 8) #error Sorry, nextgen does not support chunksize != 8 #endif static inline void __receive_span(struct t4_span *ts) { #ifdef VPM_SUPPORT int y; unsigned long merged; merged = ts->dtmfactive & ts->dtmfmutemask; if (merged) { for (y=0;yspan.channels;y++) { /* Mute any DTMFs which are supposed to be muted */ if (test_bit(y, &merged)) { memset(ts->span.chans[y]->readchunk, DAHDI_XLAW(0, ts->span.chans[y]), DAHDI_CHUNKSIZE); } } } #endif #ifdef ENABLE_PREFETCH prefetch((void *)(ts->readchunk)); prefetch((void *)(ts->writechunk)); prefetch((void *)(ts->readchunk + 8)); prefetch((void *)(ts->writechunk + 8)); prefetch((void *)(ts->readchunk + 16)); prefetch((void *)(ts->writechunk + 16)); prefetch((void *)(ts->readchunk + 24)); prefetch((void *)(ts->writechunk + 24)); prefetch((void *)(ts->readchunk + 32)); prefetch((void *)(ts->writechunk + 32)); prefetch((void *)(ts->readchunk + 40)); prefetch((void *)(ts->writechunk + 40)); prefetch((void *)(ts->readchunk + 48)); prefetch((void *)(ts->writechunk + 48)); prefetch((void *)(ts->readchunk + 56)); prefetch((void *)(ts->writechunk + 56)); #endif dahdi_ec_span(&ts->span); dahdi_receive(&ts->span); } static inline void __transmit_span(struct t4_span *ts) { dahdi_transmit(&ts->span); } #ifdef ENABLE_WORKQUEUES static void workq_handlespan(void *data) { struct t4_span *ts = data; struct t4 *wc = ts->owner; __receive_span(ts); __transmit_span(ts); atomic_dec(&wc->worklist); if (!atomic_read(&wc->worklist)) t4_pci_out(wc, WC_INTR, 0); } #else static void t4_prep_gen2(struct t4 *wc) { int x; for (x=0;xnumspans;x++) { if (wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) { __receive_span(wc->tspans[x]); __transmit_span(wc->tspans[x]); } } } #endif #ifdef SUPPORT_GEN1 static void t4_transmitprep(struct t4 *wc, int irq) { u32 *writechunk; int x,y,z; unsigned int tmp; int offset=0; if (!wc->t1e1) offset = 4; if (irq & 1) { /* First part */ writechunk = wc->writechunk + 1; } else { writechunk = wc->writechunk + DAHDI_CHUNKSIZE * 32 + 1; } for (y=0;ynumspans;y++) { if (wc->tspans[y]->span.flags & DAHDI_FLAG_RUNNING) dahdi_transmit(&wc->tspans[y]->span); } for (x=0;xtspans[3]->span.chans[z]->writechunk[x]) | (wc->tspans[2]->span.chans[z]->writechunk[x] << 8) | (wc->tspans[1]->span.chans[z]->writechunk[x] << 16) | (wc->tspans[0]->span.chans[z]->writechunk[x] << 24); writechunk[z+offset] = tmp; } if (wc->t1e1) { for (z=24;z<31;z++) { /* Only E1 channels now */ tmp = 0; if (wc->numspans == 4) { if (wc->tspans[3]->span.channels > 24) tmp |= wc->tspans[3]->span.chans[z]->writechunk[x]; if (wc->tspans[2]->span.channels > 24) tmp |= (wc->tspans[2]->span.chans[z]->writechunk[x] << 8); } if (wc->tspans[1]->span.channels > 24) tmp |= (wc->tspans[1]->span.chans[z]->writechunk[x] << 16); if (wc->tspans[0]->span.channels > 24) tmp |= (wc->tspans[0]->span.chans[z]->writechunk[x] << 24); writechunk[z] = tmp; } } /* Advance pointer by 4 TDM frame lengths */ writechunk += 32; } } #endif static void t4_dahdi_rbsbits(struct dahdi_chan *const chan, int rxs) { if ((debug & DEBUG_RBS) && printk_ratelimit()) { const struct t4_span *tspan = container_of(chan->span, struct t4_span, span); const struct t4 *const wc = tspan->owner; dev_notice(&wc->dev->dev, "Detected sigbits change on " \ "channel %s to %04x\n", chan->name, rxs); } dahdi_rbsbits(chan, rxs); } static void t4_check_sigbits(struct t4 *wc, int span) { int a,i,rxs; struct t4_span *ts = wc->tspans[span]; if (debug & DEBUG_RBS) dev_notice(&wc->dev->dev, "Checking sigbits on span %d\n", span + 1); if (!(ts->span.flags & DAHDI_FLAG_RUNNING)) return; if (ts->spantype == TYPE_E1) { for (i = 0; i < 15; i++) { a = t4_framer_in(wc, span, 0x71 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(ts->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i+16]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i+16], rxs); } rxs = (a >> 4) & 0xf; if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i], rxs); } } } else if (ts->span.lineconfig & DAHDI_CONFIG_D4) { for (i = 0; i < 24; i+=4) { a = t4_framer_in(wc, span, 0x70 + (i>>2)); /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(ts->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i+3]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i+3], rxs); } rxs = (a & 0xc); if (!(ts->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i+2]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i+2], rxs); } rxs = (a >> 2) & 0xc; if (!(ts->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i+1]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i+1], rxs); } rxs = (a >> 4) & 0xc; if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (ts->span.chans[i]->rxsig != rxs) t4_dahdi_rbsbits(ts->span.chans[i], rxs); } } } else { for (i = 0; i < 24; i+=2) { a = t4_framer_in(wc, span, 0x70 + (i>>1)); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(ts->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { /* XXX Not really reset on every trans! XXX */ if (ts->span.chans[i+1]->rxsig != rxs) { t4_dahdi_rbsbits(ts->span.chans[i+1], rxs); } } rxs = (a >> 4) & 0xf; if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { /* XXX Not really reset on every trans! XXX */ if (ts->span.chans[i]->rxsig != rxs) { t4_dahdi_rbsbits(ts->span.chans[i], rxs); } } } } } static void t4_check_alarms(struct t4 *wc, int span) { unsigned char c, d, e; int alarms; int x,j; struct t4_span *ts = wc->tspans[span]; unsigned long flags; if (!(ts->span.flags & DAHDI_FLAG_RUNNING)) return; spin_lock_irqsave(&wc->reglock, flags); c = __t4_framer_in(wc, span, 0x4c); d = __t4_framer_in(wc, span, 0x4d); /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ ts->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); if (ts->spantype == TYPE_E1) { if (c & 0x04) { /* No multiframe found, force RAI high after 400ms only if we haven't found a multiframe since last loss of frame */ if (!(ts->spanflags & FLAG_NMF)) { __t4_framer_out(wc, span, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ ts->spanflags |= FLAG_NMF; dev_notice(&wc->dev->dev, "Lost crc4-multiframe alignment\n"); } __t4_framer_out(wc, span, 0x1e, 0xc3); /* Reset to CRC4 mode */ __t4_framer_out(wc, span, 0x1c, 0xf2); /* Force Resync */ __t4_framer_out(wc, span, 0x1c, 0xf0); /* Force Resync */ } else if (!(c & 0x02)) { if ((ts->spanflags & FLAG_NMF)) { __t4_framer_out(wc, span, 0x20, 0x9f); /* LIM0: Clear forced RAI */ ts->spanflags &= ~FLAG_NMF; dev_notice(&wc->dev->dev, "Obtained crc4-multiframe alignment\n"); } } } else { /* Detect loopup code if we're not sending one */ if ((!ts->span.mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((ts->loopupcnt++ > 80) && (ts->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { dev_notice(&wc->dev->dev, "span %d: Loopup detected,"\ " enabling remote loop\n", span+1); __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */ __t4_framer_out(wc, span, 0x37, 0xf6 ); /* LIM1: Enable remote loop */ ts->span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else ts->loopupcnt = 0; /* Same for loopdown code */ if ((!ts->span.mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((ts->loopdowncnt++ > 80) && (ts->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { dev_notice(&wc->dev->dev, "span %d: Loopdown detected,"\ " disabling remote loop\n", span+1); __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */ __t4_framer_out(wc, span, 0x37, 0xf0 ); /* LIM1: Disable remote loop */ ts->span.maintstat = DAHDI_MAINT_NONE; } } else ts->loopdowncnt = 0; } if (ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { for (x=0,j=0;x < ts->span.channels;x++) if ((ts->span.chans[x]->flags & DAHDI_FLAG_OPEN) || dahdi_have_netdev(ts->span.chans[x])) j++; if (!j) alarms |= DAHDI_ALARM_NOTOPEN; } /* Loss of Frame Alignment */ if (c & 0x20) { if (ts->alarmcount >= alarmdebounce) { /* Disable Slip Interrupts */ e = __t4_framer_in(wc, span, 0x17); __t4_framer_out(wc, span, 0x17, (e|0x03)); alarms |= DAHDI_ALARM_RED; } else { if (unlikely(debug && !ts->alarmcount)) { /* starting to debounce LOF/LFA */ dev_info(&wc->dev->dev, "wct%dxxp: LOF/LFA " "detected on span %d but debouncing " "for %d ms\n", wc->numspans, span + 1, alarmdebounce); } ts->alarmcount++; } } else ts->alarmcount = 0; /* Loss of Signal */ if (c & 0x80) { if (ts->losalarmcount >= losalarmdebounce) { /* Disable Slip Interrupts */ e = __t4_framer_in(wc, span, 0x17); __t4_framer_out(wc, span, 0x17, (e|0x03)); alarms |= DAHDI_ALARM_RED; } else { if (unlikely(debug && !ts->losalarmcount)) { /* starting to debounce LOS */ dev_info(&wc->dev->dev, "wct%dxxp: LOS " "detected on span %d but debouncing " "for %d ms\n", wc->numspans, span + 1, losalarmdebounce); } ts->losalarmcount++; } } else ts->losalarmcount = 0; /* Alarm Indication Signal */ if (c & 0x40) { if (ts->aisalarmcount >= aisalarmdebounce) alarms |= DAHDI_ALARM_BLUE; else { if (unlikely(debug && !ts->aisalarmcount)) { /* starting to debounce AIS */ dev_info(&wc->dev->dev, "wct%dxxp: AIS " "detected on span %d but debouncing " "for %d ms\n", wc->numspans, span + 1, aisalarmdebounce); } ts->aisalarmcount++; } } else ts->aisalarmcount = 0; /* Add detailed alarm status information to a red alarm state */ if (alarms & DAHDI_ALARM_RED) { if (c & FRS0_LOS) alarms |= DAHDI_ALARM_LOS; if (c & FRS0_LFA) alarms |= DAHDI_ALARM_LFA; if (c & FRS0_LMFA) alarms |= DAHDI_ALARM_LMFA; } if (unlikely(debug)) { /* Check to ensure the xmit line isn't shorted */ if (unlikely(d & FRS1_XLS)) { dev_info(&wc->dev->dev, "Detected a possible hardware malfunction"\ " this card may need servicing\n"); } } if (((!ts->span.alarms) && alarms) || (ts->span.alarms && (!alarms))) set_bit(T4_CHECK_TIMING, &wc->checkflag); /* Keep track of recovering */ if ((!alarms) && ts->span.alarms) ts->alarmtimer = DAHDI_ALARMSETTLE_TIME; if (ts->alarmtimer) alarms |= DAHDI_ALARM_RECOVER; /* If receiving alarms, go into Yellow alarm state */ if (alarms && !(ts->spanflags & FLAG_SENDINGYELLOW)) { /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ unsigned char fmr4; fmr4 = __t4_framer_in(wc, span, 0x20); __t4_framer_out(wc, span, 0x20, fmr4 | 0x20); dev_info(&wc->dev->dev, "Setting yellow alarm span %d\n", span+1); ts->spanflags |= FLAG_SENDINGYELLOW; } else if ((!alarms) && (ts->spanflags & FLAG_SENDINGYELLOW)) { unsigned char fmr4; /* We manually do yellow alarm to handle RECOVER */ fmr4 = __t4_framer_in(wc, span, 0x20); __t4_framer_out(wc, span, 0x20, fmr4 & ~0x20); dev_info(&wc->dev->dev, "Clearing yellow alarm span %d\n", span+1); /* Re-enable timing slip interrupts */ e = __t4_framer_in(wc, span, 0x17); __t4_framer_out(wc, span, 0x17, (e & ~(0x03))); ts->spanflags &= ~FLAG_SENDINGYELLOW; } /* Re-check the timing source when we enter/leave alarm, not withstanding yellow alarm */ if (c & 0x10) { /* receiving yellow (RAI) */ if (ts->yelalarmcount >= yelalarmdebounce) alarms |= DAHDI_ALARM_YELLOW; else { if (unlikely(debug && !ts->yelalarmcount)) { /* starting to debounce AIS */ dev_info(&wc->dev->dev, "wct%dxxp: yellow " "(RAI) detected on span %d but " "debouncing for %d ms\n", wc->numspans, span + 1, yelalarmdebounce); } ts->yelalarmcount++; } } else ts->yelalarmcount = 0; if (ts->span.mainttimer || ts->span.maintstat) alarms |= DAHDI_ALARM_LOOPBACK; ts->span.alarms = alarms; spin_unlock_irqrestore(&wc->reglock, flags); dahdi_alarm_notify(&ts->span); } static void t4_do_counters(struct t4 *wc) { int span; for (span=0;spannumspans;span++) { struct t4_span *ts = wc->tspans[span]; int docheck=0; spin_lock(&wc->reglock); if (ts->loopupcnt || ts->loopdowncnt || ts->alarmcount || ts->losalarmcount || ts->aisalarmcount || ts->yelalarmcount) docheck++; if (ts->alarmtimer) { if (!--ts->alarmtimer) { docheck++; ts->span.alarms &= ~(DAHDI_ALARM_RECOVER); } } spin_unlock(&wc->reglock); if (docheck) { t4_check_alarms(wc, span); dahdi_alarm_notify(&ts->span); } } } static inline void __handle_leds(struct t4 *wc) { int x; wc->blinktimer++; for (x=0;xnumspans;x++) { struct t4_span *ts = wc->tspans[x]; if (ts->span.flags & DAHDI_FLAG_RUNNING) { if ((ts->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) || ts->losalarmcount) { #ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { __t4_set_led(wc, x, WC_RED); } if (wc->blinktimer == 0xf) { __t4_set_led(wc, x, WC_OFF); } #else if (wc->blinktimer == 160) { __t4_set_led(wc, x, WC_RED); } else if (wc->blinktimer == 480) { __t4_set_led(wc, x, WC_OFF); } #endif } else if (ts->span.alarms & DAHDI_ALARM_YELLOW) { /* Yellow Alarm */ __t4_set_led(wc, x, WC_YELLOW); } else if (ts->span.mainttimer || ts->span.maintstat) { #ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { __t4_set_led(wc, x, WC_GREEN); } if (wc->blinktimer == 0xf) { __t4_set_led(wc, x, WC_OFF); } #else if (wc->blinktimer == 160) { __t4_set_led(wc, x, WC_GREEN); } else if (wc->blinktimer == 480) { __t4_set_led(wc, x, WC_OFF); } #endif } else { /* No Alarm */ __t4_set_led(wc, x, WC_GREEN); } } else __t4_set_led(wc, x, WC_OFF); } #ifdef FANCY_ALARM if (wc->blinktimer == 0xf) { wc->blinktimer = -1; wc->alarmpos++; if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) wc->alarmpos = 0; } #else if (wc->blinktimer == 480) wc->blinktimer = 0; #endif } static inline void t4_framer_interrupt(struct t4 *wc, int span) { /* Check interrupts for a given span */ unsigned char gis, isr0, isr1, isr2, isr3, isr4; int readsize = -1; struct t4_span *ts = wc->tspans[span]; struct dahdi_chan *sigchan; unsigned long flags; /* 1st gen cards isn't used interrupts */ spin_lock_irqsave(&wc->reglock, flags); gis = __t4_framer_in(wc, span, FRMR_GIS); isr0 = (gis & FRMR_GIS_ISR0) ? __t4_framer_in(wc, span, FRMR_ISR0) : 0; isr1 = (gis & FRMR_GIS_ISR1) ? __t4_framer_in(wc, span, FRMR_ISR1) : 0; isr2 = (gis & FRMR_GIS_ISR2) ? __t4_framer_in(wc, span, FRMR_ISR2) : 0; isr3 = (gis & FRMR_GIS_ISR3) ? __t4_framer_in(wc, span, FRMR_ISR3) : 0; isr4 = (gis & FRMR_GIS_ISR4) ? __t4_framer_in(wc, span, FRMR_ISR4) : 0; if ((debug & DEBUG_FRAMER) && !(isr3 & ISR3_SEC)) { dev_info(&wc->dev->dev, "gis: %02x, isr0: %02x, isr1: %02x, "\ "isr2: %02x, isr3: %08x, isr4: %02x, intcount=%u\n", gis, isr0, isr1, isr2, isr3, isr4, wc->intcount); } /* Collect performance counters once per second */ if (isr3 & ISR3_SEC) { ts->span.count.fe += __t4_framer_in(wc, span, FECL_T); ts->span.count.crc4 += __t4_framer_in(wc, span, CEC1L_T); ts->span.count.cv += __t4_framer_in(wc, span, CVCL_T); ts->span.count.ebit += __t4_framer_in(wc, span, EBCL_T); ts->span.count.be += __t4_framer_in(wc, span, BECL_T); ts->span.count.prbs = __t4_framer_in(wc, span, FRS1_T); } spin_unlock_irqrestore(&wc->reglock, flags); /* Collect errored second counter once per second */ if (isr3 & ISR3_ES) { ts->span.count.errsec += 1; } if (isr0) t4_check_sigbits(wc, span); if (ts->spantype == TYPE_E1) { /* E1 checks */ if ((isr3 & 0x38) || isr2 || isr1) t4_check_alarms(wc, span); } else { /* T1 checks */ if (isr2 || (isr3 & 0x08)) t4_check_alarms(wc, span); } if (!ts->span.alarms) { if ((isr3 & 0x3) || (isr4 & 0xc0)) ts->span.timingslips++; if (debug & DEBUG_MAIN) { if (isr3 & 0x02) dev_notice(&wc->dev->dev, "TE%d10P: RECEIVE " "slip NEGATIVE on span %d\n", wc->numspans, span + 1); if (isr3 & 0x01) dev_notice(&wc->dev->dev, "TE%d10P: RECEIVE " "slip POSITIVE on span %d\n", wc->numspans, span + 1); if (isr4 & 0x80) dev_notice(&wc->dev->dev, "TE%dXXP: TRANSMIT " "slip POSITIVE on span %d\n", wc->numspans, span + 1); if (isr4 & 0x40) dev_notice(&wc->dev->dev, "TE%d10P: TRANSMIT " "slip NEGATIVE on span %d\n", wc->numspans, span + 1); } } else ts->span.timingslips = 0; spin_lock_irqsave(&wc->reglock, flags); /* HDLC controller checks - receive side */ if (!ts->sigchan) { spin_unlock_irqrestore(&wc->reglock, flags); return; } sigchan = ts->sigchan; spin_unlock_irqrestore(&wc->reglock, flags); if (isr0 & FRMR_ISR0_RME) { readsize = (t4_framer_in(wc, span, FRMR_RBCH) << 8) | t4_framer_in(wc, span, FRMR_RBCL); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Received data length is %d " "(%d)\n", readsize, readsize & FRMR_RBCL_MAX_SIZE); /* RPF isn't set on last part of frame */ if ((readsize > 0) && ((readsize &= FRMR_RBCL_MAX_SIZE) == 0)) readsize = FRMR_RBCL_MAX_SIZE + 1; } else if (isr0 & FRMR_ISR0_RPF) readsize = FRMR_RBCL_MAX_SIZE + 1; if (readsize > 0) { int i; unsigned char readbuf[FRMR_RBCL_MAX_SIZE + 1]; if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Framer %d: Got RPF/RME! " "readsize is %d\n", sigchan->span->offset, readsize); for (i = 0; i < readsize; i++) readbuf[i] = t4_framer_in(wc, span, FRMR_RXFIFO); /* Tell the framer to clear the RFIFO */ t4_framer_cmd_wait(wc, span, FRMR_CMDR_RMC); if (debug & DEBUG_FRAMER) { dev_notice(&wc->dev->dev, "RX("); for (i = 0; i < readsize; i++) dev_notice(&wc->dev->dev, "%s%02x", (i ? " " : ""), readbuf[i]); dev_notice(&wc->dev->dev, ")\n"); } if (isr0 & FRMR_ISR0_RME) { /* Do checks for HDLC problems */ unsigned char rsis = readbuf[readsize-1]; #if 0 unsigned int olddebug = debug; #endif unsigned char rsis_reg = t4_framer_in(wc, span, FRMR_RSIS); #if 0 if ((rsis != 0xA2) || (rsis != rsis_reg)) debug |= DEBUG_FRAMER; #endif ++ts->frames_in; if ((debug & DEBUG_FRAMER) && !(ts->frames_in & 0x0f)) dev_notice(&wc->dev->dev, "Received %d frames " "on span %d\n", ts->frames_in, span); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Received HDLC frame" " %d. RSIS = 0x%x (%x)\n", ts->frames_in, rsis, rsis_reg); if (!(rsis & FRMR_RSIS_CRC16)) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "CRC check " "failed %d\n", span); dahdi_hdlc_abort(sigchan, DAHDI_EVENT_BADFCS); } else if (rsis & FRMR_RSIS_RAB) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "ABORT of " "current frame due to " "overflow %d\n", span); dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT); } else if (rsis & FRMR_RSIS_RDO) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "HDLC " "overflow occured %d\n", span); dahdi_hdlc_abort(sigchan, DAHDI_EVENT_OVERRUN); } else if (!(rsis & FRMR_RSIS_VFR)) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Valid Frame" " check failed on span %d\n", span); dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT); } else { dahdi_hdlc_putbuf(sigchan, readbuf, readsize - 1); dahdi_hdlc_finish(sigchan); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Received " "valid HDLC frame on span %d" "\n", span); } #if 0 debug = olddebug; #endif } else if (isr0 & FRMR_ISR0_RPF) dahdi_hdlc_putbuf(sigchan, readbuf, readsize); } /* Transmit side */ if (isr1 & FRMR_ISR1_XDU) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "XDU: Resetting signal " "controller!\n"); t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES); } else if (isr1 & FRMR_ISR1_XPR) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Sigchan %d is %p\n", sigchan->chanpos, sigchan); if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "Framer %d: Got XPR!\n", sigchan->span->offset); t4_hdlc_xmit_fifo(wc, span, ts); } if (isr1 & FRMR_ISR1_ALLS) { if (debug & DEBUG_FRAMER) dev_notice(&wc->dev->dev, "ALLS received\n"); } } #ifdef SUPPORT_GEN1 DAHDI_IRQ_HANDLER(t4_interrupt) { struct t4 *wc = dev_id; unsigned long flags; int x; unsigned int status; unsigned int status2; #if 0 if (wc->intcount < 20) dev_notice(&wc->dev->dev, "Pre-interrupt\n"); #endif /* Make sure it's really for us */ status = __t4_pci_in(wc, WC_INTR); /* Process framer interrupts */ status2 = t4_framer_in(wc, 0, FRMR_CIS); if (status2 & 0x0f) { for (x = 0; x < wc->numspans; ++x) { if (status2 & (1 << x)) t4_framer_interrupt(wc, x); } } /* Ignore if it's not for us */ if (!status) return IRQ_NONE; __t4_pci_out(wc, WC_INTR, 0); if (!wc->spansstarted) { dev_notice(&wc->dev->dev, "Not prepped yet!\n"); return IRQ_NONE; } wc->intcount++; #if 0 if (wc->intcount < 20) dev_notice(&wc->dev->dev, "Got interrupt, status = %08x\n", status); #endif if (status & 0x3) { t4_receiveprep(wc, status); t4_transmitprep(wc, status); } #if 0 if ((wc->intcount < 10) || !(wc->intcount % 1000)) { status2 = t4_framer_in(wc, 0, FRMR_CIS); dev_notice(&wc->dev->dev, "Status2: %04x\n", status2); for (x = 0;xnumspans;x++) { status2 = t4_framer_in(wc, x, FRMR_FRS0); dev_notice(&wc->dev->dev, "FRS0/%d: %04x\n", x, status2); } } #endif t4_do_counters(wc); x = wc->intcount & 15 /* 63 */; switch(x) { case 0: case 1: case 2: case 3: t4_check_sigbits(wc, x); break; case 4: case 5: case 6: case 7: t4_check_alarms(wc, x - 4); break; } spin_lock_irqsave(&wc->reglock, flags); __handle_leds(wc); if (test_bit(T4_CHECK_TIMING, &wc->checkflag)) __t4_set_timing_source_auto(wc); spin_unlock_irqrestore(&wc->reglock, flags); return IRQ_RETVAL(1); } #endif static int t4_allocate_buffers(struct t4 *wc, int numbufs, void **oldalloc, dma_addr_t *oldwritedma) { void *alloc; dma_addr_t writedma; /* 32 channels, Double-buffer, Read/Write, 4 spans */ alloc = pci_alloc_consistent(wc->dev, numbufs * T4_BASE_SIZE * 2, &writedma); if (!alloc) { dev_notice(&wc->dev->dev, "wct%dxxp: Unable to allocate " "DMA-able memory\n", wc->numspans); return -ENOMEM; } if (oldwritedma) *oldwritedma = wc->writedma; if (oldalloc) *oldalloc = wc->writechunk; wc->writechunk = alloc; wc->writedma = writedma; /* Read is after the whole write piece (in words) */ wc->readchunk = wc->writechunk + (T4_BASE_SIZE * numbufs) / 4; /* Same thing but in bytes... */ wc->readdma = wc->writedma + (T4_BASE_SIZE * numbufs); wc->numbufs = numbufs; /* Initialize Write/Buffers to all blank data */ memset(wc->writechunk, 0x00, T4_BASE_SIZE * numbufs); memset(wc->readchunk, 0xff, T4_BASE_SIZE * numbufs); if (debug) { dev_notice(&wc->dev->dev, "DMA memory base of size %d at " \ "%p. Read: %p and Write %p\n", numbufs * T4_BASE_SIZE * 2, wc->writechunk, wc->readchunk, wc->writechunk); } return 0; } static void t4_increase_latency(struct t4 *wc, int newlatency) { unsigned long flags; void *oldalloc; dma_addr_t oldaddr; int oldbufs; spin_lock_irqsave(&wc->reglock, flags); __t4_pci_out(wc, WC_DMACTRL, 0x00000000); /* Acknowledge any pending interrupts */ __t4_pci_out(wc, WC_INTR, 0x00000000); __t4_pci_in(wc, WC_VERSION); oldbufs = wc->numbufs; if (t4_allocate_buffers(wc, newlatency, &oldalloc, &oldaddr)) { dev_info(&wc->dev->dev, "Error allocating latency buffers for " "latency of %d\n", newlatency); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); spin_unlock_irqrestore(&wc->reglock, flags); return; } __t4_pci_out(wc, WC_RDADDR, wc->readdma); __t4_pci_out(wc, WC_WRADDR, wc->writedma); __t4_pci_in(wc, WC_VERSION); __t4_pci_out(wc, 5, (ms_per_irq << 16) | newlatency); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); __t4_pci_in(wc, WC_VERSION); wc->rxident = 0; wc->lastindex = 0; spin_unlock_irqrestore(&wc->reglock, flags); pci_free_consistent(wc->dev, T4_BASE_SIZE * oldbufs * 2, oldalloc, oldaddr); dev_info(&wc->dev->dev, "Increased latency to %d\n", newlatency); } static void t4_isr_bh(unsigned long data) { struct t4 *wc = (struct t4 *)data; if (test_bit(T4_CHANGE_LATENCY, &wc->checkflag)) { if (wc->needed_latency != wc->numbufs) { t4_increase_latency(wc, wc->needed_latency); clear_bit(T4_CHANGE_LATENCY, &wc->checkflag); } } #ifdef VPM_SUPPORT if (wc->vpm) { if (test_and_clear_bit(T4_CHECK_VPM, &wc->checkflag)) { if (wc->vpm450m) { /* How stupid is it that the octasic can't generate an interrupt when there's a tone, in spite of what their documentation says? */ t4_check_vpm450(wc); } else t4_check_vpm400(wc, wc->vpm400checkstatus); } } #endif } DAHDI_IRQ_HANDLER(t4_interrupt_gen2) { struct t4 *wc = dev_id; unsigned int status; unsigned char rxident, expected; #if 0 if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag))) { goto out; } #endif /* Check this first in case we get a spurious interrupt */ if (unlikely(test_bit(T4_STOP_DMA, &wc->checkflag))) { /* Stop DMA cleanly if requested */ wc->dmactrl = 0x0; t4_pci_out(wc, WC_DMACTRL, 0x00000000); /* Acknowledge any pending interrupts */ t4_pci_out(wc, WC_INTR, 0x00000000); spin_lock(&wc->reglock); __t4_set_sclk_src(wc, WC_SELF, 0, 0); spin_unlock(&wc->reglock); return IRQ_RETVAL(1); } /* Make sure it's really for us */ status = __t4_pci_in(wc, WC_INTR); /* Ignore if it's not for us */ if (!(status & 0x7)) { return IRQ_NONE; } #ifdef ENABLE_WORKQUEUES __t4_pci_out(wc, WC_INTR, status & 0x00000008); #endif if (unlikely(!wc->spansstarted)) { dev_info(&wc->dev->dev, "Not prepped yet!\n"); return IRQ_NONE; } wc->intcount++; if ((wc->flags & FLAG_5THGEN) && (status & 0x2)) { rxident = (status >> 16) & 0x7f; expected = (wc->rxident + ms_per_irq) % 128; if ((rxident != expected) && !test_bit(T4_IGNORE_LATENCY, &wc->checkflag)) { int needed_latency; int smallest_max; if (debug & DEBUG_MAIN) dev_warn(&wc->dev->dev, "Missed interrupt. " "Expected ident of %d and got ident " "of %d\n", expected, rxident); if (test_bit(T4_IGNORE_LATENCY, &wc->checkflag)) { dev_info(&wc->dev->dev, "Should have ignored latency\n"); } if (rxident > wc->rxident) { needed_latency = rxident - wc->rxident; } else { needed_latency = (128 - wc->rxident) + rxident; } needed_latency += 1; smallest_max = (max_latency >= GEN5_MAX_LATENCY) ? GEN5_MAX_LATENCY : max_latency; if (needed_latency > smallest_max) { dev_info(&wc->dev->dev, "Truncating latency " "request to %d instead of %d\n", smallest_max, needed_latency); needed_latency = smallest_max; } if (needed_latency > wc->numbufs) { int x; dev_info(&wc->dev->dev, "Need to increase " "latency. Estimated latency should " "be %d\n", needed_latency); for (x = 0; x < wc->numspans; x++) wc->tspans[x]->span.irqmisses++; wc->needed_latency = needed_latency; __t4_pci_out(wc, WC_DMACTRL, 0x00000000); set_bit(T4_CHANGE_LATENCY, &wc->checkflag); goto out; } } wc->rxident = rxident; } if (unlikely((wc->intcount < 20))) dev_info(&wc->dev->dev, "2G: Got interrupt, status = %08x, " "CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS)); if (likely(status & 0x2)) { #ifdef ENABLE_WORKQUEUES int cpus = num_online_cpus(); atomic_set(&wc->worklist, wc->numspans); if (wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING) t4_queue_work(wc->workq, &wc->tspans[0]->swork, 0); else atomic_dec(&wc->worklist); if (wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING) t4_queue_work(wc->workq, &wc->tspans[1]->swork, 1 % cpus); else atomic_dec(&wc->worklist); if (wc->numspans == 4) { if (wc->tspans[2]->span.flags & DAHDI_FLAG_RUNNING) t4_queue_work(wc->workq, &wc->tspans[2]->swork, 2 % cpus); else atomic_dec(&wc->worklist); if (wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING) t4_queue_work(wc->workq, &wc->tspans[3]->swork, 3 % cpus); else atomic_dec(&wc->worklist); } #else #if 1 unsigned int reg5 = __t4_pci_in(wc, 5); if (wc->intcount < 20) { dev_info(&wc->dev->dev, "Reg 5 is %08x\n", reg5); } #endif if (wc->flags & FLAG_5THGEN) { unsigned int current_index = (reg5 >> 8) & 0x7f; #if 0 int catchup = 0; #endif while (((wc->lastindex + 1) % wc->numbufs) != current_index) { #if 0 catchup++; #endif wc->lastindex = (wc->lastindex + 1) % wc->numbufs; setup_chunks(wc, wc->lastindex); t4_prep_gen2(wc); } #if 0 if (catchup > 1) { dev_info(&wc->dev->dev, "Caught up %d " "chunks\n", catchup); } #endif } else { t4_prep_gen2(wc); } #endif t4_do_counters(wc); spin_lock(&wc->reglock); __handle_leds(wc); spin_unlock(&wc->reglock); } if (unlikely(status & 0x1)) { unsigned char cis; cis = t4_framer_in(wc, 0, FRMR_CIS); if (cis & FRMR_CIS_GIS1) t4_framer_interrupt(wc, 0); if (cis & FRMR_CIS_GIS2) t4_framer_interrupt(wc, 1); if (cis & FRMR_CIS_GIS3) t4_framer_interrupt(wc, 2); if (cis & FRMR_CIS_GIS4) t4_framer_interrupt(wc, 3); } #ifdef VPM_SUPPORT if (wc->vpm && vpmdtmfsupport) { if (wc->vpm450m) { /* How stupid is it that the octasic can't generate an interrupt when there's a tone, in spite of what their documentation says? */ if (!(wc->intcount & 0xf)) { set_bit(T4_CHECK_VPM, &wc->checkflag); } } else if ((status & 0xff00) != 0xff00) { wc->vpm400checkstatus = (status & 0xff00) >> 8; set_bit(T4_CHECK_VPM, &wc->checkflag); } } #endif spin_lock(&wc->reglock); if (unlikely(test_bit(T4_CHECK_TIMING, &wc->checkflag))) { __t4_set_timing_source_auto(wc); } spin_unlock(&wc->reglock); out: if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag) || test_bit(T4_CHECK_VPM, &wc->checkflag))) tasklet_schedule(&wc->t4_tlet); #ifndef ENABLE_WORKQUEUES __t4_pci_out(wc, WC_INTR, 0); #endif return IRQ_RETVAL(1); } #ifdef SUPPORT_GEN1 static int t4_reset_dma(struct t4 *wc) { /* Turn off DMA and such */ wc->dmactrl = 0x0; t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); t4_pci_out(wc, WC_COUNT, 0); t4_pci_out(wc, WC_RDADDR, 0); t4_pci_out(wc, WC_WRADDR, 0); t4_pci_out(wc, WC_INTR, 0); /* Turn it all back on */ t4_pci_out(wc, WC_RDADDR, wc->readdma); t4_pci_out(wc, WC_WRADDR, wc->writedma); t4_pci_out(wc, WC_COUNT, ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 2)); t4_pci_out(wc, WC_INTR, 0); #ifdef VPM_SUPPORT wc->dmactrl = 0xc0000000 | (1 << 29) | wc->vpm; #else wc->dmactrl = 0xc0000000 | (1 << 29); #endif if (noburst) wc->dmactrl |= (1 << 26); t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); return 0; } #endif #ifdef VPM_SUPPORT static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold) { unsigned int x; for (x = 0; x < 8; x++) { t4_vpm_out(wc, x, 0xC4, (threshold >> 8) & 0xFF); t4_vpm_out(wc, x, 0xC5, (threshold & 0xFF)); } dev_info(&wc->dev->dev, "VPM: DTMF threshold set to %d\n", threshold); } static unsigned int t4_vpm_mask(int chip) { unsigned int mask=0; switch(vpmspans) { case 4: mask = 0x55555555 << (chip >> 2); break; case 2: mask = 0x11111111 << (chip >> 1); break; case 1: mask = 0x01010101 << chip; break; } return mask; } static int t4_vpm_spanno(int chip) { int spanno = 0; switch(vpmspans) { case 4: spanno = chip & 0x3; break; case 2: spanno = chip & 0x1; break; /* Case 1 is implicit */ } return spanno; } static int t4_vpm_echotail(void) { int echotail = 0x01ff; switch(vpmspans) { case 4: echotail = 0x007f; break; case 2: echotail = 0x00ff; break; /* Case 1 is implicit */ } return echotail; } static void t4_vpm450_init(struct t4 *wc) { int laws[4] = { 0, }; int x; unsigned int vpm_capacity; struct firmware embedded_firmware; const struct firmware *firmware = &embedded_firmware; #if !defined(HOTPLUG_FIRMWARE) extern void _binary_dahdi_fw_oct6114_064_bin_size; extern void _binary_dahdi_fw_oct6114_128_bin_size; extern u8 _binary_dahdi_fw_oct6114_064_bin_start[]; extern u8 _binary_dahdi_fw_oct6114_128_bin_start[]; #else static const char oct064_firmware[] = "dahdi-fw-oct6114-064.bin"; static const char oct128_firmware[] = "dahdi-fw-oct6114-128.bin"; #endif if (!vpmsupport) { dev_info(&wc->dev->dev, "VPM450: Support Disabled\n"); return; } /* Turn on GPIO/DATA mux if supported */ t4_gpio_setdir(wc, (1 << 24), (1 << 24)); __t4_raw_oct_out(wc, 0x000a, 0x5678); __t4_raw_oct_out(wc, 0x0004, 0x1234); __t4_raw_oct_in(wc, 0x0004); __t4_raw_oct_in(wc, 0x000a); if (debug) dev_notice(&wc->dev->dev, "OCT Result: %04x/%04x\n", __t4_raw_oct_in(wc, 0x0004), __t4_raw_oct_in(wc, 0x000a)); if (__t4_raw_oct_in(wc, 0x0004) != 0x1234) { dev_notice(&wc->dev->dev, "VPM450: Not Present\n"); return; } /* Setup alaw vs ulaw rules */ for (x = 0;x < wc->numspans; x++) { if (wc->tspans[x]->span.channels > 24) laws[x] = 1; } switch ((vpm_capacity = get_vpm450m_capacity(wc))) { case 64: #if defined(HOTPLUG_FIRMWARE) if ((request_firmware(&firmware, oct064_firmware, &wc->dev->dev) != 0) || !firmware) { dev_notice(&wc->dev->dev, "VPM450: firmware %s not " "available from userspace\n", oct064_firmware); return; } #else embedded_firmware.data = _binary_dahdi_fw_oct6114_064_bin_start; /* Yes... this is weird. objcopy gives us a symbol containing the size of the firmware, not a pointer a variable containing the size. The only way we can get the value of the symbol is to take its address, so we define it as a pointer and then cast that value to the proper type. */ embedded_firmware.size = (size_t) &_binary_dahdi_fw_oct6114_064_bin_size; #endif break; case 128: #if defined(HOTPLUG_FIRMWARE) if ((request_firmware(&firmware, oct128_firmware, &wc->dev->dev) != 0) || !firmware) { dev_notice(&wc->dev->dev, "VPM450: firmware %s not " "available from userspace\n", oct128_firmware); return; } #else embedded_firmware.data = _binary_dahdi_fw_oct6114_128_bin_start; /* Yes... this is weird. objcopy gives us a symbol containing the size of the firmware, not a pointer a variable containing the size. The only way we can get the value of the symbol is to take its address, so we define it as a pointer and then cast that value to the proper type. */ embedded_firmware.size = (size_t) &_binary_dahdi_fw_oct6114_128_bin_size; #endif break; default: dev_notice(&wc->dev->dev, "Unsupported channel capacity found " "on VPM module (%d).\n", vpm_capacity); return; } if (!(wc->vpm450m = init_vpm450m(wc, laws, wc->numspans, firmware))) { dev_notice(&wc->dev->dev, "VPM450: Failed to initialize\n"); if (firmware != &embedded_firmware) release_firmware(firmware); return; } if (firmware != &embedded_firmware) release_firmware(firmware); if (vpmdtmfsupport == -1) { dev_notice(&wc->dev->dev, "VPM450: hardware DTMF disabled.\n"); vpmdtmfsupport = 0; } wc->vpm = T4_VPM_PRESENT; dev_info(&wc->dev->dev, "VPM450: Present and operational servicing %d " "span(s)\n", wc->numspans); } static void t4_vpm400_init(struct t4 *wc) { unsigned char reg; unsigned int mask; unsigned int ver; unsigned int i, x, y, gen2vpm=0; if (!vpmsupport) { dev_info(&wc->dev->dev, "VPM400: Support Disabled\n"); return; } switch(vpmspans) { case 4: case 2: case 1: break; default: dev_notice(&wc->dev->dev, "VPM400: %d is not a valid vpmspans " "value, using 4\n", vpmspans); vpmspans = 4; } for (x=0;x<8;x++) { int spanno = t4_vpm_spanno(x); struct t4_span *ts = wc->tspans[spanno]; int echotail = t4_vpm_echotail(); ver = t4_vpm_in(wc, x, 0x1a0); /* revision */ if ((ver != 0x26) && (ver != 0x33)) { if (x) dev_notice(&wc->dev->dev, "VPM400: Inoperable\n"); return; } if (ver == 0x33) { if (x && !gen2vpm) { dev_notice(&wc->dev->dev, "VPM400: Inconsistent\n"); return; } ts->spanflags |= FLAG_VPM2GEN; gen2vpm++; } else if (gen2vpm) { dev_notice(&wc->dev->dev, "VPM400: Inconsistent\n"); return; } /* Setup GPIO's */ for (y=0;y<4;y++) { t4_vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ t4_vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ t4_vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ } /* Setup TDM path - sets fsync and tdm_clk as inputs */ reg = t4_vpm_in(wc, x, 0x1a3); /* misc_con */ t4_vpm_out(wc, x, 0x1a3, reg & ~2); /* Setup timeslots */ t4_vpm_out(wc, x, 0x02f, 0x20 | (spanno << 3)); /* Setup Echo length (128 taps) */ t4_vpm_out(wc, x, 0x022, (echotail >> 8)); t4_vpm_out(wc, x, 0x023, (echotail & 0xff)); /* Setup the tdm channel masks for all chips*/ mask = t4_vpm_mask(x); for (i = 0; i < 4; i++) t4_vpm_out(wc, x, 0x30 + i, (mask >> (i << 3)) & 0xff); /* Setup convergence rate */ reg = t4_vpm_in(wc,x,0x20); reg &= 0xE0; if (ts->spantype == TYPE_E1) { if (x < vpmspans) dev_info(&wc->dev->dev, "VPM400: Span %d " "A-law mode\n", spanno); reg |= 0x01; } else { if (x < vpmspans) dev_info(&wc->dev->dev, "VPM400: Span %d " "U-law mode\n", spanno); reg &= ~0x01; } t4_vpm_out(wc,x,0x20,(reg | 0x20)); /* Initialize echo cans */ for (i = 0 ; i < MAX_TDM_CHAN; i++) { if (mask & (0x00000001 << i)) t4_vpm_out(wc,x,i,0x00); } wait_a_little(); /* Put in bypass mode */ for (i = 0 ; i < MAX_TDM_CHAN ; i++) { if (mask & (0x00000001 << i)) { t4_vpm_out(wc,x,i,0x01); } } /* Enable bypass */ for (i = 0 ; i < MAX_TDM_CHAN ; i++) { if (mask & (0x00000001 << i)) t4_vpm_out(wc,x,0x78 + i,0x01); } /* set DTMF detection threshold */ t4_vpm_set_dtmf_threshold(wc, dtmfthreshold); /* Enable DTMF detectors (always DTMF detect all spans) */ for (i = 0; i < MAX_DTMF_DET; i++) { t4_vpm_out(wc, x, 0x98 + i, 0x40 | (i * 2) | ((x < 4) ? 0 : 1)); } for (i = 0x34; i < 0x38; i++) t4_vpm_out(wc, x, i, 0x00); for (i = 0x3C; i < 0x40; i++) t4_vpm_out(wc, x, i, 0x00); for (i = 0x48; i < 0x4B; i++) t4_vpm_out(wc, x, i, 0x00); for (i = 0x50; i < 0x53; i++) t4_vpm_out(wc, x, i, 0x00); for (i = 0xB8; i < 0xBE; i++) t4_vpm_out(wc, x, i, 0xFF); if (gen2vpm) { for (i = 0xBE; i < 0xC0; i++) t4_vpm_out(wc, x, i, 0xFF); } else { for (i = 0xBE; i < 0xC0; i++) t4_vpm_out(wc, x, i, 0x00); } for (i = 0xC0; i < 0xC4; i++) t4_vpm_out(wc, x, i, (x < 4) ? 0x55 : 0xAA); } if (vpmdtmfsupport == -1) { dev_info(&wc->dev->dev, "VPM400: hardware DTMF enabled.\n"); vpmdtmfsupport = 0; } dev_info(&wc->dev->dev, "VPM400%s: Present and operational servicing " "%d span(s)\n", (gen2vpm ? " (2nd Gen)" : ""), wc->numspans); wc->vpm = T4_VPM_PRESENT; } #endif static void t4_tsi_reset(struct t4 *wc) { int x; for (x=0;x<128;x++) { wc->dmactrl &= ~0x00007fff; wc->dmactrl |= (0x00004000 | (x << 7)); t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); } wc->dmactrl &= ~0x00007fff; t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); } /* Note that channels here start from 1 */ static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan) { unsigned long flags; int fromts, tots; fromts = (fromspan << 5) |(fromchan); tots = (tospan << 5) | (tochan); if (!wc->t1e1) { fromts += 4; tots += 4; } spin_lock_irqsave(&wc->reglock, flags); wc->dmactrl &= ~0x00007fff; wc->dmactrl |= (0x00004000 | (tots << 7) | (fromts)); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); wc->dmactrl &= ~0x00007fff; __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); spin_unlock_irqrestore(&wc->reglock, flags); } static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan) { unsigned long flags; int tots; tots = (tospan << 5) | (tochan); if (!wc->t1e1) tots += 4; spin_lock_irqsave(&wc->reglock, flags); wc->dmactrl &= ~0x00007fff; wc->dmactrl |= (0x00004000 | (tots << 7)); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); if (debug & DEBUG_TSI) dev_notice(&wc->dev->dev, "Sending '%08x\n", wc->dmactrl); wc->dmactrl &= ~0x00007fff; __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); spin_unlock_irqrestore(&wc->reglock, flags); } #ifndef CONFIG_NOEXTENDED_RESET static void t4_extended_reset(struct t4 *wc) { unsigned int oldreg = t4_pci_in(wc, 0x4); udelay(1000); t4_pci_out(wc, 0x4, 0x42000000); t4_pci_out(wc, 0xa, 0x42000000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0xa, 0x00080000); t4_pci_out(wc, 0xa, 0x00180000); t4_pci_out(wc, 0x4, oldreg); udelay(1000); } #endif static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags) { unsigned int version; version = t4_pci_in(wc, WC_VERSION); dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version); dev_info(&wc->dev->dev, "Burst Mode: %s\n", (!(cardflags & FLAG_BURST) && noburst) ? "Off" : "On"); #ifdef ENABLE_WORKQUEUES dev_info(&wc->dev->dev, "Work Queues: Enabled\n"); #endif #if defined(CONFIG_FORCE_EXTENDED_RESET) t4_extended_reset(wc); #elif !defined(CONFIG_NOEXTENDED_RESET) if (wc->flags & FLAG_EXPRESS) t4_extended_reset(wc); #endif /* Make sure DMA engine is not running and interrupts are acknowledged */ wc->dmactrl = 0x0; t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); /* Reset Framer and friends */ t4_pci_out(wc, WC_LEDS, 0x00000000); /* Set DMA addresses */ t4_pci_out(wc, WC_RDADDR, wc->readdma); t4_pci_out(wc, WC_WRADDR, wc->writedma); /* Setup counters, interrupt flags (ignored in Gen2) */ if (cardflags & FLAG_2NDGEN) { t4_tsi_reset(wc); } else { t4_pci_out(wc, WC_COUNT, ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 2)); } /* Reset pending interrupts */ t4_pci_out(wc, WC_INTR, 0x00000000); /* Read T1/E1 status */ if (t1e1override > -1) wc->t1e1 = t1e1override; else wc->t1e1 = ((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8; wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28; order_index[wc->order]++; return 0; } static int t4_hardware_init_2(struct t4 *wc) { int x; unsigned int regval; if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) { wc->tspans[0]->spanflags |= FLAG_OCTOPT; dev_info(&wc->dev->dev, "Octasic Optimizations: Enabled\n"); } /* Setup LEDS, take out of reset */ t4_pci_out(wc, WC_LEDS, 0x000000ff); t4_activate(wc); /* * In order to find out the QFALC framer version, we have to temporarily term off compat * mode and take a peak at VSTR. We turn compat back on when we are done. */ if (t4_framer_in(wc, 0, 0x4a) != 0x05) dev_info(&wc->dev->dev, "WARNING: FALC framer not intialized " "in compatibility mode.\n"); regval = t4_framer_in(wc, 0 ,0xd6); regval |= (1 << 5); /* set COMP_DIS*/ t4_framer_out(wc, 0, 0xd6, regval); regval = t4_framer_in(wc, 0, 0x4a); if (regval == 0x05) dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or " "earlier\n"); else if (regval == 0x20) { dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n"); wc->falc31 = 1; } else dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " "(VSTR = 0x%02x)\n", regval); regval = t4_framer_in(wc, 0 ,0xd6); regval &= ~(1 << 5); /* clear COMP_DIS*/ t4_framer_out(wc, 0, 0xd6, regval); t4_framer_out(wc, 0, 0x4a, 0xaa); dev_info(&wc->dev->dev, "Board ID: %02x\n", wc->order); for (x=0;x< 11;x++) dev_info(&wc->dev->dev, "Reg %d: 0x%08x\n", x, t4_pci_in(wc, x)); return 0; } static int __devinit t4_launch(struct t4 *wc) { int x; unsigned long flags; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) return 0; dev_info(&wc->dev->dev, "TE%dXXP: Launching card: %d\n", wc->numspans, wc->order); /* Setup serial parameters and system interface */ for (x=0;xtspans[0]->span, 0)) { dev_err(&wc->dev->dev, "Unable to register span %s\n", wc->tspans[0]->span.name); return -1; } if (dahdi_register(&wc->tspans[1]->span, 0)) { dev_err(&wc->dev->dev, "Unable to register span %s\n", wc->tspans[1]->span.name); dahdi_unregister(&wc->tspans[0]->span); return -1; } if (wc->numspans == 4) { if (dahdi_register(&wc->tspans[2]->span, 0)) { dev_err(&wc->dev->dev, "Unable to register span %s\n", wc->tspans[2]->span.name); dahdi_unregister(&wc->tspans[0]->span); dahdi_unregister(&wc->tspans[1]->span); return -1; } if (dahdi_register(&wc->tspans[3]->span, 0)) { dev_err(&wc->dev->dev, "Unable to register span %s\n", wc->tspans[3]->span.name); dahdi_unregister(&wc->tspans[0]->span); dahdi_unregister(&wc->tspans[1]->span); dahdi_unregister(&wc->tspans[2]->span); return -1; } } set_bit(T4_CHECK_TIMING, &wc->checkflag); spin_lock_irqsave(&wc->reglock, flags); __t4_set_sclk_src(wc, WC_SELF, 0, 0); spin_unlock_irqrestore(&wc->reglock, flags); tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc); return 0; } static void free_wc(struct t4 *wc) { unsigned int x, y; for (x = 0; x < sizeof(wc->tspans)/sizeof(wc->tspans[0]); x++) { if (!wc->tspans[x]) { continue; } for (y = 0; y < sizeof(wc->tspans[x]->chans)/sizeof(wc->tspans[x]->chans[0]); y++) { if (wc->tspans[x]->chans[y]) { kfree(wc->tspans[x]->chans[y]); } if (wc->tspans[x]->ec[y]) kfree(wc->tspans[x]->ec[y]); } kfree(wc->tspans[x]); } kfree(wc); } /** * wct4xxp_sort_cards - Sort the cards in card array by rotary switch settings. * */ static void wct4xxp_sort_cards(void) { int x; /* get the current number of probed cards and run a slice of a tail * insertion sort */ for (x = 0; x < MAX_T4_CARDS; x++) { if (!cards[x+1]) break; } for ( ; x > 0; x--) { if (cards[x]->order < cards[x-1]->order) { struct t4 *tmp = cards[x]; cards[x] = cards[x-1]; cards[x-1] = tmp; } else { /* if we're not moving it, we won't move any more * since all cards are sorted on addition */ break; } } } static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res; struct t4 *wc; struct devtype *dt; unsigned int x, f; int init_latency; if (pci_enable_device(pdev)) { return -EIO; } if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { return -ENOMEM; } memset(wc, 0x0, sizeof(*wc)); spin_lock_init(&wc->reglock); dt = (struct devtype *) (ent->driver_data); wc->flags = dt->flags; if (wc->flags & FLAG_2PORT) wc->numspans = 2; else wc->numspans = 4; wc->variety = dt->desc; wc->memaddr = pci_resource_start(pdev, 0); wc->memlen = pci_resource_len(pdev, 0); wc->membase = ioremap(wc->memaddr, wc->memlen); /* This rids of the Double missed interrupt message after loading */ wc->last0 = 1; #if 0 if (!request_mem_region(wc->memaddr, wc->memlen, wc->variety)) dev_info(&wc->dev->dev, "wct4: Unable to request memory " "region :(, using anyway...\n"); #endif if (pci_request_regions(pdev, wc->variety)) dev_info(&pdev->dev, "wct%dxxp: Unable to request regions\n", wc->numspans); dev_info(&pdev->dev, "Found TE%dXXP at base address %08lx, remapped " "to %p\n", wc->numspans, wc->memaddr, wc->membase); wc->dev = pdev; /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (wc->flags & FLAG_5THGEN) { if ((ms_per_irq > 1) && (latency <= ((ms_per_irq) << 1))) { init_latency = ms_per_irq << 1; } else { if (latency > 2) init_latency = latency; else init_latency = 2; } dev_info(&wc->dev->dev, "5th gen card with initial latency of " "%d and %d ms per IRQ\n", init_latency, ms_per_irq); } else { if (wc->flags & FLAG_2NDGEN) init_latency = 1; else init_latency = 2; } if (max_latency < init_latency) { printk(KERN_INFO "maxlatency must be set to something greater than %d ms, increasing it to %d\n", init_latency, init_latency); max_latency = init_latency; } if (t4_allocate_buffers(wc, init_latency, NULL, NULL)) { return -ENOMEM; } /* Initialize hardware */ t4_hardware_init_1(wc, wc->flags); for(x = 0; x < MAX_T4_CARDS; x++) { if (!cards[x]) break; } if (x >= MAX_T4_CARDS) { dev_notice(&wc->dev->dev, "No cards[] slot available!!\n"); kfree(wc); return -ENOMEM; } wc->num = x; cards[x] = wc; #ifdef ENABLE_WORKQUEUES if (wc->flags & FLAG_2NDGEN) { char tmp[20]; sprintf(tmp, "te%dxxp[%d]", wc->numspans, wc->num); wc->workq = create_workqueue(tmp); } #endif /* Allocate pieces we need here */ for (x = 0; x < PORTS_PER_FRAMER; x++) { if (!(wc->tspans[x] = kmalloc(sizeof(*wc->tspans[x]), GFP_KERNEL))) { free_wc(wc); return -ENOMEM; } memset(wc->tspans[x], 0, sizeof(*wc->tspans[x])); if (wc->t1e1 & (1 << x)) { wc->tspans[x]->spantype = TYPE_E1; } else { if (j1mode) wc->tspans[x]->spantype = TYPE_J1; else wc->tspans[x]->spantype = TYPE_T1; } for (f = 0; f < (wc->tspans[x]->spantype == TYPE_E1 ? 31 : 24); f++) { if (!(wc->tspans[x]->chans[f] = kmalloc(sizeof(*wc->tspans[x]->chans[f]), GFP_KERNEL))) { free_wc(wc); return -ENOMEM; } memset(wc->tspans[x]->chans[f], 0, sizeof(*wc->tspans[x]->chans[f])); if (!(wc->tspans[x]->ec[f] = kmalloc(sizeof(*wc->tspans[x]->ec[f]), GFP_KERNEL))) { free_wc(wc); return -ENOMEM; } memset(wc->tspans[x]->ec[f], 0, sizeof(*wc->tspans[x]->ec[f])); } #ifdef ENABLE_WORKQUEUES INIT_WORK(&wc->tspans[x]->swork, workq_handlespan, wc->tspans[x]); #endif wc->tspans[x]->spanflags |= wc->flags; } /* Continue hardware intiialization */ t4_hardware_init_2(wc); #ifdef SUPPORT_GEN1 if (request_irq(pdev->irq, (wc->flags & FLAG_2NDGEN) ? t4_interrupt_gen2 : t4_interrupt, DAHDI_IRQ_SHARED_DISABLED, (wc->numspans == 2) ? "wct2xxp" : "wct4xxp", wc)) #else if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) { dev_notice(&wc->dev->dev, "This driver does not " "support 1st gen modules\n"); free_wc(wc); return -ENODEV; } if (request_irq(pdev->irq, t4_interrupt_gen2, DAHDI_IRQ_SHARED_DISABLED, "t4xxp", wc)) #endif { dev_notice(&wc->dev->dev, "t4xxp: Unable to request IRQ %d\n", pdev->irq); free_wc(wc); return -EIO; } init_spans(wc); if (!ignore_rotary) wct4xxp_sort_cards(); dev_info(&wc->dev->dev, "Found a Wildcard: %s\n", wc->variety); wc->gpio = 0x00000000; t4_pci_out(wc, WC_GPIO, wc->gpio); t4_gpio_setdir(wc, (1 << 17), (1 << 17)); t4_gpio_setdir(wc, (0xff), (0xff)); #ifdef VPM_SUPPORT if (!wc->vpm) { wait_a_little(); t4_vpm400_init(wc); if (!wc->vpm) t4_vpm450_init(wc); wc->dmactrl |= wc->vpm; t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); if (wc->vpm) set_span_devicetype(wc); } #endif create_sysfs_files(wc); #if 0 for (x=0;x<0x10000;x++) { __t4_raw_oct_out(wc, 0x0004, x); __t4_raw_oct_out(wc, 0x000a, x ^ 0xffff); if (__t4_raw_oct_in(wc, 0x0004) != x) dev_notice(&wc->dev->dev, "Register 4 failed %04x\n", x); if (__t4_raw_oct_in(wc, 0x000a) != (x ^ 0xffff)) dev_notice(&wc->dev->dev, "Register 10 failed %04x\n", x); } #endif res = 0; if (ignore_rotary) res = t4_launch(wc); return res; } static int t4_hardware_stop(struct t4 *wc) { /* Turn off DMA, leave interrupts enabled */ set_bit(T4_STOP_DMA, &wc->checkflag); /* Wait for interrupts to stop */ msleep(25); /* Turn off counter, address, etc */ if (wc->tspans[0]->spanflags & FLAG_2NDGEN) { t4_tsi_reset(wc); } else { t4_pci_out(wc, WC_COUNT, 0x000000); } t4_pci_out(wc, WC_RDADDR, 0x0000000); t4_pci_out(wc, WC_WRADDR, 0x0000000); wc->gpio = 0x00000000; t4_pci_out(wc, WC_GPIO, wc->gpio); t4_pci_out(wc, WC_LEDS, 0x00000000); if (debug) { dev_notice(&wc->dev->dev, "Stopped TE%dXXP, Turned off DMA\n", wc->numspans); } return 0; } static void _t4_remove_one(struct t4 *wc) { struct dahdi_span *span; int basesize; int i; remove_sysfs_files(wc); /* Stop hardware */ t4_hardware_stop(wc); #ifdef VPM_SUPPORT /* Release vpm450m */ if (wc->vpm450m) release_vpm450m(wc->vpm450m); wc->vpm450m = NULL; #endif /* Unregister spans */ basesize = DAHDI_MAX_CHUNKSIZE * 32 * 4; if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) basesize = basesize * 2; for (i = 0; i < wc->numspans; ++i) { span = &wc->tspans[i]->span; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) dahdi_unregister(span); } #ifdef ENABLE_WORKQUEUES if (wc->workq) { flush_workqueue(wc->workq); destroy_workqueue(wc->workq); } #endif free_irq(wc->dev->irq, wc); if (wc->membase) iounmap(wc->membase); pci_release_regions(wc->dev); /* Immediately free resources */ pci_free_consistent(wc->dev, T4_BASE_SIZE * wc->numbufs * 2, wc->writechunk, wc->writedma); order_index[wc->order]--; cards[wc->num] = NULL; pci_set_drvdata(wc->dev, NULL); free_wc(wc); } static void __devexit t4_remove_one(struct pci_dev *pdev) { struct t4 *wc = pci_get_drvdata(pdev); if (!wc) return; _t4_remove_one(wc); } static DEFINE_PCI_DEVICE_TABLE(t4_pci_tbl) = { { 0x10ee, 0x0314, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp }, { 0xd161, 0x1420, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct420p5 }, { 0xd161, 0x1410, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p5 }, { 0xd161, 0x1405, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p5 }, { 0xd161, 0x0420, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct420p4 }, { 0xd161, 0x0410, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p4 }, { 0xd161, 0x0405, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p4 }, { 0xd161, 0x0410, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p3 }, { 0xd161, 0x0405, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p3 }, { 0xd161, 0x0410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p2 }, { 0xd161, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p2 }, { 0xd161, 0x1220, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct220p5 }, { 0xd161, 0x1205, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p5 }, { 0xd161, 0x1210, 0x0005, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p5 }, { 0xd161, 0x0220, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct220p4 }, { 0xd161, 0x0205, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p4 }, { 0xd161, 0x0210, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p4 }, { 0xd161, 0x0205, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p3 }, { 0xd161, 0x0210, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p3 }, { 0xd161, 0x0205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct205 }, { 0xd161, 0x0210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct210 }, { 0, } }; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) static void _t4_shutdown(struct pci_dev *pdev) { struct t4 *wc = pci_get_drvdata(pdev); t4_hardware_stop(wc); } #endif static int t4_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } static struct pci_driver t4_driver = { .name = "wct4xxp", .probe = t4_init_one, .remove = __devexit_p(t4_remove_one), #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) .shutdown = _t4_shutdown, #endif .suspend = t4_suspend, .id_table = t4_pci_tbl, }; static int __init t4_init(void) { int i; int res; res = dahdi_pci_module(&t4_driver); if (res) return -ENODEV; /* initialize cards since we have all of them */ /* warn for missing zero and duplicate numbers */ if (cards[0] && cards[0]->order != 0) { printk(KERN_NOTICE "wct4xxp: Ident of first card is not zero (%d)\n", cards[0]->order); } /* If we're ignoring the rotary switch settings, then we've already * registered in the context of .probe */ if (!ignore_rotary) { for (i = 0; cards[i]; i++) { /* warn the user of duplicate ident values it is * probably unintended */ if (debug && res < 15 && cards[i+1] && cards[res]->order == cards[i+1]->order) { printk(KERN_NOTICE "wct4xxp: Duplicate ident " "value found (%d)\n", cards[i]->order); } res = t4_launch(cards[i]); if (res) { int j; for (j = 0; j < i; ++j) _t4_remove_one(cards[j]); break; } } } return res; } static void __exit t4_cleanup(void) { pci_unregister_driver(&t4_driver); } MODULE_AUTHOR("Digium Incorporated "); MODULE_DESCRIPTION("Wildcard Dual-/Quad-port Digital Card Driver"); MODULE_ALIAS("wct2xxp"); MODULE_LICENSE("GPL v2"); module_param(pedanticpci, int, 0600); module_param(debug, int, 0600); module_param(noburst, int, 0600); module_param(timingcable, int, 0600); module_param(t1e1override, int, 0600); module_param(alarmdebounce, int, 0600); module_param(losalarmdebounce, int, 0600); module_param(aisalarmdebounce, int, 0600); module_param(yelalarmdebounce, int, 0600); module_param(max_latency, int, 0600); module_param(j1mode, int, 0600); module_param(sigmode, int, 0600); module_param(latency, int, 0600); module_param(ms_per_irq, int, 0600); module_param(ignore_rotary, int, 0400); MODULE_PARM_DESC(ignore_rotary, "Set to > 0 to ignore the rotary switch when " \ "registering with DAHDI."); #ifdef VPM_SUPPORT module_param(vpmsupport, int, 0600); module_param(vpmdtmfsupport, int, 0600); module_param(vpmspans, int, 0600); module_param(dtmfthreshold, int, 0600); #endif MODULE_DEVICE_TABLE(pci, t4_pci_tbl); module_init(t4_init); module_exit(t4_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/wct4xxp/vpm450m.h0000644000175000017500000000250511046336665021554 0ustar tzafrirtzafrir/* * Copyright (C) 2005-2006 Digium, Inc. * * Mark Spencer * * All Rights Reserved * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _VPM450M_H #define _VPM450M_H #include struct vpm450m; /* From driver */ unsigned int oct_get_reg(void *data, unsigned int reg); void oct_set_reg(void *data, unsigned int reg, unsigned int val); /* From vpm450m */ struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware); unsigned int get_vpm450m_capacity(void *wc); void vpm450m_setec(struct vpm450m *instance, int channel, int eclen); void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int dtmfmute); int vpm450m_checkirq(struct vpm450m *vpm450m); int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start); void release_vpm450m(struct vpm450m *instance); #endif dahdi-linux-2.5.0.1/drivers/dahdi/wct4xxp/vpm450m.c0000644000175000017500000003773211571765744021570 0ustar tzafrirtzafrir/* * Copyright (C) 2005-2006 Digium, Inc. * * Mark Spencer * * All Rights Reserved */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include "vpm450m.h" #include "oct6100api/oct6100_api.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #include #endif /* API for Octasic access */ UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime) { /* Why couldn't they just take a timeval like everyone else? */ struct timeval tv; unsigned long long total_usecs; unsigned int mask = ~0; do_gettimeofday(&tv); total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) + (((unsigned long long)(tv.tv_usec))); f_pTime->aulWallTimeUs[0] = (total_usecs & mask); f_pTime->aulWallTimeUs[1] = (total_usecs >> 32); return cOCT6100_ERR_OK; } UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength) { memset(f_pAddress, f_ulPattern, f_ulLength); return cOCT6100_ERR_OK; } UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength) { memcpy(f_pDestination, f_pSource, f_ulLength); return cOCT6100_ERR_OK; } UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate) { return cOCT6100_ERR_OK; } UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy) { #ifdef OCTASIC_DEBUG printk(KERN_DEBUG "I should never be called! (destroy serialize object)\n"); #endif return cOCT6100_ERR_OK; } UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize) { /* Not needed */ return cOCT6100_ERR_OK; } UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease) { /* Not needed */ return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams) { oct_set_reg(f_pWriteParams->pProcessContext, f_pWriteParams->ulWriteAddress, f_pWriteParams->usWriteData); return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams) { unsigned int x; for (x=0;xulWriteLength;x++) { oct_set_reg(f_pSmearParams->pProcessContext, f_pSmearParams->ulWriteAddress + (x << 1), f_pSmearParams->usWriteData); } return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams) { unsigned int x; for (x=0;xulWriteLength;x++) { oct_set_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulWriteAddress + (x << 1), f_pBurstParams->pusWriteData[x]); } return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams) { *(f_pReadParams->pusReadData) = oct_get_reg(f_pReadParams->pProcessContext, f_pReadParams->ulReadAddress); return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams) { unsigned int x; for (x=0;xulReadLength;x++) { f_pBurstParams->pusReadData[x] = oct_get_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulReadAddress + (x << 1)); } return cOCT6100_ERR_OK; } #define SOUT_G168_1100GB_ON 0x40000004 #define SOUT_DTMF_1 0x40000011 #define SOUT_DTMF_2 0x40000012 #define SOUT_DTMF_3 0x40000013 #define SOUT_DTMF_A 0x4000001A #define SOUT_DTMF_4 0x40000014 #define SOUT_DTMF_5 0x40000015 #define SOUT_DTMF_6 0x40000016 #define SOUT_DTMF_B 0x4000001B #define SOUT_DTMF_7 0x40000017 #define SOUT_DTMF_8 0x40000018 #define SOUT_DTMF_9 0x40000019 #define SOUT_DTMF_C 0x4000001C #define SOUT_DTMF_STAR 0x4000001E #define SOUT_DTMF_0 0x40000010 #define SOUT_DTMF_POUND 0x4000001F #define SOUT_DTMF_D 0x4000001D #define ROUT_G168_2100GB_ON 0x10000000 #define ROUT_G168_2100GB_WSPR 0x10000002 #define ROUT_SOUT_G168_2100HB_END 0x50000003 #define ROUT_G168_1100GB_ON 0x10000004 #define ROUT_DTMF_1 0x10000011 #define ROUT_DTMF_2 0x10000012 #define ROUT_DTMF_3 0x10000013 #define ROUT_DTMF_A 0x1000001A #define ROUT_DTMF_4 0x10000014 #define ROUT_DTMF_5 0x10000015 #define ROUT_DTMF_6 0x10000016 #define ROUT_DTMF_B 0x1000001B #define ROUT_DTMF_7 0x10000017 #define ROUT_DTMF_8 0x10000018 #define ROUT_DTMF_9 0x10000019 #define ROUT_DTMF_C 0x1000001C #define ROUT_DTMF_STAR 0x1000001E #define ROUT_DTMF_0 0x10000010 #define ROUT_DTMF_POUND 0x1000001F #define ROUT_DTMF_D 0x1000001D #if 0 #define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_HT_FREEZE #else #define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_POWER_DOWN #endif struct vpm450m { tPOCT6100_INSTANCE_API pApiInstance; UINT32 aulEchoChanHndl[128]; int chanflags[128]; int ecmode[128]; int numchans; }; #define FLAG_DTMF (1 << 0) #define FLAG_MUTE (1 << 1) #define FLAG_ECHO (1 << 2) static unsigned int tones[] = { SOUT_DTMF_1, SOUT_DTMF_2, SOUT_DTMF_3, SOUT_DTMF_A, SOUT_DTMF_4, SOUT_DTMF_5, SOUT_DTMF_6, SOUT_DTMF_B, SOUT_DTMF_7, SOUT_DTMF_8, SOUT_DTMF_9, SOUT_DTMF_C, SOUT_DTMF_STAR, SOUT_DTMF_0, SOUT_DTMF_POUND, SOUT_DTMF_D, SOUT_G168_1100GB_ON, ROUT_DTMF_1, ROUT_DTMF_2, ROUT_DTMF_3, ROUT_DTMF_A, ROUT_DTMF_4, ROUT_DTMF_5, ROUT_DTMF_6, ROUT_DTMF_B, ROUT_DTMF_7, ROUT_DTMF_8, ROUT_DTMF_9, ROUT_DTMF_C, ROUT_DTMF_STAR, ROUT_DTMF_0, ROUT_DTMF_POUND, ROUT_DTMF_D, ROUT_G168_1100GB_ON, }; static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode) { tOCT6100_CHANNEL_MODIFY *modify; UINT32 ulResult; if (vpm450m->ecmode[channel] == mode) return; modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); if (!modify) { printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setec!\n"); return; } Oct6100ChannelModifyDef(modify); modify->ulEchoOperationMode = mode; modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel]; ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify); if (ulResult != GENERIC_OK) { printk(KERN_NOTICE "Failed to apply echo can changes on channel %d %08x!\n", channel, ulResult); } else { #ifdef OCTASIC_DEBUG printk(KERN_DEBUG "Echo can on channel %d set to %d\n", channel, mode); #endif vpm450m->ecmode[channel] = mode; } kfree(modify); } void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute) { tOCT6100_CHANNEL_MODIFY *modify; UINT32 ulResult; modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL); if (!modify) { printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n"); return; } Oct6100ChannelModifyDef(modify); modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel]; if (mute) { vpm450m->chanflags[channel] |= FLAG_MUTE; modify->VqeConfig.fDtmfToneRemoval = TRUE; } else { vpm450m->chanflags[channel] &= ~FLAG_MUTE; modify->VqeConfig.fDtmfToneRemoval = FALSE; } if (detect) vpm450m->chanflags[channel] |= FLAG_DTMF; else vpm450m->chanflags[channel] &= ~FLAG_DTMF; if (vpm450m->chanflags[channel] & (FLAG_DTMF|FLAG_MUTE)) { if (!(vpm450m->chanflags[channel] & FLAG_ECHO)) { vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE); } } else { if (!(vpm450m->chanflags[channel] & FLAG_ECHO)) vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL); } ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify); if (ulResult != GENERIC_OK) { printk(KERN_NOTICE "Failed to apply dtmf mute changes on channel %d!\n", channel); } /* printk(KERN_DEBUG "VPM450m: Setting DTMF on channel %d: %s / %s\n", channel, (detect ? "DETECT" : "NO DETECT"), (mute ? "MUTE" : "NO MUTE")); */ kfree(modify); } void vpm450m_setec(struct vpm450m *vpm450m, int channel, int eclen) { if (eclen) { vpm450m->chanflags[channel] |= FLAG_ECHO; vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_NORMAL); } else { vpm450m->chanflags[channel] &= ~FLAG_ECHO; if (vpm450m->chanflags[channel] & (FLAG_DTMF | FLAG_MUTE)) { vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE); } else vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL); } /* printk(KERN_DEBUG "VPM450m: Setting EC on channel %d to %d\n", channel, eclen); */ } int vpm450m_checkirq(struct vpm450m *vpm450m) { tOCT6100_INTERRUPT_FLAGS InterruptFlags; Oct6100InterruptServiceRoutineDef(&InterruptFlags); Oct6100InterruptServiceRoutine(vpm450m->pApiInstance, &InterruptFlags); return InterruptFlags.fToneEventsPending ? 1 : 0; } int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start) { tOCT6100_TONE_EVENT tonefound; tOCT6100_EVENT_GET_TONE tonesearch; Oct6100EventGetToneDef(&tonesearch); tonesearch.pToneEvent = &tonefound; tonesearch.ulMaxToneEvent = 1; Oct6100EventGetTone(vpm450m->pApiInstance, &tonesearch); if (tonesearch.ulNumValidToneEvent) { if (channel) *channel = tonefound.ulUserChanId; if (tone) { switch(tonefound.ulToneDetected) { case SOUT_DTMF_1: *tone = '1'; break; case SOUT_DTMF_2: *tone = '2'; break; case SOUT_DTMF_3: *tone = '3'; break; case SOUT_DTMF_A: *tone = 'A'; break; case SOUT_DTMF_4: *tone = '4'; break; case SOUT_DTMF_5: *tone = '5'; break; case SOUT_DTMF_6: *tone = '6'; break; case SOUT_DTMF_B: *tone = 'B'; break; case SOUT_DTMF_7: *tone = '7'; break; case SOUT_DTMF_8: *tone = '8'; break; case SOUT_DTMF_9: *tone = '9'; break; case SOUT_DTMF_C: *tone = 'C'; break; case SOUT_DTMF_STAR: *tone = '*'; break; case SOUT_DTMF_0: *tone = '0'; break; case SOUT_DTMF_POUND: *tone = '#'; break; case SOUT_DTMF_D: *tone = 'D'; break; case SOUT_G168_1100GB_ON: *tone = 'f'; break; default: #ifdef OCTASIC_DEBUG printk(KERN_DEBUG "Unknown tone value %08x\n", tonefound.ulToneDetected); #endif *tone = 'u'; break; } } if (start) *start = (tonefound.ulEventType == cOCT6100_TONE_PRESENT); return 1; } return 0; } unsigned int get_vpm450m_capacity(void *wc) { UINT32 ulResult; tOCT6100_API_GET_CAPACITY_PINS CapacityPins; Oct6100ApiGetCapacityPinsDef(&CapacityPins); CapacityPins.pProcessContext = wc; CapacityPins.ulMemoryType = cOCT6100_MEM_TYPE_DDR; CapacityPins.fEnableMemClkOut = TRUE; CapacityPins.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ; ulResult = Oct6100ApiGetCapacityPins(&CapacityPins); if (ulResult != cOCT6100_ERR_OK) { printk(KERN_DEBUG "Failed to get chip capacity, code %08x!\n", ulResult); return 0; } return CapacityPins.ulCapacityValue; } struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware) { tOCT6100_CHIP_OPEN *ChipOpen; tOCT6100_GET_INSTANCE_SIZE InstanceSize; tOCT6100_CHANNEL_OPEN *ChannelOpen; UINT32 ulResult; struct vpm450m *vpm450m; int x,y,law; if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL))) return NULL; memset(vpm450m, 0, sizeof(struct vpm450m)); if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) { kfree(vpm450m); return NULL; } memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN)); if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) { kfree(vpm450m); kfree(ChipOpen); return NULL; } memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN)); for (x = 0; x < ARRAY_SIZE(vpm450m->ecmode); x++) vpm450m->ecmode[x] = -1; vpm450m->numchans = numspans * 32; printk(KERN_INFO "VPM450: echo cancellation for %d channels\n", vpm450m->numchans); Oct6100ChipOpenDef(ChipOpen); /* Setup Chip Open Parameters */ ChipOpen->ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ; Oct6100GetInstanceSizeDef(&InstanceSize); ChipOpen->pProcessContext = wc; ChipOpen->pbyImageFile = firmware->data; ChipOpen->ulImageSize = firmware->size; ChipOpen->fEnableMemClkOut = TRUE; ChipOpen->ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ; ChipOpen->ulMaxChannels = vpm450m->numchans; ChipOpen->ulMemoryType = cOCT6100_MEM_TYPE_DDR; ChipOpen->ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_32MB; ChipOpen->ulNumMemoryChips = 1; ChipOpen->ulMaxTdmStreams = 4; ChipOpen->aulTdmStreamFreqs[0] = cOCT6100_TDM_STREAM_FREQ_8MHZ; ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE; ChipOpen->ulMaxFlexibleConfParticipants = 0; ChipOpen->ulMaxConfBridges = 0; ChipOpen->ulMaxRemoteDebugSessions = 0; ChipOpen->fEnableChannelRecording = FALSE; ChipOpen->ulSoftToneEventsBufSize = 64; #if 0 ChipOpen->fEnableAcousticEcho = TRUE; #endif ulResult = Oct6100GetInstanceSize(ChipOpen, &InstanceSize); if (ulResult != cOCT6100_ERR_OK) { printk(KERN_NOTICE "Failed to get instance size, code %08x!\n", ulResult); kfree(vpm450m); kfree(ChipOpen); kfree(ChannelOpen); return NULL; } vpm450m->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize); if (!vpm450m->pApiInstance) { printk(KERN_NOTICE "Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize); kfree(vpm450m); kfree(ChipOpen); kfree(ChannelOpen); return NULL; } ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen); if (ulResult != cOCT6100_ERR_OK) { printk(KERN_NOTICE "Failed to open chip, code %08x!\n", ulResult); vfree(vpm450m->pApiInstance); kfree(vpm450m); kfree(ChipOpen); kfree(ChannelOpen); return NULL; } for (x = 0; x < ARRAY_SIZE(vpm450m->aulEchoChanHndl); x++) { /* execute this loop always on 4 span cards but * on 2 span cards only execute for the channels related to our spans */ if (( numspans > 2) || ((x & 0x03) <2)) { /* span timeslots are interleaved 12341234... * therefore, the lower 2 bits tell us which span this * timeslot/channel */ if (isalaw[x & 0x03]) law = cOCT6100_PCM_A_LAW; else law = cOCT6100_PCM_U_LAW; Oct6100ChannelOpenDef(ChannelOpen); ChannelOpen->pulChannelHndl = &vpm450m->aulEchoChanHndl[x]; ChannelOpen->ulUserChanId = x; ChannelOpen->TdmConfig.ulRinPcmLaw = law; ChannelOpen->TdmConfig.ulRinStream = 0; ChannelOpen->TdmConfig.ulRinTimeslot = x; ChannelOpen->TdmConfig.ulSinPcmLaw = law; ChannelOpen->TdmConfig.ulSinStream = 1; ChannelOpen->TdmConfig.ulSinTimeslot = x; ChannelOpen->TdmConfig.ulSoutPcmLaw = law; ChannelOpen->TdmConfig.ulSoutStream = 2; ChannelOpen->TdmConfig.ulSoutTimeslot = x; ChannelOpen->TdmConfig.ulRoutPcmLaw = law; ChannelOpen->TdmConfig.ulRoutStream = 3; ChannelOpen->TdmConfig.ulRoutTimeslot = x; ChannelOpen->VqeConfig.fEnableNlp = TRUE; ChannelOpen->VqeConfig.fRinDcOffsetRemoval = TRUE; ChannelOpen->VqeConfig.fSinDcOffsetRemoval = TRUE; ChannelOpen->fEnableToneDisabler = TRUE; ChannelOpen->ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_DIGITAL; ulResult = Oct6100ChannelOpen(vpm450m->pApiInstance, ChannelOpen); if (ulResult != GENERIC_OK) { printk(KERN_NOTICE "Failed to open channel %d!\n", x); continue; } for (y = 0; y < ARRAY_SIZE(tones); y++) { tOCT6100_TONE_DETECTION_ENABLE enable; Oct6100ToneDetectionEnableDef(&enable); enable.ulChannelHndl = vpm450m->aulEchoChanHndl[x]; enable.ulToneNumber = tones[y]; if (Oct6100ToneDetectionEnable(vpm450m->pApiInstance, &enable) != GENERIC_OK) printk(KERN_NOTICE "Failed to enable tone detection on channel %d for tone %d!\n", x, y); } } } kfree(ChipOpen); kfree(ChannelOpen); return vpm450m; } void release_vpm450m(struct vpm450m *vpm450m) { UINT32 ulResult; tOCT6100_CHIP_CLOSE ChipClose; Oct6100ChipCloseDef(&ChipClose); ulResult = Oct6100ChipClose(vpm450m->pApiInstance, &ChipClose); if (ulResult != cOCT6100_ERR_OK) { printk(KERN_NOTICE "Failed to close chip, code %08x!\n", ulResult); } vfree(vpm450m->pApiInstance); kfree(vpm450m); } dahdi-linux-2.5.0.1/drivers/dahdi/wct4xxp/wct4xxp-diag.c0000644000175000017500000002162711253530516022657 0ustar tzafrirtzafrir/* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include "wct4xxp.h" struct t4_reg_def { int reg; char *name; int global; }; static struct t4_reg_def xreginfo[] = { { 0x00, "RDADDR" }, { 0x01, "WRADDR" }, { 0x02, "COUNT" }, { 0x03, "DMACTRL" }, { 0x04, "WCINTR" }, { 0x06, "VERSION" }, { 0x07, "LEDS" }, { 0x08, "GPIOCTL" }, { 0x09, "GPIO" }, { 0x0A, "LADDR" }, { 0x0b, "LDATA" }, }; static struct t4_reg_def reginfo[] = { { 0x00, "XFIFO" }, { 0x01, "XFIFO" }, { 0x02, "CMDR" }, { 0x03, "MODE" }, { 0x04, "RAH1" }, { 0x05, "RAH2" }, { 0x06, "RAL1" }, { 0x07, "RAL2" }, { 0x08, "IPC", 1 }, { 0x09, "CCR1" }, { 0x0a, "CCR2" }, { 0x0c, "RTR1" }, { 0x0d, "RTR2" }, { 0x0e, "RTR3" }, { 0x0f, "RTR4" }, { 0x10, "TTR1" }, { 0x11, "TTR2" }, { 0x12, "TTR3" }, { 0x13, "TTR4" }, { 0x14, "IMR0" }, { 0x15, "IMR1" }, { 0x16, "IMR2" }, { 0x17, "IMR3" }, { 0x18, "IMR4" }, { 0x1b, "IERR" }, { 0x1c, "FMR0" }, { 0x1d, "FMR1" }, { 0x1e, "FMR2" }, { 0x1f, "LOOP" }, { 0x20, "XSW" }, { 0x21, "XSP" }, { 0x22, "XC0" }, { 0x23, "XC1" }, { 0x24, "RC0" }, { 0x25, "RC1" }, { 0x26, "XPM0" }, { 0x27, "XPM1" }, { 0x28, "XPM2" }, { 0x29, "TSWM" }, { 0x2b, "IDLE" }, { 0x2c, "XSA4" }, { 0x2d, "XSA5" }, { 0x2e, "XSA6" }, { 0x2f, "XSA7" }, { 0x30, "XSA8" }, { 0x31, "FMR3" }, { 0x32, "ICB1" }, { 0x33, "ICB2" }, { 0x34, "ICB3" }, { 0x35, "ICB4" }, { 0x36, "LIM0" }, { 0x37, "LIM1" }, { 0x38, "PCD" }, { 0x39, "PCR" }, { 0x3a, "LIM2" }, { 0x3b, "LCR1" }, { 0x3c, "LCR2" }, { 0x3d, "LCR3" }, { 0x3e, "SIC1" }, { 0x3f, "SIC2" }, { 0x40, "SIC3" }, { 0x44, "CMR1" }, { 0x45, "CMR2" }, { 0x46, "GCR" }, { 0x47, "ESM" }, { 0x60, "DEC" }, { 0x70, "XS1" }, { 0x71, "XS2" }, { 0x72, "XS3" }, { 0x73, "XS4" }, { 0x74, "XS5" }, { 0x75, "XS6" }, { 0x76, "XS7" }, { 0x77, "XS8" }, { 0x78, "XS9" }, { 0x79, "XS10" }, { 0x7a, "XS11" }, { 0x7b, "XS12" }, { 0x7c, "XS13" }, { 0x7d, "XS14" }, { 0x7e, "XS15" }, { 0x7f, "XS16" }, { 0x80, "PC1" }, { 0x81, "PC2" }, { 0x82, "PC3" }, { 0x83, "PC4" }, { 0x84, "PC5" }, { 0x85, "GPC1", 1 }, { 0x87, "CMDR2" }, { 0x8d, "CCR5" }, { 0x92, "GCM1", 1 }, { 0x93, "GCM2", 1 }, { 0x94, "GCM3", 1 }, { 0x95, "GCM4", 1 }, { 0x96, "GCM5", 1 }, { 0x97, "GCM6", 1 }, { 0x98, "GCM7", 1 }, { 0x99, "GCM8", 1 }, { 0xa0, "TSEO" }, { 0xa1, "TSBS1" }, { 0xa8, "TPC0" }, }; static struct t4_reg_def t1_reginfo[] = { { 0x00, "XFIFO" }, { 0x01, "XFIFO" }, { 0x02, "CMDR" }, { 0x03, "MODE" }, { 0x04, "RAH1" }, { 0x05, "RAH2" }, { 0x06, "RAL1" }, { 0x07, "RAL2" }, { 0x08, "IPC", 1 }, { 0x09, "CCR1" }, { 0x0a, "CCR2" }, { 0x0c, "RTR1" }, { 0x0d, "RTR2" }, { 0x0e, "RTR3" }, { 0x0f, "RTR4" }, { 0x10, "TTR1" }, { 0x11, "TTR2" }, { 0x12, "TTR3" }, { 0x13, "TTR4" }, { 0x14, "IMR0" }, { 0x15, "IMR1" }, { 0x16, "IMR2" }, { 0x17, "IMR3" }, { 0x18, "IMR4" }, { 0x1b, "IERR" }, { 0x1c, "FMR0" }, { 0x1d, "FMR1" }, { 0x1e, "FMR2" }, { 0x1f, "LOOP" }, { 0x20, "FMR4" }, { 0x21, "FMR5" }, { 0x22, "XC0" }, { 0x23, "XC1" }, { 0x24, "RC0" }, { 0x25, "RC1" }, { 0x26, "XPM0" }, { 0x27, "XPM1" }, { 0x28, "XPM2" }, { 0x2b, "IDLE" }, { 0x2c, "XDL1" }, { 0x2d, "XDL2" }, { 0x2e, "XDL3" }, { 0x2f, "CCB1" }, { 0x30, "CCB2" }, { 0x31, "CCB3" }, { 0x32, "ICB1" }, { 0x33, "ICB2" }, { 0x34, "ICB3" }, { 0x36, "LIM0" }, { 0x37, "LIM1" }, { 0x38, "PCD" }, { 0x39, "PCR" }, { 0x3a, "LIM2" }, { 0x3b, "LCR1" }, { 0x3c, "LCR2" }, { 0x3d, "LCR3" }, { 0x3e, "SIC1" }, { 0x3f, "SIC2" }, { 0x40, "SIC3" }, { 0x44, "CMR1" }, { 0x45, "CMR2" }, { 0x46, "GCR" }, { 0x47, "ESM" }, { 0x60, "DEC" }, { 0x70, "XS1" }, { 0x71, "XS2" }, { 0x72, "XS3" }, { 0x73, "XS4" }, { 0x74, "XS5" }, { 0x75, "XS6" }, { 0x76, "XS7" }, { 0x77, "XS8" }, { 0x78, "XS9" }, { 0x79, "XS10" }, { 0x7a, "XS11" }, { 0x7b, "XS12" }, { 0x80, "PC1" }, { 0x81, "PC2" }, { 0x82, "PC3" }, { 0x83, "PC4" }, { 0x84, "PC5" }, { 0x85, "GPC1", 1 }, { 0x87, "CMDR2" }, { 0x8d, "CCR5" }, { 0x92, "GCM1", 1 }, { 0x93, "GCM2", 1 }, { 0x94, "GCM3", 1 }, { 0x95, "GCM4", 1 }, { 0x96, "GCM5", 1 }, { 0x97, "GCM6", 1 }, { 0x98, "GCM7", 1 }, { 0x99, "GCM8", 1 }, { 0xa0, "TSEO" }, { 0xa1, "TSBS1" }, { 0xa8, "TPC0" }, }; static struct t4_reg_def t1_sreginfo[] = { { 0x00, "RFIFO" }, { 0x01, "RFIFO" }, { 0x49, "RBD" }, { 0x4a, "VSTR", 1 }, { 0x4b, "RES" }, { 0x4c, "FRS0" }, { 0x4d, "FRS1" }, { 0x4e, "FRS2" }, { 0x4f, "Old FRS1" }, { 0x50, "FECL" }, { 0x51, "FECH" }, { 0x52, "CVCL" }, { 0x53, "CVCH" }, { 0x54, "CECL" }, { 0x55, "CECH" }, { 0x56, "EBCL" }, { 0x57, "EBCH" }, { 0x58, "BECL" }, { 0x59, "BECH" }, { 0x5a, "COEC" }, { 0x5c, "RDL1" }, { 0x5d, "RDL2" }, { 0x5e, "RDL3" }, { 0x62, "RSP1" }, { 0x63, "RSP2" }, { 0x64, "SIS" }, { 0x65, "RSIS" }, { 0x66, "RBCL" }, { 0x67, "RBCH" }, { 0x68, "ISR0" }, { 0x69, "ISR1" }, { 0x6a, "ISR2" }, { 0x6b, "ISR3" }, { 0x6c, "ISR4" }, { 0x6e, "GIS" }, { 0x6f, "CIS", 1 }, { 0x70, "RS1" }, { 0x71, "RS2" }, { 0x72, "RS3" }, { 0x73, "RS4" }, { 0x74, "RS5" }, { 0x75, "RS6" }, { 0x76, "RS7" }, { 0x77, "RS8" }, { 0x78, "RS9" }, { 0x79, "RS10" }, { 0x7a, "RS11" }, { 0x7b, "RS12" }, }; static struct t4_reg_def sreginfo[] = { { 0x00, "RFIFO" }, { 0x01, "RFIFO" }, { 0x49, "RBD" }, { 0x4a, "VSTR", 1 }, { 0x4b, "RES" }, { 0x4c, "FRS0" }, { 0x4d, "FRS1" }, { 0x4e, "RSW" }, { 0x4f, "RSP" }, { 0x50, "FECL" }, { 0x51, "FECH" }, { 0x52, "CVCL" }, { 0x53, "CVCH" }, { 0x54, "CEC1L" }, { 0x55, "CEC1H" }, { 0x56, "EBCL" }, { 0x57, "EBCH" }, { 0x58, "CEC2L" }, { 0x59, "CEC2H" }, { 0x5a, "CEC3L" }, { 0x5b, "CEC3H" }, { 0x5c, "RSA4" }, { 0x5d, "RSA5" }, { 0x5e, "RSA6" }, { 0x5f, "RSA7" }, { 0x60, "RSA8" }, { 0x61, "RSA6S" }, { 0x62, "RSP1" }, { 0x63, "RSP2" }, { 0x64, "SIS" }, { 0x65, "RSIS" }, { 0x66, "RBCL" }, { 0x67, "RBCH" }, { 0x68, "ISR0" }, { 0x69, "ISR1" }, { 0x6a, "ISR2" }, { 0x6b, "ISR3" }, { 0x6c, "ISR4" }, { 0x6e, "GIS" }, { 0x6f, "CIS", 1 }, { 0x70, "RS1" }, { 0x71, "RS2" }, { 0x72, "RS3" }, { 0x73, "RS4" }, { 0x74, "RS5" }, { 0x75, "RS6" }, { 0x76, "RS7" }, { 0x77, "RS8" }, { 0x78, "RS9" }, { 0x79, "RS10" }, { 0x7a, "RS11" }, { 0x7b, "RS12" }, { 0x7c, "RS13" }, { 0x7d, "RS14" }, { 0x7e, "RS15" }, { 0x7f, "RS16" }, }; static char *tobin(int x) { static char s[9] = ""; int y,z=0; for (y=7;y>=0;y--) { if (x & (1 << y)) s[z++] = '1'; else s[z++] = '0'; } s[z] = '\0'; return s; } static char *tobin32(unsigned int x) { static char s[33] = ""; int y,z=0; for (y=31;y>=0;y--) { if (x & (1 << y)) s[z++] = '1'; else s[z++] = '0'; } s[z] = '\0'; return s; } int main(int argc, char *argv[]) { int fd; int x; char fn[256]; struct t4_regs regs; if ((argc < 2) || ((*(argv[1]) != '/') && !atoi(argv[1]))) { fprintf(stderr, "Usage: wct4xxp-diag \n"); exit(1); } if (*(argv[1]) == '/') dahdi_copy_string(fn, argv[1], sizeof(fn)); else snprintf(fn, sizeof(fn), "/dev/dahdi/%d", atoi(argv[1])); fd = open(fn, O_RDWR); if (fd <0) { fprintf(stderr, "Unable to open '%s': %s\n", fn, strerror(errno)); exit(1); } if (ioctl(fd, WCT4_GET_REGS, ®s)) { fprintf(stderr, "Unable to get registers: %s\n", strerror(errno)); exit(1); } printf("PCI Registers:\n"); for (x=0;x * * Copyright (C) 2001-2010, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #define FRMR_TTR_BASE 0x10 #define FRMR_RTR_BASE 0x0c #define FRMR_TSEO 0xa0 #define FRMR_TSBS1 0xa1 #define FRMR_CCR1 0x09 #define FRMR_CCR1_ITF 0x08 #define FRMR_CCR1_EITS 0x10 #define FRMR_CCR2 0x0a #define FRMR_CCR2_RCRC 0x04 #define FRMR_CCR2_RADD 0x10 #define FRMR_MODE 0x03 #define FRMR_MODE_NO_ADDR_CMP 0x80 #define FRMR_MODE_SS7 0x20 #define FRMR_MODE_HRAC 0x08 #define FRMR_IMR0 0x14 #define FRMR_IMR0_RME 0x80 #define FRMR_IMR0_RPF 0x01 #define FRMR_IMR1 0x15 #define FRMR_IMR1_ALLS 0x20 #define FRMR_IMR1_XDU 0x10 #define FRMR_IMR1_XPR 0x01 #define FRMR_XC0 0x22 #define FRMR_XC1 0x23 #define FRMR_RC0 0x24 #define FRMR_RC1 0x25 #define FRMR_SIC1 0x3e #define FRMR_SIC2 0x3f #define FRMR_SIC3 0x40 #define FRMR_CMR1 0x44 #define FRMR_CMR2 0x45 #define FRMR_GCR 0x46 #define FRMR_ISR0 0x68 #define FRMR_ISR0_RME 0x80 #define FRMR_ISR0_RPF 0x01 #define FRMR_ISR1 0x69 #define FRMR_ISR1_ALLS 0x20 #define FRMR_ISR1_XDU 0x10 #define FRMR_ISR1_XPR 0x01 #define FRMR_ISR2 0x6a #define FRMR_ISR3 0x6b #define FRMR_ISR4 0x6c #define FRMR_GIS 0x6e #define FRMR_GIS_ISR0 0x01 #define FRMR_GIS_ISR1 0x02 #define FRMR_GIS_ISR2 0x04 #define FRMR_GIS_ISR3 0x08 #define FRMR_GIS_ISR4 0x10 #define FRMR_CIS 0x6f #define FRMR_CIS_GIS1 0x01 #define FRMR_CIS_GIS2 0x02 #define FRMR_CIS_GIS3 0x04 #define FRMR_CIS_GIS4 0x08 #define FRMR_CMDR 0x02 #define FRMR_CMDR_SRES 0x01 #define FRMR_CMDR_XRES 0x10 #define FRMR_CMDR_RMC 0x80 #define FRMR_CMDR_XTF 0x04 #define FRMR_CMDR_XHF 0x08 #define FRMR_CMDR_XME 0x02 #define FRMR_RSIS 0x65 #define FRMR_RSIS_VFR 0x80 #define FRMR_RSIS_RDO 0x40 #define FRMR_RSIS_CRC16 0x20 #define FRMR_RSIS_RAB 0x10 #define FRMR_RBCL 0x66 #define FRMR_RBCL_MAX_SIZE 0x1f #define FRMR_RBCH 0x67 #define FRMR_RXFIFO 0x00 #define FRMR_SIS 0x64 #define FRMR_SIS_XFW 0x40 #define FRMR_TXFIFO 0x00 #define FRS0 0x4c #define FRS0_LOS (1<<7) #define FRS0_LFA (1<<5) #define FRS0_LMFA (1<<1) #define FRS1 0x4d #define FRS1_XLS (1<<1) #define FRS1_XLO (1<<0) #define NUM_REGS 0xa9 #define NUM_PCI 12 struct t4_regs { unsigned int pci[NUM_PCI]; unsigned char regs[NUM_REGS]; }; #define T4_CHECK_VPM 0 #define T4_LOADING_FW 1 #define T4_STOP_DMA 2 #define T4_CHECK_TIMING 3 #define T4_CHANGE_LATENCY 4 #define T4_IGNORE_LATENCY 5 #define WCT4_GET_REGS _IOW (DAHDI_CODE, 60, struct t4_regs) dahdi-linux-2.5.0.1/drivers/dahdi/pciradio.rbt0000644000175000017500000124653211015035664021057 0ustar tzafrirtzafrirXilinx ASCII Bitstream Created by Bitstream E.33 Design name: pciradio_xilinx.ncd Architecture: spartan2 Part: 2s30vq100 Date: Sat Mar 12 18:19:05 2005 Bits: 336768 11111111111111111111111111111111 10101010100110010101010101100110 00110000000000001000000000000001 00000000000000000000000000000111 00110000000000010110000000000001 00000000000000000000000000001000 00110000000000010010000000000001 00000000100000000011111100101101 00110000000000001100000000000001 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000001001 00110000000000000010000000000001 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000000001 00110000000000000100000000000000 01010000000000000010010001100011 00000000000100100010000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000001000000000010010000000 00000000000000000000000000000000 00000000000100100010000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010010000000 00000000000000000000000000000000 00010000000000100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000000000000000000000000000 00000000000000100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000000000000000000000000000 00000000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010010000000 00000000000000000000000000000000 00010000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000001000000000010010000000 00000000000000000000000000000000 00010000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000000000 00000000000000000000000000000000 11101111000100100000000000001110 00000000000000111000000000000001 11100000000000000111100000000000 00011110000000000000011110000000 00000001111000000000000001111000 00000000000111100000000000000101 00000000000000010100000000000000 01010000000111111100010000000000 00000000000000000000000000000000 11000000000001011111101000000001 11101111001110000011011111110000 00001100111100000101001100111100 00000000111111011000000000110111 11000100000011001101000000000011 00110000010000001100111000000000 00110011100000000000110101000000 00000011001100000000000001110000 00000000000000000000000000000000 10000000000100001110101000000000 11101111010000000010001011000000 01011101111101000000001000111101 00010000101110011000001000100011 11010000100010101000000000000010 00001000000000001000100010000000 00100010100101000000100010101000 00000011001000000000010000110000 00000000000000000000000000000000 10001000000001011100010000010001 10100011001000000010011011001000 00001000001101000000101000001101 00000000101110010000000000100100 11011000000010001001000000000010 00001000000000001000000100000000 00100010100000000001100100010000 01000010011000100000000101110000 00000000000000000000000000000000 11000000000101011010000000000000 10101011000000000010001011000100 00011001101100000000001000101100 00000000101110011000000000100010 11000000000010101001000000000010 00101000001000001000100000001000 00100010101100000010100010110000 10000010001100000000010001100000 00000000000000000000000000000000 00000000000101011110101110010000 11101011000000100011010011101000 00001100101100000000001100101100 00000000111100110000000000110110 11000000010011000001100000001011 00100111000000001100101001000000 00110010001000000000110110000100 00000011010000000000010001110000 00000000000000000000000000000000 11100000000000011011101100000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111110 11000000000011111100000100000011 11111000100000001111101000100000 00111110110000000010111101000000 00001011111110000000000001100000 00000000000000000000000000000000 01000000000100001010010100000000 11110011000001010011111011010001 00001101001100100000001111101100 00000000110010010001010000110110 11000000000011001001000100000011 00101101000000001110000101100000 00111010000100000000110110101100 00000011000100000000010000100000 00000000000000000000000000000000 11001000000001010010000000000100 10111111000000000010111011000000 00001000111101000000001011111101 01000010100010011000010100101111 11000001000010001001000000001010 10101000000000001000101001000000 00100000110101000000100010100000 00000010101100100000000001000000 00000000000000000000000000000000 11100000000001010100100000000000 10110011000000000010110011000000 01001000001111010001001001001100 00000000100000010100100000101110 11000000100010000011110010000010 00101000000000001010001001000001 00101000100000000000100000000000 00000010101110000000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010111110100000 00101000011110000000001011001110 00000000100001011000000000101101 11100000010010000010100100000010 10011110000010001000010110000010 00100001111000000000100001101000 00000010100110000000000001000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001100001100000000001101001100 11000000110000110000000000110100 11000000000011000011000000000011 00001000000100001110001100000000 10111000100000000010110000010000 00000011000100100000001000000000 00000000000000000000000000000000 01000000010011011011110000000000 11111111000000000011110111000000 01001110111101010000001111111100 01000000111111110000000000110111 11000010000011111111000000000011 11111100010000001111110100010000 00111111110000000000111011110001 00000011010100000000011001100000 00000000000000000000000000000000 10101000000101011110100100000000 11111011001000000011110011000000 00011100101101000000101100101100 10000001111110110010100000111110 11000000001011001001000000001011 00101100000000001100101000000001 00110010100000000000000010010000 00000011111010100000000001010000 00000000000000000000000000000000 01001000000110011001110100100000 10110111010010010010110101000000 00101100001101100000001000011100 00100101101101110100000000101111 11001100000010000100000000000010 00001100000010001000001100000000 10100001100000000000100000010000 00000010100100100000010001100000 00000000000000000000000000000000 11000000000000001001111010000000 10110111101000000010111111100000 00001000011110100001001000011110 01001000100101111010001000100101 11101000000010000101100001100010 00011110000000001000011110000000 00100001101000000000101001111000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000001001100110000010000 10110011000000000010111011110000 00001000001100000000001000001100 00000000101100110000000000101110 11000000000010000001100000100010 00001101001000001000001110010000 00100010101001000010101000110010 00000010100100100000010000110000 00000000000000000000000000000000 11101000000101011110100000000000 11111010000000000011111110000000 00011100101000000000011100101000 00000000101110100000001000111110 10000000000011001110101000000011 00111000000000101100111000000001 10110011100000000000111011100010 00101011101110100000010001100000 00000000000000000000000000000000 01001000000000011010000000000000 11111000000000010011111000001100 01011110100000000000011111000000 00000000111110000000000000111110 00000000000011111000000000000011 11000000000000001111100000000000 00111110001000000000010110000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001010010000000000 11110001000000000001001001000000 00000100100100000010001100100101 00011000110010010010000000111110 01000000000011001001000000000010 00100100000000000100100100000000 00110010010100000000110000010000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110111001000000 10111001000000000010001001000000 00001000100100000000001010100101 00000010100010111100000100101110 01000001010010000001110110001010 00100100000001001000000101100000 10101010011100000000100010010000 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000100000 10111001000000000010101001000000 00101000000100000000001000100101 00000000100010010000011000101110 01000001100010001001000000000010 10100100000000001000100100000000 00100010010000000010100010011000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000101001000010000000001 10110001001010001010100001000000 00001000000100101000001010000100 10101000000000110000000000101100 01001010000010001001001000000010 10000100100000101000000100100000 00101000110010000000100000010010 00011000000000100000000100000000 00000000000000000000000000000000 10111000000011011110000000000000 11111000001000000011101000000000 00001100100001110000001100100001 11000000010010000000000000011110 00001000000011000000010100010011 10100000000000001100100000000001 00110000000101000000110010000000 00000011001011100000001101010000 00000000000000000000000000000000 10011000000101011110010000000000 11111001001010000011011101001011 00101111100100000000001111100100 00000000111110010000000000111110 01001010001011111101000100000011 01110100111000001011110100010000 00011111010001000000111111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000101011110010000000001 11111001001010000011111001000100 00001110110100000000001100110100 11100000110010110000000000111110 01010000000011111001010000000011 00100100000000001100100100000001 00110011010100000000100011010000 10000001001001100000000001110000 00000000000000000000000000000000 00111000000110000110000000000101 10110000001000000010111000001000 00001000100001001001001000100001 00000010110010000000000000101110 00101000000010111000000000000010 10100000101010001000101000000000 00110110000000000000100010000100 00000010000011100000010000110000 00000000000000000000000000000000 00001000000001010100110000001000 10110001001011000010111001001000 00001010000100110000101000000100 10010010100000010000000000101100 01010001000010111001010000000010 00000101000000001000000101000000 00100000010100000011101000010000 00000110000000100000000101110000 00000000000000000000000000000000 00011000010001011010010010000000 10111001000000000000111001000000 00000000100100000000001000100100 00010000100010010000000000101110 01000000000010111001010000000010 10100100100000001000100100000000 00100100010000000100101010010100 00000010000001100000010001100000 00000000000000000000000000000000 10100000000101011110010100100000 10111001000000010011110001111000 01000010100100000011001100100100 00000000110010010000010000111110 01000000000011110001000000000011 00100100000000101100000101000000 00110010010000000000111010011000 00001010001010000000010001110000 00000000000000000000000000000000 00101000000000001010011000100000 11111001000001000011111001100100 00001111000100001000011111000100 00000000111110011100000000111110 01000000000011111011000000000011 11000100000010001111101100010010 00111110010000000000110110010010 00000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000100000000 11111000000001010011101000010000 00001111100000000000001111100000 00000000111110000000000000110110 00000000000011111000000000000011 11100000000000001111100011000000 10110010000000000000110010000000 01000011110010100000010000100000 00000000000000000000000000000000 00101000000001000010100100001000 10111010000000000010001010000000 00001011111001000001001011111000 00100000100110100101000000101110 10000001000010111010100000000010 11101000000000001011101000000000 00100011101000000000100001100000 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110100000001 10110011000000001010000011000000 00001011001111000000001011001100 00000000101100110000000000100100 11000000010010110010000001000010 11001100000000001011001100000100 00100000111000000010000100010001 00000010100010100000000001010000 00000000000000000000000000000000 00100000000100010001110000000000 10110111101000100010000111000000 10001011011100001000001011011000 00000000100101110000000000101101 11000000000010110110010000000010 11011100110000001011001100000000 00100000110000100000100101010000 00000010001010000000000001000000 00000000000000000000000000000000 00101000000010000001001001000000 11110111100000010011000111100000 00011111011110000000001111011110 00000000111101001000100000110101 11100000100011110111100000000011 11011110101000001111011110010010 00110001011000000000110100011000 00000011101010100000001000000000 00000000000000000000000000000000 00001000000101011010000110010000 11111011011010000011011011011010 00011111101100000001001111101000 00000001110110100110000000111110 11000000000011111010010000000011 11101100100000001111101101000000 00111110000000000110111010010000 00000011100000100000011001100000 00000000000000000000000000000000 01000000010011011111111000000000 11001111100010000011011111100110 00000100110110000000000100111110 01000000110111111000000000111111 11100000000011001110110000000011 00111110000000001100111110000000 00110011111000000000110011011000 00000011000100000000000001110000 00000000000000000000000000000000 10101000000000011001110001000000 11011111000000000010000111000000 01001101010100010000001000111000 00000000110101100000000001101101 11000000000010000110010000000010 00011100000010001010011100000000 00111111110000000000100001010010 00000010001010100000010001100000 00000000000000000000000000000000 00000000000000001011010000000000 10000111000000000010010111000001 00001001010100000000001000011100 00001000100001010000000000101000 11000000000010000111000000000010 00011100000000001001011100000000 00100001110000100000100001010000 00000010000001100000000000100000 00000000000000000000000000000000 01100000000101001100010000000000 10010011000000000010010011010100 00001000100100000000101010001000 00000000100100100000001000101100 11000000000010000000010000000010 00001110100000000011001100100000 00101100101000000010100000011000 00000010000110000000010000110000 00000000000000000000000000000000 10101000000101011010110100000000 10001111000001000011011111010000 00001001101000000000001100100100 00000001110010110000000000111111 11000000001011001000000100001011 00111100100010101101101100100000 00110010111000000010110010011010 00000010001011100000010001100000 00000000000000000000000000000000 10000000000000001110110000100000 11111011000000000011101011001000 00101111101000000000001101100000 00000000111110010000000000111110 11000000000011111100010001000011 11001100000000001110101100000000 00111110110010000000111110010000 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001111101000000000 11111111000000000011111111000000 00001100101000000000001100111110 01000000110011001000000001111111 11000000000011111100001000000011 00101100000000101100111100000000 00110011010000000000110001011000 00000011101000000000010000110000 00000000000000000000000000000000 10000001010001000110101000011000 10111011000001000010110011000000 00001000101011011000001010101111 10001000101010001000000000101110 11000000000010010000110000000010 00101100000000001000001100000000 00100010000000000010100010011000 00100011011000000100000000010000 00000000000000000000000000000000 10000000000001010010010010000000 10111011000000000110111011000000 00001000101000000000001000000100 00000000100010110001000000101110 11000000000010111000000000000010 00101100000010001000101100000000 00100000110000000000100010010010 00000010101000000000000001000000 00000000000000000000000000000000 00001000000001000000010000000000 10110011000000000110011011000000 00011010000100000000001010000000 00000100101000000000000000101100 11000000000010011000000000001010 00001100000000011000001110000000 00100000110000000000100000110000 00000010010000100000000100000000 00000000000000000000000000000000 00000000000001010110010000000000 11111111000000010011110111000000 00101100101000000000001100100100 00000000110010010000010000101110 11000000000011110000000000000011 00111100000000001100101100000000 00110010110000000000110010010000 00000011101000000000001101010000 00000000000000000000000000000000 10100000000101011101010000000000 10111111000001000011111111000000 01001101110100000000001111110100 00000000111111000000000000111111 11000000000011011100000000000011 11111100000000001111011000000000 00111111100000000000111101010000 00000011101010000000011001110000 00000000000000000000000000000000 11000000000001011111010000000100 10101111001100000011001111010000 10001101110101000000001111111100 01000000110011110001000000111111 01100000000011111111000000000011 00110110000000001111010010000000 10110011001000000000111011011001 00000011111100000000000001110000 00000000000000000000000000000000 10000000000100001110011000000000 10001111000100000010001111010000 00001000101100000000001011011100 10000000100011110001010000101110 01100000000010111111010011000010 00100110000100001011100010000000 00100000000010001000111000010000 00000010111000000000010000110000 00000000000000000000000000000000 10001000000001011100010000000000 10100011001000000010000011001101 00011001000000100000001011001100 11000000100000110010000100101100 11000000000110110011001100000010 10000100000000001011100000000000 01100000000000100000101000000010 00000010111000100000000101110000 00000000000000000000000000000000 11000000000101011010010000000011 10100011000000000010001011000000 00011000101000001000001011101100 00000000100010110000000000101110 11000100000010111011000000000010 10100110000000001011100000000000 01100010000001000000101010000001 00000010111100000000010001100000 00000000000000000000000000000000 01000000000101011110011000000000 11101011000001000011001011000000 00001101100101000001001111101100 00000000110010110000000000111110 01100000000011111011000000001011 10100100000000001111000001100001 00110010001010000000111010011000 00000011110100000000010001110000 00000000000000000000000000000000 11100000000000011011011001000100 11011111000000000011111111000000 00001111111101000100001111111100 00000000111111110000000000111111 01000000000011110111000000000011 01110100000000001111110000000000 00111111001000000000111111011000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010011000001000 11011011000000000011001011000000 00001100100101000000001111001100 00000000110010110000000000111110 11000100000011111011000000000011 11101100000001001111100001000100 00110010001000000010110010000000 00001011000100000000010000100000 00000000000000000000000000000000 11001000010001010000010000010000 10001111000000000010001111000000 10001010101100000010001011111100 00000000100011110000000000101110 11100001000010111111000000000010 11101101000001001011100000000000 00100010001100000100100010001000 00000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100010000000000 10010011000000000010001011000000 00001000001000000000001011001100 00000000100000110000000000101100 01101000000010110011000000000010 11001100001000001011000100000000 00100100110000100100100000111000 01000010011110000000000001010000 00000000000000000000000000000000 00100000000000010001011000000000 10010011100000000010000011100100 00001010011010000010001011011110 00001000100001111000000001101101 11100001010010110111100000000010 11011110000000001011110111000000 10100101111000000000100001111000 00000010010010000000000001000000 00000000000000000000000000000000 01001000000010000000110000000000 11010011000000000011000011000000 00001100000000000100001111001100 00000000110000110000000000111100 01000000000001110011000000000011 11001100000000001111000100000000 00110100110000000000110000100000 10000011010100100000001000000000 00000000000000000000000000000000 01000000000111011001110001000000 11101111010000100011111111010001 10001110111000010000001111111100 00000000111111110000100000111111 11010000100011111111000000100011 11111101000010001111110100000000 00111011110000000000111111101000 00000011100100000000011001100000 00000000000000000000000000000000 10101000000001011110111000000000 11001011111000000011001011000100 00001100101100000000001100101101 10001000111110110110000000111110 01010100000011111011110101000111 00100101000000001111100100000000 00110010110000000000111110110000 00000011111010100000000001110000 00000000000000000000000000000000 01001000000100011001110000000000 10001111011000101010001111000000 10001000111100000000001000011101 00100000101101110001000100101101 11001000000010110111001010010110 00010100100000001011010100000001 00100001110000000000101101110000 00000010110100100000010001100000 00000000000000000000000000000000 11000000010000001000111000010000 10000111100000000010000111101001 00001000010110000100001000011110 10000000101101111010000000101101 01100000000010110111100001001010 00011110010000001011010110000101 10100001111000010000101101101000 00000010111100000000000000100000 00000000000000000000000000000000 01001000000101000100110000000000 10000011000000000010000011000000 00111000001100000000001000001100 00000000101100110000000000101100 11000000000010110011000000000010 00001110000000001011000100000000 00100000110000000000101110100000 00000010110100100000010000110000 00000000000000000000000000000000 11101000000101011010101010000010 11001010000000000011001010000000 00001100111001000000101100101000 00000000111110100000000000111110 10000000000011111010000000000011 00101000000000001111001000000000 00110010100000000100111110100000 00000011111110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000100011111000000000 00001111100000100000001111100000 00000000111110000000000100111110 00000000010011111000000001000011 11100001010000001111100001000000 00111110000000000000111111000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110011100000000 11111001000000000011111001000000 00000000100100000000101100100100 00000000111100010000000000111010 01000000000011111001000000000011 11100110000000001111100110000000 00110010010000000000111110011000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000001010010111001000000 00001000100100000000001000100100 00000000101110010000000000100010 11000000000010111001000000000010 11101100000000001011100100011000 00100010010100001000101110011100 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010110001000000 00001010000100000000001000100100 00000000101110010000000000100010 01000000000010111001000000000010 11100100010000001011100100000000 10100011010000000100101111010010 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010010100000 10110001001010100010110001001011 00101010000100100000101000000100 10100000101100010010100000100000 01100000000010110001001010000010 11000100000000001001100100000000 00100001011000000000101101011000 00001010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000010000000 11111000001000000011111000001000 00001110100000000010001100100000 10000000111110000010000000111010 00000000100011110000001000000011 11101000000000001111100000000000 00110010000101000000111111000101 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011111010000010000 11111001001010000011111001001010 00001101110100111000001111100100 10100000111110010010100010111110 01000000000011111001001010000011 11100100000000001111010100000000 00111110010000000000111110010000 00000011111001100000011001110000 00000000000000000000000000000000 00011000010011011111011000010000 11111001010010000011001001000100 00001101100100010100001100100100 00100000110010010100100000110010 01000000000011111001010010000011 00100100000000001100010100000000 00110011010000000000110011010100 00000011110001100000000001110000 00000000000000000000000000000000 00111000000000001110000100000000 10111000011000000010000000001000 00001000100000100000101000100001 10000000100010000110010000100010 00000000000010111000010001000010 00100000000000001000100000000000 00100010000010000000110110000000 00000010110011100000010000110000 00000000000000000000000000000000 00001000000001010100010100000000 10110001000000000010000001010000 00011011000101000000001000000100 00100000100000010010000000100000 01000000000010110001001000001010 00101100000001001000000100000000 01100000110000100000100100010000 00000010110000100000000101110000 00000000000000000000000000000000 00011000000101011010010000001000 10111001000000000010000001000000 10000010100101100000001000100100 00000000100010010000010010100010 11001000010010111001000000000010 00100100100000001000100100000000 00100010010000000000100010010000 00000010110001100000010001100000 00000000000000000000000000000000 10100000000101011110011000000000 11111001000000000011001001000000 00001111100100000000001100100100 00000000110010010000000000110010 01000000000011111001000000000011 00000100000000101100100100000000 00110010010000000010100110010010 00000011111010000000010001110000 00000000000000000000000000000000 00101000000000011010011100000000 11110001000000011011111001000000 00001101000100000000001111000100 00000010111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 10111110010000001000111110010000 00000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000001000 11101000000000000011111000000000 00001101100001000000001100100000 00001100110010000000000000111110 00000000000011110000000000000011 00100000001000001111100010000000 00110010001000000000110010000010 00000011110010100000010000100000 00000000000000000000000000000000 00101000010001010010101000100000 10001010000000100010111010000000 00000000101000000000101000101000 00000000100010100000010000101110 10000000000010111010000000010010 00101000000010001011011010001000 00100011100000000110100011100100 00000010110010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10100011000000000010110011000000 01000010001100000100001000001100 00000010100010110000000000101100 11000100000010110011000000000010 00001100000000001011001000000000 00100110110000000100100000110000 00000010110010100000000001010000 00000000000000000000000000000000 10100000000000010000111000000000 10000111000000000010110111000000 00001010011100100000001000011100 10000000100001110010010000101101 01000000000010110111001000000010 00011100000010001011111100000000 10100101110000000000100001110000 00000010111010000000000001000000 00000000000000000000000000000000 10101000000000000001111000000000 11100111101100100011110111101010 00101110001110110001001100111110 10000000110001111000000000111101 10100000010011111111101100000011 00011110000000001111011010000000 00110111111000000000110001111000 00000011111010100000001000000000 00000000000000000000000000000000 00001000000101011010110000000000 11111011011000000011111011110000 00001100101100110000001111101101 11010000111110110011110100111110 01011000000011111011010000011011 11101001001000001111101100000000 00111010110000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000011011111111000000000 11101111100110000011111111100010 00101100111110000000001111111111 00010000111111111000000000110111 11110100000011001111100010000011 11111010010000001111111110000000 00111111111000000000111111111000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000000011001110001000000 11100111000100000010111111000000 00001000011100000000001011011100 01000000101101110001000000100001 11000100001010000111000000000010 11011000000000001011011100010000 00101101110000000000101101110000 00000010001010100000010001100000 00000000000000000000000000000000 00000000000000000001110000000000 10100111000000000110110111100000 00001000011100000000001011011100 00000000101101110000000000100011 10000010000010010111000000000010 11010100000000001011011100000000 00101101110000000000101101110000 00000010000000000000000000100000 00000000000000000000000000000000 00100000000101001100110000000001 10100011000000100010110011000000 00011000101110010000001011001100 00000000101100110000000000100000 11100000000110010011000000000010 11000000000000001011001100000000 00101100100000000000101110110100 00000010000010000000010000110000 00000000000000000000000000000000 10101000000101011010110000000000 11101111000000000011111111000000 00001100111100000000001111111100 00001000111111110000000000110110 11100000000011011111000000000011 11100100000000001111000100000000 00101110110000000000111110110000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000100011111011000000 00001111101100000000001111101100 00000000111100110000000000111110 00010000000011101011000000000011 11100100000000001111100101000000 00111110110000000000111110111100 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001101011100001000 11001111000000000011110111000000 00000100111100000010011100111100 00000000111111110000000000110011 10000000000011111111000000000011 11111110000000001111110010000000 00111011110000000000110011111000 10000011000000000100010000110000 00000000000000000000000000000000 10000001010000000110111000000010 10001011000000000010111011000000 00001010101100000000001101101100 00000000101110110000010000100010 00010000000010111011000000000010 11101010000001001011100111000000 00111010111001010000100010010010 00000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10001011000000000010111011000000 00001010101100000000001000101100 00000000101110110000000000100010 01100000000110111011000000000010 11100000100000001011101100101000 00101000110000000000100010110010 00000010001000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10000011000000000010110011000000 00001010001100000100101000001100 00000100101100110000000100100000 00000000000010010011000000000010 11000000000000001011001100000000 00100000010000010000100000110000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000001010110110000000000 11001111000000000011111111000000 00001110111100000000001000111100 00000000111101110000000000110010 00000000100011111111000000000011 11100100000000001111100100000000 01111010110000010000110000100000 00000011000000000000001101010000 00000000000000000000000000000000 10100000000101011111110000000000 11111111000000000011111111000001 01001111111100000000001111111100 00000000111111110000000000111101 00000000000011111111000000000011 11110000000000001111110100000000 00111011000000000000111111000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111110001000000 11001110100000000011011111100000 10001100111100100000001101111100 00000000111111110010000000111111 11000000000011001111000010000011 00110000000000001100110110000000 00110011000000000000111111000000 00001011001100000000000001110000 00000000000000000000000000000000 10000000000100001111110100000000 10001010100000000010001011001010 00001000101111000000001000111110 00000000101111110001000100101111 11000110000011011111011001000010 00100000000000001000100000000000 00100010101000010000101110001100 00000010001000000000010000110000 00000000000000000000000000000000 10001000000001011100110001000000 10101001000000000010011011000000 00101000001100010000001001001100 00000000101100110000000000101100 11000000000010000011000010001010 00000100000000001000000000000000 00100000010000000000101100100100 00000010001000100000000101110000 00000000000000000000000000000000 11000000000101011010110000000000 10101001001000000010001011000000 00011000101100000100001000101100 00000000101110110000000000101110 11000000000010010011000000000010 00101000000100001000000010000000 00100010110000000000101110100000 00000010001100000000010001100000 00000000000000000000000000000000 01000000000100011110110000000000 11101001100000000011010011000110 00001100001100000100001101101100 00000000111110110000000000111110 11000000000011001011000000000011 00100101000000101100101011000000 00110010110000000000111110010000 00000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011110000000000 11011101000001000011111111000001 10001111101100000000001111101100 00010000111110110000000000111111 11000000000011111111000000000011 11110000000000101111111000000000 00111111110000000000111111010010 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001000110000000000 11101001000100000111101011000000 00001101101100000000001101101100 01100010110010110000000000110010 11000000000011001011000000000011 11001101100000101100101001000000 10110010110000000000111101111010 00000011000100000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10000001010100000110001011000000 00001000111101110100001101111110 00000000100011110000000000100011 11000000001010001111000000000011 10101011100000001000101000000000 10110010110101000000101110110100 00000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000000 10100010100000000010100011000000 00001001001110000000001000001101 00000000100000110000000000100010 11000000000010000011000000000010 01000001000000001000000010000000 00100100000000000000101100000000 00100010001110000000000001010000 00000000000000000000000000000000 00100000000000010001111000001001 10000110100000000010001111100000 01001001011110000000001001011110 00000001100001111000000001100001 11100100000110000111100100000010 10000010000000001000010011100000 00100001101000000000101100001000 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000010110000000000 11100001000000100010100011000000 00001101001100000000001000001100 00000000110000110000000010110010 11000000000011000011000000000011 11000101000000001100100001001000 00110100010000000000111100100000 00001011000100100000001000000000 00000000000000000000000000000000 01000000000111011011111000100000 11110101000000000011110111000000 00001110111100001000001111111100 00000000111111110000000000111111 11000000000011111111000011000011 11111100000000001111110000100000 00111111110000000000111111100000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110111000000000 11000011100000000011011010000000 00101100101100000000001111101100 10000000111110110100000000110010 11001010000011001011101000001011 00100100000000001100100000000000 00110010110000000010110010010100 10000011111010100000000001110000 00000000000000000000000000000000 01001000000100011011110010001000 10000111000000001010001111000000 00001000011100100001001011011100 11000000101100110000100000110101 11000000000010000111001010000010 00010100010000101000011000000000 00100001110000000000100001110000 00000010110100100000010001100000 00000000000000000000000000000000 11000000000000001001111000001001 10000101100000000010000111100000 00001000011110000000001011011110 11000000101101111001000000100001 11100100000010010011101000000010 00011110000000001000011010000000 00100000111000000000101001011000 00000010111100000000000000100000 00000000000000000000000000000000 01001000000101001100110000000000 10000001111000000010000001110000 00011000001100000000001011001100 00001000101100110000000000100100 11000000001010010011000000000010 00001100000000001000001011100000 10100000110100000000101000110101 00000010110100100000010000110000 00000000000000000000000000000000 11101000000101011010100000000000 11001110110000000011001110000000 00001100101000000000001111001000 00000000111110100000000000110010 10000000000011011010000000000011 00101001000000001100111011001000 00110011101000000000111000101000 00000011111110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000010 11111000000100000011101000001100 00001111100000000000001111100001 00000000111110000000001000111100 00000000000011101000000000000011 11100000100000001111100001000000 00111110000011000000010110000000 10010011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000100000011111001000000 00101100000100000000001100100110 00000000110010010000000000110010 01000000000011001001000000000011 11101111000000001110100100000100 00110000010000000000110010110000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000111010000000000 10111001010000000010111001000000 00001000100100000000101000100101 00000000110110010000000000101010 01000000010010101001000000000010 11000101000010001000000100100100 00110110010000000110100010010000 00000010001000000000000000010000 00000000000000000000000000000000 00011000000000010010010000000000 10111001000010000010110001000000 00001000100100001000001000100100 01000000100000010000000000100010 01000000010010001001000001000010 11100101000000001010100110000000 00100010010000000010100010010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010010000000 10110001000000000110110001000000 01001000000100100000001000000100 10000100100100010010100000101000 01001010000110100001001011000010 11000100100000001000100100000000 00100100010010000000100000010010 00010010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000101000000 11111000000000000011111000010100 00001100100000000000001000101000 00000000110010000111000100110000 00001001000011001000001000010011 11100001010000001110000001010000 00110010000000000000110010000000 00001011001011100000001101010000 00000000000000000000000000000000 10011000000111011110010100000000 11111101000000000011111101000000 00001111100100010000001111100100 01000000111110010000000000111110 01001010000011111001001010000011 11000100010000001111111100000000 00111111010001000000111110010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010100100000 11110101000000000011101001010000 00001100110100101000001111110100 00100000111110010000000000110010 01000010000011001001000000000011 00001101001000001100010100000000 00110010010000100000110010010000 10000011110001100000000001110000 00000000000000000000000000000000 00111000000100001110000110000000 10111000000000000010001000000001 00101000100001000000001110100001 00000000101110000101000000100010 00111010000011011000000000001010 00100001000000101000100000100000 00100010000100010010100011000100 00000010110011100000010000110000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010101001001000 00001000000100000000001011000100 00000000101100010010100010100000 01000000000010000001011010100110 00000100000001001000000100001000 01100001011000000000100001010000 00000010110000100000000101110000 00000000000000000000000000000000 00011000000101011010010000000000 10111011000000000010001001000010 00001000100100000100001011100100 00000000101110010000000000100000 01000000000110011001000000000110 00000101000000001000000100000101 00100010010000000010100011010000 00000010110001100000010001100000 00000000000000000000000000000000 10100000000101011110010000001000 11110001010010000011100001110000 00001100100100000000001111100100 00000000111110010000000000110010 01000000000011001001000000000011 00100110000000001100100110000000 00110010010100000000110010010000 00000011111010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000000 11111001110010000011111001101000 01001111100100000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11101100100000101111100111000000 10111110010000000000111110011010 10000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000010000 11111000010000100011001000010000 00001101100000000000011111100000 01010000110010000000010000111110 00000001010011001000000000010011 11100001000000001110100010000000 00110000000000000000110011000000 01000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000000 10111110010000000010001010000001 00001000111011000100001011111001 00000000100010100000000000101110 10000000001010001010000000010010 11101000000000001000111010100000 00111010100000010000100010100000 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000100000010000011000000 00001001000111011001001011001101 00101000101010110000000001101100 11000000000010011011000000100010 11001101100000001010001110000000 00100100111000000000100000100000 00000010000010100000000001010000 00000000000000000000000000000000 10100000000000010001110011000000 10111111000000000010001111001000 01101000010100000100001011011110 00000000101001110010000000101101 11000100101110010111000000000010 11010000000000001000111100000000 00101001100100000000100001101000 00000010001010000000000001000000 00000000000000000000000000000000 10101000000010000001111010000000 11110111100000001011000111110000 00001101010010000000001011001110 00000010111001111110000000111111 11101000000011010111110010100001 11011010000000001110011110000000 00110100111000000010110000101000 00001011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000100011110011000010 00001111100000000000001111101100 00000000110110110100001000111110 11010000010011101011011000000011 11101000001000001111101100000000 00111110100000000000111110100000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011001111100000 00001100110110000000001111111110 00000100111111111100000000111111 11110000000011101111100100011011 00111110000000001100110010100000 00110011011000000000110011111000 00000011110000000000000001110000 00000000000000000000000000000000 10101000000100011001110001000000 11110111001000000011010111001000 00001000010100010000001111011100 00000000111101110000000000111101 11001000000010000111000000000010 00010000001000101000011100100000 00100001000000000000100001110000 00000010111010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000001000010000111000000 00001000010100000000001011011100 01000000101101110000000000101101 11000000010010000011000000000110 00011100010000001000011100110100 00100001010000000000101001111000 10000010110000000000000000100000 00000000000000000000000000000000 00100000000101001100110000000000 10100011000000000010011011010100 00000000000100000000001010001000 00000000101000110000000000101000 11000000001110000011000000000010 00001011001000001000101110000000 00100000000000000000101000111000 00000010110010000000010000110000 00000000000000000000000000000000 10101000000101011011110000000000 10111010000000000011001111010000 00101100001100000000001011100100 00000000101111110000000000101111 11000000000010001111000000000011 00101111000000101000101101100000 00110010111000000100111010001000 00000011111010100000010001100000 00000000000000000000000000000000 10000000000000001110110000010000 11111011000000000011111011001000 00001111100001000001001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11100100000001001111101100100000 00111100101000000100100110000000 00000001111000000000000000110000 00000000000000000000000000000000 00000001000100001111110000000000 11111111100000000011001111000000 00001100111010100000101100011100 00000000110011110000000000111101 11000000000011001111000000000011 11111000000000101100111100000101 00010010110000000100110011000000 00000011110000000100010000110000 00000000000000000000000000000000 10000001000001000110110000010000 10110011000000000010001011000000 00101000100000100000001000101111 00000000100010110000000100101110 11000000000010001011000000010010 11101001001000001000101100000000 00100010100000000110100010001001 00000010111000000100000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000100000010001011000000 10001000101100000000001000101111 00000000100010110000000000101110 11000000000010001011000000000010 11001100000000001000100010000000 00101010010000000000100010010000 00000010111000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010000011000001 00001000001000000000001000001100 00000000100000110000000000101100 11000000000010000011000000000010 11000100000000001000000110000000 00101000000000000000100000010000 00000010110000100000000100000000 00000000000000000000000000000000 00000000000011010110110000000000 11111001000000000011000111000000 00001100101100000000001100101100 00000010110011110000000000111101 11000000000111001111000000000011 11001100000011011100001000000100 00111010010000000000110010010000 00000011110000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11110111000000001011111111000000 00001111111000000000001111111100 00000100111111110000000100111111 11000000000011111111000000000011 11111100000000011111111100000000 00110111000000000000111111010000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111111000000000 11101101100000000011111100000100 00001110111100000000001101110110 00000100111111110110000000110011 11001100100011001110000100100011 10110000010100001100110000000000 10110011000001000100110011010001 01000011001100000000000001110000 00000000000000000000000000000000 10000000000100001100110000000000 10001001100001000010110011001000 00001100101111000000001000100110 00010000101111110001000000100011 11001100000010000010000000000111 10100000100000001000100000000000 00110010100010000000100010010010 00000010001000000000010000110000 00000000000000000000000000000000 10001000000001011110111000000010 10100011000000000010110011001001 00001010001100010000001000000100 00000000101100110010000000100000 11000000000010010011001000100010 10000000100000001000000000000000 00100100000010010000100000010010 00000010011000100000000101110000 00000000000000000000000000000000 11000000000101011010111000000000 10101011000000000010111000100000 00001001101000000000000000100100 00000000101110110000000000000000 11000000000010011011000000000010 10100000000000001000100000000000 00100010100000000000100010010000 00000010011100000000010001100000 00000000000000000000000000000000 01000000000101011100110000000000 11101001000000000011111001100000 00001110100101000000101101101110 00000000111110110000000010110010 11000000000011011010000000000011 10100011000000001100100100010000 10110110010000000010110010100000 00001011010100000000010001110000 00000000000000000000000000000000 11100000000000011011110000000000 11011111000010000011110111000000 00001110111101000100001111111110 10000000111101110000000100111111 11000000001011101110000000000011 11010010010001101111100110000000 10111111110000000000111101100000 00000011101110000000000001100000 00000000000000000000000000000000 01000000000100001010111000000000 11101001000000010011111011000000 01001110001000001000101101101100 00000000111110110001000010110010 11000000000011001011000000000011 00100001000000101100000100001000 00110000010000000000110010101010 00000011000100000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10001011000000010000111001000000 00001000101000000000001000101100 00000000101111110101000000100011 11000000000010001011000000000010 00100000000000001000100101100010 00100010110000010000100010100100 00000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000000 10000001000000000010110011000000 00001010000110000000001010000111 10010000101100110000010000101000 11000000000010000010000000100010 00001100000000001000001000000000 10100000000000000000100000010000 01000010001110000000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 10000101100000000010110111100100 00001000001010000100101010010110 00100000101100111000000000101001 11100000101010000110100000000010 00001110000000001000011010000000 00100000101000000010100001011000 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000110000000000 11100011000001000011110011010000 01001110001100101000101110001100 10000000111100110010000000111010 11000000010001000011000100000111 00001101100001001100001000100000 01110000000000000000110010010010 00001011000100100000001000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 10001111111000000000001100111100 00000000111111110000000000110111 11000000000011111111000000000011 11111100000000001111111000000000 10111111100000000000111111011000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011100010000000000 11001001011000000011111010000000 00001101000000100000001101100110 11100000110010110010100010111010 11100000000011001010000000000011 11101100000000001100101100000000 00110110010000000100110010100000 01000011001010100000000001110000 00000000000000000000000000000000 01001000000100011001110000000000 11010111001010010010111111000000 00000101011000010000101000010100 00000000100011110000000010100000 11011100000010000110000000000010 11011100000001001010011100000000 10100001110000000100100001100000 00000010000100100000010001100000 00000000000000000000000000000000 11000000000000001011101000000000 10000101110100000010110111100000 00001001011010000000001001111110 10000010100001111001000000101001 11101001100010000111100000000010 10001110000000001010001110000000 00100001011000000000100001101000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000101001100110000000000 10010011000000010010110010000000 00001001001011000000001000001110 00000000100010110000001010100000 11000000001010000011000001100010 11001100000000001010001100000100 00100000110000000110100000100111 00001010000100100000010000110000 00000000000000000000000000000000 11101000000101011011100000000000 11001010000000000011111110010000 00001101101000011000001101101010 00000000110010100000000010111010 10000000000011001010000000100011 10101000000000101110101001000000 00110010100100000000110011101100 00001011001110100000010001100000 00000000000000000000000000000000 01001000000000001110001100000000 11111000000000000011111000000010 00001111000000000000001111100001 01010000111110000000000000111110 00000000000011110000000001000011 11100000000000001011000000001000 00111110000000100000111101000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000010 11101001001000000011000001000000 00001100101100000000001100100100 00000100111110010000000010110010 01000000000011111001000000000011 00100100000000001000100100000100 00110010010000000010110010010000 00001011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010100100000 10000011111000000010001001000000 00001000100100110000001000101100 00000000101110010000000010100010 01000000000010111001000000000010 00100100000000001000100100000000 00100010010100000000100010010100 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010000011000000000 10101001000000000010001001000000 01101000101100000100101000100100 00000000101110010100000000100010 01000000100010111001000000000010 00010100000000001010110100000000 00100001010000100100100011010000 11000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010000000010 10001001000000000010000001001000 00001000000100100000001000000100 00000000101100010010100010100000 01001011000010110001001000001010 00010100100000101010010100100000 00100001010010000000100001010010 00000010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000000000000 11101000000000000011001000000000 00001100100000000000001100101000 00000000111110000111000010110010 00001000000011111000100000000011 00100010000000001110100011010000 00110000001101000000110001001101 00001011001011100000001101010000 00000000000000000000000000000000 10011000000111011111010010100000 11111001000000001011111101001110 01001111100100010000001111000100 00000000111110010000000010011110 01001010000011111001001110000011 11100100111000001101100100010000 10111110010001000100111110010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000000011110110100000000 11001001000000000011111001010000 00001110110100000000001110100100 00000000111111010001001010110010 01001010100010111001000000000011 00100101000000101100110101000100 00110010010000000000110010010010 00001011000001100000000001110000 00000000000000000000000000000000 00111000000100001100001000000100 10001000000000010010111000010100 00001000100001000000001000100000 00000100101110000100000010101010 00011000000010111000010000000010 00100001010000001000000001000001 00100010000100000000100011000110 10000010000011100000010000110000 00000000000000000000000000000000 00001000000001011100010010000000 10000001000000010010110001001000 00001010000101000000001010000100 00000000101100010110000010100000 01000011000010110001011010000010 00000100100001001010000101100100 00100001010110100000100101010001 00000010000000100000000101110000 00000000000000000000000000000000 00011000000101011000010101000010 10001001000000100010111001001000 01001000100100001000001000100100 00000100101100010000000010001010 01000001010010111001010000001010 00100100000000001010100100000001 00100010010000000000100111010000 00000010000001100000010001100000 00000000000000000000000000000000 10100000000101011110011000000000 11001001000000000011111001101000 00001110100110000000001110100110 00000100111110010000000010010010 01000000000001111001000000000010 00100100000000001110100100000000 10110010010000000000100110010000 00000011001010000000010001110000 00000000000000000000000000000000 00101000000000011010111000000000 11111001100101000011110001100000 00001111100101000000001111100100 10010100111110010000000000111110 01000000000011111001000000000011 11100100000000101101100100001000 00111100010000000010111000010000 00000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000010 11001000100000000011111000000000 10001100000001001000101110100010 00000000111110000000000010110010 00000000000011110000000000000011 00000000000100001100100000000000 10110010000000000000110011000000 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100001000000 10001010101000000010111010000000 00001000111000000000001000101000 00100000101111101100000010110110 10000000000010111010000000001010 00101000000000000000111001001000 00100010100000010000100011100000 00000010100010100000000001000000 00000000000000000000000000000000 00101000000001010100100100000010 10000011100000000010110011000000 10011000001100010000001010001100 00000000101100010110000000101000 11000001000010110011000000000010 00001100000000101000101110000000 10100000111000000010100000101000 00000010000010100000000001010000 00000000000000000000000000000000 10100000000000010001100100000000 10000111000000000010110011000000 00111000011100000000001000011100 00000000101101000000100010101101 11000000000010110111000000000010 00001100000000001000010100000000 00100001110100000000100001100100 00000010001010000000000001000000 00000000000000000000000000000000 10101000000010000001111000000010 11000111100010000011110111100100 00001100011010000000001110011110 00000100111111011000000010111001 11100100010011111111101010000111 00011110001000001100011110000010 00110011101000000010110011111000 00001011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110110110000 11111010010000000011111011100100 10001011001100000000001111101000 10100000111110000000000000110110 11000100000011111011010100100011 11101101110000001111100100000100 10111110100000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111001000000000 11001110100000000011111111100001 00001111111110000000101110111010 00000000111111111000000000111011 11100000000011111111100000000111 00111110010000001100111010000000 00110011011000000100110011001000 01000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001000001000010 10000110000100000010110111000000 00001011011100101000001000010100 01000000101101100000000000100001 11000000010011100111000000000010 00111100110000001000111100010000 00100001010001000100100001000001 10001010001010100000010001100000 00000000000000000000000000000000 00000000000000001001010000100010 10000101000000000010110111100010 00001011001100000000001011011000 00000000101101110000000000101101 11000000000010110011000000001010 00011100000000001000011000000000 00100000000000000010100000011000 00001010000000000000000000100000 00000000000000000000000000000000 00100000000101001100110000000000 10000000000001000010110011110010 00001011001101000000001001000000 00000100101100110000001010100100 11000000000010100011000000000010 00001100000000011000101100000000 00100000001001000000100000010100 00000010000010000000010000110000 00000000000000000000000000000000 10101000000101011000110000000000 11001001000000000011111111100000 00001111101100000000001111100100 00000000111110000000000000111111 11000000010011111111000000100011 00111100000000001100101100000000 00110010110000000000110010101101 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110110100000000 11111001100000000011111011000001 00001111101101000000001110101100 00010000111110110100000000111010 11000000000111111011000000000011 11101100000000001111100000000000 00111110110000000000111110100000 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001111111000100000 11011111010000000011111111000000 00011111111100011000001101110100 00000000111111000001000010110001 11000000000001001111000000100011 11011100000000001000111100000000 00110001100000000010110001110000 00001011000000000100010000110000 00000000000000000000000000000000 10000001000001000110111101100000 10001010100000000010111011000000 10001011001101000000001000101000 00000100101110110100000010110110 11000001000010101011000000000010 11101100000100001101100011001010 00100010100000010000101010110000 00000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010100000000000 10011000000000000010111011000000 00011011101100001000001001100010 00001000101100100000100010100010 11000000010010101011000001000010 11101100000000001010100000100000 00100010010000000000100010000000 00000010001000000000000001000000 00000000000000000000000000000000 00001000000001000010100000000000 10000000000000000010110011000000 00001011001100000000011000000100 00000000101100110000000001100100 11000000000010100011000000000010 11001100000000001011000000000000 00000000010000000010100000000000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000011010100100000000000 11011001000000000011111111000001 00001011101100000000101101100000 00000100111100110000000010110011 11000000000011101111000000000011 11111100000010001110100000000000 10110010000000000100110010010000 00000011000000000000001101010000 00000000000000000000000000000000 10100000000110011111100000000000 11111100000000000011111111000000 00001111110100000000101111110000 00000000111111110000000000111111 11000000000011011111000000000011 11111100000000001101110000000000 00111111000000000000111111010000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111110001000000 11011111000000000011001111000000 00011110111100100000001100111100 00000000110011110010000000110011 00001010000011111101100000000011 11110100000000001101111000000010 00110011110000000000111101101000 00000011011100000000000001110000 00000000000000000000000000000000 10000000000110001110110010000000 10001011001100000011001111011010 00001101111101000010001000111101 11101000100011110110100000100010 00011011000010111001000000000010 11110110000000001000100010000100 00110010111000000000100110110000 00000010001100000000010000110000 00000000000000000000000000000000 10001000010001011000110000000100 10010011000010000010000011010000 00001000001100010001001010001100 00000010100000110001000000100000 00000000000010110001000000000110 11001100000000001011000000000000 00101000111000000000101100010000 00000010001100100000000101110000 00000000000000000000000000000000 11000000000001011100110000000000 10000011000000000010001011000000 00001001101100000000001010001100 00000000100010110000000000100010 00100000000010111010100000000010 11100110000000001010100010000001 00101010100000000000100100011000 00000010001100000000010001100000 00000000000000000000000000000000 01000000000101011110110000000000 11011011000000011011001011000000 00001100101100000000101110101100 00000001110010110000000010010010 00110000000010111001100000010111 11100110100000001111101010000000 00101010110000001000111110111000 00001011010100000000010001110000 00000000000000000000000000000000 11100000000000011010110000000000 11111011000000000011101011000000 00001111111100000000001101111100 00000100111111110000000000111110 11000000000011111101000000000011 11110100000000001101101100000000 00110011110000100000111111110000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11101011000000010011010011000000 01001100001100000001001111101100 00010000110010110000000000110110 01000000000011011011000010000011 10001100000000001101100011000000 00110010110000001000110010010010 00000011000101010000010000100000 00000000000000000000000000000000 11001000000001010011110000001000 10001111000000000010001111000000 01001010111101000000001011111100 00000011101011110000000010100010 11000000000010001011110011000010 10101100000000000000000100000000 00010110111100000010110010010100 00000010001100100000000001000000 00000000000000000000000000000000 11000000000001000100110000000000 10100011000000000010010011000000 01001001001110011000000011001100 00000000100010110000000001101100 00000000000110010011100000000010 01001100000000010001001000000001 01100000111101000000100100000100 00010010001110000000000001010000 00000000000000000000000000000000 00100000000100000101111000000000 10000111100000000010000111100000 01001010011110000000001011011110 01000000101000111001000001101001 01100100010110000111100000000010 11010110000000101000010010010000 00100100111000000000100001011000 00010110001011000000000001000000 00000000000000000000000000000000 01001000000010000100110000000000 11100011000000000011010011000000 00001101001100100000001011101100 00000000100000110000000000111100 11010000000011011011000000000011 11001000000000001101001001000000 00110000110001000000110100010000 00001011000100100000001000000000 00000000000000000000000000000000 01000000000101011011110000000000 11111111000000000011111111010100 00001111111100000000001111111101 00100010111111110000000000110111 11000000010011111110000000000010 10010100000000001111110000000100 00111011110001000000111111010001 00000011110100000000011001100000 00000000000000000000000000000000 00001000000001011110110001000000 11111011000000000011111011010100 00001110101111001000001100101101 00000000110010110111001000111010 00000000000011101011100000000011 00101100000000001101101000000000 10110010110010100000111100111000 00100011001010100000000001110000 00000000000000000000000000000000 01001000000110010001110010000100 10110111001000000010110111000000 00000011011101000100001010001100 10000000110101110011000000100001 11000000000010001111000000010010 00011100010000001010011000000000 00100001110000001000101101110000 00000010001100100000010001100000 00000000000000000000000000000000 00100000000000000001111000000000 10110111100100000010110111101000 00001010001110100000001000011110 00000000100000111000000000101001 01100000000110100111100000000010 00001110000000001000001010000000 01100001111000000000101111011000 00000010001000000000000000100000 00000000000000000000000000000000 01101000000001001100110000000000 10111011000000000010111011000000 00001011001100000000001010001100 00000000100100110000000000101000 11000000000010000011001100001010 00001110000000001010001110100000 00100000110000101000101100010101 10000010000100100000010000110000 00000000000000000000000000000000 11101000000101011110100000000000 11111010000000000011111010000000 00001110101000000000101100101000 00000000110010100000000000111011 10001000000011101110000000000011 00111011100000001100111010100000 00110010100100001000111111101100 00001011001110100000010001100000 00000000000000000000000000000000 01001000000000011010000000000000 11111000000000000011111000000000 01001111100000000000001111100000 00000000111100000000000000010110 00100000100011111000000000000011 11100000001000001110100000000001 00111110000000000100111110000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001000010000000010 11001001000000000001001001000000 01000110100110000000001111100100 00000000110010010000000000110100 01000000000011001001000000000011 11000100000000001000000100000000 00100010110000001000111110010000 00000011110000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000100 10001001000000000010001001000000 00101000100110010000001011100100 00000010100010010000000010100010 01000000000010101001010000000010 11100100000000001000100100000000 00100010010000000000101110010100 00000010111000000000000000010000 00000000000000000000000000000000 00111000000001010010010000000000 10001001000000001010101001000000 00001000100100000000001011000100 00000000100010010000000000100110 01000000000010001001000010000010 11100100000000001010100100000000 00101010010000000000101110010100 00000010110001100000000001000000 00000000000000000000000000000000 00101000000101000000010010000000 10000001001010000010100001001001 00001000000100100000001011000100 10110000100000010010100000100000 01001000010010100001000000000010 11000100100000011010000110100000 00101000010010010000101100010000 00000010110000100000000100000000 00000000000000000000000000000000 10111000000011000110000000000000 11001000011100100011101000010100 00001100100001010000001111100000 10000000110010000010000000110100 00000000100011001000010100000011 11100000000000101110100000000000 10111010000000000000111110000101 00000011111011100000001101010000 00000000000000000000000000000000 10011000000001011010010011110000 01111001000000000011011001000100 00001101100100010000001111100100 10110000111110010010100000111111 01001110000011111101000000000011 11110100010000001101110100010001 00110110010001001000111111010000 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010100001000 11111001010000000011111001000000 00001100110101000000001100100100 00100000110010011000000000110010 01001000000011111101010000000011 00010100000000101100000100000000 00110010010000101000111100010000 00100011110001100000000101100000 00000000000000000000000000000000 00111000000110001110000100001000 10111000010000000010111000011110 00001000100001000000001010000011 10001000110110001111100000100010 10011001000010110000001000010011 01100001000000001000100001000000 00100011100100000000101110000000 00000010110011100000010000110000 00000000000000000000000000000000 01001000010001011000010110000100 10110001011001000010110001000000 00101000000101100000001000000100 00100000100000010000000000100000 01010010100010110001000000000110 00000101000000001000010111000010 10100001010000000000101100011010 10000010110100100000000100110000 00000000000000000000000000000000 00011000000001001010010000001000 10111001000000000000110001000000 00000000100100000000001010100100 00000000100100010000000000100010 01000000000010110001011000000110 01100110001000101000110100000000 00100111010000000000101110010010 00000010110001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000010011111001000000 01000000100100000001001100100100 00000000110010010000000010110010 01010000000011111001010000100011 00100100000000001100100100000010 00110010010000000000111110011000 00000011111010000000010001110000 00000000000000000000000000000000 01001000000000010010010000000100 11111001000000000011111001000000 00001111100100000010001111000100 00001000111110010000000100111110 01100100000011111001000000000011 11000100000000001111000101000100 00111010010000010000111110110000 10000011110110100000000001100000 00000000000000000000000000000000 00001000000100001010000000000000 11101000000001000011001000000000 00001101000000010000001111100000 00010000110010000000000000110110 00010000001011001000000000000011 00100000000000001100100000000000 00110011000100000100111110000000 01000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000001 10001010000000000010001010000000 00001001111000000000001011101000 00000010100010100000010010100010 10000000000011011110000000000010 10101000000000101000101000000000 00100010100000000100101110100000 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000100 10100011000000100010100011000000 00001001001110001000001011001100 00000000100000110000000010100100 11000000000010000011000000000010 01000100000000011000001100000000 10100000100000000000101100110000 00000010000010100000000001010000 00000000000000000000000000000000 10000000000100010001111000000000 10000111101000000010100111001000 00011001011000000000001011011100 10000000100000110001000000100001 11100100000010000101000000010010 11010100000000001000010100000000 00100001100000010000101111111000 00100010001010000000000001000000 00000000000000000000000000000000 10001000000010001011111001000000 10101111110000000011100111110001 00001101011110000000001111011111 00100000110001111010100000110111 11101000000010000110100000000011 01010110000000001100011010000000 00110001101000000000111101111000 00000011001010100000001000000000 00000000000000000000000000000000 00001000000101011010110000000000 10111011001000001011011011011000 00001111101000000000001111101100 00000100111110110000000000111110 11010000010011111101000000000011 10100100000000001111100000000000 00111110100000000000111110110110 00001011110000100000011001100000 00000000000000000000000000000000 00000000000001001111111000100000 11111111110000000011001111110000 00001100110110000000001100111110 00000010110011111000000010110011 11110000000011111111100100000011 11110110000000001110111110000000 00110101101000000000110011111100 00000011000000000000000001110000 00000000000000000000000000000000 10101000000110001001110000000000 10110111000000000010000111000100 00001000010001000000001101111100 00000000100001110010000000100001 11000000000010110101001100010010 11010100010000001000010100000000 00100001100001000000100001110000 00000010001010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010000111000000 00001000011100000000001000011100 00000000100001110000000001100001 11000000000010110110000000100010 11010101000000001010011000000000 00100001101000000000100001110100 00000010000000000000000000100000 00000000000000000000000000000000 00100000000001001100110000001001 10110011000000000010000011000000 00001000100000000000001001101100 00000000100010110000000010100000 11110100000010110001010100000010 11000100010000001000000010000000 10100000100100100000100000110000 00000010000010000000010000110000 00000000000000000000000000000000 10101000000101010011110000000000 10111111000000001110001111000000 00101000101100000000001100111100 00000000110011110000000000110011 11110000000010111001010000000011 11100000000000001110101101001000 00110010010100000000110010110000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101000000110001111101100 00000000111110110000000000111110 11000000000011111001000000000011 11000000000000001111100100000000 00111110010000000000111110110100 00000011111000000000000000110000 00000000000000000000000000000000 00100001000100001111110000000000 11111111000000000001111111000000 00001111111100000000001100111100 00000000110011110000000000110011 11000010000011111100000010000011 00100000000000001100101000001000 00111111010000001000111111110000 00000010000000000100010000110000 00000000000000000000000000000000 10100001000001000110110000000000 10111011000000000010111011000001 00001011101000000000001010101100 00000010100010110000000010100010 11000000000010110001100000000010 00100001100000001000100000000000 00101110011000000000101100110000 00001010001000000000000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011100100000000001000101100 00000000100010110000000000100010 11000000000010111001000100100010 00100000000010001000101100000010 00101110010001000000101110110100 00000010101000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 01001001000100000000001010001100 00000000100000110000000000100000 11000000000010111001000000000010 00000000000000001000000100000000 00101100011000000000101110110000 00000010100000100000000100000000 00000000000000000000000000000000 00000000000011010111110000000000 11110111000000000011110111000000 00001111001100000000001100111100 00000000110001110000000000110011 11000000000011111000000000001011 00100000000000001100101000000000 00111110010000000000111110110000 00000011100000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111110100000010001111111100 00000000111111110000001000111111 11000000000011111101000000000011 11110000000000101111110000000000 00111111010000000000111101100000 00000011011010000000011001110000 00000000000000000000000000000000 11000000000001011111100000000000 11001101100000000011111111001000 00001111111100110000001000110110 00000000110011110001000000110011 00001100001010001101100000000011 11111100000000001100111110000000 00110111010000000000110011000000 00110011111100000000000001110000 00000000000000000000000000000000 10000000000100001010010000000100 10001001100000010010111111001110 00001011111101100000101000100110 00000100100000110010000000100010 00001100100010001011100000000010 11111101100010001000100110000001 00100010011000000000110110001000 00000010111000000000010000110000 00000000000000000000000000000000 10001000000001001100000000000001 10000011000001000010110011000000 00001011001100110000001010101100 00000000100000110010000000100000 10001000000010000001000000000010 11001100011000001010001100000000 00101110110000000011100000100000 00000010111000100000000101110000 00000000000000000000000000000000 11000000000101011000010000100011 10001011001000000010111011000000 00011011101100000000001010100110 00000000100010110000000001101010 00000000000010001011000000010010 11101100000000001010101111000110 00101010110000000000100110100000 10000010111100000000010001100000 00000000000000000000000000000000 00000000000101011110000101000000 11001001000000010011111011000000 00001111101100000100001110000100 00000000110010110000000001110010 01001000000011001001100000000011 11101100000000000110100110000000 00111100010100100000110010000100 00000011110000000000010001110000 00000000000000000000000000000000 11100000000000011011011000000000 11111101000011000011111011000000 00001111111100000000001101110100 00010000111101110000000011110111 00000100010011111111100100000011 11111100000001101101110100000001 00110111010001000000111110000100 00100011111110000000000001100000 00000000000000000000000000000000 01000000000100001010000100000000 11101011000000100011111011000000 00101100001100010000001110101100 00000000111110110000000000110000 11000100000011111001000000000011 11101100000000101110101101001000 00111110110000100010110010110100 00001011000100000000010000100000 00000000000000000000000000000000 11001000000001010010010111010000 10001011000000000010111111000000 00001000111101010000001000100100 10000000101111110000010000100010 00100000000010111011100000000010 11111110000000001000001101100000 00001110110110000000100010111000 01000000001100100000000001000000 00000000000000000000000000000000 11100000000001010100011100000010 10100001110000000010110011000000 00011001001110000000001010000100 00000100101100110000000000000100 00011000010010110001100000000010 11101100010000000010000100000000 00001100000100010000100100010000 00000010001110000000000001010000 00000000000000000000000000000000 01100000000000010000111000000000 10010101100010110010110111100000 11001001011110000000011000011110 00000000101101111000001000100101 11100000000010110101100010000010 11011110000000001010010110000010 00101100001000010100100101011010 10010010000110000000000001000000 00000000000000000000000000000000 01001000000010000000110010001001 11100001000001000011110011001000 10011101101100100000001110001100 00000000111100110000000010110100 10001000100011110001000000000011 11101100000000001110001100110000 00111100110000000000110100000000 00001001000100100000001000000000 00000000000000000000000000000000 01000000000111011011110100000001 11101101000000000011111111000000 00011110111101000001001111111101 00000000111111110001000000111011 11000000000011111101000100000011 11111101001000001101111100010000 00111111110000000000111011000010 01000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110110000000000 11001011000000000011111011001001 00001111101100010000001111100100 10000000111110110001000000111110 01000000010011111011001100000011 11101100100000101100100000000000 00111100010000000010110010110000 00010011001010100000000001110000 00000000000000000000000000000000 01001000000100010000110000000000 10000111001100000010110111010010 00001011011100000101001011011100 00010000101101110000001000101101 11000000000010110111000010000010 11011100000000001000010000000010 00101101010000000000100001110000 00000010000100100000010001100000 00000000000000000000000000000000 11000000010000000001111000000100 10000111100101000010110111101000 00001011011110100000001011011110 01000001101101111000000000101101 11100000000010110111101000000010 11001110100000001011011010001000 00101101011000000000100000111000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000101001100111000000000 10000011000000000010110011000000 00001011001100000000001011001100 00011000101100110000001000101100 11000000000010110011000100000010 11101100000000001011001010000010 00101100111000010000100000111111 00000010000100100000010000110000 00000000000000000000000000000000 11101000000101011010100000100010 11001010101000000011111010000000 10001111101000000100001111101000 00000000111110100000011001101111 10010001000011111010100000000011 11101000000010001111111000000100 00111111101000000000110011100100 00001011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000010 11111000000000000011111000000000 00000011100001000000001111100000 00000000111110000000000001111110 00000010010011111000000000000011 11100000000000000000100000100000 00111100000001000000111100000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110110001000010 11001001000000000001001001000000 10000011000100000010001100100100 00000000111110010000001001111100 01000001100011001001100100000011 11100100000000001100100110000010 00111110010001100000110010011000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010100000000 00000011000000000010001001000000 00001011100100000000001000101101 00000100101110010000000000101110 01000000000010001011100000000010 11100110000010001000100111000000 00101110010110000000101010011000 01000011001000000000000000010000 00000000000000000000000000000000 00011000000001010000010100000000 10001001010000100010101001000000 01011011100100000000001000100101 00000000101110010000000000101110 01000000000010001001000000000010 11100100010000101000100100101000 00101110010000000010100010010001 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010010100010 10001001000000000010100001001010 00001011000100101000001000000100 00000000101100010010001100101100 01001000100010000001000000000010 11000100101000011000000100000000 00101100010010000000101000010010 00000010000000100000000100000000 00000000000000000000000000000000 10111000000011000110000010010000 11001000000001000011101000001000 10001111101001110000001100100000 00000000111110000000000100101110 00010100001011001010000000000011 11100001110000001100100000000100 00111110000000000000110010000000 00001011001011100000001101010000 00000000000000000000000000000000 10011000000111011010010010100010 11111001000000011011011001001010 00001111100100000000101111100100 00000000111110010011100000111111 01000100100011111001000000000011 11100100000000001111110100000000 00111111010001010010111111010001 00000011101001100000011001110000 00000000000000000000000000000000 10011000000001011010011000000000 11001001000000000011111001000100 00001111110100100000001111100100 00010000111110010110000000111111 01001011000011000001000000000011 11110101000000101100110100000100 00111111010010000100110011010000 00000011001001100000000001110000 00000000000000000000000000000000 00111000000100001110001010000010 10001000000000000010110000010100 00001011100000100000001011100000 00000000101110000101000000101100 00011001000010001000000000000010 11100001000010001000100000000010 00101110000100000100110110000100 00001010000011100000010000110000 00000000000000000000000000000000 00001000000001001100010100100001 10000001000001000010110001001000 00011011000101001000001011000100 00010001101100010010000000101100 01000010000010000001000000000010 11000101100001001000000100000100 00101100011001000010100000010100 01000010100000100000000101110000 00000000000000000000000000000000 00011000000101011000110010010000 10001001000000000010111001000001 00011011100100000000001011100100 10000000101110010000000000101110 01000001000010001001000000000010 11100100000000001000100100000110 00101110010000000000100110010100 01000010100001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11001001000100000011111001000000 01001011100100000100001111100100 00001000111110010000000000111110 01000000001011001001000000000011 11100100000000001100100100010000 00111110011100000000110000010000 00000011101010000000010001110000 00000000000000000000000000000000 00101000000000011010110000111000 11111001100000000011111001000000 00001111100100001000001111100100 00000000111110010000000000111110 01000100000011111001000000000011 11100100000010001111100110000010 00111110011001000100111110010010 00000011010010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000100 11001000000000010011111000000000 10001101100000000000001110100000 00000000111110000000000011110010 00000000000011001000000010000011 00100000000000001101100010000000 00111110000010000010110010000000 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010101000001010 10001010000000100010111010000000 00101000111000000000001000101011 00000000101110100000000100000011 10000000000010001010010000100010 00101000000100001000111000000000 00101101100100001000101011100000 00000011100010100000000001000000 00000000000000000000000000000000 00101000000001010100111000000000 10010011000100000010110011000000 00011000001110000000001010001100 10000000101100110000000000100010 11100000000010000011010000000010 00100100000000001001001100000000 00101100010000000100100000011000 00000000010010100000000001010000 00000000000000000000000000000000 10100000000000010001110000110000 10010111000000000010110111101000 00011000010110001000001000010101 00000100101101111010001000100001 11010000000010001111100000000010 00010100000000011000011100000000 00101101010000001000101001110100 00010110101010000000000001000000 00000000000000000000000000000000 10101000000010000000101001000000 11010111100010010011110111101000 00001100111110000000001110011010 00000000111111111100001000100001 11100000001011000111100000001011 00111110000000001101011110000000 00111100011000000010110000111000 00001011011010100000001000000000 00000000000000000000000000000000 00001000000011011010100010000000 11101010001000000011111011000100 00001110100000000000001111100000 10000000111110110110100000111110 11000000000011111001011000010011 11100100000000001111101100000000 00111110010000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 01000000000001011111011001011000 11101111100100000011111111110000 00101100111010000000001111111111 00000000111111111000000000110011 01100000010011111111110000000011 11110110000000001100111110000000 00110001011001000010110011111000 01000011000100000000000001110000 00000000000000000000000000000000 10101000000100011001010011000000 10000101000000000010110111000000 00001000010000000000001011010100 00000000101101110000000000101001 11000000000010110111000000000010 11110100100000101101011100000000 00111101010011000000100001110010 00100010001010100000010001100000 00000000000000000000000000000000 00010000010000001001110000010000 10000111000000000110110011000000 00001000011100000000001011011100 00000000101101110000000000100001 01000010000010110110000000000010 11011100000010001000111100000000 00100001010000000100100001110000 00000110100000000000000000100000 00000000000000000000000000000000 01100000000101001100000100001001 10000000000000000010111011000001 00001000000000000000001011000100 00000001101100110000000000101000 11100000000010110000000000010000 11000100000000001000001100000010 00101000010000000000100000110000 01100110100110000000010000110000 00000000000000000000000000000000 10111000000101011010100100000010 11001000000000100011111111000000 10001100101100000000001111101110 00000000111111110000000000110010 11110100000011111000100000000001 11100100000000001000101100000000 00100010111000000000110000110000 00000011101011100000010001100000 00000000000000000000000000000000 10000000000000001100101100000000 11111011000000000011111011000000 00001111101100000000001111101101 01000000111110110000000000111110 00010000000011111010000100010011 11000100000000001111101100010000 00111110011000000000111110110000 00000001011000000000000000110000 00000000000000000000000000000000 10000000000100001111110000100000 11011100100000000011111111000000 00001100111100100000000110111010 00010000111100110000010000110011 11000000000011111101000000000011 11111100000000001100111100000000 00111111010000000000110011111010 00000011001000000000010000110000 00000000000000000000000000000000 10000101000001000110110000000000 10001010110000000010111011000000 00001000101000000010101000101001 10000000101110110000000000100010 00101000000010111001100001000010 11100100000000001000100110000010 00101100011000000010100010110000 00000010001001000100000000010000 00000000000000000000000000000000 10000000000001010010010000010010 10001000011000000010111011000000 00001000000000000000011000100000 01000000101110110000000000100010 01001001000010111000000100000010 11100100000000001000101110000000 00101110101000100100100010110000 00000010001000000000000001000000 00000000000000000000000000000000 00001000010001000000010000000000 10000001000000100010110011000000 00101000000000000000001010000000 00000000101100110000010100100000 00000000000010110010100000000010 11000100000000001000001110000000 00101110010000000000100000110000 00001010000000100000000100000000 00000000000000000000000000000000 10000000000011010100110000000000 11001000000000000011111111000000 00001100100100000000001100100000 00000100111111110000001000110010 01000000000011111000000000000011 11101100000000101100101100000000 00111110010000000100110010110000 01000011001000000000001101010000 00000000000000000000000000000000 10100000000111011111000000000000 11111100000000000011111111000000 00001101110000000010001101110000 00000000111111110000000010111111 00000000000011111100000000000011 11110100000000001111010000000000 00111111010000000000111101110000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000000011111011000000000 11011111000010000011001111000110 00001101110110010000001111110000 00000000111111011000001100001111 01100000100011001100001100100001 11110110000000001100110000000010 00110011110000000100110011110000 00000000001100000000000001110000 00000000000000000000000000000000 10000000000100001110010000000000 10001011100000010011011111011000 00001101100100100000001011100001 00100100101110011000000000101110 01100000000010001000011100000010 11100100000010001000100010000100 00101010111000000000100010010111 00010010001000000000010000110000 00000000000000000000000000000000 10001000000001011110110000000000 10010011000000000010000011000000 00001000000100100000001011000000 11000000101100010000010000100100 01000000000010000000000000000010 11000100000000001000000000000000 00100000101000000000100000010000 10000010001000100000000101110000 00000000000000000000000000000000 11000000000101011010111000100000 10001011000000000010010011000000 00001001100100000000001011100110 00010000101110111000000000101110 10100000001010001011100000000010 11100100100100000000100100000000 00101010100000010010100000011000 00100010001100000000010001100000 00000000000000000000000000000000 01000000000101010100011100000000 11011011000000000001001011000000 00001100100100000000001111100010 00000000111110011010000000110110 01100000000011001000110010000011 11100111000000000100101001010000 00110010110000000000100010010000 00000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011010000000000 11111111000000000011111011000001 00001111110101000000001111111000 00101000111111010000000000111111 01000001000011111101000000000011 11110100000011001111111000000010 00111110110100001000111111010000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11101011000000000011111011000000 00001101100100000000001111100101 00000000111110110100000000111110 11001001010011111000010001000011 00100100001010001100001101001000 00110010010000000000110010010000 00000011000100000000010000100000 00000000000000000000000000000000 11001000000000010010110000000000 10110111101000000010111111000000 00101100100100000000001011101101 00011000101110110000000001111100 11100000000010111011110010000010 10000100000000001000101111100000 00100000000111000000100010010111 00000011001100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000000 10100011000000010010110011000001 00001000000100000000001011000011 00000000101100111000010000101100 11010100000010110000100010000010 00000101000100001010000010000000 00100000110000000010100000010000 00000010011110000000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100001000010110111100000 00011000011110000000011011010110 01000000101101101100010000101001 11100000000010110100100001000010 10110110000010001010011110000001 00100001111010000000100001011001 01000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000110000000000 11100011000000000011110011000100 00001100000100000100001111001001 00100000111100110001100000101100 11001000000011111001000000000011 00000101000001001110001000000000 10110000110000000000110010010000 00000001010100100000001000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000100011111111000000 00001111111100000010001111110100 00010000111111100000000100111111 10000000000001111111000000000011 11010100010010001101011100010000 00111111110010010000111111010000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000110 01000011100100000000001111100100 00000000111010110000000000111110 11100001000011001011000000010011 00100110000000000000001100000000 00100010110000000000110010010000 00010011001010100000000001110000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111001000 00001011011100000010000011111100 00000000100001110000000100111101 11000000000010000101000001000011 01010000000000001000011100000001 00101000110000000000100011010000 00010010000100100000010001100000 00000000000000000000000000000000 11000000010000001001111000010100 10110111100001000010110111100000 00011011010110000100001011011111 00010000101001111100010000101111 11110000000010010011100000000010 00011111000000101000011110000100 00100001111000001010100001011000 00001010001100000000000000100000 00000000000000000000000000000000 01001000000101001100100000000100 10110011000000000010110011000000 00011011001100000000001011001110 00100000100000111000000000101100 11001000000010011011110000000010 01000101001000001000001110000000 00101000010000000000100000010000 00001010000100100000010000110000 00000000000000000000000000000000 11101000000101011011100000000000 11111010000000000011111010000000 00001111101000000000001111111001 00000100111011101000001000111111 10000000000011011110101100000011 00111010000000001100111011000000 10110011100110000010110010100000 00000011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000000100100 11111000000000000011111000000000 00001111100000000000001111100001 00000000111110001000000001111010 00010000011011101000010000000011 11100000000000101111000001010000 00111110000000100000111110000001 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11101001000000000011111001000000 00001111100100000000011100000100 00000000110010010000000000111110 01110000100011111001000100000011 00100100000001001111100110101000 00110000011000000000111000010001 00001011000000100000010000110000 00000000000000000000000000000000 10000000000001000100010000000000 10001001000000000010111001000000 00001011000100000000001000100100 00010000101010011000010000101110 01001000000010111001101000000010 00100111000000001011100111000010 10110110010100000000100010011000 00001010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10101001000000000010111001000000 00011011100100000000101000100100 10000000100010010010000000101110 01000000000110111001000000000010 10100100010000001011101101000000 00100010010001100000101010010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000010010000000000 10000001001000000010110001001001 00011011100100000000001000000100 10000000101000011000000000101100 01000000000010110001001000001010 00001100000000001011000100100100 00100100010010000010100000010010 00000010000000100000000100000000 00000000000000000000000000000000 10111000000011000110000101000000 11101000000010000011111000010100 00001111100000000000001000101001 01000000110010000000000000111110 00000000000011111000010100000011 10000001010000001111100000000000 00110010000000010000111010000101 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011011010000000000 11111001000000000011111001000100 00001111110100101000001111110100 01000000111111010000000000111101 01000000000011111101000100100011 11110100000000001111110100010000 00111111010001000000111111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010001000000 11111101100000000011111001010000 00001111100101000000001111110101 00000000010001010000000000111111 01000000000011110101001000000011 00110101000000001100110100000110 00110011010000000010110011010110 00001011010001100000000001110000 00000000000000000000000000000000 00111000000100001110000000000100 10111000010100000010111000011100 00001011100000100000000011101001 00000100110110000000000000101110 10000000000010111000001011000011 01100000000000101000100001000000 00101010000100010000100000000110 00000010000011100000010000110000 00000000000000000000000000000000 00001000010001011100010010010000 10110001000001000110110001001000 00011011000100100000001011000101 10000001100000010000000000101100 01000000000010110001010000000010 00000100100001101000000101000000 01100000010100000100100000010011 00100010010000100000000101110000 00000000000000000000000000000000 00011000000101011010010000010000 10111001000000000010111001000000 00011011100100000001001011100110 00000100100110010000000000101110 01000001000010111011001000010010 01000101100000001000100100001000 01101010010010000000100010011000 00000010000001100000010001100000 00000000000000000000000000000000 10100000000101011110010101100000 11111001000000000011111001000000 00001111100100000010001111100101 00000000110010011000000000111110 01000000000011111001001000000011 00100101000010001100100111000000 00110000010010001000100010010000 00001011011010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000001001111100100 00000000111110010010000100111110 01110001000011111001000000000011 11100110000000001111100100101000 00111110010000000010111100010000 10011011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000100000000 11001000000000000011001000000000 00001111100000000000001100100001 00000001110010000000100000110110 00000010000011111000000010000011 00100011000010001111100001000000 00110010000101100000111010000000 00001011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000000 10001010000000010010101010000000 00001011101000000001001000111001 00000000100011100000010000100011 10101001000010111110010000010010 00111000000001001011011000100001 10100011100000000000100011100100 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000010 10000001000000000010010011000000 00001011001100000010001000101110 10000000100000110000000000100100 11100000000010111011110000100010 00001100000000011011001010000000 00100100101000001000101000110000 00001010000010100000000001010000 00000000000000000000000000000000 10100000000000010001111011000000 10000011100000000010110111000100 00001011011110100000001000001101 00001000100101111000000000100001 11000000000010110111010000000010 00011100000000001011011000000000 00100101010000000000100001010000 00010010001010000000000001000000 00000000000000000000000000000000 10101000000010000011111000000000 11000101100000000011010111100010 01011111111110101000001100011110 00000010110001101000000000110101 11100000000011110111100000001011 00010110000000001111000010000000 00110100111000001000111001111000 00000011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011101011011000 00001111101101110000101111100100 00010100111010110000000100111110 11000000100001111001000000000011 11100100000110001111100000000001 00111010010000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 11111101100000000011111111100000 00001000111110000010001111110110 00000000111101111000000100111011 10100100000000111111101100000011 00111110000000001111111010000000 00110011111010000000111111111000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001110001000000 10110111000000000010111111000001 00001101011100100000001011111100 01000100110001100010000100100001 11000000000010110110000101000010 00011100000001001111010001100100 00110101010000000000101101000001 10000010101010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110101000000000010110111000000 00001000011100000010001011010000 00000000101001110000001000101001 11000000000010110101001000000010 00010000001000001011110000001000 01100001010110000000101101110000 00000010000000000000000000100000 00000000000000000000000000000000 00100000000101001100110000010000 10110011000000000010110011000000 00001001001110000000000011000000 00000000100000110101100000100000 11011100000010110000000000000010 00000011000000001010000010000000 01100000010000000000101110101000 00000010100010000000010000110000 00000000000000000000000000000000 10101000000101011011110000000000 11111001000000000011111111000000 00001100111110001000001111101110 01000000111010011000000000111010 11100000000011111001101000001011 00101100000000001011001011000000 00100010101100000000111110111000 00001011001010100000010001100000 00000000000000000000000000000000 10000000000000001110110000100000 11111001000000000011110011000000 00001111101100000001001111100001 01000000111110110000000100111110 01000000000011111001010001000011 11101001001000001111101000000000 00111110111000000000111110000000 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001111110000000000 11111101010000000011111111000000 00001100111100000000001101011100 00000000110011110000000000110011 11000000000011110010000010000010 00111101000000001000110000001000 00110011110000000100110010110000 00000011000000000100010000110000 00000000000000000000000000000000 10000001000001000110110000000000 10111001000000010010111011000000 10101000101100000000001000100011 00000100101000101100110000100010 01100000010010111000010000000011 01001011000000001000100011000100 00100000111000000000100010100000 01000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10111001000000000010111011000000 00001000001100000000001001100111 00000000100010001000000000100010 10100000000010111001100000000010 10101100001000001010101010000000 00100010111000000000100010110000 10000010001000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10110001000000000010110011000000 00001000001100000001001000000000 00000000101010110000000010100000 01000000000110110000000000000010 01101000000000001010001000000001 00100000110000000000100000010000 00001010000000100000000100000000 00000000000000000000000000000000 00000000000011010110110000000000 11111001000000000010111111000000 10001100111100000000001101100000 00000000110010110000000000110010 01000000000011111000000000100011 10101000000001001110100000000000 10110010010000000000110010110000 00000011000000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11111101000000000011111111000000 00001111111100000000001111110000 00000000111111110000000000111111 01000000010011111100000000010011 11111000000000000101010100000000 00111111010000000000111111110000 01000011111010000000011001110000 00000000000000000000000000000000 11000000000001011101111000000000 11011111100100000011001110100000 00011111111101101010001100111100 00000000110011010000000000110011 00000100000011001111000000000001 01110100000010001101011100000000 00110011111000000000110001111000 00000011111100000000000001110000 00000000000000000000000000000000 10000000000100001110111000001000 10000001001000001010001000100000 00001011111101000000011000111100 10100010100010011000001000100010 00001000000011011011100000000010 00010100000001001010101111010000 00110010011000000000100010111000 00000010111000000000000000110000 00000000000000000000000000000000 10001000000001011100100000000000 10111011000000000010000011100000 00000011001100100000001000001100 01000000100000010000000010100000 00000000000010000000000000100010 01000100000010001001000100000100 00100110110000000000100000110000 01000010101000100000000101110000 00000000000000000000000000000000 11000000000101011010110001000000 10001011100000000010001000000000 00011011101100000000001000101100 00000100100010010010000000100010 11000000000010011001010001000010 00100100000000001010100100000010 00100010110000000010100010111000 00000010111100000000010001100000 00000000000000000000000000000000 01000000000101011100110000000000 11011011100010001011001010000100 00001011101100000100001000101100 00000000100010100110000000110010 00100000000111000010100000000011 01100110000000001101100100000000 00110100110000000000110010111010 00000011110100000000010001110000 00000000000000000000000000000000 11100000000000011011110000100000 11111111000000000011111100000000 00001111101100000000001111111100 00000000111111000000000000111111 01101000001011101110101001000011 11110110010000001111010100000010 10111111111001000000111111110000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010010001000000 11011011000000000011111011000000 00001111101100000011001100001100 00000001111110100100000000010001 00000000000011101000000000000011 10100110000010001100100100100000 00110010110000100100111110010010 00001011000100000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10100011000000010010001000000000 00001011111100000000001000111101 11000000101101000000001000100010 11000001010010001000000000010010 00100101000000001000100110100000 00100010110000000000111010111100 10000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100111000000000 10010011000000001010110000011000 00001011101100000001001010001100 00000000101100110000001100100000 00000001000010100011000000000010 00100101100000001000001111000000 00100000111100000000101100110000 00000010001110000000000001010000 00000000000000000000000000000000 00100000000000010011111001001000 10100111100000000010000101100000 10001011011110010000001010011110 00000001101100011000000000100001 00100000110000000011100100000010 00010110110000001000011110010000 00100001111000000000101001111001 00000010000010000000010001000000 00000000000000000000000000000000 01001000000010000000110101000000 11010011000000000011110011000100 00001111001100000000001110001100 00000100101100110000000010110010 11000000010011100010000000001011 10001100100000001100000100000000 01110000110000100000111100110000 00000011000100100000000000000000 00000000000000000000000000000000 01000000000111011011110001000000 11111111000000000011111111000110 10001111111100000000001101111100 00000000111111010000100010111111 11000000000011111111010001000011 11111100100000001111110100000000 10111111110000000000111111110000 00000011110100000000010001100000 00000000000000000000000000000000 10101000010101011100110000001000 11011010000000010011111000001010 00001111101111100000001101101101 00100000111110110000000000111110 01000000100011110011000000000010 01101100101000001100100100000000 00110110110000000100111100110000 00100011001010100000000001110000 00000000000000000000000000000000 01001000000100010001110000000000 10001111000000000010000101000000 00001011011100010010001000011100 10000000101101010010000010100001 01000100000010110111000000000010 00001100000000001000010100000000 00100001110000000000101101110000 00000010000100100000010001100000 00000000000000000000000000000000 11000000000000001001111000100000 10010111100000000010110111101000 00001011001110010100001001011110 01000000101100111100000000100101 11100000000010110110100000000010 01011110000001001000010110000000 00100001111000000000101101111100 00001010001100000000000000100000 00000000000000000000000000000000 01001000000101001100110100000000 10000011010000000010000011000000 00001011001100000010001000101100 00001000101100011100000000100000 11000000000010110011010000000010 00001110000010001000000100000100 00100000111000000000101100101000 10000010000100100000010000110000 00000000000000000000000000000000 11101000000001011001101000000000 11011110100001000011111010000000 00001011101000000000001101101000 00001000111111100000010000110110 10010000000011111010000000000111 01101010100000101100101000100000 00110011101000010000111111101100 00000011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000110000000 11111000000100000011111000000000 00001111100000000010001111100000 00000000111110000010000000011110 00000010000011110000000000000011 11100000000000001111100000000000 10111110000001000000111110000100 00000011110100100000000000110000 00000000000000000000000000000000 00001000000000001110011000001000 11101001000010000011011001100000 10001111100100000000001111100100 00000000010000011010000000110010 11000000000011101011000010000011 00000100000000001100000100000000 00110010011001000000111010011010 00000011000000100000010000110000 00000000000000000000000000000000 10000000010001000110010001000000 10000001000000000010001011000001 00001011100100000010001011100100 00000000100010011000000000100010 01000000000010001001000000000010 00100100000010001000100101010000 00100000010000000000100000011100 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000010 10101001000000000010111001001000 00001011100100000000001011100101 00000000101010010000000000100000 11000000010010101001000000000010 00100100000000001000100100001000 10100010010000000100101010010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10001001000000000010100001000000 00001011000100101000001011000100 10110110001000010010001000100000 01001000000010000001001000001010 00000110100000101000000100100000 10100000010000000000100000010000 00001010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000000000000 11101000000000000011111010000000 00001111100000100000001111100001 11000000111010000000000010110010 00000000010011101000000000001011 00100001010000101100100000000100 00110010000000000100111010100000 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011111010000000000 11111101001010010011011001000000 00001011100100101000001111100100 00000000110111010001000000111110 01001111000011111001000100000011 11110100010000001111010100010000 00111111010000000000111111010000 00000011111001100000011001110000 00000000000000000000000000000000 00011000000000011111010000000000 11110001010000011011101001000000 00001111100101100000011111110101 00000000110001010010000000110110 01001010010011111101001000000011 00110101000000101100110100101000 10110010010000000000111111010000 00000011000001100000000001110000 00000000000000000000000000000000 00111000000100001110000000000100 10111000000000000010001000000000 00001111100000000000001011100001 00000000100010000101000000101010 10011000000010111000000001000010 00000001000000001000100001000000 00100010000000001000101110000000 00000010100011100000010000110000 00000000000000000000000000000000 00001000010001011100011000010000 10110001001000000010100001000000 00011011000101100000001011001101 10000000100000010000000010100100 01000011000010110001010000100010 00001101100000001000000100000000 00100000010000000000101110010000 00000010000000100000000101110000 00000000000000000000000000000000 00011000000100011010011000000000 10111001000010100010001001000010 00001010100100000001001011000100 00000000100010010000000010100010 01000000000010111001000010010010 00100100000000001000100100000000 00100010010000000000101110010100 00000010100001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11111001110000000011101001000000 00001011100100000000001011100100 00000010100010010000000010110110 01110000000011111001010000001011 00100100000001001100100100000000 10110010010000000000111100010100 00000010001010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000000 01111001110000000011111001001000 00001111100100000000001111100100 00000000111110010000000100111110 01001001000111111001100100000011 11100110010100001111000100100000 00111110111001000000111110010001 00000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11011000010000000010001000010000 00001110100000000000001100100000 00000000110100000001000000110010 00010000001011000000011000000011 00100000000000101110100000010000 00110110000000000000111110000000 10000011110010100000010000100000 00000000000000000000000000000000 00101000000001010011101100000000 00001010000000000010001010100100 00001011101000000000001000111000 00000000111010100000000000110110 10000000000010001110110000000011 01111000000000001000111010000000 00100010101010000000101111101100 01000010110010100000000001000000 00000000000000000000000000000000 00101000000001010100111110010000 10011011000000000010000011010000 10001011001100000000011000001100 00000001100100110000000001100000 11000000000010000000100000000010 00101100000000001010001010000000 00100100001000000000101100111000 00000010110010100000000001010000 00000000000000000000000000000000 10100000010000010011101000100000 10001111001000001110000110000010 00001011011110000000001000010000 00000000101111110000000000100101 11101100000010000100000010000010 01011100000000001000011100000000 00100001010000000000101101110000 10000010111010000000000001000000 00000000000000000000000000000000 10101000000010000001111000000000 11010111101100000010000111100010 00001110001110000000101100011110 00000000110101011000010100110000 11101010000011000000100000000011 00011110000000001110011110000000 00110101001001000000111101111000 00000011111010100000001000000000 00000000000000000000000000000000 00001000000111011000110000000000 11111011001100000011111010001000 00001011101101010001001111100100 00000100111010010000000100111110 11000000100011111000000000000011 11101000000000001111001100000000 00111110110010000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000010001011101111011000100 11010111100000000011001101100000 00001111111111000000001110111110 01000000110011111001000010110011 11100000000011111110100000000011 11111110000000001111111010000000 00110011001000000000111111111000 00000011100000000000000001110000 00000000000000000000000000000000 10101000000000011001110001000000 11010111001000000011010101000000 00001110011100000000001000010001 00000000100001110011000000100001 11001000000011110110001000000010 11010100000001001011011100000000 10100001010000000000101101110000 00000010111010100000010001100000 00000000000000000000000000000000 00000000010000001001110110010100 10111111000000000010000101000010 00001010001100000000001011011100 00000100100100010000000111100001 11000000000010110110000000000010 11011100000000001011011100000000 00101001100000000000101101110000 00000010100000000000000000100000 00000000000000000000000000000000 00100000000101000100110000000001 10010011000000000010010001100000 00001010001100000000001001000100 00000000100100010000000001100000 11000000000010110010010000000010 11000000000000001011001100000000 00101000111000000000101100100100 10000010110010000000010000110000 00000000000000000000000000000000 10101000000101011000110000000000 11111111111000001011001011100000 00001110111100000000001111101100 00000000110110110000000000110011 11000000000011111001000000000011 11101100000000001111101100000000 00111000001000100000111110111010 00000011101010100000010001100000 00000000000000000000000000000000 10000000000000001110111100000000 11111011000010000011111011010010 00001110101100000000001110101000 00000000111000110001000000111100 11001100000011100001001000000111 11100100000000001111100100000000 00100110010000000000111110110000 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001111110000010000 11011111000000000011011100100100 00000100111100000010000100101011 00000000111111011100000000110111 11000000000001001101100000000011 00111000100010001110001100000000 00110011100000001000110011110000 00000011000000000100010000110000 00000000000000000000000000000000 10000001010001000110110000000000 10000011000000010010000000110000 00001010101100000000001000101001 00000000101110010000000000110010 11000000010010001001010010011010 00100010000000001011101111000010 00100010111000000000100000011100 00000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010110110010000 10011011000000100010011011000011 00011010001100000000001010100100 00000000101110010000000000100110 11000000101010101000000100000010 00101100000001011011101111000000 00100010000001000000100010111000 11000010001000000000000001000000 00000000000000000000000000000000 00001000010001000010110000000000 10001011000000000010001011000000 00011010001100000000001010000000 00000001101100010000000010100000 11000000000010100000000000000010 00000110000000001011001100000000 10100010010000000000100000110000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000001010110010000000000 11011111000000000011011000000000 00011110111100000000101110100000 00000000111110010000000000110111 11000000000011101000000000000011 00101000000001001110101100000000 10110010100000000000110010110000 00001011000000000000001101010000 00000000000000000000000000000000 10100000000110011111110000001010 11111111000000000011111100000000 00001111111100000000001101110000 00000000111111010000000010111011 11000000010011011100000000000011 11110000000000001111111100000000 00111111110000001010111111110000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011101000001000000 11001111000110000011111111000000 00011111110010000000001101110010 00000000110001011000000000111101 01100000000011111100001100000011 00010000000000001100111100010000 00110011111000000000110011110010 00000011001100000000000001110000 00000000000000000000000000000000 10000000000100001110010110001010 10001111000000000010111111110100 00000011100000100000001000100010 00000000000010111000010100101110 01100000010010111000001000001010 00100010000000001010111101010000 00100010110000000000101000100100 00010010001000000000010000110000 00000000000000000000000000000000 10001000000001011100000100000000 10100011000000100010110011000000 00011011001000001100001011000000 00000000100000110000001000101100 01000000000110110000000100000010 10001000000000001000001100000010 00100000110000000000100100101001 00000010001000100000000101110000 00000000000000000000000000000000 11000000000101011000000000000000 10101011000000000010111011000000 00001011101001100000001010101000 10000000100010110000100000101110 10100000010010110011100010000010 10101010001000001010101100000000 00100010110000000100101110111000 00000010001100000000010001100000 00000000000000000000000000000000 01000000000101011110001000000000 11101011000000000011111011000000 00001011100110000000001111100011 00100000110010111101000000111110 01100000000011111000100000000010 10100010000000001100101100000000 10100010110000000000110110100000 00000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011010010000000 11011111000000010011111111000000 00001111110000000000001101110010 00000000111111111000000000111111 01000001000011111000000000100011 01010000000001101111111100000100 00111111111001000100111011100000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010000000000000 11101011000000000011111011000000 00001111101101000100001111100101 10000000111110111010000000110010 11000000000011011001010000010011 00100001000000101100101110100000 00111110110010000000110000110000 00001011000100000000010000100000 00000000000000000000000000000000 11001000000000010010000000000000 10001111000000000010111111000000 01001110101000000000001011000011 10000000101110101100000000100010 11100010000010001011000000000010 00101000100000101000111100000100 00101100111100000000110110110000 00001010001100100000000001000000 00000000000000000000000000000000 11100000000001010100000000000000 00100011000000000010110011100000 00001011100000000000000011000000 00000000101100110100000000100000 11100000000010010000000000100010 00001001001000001000101101000000 01101100010101000000100000010000 00000010001110000000000001010000 00000000000000000000000000000000 00100000000000010011011000000000 10000111100000000010110111100010 00001010011110000000001011011010 00000100101101111000000000100001 11100000000010010101100000100110 00011110010000001000011110010000 00101101111000000000100101011101 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000000000000000 11100011000100000011110011000000 00001111000000000000001111000100 10000000101100110001000000110000 11000000010011010000000000000011 00001000010000001100001100000000 00111100010000001000110000010000 00000011000100100000001000000000 00000000000000000000000000000000 01000000000111011011000000000000 11111111010000000011111111000000 00001111111100010000001111110000 00000000111111110001011010111111 10000000000011101111000100000011 11111100010000101111111101000000 00111101110000000000111111010000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110000000000000 11001011010100010011111011001010 10001111100100000000001111100000 00000000111110110000000000101110 11000000100011101011000000000011 00100000000000001100101111010001 10110000010000000000110010110000 01000011001010100000000001110000 00000000000000000000000000000000 01001000000100011000010000000000 10000111000000000010110111010000 00001011011100000000001011010000 00000000101101110000000000101101 11000001000010001101000000010010 00011000000000001010111100000000 00100001110000000000111000110000 00001010000100100000010001100000 00000000000000000000000000000000 11000000000000001001001000000010 10000111101000000010110111100000 00001011010110000000001011010010 00000001101101011000000000101111 11100000000010000111100000000010 00010010000000001001011110000000 00100001111000000000100001111000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000101001110100000000000 10000011000000000010110011000000 00001011001100000010001011000001 00000000101100110000000001101100 11000000000010000011110000001010 00001100000000001011001100000001 00100000111000000000101000111000 00000010000100100000010000110000 00000000000000000000000000000000 11101000000101011011100000000000 10001010000000000011111010000000 00001011111000000000001111011000 00000000111111100001100000111111 10010010000011001110101000000011 00011000001000101101101000000000 00110010101000000000110011101010 00000011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000001000000 11110000000000000011110000000000 00001111100000000000001111100001 01000000111110000000000100111110 00000010001011111000000010000011 11100010000000001110100000000010 00111110000001000000111010001000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11001001000000000011001001010000 00001100100100001010001111100100 01100000110010011000001000111110 01101000000011000001000000010011 00100100000000101100100111000000 00101110011000000000111010010000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000000 10001001000000001010001001100000 00001010100100000000001011100101 00100000100010010000000100101100 01100000001010001001000000100010 10100101000001001101100110000001 00101110010000000010100000010000 00000011011000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000010 10001001000000000010001001000000 00001000100100000000001011100100 00000010100010010001000000101110 01000000000010001001000000000010 00100100010000011000100100000000 00101100010001010000101010010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010010000000 10000001001000000010000001001000 01001010000100000000001011100100 00000000100000010000000001101100 01000000000010000001001000000010 10000100100000001001000110100100 00101100011000000000100010110010 00000010010000100000000100000000 00000000000000000000000000000000 10111000000011010110000101000000 11001000000000000011001000000000 00001000100001010100001111100000 00000000110010000000000000101110 00000000000011001000010100000011 00101000000000101100100001010000 00111110000101000100111010000101 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011111010001000000 11111001001110000011111001000100 01001111110100000111001111110100 00010000111111010000000000001101 01000000010011111101000100100010 11010100010000001111100100010000 00111111010000000000111111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010000000000 11101001000000000011001101000010 00001111100100000000001111110100 00000000111110010000010000110010 01000000000011111101001000100011 00110100000001001100110101100000 10100011010100000000110011010010 00000011000001100000000001110000 00000000000000000000000000000000 00111000000100001110100111000000 10001000011010000010001000010000 00001011100000000000001011100000 00000000101110000000000010100010 00000000000010111010010000000011 01100001000001001000100001000000 00110110000000001000111110000010 10000010100011100000010000110000 00000000000000000000000000000000 00001000000001011100010000100000 10100001010000001010000001000000 00001011000100101001011011000100 00010000101110010000000000100000 01000000000010100001001111000010 00000101000000101000000100010001 00100010010010010000100000010100 00001010010000100000000101110000 00000000000000000000000000000000 00011000000101011010010000000100 10001001000000000010001001000000 00001011100100000010010011100100 00000000101110110000100000100010 01000000010110111001000000000010 01101100000000101000101100000000 00100110110000000000101110010000 00000010110001100000010001100000 00000000000000000000000000000000 10100000000100011110011101000000 11101001000000000011001001000000 00001111100110000000001111100110 00110000111100011101000000110010 01000010000011101001100100010011 00100100100000001100100100000000 00110000011000000000110010010010 00001011011010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000000 01110001000000000011111001000000 00001111100110010000001111100100 10001000111110111000000000111110 11110001000011110001100001000011 11000111000000001111100100000000 00111110011010000000111110010000 00000011100010100000000001100000 00000000000000000000000000000000 00101000000100001000000100000010 11001000000000000011001000000001 01001111100000000000001111100000 00010000111110000100000000111110 00010000000011111000010000000011 00100001000000001100100000000000 00110010000000100000110010000100 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000000 10001010000000000010001010100000 00001011101000000000001111111010 00100000101110100100010000101110 10001000100010111010000000000010 00111001000000101101111010000000 00111011100000000000100011101001 10000010100010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10000011000000000010000011000000 00001011001100000000001011001111 10000000101100110010000001101100 00100000000010110011100000100010 00001100100000001000101100100000 00100000111000000000100010110100 00000010000010100000000001010000 00000000000000000000000000000000 10100000000000010001110010010101 10000111001000000010000111010000 00001011011100000000001010011100 00000000101101000000010000101101 10000000000110110111010000010010 00010000000000001001001101000000 00101101010000100000100001110000 00000010001010000000000001000000 00000000000000000000000000000000 10101000000010000000111001000000 11001111111100000011000111100000 00001011011110000000001011011010 00000000111101011001000000111101 10100100000011111111100000001011 00010110000000001100010110000000 00110001111000000010110000111000 00001011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110110000000 11111011000000001011111011000000 00001111101100010000001111101100 00000100111110000100000000111110 10001000000011111011010000000010 11000000000001001011100100000000 00111000010000000000111110100000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000100000 11001111100000000011101111100000 00001100011110010000001110111110 01000000111011101001000000111011 00100000010011001101110000100011 01111010000000001100111110010000 00110001101000000000110011111000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001110001000000 11010111000000000010000111000000 00001101011100000001001000011100 01000000100001000001110000100001 00000001000010000101000000000010 00010000000000101000010000110000 00110101000010100000101011110000 00000010101010100000010001100000 00000000000000000000000000000000 00000000000000001000110000000000 10000111000000000010100101000000 00001000111100000000011010111100 00000001101001000000000000101101 00000000000010000101100010000010 00010001010000101000001100000001 00100001010000000000100001110000 00000010000000000000000000100000 00000000000000000000000000000000 00100000000101001100110100100000 10010011000000000110000001000000 00001001001101000000001000001110 00000000100000001100110000100100 00011000000010000001101000100010 00000000010000101000100000000000 00100100000000000000101000100100 00000010100010000000010000110000 00000000000000000000000000000000 10101000000101011011110000000000 11001111000000000011100011000000 00001100111100011000001110101101 00100000111010000100000000111110 10000000000010001001100000001011 00000001000000001100101100000000 00110010110000000000110010110100 00001011001010100000010001100000 00000000000000000000000000000000 10000000000000001100110001000010 11111011000000000011111001000000 00001111101100000000001111101100 10000000111110000000000000111010 10000100001011111001000000000011 11100000000000001111101101000000 00111110010000000000111110110010 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001111110000000000 11001111000000000011111011100000 00001101111100000000001100110000 00000000011111001000000000111111 10000000000011001101000100000010 00110100000000001000110000000010 00110011011010000010111011110000 00000011100000000100010000110000 00000000000000000000000000000000 10000001000001000110110000000000 10101011000000000010111001100000 00001000001100000000001010100110 00000000101110000100000000101100 10000000000010001001000000000010 00100010000000001000100011000000 10100010010000000100101010101101 10000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10001011000000000010111011001000 00001001101100000000001000101110 00000000101110000001010000101110 00001000000010100011000000000010 10100010000000001010100110000100 00100000110000001000101000000000 00000010101000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10100011000000000010110001000000 00001000101100000000001010000100 00010000101100000000000001101100 00000000000010100011000000001010 10100000000000001010000000000010 00100000010000000000100000000000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000011010111110000000000 11000111000000100011111001000000 00001101101100000000001100100100 00000000111110000000000000111110 00000000000011100111000000100011 10100000000000001110100000000000 00010010010000000000111010000000 00000011100000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111101000000 00001111111100000100001111010100 00000000111101000000000000111101 00000000000011011111000000000001 01010000000001100101110000000000 00111111010000001000111111000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111101000000000 11111111001000000011001101000100 00001100111010000001001111111010 00000000111111101000000000111111 11000100000011111100000000000011 00111000000000001100110000000000 00110011000000000000110011100000 00000011001100000000000001110000 00000000000000000000000000000000 10000000000100001110101000000000 10111111110100000010001101000000 00001000100010000000001011101010 00000000101110101000000000001111 11011000000010111010100001000010 00101110000010001000101010000010 00100010101000000000100010101000 00000010101000000000010000110000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010000001001000 00001010001100000000001011000000 00000000101100100000000000101100 11000100000010110001000000001010 00000000000000001000000000000000 00100000010000000000100000110000 00000010001000100000000101110000 00000000000000000000000000000000 11000000000101011010100000010000 10111011000000000010001001000000 00101010100000000000011011100000 00000000101110100000000000101110 11000000010010111011000000010010 00101110001000001000101100000000 00100010110010000000100010110000 00000010101100000000010001100000 00000000000000000000000000000000 01000000000100011110100000000000 11111011000000000011001001000000 00001110100001011000001111101001 00000100111110110100100000111110 11000000000011111000000000000011 00101001000000101100100100000000 00110010000100100100110010001001 10000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011110001000000 10111111000000100011111001100100 00001101110010000000001111111010 01001000111111111001000000111111 11000000000011111110000000000011 11101000000000001111011100000000 10111101101000000000111100000000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11110011000000000011111111000000 00101100100100110000001111100101 00100000111110110100001000111110 11000000000011100011010000100011 10000001000000101100101100000000 00110010010000000000110010010101 00000011000100000000010000100000 00000000000000000000000000000000 11001000000001010010111001000000 10111111000001100010111011000000 00000000100000000000001111101110 10000000101110110001100000101111 11000000000010001011000000000010 00101000000000001000101100000010 00110110110010001000100010010000 00010010001100100000000001000000 00000000000000000000000000000000 11100000000001010100001100000000 00110011000000000010111001000000 00001000001011000000001011000101 00000000101100101100000000101100 11000000010010100000000001001010 01000000000000001000000000000000 10100000000000000000100000101010 00000010001110000000000001010000 00000000000000000000000000000000 00100000000000010001001000100001 10110111100000000010110101100000 00001000010110000000001010010110 00000000101101111000010000101101 11100000100010000011101100000010 01010110000000001000001010000000 00100100111000000000100001101000 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000010000000000 11110011000000000011110001000000 00001100001100000000001011001000 00000000111100100000000000111110 11000000000011100001011000000011 11000000100000001100000000000000 00110000010000000000110000110000 00001011000100100000001000000000 00000000000000000000000000000000 01000000000111011011000000100000 11111111010000000011111101000000 10001111110100001001011111111000 00001000111111110000000000111111 11010000010011111111001000010011 10110100000000000111111100000000 00111111110000000000111111110000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110100100100000 11011011101100000011001101001000 00001111101001100000001111100101 10001000111110000110000000111110 11001000000011111000000000000011 00111010000000001110100100000000 00110010101000000000110010010000 00000011001010100000000001110000 00000000000000000000000000000000 01001000000100011001110010000000 10110111001000001010000101000100 00001011011100001000001011010101 10100000101101010010101000101101 11010000000010110011000000000010 00001100000000001000011100000010 00100001110000000000100001110000 00000010000100100000010001100000 00000000000000000000000000000000 11000000000000001001111000000000 10010011100000000010000101100000 00001011011110000000001011011110 00000000101101001001000000101101 11100000000010110111100000001110 00010010000000001010001110000000 00100000111000000000100000011000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000101001100110101100000 10110011000000000010000001100000 01011011001100000000001011001100 00000000101100010010000000101100 11000000000010110011000000000010 00001101000000001000001101110000 10100000111000000010100000111001 01001010000100100000010000110000 00000000000000000000000000000000 11101000000101011010101000001000 11011010000000000011001010101000 00001111101000100000001111101000 10000000111110100000100000111110 10000000000011111110100000000011 00111000110000101110011011000000 00110011101010000000110011100100 00000011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100001000000001111100010 00000000111110000000000000111110 00000000010011110000000100000011 11100000000000001111100000000000 00111110000000000000111100000000 10000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110011010000000 11111001000000000011111001000000 00001111100100000000001011100100 00000000111110011000000000111110 01000000000011101001000000100011 00100100000000001111100100000000 00110010010000000000111110010000 00000001000000100000010000110000 00000000000000000000000000000000 10000000000000000110111000000000 10111001000000100010111001000000 00001011101100001000011111101100 00000000101110111000000000101110 01000000000010001001100000000010 00100100000000001011100101000010 00110010010100000100101110010100 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000001 10111001000000000010111001000000 00001011100100000100001011101100 00000000101110010010000000101100 01000000000010101001000100000010 00100100000011001011100100001100 00100010010000100000101110010000 10000010100001100000000001000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001001010010010110001001000 00001011000100000000001010000100 00000000101100010000000000101100 01001010000110000001001000000010 00000100100000001011000100100000 00100000010010000000101100010010 00000010100000100000000100000000 00000000000000000000000000000000 10111000000011010110000000000100 11111000001000100011111000000000 00001111100000000000001011100000 00000000111110000000000000111110 00001000000011101000000000000011 00100000000000001111100000000000 10110010000000000000111110000000 00001011101011100000001101010000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111101001110 00001111100100000000001111100100 00000000111110010000000000111110 01001010010011111101000100001011 11110100010000001111110100010000 00111011010001000000111111010001 00000011011001100000011001110000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000010000011011001000100 00001111100100000101001111100100 00000001111110010000001000111110 01011000000011111001001000000011 00100100000000001100100100000000 10110010010010000000110010010010 00000011110001100000000001110000 00000000000000000000000000000000 00111000000100001110000000000000 10111000010000000010001000010100 00001011100000000000001001101000 00000000101110000000000000101110 00001000000010111000000000000010 00100001010000001000100001010000 00100010000100000000100011000101 00000010110011100000010000110000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010010001001000 00001011000110000000001011000100 00001000101100010000000000101100 01011000000010110101110000000110 00010100000000001000010110000000 00100001011001000000100001011000 00000010110000100000000101110000 00000000000000000000000000000000 00011000000101011010010000100100 10111001000000000010001001000000 00001011100100000000001001100100 01000000101110010000000000101110 01000000010010111001000100010010 00110100000100001000110110000000 00100011010000010001100011010000 00000010110001100000010001100000 00000000000000000000000000000000 10100000000101011110010100001000 11110001000000000011011001000100 00001111100100000000001111100100 00000000101110010000000000111110 01000000000011111001110000000011 00100110000000001100100100000000 00110010010100000010110010010100 00000011111010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000000 11111011000010000011111001000000 00001111100100000000001111100110 00000000111110010000001000111110 01000000000011110001000000001011 11000111000000101111000100000000 00111110010000000000111110010000 00000011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000111111000000000 00001111100000000000001111100001 00000000111110000000000000111110 00000000000011001000001000001011 00100010000000101100100000000000 00110000000000000000111111000000 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000010000 10111010100010000110111010000000 00001011101011100001000011101010 00100000101110101000000000101110 10000000100010101010010000010011 00101000000000001000101000000000 00100010100000000000101110100000 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10110001000000000010110011000000 00001011001101001000001011001100 00000000101100110100100000101100 11000000000010000011000000000010 01001100000100001000001110000000 00100000110000000000101100101000 00000010000010100000000001010000 00000000000000000000000000000000 10100000000000010001110000000100 10110101000000000010110111001000 00001011010100000000001011011100 00001000101101110000100000101100 11101100000010100011000000001010 00011100000000001000011101000000 00100001010000000000101101101100 00000010001010000000000001000000 00000000000000000000000000000000 10101000000010000001011000100000 11110101100000000010110111110100 00001111011110001000001111011110 01000000111101111000100000111101 11101010000011000101100000000011 01001110000000001100001010000000 10110001101000000000111100111000 00001011001010100000001000000000 00000000000000000000000000000000 00001000000111011010010110000000 01111001011010000011111011000000 00001111100101100000001111101101 10000000111110010000000000111110 11000000000011111001000000000011 11101100000000001111101000000000 00111110000000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 11001110100000000011111111100000 00001100111110000000001100111110 00000000110011001000000100110011 11100001000011001110100000000011 00111010000000001100110110000000 00111111111000000000111111001000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001110001010000 11010110000000000010110111000001 00001000010000000000001101010100 00000000110101110000000000110101 11000000000011010110000100000010 00011000011010001101010100000010 00101101010001000000101101000000 00000010101010100000010001100000 00000000000000000000000000000000 00000000000000001011010000000000 10000110000000000010110111000000 00001000111100000000001000111100 00000000100111000000000000100100 11000000000010000100000000001010 00011000000000001000010000000000 00101101100000000000101100011000 00000010000000000000000000100000 00000000000000000000000000000000 00100000000101001100010110000100 10010010000000000010110011000000 00001000000011000000001001000110 00000000100100010100010000100100 11000000000010010000011000001010 00001001000000001001000001000000 00101100000100000000101100010001 00000010100010000000010000110000 00000000000000000000000000000000 10101000000101011010100000000000 11001001000000000011111111000000 00001100101000100000001100100010 00000000110110110000000000110111 11000000000011001011100000000011 00000111000000001100101110000000 00111110111000000000111110100000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110010000000000 11111001000000000011110011000000 01001111101000000000001111101100 01000000111110110010000000111110 11000000000011111011100000001011 11100100000000001110101110000001 00111110011000000000111110100000 00010011111000000000000000110000 00000000000000000000000000000000 00000001000100001111100000000000 11111101000000000011101111000000 00001101111100001000001111110001 00000000111111110000000000111111 11000000000011110001000000000011 01110100001000001100111000001000 00111111100000100000111111110000 00000011110000000100010000110000 00000000000000000000000000000000 10000001000001000110011001100100 10111001100101000010111011000000 00001010101100000000001011101110 00100000101110010000000000101110 11000000000010111001000000000010 00100100000100001000101000000000 00101110000000001000101110110000 00000010111000000100000000010000 00000000000000000000000000000000 10000000000001010010100000000000 10111000000000000010111011000000 00001001100100100000001011100000 00000001101110000000000000101110 11000000000010111010000000000010 01100010000000001000100100000000 00101110110000000001101110000000 00000010111000000000000001000000 00000000000000000000000000000000 00001000000001000000010000000000 10110000000000000010110011000000 00001010000010000000001011000100 00010000101100110000000000101100 11000000000010110010000000000010 00000000000000001000000100000000 00101100010000000000101100000000 00000010110000100000000100000000 00000000000000000000000000000000 00000000000011010110100000010000 11111000000000000011100111000000 00001101100100000000001111100000 00000000111110000000000000111111 11000000000011111000000000000011 01100000000100001100100000000000 00111110100000000000111110010000 01000011110000000000001101010000 00000000000000000000000000000000 10100000000111011101010000000000 11111100000000010011111111000001 00001111010000000000001111010100 00000000111101010000000000111111 11000001000011111100000000000011 11010000000000001011110000000000 00111111000000000000111111010000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111111000000000 11111111110010000011001111011000 10000100110010000000001100110010 00000000101111110000000000110011 00001000000011101100100000000000 01110000000000001100010010000000 00111111001000000000111111011000 00100011001100000000000001110000 00000000000000000000000000000000 10000000000000001110110000000000 10111111010000000010001111000100 00001010100110000000001000000000 00001000101111110000000000100010 10110000000010001000000000010010 00100000000000001010100010000000 00101100000000000000101100010010 00000010001000000000011000110000 00000000000000000000000000000000 10001000000001011000110000000000 10110011001000000010000011001000 00001010100100000100101000000000 00000000101100110000000000100000 10010000100010100000000000000010 11001000000100001000000100000010 01101100000000000000101100100000 10000010001000100000000101110000 00000000000000000000000000000000 11000000000101011110110000000000 10111011000000000010001011000000 00111010100110000000001000101010 00100000101110110000000110100010 10100010010010001000100010000010 10101010001100001010100100000000 00001110000000001000101110100000 00000010001100000000000001100000 00000000000000000000000000000000 00000000000001011110110000000001 11111011000000001011000011000000 01001100000010100000001100100010 00000001111110110000000000110000 10000000000011101000110001000011 11100000000000001100100000000000 00111110001000000000101110010000 00001011000000000000010001110000 00000000000000000000000000000000 11100000000100011011110000000000 11111111000000000011111011000000 00001101110100000000001111111000 00000000111101110000010000111111 10000000000011111100000000000011 01110000000000001111110000000000 00111111000100010000111111010000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 01001100100100011000001110100001 00000000110010110000001000111110 10010000010011001000010010001011 00111000010100001110100100000000 00111010000000100000111010100010 00001011000100000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10111111000001000010111111001000 10100000100111000000001000101000 00000000101011110000000000101110 10100000000010001000110000100011 01101000000000001000100100000000 00100010000010010000100010101100 00000010001100100000000001000000 00000000000000000000000000000000 11000000000001000000110000000000 10111011000000100010110011000000 10001001001001000000001010001000 00000000100000110000000000101100 10001000001010001000110000001010 00100110100000001010000010010100 00101100110000000000101010011000 00000010011100000000000000010000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100100 10001001111110000001001000011010 00000001101001111010000000101101 11100101000010001100100000100010 01011110000000101000010010010000 00101101111001000000100001011000 00000010010110000000010000010000 00000000000000000000000000000000 01001000010110000000110000001000 11110011000000100010110011000100 00001101001100000000001110001000 00000000110000110001000000111100 10000110000011000000001010010011 00101100100000101110000100000000 00111100110101000000111000100000 10000011010100100000001000010000 00000000000000000000000000000000 01000000000011011011110000000000 11111111000000010011111111010100 00001110011100000000001111111000 00000000111111110111100000001101 11000100000011110111000000000011 11111000000000001111110100000001 00110011110001000000111111101000 00000011100100000000010001100000 00000000000000000000000000000000 00001000000001011110110000000000 11111011001000000011111011010000 00101100001010000000001100101010 00000000110010110100000010110000 10011010000010011000000000000011 01100100000100001100000010000000 00110110110000000000110010010000 00001011000000100000000001110000 00000000000000000000000000000000 01001000000000011001110000000000 10110111010010000010110111001000 00101000010100000000001010111100 00000000110100110010000000100001 11000000000010001100000000000010 00011100000000001000010000000000 00100011110000000000110001010000 00000010000100100000011001100000 00000000000000000000000000000000 00100000000000001001111000000000 10110111101000000010110111100100 00011000111011000000001000011010 00000000100001111000000000100001 10100010000010010100100000010010 01111110000010001000010110000000 00100101111000000001100011101000 00000010000010000000000000100000 00000000000000000000000000000000 01101000000101001100110000000100 10110011000000000010110011000000 00001000001101001000001010001111 00000000100110110000000000100000 11100000010010000011000000000010 01001100000000001000000100000000 00100000110000000000100010100000 00000010000110100000000000110000 00000000000000000000000000000000 11101000000001001010100000000000 11111010000000000011110010000000 00101100111011000000001100111010 11000000110010100000000000110000 10000000101011010110000000001011 01111001000000101100101000000000 00110100100000000010110010100000 00000011001110100000010001110000 00000000000000000000000000000000 01001000000100001010000000000000 11111000000000000011111000010000 01101111100001000000001111100000 00010000111110000000000000111110 00000001001011111000000000010011 10000000100001001111100000000000 00111110000000001000111011000000 00000011110100100000000001100000 00000000000000000000000000000000 00001000000100001010010000000000 11111001000000000011111001100000 00001100100100000000001111100100 00000000111110010000000100110010 11000000000011001001100000001011 00100100000000101100100111000000 00111110010000000000110010010000 00000011000000100000010000100000 00000000000000000000000000000000 10000000000001000010010000001000 10111001000000000010111001010000 00101010100111100010001011100100 00000000101110010000000000101010 01000001000010001001100100001010 00100110000010001010100110000000 00101110010110000000100010010000 00000010101000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001001000 00001000100100100000001011100100 00000000101010010000000100101010 01000000000010001001000000000010 00100100100000001000100100000000 00101111010000000010100011010000 00000010000011100000000001000000 00000000000000000000000000000000 00001000000001001000010000000000 10110001001000000010110001001000 00001010000100000000001011000100 00000000001100010010001000101000 01101001001010001001000000001110 00000100100000001000000100000000 00101111010000000000100001010000 00001010100010100000010100000000 00000000000000000000000000000000 10111000000111010110000101000000 11111000010100000011110010010100 00001100100000000100001111100001 01000000111010000101000000110010 00000000000011001000010101000011 00100001010010001100100000000100 00111110000101000000110011000101 00000011001011100000001101010000 00000000000000000000000000000000 10111000000111011110010000000000 10111001000100100011111001000100 00001111110100000000001111110100 00000100111110010001000000111110 01000100000011111101000000010011 11010100010000001111110100000000 00111110010000000000111100010000 00000011011001100000010001110000 00000000000000000000000000000000 00111000000001011110010000000000 11111001000000000011001101000110 00001100110100000000101100100100 00000000110010010110000000111011 01000010000011001101010000000001 11110100010000001100110100000000 00110001010100000000110011010000 00000011001001100000000101110000 00000000000000000000000000000000 00011000000100001110000010000000 10111000001000100010000000010000 10001000100000000000001000100000 10001000100010000100010000110110 00010000000011111000001000001010 00101000000000101000100000000000 00100010000010000000111100000010 10001010000011100000011000110000 00000000000000000000000000000000 01001000000000001000010000101000 10110001010010000010000001001000 00101000100110000000001000100100 00100000100000010011000100100000 01000000000010001001001000000110 11000101100000001000100110000100 00100000010000000100100100010000 00001010100100100000000101100000 00000000000000000000000000000000 00011000010101001010010000010000 10110001000000000010001001000000 00001000101100000000001000100100 00000010100000010000001000100110 01000000000010111001000100001110 00100100000001101000100100000000 10100010010000000000001010010000 00000010100001100000000000100000 00000000000000000000000000000000 10100000000001001010010000000000 11111001000000001011001001000000 00001100100110010000001100000100 01000000110010010000000000111010 01000000000011001001000011000011 11100111000000001100000100000000 00110010010000000010100110010110 00000011101010000000010001110000 00000000000000000000000000000000 01101000000100001010010000000000 11111001000000000011111001000000 10001111100110000001001111100110 00000000111110010000010000111110 01001000000011111001100000001011 11100100010000001111100100000000 00111110010000000100111110010001 00000011010100100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11001000000000000011111000000001 00001100100000000000001111100000 00000000111010000000000000111100 00000010000111001000000000000011 00100011000000001100100000000001 00111110000000001000110010000100 00000011000000100000010000100000 00000000000000000000000000000000 00001000000001000010100000000000 10001010000000000010110110000000 00101000011010000001001011101000 00000000101110100000000000101111 10110000000010100110100000000010 00111000000000001000111000000000 00101111101000000000100011100000 00000000000010100000000001000000 00000000000000000000000000000000 00001000000001010100110000000000 10000011000000000010110010100000 00001010001110100010001011001100 00000000101000110000000000101100 11010000000010000011100110000110 00101110000000001010001100010000 00101110110001000001101010110000 01000010000010100000000001010000 00000000000000000000000000000000 00100000000100010001111011000000 10000111001000000010110110010000 00101010011100001000001011011100 10000000101101110010010000101101 10010000000010101111000000000010 00011001000100001000011100000000 00101111010000000000101001110000 00000010001000000000010001000000 00000000000000000000000000000000 00101000000010001011111000000010 11000111101100000011110110100000 00101110011110000000001111011111 00000000111001111011000000111100 11100000010010000111100000001011 00000110000000101110011110000000 00111101111000000000111001111000 00001011001000100000001000000000 00000000000000000000000000000000 00001000000101011010110110100000 11111011000000000011111010000000 00001101101100000000000111101100 00101000111110110000000000111110 10000000000011110011000000000001 10101000000001001111101100000000 00111110000000000010110110110000 00000011110000100000010001100000 00000000000000000000000000000000 01100000000001001011111000000000 11111111100010000011101110100000 01001100011110000010001100111110 00000001111111111001100000111001 11100000010011000101100000000011 00111010000000001100011110010000 00110011011000000000111111111000 00000011000100000000000000100000 00000000000000000000000000000000 10101000000100001001110000000000 10110111000000100010000110000000 00001000010100000000101000011100 00000000111101110001000000111101 00000010000010000100000000001010 00111000010000001000011100000000 00100001010001000000101101110000 10000010001010100000011000100000 00000000000000000000000000000000 00000000000000001001110000000000 10110011000000000010110110000000 00001001111101000000001000011100 00100000101101110000000000101101 11000000001010001101000100000010 00010001001000001000111100000000 00100101010000000000101101110000 00000010000001000000000000100000 00000000000000000000000000000000 01000000000101001000110000010000 10110011000000000010010010000000 00000001000100000000001000001111 00000000101100110000000100101100 00110000000010000000010101000010 00101010000000001000001100000000 00000100000000000000101100111100 00000010000110000000000000100000 00000000000000000000000000000000 10101000000001011011110000000000 10111111000000000011111000000000 00001101001110000000001100111111 00000000111111110000000000111000 11110000000011001001110000000011 00101110000000101100100100000000 00110110110000000100111110110100 00000011001010100000010001100000 00000000000000000000000000000000 10100000000100001110110000000000 11111011000000000011100000000000 01001110101110000000001111101100 10000000111010110000000000111010 10000000000011111001000001000011 11101000000000001111100100000000 00111010110000000000111110000100 00000011111001000000000000110000 00000000000000000000000000000000 00000001000100001111110000000010 11000111000000000011001111100000 00001100110100000000001100111100 00001000101111110000000000111111 11000010000011011101000010010011 00110100000000001100110110000000 00110011111100000000110011110000 10000011001010000000010000110000 00000000000000000000000000000000 10000001000001000110110000001000 10001011000000000010001011000000 00101000100110000100101000101100 00000000101110110000000000101110 10111000000010100011100000000010 00101010000001001000000110000100 00100010101000001000100010001101 00000010001011000100000000010000 00000000000000000000000000000000 10000000000001010000110000000000 10001011000000000010001000010100 00001000101110000000001000101100 00000000101110110000000000101110 01100000000010011001100000000010 00100010000000001000100100100000 11100000010000000000100000110100 00100010001000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10000011000000000010000010000000 00001000000100000000001000001100 00000000101100110000000000101100 00000000000010001000000000001010 00000000000001101000000100000000 00100000010000000000100000000000 00000010000000100000010100000000 00000000000000000000000000000000 00000000000011010111110000000000 11001111000000001011000011000000 00001100100100000000001100111100 00000000111111110000000000111110 01000000000011011001000000001011 00100000000010001100100100000001 00110010010000000010110000110000 00000011001000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 10001111110000000000001111111100 00000000111111110000000000111111 01000000100011111100000000000011 11110000000100001111111100000000 00111111000000000000111111000000 00000011111010000000000001110000 00000000000000000000000000000000 11000000000101011101111000000000 11111110100000010011111110100000 00001111111100110010001101111100 11000000111111011000010000110001 01100000000011001101000000000011 00110000000001001101110010000000 00110011101000000000110011110000 00000011001100000000000001110000 00000000000000000000000000000000 11000000000010001110111000000000 10001010100001000010111000100000 00001011111100100000101000111100 01000000101110010000000100100010 00000000000010101000100000000010 00100110000000001011100100000010 00100010110000001100100010000000 00001010001100000000010000110000 00000000000000000000000000000000 11001000000001011100110000000000 10100011000000000010110010000000 00001011001100010000001011001100 00000000101100010010100010101010 01000000000010000001000000000010 00000000000010001001000000000000 10100010110000000000100000110000 00000010001100100000000101110000 00000000000000000000000000000000 11000000000001011010110000000100 10101010000000000010111000010100 00001011001100000000001010101100 00000000101110010000000000100010 11100000000010101000100000000010 00101110001000000011000110001000 00100010110000100000100000111100 00000000001100000000010001100000 00000000000000000000000000000000 10000100000100011110110000000000 11101010000000000011111010100000 00001011101100000010001111101100 00000000111110110000000000110000 01101000000011001000101000001011 00100110000000001101100110000000 00110010110001000000110010111000 00000001000000000000010001110000 00000000000000000000000000000000 11100000000000011011110001000000 11011110000010000011111100000001 00001111111100000100101001111100 00000000111111110000000000011111 11000000000011110000000000100011 11100100000000001111111100000010 00111111110000000000111111000000 00000000111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11011011000000000011111011010110 00001110101100000000001100101100 00000000111110010000000000111110 01010000000011001011000000000011 00100100000000001100101101100000 00111110110100000100110010111100 00001011000100000000010000100000 00000000000000000000000000000000 11011000000001010000111000000000 00001010000010000010111001010000 00001011111100000000001101111100 00000000101110010000000000101110 11000000000010101010100000010010 00101110000100001000101101000000 00101100111000000000100010111000 01100010001101100000000001000000 00000000000000000000000000000000 11000000000001000000110000000000 10010010110000000010110001010000 00001011001100000000101010001100 00000000101110010000000000100100 01000000000010000001000000010010 00001110000000000010000100000000 00101100111000000000100000110000 00000010101110100000000001010000 00000000000000000000000000000000 11110000000000000011011000000001 10000111100000000010110101100000 00001011011110010000001001011110 00000000101101011000010001101111 11100000000000100111110100000010 00011110001000001010010110000000 00101101111000000010100011111000 00000000101111000000000001000000 00000000000000000000000000000000 01001000000110000000110010100010 11010011000000000111110010000000 10011111101100000000001110001100 00000000111100010000000000111100 01000100000011000001000010000011 00000000010000001110000100000000 00111110110000100100110000110000 00001011100100100000001000000000 00000000000000000000000000000000 11000000100111001011110000000000 11111111000000000011111110000010 00001111111100000000001101111101 01000000111111010000000000111111 11000000000011111111000001001011 11111100000000101101110100010000 00111111110001000000111101110000 00000011010100000000011001100000 00000000000000000000000000000000 00001000000001011110110000000000 11011010010000000011111001010000 00001111101101110000001100101101 11000000111110110000000000111110 01000000010011111001100000000011 00101100000000001111101100000000 00111100110000000000110010110000 00000011001010100000000001110000 00000000000000000000000000000000 11001000100000011001110000000000 10000111001010100010110101001010 00001011111100110000001000011100 00000000111001110000000000101101 11000000000010110101000001000010 00011100000000001011011100000000 00101101110000000000100001110000 00000010001100100000010001100000 00000000000000000000000000000000 00100001000000001011111000000000 10010111100100000010110111100000 00001011011110000000101000011110 00000000101001011000000001101101 01100000000010110011100000000010 01010110000000001011011110000000 00101111111000000000100001111000 00001010001000000000000000100000 00000000000000000000000000000000 01101000000101001100110000001000 10000011000000000010110011000000 00001011001100000000001000001100 00000000101000010000000000101100 11100000000010110011110100000010 01001101001000001011001111100000 00101100010111000000100000110000 00000010000100100000010000110000 00000000000000000000000000000000 11100000100001001010101010001000 11011010000000000011111010010000 00001011101000000000001100101000 00000000111010100010000000111111 10000010000011111110110100000011 01111001000000001111111011000010 00111111101100000010110011100000 00000011001110100000010001100000 00000000000000000000000000000000 01001000000100001010000000000000 11111000010000010011111000010010 01001111000000000000001111100000 00000000111010000000000000111110 00000010100011111000000000001011 10100001000001001111100000010001 00111110000000000000111110000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001010010000001010 11001001000000000011111001000000 00001111100100000000001100100100 00010000111110010000000000110010 01000000000011111001100000000011 11100100000000001111100100000100 00110010010000000000110000010000 00000011000000100000010000110000 00000000000000000000000000000000 10000001010001000000010000000000 10001011000000000010111011101000 00000011100100000100001000100100 00000000111100010000000000100010 01000000000010111001100000000010 11100111100010000011100100000110 00100000010100001000110110011000 11000010001000000000000000010000 00000000000000000000000000000000 00011000000000010010010000000000 10001011000000000010111001000100 00001011100100000000001000100100 00010000101110010000000000100010 01000000000010111001001000000110 11100100010000000001000101100000 10100010010110000100100010010001 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000010010000010000 10000011000000010110110001000000 01001011000100101000001000000100 10100000101110010000000000100000 01000000000010110001101000000010 11000100100000001011000100000000 00100010010000000000100100010010 00000010000000100000000100000000 00000000000000000000000000000000 10111000000111010110000000000000 11001000000000000011111000000000 01001111100000100000101100100000 10000001101110000000000010110010 00010100000011111000000000000011 11100000000000001111100001010000 00110010000101000000110000000101 00001011001011100000001101010000 00000000000000000000000000000000 11111000100111011101010000000000 11111001000000000011111001000000 00011111100100101001101111100100 10100000111011010010100000111111 01000000000011111111000100000011 11110100010010001111110100000000 10111111010000000000111111010001 00000011111001100000011001110000 00000000000000000000000000000000 10111001000011011111010000000000 11111001000000000011111001000000 01001111100100101000001101100100 11000000111110010100000000111100 01010000000011110101001000000011 00110100000010001111110100010000 00111110010000000000110010010010 00000011001001100000000001110000 00000000000000000000000000000000 01011001000000000110000000000100 11101000000000000010111000000000 00001110100000100000001010100010 01000000101110001000000000101110 00001000000010111000000000010010 00100001010000001011100000000000 00101110000010100010100011000110 10000011000011100000010000110000 00000000000000000000000000000000 01001000000000000000010000001000 10110001100000000010110001000000 10011011000100101000001011000100 10000000101100010000000000101100 01001000000010110001010001000010 00001110000000001011000100100000 00101101011000000000100001010001 00000010010100100000000101110000 00000000000000000000000000000000 00011000000101001010010010010000 10101001000000110010111001000000 00000010000100000000001010100100 00000000101110010000000000101110 01010100000010111011100000010010 00100100010000001011101100000000 00101101011000000010100011010010 00000010000001100000010001100000 00000000000000000000000000000000 10100000100001001010011000001000 11111001000000000011111001111001 00000111100100000000001111100100 00000000111110011000000000111110 01010000000011111001110000001011 00100110000000001111100110000000 00111110010000000000110010010010 00000011011010000000010001110000 00000000000000000000000000000000 01101010000100001010011000000000 11111001000000100011111001100100 00001111100100000000101111100100 00000000111110010010000000011110 01100000000011110001000011000011 11100110000000001111100101000000 00111110010000000000111100010000 00001011110110100000000001100000 00000000000000000000000000000000 01101010000100001010000000000000 11111000000000000011111000010010 01001111100000000000101110100000 00011000110010000000000000111110 00000001100011001000010000000011 00100010000000001111100000000000 00110010000000000000110010000100 00000011000010100000010000100000 00000000000000000000000000000000 10000000000001000010101000000000 10111010100000000010111010101000 00001011101000000000001010101000 00010010100010100000011000101110 10000000011010001110101001000010 00111000000001001011101000001000 00100010100000100000100010100000 00000010000010100000000001000000 00000000000000000000000000000000 01001000000001010100011001000000 10110011100000000010110011000000 00001011001100000000101010001100 00000000100000110000000000101100 11000000000010000010010000000010 00000100000000001011000100000000 00100000110000000010100000111000 00001010000010100000000001010000 00000000000000000000000000000000 01100001000000010001110000000000 10110110000010000010110111000000 00011011011100000000001010011110 00001000000001110000010000101111 11101000000010000101000000001010 00010100000000001011010010000000 00100001110000000000100001110000 10000010001010000000000001000000 00000000000000000000000000000000 00101000100000000001011000000000 11110111100000000011110111100000 00001111111110010000101110111110 00000000010001111000010000111101 11110000000011000101100000000011 00010110000000001111010110000000 00110011101000000000110011101000 00001011001010100000001000000000 00000000000000000000000000000000 01001010000101011010110000000001 10111011011010000011111000000010 00001111101100000010101111101100 00000000111110110000001000111110 11000000000011111001000000010011 11100100000001001111000000000000 10111110100000000000111110100110 00000011110000100000011001100000 00000000000000000000000000000000 11100010010001001011111000001101 11111111100100000010111101100100 00001101111110001000001110111110 00010010100011111001000001111111 11100000000011111110100000000011 00010110010000001100110110000000 00110001111000000100110011111100 00001011010100000000000001110000 00000000000000000000000000000000 10101001000000001001110000001000 11100100000000000010110111010000 00001101011100010000001000011100 10000000100001110001000101101101 11001000000010110101000100000010 00010100000010001000010000100000 00100001110000000000101001110001 00000011111010100000010001100000 00000000000000000000000000000000 00010010000000001001110001000000 10100111000000100010111101000000 10001000011100000000001011011100 00000100100001110001010000101101 11000010000010110101010000000010 00010100000010001000110100001000 01100011100100000000100001100000 00000010000001000000000000100000 00000000000000000000000000000000 01000000000101001000110001000100 10100001010000000010110000000000 01001001001100000000001001001100 00000000100000110000000000101110 11110000000010110001100001000010 00001101000000001000000011000000 10100000100000000000101000101101 00000010110110100000010000110000 00000000000000000000000000000000 11111000000000010010011000000000 11101001000000000011111010000000 00001100111100000000101111111100 00000000100011110000000000111111 11110100000011111010010010000011 00100110000100001100100110000000 00110000010000000000110010010100 00000011001011100000010001100000 00000000000000000000000000000000 10100100000100001110110000000000 11101001010001000011111010010100 00001111101100000000001110001100 00000000111110110000000000111110 11000000000011111001000000001011 11100110000000001111100101000000 00111110011000000100111110010000 00100011111000000000000000110000 00000000000000000000000000000000 11000001000100001111010000001100 11001101010010000011001111000000 00001111101100000000101100101100 00000000110011110000000000111111 11000000000010101111000000000011 11010000001000001100110100011000 00110011000100000000110010000100 10000011001000000000010000110000 00000000000000000000000000000000 10000001010000000100110000010000 10100001010000000010101000010000 00001110101100000000001101101100 00001000100010110000001000101110 11000000000010001001110000000010 11100001001000101000100000000001 00100010000000000000100010000000 00000010001000000000000000010000 00000000000000000000000000000000 10000000010001010110110000001001 10011011010000000010101001000000 01001011001100000000011000101100 00000000100010110000000000101110 11000000000010101011100000000010 11100100000000001000001100000000 00100010010000000100100000010000 00000010001000000000000001000000 00000000000000000000000000000000 00001010000000000010110000000000 10101001000000000010100011000000 00001011001100000000101001001100 00000000000000110000000000101100 11000000000010100001000000000010 11000100000000001000001100000000 10100010110000000000100000110000 00001010000000100000000100000000 00000000000000000000000000000000 10000000000110000110110000000001 11011011000000100011101001000000 00001111111100000000001100101100 00000000110010110000010000111110 11000000000011101001000000000011 11100100000000001100100100000000 00110010000000000010110010000000 00000011001000000000001101010000 00000000000000000000000000000000 10100010000111011111110000000000 11111101000000000011110100000000 00001110111100000000001111111100 00000000111111110000001000111111 11000000000011010101000000000010 11111100000000001101010000000000 00111111000000000000111111000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111111000000000 11000100100000000011001100001000 00001100011000000000001100111110 00000000111111110100000000110011 11000000010011110100100000000010 00111100000000001100111100111000 00110011011000000010110011101000 00000011001100000000000001110000 00000000000000000000000000000000 10000000000100001110011000000010 10001000100000000010001010110000 01001000100001000001001000100110 00000000101111110111000000101011 11000000010010111000100000000010 00111101010000001000111101000100 00100010110000000000100010011000 00010010101000000000010000110000 00000000000000000000000000000000 10001000000001011110110000000000 10001010000000001010000010000100 00001000001001000000001000001100 00000000101100110000001000100000 11000000000010110011000000001010 00001100000000001000001100100000 00100000010000000010100010010000 00001010001000100000000101110000 00000000000000000000000000000000 11000000000101011010010000000000 10001010000000000010001010100000 00001000100100000000001000101100 00010000101110110000000000101010 11000000000010111001110000101010 00101100000000001000001100000000 00100010110000000000100010011000 00000010101100000000010001100000 00000000000000000000000000000000 00000000000101011100110000000000 10001000000000000011001001100000 00101000101000001000001100101100 00000000111110110000000000110010 11000000010011111000110000001011 00101100000000001100101100000000 00110010010000001000110000001000 00000010000000000000010001110000 00000000000000000000000000000000 11100000000000011011010001000000 11111100010010000011111111000000 00001111111000000000001111110100 00000100111111110000001000111111 11000000000011111100000000000011 11111100000000001111101100000000 00111111111100000000111111010000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110010000000 11111010000000000011001010100000 00001101101000100000001100101100 00000000111110110000000000110010 11000000000011111011100001000000 00101100001000001100101100000000 00110010010000100000110010010000 01000001000100000000010000100000 00000000000000000000000000000000 11001000000001010010010100000000 10110010000000000010000010000000 00001000001011100000001000101101 01000000101111110000000000100011 11000000000010110000100000000010 00111110000010001000111100000000 10100010111100000010100010010010 00000011011100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000000 10110001000000000010010000000001 00001000001001000100001000001100 00000000101110110000000000100000 11000000000010110000000010000010 00101101000000001000001110000000 00100010111000000000100000000000 01000010001110000000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 00110100100000000010011100110100 01001000110010000000001000010110 00000000101100111000000000100001 11100000100010110100100100000010 00011110001000011000011111001000 00100001111001000010100001011100 00000010010110000000000001000000 00000000000000000000000000000000 01001000010010000000110000000000 11110001010000001011010000000100 00001100001000000100001100001100 00010000111100110001000010100000 11000001100011110001000000000011 00101100000000001100001100010011 00110010110000110000110000010000 00000011000100100000001000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111100000000000011100100000101 00101110110000000000001111111100 00000000111111110100001100111111 11000000000011111101000000001011 11111100001000001011111100000000 00111111110000000010111101010000 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110110111000000 11111001000000000011110001000000 00001100101000000000101100101100 11100000111110110000000000110110 11110010000011100000000000000000 10101100100001101100101100101000 00111110110000000010110010000000 00000011111010100000000001110000 00000000000000000000000000000000 01001000000100011001110010100000 10110100000000100010110111000000 01001000011000000000001000010100 10000000101101110110000000100111 11010000000010000101000000000010 00011100001000001000011101000000 00101111110000000000101001010000 00010010110100100000010001100000 00000000000000000000000000000000 11000000000000001001111010000000 10110100100000000010111110100000 00001000011010000000001000011110 10000000100001111010010001101101 11100000010010101101100000000110 10011110100010001000011110000000 00101101111000000000100101011000 00000010111100000000000000100000 00000000000000000000000000000000 01001000000101001100110000001000 10110000010010000010110010001000 00000000001011001000001000001100 00000000101100110000000001101100 11000000000010000001000000000010 00001100000000000000001100000000 00101110110000000000101100010000 00000010110100100000010000110000 00000000000000000000000000000000 11101000000101011010100000001100 11111110000000100011111110010000 00100000111011100000000100101000 00000000110010100000000000111110 10000000000011101110010000000011 10101000000000000100101000000001 00111110100000000000110111100000 00000011111110100000010001100000 00000000000000000000000000000000 01001000010000001110000100000000 11111000010001000011110000010100 01001111000000000000001111100000 00000000111110000000000000110110 00000000000011111000001000000011 11100000000001001111100000000000 00111110000000000010111010000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010001000000 11111001000000000011111001000000 00001100100100000000101100100100 10000000111110010000000000111110 01000000000011111001100000000010 01100110100000000100100100000000 00100010011000000000100010010000 00000011110000100000010000110000 00000000000000000000000000000000 10000000000001000110110100100000 10111001010010110010111001010000 00001000100101000000101000101110 00000000101110010000000000101110 01000000010010110001010000000010 00100110000001001000100100000000 00100010011101000010100010010000 00000010111000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000001 00001000100100001000001000100100 00000000101110010000000000101110 01000000000010111001000100000010 11000100000000101010000100010000 00101010010000000100101010010000 00000010110001100000000001000000 00000000000000000000000000000000 00001000000001001000010000000000 10110001000000000010110001001001 00001000000100100000001000000100 00000000001100010010010000101100 01001000000010111001000000000010 10000100100000001010000100100000 00101000011000000001101000010000 00000010110000100000000100000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111010000000 00101100100001010000101100100000 00000000111110000101000000111110 00010100000011111010000000010011 11000001010000001110100001010000 00111010000101000010111010100000 00100011111011100000001101010000 00000000000000000000000000000000 10011000000011011110010000000000 11111101000000010011111101000100 00000111010100010000001111100100 00000000111110010001000000111110 01000100000011111101000000000010 01100100010000001101100100010000 10110111010000000000110111010000 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011011101000000 00001100010100100000001100100100 00000100111110010000100000111110 01000000000011111101000000000011 10110100010000001100110100010000 00110011010000000010110011110000 00000011001001100000000001110000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000010010001000010100 00001000100001101000000010100000 00000000101110000100000000101110 00010100000010111000000000000010 00100001010000001000000000000000 00100010000010100000100010100000 00100010000011100000010000110000 00000000000000000000000000000000 00001000000001011100010000000000 10111001100000000010010001000000 00001010000100010000001000000100 00000000101100010010100000101100 01001010010010110001000000000110 10000100100000101000000101100100 00100010010000000000100000110000 00000010010000100000000101110000 00000000000000000000000000000000 00011000010101011010010000000000 10111001100000000010001001000000 00001001000100001000001010100100 00000100101110010000000000001110 01000000000010111001001000000010 00100100000000001010000100000000 10101010010000000100000010110001 00000010010001100000010001100000 00000000000000000000000000000000 10100000000101001010010000010100 11110001000001000011011001001000 00001110100101000000001100100110 01000000101110010000000000011110 01000000000011110001111000000011 10100100000100001100100100000000 00100000010000000000110000011000 00001011011010000000010001110000 00000000000000000000000000000000 00101000010000001010010000100000 11111011000000100011111001001000 10101110100100000000001111100110 00010000111110010000000000111110 01000000000011111001100010000011 11100100000000001101100100000000 00110110010000100000111110011000 10010011100010100000000001100000 00000000000000000000000000000000 00101000000100001010000001000000 11111000000010000011110000010000 01001101100001000000101101100000 01111000111110000000010100111110 00000000000011001000000100000011 00000000001000001111100000001000 00110010000000000000110010000100 00000011110010100000010000100000 00000000000000000000000000000000 00101000000001000010100100000000 10111010010001000010111110110000 00101000111000100000001000101011 00000000101110100000010100101110 10000000000010001110100000000011 01111000001001001011111001000000 00100011101000000000110111100000 00000010110010100000000001000000 00000000000000000000000000000000 00101000000001010100110100000000 10110011010000000010110010110011 10101000001000000000001001001101 00000001101100110000001000101100 11000000000110000011000000000110 01001111000000001011000101000000 00100000111000000100101000110100 00000010110010100000000001010000 00000000000000000000000000000000 00100000000000010001100000000100 10110111000000000010110110000010 00001000011000000000001000011000 00000000101101110010000000101100 11101000000010000110000000000010 01011100000000000011010100000000 10100001110000100000101101110000 00000010111010000000000001000000 00000000000000000000000000000000 00101000000010000001111001000000 11110111100100010010110010100000 00101100011110000100001101010110 00110000101101111010001000111101 11101100001011000111100000000011 01011110000000001111011110000000 00110011111000001000111001111000 00000011111010100000001000000000 00000000000000000000000000000000 00001000000011011010100000010000 10111011010000000011111011000000 00001110101001000000001111100000 00000000111110110110100000011110 11011100000011110011000000000011 11101100000000001111100100000000 00111110010000000000110110110000 00000011110000100000011001100000 00000000000000000000000000000000 01000000000001011111111000000000 11111111100000000011111101100001 00001100111011010000101100111110 00000000101111111001100000110011 11100000000011001111100000000010 10111010010000101100110110000000 00110011011000000000110011111000 00100011110100000000000001110000 00000000000000000000000000000000 10101000000100011001110000000000 10110110000000010010110110010000 10001000010000111000101000011001 00000000101101110000000000101001 11000000000010000110000100000010 00111000010000001000010000000000 00100011010000000000100001110001 00010010111010100000010001100000 00000000000000000000000000000000 00000000000000001001000000100000 10110111000100000010110001000000 10111001011110000100001000011100 01100000101101110000001000100100 11000000001010000110000000000010 10011000000010001001001100000000 00100001010000000010100101110000 00000010110001000000000000100000 00000000000000000000000000000000 01100000000101001100001000000100 10110011011000000000110011000000 00001001000011000000101000001000 00000001001100110000010000101000 11000000000000000010000000000010 00001000000000001001000000000000 01100010010000000010100100111101 00000010110110000000010000110000 00000000000000000000000000000000 10101000000101011010011000000000 10111011010000000011111010100000 00100001101010000000100100101110 00000001101111110000000001110011 11000000000011000011110000000011 10101000000001001101000100000000 00100010111000000110110110110000 00100011111011100000010001100000 00000000000000000000000000000000 10000000000000001110000000000000 11111011000000000011111011100000 10001110001000000000001111101101 00000101111110110000000001111110 11000000010011111011111000000011 11101100000001001110100100000000 00111110110101000000111010110100 00000011111000010000000000110000 00000000000000000000000000000000 00000001010100001111111001000000 11111111000000000011111110000000 00101100111100011000001100110111 00000000110010110000001000110111 11000000110011001111000000100011 01011000000000001100110110100000 00110011110000000000100011110000 10000011001000000000010000110000 00000000000000000000000000000000 10000001000001000110101000000000 10111011000000100010110011010001 00001000101000000010101000000101 00000000100010110000000000100010 11000000000010001011110010000010 00101101010001101000100100000000 00100010011000000000100000110100 01001010001000000100000000010000 00000000000000000000000000000000 10000000000001010010010000000000 10111011000000000010111001000000 00001000101000000000001000100000 00000000100000110000000000100000 11000000000010001010100000101010 01101001000000011000100100000000 10100010111100000000101010111000 00000010001000000000000001000000 00000000000000000000000000000000 00001000000101000000010000000000 00110011100000000010111011000000 00011000001000000000001000100000 00000000100000110000000000100000 11000000000010001000000000000010 00001000000000011000000000000000 00100000110000000001101010010000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000011010110000000000000 11111011000000000011111001000000 01001100111100000000101100100000 00000010110011110000000010110111 11000000000011001010000000000011 01101000000000001100100100000000 01110010110000000010111010110000 00000011001000000000001101010000 00000000000000000000000000000000 10100000000101011111000000000001 11111111000000000011111111000000 00011111011000000000001111110000 00001001111111110000001000111111 11000000001011110110000000000011 11110000000000001111110000000000 00111111000000000010110111000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111110000000000 11001101100000000011011111001001 00001100111100100010001100110010 01000000110001001000001010110011 11000000000011110100100000000011 00010010000000001111110010000000 00111101001000000000110011110000 00100011001100000000000001110000 00000000000000000000000000000000 11000000000110001111111101000000 10001001100000000000111111100001 00001000111100101011001000100000 00000000100010010000001100100011 11010000000010111001000000000010 10100010000000001011100010000000 00101110100000000000101010111100 00010010101100000000010000110000 00000000000000000000000000000000 11001000000001011100110000000001 10000001000000000010010011010000 00001000001100110001001000001000 00000011100010100010100000100000 11000100000010111000000000010010 10000000000000011011000000000000 00101100110000000000100100010100 00000010001100100000000101110000 00000000000000000000000000000000 11000000000001011010110000000000 10001001110000000010111011000000 00001000101100000000001000101100 00000000000010110000000000100010 11000000000010111001000000000010 10100011000000011011101000000000 00101100111000000000101110011000 00000010101100000000010001100000 00000000000000000000000000000000 11000000000101011110110000000000 11001000100000000011011011000000 00001100101100000010001100100000 00010000110010000000000000110010 11000000100011110001110100000011 10100010000000001111100010000001 00111110111000000000110100010000 00000011000100000000010001110000 00000000000000000000000000000000 11100000000000011000110000000010 11111101000000000011110011000001 00001111111100000000001111110000 00001000111111000000000000111111 11000000000011111111000000000011 11110100000000001111111000010000 00111111110000011000111011010000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11001000010000000011111011000000 00001100101100000000001100101000 00000000111110000000000000110110 11100010000011001001010000000011 00100101001000001100100000010000 00111110111000000000110010110000 00000011110101010000010000100000 00000000000000000000000000000000 11000000000001010011111000010000 10001001101000000000111111000000 10001000111100000000001000101100 00000000101100000000000000100011 11010000000000001001011000001010 10100101100000001000101001010000 00101110110000000000100010111000 10000010111100100000000001000000 00000000000000000000000000000000 11000000000001000100110000001000 10000000100001000000110011000000 00001000101100000000001001100100 00010000101100000000000000100100 11000000000010000001000000010010 01000010000000001001000010000000 00101100100000000000100000010000 00000010111110000000000001010000 00000000000000000000000000000000 10111000000100000101111000000000 10010110100000000010110111100000 00001001001110000001101001010110 00000000101111011000010001100000 11100000001010000111110100000010 11011110000000011001010010000000 00101111101100000010100001011100 00000010111011000001000001000000 00000000000000000000000000000000 01001010000010000100110000100000 11000011000000000011110011000001 00001100001100000000001101001000 00000100111100100000000000110100 11000000010011000001000000100011 01000100000000001101001000000000 00111100110000000000110000110000 00000011110100100000001000000000 00000000000000000000000000000000 11000000000101011011110000100000 11101111000100000011111111000000 00001110111100011000101110111101 01001000111111110000000000111111 11000000000011111101000000000001 10111100010000001010111000010000 00111111110000000000111111110001 00000011110100000000011001100000 00000000000000000000000000000000 00001000000001011110110010100000 11011011000000000011111011010110 00001100101101101000001100000111 00010000110010000000000000111010 11010010001011000001000000000011 10100000000000001111001010001000 00110010111000000000110000010000 00000011001010100000000001110000 00000000000000000000000000000000 11001000100110011000110010000100 10000101000000000010110111001000 00001000001100000000101000010100 00000010100011000000000000101001 11011000000010000111000000000010 00011100000000001011011000000000 00100001110000000000101001010000 00000010101100100000010001100000 00000000000000000000000000000000 00100000000000000001111010000010 10100111100011000110110111101001 00111000011110100000001000111010 00000000100001001000000000101001 11101000000010101101110000000010 10010110000000001011111010000000 00100011110000100010101001111000 00000010001000000000000000100000 00000000000000000000000000000000 01101000000001001100110000000000 10100011101000000110110011000000 00001000001100000100011000001100 00000000100000000100000001101000 11000000000010110001000000000010 00001100000010001011001010010000 00100010111000000000101000110000 00000010100100100000010000110000 00000000000000000000000000000000 11100000000101010110100000000000 11101110100000100011111010000000 00001100101000000000001100101000 00010000110011100010000000111000 10000000000011101110010000000011 10111001000000001111101000000000 10110011100100000000111010100000 00000011001110100000010001100000 00000000000000000000000000000000 01001000000000011010000000010000 10001000000000000011111000000000 00001111100000000000001111100000 00001000111110000000100000110110 00000000000001001000000001001011 11100001000000001111100001000000 00111110000100100000101110000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001000010000000000 11001001000000000010110001000000 00001000000100000010011100101100 00010000111110010000000000110110 01100000000011001001101010000011 00100100001010001011101110100000 00111110010000000010010000010000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000000000110011000000000 10001001000000000010111001000000 00001000100100000000001101100100 00000000101110010000000000100010 01100000000010000001010000000010 10100100100000001001100111000000 00111010010100000000100010010000 00000010001000000000000000010000 00000000000000000000000000000000 00111010000001010010010001000110 10001001000000000010111001000000 00001010100100000000101000101100 00000000101100010000000100100110 01001000000010001011010000000010 00100100100000001011100101000000 00101110010000000000101010010000 00000010000001100000000001000000 00000000000000000000000000000000 00101000000101000000010010100000 10000001000000100010110001001010 00101010000100101000001000000100 00000000001100010000000000100000 01101000001110000001000000000010 10000100000000011001000100000000 00101000110000000000101000011010 00001010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000010000000 11001000000000000011111000001000 11001110100000100000001000100000 00000000111110000101000000110100 00010100000011001000010100000011 00100000000011001111100000000000 00111110000101000000111010000000 00000011001011100000001101010000 00000000000000000000000000000000 11011000100101011110010000000100 11111101000000000011110001000000 10000101100100101100101111100100 10100000111111010000000000111110 01000100000011111101000000000001 11110100000001000111100100000000 00111001110000000100110111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000010000011110010010101000 11001001000000000011001001000000 00001000100100000010001100100101 00010000111110010000011010110011 01011000000011001101010000000011 00110100000000001100110100000000 00111111010100000000110011110010 00100011000001100000000001110000 00000000000000000000000000000000 01111000000110001110000100000000 10001010000000000010001000000001 00001000100000100001001000000000 00000000101110000010100100100010 00000000000010001000001000000010 00100000000000001000100000000000 00101110000000000000110110000100 00000010100011100000010000110000 00000000000000000000000000000000 01001000000000001000010000000000 10001001000001000010000001010000 00001000000101001000001000000100 10000000101100010000000000100000 01011000000010000001000000001010 00100100000000001010000100000000 00101100010010000000100100010001 00000010000100100000000101110000 00000000000000000000000000000000 00011000000001001010010000010010 10001001000000000010001001000000 00001000100100000000001000100100 10000000101100010000000001100000 01000000000010000001000100000010 00100101000000001010100100000000 00101100111000000000100110010010 00000010100001100000010001100000 00000000000000000000000000000000 10100000000100011100010000000000 11000001000000000011001001000000 00101100100100000000101100100100 10000000111110011000000000110010 01000000010011001001000000000011 00000100000000001110100100000001 00111110010100000010110100010000 00000011001010000000010001110000 00000000000000000000000000000000 01001000000000011010110000000000 11111011100100101011110011000001 00001111100100000010001111100100 00000000111110011010000000111110 01000000001011111001000000000011 11100100000000101101100111000000 00111110010000010010111110010000 00000011110110100000000001100000 00000000000000000000000000000000 01001000000100001010000010001000 11001000010000000011111000001000 00001100100000000000001100100000 00000000110010000000010000111110 00000000000011001000000000000011 00100000110000001111100000000001 00111110000100000010110010000001 00000011110010100000010000100000 00000000000000000000000000000000 00101000010001010010100000000000 10001010010000000010111010100000 00001000101000000000001101101000 00000000100010100000010000111111 10000000000010001110011100010010 00111000000000001011111000000000 00101111100000000000100011100000 00000011100010100000000001000000 00000000000000000000000000000000 01101000000001010100110100000010 10000010001000000010110011110001 00101011101100000000001001001100 00000000000100110000000000101100 01000000001010000011110000010010 00000110000000000011001100010000 00101100111000000000100000010000 00000010110010100000000001010000 00000000000000000000000000000000 10000000000100010001010000000001 10000100000000000010110111000010 00011011001100000001001001011110 00000000100101110010000000001000 01000000000010000111000000000010 00011100000000001011011100000000 00101101110100000000100001010000 00000010101010000000000001000000 00000000000000000000000000000000 10001000100010001000011000000010 11000110100100000011110011100010 00101111011111110010001101011110 10000000110101111100010000101101 10100000000011001111100000001011 00011110000000001111011110000001 00111111111000000010110001011000 00000011111010100000001000000000 00000000000000000000000000000000 00001010000101011010010000100100 11111000010000000011111011001000 00001100101100100000001111101100 10110010111010110110000000111110 00000000000011111001011010001011 11101100000001001011101100000000 00111110100000000100111110010000 00000011110000100000011001100000 00000000000000000000000000000000 00000010000001001011101000000000 11001111100100000011111100100000 00001100111110000000001100111110 00100000111111111100000000111111 01100001000011101111100000000011 00111110000100001111010110010000 00110011011000000000110011011001 00000011000000000000000001110000 00000000000000000000000000000000 10101000000110001001000000000010 10000101000100100010110100011000 00001000011100010100101000011100 00000000101101110001000000101101 01000100000010000111000000000010 00011100000100001011010100000000 00110101110001000000100001110000 00000010101010100000010001100000 00000000000000000000000000000000 00000000100000001000000000000010 10000111010110010010110000000000 00111000011100000000101001011100 00000000101101110000000000101101 10000000000010100111000000000010 00011000011000001011010100001000 00100011010000000000100001010000 00000110000000000000000000100000 00000000000000000000000000000000 00100000000001001000000000000000 10000001000000010010110000000000 00011000001100000000001001001101 10000000101100110100000000101100 00000000000010001001110000000010 00001011100000001011000110000000 00100100101000000000100000110000 00000010100010000000010000110000 00000000000000000000000000000000 10101000000100011010110000000000 11001010010000000011111010000000 00101100111100000000001101111101 00010000111111110000000000111110 00000000000011101001000000000011 00001111000000001111101100000000 00110010100000100010110010010000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110010000000100 11111000000000010011111010010000 00001111001100000010001110101100 00000000111110110010000000111101 01000000000011111001010100000011 11101000000000001111101100000000 00111110010100000000111110010000 00000011111000000000000000110000 00000000000000000000000000000000 00100001000100001101010000001000 11011110000000000011110110000000 00001100111100000000001100111100 00000000111111110000000000111110 10000000000011001101000010000011 00111100000000101100111000000001 00111111101010000000110001010000 00000011000000000100010000110000 00000000000000000000000000000000 10100001010001000110010000000010 10001000011000000010111010000000 00001100101100000000001000101100 00000000101110110000000000101110 00010000000010101001100000010010 00101011110000001000100111000000 00100110000100000000100010001100 10000010001000000000000000010000 00000000000000000000000000000000 10000000000001010010100000000000 10001010000000000010111000000000 00001000101100000100101000101100 00001000101110110000000000101110 00010000000010001011100010000010 00101100000010001000100110001001 00101100000000000000100010011000 00100010001000000000000001000000 00000000000000000000000000000000 00001010000101000000000000000000 10000000000000000010110000000000 00001000001100000000111000001100 00010000101100110000000000101100 01000000000010100011000000000010 00001000000001001000000100000100 00100100010000000010100000010000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000011010110000000000000 11001010000000000011111000000000 00101100011100000000001100111100 00000000111111110000001000111110 10000000000011000111000000000011 00101000000000001100100000000000 00111110000000000000110010010000 00001011000000000000001101010000 00000000000000000000000000000000 10100010000101011111000000000000 11111100000000000011111100000000 00001110111100000000001111111100 00001000111111110000010000111111 00000000000011111100000000000011 11111000000010000111110100000000 00111101000000000000111101000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011101011000000000 11111111000000000011001111001000 00001101110010010001001100111110 00000000111111110011000000110011 11001010000011001111100000000011 11111100111010001111111110000000 00110011110000000000110011100000 00000011001100000000000001110000 00000000000000000000000000000000 10000000000100001110010000000000 10111011100001000010001111110000 00001000100010000001001000101110 00000000101111110011000000111011 11111010010010001011100000000010 11111101000100001011101110000010 00101011111100010000101010101100 00010010001000000000010000110000 00000000000000000000000000000000 10001000000001011100010000000000 10110011000000000010000011000101 00101001001000100100001000001100 00000000101100110000000000100000 11000000001010000011000000000010 11001100100000001011101100000000 00100000110100000000100000000100 00000010001000100000000101110000 00000000000000000000000000000000 11000000000101011010010000000100 10111011000000001010001011000000 01001000100000000000101000101100 00000000101110110000010000101110 11000000010010001011000000000010 11101100000000001011101100000000 00101010110000000000101010000000 10000010001100000000010001100000 00000000000000000000000000000000 01000000000101011110010000000000 11111011000000000011001011000000 01001101100100000000001100100110 01000000111110110000000000110010 11000000000010001011000000000011 11101100000000001111001100000000 00110010110000000000110010111101 00000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011010000000000 11110011000010000011111111000001 01101111110100010000001111110100 00001000111101110000000000111011 11000000000011111111000111000011 11111100000100001111111110010000 00111111110000010000111101110000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11101011000000100011001011100000 00001111101100000010001101100100 01100000111110110000000000111110 11000000000011001011000000000011 11101100000110001111101110000000 00111110110000000000111110010000 10000011000100000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10001111000001000010000111010000 00001011100100000000001011100101 00000000101111110000010000101111 11000000000010001011110000010010 11111100000000001011101100000000 00101101110000110100101110010100 00000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100010000000000 10100011100100000010000011000010 00001011100000000000001011001101 00000000101100110000001000101110 11000000000010000001010000000010 01001100000000001011000101100000 01101100110000001000101100110101 01000010001110000000000001010000 00000000000000000000000000000000 00100000000000010011011000010000 00000111100100000010000111100000 00001011011110000000001011011110 01000000101101111000000000101100 11100000001010000101100010000010 11011110000000001011010110000000 00101101111000000000101100111000 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000010000000000 11100011000000000011000011000000 00001111001000000000001111001100 00000000111100110000000000111100 11000000000011000001000000000011 01001100000000001111001100010000 00111100110000000000111100110000 00100011000100100000001000000000 00000000000000000000000000000000 01000000000111011011010000000000 11111111000010001011111111000000 00001111111100000000001111111100 00000000111111110000000001111111 11000000000011101101000000100011 11111100011000001111111100000100 00111111110000000100111111110001 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110010000000000 11111011000000100011001011001010 00001011100000000000001111101111 11000000110110110011100000111110 11000100000011001011101000000000 00101110100000001100100101100000 00111110110010000000111110110000 00000011111010100000000001110000 00000000000000000000000000000000 01001000000100011001010000000000 10110111001000001010000111010000 00001011011100000001001011011100 10110000100001110010000000101101 11000010000010000111011010000010 10001100001000001000010101101000 00101101110100100100101101110000 00000010110100100000010001100000 00000000000000000000000000000000 11000000000000001001111000000000 10110011100000000010000111100000 00001011011010000001001011111110 10001000100101111010000000101101 11100000000010001111100000000010 00011110100000001000011110000000 00101101111010000000101101111000 00000010111100000000000000100000 00000000000000000000000000000000 01001000000101001100111000000000 10110011000000000010000011000000 00001011001100000000001011001110 00000000100000110000000000101100 11000000000010000011100000000010 10001100000000001000001100000000 00101100110000000001101100110000 00100110110100100000010000110000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011001010000001 00001111011001000000001111101000 00100000110110100000000000101110 10000000000011001010101000100011 00101000000000101100101000000000 00111110100000000000111111100100 00000011111110100000010001100000 00000000000000000000000000000000 01001000000000001110000001000100 11111000000000010011111000000000 01001111100000001000001111100000 00000000111100000000000000111110 00000000001011111000000000000011 11100000000000001111100001000010 00111110000000010000111110000000 10000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11110001100100000011001001000000 00101100100100000000001100100100 00000000111110010000000000110000 01000000000011001001000000000011 11100100000000001111100100000000 00111100011000000000110000010000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010000001000000 00001000100100000000001000101110 01000100101110010000000000100010 01000001000010001011000000000010 11100100000000001011101101000001 00101110010001010000100010010010 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001010000001010001001000000 00001000101100000000001000100100 00001000101110010000000000100010 01000000001010001001000000000010 11100100000000001011100101000000 00101110010000000000100010010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001001000000010000001001000 10001000100100000000001000001100 00000000101100010010000000100000 01001000000010000001000000000010 11000100100000001011000100000000 00101100010010000010100000010010 00001010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000101000000 11111000000000000011001010000000 00001100100001010000001100100000 00000000111110000101000010110000 00010100000011001000000000000011 11100001010000001111100000000000 00111110000000000100110010000000 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011111010000000000 11111001000100000011111001000100 00001111110100000000101111000100 00000000101110010001010000111110 01000100000011110001000001000011 11100100010000001111100100000100 00111110010001010100111111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010001000000 11111001000000000011001101000000 00001110100100000000001111100100 00010000111110010000110000110010 01000010000011111001000000000011 11100100010000001111100100000010 00101111010000000000111111010000 00100001000001100000000001110000 00000000000000000000000000000000 00111000000100001110000000001000 10111000010100000010001000010100 01001000100000101000001011100000 00000000101110000000000000101010 00001010100010111000000000000010 11000001010000001011100000000000 00101110000000001000101110000000 00000010000011100000010000110000 00000000000000000000000000000000 00001000000001011100010010000000 10110001000000001010000001000000 00001010000100000100001011000100 00000000101100010000100000100000 01000000000010110001000000000010 11000100100000001011000100000000 00101100010100001101101100010100 00000010000000100000000101110000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010001001000001 00001000100100010000001011100100 00000000101110010000000000101010 01000000000010111001000000000110 11100100000000001011100100100010 01101110010000000001101110010010 00100010000001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011001001000000 10001110100110000000001011100100 00000000111110010000000000010010 01000000000010111001000000000011 11100100000001001111100100000000 00111110010000000000111110010000 00000011001010000000010001110000 00000000000000000000000000000000 00101000000000011010011001000000 11110011000000001011111001000000 01001111100100000000001111100100 00001000111110010000010000111110 01000000000011111001000000000011 11100100000000001111100110000000 00111110010000010100111110010000 10001011110010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11001000000010000011110000000000 00001101100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000101100100000000000 00111110000000001000110010000001 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000000 10001010000000000010111110000000 10001000101000000000001011101010 10000000101110100000000000101110 10000000000010111010001100000010 11101000000001001000101000000000 00101110100000000000100001100100 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10000011100000000010110011000100 00001001001100000000001011001100 00000000101110110000000001101100 11000000010010110011100000000010 11001100000000001000001100010000 00101100110001000000100100011100 00001010000010100000000001010000 00000000000000000000000000000000 10100000000000010001111011000000 00000101010000010010110011000000 00001000011100110000001011011100 00000100101101110010001000101101 11001000000010110110000000000010 11011110100000001000011000000000 00101101111000000000100100110000 00000010001010000000000001000000 00000000000000000000000000000000 10101000000010000011111010000010 11000110100010000011110111100000 00001101011110010001001111011010 01001000111101111011000000111101 11111010000011110111100000000011 11011110000000001100011110001000 00111100111000000010110101011000 00000011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110110100000 11111011011000000011111010000000 00001111101100100000001111100101 10000000111110110000000000111110 11000000100011111010000010000011 11101100010000001111101100100010 00111110010000000000111010110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 10111100100100000011001101100101 00001100111110000000001110110110 00000000111111111000100000111111 11100000000011111101100100000011 11111111000000001100110110010000 00111111111000000000101111011001 00000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001110000000000 10110101000100001010000111001100 00101000011100001000001000011100 00000000101101110000010000101101 11000000000010110111000000000010 11011100000000001000010000000000 00101101110010010000101101010011 00001010001010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110110000001010010000101000000 00001000111100000000001011010000 00000000101101110000000000101101 11000000000010110101000000100010 11011100000000001001010100000000 01101101110000000000101100010000 00100010000000000000000000100000 00000000000000000000000000000000 00100000000101001100110000000001 10110011000000000010000010000000 00011000001110100000001001000100 00000000101100110000010000101100 11000000000010110011000000000010 11101100000000001001000100000000 00101100010000000000101100010000 00000010000010000000010000110000 00000000000000000000000000000000 10101000000101011011110000000000 10111011000000000010001010000000 00001100111100000000001011101100 00000000101111110000001000101111 11000000000011111011000000000011 11111100000000001101101100000000 00111110110000000000111110010000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110110000000000 11111011010000000011111011000000 00001111101100000000001100101000 00000000111110110000000000111110 11000000000011111000010000000011 11101100000010001110100001000010 00111110110000000000111110000100 00010011111000000000000000110000 00000000000000000000000000000000 00000001000100001111110000000010 11001011001000000011001110000000 00001111111100000000001100111000 00000000111111110000000010110011 11000000000011111111000000000011 11101100000001001100111010100000 00111111110000000000111111010000 00000011000000000100010000110000 00000000000000000000000000000000 10000001000001000110110000000000 10000011110000100010001010100000 00001011101100000010001000100000 00000000101110110000000001100010 11000000000010111000011000000010 11101100000001001000100000000001 00101110011000000000101100010000 00000011011000000100000000010000 00000000000000000000000000000000 10000000000001010000110000000000 10011011000010000010001010100000 01001011001100000100001000100100 00001000101100110000001000100010 11000000000010111000100000000010 11101100000000001000101101000010 00101110010001000000101110010110 00000010001000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10000011000000000010000011100000 10001011001100000000011000001010 00000000101100110000000000100000 11000000000010110000000000000010 11001100000011001000000000000000 00101100010000000100101100010000 00000010010000100000000100000000 00000000000000000000000000000000 00000000000011010111110000000000 11011011000000001011001010000000 01001111111100000100001100100000 00000100111111110000000001100011 11000000000011111000000000000011 11111100000000001100101000000010 00011110010000000100111110010000 00001011000000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 01111111000000000011110110000001 00001111011100000000101111110000 00000000111111110000010000111111 11000000000011111100000000100011 11111100000000001111110000000000 00111111010000010100111111010000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011101110010000000 11111101100000000011101100100000 00001100110110000000001111110010 00000100110011110010010000110011 11000000000011001100010000000011 10110000000100001100110110000000 00110011010010000000110011110100 00100011001100000000000001110000 00000000000000000000000000000000 10000000000100001111111101001000 10111001100000000010001001100000 10001000100110000010001011100110 00000000100011110101000100100011 11010000000010001000001000000010 10100000001101001000001100001100 00100010010101100000101011110101 00010010001000000000010000110000 00000000000000000000000000000000 10001000000001011100110000000000 10111011000000000000100010000000 00001000000000000000001011100000 00000000100000110010100000100000 11010001000010100000000000010010 00000100100010001000001100100000 00100000010010000000100100110010 00000010001000100000000101110000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000001000010001011000000 00101000100110000000001011100100 00000000100000110000010010100010 11000000001010100000010000000010 10100110000000101000101100000000 00100010010000000000001110110000 00000010001100000000010001100000 00000000000000000000000000000000 01000000000100011110110000000000 11110001100100000011100000010010 00001100100011001000001111100010 00000000110010110000000000110010 11000000000011101011010100000010 10100010100100001100101110010001 00100010010000000010110110011000 00001011000100000000010001110000 00000000000000000000000000000000 11100000000000011011110000000000 11111101000000000011111101000000 00001111110000000010001111111110 10000000111111110000000000111110 11000000000011011001100000000011 11110000001000001111111100000000 10111100010000001010111001011001 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000100 11001011001001000111111010010001 10001111100100000000011111100000 10000000111110110000000000111100 11000000000011001011010000000011 00100101000000001111101100001000 00110010010000000000110010010000 00001011000100000000010000100000 00000000000000000000000000000000 11001000000001010011111000000000 10001011110000000010111011000000 00001011100100000000011111001100 00010000101111110000000000101111 11000000000000001001111000000001 00100100000100001011101101000000 00110011010000001000100010011010 00000010001100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000001 10000011000100000010110000000000 00001011000100000010001011001001 00000001101100110000000000101100 11000001000010000000001000101010 00100000000001001011101100000010 00100000010000010000101000010000 01000010001110000000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 10000111100000000010110100100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000001010000110100101001010 01010010000000001011011110000000 00100101011000000000101000011000 00000010000010000000000001000000 00000000000000000000000000000000 01001000000010000000110000100000 11000011000000000010110011000000 00001111001000000000001011001000 01000000111100110000000000111100 11000110000011000001000100001011 00000100011000001111001100100000 10110000010010000010111000010000 00000011000100100000001000000000 00000000000000000000000000000000 01000000000111011011110000100010 11111111000000000011111111010100 00001111111100000000001110111101 00000000111111110000000000111111 11000001000011111111000100000000 10110100000000001111111100000000 00111011010000000000110111011001 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110111010000010 11001011000000000011110000101000 00001100101110000000001100100001 00000000111110110010100000111110 11010010000011111010000001000011 00110000000000000011101100000001 00111110011000010000110010110010 00000011001010100000000001110000 00000000000000000000000000000000 01001000000100011000110011000000 10000111000000000010110100000000 00001000010100000001001000011100 00000100101101110000000000101101 11011000000010110010000000000010 00010100000000001011011100000001 00101101010110000000100000110001 00000010000100100000010001100000 00000000000000000000000000000000 11000000000000001001111010000000 10000111100000000010111111100000 00001000111110000000101000010010 00100000101101111001000000101101 11101000000010110111110000000010 00011110000000001011011110000100 00101100010000000000100001111000 00000010001100000000000000100000 00000000000000000000000000000000 01001000000101001100110000000000 10000011000000000010110011000000 10001000001101010000001000001100 00010000101100110000000000101100 11000000000010111011110000000010 00001100100000001011001110010001 00101100010000000000100000110001 00000010000100100000010000110000 00000000000000000000000000000000 11101000000101011010100000000000 11001010000000000011111010000000 00101100111010000000001100101010 00000000111110100000000000111110 10000000000011111110100000001011 00111001000000001111101000000010 00111110100000000110110010101000 01001011001110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000010011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000001111000000010000011 11100000000000001111100000000000 00111110000000000000111110000100 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11111001100000000011111011000100 00011111100100011000001111101101 00000000111110010000000010110010 01000000000011111001000000000011 00000100100000001100100110010001 00110010010000000000110010010000 00000011000000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000000 10111001100000000110111001110000 00001011100100000000001011100101 00000000101110010000000000100010 01000000000010111001000000000011 01100111100000001101000111100000 00100010010000000100100010010110 00000010001000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001001000000010111001000010 00001011100100000000001011100100 00000000101100010000001001100010 01000000000010111001000000000010 00100100000000001000100100000000 10100000011000000000100000010000 00000010000001100000000001000000 00000000000000000000000000000000 00001000000001000000010010100000 10110001000000000010110001000000 00001011000100000000001011001100 00000000101100010010100001100000 01001000000010110001001000000010 01000100100100001001100100000000 00100000011010000010100000010010 00001010000000100000000100000000 00000000000000000000000000000000 10111000000011010110000010000000 11111010000000000010111000000000 00001011100000000000001111100000 00000000111110000111000000110010 00010100000011111000010100000011 00100001010000001100100001010000 00110010000101000000110010000101 00000011001011100000001101010000 00000000000000000000000000000000 10011000000111011110010000000000 11111101000000100011111001000000 00001111010100000000001111100100 00000000111110010000000000111110 01000100000011111101000100000011 11111100010001001111110100000001 00111111010001000000111111010001 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010010100000 11111101000001000011111001000000 00001111100100000010001111100100 00000000110010010010000000111011 01001000000011001001001001000011 00101101000000001100000101000000 00111110010100100000110010010010 00000011000001100000000001110000 00000000000000000000000000000000 00111000000100001110000100000000 10111000000000010010111000000000 00001011100000000000001011100000 00000000100010000110100000100010 00011010010010001000011010000011 00100001110000001000100000100000 00101110000100000000110111000110 10000010000011100000010000110000 00000000000000000000000000000000 00001000000001011100110000000000 10110001000000000110110001000000 00001011001100000000001011000100 00010000100000010001010000101000 01000100000010010101010000000010 01010100100000001000010100000000 00101111010010000000100001010001 00000010010000100000000101110000 00000000000000000000000000000000 00011000000101011010010000000000 10111001001000010010111001110000 00001011100110000000001011100100 00000000100010010000010000100010 01000000000010010011010000000010 00011100000000000000110100000001 00101111110000000000100101010000 00000010010001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011111001000000 00001111100101100000001111000100 00000000110010010000000000111010 01000000000011011001000000000011 01100111000000001100100110000000 00111100010000000000110010010000 00000011011010000000010001110000 00000000000000000000000000000000 00101000000000011010110000001000 11111001000000000011111011000001 01001111101100000000001101101100 00000010111110010000000010111100 01000000100011101001000000001011 11100110010000101111100100100000 00111110010000100000111110010000 10000011100010100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000100000011001000010000 10001111100011000000001111100000 00000000111110000000000000110010 00000000000011001000010000000011 00100000000000001100100000100000 00110010000001000000111110000000 00000011000010100000010000100000 00000000000000000000000000000000 00101000000001010010100000010000 10111110110000000010001010100000 00001011101000000010001011101000 00000000101110100000000000100010 10001000000010001010010001000010 00101000000100001000101001001000 00100010100000000100101110100000 00000010100010100000000001000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011110010001010010011000000 00001011001100000000001011001100 00000000101110110000000000100000 11100000001010000011100010000010 00001110000000001010001110000001 10100000111100010000101100111100 00000010000010100000000001010000 00000000000000000000000000000000 10100000000000010001110000000000 10110111100000000010010111010000 00001011011100000000001011011100 00000000101100110010000000100001 11100000000010000111010000000010 00011101000001001010111110000000 00100001110000010000101101111100 00000010101010000000000001000000 00000000000000000000000000000000 10101000000010000001111000000000 11110101100000000011010110100010 00001111010110010000001111010110 00000000111101111010000010110000 11000000000011001111100000001011 00111110000000101110011110000000 00110001111000000000111111110000 10001011001010100000001000000000 00000000000000000000000000000000 00001000000111011010110000100000 01110011000000000011101010001000 00001111100101000000001111100001 00000000111110110101000000111110 11000001000011111011000000010011 11101100000000001101101100000000 00111110110000010000111110110110 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011111111100000 00001111111010000000001111111111 00000000111111111100000000110011 11100001000011001101100000000011 00110110010000001111111010000100 00110011101000000000110011001000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000100011001010000000100 10110111000000000010110111000100 00001011011000000011001011011101 00000100101101110001000000100011 01000000000010000111000100000010 00011100110000001011011100011001 00100001100001000010100001100000 00000010001010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110110000100000010110100010000 00001011010001000000001011010100 01100000101100110000000000100001 11000100000010000001000000000010 00010101000000001011011000000000 00100001110000000010100001010000 00000010000000000000000000100000 00000000000000000000000000000000 00100000000101001100010000010000 10110001000001000010110000000000 00001011000010010100001011000011 00000000101100110000000000100010 01000000000010000011000000000010 00000100000000001011101010000000 10100010110000000000100000110000 00000010000010000000010000110000 00000000000000000000000000000000 10101000000101011010000000000000 11111001000000100011111001000000 00001111101101000000001111101010 00000000111111110000010010110010 11000000000011001010000001001011 00101000000000001111100100000000 00110010010000000000110010110000 00000011001010100000010001100000 00000000000000000000000000000000 10000000000000001110100000000100 11111000010000000011111001000000 00001111101100000000001111101101 00000000111110110000000000111110 11000000000011111011010100000011 11101101000000001111100100000000 00111110010100000010111100110100 00000011111000000000000000110000 00000000000000000000000000000000 00000001000100001101001000000000 11001101000000110011111100110000 00001111111100000000001111110000 00101000111111110000000000111111 11000000000011000110101000000011 00111000000000001100110100010000 00110010110000000000110010111000 00000011000000000100010000110000 00000000000000000000000000000000 10000001000001000110101000010000 10001000100000000010111000100000 00001011101110000100001011100000 00000000101110110000000000101110 11000000110010001011010000001010 00101001000000001000100100000000 00100010111101000000101010111000 00000010001000000100000000010000 00000000000000000000000000000000 10000000000001010010000001000010 10001001110000000010111011000000 00001011100000010001001011101000 00001000101110110000000000101110 11000000000010001000000000000010 00000000000010101000101000000000 00100010000000001000100010000110 00000010001000000000000001000000 00000000000000000000000000000000 00001000000001000000001000000000 10000001000000000010110011000000 00001011000000000000001011001100 00001100101100110000000000101100 01000000000010000000000000000010 00001100000000001000001100000000 10100000000000000000101000000000 00000010000000100000000100000000 00000000000000000000000000000000 00000000000011010110000000000000 11001000000000000011111000000000 00001111100000000000001111100000 00000000111111110000000000111110 11000000000011001000000000000011 00100000000000001100000000000000 00110010000000000010110010000000 01000011000000000000001101010000 00000000000000000000000000000000 10100000000111011111000000000000 11111101000000000011111100000001 00001111110000000000001111110000 00000000111111110000010000111111 01000000000011111100000000000011 11110000000000001111110000000000 00111111000000000000111111000000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000111101111010000 00001100011100100000001111111100 00000000010011111000000000111111 11001000010011001111001100000011 00111110000000001111111110000000 00110001111000000000110011011000 01000011011100000000000001110000 00000000000000000000000000000000 10000000000100001110110000000000 10111111110000000010001011010100 00001000111111010000001011111101 10100000101010111000010000101111 11000100000010000111001000000010 10100110000101001011101110000001 01101010111000000000101010011000 01010010001100000000010000110000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000100000010100011001000 00001000001100000100000011001101 00000000100000010000000000101100 11001010000010000011001100010010 00001100000000001011101100000000 00100100110000000000100000010000 00000010011100100000000101110000 00000000000000000000000000000000 11000000000101011010110000010000 10111011000000000010000011000000 00001000101100000000001011101100 00001000101010010000000000101110 11000000000010001011000000000010 10100100000000001011101100000000 00101110110000100000101010010000 00000010001100000000010001100000 00000000000000000000000000000000 01000000000101011110110000000000 11111011000000000010101011000000 01101000101100000000001111101100 00000000110010110000000000111110 11000000001011001011000000000011 00101110010001001111001100000000 00100110110100000000110010011000 00000011010000000000010001110000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111011000000 00001111111100001000001111011100 00010000111111111001010000111101 11000000000011110111000000000011 11110100000100001111111110010000 00111011011100000000111111011001 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010110000000000 11110011000000000011001011000001 01001110101100000000001100101100 00000001110010010000100000111110 11000000001011001011000000000011 10101110000000001111101100001000 00111110110000000000110010010000 00000011110101000000010000100000 00000000000000000000000000000000 11001000000001010010110000000000 10111111011000010010001111000000 00001000111101000000001000111100 00000000101010010000000000101111 11000000010010001111000000000010 00100100000000001011101111000000 00101100110000100000110100011000 00000010111100100000000001000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011100010000010000011000001 00101010001110010000001000001100 00000000101000111100000000101100 11000000000010000011000000000010 00001100100000001011000101010000 00101100110000000000100000011001 00000010111110100000000001010000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010000111100000 00001000011110000100001000011110 01000000101001111000100000101100 11100000000010000111100000000000 00011110000000001011011110000000 00101111111000000000100101011000 00000010111111000000000001000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011000011000000 00001110001100000000101100101100 00000000100000110000001000111100 11000000000011000011000000000011 00001100000000001111000100000000 00111100110000000000110000010000 00000011110100100000001000000000 00000000000000000000000000000000 01000000000111011010110000000000 11110011000000001001111011000000 00001111101101000000001111101100 00000000010110110000000000111110 11000010000011111011000010000011 11101101001000001111101101001000 00111110110000000000111110010001 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110110000000000 11111011010000000011111011000000 10001001001101010000001110101111 01000000110010110011100000101110 11010010000011111011010000000011 11101101000000001011100101000000 00111100110000000100110110010000 00000001111010100000000001110000 00000000000000000000000000000000 01001000000100011001110000000000 10110111010010000010110111001000 00001000011100000100001000001100 10100000101001110000000000101101 11000000000010110111001010000010 11011100000000001011011100000000 00101101100000000000100001110000 00000010111100100000010001100000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110011101100 00001001011110100110001010011110 00000000100001111000000000101101 11101000010010110111100000100010 11011110100000001011010110000001 00101011111000010000100101011000 00000010111000000000000000100000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010111011000000 10001000001100000000001000001100 00000001101000110000000000101100 11000000000010111011000000000010 11001100000001001011001100000000 00101100111100100101100000111000 00000010110100100000010000110000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001101101000000000001110101000 00000000100010100000000100111110 10000000000011111010000000000011 11101000000000001111101000000000 00111011100000100000110110101010 00000011111110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111000000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100001000100 00111110000000000000111110000000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001100100100000000101100100100 00000000111110011000000000111110 01000000000011001001000000000011 00100100000000001100100100010000 00111110010000000010110010011000 00000011110000100000010000110000 00000000000000000000000000000000 10000000000001000110010000000000 10111001010000000010111001000000 00011000100101000000001000100100 00000000001110111001000000101110 01000000010010001001000000000010 00001100000000001101101101001000 00101100010000000100100010010000 00000010111000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 01101000100100000000001000100100 00000000001110010100000000101100 01000000000010101001000000000010 00100100000000001000100100000000 00101110010010000000100010010001 00000010110001100000000001000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001001000000010110001001000 00001000000100100000001000000100 10000100101100010000000000101100 01001000000010100001001000000010 00100110000000001001000100000000 00001110010000000000100000010000 00000010110000100000000100000000 00000000000000000000000000000000 10111000000011010110000101000000 11111010000000000011111000010100 00001000101000000100001100100001 01000000111110000000000000111110 00010100001011101000010100000011 00100000000000001100100000000000 00111110000000000000110010000000 00000011111011100000001101010000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000100000010111001000100 00001111100100010000001111100100 01000000111110010000000000111110 01000100000011011001000100001011 11100100000000001111100100000100 00111111010000000100111111010000 00000011111001100000011001110000 00000000000000000000000000000000 00011000000001011110010001000000 11001101000000000011101001000100 00001101110100100000001111100100 10000100110010010000000100111110 01001001000010111001010000000011 11100100000100000011100100000000 00111111010000000000110001010000 00000011111001100000000001110000 00000000000000000000000000000000 00111000000100001110000000000000 10001000010100000010001000010100 00001000100001000000001011100000 00010000100010000000000000101110 00011010000010111000000001000010 11100000000000001011100000000000 00101110000000000000101010000000 00000010110011100000010000110000 00000000000000000000000000000000 00001000000001011100010010000000 10000001000000000010100001001000 00001000000100010000001011000101 10100000100000010000000000101100 01000100000010110001010000000010 11000100000000001011000100000000 00101110010000000000100000010000 00000010110100100000000101110000 00000000000000000000000000000000 00011000000101011010010000000000 10001001000000000010001001000000 01001000100100000000001011000100 00000110100010010000000001101110 01000000000110111001000000000010 11100100000000001011100100000000 00101110010000000001101010010000 00000010110001100000010001100000 00000000000000000000000000000000 10100000000101011110010000000000 11001001000000000011101001000000 00001100100100000000001111100100 00000000100010011000000000111110 01000000100011111001000000000010 11100100000000001111100100000000 00111110011001100000110010010000 00000011111010000000010001110000 00000000000000000000000000000000 00101000000000011010010000000010 11110001000000000010110001000000 00101110100100001000001111100100 00000000111110010001000000111110 01000000000011111001000001000011 11100100000000001111100100001000 00111110011000000000111110010000 00000011110110100000000001100000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000001 00000000100000000001001111100000 00000001111110000000000100111110 00000000001011001000000000000011 11100000000000001111100000000100 00111110000000000000110010000000 00000011100010100000010000100000 00000000000000000000000000000000 00101000000001010010100000000000 10111110000110000010111010000000 00001000111000000000001011101000 00000000101110100000100000101110 10000000000010001010000000000010 11101000000000001011101000000000 00101100100000000000110110101000 10000010000010100000000001000000 00000000000000000000000000000000 00101000000001010110110000000000 10110011000000000010110011000000 00101000001101010000001011001100 00000000101100110000000000101100 11000000000010010011000000000010 11001110000000001011001100000000 00101100111000000000100100110000 00000010100010100000000001010000 00000000000000000000000000000000 10100000000000010001110000000000 10110110000000000010110011001000 00001000011100000000001011011100 00000000101101010000000000101101 11100000000010010111001100000010 11010000001000001011011100000000 00101111110000110000100111111000 01000010001010000000000001000000 00000000000000000000000000000000 10101000000010000001111100000000 11110111100000000011110111100000 01001100011110000000001111011110 00000000101101101000001000111111 11100001010011010111100100010001 11011110001001001111011110000000 00111101111000000000110101111000 00000011101010100000001000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111010000000000011111011011101 01001111101000000000001111101100 00000100111110110110100000111110 11010000000011101011000000000001 11100000100000001111100001101000 00111100010000000000111110110000 00000011110000100000011001100000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011101111110000 10001100111010010000001111111111 00100000111111111001000000110011 11110010000011111111100001000011 11111110000001001111111010000000 00111111111000000000110011111000 00000011110100000000000001110000 00000000000000000000000000000000 10101000000100011001110001000000 10110101000000000010000111000100 00001000010100000000001011011100 00000000101101010000000000101001 11000100000010110111000000000010 11010000000000001011011100010000 00101101110001010000101001110001 00000010111010100000010001100000 00000000000000000000000000000000 00000000000000001001110000000000 10110110000000000010100111000000 00101000011000000000001011011100 00000000101111000000000001100001 11000000000010010111000000000010 11011100000000001011011000000000 00101111110000000000100001110000 10000010110001000000000000100000 00000000000000000000000000000000 00100000000101001100110000000000 10110000000000000010000011000000 00001000000000000000000011001100 00000001101100010000000001101000 11000000000010110011000000000010 11000000000000001011000000010000 00101100010100000000101000111000 00000010110110000000010000110000 00000000000000000000000000000000 10101000000101011011110000000000 11111001000000000011101111000000 00000100100100000000001011111100 00000000111110110000000000110011 11000000000011011111000000000011 11101110001000001111100110000000 00111100111100100001110010110000 00000011111010100000010001100000 00000000000000000000000000000000 10000000000000001110110000000000 11111000000001000011111011000000 00001111100100000000001111101100 00000000111110000100000000111110 11000000000011110011000000000011 11101100000000001111100100000001 00111110110010000000111110110000 00000011111001000000000000110000 00000000000000000000000000000000 00000001000100001111110000000000 11111101100000000011110011000000 10001100010100000000101100111100 00000000111111100000000000111111 11000000000011111111000000000011 00111000000000001111111111000000 00011111110010000000110011111000 00000011111000000000010000110000 00000000000000000000000000000000 10000001000001000110110000000000 10111000100000000010111011000001 01001000100000000000001000101100 00000000101110100000010000101110 11000000000010111011000000000010 00101000011001001011100010000000 00101110011000000000100010111001 00000010111000010000000000010000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000100000010111011000000 00001000101000010000001000101100 00000000101010110100000000101010 11000000010010111011000000000110 00100100000000011011100000000000 00101110010000000000100010110000 00100010111000000000000001000000 00000000000000000000000000000000 00001000000001000000110000000000 10110001000000000010110011000000 00101000000100000000001000001100 00000000101100000000000000101100 11000000000010110011000000001000 00000100000000011011000100000000 00101110010000000000100000110000 00000010110000100000000100000000 00000000000000000000000000000000 00000000000011010110110000000000 11111010000000000011111111000000 00001100101000000000011100111100 00000000111010000000000000111011 11000000000011111111000000000011 00100000000000001111101000000001 00111110010000000010110010110000 00000011111000000000001101010000 00000000000000000000000000000000 10100000000111011111110000000000 11110100000000000011111111000000 00000111110000000000001111111100 00000000111101000000000100111111 11000000000011111111000000000010 11110000000000001111110000000000 00111101010000000000111111010000 00000011111010000000011001110000 00000000000000000000000000000000 11000000000001011111001000000000 11111100100000100011001100100001 00001100110010000000001111010110 00010000110011011000000000110001 01100000100011001100100000000011 11110000000000001100110000000000 00110011110001000000110011101000 00010011001100000000000001110000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000100010001000100000 00001000101010000000001011100110 00000000100010000000000000100010 01000000000010001010100000000010 11101010000000101000100100000000 00101011110000001000100010101000 00000010001000000000010000110000 00000000000000000000000000000000 10001000000001011100000000000001 10110000000000000010000000100000 00001000000000000000011011000000 00000000100010000000000000101000 01000000001010000010000000100010 11000100000000001000000000000000 00100000110000000010100000100000 00001010001000100000000101110000 00000000000000000000000000000000 11000000000101011010110000000001 10111011000000100010001000000000 01001000101000000000001011100010 00000000100010011000000000101010 11000000000010001010100000000010 11100100000000101000100000000010 00101010110000000010100010100000 00000010001100000000010001100000 00000000000000000000000000000000 00000000000100011110000100100000 11111000000000000011001001000000 01001100100100000000001111100010 00000000110000011010000000111000 01000000000011001000110000000011 11100000100000101100100010010000 10110010110000000000110000101001 10000011000100000000010001110000 00000000000000000000000000000000 11100000000000011011110000000000 11111110000010100011111100010000 00001111111000000010001011110100 00000000111111010000001000110111 01000000000011111100000000000011 11101000000000001111011100000000 00111110110000010000111111110000 00000011111110000000000001100000 00000000000000000000000000000000 01000000000100001010000001000000 11111001000000000000111011000000 00001111100101000010001111100100 11000000110010000000000000111110 11001000000011001000011000000001 11001101000001001100100100100000 10110000110000000010110010110100 10000011110100000000010000100000 00000000000000000000000000000000 11001000000001010010111000010000 10110011010000010010110010110100 01001011101000000000001110000100 00000000100010010000000000001110 11010000001010001000001000000010 11101111001000001000101100000000 00100011110111000010100010111100 10000010111100100000000001000000 00000000000000000000000000000000 11100000000001010100001000000000 10110000100000000010110010010001 00001011000000000000001011000101 00000000100000010000000000101100 01010100000010000000010000000010 11000001001000001000001001000000 00100000110000000000100000001000 00000010111110000000000001010000 00000000000000000000000000000000 01100000000000010001101000000001 10110111100101000010110111100010 00001011011110000000001010111110 00000000100001101000001000101101 01100100000010000110100000000010 11011010000000001000010110011000 00100001111001000000100001001000 00000010110010000000000001000000 00000000000000000000000000000000 01001000000010000000000000000000 11110000000010000011110010000000 00001111000001000000001111001100 00000000110000110000000000111100 01000100000011000010010100000011 11000000000000101100101000010001 01110000110001000100110000100000 01000011110100100000001000000000 00000000000000000000000000000000 01000000000111011011100000000000 11111111000000000011111111010000 00001111111100000000001111111100 00000000111111110000000000111111 11000100000010111110000000000011 11110000000000001111110000010000 00111111110001100000111111100100 00000011110100000000011001100000 00000000000000000000000000000000 10101000000001011110010000000000 11110000110000000011001001001000 00001111000111100000001100101000 00000000111110110000000000110010 01000000010011001000000000000011 11100100000000101100101000000000 10110000110010000000110010010110 00000011111010100000000001110000 00000000000000000000000000000000 01001000000100011001110001000000 10110110000100000010000101000000 00001011011100001000001000011100 00000000101111010000000000110111 01000000000010000110000000000010 11011100000000001000011100000000 00100001110011000000100001010000 00000010110100100000010001100000 00000000000000000000000000000000 11000001000000001001011000000001 10111101100000000010100111110000 00001011110110000000001001010110 00100000101101111000000000100001 11100000000010000110110000000010 11001110000000001010001110000000 00100001111010000000100001111000 00000010111100000000000000100000 00000000000000000000000000000000 01001000000101001100110100000000 10110011000000000010000011000000 00001011001100000000001001001100 00100100101110111111000000100100 11100000000010000011100000000010 11001110010000001010001101110000 00100000110000000000100000110000 00000010110100100000010000110000 00000000000000000000000000000000 11101000000101011000100100000000 11111010010000000011101010000000 00001111101001000000001101111010 00000000111111100100000000110010 10101000001011001110100000000011 11111001000010001110111011000000 00110010100000000000110010100100 00000011111110100000010001100000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000010001011111000110000 00001111100000001000101110100001 00000000111110000000000000111110 00000000001011111000000000000011 11100000001000000001000000000000 00111110000000000010111110001000 00000011110100100000000000110000 00000000000000000000000000000000 00001000000100001110110000100000 11011011010000000011111011000000 00001111101110000000001111100100 01000000101110010000000000110010 01000000000011001001000010000011 11000110100000001100100100000011 00110000010000001000110010111000 00000011110000100000010000110000 00000000000000000000000000000000 10000000100001000110010000000000 10001001010000000010111001011000 00001011100110000000001011100111 00000000101110010000001000100000 01100000000010001001000000000010 11100110000000101000100101000010 00100010010000000010100010011100 00000010111000000000000000010000 00000000000000000000000000000000 00011000000001010010010000000000 10011001000010000010111001000100 00001011100100100000001011101100 00000000101110010000000010100010 01001000000010001001001001000010 11100101000000001000100101000000 10100010010000000000100010010010 00000010110001100000000001000000 00000000000000000000000000000000 00001000000001000010010000000000 10000001000001000010110001000000 00001011000100000010011011000100 00000000101100010000000000100010 01000000000010000001000000000010 11000100100000101000000100100000 00100000010010000000100000011000 00000010110000100000000100000000 00000000000000000000000000000000 10111000000011010110000000000000 11011000000000000011111000000000 00001111100000000000001111101000 00000100111110000101000000110010 00010100000011001010000000010011 11100000000000001100100001010000 10110010000101000000110010000000 00100011111011100000001101010000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111110100 00000000111111010000000000111111 01000000001011111101000000000011 11110100010000001111111100010000 00111110010001000010111111010000 00000011111001100000011001110000 00000000000000000000000000000000 10011001000101011100010000000000 11111101000000010011111101000000 00001100100100000000001111110100 00000000111110010100000000111101 01000000000011000101000000000011 00110100001000001100110100000000 00110011010110100100110010010000 00000011110001100000000001110000 00000000000000000000000000000000 00111001000110001110000000010000 10111000000000100010111000000000 10001101100000000000001011101000 00001000101110000000001000101110 00000000000010001000000000000010 00100000000000001000000001100000 10100010000100000010101010000000 00000010110011100000010000110000 00000000000000000000000000000000 00001000000001011100010000001000 10110001000000000010111001000000 00001000000100000010011011000100 00000000101100010010000000101100 01001010000010000001100000011010 00000100000000101000000101001000 10100000010000000010100000010000 00000010110000100000000101110000 00000000000000000000000000000000 00011000000001011010010000000000 10111001010000000010111001000000 00001001100100000000011011100100 01000000101110010010000100101110 01001000001010001001000000000010 00100101000000001000100100000010 00100010010000000000101010010010 10000010110001100000010001100000 00000000000000000000000000000000 10100000000101001010010000000000 11111001010000100011111001000001 00001100100100000000001111100111 00000000111110010010000000111110 01000000010011000001010000000011 00100110000001001100100101000000 10110010010000000010110010010000 00000011111010000000010001110000 00000000000000000000000000000000 00101010000000001010110000001100 11111001000000000011111001001000 00001111101100000000001011100100 00010000111110011000000000111110 01100000100011111001001000000011 11100111000000001111100100001010 00111110010000000000111110110000 00000011110010100000000001100000 00000000000000000000000000000000 00101010000100001010000000000000 11001000001000000011111000000000 00001111100000000000001111100010 01000000101110000000000000111110 00000000000011001000000010000011 00000000000000001111100001000000 10110000000000000010110010000000 00000011000010100000010000100000 00000000000000000000000000000000 10100000100001000010100000000000 10001110000000000010110110101000 00001011101000000000000011111000 00000000101110100000000000101111 10100010001010001110010010001010 00111010010000001011111011000000 00100011100000001000110110100000 00000010000010100000000001000000 00000000000000000000000000000000 00101000000001010100111001000000 10000011000000000010110011100010 01001011001110010000000011001100 00000000101100110000000000101110 11100000000010000011010000000110 00001000010101001011101110000000 00100000001000000000100000110010 00100010000010100000000001010000 00000000000000000000000000000000 01100001000000010001111000000000 10000101010000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 01000000000010001111000000000010 00011100000000001011011101000000 00100000010100000010100111111000 00000010001010000000000001000000 00000000000000000000000000000000 00101000000010000001111000000000 11000111100000000011110111100000 00001111011110000000001111010110 00000000101101111010001000111101 11100000000011000111100000000011 00011110000000001111011110000000 00110001001000000010110001001000 00001011001010100000001000000000 00000000000000000000000000000000 01001000000111011010110000101010 11111010000000100011111010000000 10001111101100000000001111101100 00000000111110110000000000111110 01000000000011111001000000000010 11101100000000001111101000000000 00111110010000000000111100000000 10000011110000100000011001100000 00000000000000000000000000000000 11000000000001011111011000000000 11111111100100000011111101100100 00001111110111010000001111111110 01000000111111111000100000111111 11100000000011001111100000000011 11111110010000001100111010000000 10110011101000001000110011111000 00000011000000000000000001110000 00000000000000000000000000000000 10101000000000011001110100000000 10110111000000000010110111000000 10001011010101000000001011011000 00000000001101110000000000101111 11000000000010000111000000000010 11011100000000001101010100000000 00110101010000000000101001110000 00000010101010100000010001100000 00000000000000000000000000000000 00011001000000001001010000000000 10110111000000010010110111000000 00011011010100000001001011011100 00000001101101110000000000101101 11000000000010100110000000000010 11001100001010001001011000000000 00100001100000000000100001000000 00000010000000000000000000100000 00000000000000000000000000000000 01100010000101001100110001001001 10110001111000000010110000010000 00001011000100100000001011000100 10000001100100111100000000101100 11000000000010100000010000000010 11001110000000001001000000100010 00100100010000000000101000000000 10000010100010000000010000110000 00000000000000000000000000000000 11111000000101011010100000000000 11111001000000000011111001000000 00001111101010100000001111100101 00000000111111110000000000111110 10000000001011101011000100000011 11001110000000001101100101000000 00110010000000000000110010000000 00100011001010100000010001100000 00000000000000000000000000000000 10000000000000001110000100100000 11111001010100000011111001010000 00001111101001000000001111100101 01000000111110110011000000111110 01010100100001011010100000000011 11101101000000001111001100010000 00111110000100000000111110100100 00000011111000000000000000110000 00000000000000000000000000000000 11000001000100001111101000000000 11111101000000100011111101000010 00001111110000000000001100110000 00000000111111110000000001111111 00000000000011001111000100000011 11111100000000001100110110010100 00110001000000000000110011000000 00000011000000000100010000110000 00000000000000000000000000000000 10000001000001000110001000000000 10111000110001000010011001100001 00001011000000000000001000100110 10000000110010110000001001111100 01101000001010001000011000000010 01101111100000001000101010000010 00100010000100001000100000000000 00000011001000000100000000010000 00000000000000000000000000000000 10000000000000010110000001000000 10111000110000000010111000100010 00001011101000100000101000100110 00000000101110110000010000101110 10100000000010001001000000000010 11100110000001001000100000000000 00100010100000100000100010000110 00000010001000000000000001000000 00000000000000000000000000000000 00001000000000000000000000000000 10110001000000000110010001000000 00001011001000000000001000000000 00001000101000110000001000101000 11000000000010000000000000000010 01001100000000001000000100000000 10100000000000001100100000110000 00000010000000100000000100000000 00000000000000000000000000000000 10000000000000000110000000000000 11111000000000000011111000000000 00001111100000000000001100100000 00000000111110110000000000101110 00000001000011001000000000000011 11101100000001001100000000000000 10110000100000000100110010000000 00001011000000000000001101010000 00000000000000000000000000000000 10100000010110011111000000010000 11111101000000000011011101000000 00001111110000000000001111110100 00001000110011110000000000111111 01000000000011111100000000000011 01111100000010000111110000000000 00111111000000000000111101000000 00000011101010000000011001110000 00000000000000000000000000000000 00000000110001010100000100000011 01110000010000001001110001010000 00000111000001000000110111000101 00000001011100010100000011011100 00010000001101110000010000001101 11000101000000110111000101000000 11011100000100000011011100000100 00001101110000000011000100000000 00000000000000000000000000000000 00000000110001010100010000000101 01110001000000010101110001000000 01110111000100000001010111000100 00000101011100011000000101011100 01000000010001110001000000010101 11000100000001010111000100000001 01011100010000000101011100010000 00010101110000000011000101010000 00000000000000000000000000000000 00000000100000000000001000000001 00100000100000000100100001100000 00010010000010000000010010000110 00000001001000001000000001001000 00100000000100100000100000000100 10000010000000010010000110000000 01001000001000000001001000001000 00000100100000000010000000000000 00000000000000000000000000000000 00000000100000000000000000000001 01100000000000000101100000000000 00010110000000000000010110000000 00000101011000010000000001011000 00000000000100100000000000000101 10000100000000010110000000000000 01011000000000000001011000000000 00000101100000000010000000000000 00000000000000000000000000000000 00000000110001010100100000000101 01110010000000010101110010000000 01010111001000000001010111001001 00000101011100100000000101011100 10000000010101110011000000010101 11001010000001010111001000000001 01011100100000000101011100100000 00010101110000000011000101010000 00000000000000000000000000000000 00000000110001010100000000000000 01100000000000000001100001000000 00000110000000000000000110000010 00000000011000000000000000011000 00000000000001100000000000000001 10000000000000000110000101000000 00011000000000000000011000000000 00000001100000000011000100000000 00000000000000000000000000000000 00000000110001010100100000000100 00100010000000010000100000100000 01000010001000000001000010000100 00000100001000100000000100001000 10000000010000100011000000010000 10001000000001000010001110000001 00001000100000000100001000100000 00010000100000000011000100000000 00000000000000000000000000000000 00000000110001010100111100000101 01000010100000010101000001110000 00010100001010000001010100000010 00000001010000101000000101010000 10100000010101000010100000010101 00001010000001010100001010000001 01010000101100000101010000111100 00010101000000000011000101010000 00000000000000000000000000000000 00000000100000000000111000000001 00010011000000000101010111000000 00010001011100000000010101001100 00000001010100110000000000010101 11000000000101010111000000000101 01001100000000010101011100000000 01000000110000000001000100110000 00000100010000000010000000000000 00000000000000000000000000000000 00000000100000000000010000000000 00010000000000000001000001000000 01000001000000000000000100001100 00000000010000000000000000010000 00000000000001000001000000000001 00000000000000000100000100000000 00000000000000000000000100011000 00000000010000010010000000000000 00000000000000000000000000000000 00000000110001010110000000000010 00011000000000001000001000000000 00100001100000000000100000100000 00000010000010000000000010000010 00000000001000001000000000001000 00100000000000100000100000000000 10000010000000000010000110000000 00001000010000010011000101010000 00000000000000000000000000000000 00000000110001010100000000000101 01100000000000010101100100000000 01010110010000000001010110000000 00000111011000000000000101011001 00000000010101100100000000010101 10000000000001010110010000000001 01001000000000000101011000000000 00010101100000000011000100000000 00000000000000000000000000000000 00000000110001010100000000000011 01100000000000001101100000000000 00010110000000000000110110001000 00000001011000000000000011011000 00000000001101100000000000001101 10000000000000110110000000000000 11011000000000000011011000000000 00001101100000000011000100000000 00000000000000000000000000000000 00000000110001010100001000000100 00110000100000010000110000100000 01100011000010000001000011000011 00000100001100001000000100001100 00100000010000110000100000010000 11000010000001000011000010000001 00001100001000000100001100001000 00010000110000000011000101010000 00000000000000000000000000000000 00000000100000000000000000000000 00110000000000000000110010000000 00000011000000000000000011000000 00000000001100000000000000001100 00000000000000110000000000000000 11000000000000000011000000000000 00001100000000000000001100000000 00000000110000000010000000000000 00000000000000000000000000000000 00000000100000000000001000000001 00110000100000000100110010110000 00010011000010000000010011000010 00000101001100001000000001001100 00100000000100110000100000000100 11000010000000010011000010000000 01001100001000000001001100001000 00000100110000000010000000000000 00000000000000000000000000000000 00000000110001010100001000000101 01100000100000010101100000110000 01010111000010000001010110000011 00000101011000001000000101011000 00100000010101100000100000010101 10000010000001010110000010000001 01011000001000000101011000001000 00010101100000000011000101010000 00000000000000000000000000000000 00000000110001010100001000000000 00100000100000000000100000100000 00000110000010000000000010000010 00000000001100001000000000001000 00100000000000100000100000000000 10000010000000000010000010000000 00001000001000000000001000001000 00000000100000000011000100000000 00000000000000000000000000000000 00000000110001010101001000000100 01100000100000010001100100100000 01000010000010000001000110010010 00000100001100001000000100011000 00100000010001100100100000010001 10000010000001000110010010000001 00011001001000000100011001001000 00010001100000000011000100000000 00000000000000000000000000000000 00000000110001010110000000000101 01011000000000010101011000000000 00010001100000000001010101100000 00000000000110000000000101010110 00000000010101011000000000010101 01100000000001010101100000000001 01010110000000000100010110000000 00010101010000000011000101010000 00000000000000000000000000000000 00000000100000000000011000000001 01000001100000000101000001100000 00010100000110000000010100000110 00000001010000011000000001010000 01100000000101000001100000000101 00000110000000010100000110000000 01010000011000000000010000011000 00000100000000000010000000000000 00000000000000000000000000000000 00000000100000000001001000000001 00000000100000000100000100100000 01010000000010000000010000010010 00000001000000001000000001000000 00100000000100000100100000000100 00000010000000010000010010000000 01000001001000000001000001001000 00000100000000000010000100000000 00000000000000000000000000000000 00000000110001010100011000000011 01010001100000001101010001100000 00110101000110000000110101000110 00000011010100011000000011010100 01100000001101010001100000001101 01000110000000110101000110000000 11010100011000000011010100011000 00001001010000000011000101010000 00000000000000000000000000000000 00000000110001010100011000000101 01110001100000010101110001100000 01010111000110000001010111000110 00000111011100011000000100011100 01100000010101110001100000010001 11000110000001010111000110000001 01011100011000000101011100011000 00010101110000000011000100000000 00000000000000000000000000000000 00000000010001010100011000000011 01110001100000001101110001100000 00010111000110000000110111000110 00000000011100011000000011011100 01100000001101110001100000001001 11000110000000110111000110000000 11011100011000000011011100011000 00001101110000000001000100000000 00000000000000000000000000000000 00000000010001010100011000000101 01110001100000010101110001100000 01100111000110000001010111000110 00000000001100011000000101011100 01100000010101110001100000010101 11000110000001010111000110000001 01011100011000000101011100011000 00010101110000000001000101010000 00000000000000000000000000000000 00000000000000000000001000000001 00100000100000000100100000100000 00010010000010000000010010000010 00000001011100001000000001001000 00100000000100100000100000000100 10000010000000010010000010000000 01001000001000000001001000001000 00000100100000000000000000000000 00000000000000000000000000000000 00000000010000000000011000000001 01100001100000000101100001100000 00010010000110000000010110000110 00000101011000011000000001011000 01100000000101100001100000000001 10000110000000010110000110000000 00011000011000000000011000011000 00000101100000000000000100000000 00000000000000000000000000000000 00000000010001010100000000000101 01110000000000010101110000000000 01010111000000000001010111000000 00000101011100000000000100011100 00000000010001110000000000010100 11000000000001010111000000000001 01001100000000000100011100000000 00010101110000000001000101010000 00000000000000000000000000000000 00000000010001000100001000000000 01100000100000000001100000100000 00000110000010000000000110000010 00000000011000001000000000011000 00100000000001100000110000000000 10000010000000000110000011000000 00001000001000000000011000001000 00000001100000000001000100000000 00000000000000000000000000000000 00000000010001010100001000000100 00100000100000010000100000100000 01000010000010000001000010000010 00000100001000001000000100001000 00100000010000100000100000010001 10000010000001000010001010000001 00011000001000000100001000001000 00010000100000000001000100000000 00000000000000000000000000000000 00000000010001010100001000000101 01000000100000010101000000100000 00010100000010000001010100000010 00000001010000001000000101010000 00100000010101000000100000010101 01000010000001010100000010000001 01010100001000000101010000001000 00010101000000000001000101010000 00000000000000000000000000000000 00000000000000000000001000000001 01010000110000000101010000100000 00010101000011000000010101000011 00000001010100001100000001010100 00110000000101010000110000000101 01000011000000010101001010000000 01010100001100000001010100001000 00000101010000000000000000000000 00000000000000000000000000000000 00000000010000000000100000000000 01000010000000000001000010000000 01000100001000000000000100001000 00000000010000100000000000010000 10000000000001000000000001000001 00001000000000000100000000000000 00010000100000000000010000100000 00000001000000000000000000000000 00000000000000000000000000000000 00000000010001010100001000000010 00100000100000001000000000100000 00100000000010000000100000000010 00000000000000001000000010000000 00100000001000000010100000001000 00000010000000100000000010000000 10000000001100000010000000001000 00001000000000000001000101010000 00000000000000000000000000000000 00000000010001000100000000000101 01100000000000010101100000000000 01010110000000000001010110000000 00000111011000000000000101011000 00000000010101100000000000010101 10000000000001010110000000000001 01011000000000000101011000000000 00010101100000000001000100000000 00000000000000000000000000000000 00000000110001010100000000000011 01100000000000011101100000000001 01010010000000000000110110000000 00000001011100000000000011011000 00000000001101100000000000001101 10000000000000010110000000000000 11011000000000000011011000000000 00001101100000000000000000000000 00000000000000000000000000000000 00000000000000000000000100000100 00110000000000000000110000010000 01000010000000000001000011000000 00000100011000000000000100001100 00000000010000110000000000000000 11000000000000000011000000000001 00001100000000000100001100000100 00010000110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000000110101000000 00000010000110000000000011010000 00000000001001000000000000001100 01000000000000110001000000000000 11010000000000000011010110000000 00001100000000000000001100000000 00000000110000000000000000000000 00000000000000000000000000000000 00000000000000000000010100000001 00110001010000010100110001110000 01010010000101000000010011000101 00000101001100010100000001001100 01010000000100110001110000000100 11000101000000010011000100100000 01001100010000000001001100010100 00000100110000000000000000000000 00000000000000000000000000000000 00000000000000000010001100000101 01101000110000000101101000110000 00010110100011000001010110100011 00000101011010001100000101011010 01110000010101101001110000010101 10100011000001010110100011000001 01011010001100000101011010001100 00010101100000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000000000100101000000 00000010000100000000000010010000 00000000001001000000000000001000 00010000000000100010000000000000 10010000000000000010010100000000 00001000000000000000001000000000 00000000100000000000000000000000 00000000000000000000000000000000 00000000000000000000100001000100 01100010000100000001100010000000 00000110001000000001000110001000 01000100011000100001000100011000 10000000010001100000000110010001 10001000010001000110000000010001 00011000100001000100011000100001 00010001100000000000000000000000 00000000000000000000000000000000 00000000000000000000000001000101 01010000000100000101010000000100 00010101000000010001010101000000 10000000010100000001000100010100 00000100010101010000000001010101 01000000010001010101000000011001 01010100000001000101010100000001 00010101010000000000000000000000 00000000000000000000000000000000 00000000000000000000100000100000 01000010000010000101000010000010 00000100001000001000010100001000 00100001010000100000000001010000 10000010000101000010000010000101 01001000000000010100001000000000 00010100100000100001010000100000 10000101000000000000000000000000 00000000000000000000000000000000 00000000000000000000101000000001 00000010100000000100000010111110 01010000001010000000010000001010 01000001000000101000000001000000 10100000000100000010100000000000 00001010000000010000001010000000 00000000101000000001000000101010 01000100000000000000000000000000 00000000000000000000000000000000 00000000000000000000110010000011 01010011000000000101010011001110 00110101001100000000110101001100 01000011010100110000000011010100 11000000001101010011000000000000 01001100000000010101001100100000 10000100110000000011010100110010 00001101010000000000000000000000 00000000000000000000000000000000 00000000000000000000100010000101 01110010000000010101110010010000 01000111001000000001010111001000 00000110011100100000000101011100 10000000010101110010000000010101 11001000000001100111001000001001 00011100100000000101011100100010 00010101110000000000000000000000 00000000000000000000000000000000 00000000000000000010001100001000 01001000110001100001000000110000 00000100000011000110000100100011 00000000010010001100010000010000 00110001100001000000110000100001 00100011000100000100000011000000 00010010001100001000010010001100 00100001000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 01001111111111111101001111111111 11110100111111111111110100111111 11111111010011111111111111010011 11111111111101001111111111111101 00111111111111110100111111111111 11010011111111111111010011111111 11111101000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010110111111011 00001011001101101100001001011111 11110100100100110110110000101100 10011111010010110011011001000010 01001101101100001111101001101100 00101100110110010000111111111110 01000010110011011011000010110111 11101100000000000000000000000000 00000000000000000000000000000000 00000000000000000011001111111100 01001100110011110001001101011111 11110100110101001111000100110010 10111111010011001100111101000011 01010011110001001111101011110001 00110011001111010000111111111111 01000011001100111100010011001111 11110001000000000000000000000000 00000000000000000000000000000000 00000000000000000011101100011110 01001110110111111001001110010001 10000100111001011111100100111010 01111000010011101101111110000011 10010111111001001000100111111001 00111011011111100000100011000111 10000011101100011110010011101100 01111001000000000000000000000000 00000000000000000000000000000000 00000000000000000000000100000110 01110000010001011001110001010000 00110011000001000000110111000101 00000001011100010100000000011100 00010000001001110000010000001001 11000001000000100111000001000001 00011100000100000110011100010100 00000001110000000000000000000000 00000000000000000000000000000000 00000000000000000000010000000001 01110001000000010101110001000000 00010011000100000001010011000000 00000111001100000000000101011100 01000000010101110001000000010101 11000100000001010111000100000001 01011100010000000101011100010000 00000101110000000000000000000000 00000000000000000000000000000000 00000000000000000000001000000001 00100000100000000100100000100000 00010010000010000000000010000010 00000000001000001000000001001000 00100000000100100000100000000100 10000010000000010010000010000000 01001000001000000001001000001000 00000100100000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 01100000000000010001100101100000 00000110000000000000000110010010 00000000011001000000000100011000 00000000000001100000000000000001 10000000000000000110000000000000 00011000000000000100011000010000 01000001100000000000000000000000 00000000000000000000000000000000 00000000000000000000100100000000 01110010000000000001110010000000 00010010001000000001000111001000 00000100011100101000000100011100 10000000010001110010010000010001 11001000000001000111001000000001 00011100100000000100011100101000 00010001110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01100000000000000001100100000000 01000110000000000000000110010000 00000000011001000000000000011000 00000000000001100000000000000001 10000000000000000110000000000000 00011000000000000000011000000000 00000001100000000000000000000000 00000000000000000000000000000000 00000000000000000000100000000000 00100010000000000000100100000000 01000010001000000001000010010000 00000100001001000000000100001000 10000000010000100010000000010000 10001000000001000010010000000001 00001000100000000100001001100000 00010000100000000000000000000000 00000000000000000000000000000000 00000000000000000010111100000000 01001010110001000001001000100000 01000100101010000001000100100011 00000000010010001000000000010010 10100000010001001010000000010001 00101010000001000100100011000001 00010010101100000000010010101100 00010001000000000000000000000000 00000000000000000000000000000000 00001000110000000000110000000000 00010010000000000000010010000000 00000000001100000000000101001000 00000000000100110000000000010100 11000000000001010011000000000100 00001100000000000101001100000000 01000000110000000000000100110000 00000000010000000001000000000000 00000000000000000000000000000000 00000000110000000000010000000000 00010001100000000000010101100000 00000000000000000000000100010110 00000100000101100000000000011000 00000000000001000001000000000001 00000000000000000100010000000001 00000100000000000000000101000000 00000000010000000011000000000000 00000000000000000000000000000000 00001000110000000100000000000000 00010000000000001000010000000000 01100000000000000000100000000000 00000010000100000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 10000000000000000010000100000000 00000000010000000011000000000000 00000000000000000000000000000000 00001000110000000100000000000100 01100000000000010001100000000000 01000010000000000000000110000000 00000000011000000000000110011000 00000000010001100000000000010001 10000000000001000110000000000001 00011000000000000100011000000000 00111001100000000011000000000000 00000000000000000000000000000000 00010000000000000100000000000000 01100000000000100001100000000000 00100110000000000000100110000000 00000000011000100000000000011000 00000000001001100000000000001001 10000000000000100110000000000000 00011000000000000010011000000000 00001001100000100000000000000000 00000000000000000000000000000000 01000000010001010100001000000000 00110000100000000000110000100000 00000011000010000001000011000010 00010110001100001000000100001100 00100000010000110000100000010000 11000010000001000011000010000001 10001100001000000100001100001000 00010000110000000001000101010000 00000000000000000000000000000000 01000000010000000000000000000000 00110000000000000000110010000000 00000011000000000000000011001000 00000000001100000000000000001100 00000000000000110000000000000000 11000000000000000011001000000000 00001100000000000000001100000000 00000000110000000001000001000000 00000000000000000000000000000000 01000000000000000000001000000000 00110000100000000000110010110000 00000011000010000000000011001011 00000000001100001100000100001100 00100000000000110000100000000000 11000010000000000001001011000000 00001100001000000000001100001000 00000000110000000000000000000000 00000000000000000000000000000000 01000000010001010100000000000100 01100000000000010001100000011000 00000011000010000001000110000001 00000100011100001100000100011000 00100000010001100000100000010001 10000010000001000110000011000001 00011100001000000100011000001000 00010001100000000001000101010000 00000000000000000000000000000000 01000000000000010100001000000000 00100000100000000000100000100000 01000010000010000000000010000010 00000000011000001000000000001100 00100000000000100000100000000000 10000010000000000010000010000000 00011000001000000000001000001000 00000000100000000000000000000000 00000000000000000000000000000000 01010000000000000100001000000100 01100000100000010001100000100000 01000010000010000001000110000010 00000100001000001000000100001100 00100000010001100000100000010001 10000010000001000110000010000001 00001000001000000100011000001000 00010001100000000000000000000000 00000000000000000000000000000000 01000000010001010100000000000100 01010000000000010001010000000000 01010001000000000001000101000000 00000000000100000000000000000100 00000000010001010000000000010001 01000000000001000101000000000000 00000100000000000100010100000000 00010001010000100001000101010000 00000000000000000000000000000000 01001000010000000000011000000000 01000001100000000001000001100000 00000100000110000000000100000110 11000000010000011000000000010000 01100000000001000001100000000001 00000110000000000100000110000000 00010000011000000000010000011000 00000001000000000000000000000000 00000000000000000000000000000000 01001000000000000000001000000001 00000000101010000100000000101100 00010000000010000000010000000010 11010101000000001001000001000000 00100000000100000000100000000100 00000010000000010000000010000001 01000000001000000001000000001000 00000100000000000000000000000000 00000000000000000000000000000000 01000000010001010100011000100001 01010001101000000101010001100110 01110001000110000000110101000110 11000011010100011001000011010100 01100000001101010001100000001101 01000110000000110101000110000000 11010100011000000011010100011000 00001101010000000001000101010000 00000000000000000000000000000000 00000000000000010100011000101110 01110001100010011001110001000010 01010011000110000001000111000100 10100100011100010010000110011100 01100000010001110001100000010001 11000110000001000111000110000001 00011100011000000100011100011000 00010001110000000000000000000000 00000000000000000000000000000000 01000000000000010100011000000010 01110001100000001001110001100000 00110111000110000000110111000110 00000001011100011000000000011100 01100000001001110001100000001001 11000110000000100111000110000001 00011100011000000010011100011000 00001101110000000000000000000000 00000000000000000000000000000000 01010000010001010100011000000101 01110001100000010101110001100100 00000111000110000001010010000110 00000111001100011000010100001100 01100000010101110001100000010101 11000110000001010111000110000001 00001100011000000101011100011000 00010100110000100001000101010000 00000000000000000000000000000000 01000000000000000001001000000001 00100100100000000100100100100100 00010010000010000000010010010010 00000001011000001000000001011100 00100000000100100100100000000100 10000010000000010010010010000000 00001001001000000001001001001000 00000101100000000000000000000000 00000000000000000000000000000000 01000000000000000000011000000000 01100001100000000001100001100000 00000010000110000000000110000110 00000001011000011000000100011000 01100000000001100001100000000001 10000110000000000110000110000001 00001000011000000000011000011000 00000001100000000000000000000000 00000000000000000000000000000000 00000000010001010110000000010100 01111000000000010001111000000010 00000011100000000001000111100000 00000100011110000000000100011110 00000000010001111000000000010001 11100000000001000111100000000001 00011110000000000100011110000000 00010001110000000001000101010000 00000000000000000000000000000000 01000000000000010101001000000000 01100100100000000001100100101000 01000010000010000000000110010010 00000000011000001000000000011000 00100000000001100100100000000001 10000010000000000110010010000000 00011001001000000000011001001000 00000001100000000000000000000000 00000000000000000000000000000000 01000000000000010101001000000100 00100100100000010000100100101000 01000110000010000001000010010010 00000100001000001000000100001000 00100000010000100000100000010000 10000010000001000010000010000001 00001000001000000100001000001000 00010000100000000000000000000000 00000000000000000000000000000000 01000000010001010100001000000100 01000000100000010001000000011000 01000101000010000001000100000010 00000000010000001000000000010000 00100000010001000000100000010001 00000010000101000100000010000000 00010000001000000100010000001000 00010001000000000001000101010000 00000000000000000000000000000000 01000000000000000001001000000000 01010100100000000001010100100000 00000101000011000000000101010010 00000000010100001100000000010100 00110000000001010000110000000001 01000011000000000101000010000000 00010100001000000000010100001000 00000001010000000000000000000000 00000000000000000000000000000000 01000000000000010000100000000000 01100010000000000001100100000100 00000110001000000000000100001000 00000100010000100000000000010000 10000000000001000010000000000001 00001000000000000100001000000001 00010000100000000000010000100000 00000001000000000000000000000000 00000000000000000000000000000000 01000000010001010100001000100010 00000000100010001000000000100110 00000000000010000000100000000010 00100010000000001000000010000000 00100000001000000000100000001000 00000010000000100000000010000000 10000000001000000010000000001000 00001000000000000001000101010000 00000000000000000000000000000000 01000000000000010100000010000100 01100000000000010001100100001100 01000110000000000000000110000000 01000100011000000001000110011000 00000000010001100000000000010001 10000000000001000110000000000001 00011000000000000100011000000000 00010001100000000000000000000000 00000000000000000000000000000000 01000000000000010100000010000010 01100000001000001001100100001100 00000010000000000000100110000000 10100000001000000001000000011101 00000000011001100100000001011001 10000000000000100110010000000000 00001000000000000010011000000000 00001001100000000000000000000000 00000000000000000000000000000000 01000000010001010110000010000100 00111000001000010000111000000110 00000010100000000001000011100000 00100110001010000000100100011010 00000000011000111000000000010000 11100000000001000011100000000001 10001010000000000100001110000000 00010000110000000001000101010000 00000000000000000000000000000000 01010000000000000000000100000000 00110000010000000000110001010100 00000010000001000000000011000001 00000000001000000100000000001000 01010000000000110001010000000000 11000001000000000011000101000000 00001000000100000000001100000100 00000000110000000000000000000000 00000000000000000000000000000000 01000000000000000000010000000000 00110001000000000000110101001000 00000010000101000000000011000100 00100000001000010100100100001101 01010000000000110101010000010000 11000101000000000011010100000000 00001000010000000000001100010000 00000000110000100000000000000000 00000000000000000000000000000000 01000000010001010100001100000100 01100000110000010001100000111000 00000110000011000001000110000011 00000100011000001100000100011000 00110000000001100000110000000001 10000011000001000110000111000001 00011000001100000100011000001100 00010001100000000001000101010000 00000000000000000000000000000000 01000000000000010100000000000000 00100000000000000000100011000000 01000010000000000000000010000000 00000000001000000000000000001000 01000000000000100001000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000000000 00000000000000000000000000000000 01000000000000010100100001000100 01100010000100010001100011000100 01000110001000010001000110001000 01000100011000100001000100011000 10000000000001100010000000000001 10001000010001000110001000000001 00011000100001000100011000100001 00010001100000000000000000000000 00000000000000000000000000000000 01000000010001010100000001000100 01010000000100010001010000000100 01000101000000010001000101000000 01000001000000000001000000010100 00010100000001010000010000000001 01000000010001000101000100010000 00010100000001000100010100000001 00010001010000000001000101010000 00000000000000000000000000000000 01000000010000000000100000100000 01000010000010000001000010001010 00000101001000001000000100001000 10100000010000100000100000010000 10000010000001000010000010000001 00001000001000000100001000001000 00010000100000100000010000100000 00000001000000000000000000000000 00000000000000000000000000000000 00000000000000000100101000000001 00000010100000000100000010100000 00000000001010000000010000001010 01000101000000101000100001000000 10100000000100000010100000000100 00001010000000010000001010000001 01000000101000000001000000101000 00000100000000000000000000000000 00000000000000000000000000000000 01000000010001010100110100000011 01010011010010001101010011010010 00000001001101000000110101001101 01000011010100110100000011010100 11010000001101010011010000001101 01001101000000110101001101000000 11010100110100000011010100110100 00001101010000000001000101010000 00000000000000000000000000000000 01000000000000010100100010000000 01110010000000000001110010000000 01100111001000000001000111001000 10000100011100100000000110011100 10000000010001110010000000010001 11001000000001000111001000000001 00011100100000000100011100100000 00010001110000000000000000000000 00000000000000000000000000000000 00000000000000000010001100001000 01001000110000100001000000110000 00000100100011000110000100100011 00000000010010001100010000010000 00110001100001000000110000100001 00100011000110000100000011000000 00010010001100001000010010001100 00000001000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 01001111111111111101001111111111 11110100111111111111110100111111 11111111010011111111111111010011 11111111111101001111111111111101 00111111111111110100111111111111 11010011111111111111010011111111 11111101000000000000000000000000 00000000000000000000000000000000 00000000000000000000000001000000 00000000000100000000000010000100 00100000000000000000000000000000 01000010000000000000000010000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010110111111011 00001011011111101100001111111111 11110100101100110110110000101101 11111111010010110011011111010010 01001101101100001001001001101100 00101100110110110000100100110110 11000010110011011011000010110011 01111101000000000000000000000000 00000000000000000000000000000000 00000000000000000011001111111100 01001100111111110001001111111111 11110100110011001111000100110011 11111111010011001100111111010011 01010011110001001101001011110001 00110011001111000100110101001111 00010011001100111100010011001100 11111101000000000000000000000000 00000000000000000000000000000000 00000000000000000011101100011110 01001110110001111001001000110001 10000100111011011111100100111011 00011000010011101101111000010011 10010111111001001110000111111001 00111011011111100100111001000110 00010011101100011110010011101100 01111001000000000000000000000000 00000000000000000000000000000000 00000000000000000000001010000100 00000000101000010000000000101000 01000000000010100001000000000010 10000100000000001010000011001100 00101000010000000000101000001100 11000010100001000000000010100001 00000000001010000100000000001010 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100000000100 00000010000000010000000010000000 01000000001000000001000000001000 00000100000000100000000100000000 10000000010000000010000000010000 00001000000001000000001000000001 00000000100000000100000000100000 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000100 00000000001000010000000000001000 01000000000000100001000000000000 10000100000000000010000100000000 00001000010000000000001000010000 00000000100001000000000000100001 00000000000010000100000000000010 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 00000000000000010000000000000000 01000000000000000001000000000000 00000100000000000000000100000000 00000000010000000000000000010000 00000000000001000000000000000001 00000000000000000100000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000001000001100110000001000 00110011000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000001000000000000000 00100000000000000000100000000000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 00000000000000000000000000000000 00001000000000000000100010000000 00000010001000000000000010001000 00000000001000100000000000001000 10000000000000100010000000000000 10001000000000000010001000000000 00001000100000000000001000100000 00000000100010000000000000100010 00000000000000100000000000000000 00000000000000000000000000000000 00001000000000000000100000000000 00000010000000001100110010000000 00110011001000000000000000001000 00000000000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000000100000000000000000 00000000000000000000000000000000 00001000000000000000101010000100 00000010101000010000000010101000 01000000001010100001000000001010 10000100000000101010000100000000 10101000010000000010101000010000 00001010100001000000001010100001 00000000101010000100000000101010 00010000000000100000000000000000 00000000000000000000000000000000 00001000000000000000100000000100 00000010000000010000000010000000 01000000001000000001000000001000 00000100000000100000000100000000 10000000010000000010000000010000 00001000000001000000001000000001 00000000100000000100000000100000 00010000000000100000000000000000 00000000000000000000000000000000 00001000000000000000000010000100 00000000001000010000000000001000 01000000000000100001000000000000 10000100000000000010000100000000 00001000010000000000001000010000 00000000100001000000000000100001 00000000000010000100000000000010 00010000000000100000000000000000 00000000000000000000000000000000 00001000000100000000000000000111 00110000000000011100110000000000 01110011000000000001110011000000 00000111001100000000000111001100 00000000011100110000000000011100 11000000000001110011000000000001 11001100000000000111001100000000 00011100110000100000010000000000 00000000000000000000000000000000 00001000000000000000000010000100 00000000001000010000000000001000 01110011000000100001000000000000 10000111001100000010000100000000 00001000010000000000001000011100 11000000100001000000000000100001 00000000000010000100000000000010 00010000000000100000000000000000 00000000000000000000000000000000 00000000000000000000001000000000 00000000100000000000000000100000 01000000000010000000000000000010 00000100000000001000000000000000 00100000000000000000100000010000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000001000000000000000001000 01000000000000100000000000000000 10000100000000000010000000000000 00001000000000000000001000010000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000000000000000000000 00000000000000000000000000000000 00000000000100001000000000000000 00000000000000000000000000000000 00110011000000000000000000000000 00000011001100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000100000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00111100001111000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011110000111100000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000001010000100 00000000101000010000000000101000 01000000000010100001000000000010 10000100000000001010000100000000 00101000010000000000101000010000 00000010100001000000000010100001 00000000001010000100000000001010 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 00000000000000010000000000000000 01000000000000000001000000000000 00000100000000100000000100000000 10000000010000000010000000010000 00001000000001000000001000000001 00000000100000000100000000100000 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100010000100 00000000001000010000000010001000 01000000001000100001000000001000 10000100000000100010000100000000 00001000010000000000001000010000 00000000100001000000000000100001 00000000000010000100000000000010 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 00000000000000010000000000000000 01000000000000000001000000000000 00000100000000000000000100000000 00000000010000000000000000010000 00000000000001000000000000000001 00000000000000000100000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000001000000000000000 00100000000000000000100000000000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 00000000000000000000000000000000 00000000000000000000100010000000 00000010001000000000000010001000 00000000001000100000000000001000 10000000000000100010000000000000 10001000000000000010001000000000 00001000100000000000001000100000 00000000100010000000000000100010 00000000000000100000000000000000 00000000000000000000000000000000 00001000000000000000000000000000 00000000000000000000000000000000 00000000001000000000000000000000 00000000000000000000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000000100000000000000000 00000000000000000000000000000000 00001000000000000000101010000111 00110010101000010000000010101000 01110011001010100001000000001010 10000100000000101010000100000000 10101000010000000010101000010000 00001010100001000000001010100001 00000000101010000100000000101010 00011100110000100000000000000000 00000000000000000000000000000000 00001000000000000000100000000100 00000010000000010000000010000000 01000000001000000001000000001000 00000100000000100000000100000000 10000000010000000010000000010000 00001000000001000000001000000001 00000000100000000100000000100000 00010000000000100000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000001000010000000000001000 00000000000000100001000000000000 10000100000000000010000100000000 00001000010000000000001000010000 00000000100001000000000000100001 00000000000010000100000000000010 00010000000000100000000000000000 00000000000000000000000000000000 00001000000100000000000000000100 00000000000000011100110000000000 01000000000000000001110011000000 00000100000000000000000111001100 00000000011100110000000000011100 11000000000001110011000000000001 11001100000000000111001100000000 00011100110000100000010000000000 00000000000000000000000000000000 00001000000000000000000010000100 00000000001000010000000000001000 01000000000000100001000000000000 10000100000000000010000100000000 00001000010000000000001000010000 00000000100001000000000000100001 00000000000010000100000000000010 00010000000000100000000000000000 00000000000000000000000000000000 00000000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000001000000000000000 00100000000000000000100000000000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000000000000000000000 00000000000000000000000000000000 00000000000100001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000100000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00111100001111000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011110000111100000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000010000000000001 00000010000000000000000000000000 00110000000000000100001001001001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000010000000000001 00000010000000100000000000000000 00110000000000000100001001000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000000000000000001 00000000000000001010001010111110 00110000000000001000000000000001 00000000000000000000000000000011 00110000000000000100000000001001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000000101 00110000000000001010000000000001 00000000000000000000000000000000 00110000000000000000000000000001 00000000000000001100000101111101 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 dahdi-linux-2.5.0.1/drivers/dahdi/biquad.h0000644000175000017500000000323011157510112020144 0ustar tzafrirtzafrir/* * SpanDSP - a series of DSP components for telephony * * biquad.h - General telephony bi-quad section routines (currently this just * handles canonic/type 2 form) * * Written by Steve Underwood * * Copyright (C) 2001 Steve Underwood * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ static inline void biquad2_init (biquad2_state_t *bq, int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) { bq->gain = gain; bq->a1 = a1; bq->a2 = a2; bq->b1 = b1; bq->b2 = b2; bq->z1 = 0; bq->z2 = 0; } /*- End of function --------------------------------------------------------*/ static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample) { int32_t y; int32_t z0; z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; bq->z2 = bq->z1; bq->z1 = z0 >> 15; y >>= 15; return y; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ dahdi-linux-2.5.0.1/drivers/dahdi/datamods/0000755000175000017500000000000011631523355020336 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_cisco.c0000644000175000017500000002072010751714440022574 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * Cisco HDLC support * * Copyright (C) 2000 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DEBUG_HARD_HEADER #define CISCO_MULTICAST 0x8F /* Cisco multicast address */ #define CISCO_UNICAST 0x0F /* Cisco unicast address */ #define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ #define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ #define CISCO_ADDR_REQ 0 /* Cisco address request */ #define CISCO_ADDR_REPLY 1 /* Cisco address reply */ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, u16 type, void *daddr, void *saddr, unsigned int len) { hdlc_header *data; #ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif skb_push(skb, sizeof(hdlc_header)); data = (hdlc_header*)skb->data; if (type == CISCO_KEEPALIVE) data->address = CISCO_MULTICAST; else data->address = CISCO_UNICAST; data->control = 0; data->protocol = htons(type); return sizeof(hdlc_header); } static void cisco_keepalive_send(struct net_device *dev, u32 type, u32 par1, u32 par2) { struct sk_buff *skb; cisco_packet *data; skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet)); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", dev->name); return; } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); data = (cisco_packet*)(skb->data + 4); data->type = htonl(type); data->par1 = htonl(par1); data->par2 = htonl(par2); data->rel = 0xFFFF; /* we will need do_div here if 1000 % HZ != 0 */ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); skb_put(skb, sizeof(cisco_packet)); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; skb->nh.raw = skb->data; dev_queue_xmit(skb); } static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) { hdlc_header *data = (hdlc_header*)skb->data; if (skb->len < sizeof(hdlc_header)) return __constant_htons(ETH_P_HDLC); if (data->address != CISCO_MULTICAST && data->address != CISCO_UNICAST) return __constant_htons(ETH_P_HDLC); switch(data->protocol) { case __constant_htons(ETH_P_IP): case __constant_htons(ETH_P_IPX): case __constant_htons(ETH_P_IPV6): skb_pull(skb, sizeof(hdlc_header)); return data->protocol; default: return __constant_htons(ETH_P_HDLC); } } static int cisco_rx(struct sk_buff *skb) { struct net_device *dev = skb->dev; hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_header *data = (hdlc_header*)skb->data; cisco_packet *cisco_data; struct in_device *in_dev; u32 addr, mask; if (skb->len < sizeof(hdlc_header)) goto rx_error; if (data->address != CISCO_MULTICAST && data->address != CISCO_UNICAST) goto rx_error; switch(ntohs(data->protocol)) { case CISCO_SYS_INFO: /* Packet is not needed, drop it. */ dev_kfree_skb_any(skb); return NET_RX_SUCCESS; case CISCO_KEEPALIVE: if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN && skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) { printk(KERN_INFO "%s: Invalid length of Cisco " "control packet (%d bytes)\n", dev->name, skb->len); goto rx_error; } cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header)); switch(ntohl (cisco_data->type)) { case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ in_dev = dev->ip_ptr; addr = 0; mask = ~0; /* is the mask correct? */ if (in_dev != NULL) { struct in_ifaddr **ifap = &in_dev->ifa_list; while (*ifap != NULL) { if (strcmp(dev->name, (*ifap)->ifa_label) == 0) { addr = (*ifap)->ifa_local; mask = (*ifap)->ifa_mask; break; } ifap = &(*ifap)->ifa_next; } cisco_keepalive_send(dev, CISCO_ADDR_REPLY, addr, mask); } dev_kfree_skb_any(skb); return NET_RX_SUCCESS; case CISCO_ADDR_REPLY: printk(KERN_INFO "%s: Unexpected Cisco IP address " "reply\n", dev->name); goto rx_error; case CISCO_KEEPALIVE_REQ: hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); if (hdlc->state.cisco.request_sent && ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { hdlc->state.cisco.last_poll = jiffies; if (!hdlc->state.cisco.up) { u32 sec, min, hrs, days; sec = ntohl(cisco_data->time) / 1000; min = sec / 60; sec -= min * 60; hrs = min / 60; min -= hrs * 60; days = hrs / 24; hrs -= days * 24; printk(KERN_INFO "%s: Link up (peer " "uptime %ud%uh%um%us)\n", dev->name, days, hrs, min, sec); #if 0 netif_carrier_on(dev); #endif hdlc->state.cisco.up = 1; } } dev_kfree_skb_any(skb); return NET_RX_SUCCESS; } /* switch(keepalive type) */ } /* switch(protocol) */ printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name, data->protocol); dev_kfree_skb_any(skb); return NET_RX_DROP; rx_error: hdlc->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } static void cisco_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->state.cisco.up && time_after(jiffies, hdlc->state.cisco.last_poll + hdlc->state.cisco.settings.timeout * HZ)) { hdlc->state.cisco.up = 0; printk(KERN_INFO "%s: Link down\n", dev->name); #if 0 netif_carrier_off(dev); #endif } cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++hdlc->state.cisco.txseq, hdlc->state.cisco.rxseq); hdlc->state.cisco.request_sent = 1; hdlc->state.cisco.timer.expires = jiffies + hdlc->state.cisco.settings.interval * HZ; hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.data = arg; add_timer(&hdlc->state.cisco.timer); } static void cisco_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); hdlc->state.cisco.up = 0; hdlc->state.cisco.request_sent = 0; hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0; init_timer(&hdlc->state.cisco.timer); hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/ hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.data = (unsigned long)dev; add_timer(&hdlc->state.cisco.timer); } static void cisco_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); del_timer_sync(&hdlc->state.cisco.timer); #if 0 if (netif_carrier_ok(dev)) netif_carrier_off(dev); #endif hdlc->state.cisco.up = 0; hdlc->state.cisco.request_sent = 0; } int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco; const size_t size = sizeof(cisco_proto); cisco_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: ifr->ifr_settings.type = IF_PROTO_CISCO; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size)) return -EFAULT; return 0; case IF_PROTO_CISCO: if(!capable(CAP_NET_ADMIN)) return -EPERM; if(dev->flags & IFF_UP) return -EBUSY; if (copy_from_user(&new_settings, cisco_s, size)) return -EFAULT; if (new_settings.interval < 1 || new_settings.timeout < 2) return -EINVAL; result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; hdlc_proto_detach(hdlc); memcpy(&hdlc->state.cisco.settings, &new_settings, size); memset(&hdlc->proto, 0, sizeof(hdlc->proto)); hdlc->proto.start = cisco_start; hdlc->proto.stop = cisco_stop; hdlc->proto.netif_rx = cisco_rx; hdlc->proto.type_trans = cisco_type_trans; hdlc->proto.id = IF_PROTO_CISCO; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->hard_header_cache = NULL; dev->type = ARPHRD_CISCO; dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->addr_len = 0; return 0; } return -EINVAL; } dahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_raw_eth.c0000644000175000017500000000541110751714440023125 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * HDLC Ethernet emulation support * * Copyright (C) 2002-2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int eth_tx(struct sk_buff *skb, struct net_device *dev) { int pad = ETH_ZLEN - skb->len; if (pad > 0) { /* Pad the frame with zeros */ int len = skb->len; if (skb_tailroom(skb) < pad) if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { hdlc_stats(dev)->tx_dropped++; dev_kfree_skb(skb); return 0; } skb_put(skb, pad); memset(skb->data + len, 0, pad); } return dev_to_hdlc(dev)->xmit(skb, dev); } int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); int result; void *old_ch_mtu; int old_qlen; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: ifr->ifr_settings.type = IF_PROTO_HDLC_ETH; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) return -EFAULT; return 0; case IF_PROTO_HDLC_ETH: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (dev->flags & IFF_UP) return -EBUSY; if (copy_from_user(&new_settings, raw_s, size)) return -EFAULT; if (new_settings.encoding == ENCODING_DEFAULT) new_settings.encoding = ENCODING_NRZ; if (new_settings.parity == PARITY_DEFAULT) new_settings.parity = PARITY_CRC16_PR1_CCITT; result = hdlc->attach(dev, new_settings.encoding, new_settings.parity); if (result) return result; hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); memset(&hdlc->proto, 0, sizeof(hdlc->proto)); hdlc->proto.type_trans = eth_type_trans; hdlc->proto.id = IF_PROTO_HDLC_ETH; dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; ether_setup(dev); dev->change_mtu = old_ch_mtu; dev->tx_queue_len = old_qlen; memcpy(dev->dev_addr, "\x00\x01", 2); get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); return 0; } return -EINVAL; } dahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_raw.c0000644000175000017500000000432010751714440022263 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * HDLC support * * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_IP); } int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) { raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: ifr->ifr_settings.type = IF_PROTO_HDLC; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) return -EFAULT; return 0; case IF_PROTO_HDLC: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (dev->flags & IFF_UP) return -EBUSY; if (copy_from_user(&new_settings, raw_s, size)) return -EFAULT; if (new_settings.encoding == ENCODING_DEFAULT) new_settings.encoding = ENCODING_NRZ; if (new_settings.parity == PARITY_DEFAULT) new_settings.parity = PARITY_CRC16_PR1_CCITT; result = hdlc->attach(dev, new_settings.encoding, new_settings.parity); if (result) return result; hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); memset(&hdlc->proto, 0, sizeof(hdlc->proto)); hdlc->proto.type_trans = raw_type_trans; hdlc->proto.id = IF_PROTO_HDLC; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->addr_len = 0; return 0; } return -EINVAL; } dahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_generic.c0000644000175000017500000001641110751714440023112 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * * Copyright (C) 1999 - 2005 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * Currently supported: * * raw IP-in-HDLC * * Cisco HDLC * * Frame Relay with ANSI or CCITT LMI (both user and network side) * * PPP * * X.25 * * Use sethdlc utility to set line parameters, protocol and PVCs * * How does it work: * - proto.open(), close(), start(), stop() calls are serialized. * The order is: open, [ start, stop ... ] close ... * - proto.start() and stop() are called with spin_lock_irq held. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char* version = "HDLC support module revision 1.18"; #undef DEBUG_LINK static int hdlc_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) return -EINVAL; dev->mtu = new_mtu; return 0; } static struct net_device_stats *hdlc_get_stats(struct net_device *dev) { return hdlc_stats(dev); } static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->proto.netif_rx) return hdlc->proto.netif_rx(skb); hdlc->stats.rx_dropped++; /* Shouldn't happen */ dev_kfree_skb(skb); return NET_RX_DROP; } static void __hdlc_set_carrier_on(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->proto.start) return hdlc->proto.start(dev); #if 0 #ifdef DEBUG_LINK if (netif_carrier_ok(dev)) printk(KERN_ERR "hdlc_set_carrier_on(): already on\n"); #endif netif_carrier_on(dev); #endif } static void __hdlc_set_carrier_off(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->proto.stop) return hdlc->proto.stop(dev); #if 0 #ifdef DEBUG_LINK if (!netif_carrier_ok(dev)) printk(KERN_ERR "hdlc_set_carrier_off(): already off\n"); #endif netif_carrier_off(dev); #endif } void hdlc_set_carrier(int on, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); unsigned long flags; on = on ? 1 : 0; #ifdef DEBUG_LINK printk(KERN_DEBUG "hdlc_set_carrier %i\n", on); #endif spin_lock_irqsave(&hdlc->state_lock, flags); if (hdlc->carrier == on) goto carrier_exit; /* no change in DCD line level */ #ifdef DEBUG_LINK printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off"); #endif hdlc->carrier = on; if (!hdlc->open) goto carrier_exit; if (hdlc->carrier) { printk(KERN_INFO "%s: Carrier detected\n", dev->name); __hdlc_set_carrier_on(dev); } else { printk(KERN_INFO "%s: Carrier lost\n", dev->name); __hdlc_set_carrier_off(dev); } carrier_exit: spin_unlock_irqrestore(&hdlc->state_lock, flags); } /* Must be called by hardware driver when HDLC device is being opened */ int hdlc_open(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n", hdlc->carrier, hdlc->open); #endif if (hdlc->proto.id == -1) return -ENOSYS; /* no protocol attached */ if (hdlc->proto.open) { int result = hdlc->proto.open(dev); if (result) return result; } spin_lock_irq(&hdlc->state_lock); if (hdlc->carrier) { printk(KERN_INFO "%s: Carrier detected\n", dev->name); __hdlc_set_carrier_on(dev); } else printk(KERN_INFO "%s: No carrier\n", dev->name); hdlc->open = 1; spin_unlock_irq(&hdlc->state_lock); return 0; } /* Must be called by hardware driver when HDLC device is being closed */ void hdlc_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n", hdlc->carrier, hdlc->open); #endif spin_lock_irq(&hdlc->state_lock); hdlc->open = 0; if (hdlc->carrier) __hdlc_set_carrier_off(dev); spin_unlock_irq(&hdlc->state_lock); if (hdlc->proto.close) hdlc->proto.close(dev); } #ifndef CONFIG_HDLC_RAW #define hdlc_raw_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_RAW_ETH #define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_PPP #define hdlc_ppp_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_CISCO #define hdlc_cisco_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_FR #define hdlc_fr_ioctl(dev, ifr) -ENOSYS #endif #ifndef CONFIG_HDLC_X25 #define hdlc_x25_ioctl(dev, ifr) -ENOSYS #endif int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { hdlc_device *hdlc = dev_to_hdlc(dev); unsigned int proto; if (cmd != SIOCWANDEV) return -EINVAL; switch(ifr->ifr_settings.type) { case IF_PROTO_HDLC: case IF_PROTO_HDLC_ETH: case IF_PROTO_PPP: case IF_PROTO_CISCO: case IF_PROTO_FR: case IF_PROTO_X25: proto = ifr->ifr_settings.type; break; default: proto = hdlc->proto.id; } switch(proto) { case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr); case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr); default: return -EINVAL; } } static void hdlc_setup(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); dev->get_stats = hdlc_get_stats; dev->change_mtu = hdlc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->type = ARPHRD_RAWHDLC; dev->hard_header_len = 16; dev->flags = IFF_POINTOPOINT | IFF_NOARP; hdlc->proto.id = -1; hdlc->proto.detach = NULL; hdlc->carrier = 1; hdlc->open = 0; spin_lock_init(&hdlc->state_lock); } struct net_device *alloc_hdlcdev(void *priv) { struct net_device *dev; dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); if (dev) dev_to_hdlc(dev)->priv = priv; return dev; } int register_hdlc_device(struct net_device *dev) { int result = dev_alloc_name(dev, "hdlc%d"); if (result < 0) return result; result = register_netdev(dev); if (result != 0) return -EIO; #if 0 if (netif_carrier_ok(dev)) netif_carrier_off(dev); /* no carrier until DCD goes up */ #endif return 0; } void unregister_hdlc_device(struct net_device *dev) { rtnl_lock(); hdlc_proto_detach(dev_to_hdlc(dev)); unregister_netdevice(dev); rtnl_unlock(); } MODULE_AUTHOR("Krzysztof Halasa "); MODULE_DESCRIPTION("HDLC support module"); MODULE_LICENSE("GPL v2"); EXPORT_SYMBOL(hdlc_open); EXPORT_SYMBOL(hdlc_close); EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); static struct packet_type hdlc_packet_type = { .type = __constant_htons(ETH_P_HDLC), .func = hdlc_rcv, }; static int __init hdlc_module_init(void) { printk(KERN_INFO "%s\n", version); dev_add_pack(&hdlc_packet_type); return 0; } static void __exit hdlc_module_exit(void) { dev_remove_pack(&hdlc_packet_type); } module_init(hdlc_module_init); module_exit(hdlc_module_exit); dahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_ppp.c0000644000175000017500000000503210751714440022272 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * Point-to-point protocol support * * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static int ppp_open(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); void *old_ioctl; int result; dev->priv = &hdlc->state.ppp.syncppp_ptr; hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev; hdlc->state.ppp.pppdev.dev = dev; old_ioctl = dev->do_ioctl; hdlc->state.ppp.old_change_mtu = dev->change_mtu; sppp_attach(&hdlc->state.ppp.pppdev); /* sppp_attach nukes them. We don't need syncppp's ioctl */ dev->do_ioctl = old_ioctl; hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO; dev->type = ARPHRD_PPP; result = sppp_open(dev); if (result) { sppp_detach(dev); return result; } return 0; } static void ppp_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); sppp_close(dev); sppp_detach(dev); dev->rebuild_header = NULL; dev->change_mtu = hdlc->state.ppp.old_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->hard_header_len = 16; } static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_WAN_PPP); } int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: ifr->ifr_settings.type = IF_PROTO_PPP; return 0; /* return protocol only, no settable parameters */ case IF_PROTO_PPP: if(!capable(CAP_NET_ADMIN)) return -EPERM; if(dev->flags & IFF_UP) return -EBUSY; /* no settable parameters */ result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; hdlc_proto_detach(hdlc); memset(&hdlc->proto, 0, sizeof(hdlc->proto)); hdlc->proto.open = ppp_open; hdlc->proto.close = ppp_close; hdlc->proto.type_trans = ppp_type_trans; hdlc->proto.id = IF_PROTO_PPP; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; dev->addr_len = 0; return 0; } return -EINVAL; } dahdi-linux-2.5.0.1/drivers/dahdi/datamods/Makefile0000644000175000017500000000154410751714440022001 0ustar tzafrirtzafrir.EXPORT_ALL_VARIABLES: MODULES= \ hdlc_cisco hdlc_generic hdlc_raw syncppp \ hdlc_fr hdlc_ppp hdlc_raw_eth PWD=$(shell pwd) MODULESO:=$(MODULES:%=%.o) MODULESKO:=$(MODULES:%=%.ko) KMAKE = $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) KMAKE_INST = $(KMAKE) \ INSTALL_MOD_PATH=$(INSTALL_PREFIX) INSTALL_MOD_DIR=misc modules_install obj-m := $(MODULESO) #obj-m:=hdlc_raw.o hdlc_cisco.o #obj-m := hdlc_cisco.o hdlc_cisco.mod.o hdlc_fr.o hdlc_generic.o hdlc_ppp.o hdlc_raw.o hdlc_raw_eth.o hdlc_raw.mod.o hdlc_x25.o all: @echo "You don't want to do make here. Do it from up above" clean: $(KMAKE) clean install: $(MODULESKO) $(KMAKE_INST) datamods: @echo "To build: $(obj-m)" @echo $(KSRC) @if [ -z "$(KSRC)" -o ! -d "$(KSRC)" ]; then echo "You do not appear to have the sources for the $(KVERS) kernel installed."; exit 1 ; fi $(KMAKE) modules dahdi-linux-2.5.0.1/drivers/dahdi/datamods/hdlc_fr.c0000644000175000017500000007204110751714440022106 0ustar tzafrirtzafrir/* * Generic HDLC support routines for Linux * Frame Relay support * * Copyright (C) 1999 - 2005 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * Theory of PVC state DCE mode: (exist,new) -> 0,0 when "PVC create" or if "link unreliable" 0,x -> 1,1 if "link reliable" when sending FULL STATUS 1,1 -> 1,0 if received FULL STATUS ACK (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" -> 1 when "PVC up" and (exist,new) = 1,0 DTE mode: (exist,new,active) = FULL STATUS if "link reliable" = 0, 0, 0 if "link unreliable" No LMI: active = open and "link reliable" exist = new = not used CCITT LMI: ITU-T Q.933 Annex A ANSI LMI: ANSI T1.617 Annex D CISCO LMI: the original, aka "Gang of Four" LMI */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DEBUG_PKT #undef DEBUG_ECN #undef DEBUG_LINK #define FR_UI 0x03 #define FR_PAD 0x00 #define NLPID_IP 0xCC #define NLPID_IPV6 0x8E #define NLPID_SNAP 0x80 #define NLPID_PAD 0x00 #define NLPID_CCITT_ANSI_LMI 0x08 #define NLPID_CISCO_LMI 0x09 #define LMI_CCITT_ANSI_DLCI 0 /* LMI DLCI */ #define LMI_CISCO_DLCI 1023 #define LMI_CALLREF 0x00 /* Call Reference */ #define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI locking shift */ #define LMI_ANSI_CISCO_REPTYPE 0x01 /* report type */ #define LMI_CCITT_REPTYPE 0x51 #define LMI_ANSI_CISCO_ALIVE 0x03 /* keep alive */ #define LMI_CCITT_ALIVE 0x53 #define LMI_ANSI_CISCO_PVCSTAT 0x07 /* PVC status */ #define LMI_CCITT_PVCSTAT 0x57 #define LMI_FULLREP 0x00 /* full report */ #define LMI_INTEGRITY 0x01 /* link integrity report */ #define LMI_SINGLE 0x02 /* single PVC report */ #define LMI_STATUS_ENQUIRY 0x75 #define LMI_STATUS 0x7D /* reply */ #define LMI_REPT_LEN 1 /* report type element length */ #define LMI_INTEG_LEN 2 /* link integrity element length */ #define LMI_CCITT_CISCO_LENGTH 13 /* LMI frame lengths */ #define LMI_ANSI_LENGTH 14 typedef struct { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned ea1: 1; unsigned cr: 1; unsigned dlcih: 6; unsigned ea2: 1; unsigned de: 1; unsigned becn: 1; unsigned fecn: 1; unsigned dlcil: 4; #else unsigned dlcih: 6; unsigned cr: 1; unsigned ea1: 1; unsigned dlcil: 4; unsigned fecn: 1; unsigned becn: 1; unsigned de: 1; unsigned ea2: 1; #endif }__attribute__ ((packed)) fr_hdr; static inline u16 q922_to_dlci(u8 *hdr) { return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); } static inline void dlci_to_q922(u8 *hdr, u16 dlci) { hdr[0] = (dlci >> 2) & 0xFC; hdr[1] = ((dlci << 4) & 0xF0) | 0x01; } static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc = hdlc->state.fr.first_pvc; while (pvc) { if (pvc->dlci == dlci) return pvc; if (pvc->dlci > dlci) return NULL; /* the listed is sorted */ pvc = pvc->next; } return NULL; } static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; while (*pvc_p) { if ((*pvc_p)->dlci == dlci) return *pvc_p; if ((*pvc_p)->dlci > dlci) break; /* the list is sorted */ pvc_p = &(*pvc_p)->next; } pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC); if (!pvc) return NULL; memset(pvc, 0, sizeof(pvc_device)); pvc->dlci = dlci; pvc->master = dev; pvc->next = *pvc_p; /* Put it in the chain */ *pvc_p = pvc; return pvc; } static inline int pvc_is_used(pvc_device *pvc) { return pvc->main != NULL || pvc->ether != NULL; } static inline void pvc_carrier(int on, pvc_device *pvc) { if (on) { if (pvc->main) if (!netif_carrier_ok(pvc->main)) netif_carrier_on(pvc->main); if (pvc->ether) if (!netif_carrier_ok(pvc->ether)) netif_carrier_on(pvc->ether); } else { if (pvc->main) if (netif_carrier_ok(pvc->main)) netif_carrier_off(pvc->main); if (pvc->ether) if (netif_carrier_ok(pvc->ether)) netif_carrier_off(pvc->ether); } } static inline void delete_unused_pvcs(hdlc_device *hdlc) { pvc_device **pvc_p = &hdlc->state.fr.first_pvc; while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; *pvc_p = pvc->next; kfree(pvc); continue; } pvc_p = &(*pvc_p)->next; } } static inline struct net_device** get_dev_p(pvc_device *pvc, int type) { if (type == ARPHRD_ETHER) return &pvc->ether; else return &pvc->main; } static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) { u16 head_len; struct sk_buff *skb = *skb_p; switch (skb->protocol) { case __constant_ntohs(NLPID_CCITT_ANSI_LMI): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_CCITT_ANSI_LMI; break; case __constant_ntohs(NLPID_CISCO_LMI): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_CISCO_LMI; break; case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IP; break; case __constant_ntohs(ETH_P_IPV6): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IPV6; break; case __constant_ntohs(ETH_P_802_3): head_len = 10; if (skb_headroom(skb) < head_len) { struct sk_buff *skb2 = skb_realloc_headroom(skb, head_len); if (!skb2) return -ENOBUFS; dev_kfree_skb(skb); skb = *skb_p = skb2; } skb_push(skb, head_len); skb->data[3] = FR_PAD; skb->data[4] = NLPID_SNAP; skb->data[5] = FR_PAD; skb->data[6] = 0x80; skb->data[7] = 0xC2; skb->data[8] = 0x00; skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */ break; default: head_len = 10; skb_push(skb, head_len); skb->data[3] = FR_PAD; skb->data[4] = NLPID_SNAP; skb->data[5] = FR_PAD; skb->data[6] = FR_PAD; skb->data[7] = FR_PAD; *(u16*)(skb->data + 8) = skb->protocol; } dlci_to_q922(skb->data, dlci); skb->data[2] = FR_UI; return 0; } static int pvc_open(struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); if ((pvc->master->flags & IFF_UP) == 0) return -EIO; /* Master must be UP in order to activate PVC */ if (pvc->open_count++ == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->master); if (hdlc->state.fr.settings.lmi == LMI_NONE) pvc->state.active = hdlc->carrier; pvc_carrier(pvc->state.active, pvc); hdlc->state.fr.dce_changed = 1; } return 0; } static int pvc_close(struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); if (--pvc->open_count == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->master); if (hdlc->state.fr.settings.lmi == LMI_NONE) pvc->state.active = 0; if (hdlc->state.fr.settings.dce) { hdlc->state.fr.dce_changed = 1; pvc->state.active = 0; } } return 0; } static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { pvc_device *pvc = dev_to_pvc(dev); fr_proto_pvc_info info; if (ifr->ifr_settings.type == IF_GET_PROTO) { if (dev->type == ARPHRD_ETHER) ifr->ifr_settings.type = IF_PROTO_FR_ETH_PVC; else ifr->ifr_settings.type = IF_PROTO_FR_PVC; if (ifr->ifr_settings.size < sizeof(info)) { /* data size wanted */ ifr->ifr_settings.size = sizeof(info); return -ENOBUFS; } info.dlci = pvc->dlci; memcpy(info.master, pvc->master->name, IFNAMSIZ); if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, &info, sizeof(info))) return -EFAULT; return 0; } return -EINVAL; } static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { return netdev_priv(dev); } static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); struct net_device_stats *stats = pvc_get_stats(dev); if (pvc->state.active) { if (dev->type == ARPHRD_ETHER) { int pad = ETH_ZLEN - skb->len; if (pad > 0) { /* Pad the frame with zeros */ int len = skb->len; if (skb_tailroom(skb) < pad) if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { stats->tx_dropped++; dev_kfree_skb(skb); return 0; } skb_put(skb, pad); memset(skb->data + len, 0, pad); } skb->protocol = __constant_htons(ETH_P_802_3); } if (!fr_hard_header(&skb, pvc->dlci)) { stats->tx_bytes += skb->len; stats->tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ stats->tx_compressed++; skb->dev = pvc->master; dev_queue_xmit(skb); return 0; } } stats->tx_dropped++; dev_kfree_skb(skb); return 0; } static int pvc_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) return -EINVAL; dev->mtu = new_mtu; return 0; } static inline void fr_log_dlci_active(pvc_device *pvc) { printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", pvc->master->name, pvc->dlci, pvc->main ? pvc->main->name : "", pvc->main && pvc->ether ? " " : "", pvc->ether ? pvc->ether->name : "", pvc->state.new ? " new" : "", !pvc->state.exist ? "deleted" : pvc->state.active ? "active" : "inactive"); } static inline u8 fr_lmi_nextseq(u8 x) { x++; return x ? x : 1; } static void fr_lmi_send(struct net_device *dev, int fullrep) { hdlc_device *hdlc = dev_to_hdlc(dev); struct sk_buff *skb; pvc_device *pvc = hdlc->state.fr.first_pvc; int lmi = hdlc->state.fr.settings.lmi; int dce = hdlc->state.fr.settings.dce; int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH; int stat_len = (lmi == LMI_CISCO) ? 6 : 3; u8 *data; int i = 0; if (dce && fullrep) { len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " "LMI full report\n", dev->name); return; } } skb = dev_alloc_skb(len); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", dev->name); return; } memset(skb->data, 0, len); skb_reserve(skb, 4); if (lmi == LMI_CISCO) { skb->protocol = __constant_htons(NLPID_CISCO_LMI); fr_hard_header(&skb, LMI_CISCO_DLCI); } else { skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI); fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI); } data = skb->tail; data[i++] = LMI_CALLREF; data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY; if (lmi == LMI_ANSI) data[i++] = LMI_ANSI_LOCKSHIFT; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : LMI_ANSI_CISCO_REPTYPE; data[i++] = LMI_REPT_LEN; data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE; data[i++] = LMI_INTEG_LEN; data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq); data[i++] = hdlc->state.fr.rxseq; if (dce && fullrep) { while (pvc) { data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : LMI_ANSI_CISCO_PVCSTAT; data[i++] = stat_len; /* LMI start/restart */ if (hdlc->state.fr.reliable && !pvc->state.exist) { pvc->state.exist = pvc->state.new = 1; fr_log_dlci_active(pvc); } /* ifconfig PVC up */ if (pvc->open_count && !pvc->state.active && pvc->state.exist && !pvc->state.new) { pvc_carrier(1, pvc); pvc->state.active = 1; fr_log_dlci_active(pvc); } if (lmi == LMI_CISCO) { data[i] = pvc->dlci >> 8; data[i + 1] = pvc->dlci & 0xFF; } else { data[i] = (pvc->dlci >> 4) & 0x3F; data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80; data[i + 2] = 0x80; } if (pvc->state.new) data[i + 2] |= 0x08; else if (pvc->state.active) data[i + 2] |= 0x02; i += stat_len; pvc = pvc->next; } } skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; skb->nh.raw = skb->data; dev_queue_xmit(skb); } static void fr_set_link_state(int reliable, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc = hdlc->state.fr.first_pvc; hdlc->state.fr.reliable = reliable; if (reliable) { #if 0 if (!netif_carrier_ok(dev)) netif_carrier_on(dev); #endif hdlc->state.fr.n391cnt = 0; /* Request full status */ hdlc->state.fr.dce_changed = 1; if (hdlc->state.fr.settings.lmi == LMI_NONE) { while (pvc) { /* Activate all PVCs */ pvc_carrier(1, pvc); pvc->state.exist = pvc->state.active = 1; pvc->state.new = 0; pvc = pvc->next; } } } else { #if 0 if (netif_carrier_ok(dev)) netif_carrier_off(dev); #endif while (pvc) { /* Deactivate all PVCs */ pvc_carrier(0, pvc); pvc->state.exist = pvc->state.active = 0; pvc->state.new = 0; if (!hdlc->state.fr.settings.dce) pvc->state.bandwidth = 0; pvc = pvc->next; } } } static void fr_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; hdlc_device *hdlc = dev_to_hdlc(dev); int i, cnt = 0, reliable; u32 list; if (hdlc->state.fr.settings.dce) { reliable = hdlc->state.fr.request && time_before(jiffies, hdlc->state.fr.last_poll + hdlc->state.fr.settings.t392 * HZ); hdlc->state.fr.request = 0; } else { hdlc->state.fr.last_errors <<= 1; /* Shift the list */ if (hdlc->state.fr.request) { if (hdlc->state.fr.reliable) printk(KERN_INFO "%s: No LMI status reply " "received\n", dev->name); hdlc->state.fr.last_errors |= 1; } list = hdlc->state.fr.last_errors; for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1) cnt += (list & 1); /* errors count */ reliable = (cnt < hdlc->state.fr.settings.n392); } if (hdlc->state.fr.reliable != reliable) { printk(KERN_INFO "%s: Link %sreliable\n", dev->name, reliable ? "" : "un"); fr_set_link_state(reliable, dev); } if (hdlc->state.fr.settings.dce) hdlc->state.fr.timer.expires = jiffies + hdlc->state.fr.settings.t392 * HZ; else { if (hdlc->state.fr.n391cnt) hdlc->state.fr.n391cnt--; fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0); hdlc->state.fr.last_poll = jiffies; hdlc->state.fr.request = 1; hdlc->state.fr.timer.expires = jiffies + hdlc->state.fr.settings.t391 * HZ; } hdlc->state.fr.timer.function = fr_timer; hdlc->state.fr.timer.data = arg; add_timer(&hdlc->state.fr.timer); } static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc; u8 rxseq, txseq; int lmi = hdlc->state.fr.settings.lmi; int dce = hdlc->state.fr.settings.dce; int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i; if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH)) { printk(KERN_INFO "%s: Short LMI frame\n", dev->name); return 1; } if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI : NLPID_CCITT_ANSI_LMI)) { printk(KERN_INFO "%s: Received non-LMI frame with LMI" " DLCI\n", dev->name); return 1; } if (skb->data[4] != LMI_CALLREF) { printk(KERN_INFO "%s: Invalid LMI Call reference (0x%02X)\n", dev->name, skb->data[4]); return 1; } if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) { printk(KERN_INFO "%s: Invalid LMI Message type (0x%02X)\n", dev->name, skb->data[5]); return 1; } if (lmi == LMI_ANSI) { if (skb->data[6] != LMI_ANSI_LOCKSHIFT) { printk(KERN_INFO "%s: Not ANSI locking shift in LMI" " message (0x%02X)\n", dev->name, skb->data[6]); return 1; } i = 7; } else i = 6; if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : LMI_ANSI_CISCO_REPTYPE)) { printk(KERN_INFO "%s: Not an LMI Report type IE (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != LMI_REPT_LEN) { printk(KERN_INFO "%s: Invalid LMI Report type IE length" " (%u)\n", dev->name, skb->data[i]); return 1; } reptype = skb->data[++i]; if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) { printk(KERN_INFO "%s: Unsupported LMI Report type (0x%02X)\n", dev->name, reptype); return 1; } if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE)) { printk(KERN_INFO "%s: Not an LMI Link integrity verification" " IE (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != LMI_INTEG_LEN) { printk(KERN_INFO "%s: Invalid LMI Link integrity verification" " IE length (%u)\n", dev->name, skb->data[i]); return 1; } i++; hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */ rxseq = skb->data[i++]; /* Should confirm our sequence */ txseq = hdlc->state.fr.txseq; if (dce) hdlc->state.fr.last_poll = jiffies; error = 0; if (!hdlc->state.fr.reliable) error = 1; if (rxseq == 0 || rxseq != txseq) { hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */ error = 1; } if (dce) { if (hdlc->state.fr.fullrep_sent && !error) { /* Stop sending full report - the last one has been confirmed by DTE */ hdlc->state.fr.fullrep_sent = 0; pvc = hdlc->state.fr.first_pvc; while (pvc) { if (pvc->state.new) { pvc->state.new = 0; /* Tell DTE that new PVC is now active */ hdlc->state.fr.dce_changed = 1; } pvc = pvc->next; } } if (hdlc->state.fr.dce_changed) { reptype = LMI_FULLREP; hdlc->state.fr.fullrep_sent = 1; hdlc->state.fr.dce_changed = 0; } hdlc->state.fr.request = 1; /* got request */ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); return 0; } /* DTE */ hdlc->state.fr.request = 0; /* got response, no request pending */ if (error) return 0; if (reptype != LMI_FULLREP) return 0; pvc = hdlc->state.fr.first_pvc; while (pvc) { pvc->state.deleted = 1; pvc = pvc->next; } no_ram = 0; while (skb->len >= i + 2 + stat_len) { u16 dlci; u32 bw; unsigned int active, new; if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : LMI_ANSI_CISCO_PVCSTAT)) { printk(KERN_INFO "%s: Not an LMI PVC status IE" " (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != stat_len) { printk(KERN_INFO "%s: Invalid LMI PVC status IE length" " (%u)\n", dev->name, skb->data[i]); return 1; } i++; new = !! (skb->data[i + 2] & 0x08); active = !! (skb->data[i + 2] & 0x02); if (lmi == LMI_CISCO) { dlci = (skb->data[i] << 8) | skb->data[i + 1]; bw = (skb->data[i + 3] << 16) | (skb->data[i + 4] << 8) | (skb->data[i + 5]); } else { dlci = ((skb->data[i] & 0x3F) << 4) | ((skb->data[i + 1] & 0x78) >> 3); bw = 0; } pvc = add_pvc(dev, dlci); if (!pvc && !no_ram) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_recv()\n", dev->name); no_ram = 1; } if (pvc) { pvc->state.exist = 1; pvc->state.deleted = 0; if (active != pvc->state.active || new != pvc->state.new || bw != pvc->state.bandwidth || !pvc->state.exist) { pvc->state.new = new; pvc->state.active = active; pvc->state.bandwidth = bw; pvc_carrier(active, pvc); fr_log_dlci_active(pvc); } } i += stat_len; } pvc = hdlc->state.fr.first_pvc; while (pvc) { if (pvc->state.deleted && pvc->state.exist) { pvc_carrier(0, pvc); pvc->state.active = pvc->state.new = 0; pvc->state.exist = 0; pvc->state.bandwidth = 0; fr_log_dlci_active(pvc); } pvc = pvc->next; } /* Next full report after N391 polls */ hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391; return 0; } static int fr_rx(struct sk_buff *skb) { struct net_device *ndev = skb->dev; hdlc_device *hdlc = dev_to_hdlc(ndev); fr_hdr *fh = (fr_hdr*)skb->data; u8 *data = skb->data; u16 dlci; pvc_device *pvc; struct net_device *dev = NULL; if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI) goto rx_error; dlci = q922_to_dlci(skb->data); if ((dlci == LMI_CCITT_ANSI_DLCI && (hdlc->state.fr.settings.lmi == LMI_ANSI || hdlc->state.fr.settings.lmi == LMI_CCITT)) || (dlci == LMI_CISCO_DLCI && hdlc->state.fr.settings.lmi == LMI_CISCO)) { if (fr_lmi_recv(ndev, skb)) goto rx_error; dev_kfree_skb_any(skb); return NET_RX_SUCCESS; } pvc = find_pvc(hdlc, dlci); if (!pvc) { #ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", ndev->name, dlci); #endif dev_kfree_skb_any(skb); return NET_RX_DROP; } if (pvc->state.fecn != fh->fecn) { #ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name, dlci, fh->fecn ? "N" : "FF"); #endif pvc->state.fecn ^= 1; } if (pvc->state.becn != fh->becn) { #ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name, dlci, fh->becn ? "N" : "FF"); #endif pvc->state.becn ^= 1; } if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { hdlc->stats.rx_dropped++; return NET_RX_DROP; } if (data[3] == NLPID_IP) { skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ dev = pvc->main; skb->protocol = htons(ETH_P_IP); } else if (data[3] == NLPID_IPV6) { skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ dev = pvc->main; skb->protocol = htons(ETH_P_IPV6); } else if (skb->len > 10 && data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) { u16 oui = ntohs(*(u16*)(data + 6)); u16 pid = ntohs(*(u16*)(data + 8)); skb_pull(skb, 10); switch ((((u32)oui) << 16) | pid) { case ETH_P_ARP: /* routed frame with SNAP */ case ETH_P_IPX: case ETH_P_IP: /* a long variant */ case ETH_P_IPV6: dev = pvc->main; skb->protocol = htons(pid); break; case 0x80C20007: /* bridged Ethernet frame */ if ((dev = pvc->ether) != NULL) skb->protocol = eth_type_trans(skb, dev); break; default: printk(KERN_INFO "%s: Unsupported protocol, OUI=%x " "PID=%x\n", ndev->name, oui, pid); dev_kfree_skb_any(skb); return NET_RX_DROP; } } else { printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x " "length = %i\n", ndev->name, data[3], skb->len); dev_kfree_skb_any(skb); return NET_RX_DROP; } if (dev) { struct net_device_stats *stats = pvc_get_stats(dev); stats->rx_packets++; /* PVC traffic */ stats->rx_bytes += skb->len; if (pvc->state.becn) stats->rx_compressed++; skb->dev = dev; netif_rx(skb); return NET_RX_SUCCESS; } else { dev_kfree_skb_any(skb); return NET_RX_DROP; } rx_error: hdlc->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } static void fr_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_start\n"); #endif if (hdlc->state.fr.settings.lmi != LMI_NONE) { hdlc->state.fr.reliable = 0; hdlc->state.fr.dce_changed = 1; hdlc->state.fr.request = 0; hdlc->state.fr.fullrep_sent = 0; hdlc->state.fr.last_errors = 0xFFFFFFFF; hdlc->state.fr.n391cnt = 0; hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0; init_timer(&hdlc->state.fr.timer); /* First poll after 1 s */ hdlc->state.fr.timer.expires = jiffies + HZ; hdlc->state.fr.timer.function = fr_timer; hdlc->state.fr.timer.data = (unsigned long)dev; add_timer(&hdlc->state.fr.timer); } else fr_set_link_state(1, dev); } static void fr_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); #ifdef DEBUG_LINK printk(KERN_DEBUG "fr_stop\n"); #endif if (hdlc->state.fr.settings.lmi != LMI_NONE) del_timer_sync(&hdlc->state.fr.timer); fr_set_link_state(0, dev); } static void fr_close(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc = hdlc->state.fr.first_pvc; while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) dev_close(pvc->main); if (pvc->ether) dev_close(pvc->ether); pvc = pvc->next; } } static void dlci_setup(struct net_device *dev) { dev->type = ARPHRD_DLCI; dev->flags = IFF_POINTOPOINT; dev->hard_header_len = 10; dev->addr_len = 2; } static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type) { hdlc_device *hdlc = dev_to_hdlc(master); pvc_device *pvc = NULL; struct net_device *dev; int result, used; char * prefix = "pvc%d"; if (type == ARPHRD_ETHER) prefix = "pvceth%d"; if ((pvc = add_pvc(master, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", master->name); return -ENOBUFS; } if (*get_dev_p(pvc, type)) return -EEXIST; used = pvc_is_used(pvc); if (type == ARPHRD_ETHER) dev = alloc_netdev(sizeof(struct net_device_stats), "pvceth%d", ether_setup); else dev = alloc_netdev(sizeof(struct net_device_stats), "pvc%d", dlci_setup); if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", master->name); delete_unused_pvcs(hdlc); return -ENOBUFS; } if (type == ARPHRD_ETHER) { memcpy(dev->dev_addr, "\x00\x01", 2); get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); } else { *(u16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); } dev->hard_start_xmit = pvc_xmit; dev->get_stats = pvc_get_stats; dev->open = pvc_open; dev->stop = pvc_close; dev->do_ioctl = pvc_ioctl; dev->change_mtu = pvc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->tx_queue_len = 0; dev->priv = pvc; result = dev_alloc_name(dev, dev->name); if (result < 0) { free_netdev(dev); delete_unused_pvcs(hdlc); return result; } if (register_netdevice(dev) != 0) { free_netdev(dev); delete_unused_pvcs(hdlc); return -EIO; } dev->destructor = free_netdev; *get_dev_p(pvc, type) = dev; if (!used) { hdlc->state.fr.dce_changed = 1; hdlc->state.fr.dce_pvc_count++; } return 0; } static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) { pvc_device *pvc; struct net_device *dev; if ((pvc = find_pvc(hdlc, dlci)) == NULL) return -ENOENT; if ((dev = *get_dev_p(pvc, type)) == NULL) return -ENOENT; if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ unregister_netdevice(dev); /* the destructor will free_netdev(dev) */ *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { hdlc->state.fr.dce_pvc_count--; hdlc->state.fr.dce_changed = 1; } delete_unused_pvcs(hdlc); return 0; } static void fr_destroy(hdlc_device *hdlc) { pvc_device *pvc; pvc = hdlc->state.fr.first_pvc; hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ hdlc->state.fr.dce_pvc_count = 0; hdlc->state.fr.dce_changed = 1; while (pvc) { pvc_device *next = pvc->next; /* destructors will free_netdev() main and ether */ if (pvc->main) unregister_netdevice(pvc->main); if (pvc->ether) unregister_netdevice(pvc->ether); kfree(pvc); pvc = next; } } int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr) { fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr; const size_t size = sizeof(fr_proto); fr_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); fr_proto_pvc pvc; int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: ifr->ifr_settings.type = IF_PROTO_FR; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } if (copy_to_user(fr_s, &hdlc->state.fr.settings, size)) return -EFAULT; return 0; case IF_PROTO_FR: if(!capable(CAP_NET_ADMIN)) return -EPERM; if(dev->flags & IFF_UP) return -EBUSY; if (copy_from_user(&new_settings, fr_s, size)) return -EFAULT; if (new_settings.lmi == LMI_DEFAULT) new_settings.lmi = LMI_ANSI; if ((new_settings.lmi != LMI_NONE && new_settings.lmi != LMI_ANSI && new_settings.lmi != LMI_CCITT && new_settings.lmi != LMI_CISCO) || new_settings.t391 < 1 || new_settings.t392 < 2 || new_settings.n391 < 1 || new_settings.n392 < 1 || new_settings.n393 < new_settings.n392 || new_settings.n393 > 32 || (new_settings.dce != 0 && new_settings.dce != 1)) return -EINVAL; result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; if (hdlc->proto.id != IF_PROTO_FR) { hdlc_proto_detach(hdlc); hdlc->state.fr.first_pvc = NULL; hdlc->state.fr.dce_pvc_count = 0; } memcpy(&hdlc->state.fr.settings, &new_settings, size); memset(&hdlc->proto, 0, sizeof(hdlc->proto)); hdlc->proto.close = fr_close; hdlc->proto.start = fr_start; hdlc->proto.stop = fr_stop; hdlc->proto.detach = fr_destroy; hdlc->proto.netif_rx = fr_rx; hdlc->proto.id = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->addr_len = 0; return 0; case IF_PROTO_FR_ADD_PVC: case IF_PROTO_FR_DEL_PVC: case IF_PROTO_FR_ADD_ETH_PVC: case IF_PROTO_FR_DEL_ETH_PVC: if(!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc, sizeof(fr_proto_pvc))) return -EFAULT; if (pvc.dlci <= 0 || pvc.dlci >= 1024) return -EINVAL; /* Only 10 bits, DLCI 0 reserved */ if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC || ifr->ifr_settings.type == IF_PROTO_FR_DEL_ETH_PVC) result = ARPHRD_ETHER; /* bridged Ethernet device */ else result = ARPHRD_DLCI; if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC || ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC) return fr_add_pvc(dev, pvc.dlci, result); else return fr_del_pvc(hdlc, pvc.dlci, result); } return -EINVAL; } dahdi-linux-2.5.0.1/drivers/dahdi/datamods/syncppp.c0000644000175000017500000011576111027030713022177 0ustar tzafrirtzafrir/* * NET3: A (fairly minimal) implementation of synchronous PPP for Linux * as well as a CISCO HDLC implementation. See the copyright * message below for the original source. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the license, or (at your option) any later version. * * Note however. This code is also used in a different form by FreeBSD. * Therefore when making any non OS specific change please consider * contributing it back to the original author under the terms * below in addition. * -- Alan * * Port for Linux-2.1 by Jan "Yenya" Kasprzak */ /* * Synchronous PPP/Cisco link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. * * Copyright (C) 1994 Cronyx Ltd. * Author: Serge Vakulenko, * * This software is distributed with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Authors grant any other persons or organisations permission to use * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 * * $Id: syncppp.c 4436 2008-06-20 22:40:11Z kpfleming $ */ #undef DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXALIVECNT 6 /* max. alive packets */ #define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ #define PPP_UI 0x03 /* Unnumbered Information */ #define PPP_IP 0x0021 /* Internet Protocol */ #define PPP_ISO 0x0023 /* ISO OSI Protocol */ #define PPP_XNS 0x0025 /* Xerox NS Protocol */ #define PPP_IPX 0x002b /* Novell IPX Protocol */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ #define LCP_CONF_REQ 1 /* PPP LCP configure request */ #define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ #define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ #define LCP_CONF_REJ 4 /* PPP LCP configure reject */ #define LCP_TERM_REQ 5 /* PPP LCP terminate request */ #define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ #define LCP_CODE_REJ 7 /* PPP LCP code reject */ #define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ #define LCP_ECHO_REQ 9 /* PPP LCP echo request */ #define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ #define LCP_DISC_REQ 11 /* PPP LCP discard request */ #define LCP_OPT_MRU 1 /* maximum receive unit */ #define LCP_OPT_ASYNC_MAP 2 /* async control character map */ #define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ #define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ #define LCP_OPT_MAGIC 5 /* magic number */ #define LCP_OPT_RESERVED 6 /* reserved */ #define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ #define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ #define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ #define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ #define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ #define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ #define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ #define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ #define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ #define CISCO_MULTICAST 0x8f /* Cisco multicast address */ #define CISCO_UNICAST 0x0f /* Cisco unicast address */ #define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ #define CISCO_ADDR_REQ 0 /* Cisco address request */ #define CISCO_ADDR_REPLY 1 /* Cisco address reply */ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ struct ppp_header { u8 address; u8 control; u16 protocol; }; #define PPP_HEADER_LEN sizeof (struct ppp_header) struct lcp_header { u8 type; u8 ident; u16 len; }; #define LCP_HEADER_LEN sizeof (struct lcp_header) struct cisco_packet { u32 type; u32 par1; u32 par2; u16 rel; u16 time0; u16 time1; }; #define CISCO_PACKET_LEN 18 #define CISCO_BIG_PACKET_LEN 20 static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; static DEFINE_SPINLOCK(spppq_lock); /* global xmit queue for sending packets while spinlock is held */ static struct sk_buff_head tx_queue; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data); static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); static void sppp_lcp_open (struct sppp *sp); static void sppp_ipcp_open (struct sppp *sp); static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, int len, u32 *magic); static void sppp_cp_timeout (unsigned long arg); static char *sppp_lcp_type_name (u8 type); static char *sppp_ipcp_type_name (u8 type); static void sppp_print_bytes (u8 *p, u16 len); static int debug; /* Flush global outgoing packet queue to dev_queue_xmit(). * * dev_queue_xmit() must be called with interrupts enabled * which means it can't be called with spinlocks held. * If a packet needs to be sent while a spinlock is held, * then put the packet into tx_queue, and call sppp_flush_xmit() * after spinlock is released. */ static void sppp_flush_xmit(void) { struct sk_buff *skb; while ((skb = skb_dequeue(&tx_queue)) != NULL) dev_queue_xmit(skb); } /* * Interface down stub */ static void if_down(struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); sp->pp_link_state=SPPP_LINK_DOWN; } /* * Timeout routine activations. */ static void sppp_set_timeout(struct sppp *p,int s) { if (! (p->pp_flags & PP_TIMO)) { init_timer(&p->pp_timer); p->pp_timer.function=sppp_cp_timeout; p->pp_timer.expires=jiffies+s*HZ; p->pp_timer.data=(unsigned long)p; p->pp_flags |= PP_TIMO; add_timer(&p->pp_timer); } } static void sppp_clear_timeout(struct sppp *p) { if (p->pp_flags & PP_TIMO) { del_timer(&p->pp_timer); p->pp_flags &= ~PP_TIMO; } } /** * sppp_input - receive and process a WAN PPP frame * @skb: The buffer to process * @dev: The device it arrived on * * This can be called directly by cards that do not have * timing constraints but is normally called from the network layer * after interrupt servicing to process frames queued via netif_rx(). * * We process the options in the card. If the frame is destined for * the protocol stacks then it requeues the frame for the upper level * protocol. If it is a control from it is processed and discarded * here. */ static void sppp_input (struct net_device *dev, struct sk_buff *skb) { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; skb->dev=dev; skb->mac.raw=skb->data; if (dev->flags & IFF_RUNNING) { /* Count received bytes, add FCS and one flag */ sp->ibytes+= skb->len + 3; sp->ipkts++; } if (!pskb_may_pull(skb, PPP_HEADER_LEN)) { /* Too small packet, drop it. */ if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", dev->name, skb->len); kfree_skb(skb); return; } /* Get PPP header. */ h = (struct ppp_header *)skb->data; skb_pull(skb,sizeof(struct ppp_header)); spin_lock_irqsave(&sp->lock, flags); switch (h->address) { default: /* Invalid PPP packet. */ goto invalid; case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; if (sp->pp_flags & PP_CISCO) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", dev->name, h->address, h->control, ntohs (h->protocol)); goto drop; } switch (ntohs (h->protocol)) { default: if (sp->lcp.state == LCP_STATE_OPENED) sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, ++sp->pp_seq, skb->len + 2, &h->protocol); if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", dev->name, h->address, h->control, ntohs (h->protocol)); goto drop; case PPP_LCP: sppp_lcp_input (sp, skb); goto drop; case PPP_IPCP: if (sp->lcp.state == LCP_STATE_OPENED) sppp_ipcp_input (sp, skb); else printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); goto drop; case PPP_IP: if (sp->ipcp.state == IPCP_STATE_OPENED) { if(sp->pp_flags&PP_DEBUG) printk(KERN_DEBUG "Yow an IP frame.\n"); skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; goto done; } break; #ifdef IPX case PPP_IPX: /* IPX IPXCP not implemented yet */ if (sp->lcp.state == LCP_STATE_OPENED) { skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; goto done; } break; #endif } break; case CISCO_MULTICAST: case CISCO_UNICAST: /* Don't check the control field here (RFC 1547). */ if (! (sp->pp_flags & PP_CISCO)) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", dev->name, h->address, h->control, ntohs (h->protocol)); goto drop; } switch (ntohs (h->protocol)) { default: goto invalid; case CISCO_KEEPALIVE: sppp_cisco_input (sp, skb); goto drop; #ifdef CONFIG_INET case ETH_P_IP: skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; goto done; #endif #ifdef CONFIG_IPX case ETH_P_IPX: skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; goto done; #endif } break; } goto drop; invalid: if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", dev->name, h->address, h->control, ntohs (h->protocol)); drop: kfree_skb(skb); done: spin_unlock_irqrestore(&sp->lock, flags); sppp_flush_xmit(); return; } /* * Handle transmit packets. */ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, void *daddr, void *saddr, unsigned int len) { struct sppp *sp = (struct sppp *)sppp_of(dev); struct ppp_header *h; skb_push(skb,sizeof(struct ppp_header)); h=(struct ppp_header *)skb->data; if(sp->pp_flags&PP_CISCO) { h->address = CISCO_UNICAST; h->control = 0; } else { h->address = PPP_ALLSTATIONS; h->control = PPP_UI; } if(sp->pp_flags & PP_CISCO) { h->protocol = htons(type); } else switch(type) { case ETH_P_IP: h->protocol = htons(PPP_IP); break; case ETH_P_IPX: h->protocol = htons(PPP_IPX); break; } return sizeof(struct ppp_header); } static int sppp_rebuild_header(struct sk_buff *skb) { return 0; } /* * Send keepalive packets, every 10 seconds. */ static void sppp_keepalive (unsigned long dummy) { struct sppp *sp; unsigned long flags; spin_lock_irqsave(&spppq_lock, flags); for (sp=spppq; sp; sp=sp->pp_next) { struct net_device *dev = sp->pp_if; /* Keepalive mode disabled or channel down? */ if (! (sp->pp_flags & PP_KEEPALIVE) || ! (dev->flags & IFF_UP)) continue; spin_lock(&sp->lock); /* No keepalive in PPP mode if LCP not opened yet. */ if (! (sp->pp_flags & PP_CISCO) && sp->lcp.state != LCP_STATE_OPENED) { spin_unlock(&sp->lock); continue; } if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ printk (KERN_WARNING "%s: protocol down\n", dev->name); if_down (dev); if (! (sp->pp_flags & PP_CISCO)) { /* Shut down the PPP link. */ sp->lcp.magic = jiffies; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); /* Initiate negotiation. */ sppp_lcp_open (sp); } } if (sp->pp_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_flags & PP_CISCO) sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, sp->pp_rseq); else if (sp->lcp.state == LCP_STATE_OPENED) { long nmagic = htonl (sp->lcp.magic); sp->lcp.echoid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } spin_unlock(&sp->lock); } spin_unlock_irqrestore(&spppq_lock, flags); sppp_flush_xmit(); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } /* * Handle incoming PPP Link Control Protocol packets. */ static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) { struct lcp_header *h; struct net_device *dev = sp->pp_if; int len = skb->len; u8 *p, opt[6]; u32 rmagic; if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", dev->name, len); return; } h = (struct lcp_header *)skb->data; skb_pull(skb,sizeof(struct lcp_header *)); if (sp->pp_flags & PP_DEBUG) { char state = '?'; switch (sp->lcp.state) { case LCP_STATE_CLOSED: state = 'C'; break; case LCP_STATE_ACK_RCVD: state = 'R'; break; case LCP_STATE_ACK_SENT: state = 'S'; break; case LCP_STATE_OPENED: state = 'O'; break; } printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", dev->name, state, len, sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) sppp_print_bytes ((u8*) (h+1), len-4); printk (">\n"); } if (len > ntohs (h->len)) len = ntohs (h->len); switch (h->type) { default: /* Unknown packet type -- send Code-Reject packet. */ sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, skb->len, h); break; case LCP_CONF_REQ: if (len < 4) { if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", dev->name, len); break; } if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) goto badreq; if (rmagic == sp->lcp.magic) { /* Local and remote magics equal -- loopback? */ if (sp->pp_loopcnt >= MAXALIVECNT*5) { printk (KERN_WARNING "%s: loopback\n", dev->name); sp->pp_loopcnt = 0; if (dev->flags & IFF_UP) { if_down (dev); } } else if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: conf req: magic glitch\n", dev->name); ++sp->pp_loopcnt; /* MUST send Conf-Nack packet. */ rmagic = ~sp->lcp.magic; opt[0] = LCP_OPT_MAGIC; opt[1] = sizeof (opt); opt[2] = rmagic >> 24; opt[3] = rmagic >> 16; opt[4] = rmagic >> 8; opt[5] = rmagic; sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, h->ident, sizeof (opt), &opt); badreq: switch (sp->lcp.state) { case LCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_lcp_open (sp); /* fall through... */ case LCP_STATE_ACK_SENT: /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } break; } /* Send Configure-Ack packet. */ sp->pp_loopcnt = 0; if (sp->lcp.state != LCP_STATE_OPENED) { sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); } /* Change the state. */ switch (sp->lcp.state) { case LCP_STATE_CLOSED: sp->lcp.state = LCP_STATE_ACK_SENT; break; case LCP_STATE_ACK_RCVD: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); break; case LCP_STATE_OPENED: /* Remote magic changed -- close session. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ sppp_lcp_open (sp); /* Send ACK after our REQ in attempt to break loop */ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); sp->lcp.state = LCP_STATE_ACK_SENT; break; } break; case LCP_CONF_ACK: if (h->ident != sp->lcp.confid) break; sppp_clear_timeout (sp); if ((sp->pp_link_state != SPPP_LINK_UP) && (dev->flags & IFF_UP)) { /* Coming out of loopback mode. */ sp->pp_link_state=SPPP_LINK_UP; printk (KERN_INFO "%s: protocol up\n", dev->name); } switch (sp->lcp.state) { case LCP_STATE_CLOSED: sp->lcp.state = LCP_STATE_ACK_RCVD; sppp_set_timeout (sp, 5); break; case LCP_STATE_ACK_SENT: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); break; } break; case LCP_CONF_NAK: if (h->ident != sp->lcp.confid) break; p = (u8*) (h+1); if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { rmagic = (u32)p[2] << 24 | (u32)p[3] << 16 | p[4] << 8 | p[5]; if (rmagic == ~sp->lcp.magic) { int newmagic; if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: conf nak: magic glitch\n", dev->name); get_random_bytes(&newmagic, sizeof(newmagic)); sp->lcp.magic += newmagic; } else sp->lcp.magic = rmagic; } if (sp->lcp.state != LCP_STATE_ACK_SENT) { /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } /* The link will be renegotiated after timeout, * to avoid endless req-nack loop. */ sppp_clear_timeout (sp); sppp_set_timeout (sp, 2); break; case LCP_CONF_REJ: if (h->ident != sp->lcp.confid) break; sppp_clear_timeout (sp); /* Initiate renegotiation. */ sppp_lcp_open (sp); if (sp->lcp.state != LCP_STATE_ACK_SENT) { /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } break; case LCP_TERM_REQ: sppp_clear_timeout (sp); /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL); /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ sppp_lcp_open (sp); break; case LCP_TERM_ACK: case LCP_CODE_REJ: case LCP_PROTO_REJ: /* Ignore for now. */ break; case LCP_DISC_REQ: /* Discard the packet. */ break; case LCP_ECHO_REQ: if (sp->lcp.state != LCP_STATE_OPENED) break; if (len < 8) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", dev->name, len); break; } if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { /* Line loopback mode detected. */ printk (KERN_WARNING "%s: loopback\n", dev->name); if_down (dev); /* Shut down the PPP link. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); /* Initiate negotiation. */ sppp_lcp_open (sp); break; } *(long*)(h+1) = htonl (sp->lcp.magic); sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); break; case LCP_ECHO_REPLY: if (h->ident != sp->lcp.echoid) break; if (len < 8) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", dev->name, len); break; } if (ntohl (*(long*)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; } } /* * Handle incoming Cisco keepalive protocol packets. */ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) { struct cisco_packet *h; struct net_device *dev = sp->pp_if; if (!pskb_may_pull(skb, sizeof(struct cisco_packet)) || (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN)) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", dev->name, skb->len); return; } h = (struct cisco_packet *)skb->data; skb_pull(skb, sizeof(struct cisco_packet*)); if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n", dev->name, skb->len, ntohl (h->type), h->par1, h->par2, h->rel, h->time0, h->time1); switch (ntohl (h->type)) { default: if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n", dev->name, ntohl (h->type)); break; case CISCO_ADDR_REPLY: /* Reply on address request, ignore */ break; case CISCO_KEEPALIVE_REQ: sp->pp_alivecnt = 0; sp->pp_rseq = ntohl (h->par1); if (sp->pp_seq == sp->pp_rseq) { /* Local and remote sequence numbers are equal. * Probably, the line is in loopback mode. */ int newseq; if (sp->pp_loopcnt >= MAXALIVECNT) { printk (KERN_WARNING "%s: loopback\n", dev->name); sp->pp_loopcnt = 0; if (dev->flags & IFF_UP) { if_down (dev); } } ++sp->pp_loopcnt; /* Generate new local sequence number */ get_random_bytes(&newseq, sizeof(newseq)); sp->pp_seq ^= newseq; break; } sp->pp_loopcnt = 0; if (sp->pp_link_state==SPPP_LINK_DOWN && (dev->flags & IFF_UP)) { sp->pp_link_state=SPPP_LINK_UP; printk (KERN_INFO "%s: protocol up\n", dev->name); } break; case CISCO_ADDR_REQ: /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ { struct in_device *in_dev; struct in_ifaddr *ifa; u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */ #ifdef CONFIG_INET rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) != NULL) { for (ifa=in_dev->ifa_list; ifa != NULL; ifa=ifa->ifa_next) { if (strcmp(dev->name, ifa->ifa_label) == 0) { addr = ifa->ifa_local; mask = ifa->ifa_mask; break; } } } rcu_read_unlock(); #endif /* I hope both addr and mask are in the net order */ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); break; } } } /* * Send PPP LCP packet. */ static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data) { struct ppp_header *h; struct lcp_header *lh; struct sk_buff *skb; struct net_device *dev = sp->pp_if; skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, GFP_ATOMIC); if (skb==NULL) return; skb_reserve(skb,dev->hard_header_len); h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); h->address = PPP_ALLSTATIONS; /* broadcast address */ h->control = PPP_UI; /* Unnumbered Info */ h->protocol = htons (proto); /* Link Control Protocol */ lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); lh->type = type; lh->ident = ident; lh->len = htons (LCP_HEADER_LEN + len); if (len) memcpy(skb_put(skb,len),data, len); if (sp->pp_flags & PP_DEBUG) { printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", dev->name, proto==PPP_LCP ? "lcp" : "ipcp", proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : sppp_ipcp_type_name (lh->type), lh->ident, ntohs (lh->len)); if (len) sppp_print_bytes ((u8*) (lh+1), len); printk (">\n"); } sp->obytes += skb->len; /* Control is high priority so it doesn't get queued behind data */ skb->priority=TC_PRIO_CONTROL; skb->dev = dev; skb_queue_tail(&tx_queue, skb); } /* * Send Cisco keepalive packet. */ static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) { struct ppp_header *h; struct cisco_packet *ch; struct sk_buff *skb; struct net_device *dev = sp->pp_if; u32 t = jiffies * 1000/HZ; skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, GFP_ATOMIC); if(skb==NULL) return; skb_reserve(skb, dev->hard_header_len); h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); h->address = CISCO_MULTICAST; h->control = 0; h->protocol = htons (CISCO_KEEPALIVE); ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); ch->type = htonl (type); ch->par1 = htonl (par1); ch->par2 = htonl (par2); ch->rel = -1; ch->time0 = htons ((u16) (t >> 16)); ch->time1 = htons ((u16) t); if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n", dev->name, ntohl (ch->type), ch->par1, ch->par2, ch->rel, ch->time0, ch->time1); sp->obytes += skb->len; skb->priority=TC_PRIO_CONTROL; skb->dev = dev; skb_queue_tail(&tx_queue, skb); } /** * sppp_close - close down a synchronous PPP or Cisco HDLC link * @dev: The network device to drop the link of * * This drops the logical interface to the channel. It is not * done politely as we assume we will also be dropping DTR. Any * timeouts are killed. */ int sppp_close (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; spin_lock_irqsave(&sp->lock, flags); sp->pp_link_state = SPPP_LINK_DOWN; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); spin_unlock_irqrestore(&sp->lock, flags); return 0; } EXPORT_SYMBOL(sppp_close); /** * sppp_open - open a synchronous PPP or Cisco HDLC link * @dev: Network device to activate * * Close down any existing synchronous session and commence * from scratch. In the PPP case this means negotiating LCP/IPCP * and friends, while for Cisco HDLC we simply need to start sending * keepalives */ int sppp_open (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; sppp_close(dev); spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sppp_lcp_open (sp); } sp->pp_link_state = SPPP_LINK_DOWN; spin_unlock_irqrestore(&sp->lock, flags); sppp_flush_xmit(); return 0; } EXPORT_SYMBOL(sppp_open); /** * sppp_reopen - notify of physical link loss * @dev: Device that lost the link * * This function informs the synchronous protocol code that * the underlying link died (for example a carrier drop on X.21) * * We increment the magic numbers to ensure that if the other end * failed to notice we will correctly start a new session. It happens * do to the nature of telco circuits is that you can lose carrier on * one endonly. * * Having done this we go back to negotiating. This function may * be called from an interrupt context. */ int sppp_reopen (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; sppp_close(dev); spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sp->lcp.magic = jiffies; ++sp->pp_seq; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; /* Give it a moment for the line to settle then go */ sppp_set_timeout (sp, 1); } sp->pp_link_state=SPPP_LINK_DOWN; spin_unlock_irqrestore(&sp->lock, flags); return 0; } EXPORT_SYMBOL(sppp_reopen); /** * sppp_change_mtu - Change the link MTU * @dev: Device to change MTU on * @new_mtu: New MTU * * Change the MTU on the link. This can only be called with * the link down. It returns an error if the link is up or * the mtu is out of range. */ static int sppp_change_mtu(struct net_device *dev, int new_mtu) { if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) return -EINVAL; dev->mtu=new_mtu; return 0; } /** * sppp_do_ioctl - Ioctl handler for ppp/hdlc * @dev: Device subject to ioctl * @ifr: Interface request block from the user * @cmd: Command that is being issued * * This function handles the ioctls that may be issued by the user * to control the settings of a PPP/HDLC link. It does both busy * and security checks. This function is intended to be wrapped by * callers who wish to add additional ioctl calls of their own. */ int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct sppp *sp = (struct sppp *)sppp_of(dev); if(dev->flags&IFF_UP) return -EBUSY; if(!capable(CAP_NET_ADMIN)) return -EPERM; switch(cmd) { case SPPPIOCCISCO: sp->pp_flags|=PP_CISCO; dev->type = ARPHRD_HDLC; break; case SPPPIOCPPP: sp->pp_flags&=~PP_CISCO; dev->type = ARPHRD_PPP; break; case SPPPIOCDEBUG: sp->pp_flags&=~PP_DEBUG; if(ifr->ifr_flags) sp->pp_flags|=PP_DEBUG; break; case SPPPIOCGFLAGS: if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) return -EFAULT; break; case SPPPIOCSFLAGS: if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) return -EFAULT; break; default: return -EINVAL; } return 0; } EXPORT_SYMBOL(sppp_do_ioctl); /** * sppp_attach - attach synchronous PPP/HDLC to a device * @pd: PPP device to initialise * * This initialises the PPP/HDLC support on an interface. At the * time of calling the dev element must point to the network device * that this interface is attached to. The interface should not yet * be registered. */ void sppp_attach(struct ppp_device *pd) { struct net_device *dev = pd->dev; struct sppp *sp = &pd->sppp; unsigned long flags; /* Make sure embedding is safe for sppp_of */ BUG_ON(sppp_of(dev) != sp); spin_lock_irqsave(&spppq_lock, flags); /* Initialize keepalive handler. */ if (! spppq) { init_timer(&sppp_keepalive_timer); sppp_keepalive_timer.expires=jiffies+10*HZ; sppp_keepalive_timer.function=sppp_keepalive; add_timer(&sppp_keepalive_timer); } /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; spin_unlock_irqrestore(&spppq_lock, flags); sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; sp->pp_seq = 0; sp->pp_rseq = 0; sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ sp->lcp.magic = 0; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sp->pp_if = dev; spin_lock_init(&sp->lock); /* * Device specific setup. All but interrupt handler and * hard_start_xmit. */ dev->hard_header = sppp_hard_header; dev->rebuild_header = sppp_rebuild_header; dev->tx_queue_len = 10; dev->type = ARPHRD_HDLC; dev->addr_len = 0; dev->hard_header_len = sizeof(struct ppp_header); dev->mtu = PPP_MTU; /* * These 4 are callers but MUST also call sppp_ functions */ dev->do_ioctl = sppp_do_ioctl; #if 0 dev->get_stats = NULL; /* Let the driver override these */ dev->open = sppp_open; dev->stop = sppp_close; #endif dev->change_mtu = sppp_change_mtu; dev->hard_header_cache = NULL; dev->header_cache_update = NULL; dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; } EXPORT_SYMBOL(sppp_attach); /** * sppp_detach - release PPP resources from a device * @dev: Network device to release * * Stop and free up any PPP/HDLC resources used by this * interface. This must be called before the device is * freed. */ void sppp_detach (struct net_device *dev) { struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); unsigned long flags; spin_lock_irqsave(&spppq_lock, flags); /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { *q = p->pp_next; break; } /* Stop keepalive handler. */ if (! spppq) del_timer(&sppp_keepalive_timer); sppp_clear_timeout (sp); spin_unlock_irqrestore(&spppq_lock, flags); } EXPORT_SYMBOL(sppp_detach); /* * Analyze the LCP Configure-Request options list * for the presence of unknown options. * If the request contains unknown options, build and * send Configure-reject packet, containing only unknown options. */ static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, int len, u32 *magic) { u8 *buf, *r, *p; int rlen; len -= 4; buf = r = kmalloc (len, GFP_ATOMIC); if (! buf) return (0); p = (void*) (h+1); for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { switch (*p) { case LCP_OPT_MAGIC: /* Magic number -- extract. */ if (len >= 6 && p[1] == 6) { *magic = (u32)p[2] << 24 | (u32)p[3] << 16 | p[4] << 8 | p[5]; continue; } break; case LCP_OPT_ASYNC_MAP: /* Async control character map -- check to be zero. */ if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && ! p[4] && ! p[5]) continue; break; case LCP_OPT_MRU: /* Maximum receive unit -- always OK. */ continue; default: /* Others not supported. */ break; } /* Add the option to rejected list. */ memcpy(r, p, p[1]); r += p[1]; rlen += p[1]; } if (rlen) sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); kfree(buf); return (rlen == 0); } static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) { struct lcp_header *h; struct net_device *dev = sp->pp_if; int len = skb->len; if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", dev->name, len); return; } h = (struct lcp_header *)skb->data; skb_pull(skb,sizeof(struct lcp_header)); if (sp->pp_flags & PP_DEBUG) { printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", dev->name, len, sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) sppp_print_bytes ((u8*) (h+1), len-4); printk (">\n"); } if (len > ntohs (h->len)) len = ntohs (h->len); switch (h->type) { default: /* Unknown packet type -- send Code-Reject packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); break; case IPCP_CONF_REQ: if (len < 4) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", dev->name, len); return; } if (len > 4) { sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, len-4, h+1); switch (sp->ipcp.state) { case IPCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_ipcp_open (sp); /* fall through... */ case IPCP_STATE_ACK_SENT: /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; } } else { /* Send Configure-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 0, NULL); /* Change the state. */ if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) sp->ipcp.state = IPCP_STATE_OPENED; else sp->ipcp.state = IPCP_STATE_ACK_SENT; } break; case IPCP_CONF_ACK: if (h->ident != sp->ipcp.confid) break; sppp_clear_timeout (sp); switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: sp->ipcp.state = IPCP_STATE_ACK_RCVD; sppp_set_timeout (sp, 5); break; case IPCP_STATE_ACK_SENT: sp->ipcp.state = IPCP_STATE_OPENED; break; } break; case IPCP_CONF_NAK: case IPCP_CONF_REJ: if (h->ident != sp->ipcp.confid) break; sppp_clear_timeout (sp); /* Initiate renegotiation. */ sppp_ipcp_open (sp); if (sp->ipcp.state != IPCP_STATE_ACK_SENT) /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; break; case IPCP_TERM_REQ: /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL); /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ sppp_ipcp_open (sp); break; case IPCP_TERM_ACK: /* Ignore for now. */ case IPCP_CODE_REJ: /* Ignore for now. */ break; } } static void sppp_lcp_open (struct sppp *sp) { char opt[6]; if (! sp->lcp.magic) sp->lcp.magic = jiffies; opt[0] = LCP_OPT_MAGIC; opt[1] = sizeof (opt); opt[2] = sp->lcp.magic >> 24; opt[3] = sp->lcp.magic >> 16; opt[4] = sp->lcp.magic >> 8; opt[5] = sp->lcp.magic; sp->lcp.confid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, sizeof (opt), &opt); sppp_set_timeout (sp, 2); } static void sppp_ipcp_open (struct sppp *sp) { sp->ipcp.confid = ++sp->pp_seq; sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL); sppp_set_timeout (sp, 2); } /* * Process PPP control protocol timeouts. */ static void sppp_cp_timeout (unsigned long arg) { struct sppp *sp = (struct sppp*) arg; unsigned long flags; spin_lock_irqsave(&sp->lock, flags); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { spin_unlock_irqrestore(&sp->lock, flags); return; } switch (sp->lcp.state) { case LCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ sppp_lcp_open (sp); break; case LCP_STATE_ACK_RCVD: /* ACK got, but no Configure-Request for peer, retry. */ sppp_lcp_open (sp); sp->lcp.state = LCP_STATE_CLOSED; break; case LCP_STATE_ACK_SENT: /* ACK sent but no ACK for Configure-Request, retry. */ sppp_lcp_open (sp); break; case LCP_STATE_OPENED: /* LCP is already OK, try IPCP. */ switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ sppp_ipcp_open (sp); break; case IPCP_STATE_ACK_RCVD: /* ACK got, but no Configure-Request for peer, retry. */ sppp_ipcp_open (sp); sp->ipcp.state = IPCP_STATE_CLOSED; break; case IPCP_STATE_ACK_SENT: /* ACK sent but no ACK for Configure-Request, retry. */ sppp_ipcp_open (sp); break; case IPCP_STATE_OPENED: /* IPCP is OK. */ break; } break; } spin_unlock_irqrestore(&sp->lock, flags); sppp_flush_xmit(); } static char *sppp_lcp_type_name (u8 type) { static char buf [8]; switch (type) { case LCP_CONF_REQ: return ("conf-req"); case LCP_CONF_ACK: return ("conf-ack"); case LCP_CONF_NAK: return ("conf-nack"); case LCP_CONF_REJ: return ("conf-rej"); case LCP_TERM_REQ: return ("term-req"); case LCP_TERM_ACK: return ("term-ack"); case LCP_CODE_REJ: return ("code-rej"); case LCP_PROTO_REJ: return ("proto-rej"); case LCP_ECHO_REQ: return ("echo-req"); case LCP_ECHO_REPLY: return ("echo-reply"); case LCP_DISC_REQ: return ("discard-req"); } sprintf (buf, "%xh", type); return (buf); } static char *sppp_ipcp_type_name (u8 type) { static char buf [8]; switch (type) { case IPCP_CONF_REQ: return ("conf-req"); case IPCP_CONF_ACK: return ("conf-ack"); case IPCP_CONF_NAK: return ("conf-nack"); case IPCP_CONF_REJ: return ("conf-rej"); case IPCP_TERM_REQ: return ("term-req"); case IPCP_TERM_ACK: return ("term-ack"); case IPCP_CODE_REJ: return ("code-rej"); } sprintf (buf, "%xh", type); return (buf); } static void sppp_print_bytes (u_char *p, u16 len) { printk (" %x", *p++); while (--len > 0) printk ("-%x", *p++); } /** * sppp_rcv - receive and process a WAN PPP frame * @skb: The buffer to process * @dev: The device it arrived on * @p: Unused * @orig_dev: Unused * * Protocol glue. This drives the deferred processing mode the poorer * cards use. This can be called directly by cards that do not have * timing constraints but is normally called from the network layer * after interrupt servicing to process frames queued via netif_rx. */ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; sppp_input(dev,skb); return 0; } static struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, }; static char banner[] __initdata = KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n" KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & " "Jan \"Yenya\" Kasprzak.\n"; static int __init sync_ppp_init(void) { if(debug) debug=PP_DEBUG; printk(banner); skb_queue_head_init(&tx_queue); dev_add_pack(&sppp_packet_type); return 0; } static void __exit sync_ppp_cleanup(void) { dev_remove_pack(&sppp_packet_type); } module_init(sync_ppp_init); module_exit(sync_ppp_cleanup); module_param(debug, int, 0); MODULE_LICENSE("GPL v2"); dahdi-linux-2.5.0.1/drivers/dahdi/wcte12xp/0000755000175000017500000000000011631523356020220 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/wcte12xp/base.c0000644000175000017500000022046011611644535021303 0ustar tzafrirtzafrir/* * Digium, Inc. Wildcard TE12xP T1/E1 card Driver * * Written by Michael Spiceland * * Adapted from the wctdm24xxp and wcte11xp drivers originally * written by Mark Spencer * Matthew Fredrickson * William Meadows * * Copyright (C) 2007-2011, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wct4xxp/wct4xxp.h" /* For certain definitions */ #include "voicebus/voicebus.h" #include "voicebus/vpmoct.h" #include "wcte12xp.h" #include "voicebus/GpakCust.h" #include "voicebus/GpakApi.h" #if VOICEBUS_SFRAME_SIZE != SFRAME_SIZE #error VOICEBUS_SFRAME_SIZE != SFRAME_SIZE #endif static int debug; static int j1mode = 0; static int alarmdebounce = 2500; /* LOF/LFA def to 2.5s AT&T TR54016*/ static int losalarmdebounce = 2500; /* LOS def to 2.5s AT&T TR54016*/ static int aisalarmdebounce = 2500; /* AIS(blue) def to 2.5s AT&T TR54016*/ static int yelalarmdebounce = 500; /* RAI(yellow) def to 0.5s AT&T devguide */ static int t1e1override = -1; static int latency = VOICEBUS_DEFAULT_LATENCY; static unsigned int max_latency = VOICEBUS_DEFAULT_MAXLATENCY; static int vpmsupport = 1; static int vpmtsisupport = 0; static int vpmnlptype = DEFAULT_NLPTYPE; static int vpmnlpthresh = DEFAULT_NLPTHRESH; static int vpmnlpmaxsupp = DEFAULT_NLPMAXSUPP; static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static int t1xxp_clear_maint(struct dahdi_span *span); static const struct dahdi_echocan_features vpm150m_ec_features = { .NLP_automatic = 1, .CED_tx_detect = 1, .CED_rx_detect = 1, }; static const struct dahdi_echocan_ops vpm150m_ec_ops = { .echocan_free = echocan_free, }; static struct t1 *ifaces[WC_MAX_IFACES]; struct t1_desc { const char *name; }; static const struct t1_desc te120p = {"Wildcard TE120P"}; static const struct t1_desc te122 = {"Wildcard TE122"}; static const struct t1_desc te121 = {"Wildcard TE121"}; /* names of HWEC modules */ static const char *vpmadt032_name = "VPMADT032"; static const char *vpmoct_name = "VPMOCT032"; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static kmem_cache_t *cmd_cache; #else static struct kmem_cache *cmd_cache; #endif static struct command *get_free_cmd(struct t1 *wc) { struct command *cmd; cmd = kmem_cache_alloc(cmd_cache, GFP_ATOMIC); if (cmd) { memset(cmd, 0, sizeof(*cmd)); init_completion(&cmd->complete); INIT_LIST_HEAD(&cmd->node); } return cmd; } static void free_cmd(struct t1 *wc, struct command *cmd) { kmem_cache_free(cmd_cache, cmd); } static struct command *_get_pending_cmd(struct t1 *wc) { struct command *cmd = NULL; if (!list_empty(&wc->pending_cmds)) { cmd = list_entry(wc->pending_cmds.next, struct command, node); list_move_tail(&cmd->node, &wc->active_cmds); } return cmd; } static void submit_cmd(struct t1 *wc, struct command *cmd) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); list_add_tail(&cmd->node, &wc->pending_cmds); spin_unlock_irqrestore(&wc->reglock, flags); } static void _resend_cmds(struct t1 *wc) { list_splice_init(&wc->active_cmds, &wc->pending_cmds); if (wc->vpmadt032) vpmadt032_resend(wc->vpmadt032); } static inline void cmd_dequeue_vpmoct(struct t1 *wc, u8 *eframe) { struct vpmoct *vpm = wc->vpmoct; struct vpmoct_cmd *cmd; u8 i; /* Pop a command off pending list */ spin_lock(&vpm->list_lock); if (list_empty(&vpm->pending_list)) { spin_unlock(&vpm->list_lock); return; } cmd = list_entry(vpm->pending_list.next, struct vpmoct_cmd, node); /* Push the command onto active list, if it's a syncronous cmd */ if (is_vpmoct_cmd_read(cmd)) list_move_tail(&cmd->node, &vpm->active_list); else list_del_init(&cmd->node); /* Skip audio */ eframe += 66; /* Save ident so we can match the return eframe */ cmd->txident = wc->txident; /* We have four timeslots to work with for a regular spi packet */ /* TODO: Create debug flag for this in dev */ eframe[CMD_BYTE(0, 0, 1)] = 0x12; eframe[CMD_BYTE(0, 1, 1)] = 0x34; eframe[CMD_BYTE(0, 2, 1)] = 0x56; eframe[CMD_BYTE(1, 0, 1)] = cmd->command; eframe[CMD_BYTE(1, 1, 1)] = cmd->address; eframe[CMD_BYTE(1, 2, 1)] = cmd->data[0]; for (i = 1; i < cmd->chunksize; i++) { /* Every time slot is filled with chunk data * ignoring command/address/data structure */ eframe[CMD_BYTE(1, 2, 1) + 2*i] = cmd->data[i]; } /* Clean up fire-and-forget messages from memory */ if (list_empty(&cmd->node)) kfree(cmd); spin_unlock(&vpm->list_lock); #if 0 dev_info(&wc->vb.pdev->dev, "Wrote: "); for (i = 0; i < 7; i++) { dev_info(&wc->vb.pdev->dev, "|%x %x %x|", eframe[CMD_BYTE(i, 0, 1)], eframe[CMD_BYTE(i, 1, 1)], eframe[CMD_BYTE(i, 2, 1)]); } #endif } static void cmd_dequeue(struct t1 *wc, unsigned char *eframe, int frame_num, int slot) { struct command *curcmd=NULL; u16 address; u8 data; u32 flags; /* Skip audio */ eframe += 66; /* Search for something waiting to transmit */ if ((slot < 6) && (frame_num) && (frame_num < DAHDI_CHUNKSIZE - 1)) { /* only 6 useable cs slots per */ /* framer */ curcmd = _get_pending_cmd(wc); if (curcmd) { curcmd->cs_slot = slot; curcmd->ident = wc->txident; address = curcmd->address; data = curcmd->data; flags = curcmd->flags; } else { /* If nothing else, use filler */ address = 0x4a; data = 0; flags = __CMD_RD; } if (flags & __CMD_WR) eframe[CMD_BYTE(slot, 0, 0)] = 0x0c; /* 0c write command */ else if (flags & __CMD_LEDS) eframe[CMD_BYTE(slot, 0, 0)] = 0x10 | ((address) & 0x0E); /* led set command */ else if (flags & __CMD_PINS) eframe[CMD_BYTE(slot, 0, 0)] = 0x30; /* CPLD2 pin state */ else eframe[CMD_BYTE(slot, 0, 0)] = 0x0a; /* read command */ eframe[CMD_BYTE(slot, 1, 0)] = address; eframe[CMD_BYTE(slot, 2, 0)] = data; } } static inline void cmd_decipher(struct t1 *wc, const u8 *eframe) { struct command *cmd = NULL; const int IS_VPM = 0; /* Skip audio */ eframe += 66; while (!list_empty(&wc->active_cmds)) { cmd = list_entry(wc->active_cmds.next, struct command, node); if (cmd->ident != wc->rxident) break; if (cmd->flags & (__CMD_WR | __CMD_LEDS)) { /* Nobody is waiting on writes...so let's just * free them here. */ list_del_init(&cmd->node); free_cmd(wc, cmd); } else { cmd->data |= eframe[CMD_BYTE(cmd->cs_slot, 2, IS_VPM)]; list_del_init(&cmd->node); complete(&cmd->complete); } } } inline void cmd_decipher_vpmoct(struct t1 *wc, const u8 *eframe) { int i; struct vpmoct *vpm = wc->vpmoct; struct vpmoct_cmd *cmd; /* Skip audio and first 6 timeslots */ eframe += 66; spin_lock(&vpm->list_lock); /* No command to handle, just exit */ if (list_empty(&vpm->active_list)) { spin_unlock(&vpm->list_lock); return; } cmd = list_entry(vpm->active_list.next, struct vpmoct_cmd, node); if (wc->rxident == cmd->txident) list_del_init(&cmd->node); else cmd = NULL; spin_unlock(&vpm->list_lock); if (!cmd) return; #if 0 /* Store result */ dev_info(&wc->vb.pdev->dev, "Read: "); for (i = 0; i < 7; i++) { dev_info(&wc->vb.pdev->dev, "|%x %x %x|", eframe[CMD_BYTE(i, 0, 1)], eframe[CMD_BYTE(i, 1, 1)], eframe[CMD_BYTE(i, 2, 1)]); } dev_info(&wc->vb.pdev->dev, "\n"); #endif cmd->command = eframe[CMD_BYTE(1, 0, 1)]; cmd->address = eframe[CMD_BYTE(1, 1, 1)]; for (i = 0; i < cmd->chunksize; ++i) cmd->data[i] = eframe[CMD_BYTE(1, 2, 1) + 2*i]; complete(&cmd->complete); } inline void cmd_decipher_vpmadt032(struct t1 *wc, const u8 *eframe) { struct vpmadt032 *vpm = wc->vpmadt032; struct vpmadt032_cmd *cmd; BUG_ON(!vpm); /* If the hardware is not processing any commands currently, then * there is nothing for us to do here. */ if (list_empty(&vpm->active_cmds)) { return; } spin_lock(&vpm->list_lock); cmd = list_entry(vpm->active_cmds.next, struct vpmadt032_cmd, node); if (wc->rxident == cmd->txident) { list_del_init(&cmd->node); } else { cmd = NULL; } spin_unlock(&vpm->list_lock); if (!cmd) { return; } /* Skip audio */ eframe += 66; /* Store result */ cmd->data = (0xff & eframe[CMD_BYTE(2, 1, 1)]) << 8; cmd->data |= eframe[CMD_BYTE(2, 2, 1)]; if (cmd->desc & __VPM150M_WR) { kfree(cmd); } else { cmd->desc |= __VPM150M_FIN; complete(&cmd->complete); } } static int config_vpmadt032(struct vpmadt032 *vpm, struct t1 *wc) { int res, channel; GpakPortConfig_t portconfig = {0}; gpakConfigPortStatus_t configportstatus; GPAK_PortConfigStat_t pstatus; GpakChannelConfig_t chanconfig; GPAK_ChannelConfigStat_t cstatus; GPAK_AlgControlStat_t algstatus; /* First Serial Port config */ portconfig.SlotsSelect1 = SlotCfgNone; portconfig.FirstBlockNum1 = 0; portconfig.FirstSlotMask1 = 0x0000; portconfig.SecBlockNum1 = 1; portconfig.SecSlotMask1 = 0x0000; portconfig.SerialWordSize1 = SerWordSize8; portconfig.CompandingMode1 = cmpNone; portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh; portconfig.TxClockPolarity1 = SerClockActHigh; portconfig.RxClockPolarity1 = SerClockActHigh; portconfig.TxDataDelay1 = DataDelay0; portconfig.RxDataDelay1 = DataDelay0; portconfig.DxDelay1 = Disabled; portconfig.ThirdSlotMask1 = 0x0000; portconfig.FouthSlotMask1 = 0x0000; portconfig.FifthSlotMask1 = 0x0000; portconfig.SixthSlotMask1 = 0x0000; portconfig.SevenSlotMask1 = 0x0000; portconfig.EightSlotMask1 = 0x0000; /* Second Serial Port config */ portconfig.SlotsSelect2 = SlotCfg8Groups; portconfig.FirstBlockNum2 = 0; portconfig.FirstSlotMask2 = 0x5554; portconfig.SecBlockNum2 = 1; portconfig.SecSlotMask2 = 0x5555; portconfig.ThirdSlotMask2 = 0x5555; portconfig.FouthSlotMask2 = 0x5555; portconfig.SerialWordSize2 = SerWordSize8; portconfig.CompandingMode2 = cmpNone; portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh; portconfig.TxClockPolarity2 = SerClockActHigh; portconfig.RxClockPolarity2 = SerClockActHigh; portconfig.TxDataDelay2 = DataDelay0; portconfig.RxDataDelay2 = DataDelay0; portconfig.DxDelay2 = Disabled; portconfig.FifthSlotMask2 = 0x0001; portconfig.SixthSlotMask2 = 0x0000; portconfig.SevenSlotMask2 = 0x0000; portconfig.EightSlotMask2 = 0x0000; /* Third Serial Port Config */ portconfig.SlotsSelect3 = SlotCfg8Groups; portconfig.FirstBlockNum3 = 0; portconfig.FirstSlotMask3 = 0x5554; portconfig.SecBlockNum3 = 1; portconfig.SecSlotMask3 = 0x5555; portconfig.SerialWordSize3 = SerWordSize8; portconfig.CompandingMode3 = cmpNone; portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh; portconfig.TxClockPolarity3 = SerClockActHigh; portconfig.RxClockPolarity3 = SerClockActLow; portconfig.TxDataDelay3 = DataDelay0; portconfig.RxDataDelay3 = DataDelay0; portconfig.DxDelay3 = Disabled; portconfig.ThirdSlotMask3 = 0x5555; portconfig.FouthSlotMask3 = 0x5555; portconfig.FifthSlotMask3 = 0x0001; portconfig.SixthSlotMask3 = 0x0000; portconfig.SevenSlotMask3 = 0x0000; portconfig.EightSlotMask3 = 0x0000; if ((configportstatus = gpakConfigurePorts(vpm->dspid, &portconfig, &pstatus))) { t1_info(wc, "Configuration of ports failed (%d)!\n", configportstatus); return -1; } else { if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) t1_info(wc, "Configured McBSP ports successfully\n"); } if ((res = gpakPingDsp(vpm->dspid, &vpm->version))) { t1_info(wc, "Error pinging DSP (%d)\n", res); return -1; } for (channel = 0; channel < ARRAY_SIZE(vpm->curecstate); ++channel) { vpm->curecstate[channel].tap_length = 0; vpm->curecstate[channel].nlp_type = vpm->options.vpmnlptype; vpm->curecstate[channel].nlp_threshold = vpm->options.vpmnlpthresh; vpm->curecstate[channel].nlp_max_suppress = vpm->options.vpmnlpmaxsupp; vpm->setchanconfig_from_state(vpm, channel, &chanconfig); if ((res = gpakConfigureChannel(vpm->dspid, channel, tdmToTdm, &chanconfig, &cstatus))) { t1_info(wc, "Unable to configure channel #%d (%d)", channel, res); if (res == 1) { printk(KERN_CONT ", reason %d", cstatus); } printk(KERN_CONT "\n"); return -1; } if ((res = gpakAlgControl(vpm->dspid, channel, BypassEcanA, &algstatus))) { t1_info(wc, "Unable to disable echo can on channel %d " "(reason %d:%d)\n", channel + 1, res, algstatus); return -1; } } if ((res = gpakPingDsp(vpm->dspid, &vpm->version))) { t1_info(wc, "Error pinging DSP (%d)\n", res); return -1; } set_bit(VPM150M_ACTIVE, &vpm->control); return 0; } #define debug_printk(wc, lvl, fmt, args...) if (debug >= (lvl)) do { \ t1_info((wc), fmt , ## args); } while (0) static void cmd_dequeue_vpmadt032(struct t1 *wc, unsigned char *eframe) { struct vpmadt032_cmd *cmd; struct vpmadt032 *vpm = wc->vpmadt032; int x; unsigned char leds = ~((atomic_read(&wc->txints) / 1000) % 8) & 0x7; /* Skip audio */ eframe += 66; if (test_bit(VPM150M_HPIRESET, &vpm->control)) { debug_printk(wc, 1, "HW Resetting VPMADT032 ...\n"); for (x = 0; x < 4; x++) { if (!x) { if (test_and_clear_bit(VPM150M_HPIRESET, &vpm->control)) { eframe[CMD_BYTE(x, 0, 1)] = 0x0b; } else { eframe[CMD_BYTE(x, 0, 1)] = leds; } } else { eframe[CMD_BYTE(x, 0, 1)] = 0x00 | leds; } eframe[CMD_BYTE(x, 1, 1)] = 0; eframe[CMD_BYTE(x, 2, 1)] = 0x00; } return; } if ((cmd = vpmadt032_get_ready_cmd(vpm))) { cmd->txident = wc->txident; #if 0 printk(KERN_DEBUG "Found command txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", cmd->txident, cmd->desc, cmd->address, cmd->data); #endif if (cmd->desc & __VPM150M_RWPAGE) { /* Set CTRL access to page*/ eframe[CMD_BYTE(0, 0, 1)] = (0x8 << 4); eframe[CMD_BYTE(0, 1, 1)] = 0; eframe[CMD_BYTE(0, 2, 1)] = 0x20; /* Do a page write */ if (cmd->desc & __VPM150M_WR) { eframe[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4) << 4); } else { eframe[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4); } eframe[CMD_BYTE(1, 1, 1)] = 0; if (cmd->desc & __VPM150M_WR) { eframe[CMD_BYTE(1, 2, 1)] = cmd->data & 0xf; } else { eframe[CMD_BYTE(1, 2, 1)] = 0; } if (cmd->desc & __VPM150M_WR) { /* Fill in buffer to size */ eframe[CMD_BYTE(2, 0, 1)] = 0; eframe[CMD_BYTE(2, 1, 1)] = 0; eframe[CMD_BYTE(2, 2, 1)] = 0; } else { /* Do reads twice b/c of vpmadt032 bug */ eframe[CMD_BYTE(2, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4); eframe[CMD_BYTE(2, 1, 1)] = 0; eframe[CMD_BYTE(2, 2, 1)] = 0; } /* Clear XADD */ eframe[CMD_BYTE(3, 0, 1)] = (0x8 << 4); eframe[CMD_BYTE(3, 1, 1)] = 0; eframe[CMD_BYTE(3, 2, 1)] = 0; /* Fill in buffer to size */ eframe[CMD_BYTE(4, 0, 1)] = 0; eframe[CMD_BYTE(4, 1, 1)] = 0; eframe[CMD_BYTE(4, 2, 1)] = 0; } else { /* Set address */ eframe[CMD_BYTE(0, 0, 1)] = ((0x8 | 0x4) << 4); eframe[CMD_BYTE(0, 1, 1)] = (cmd->address >> 8) & 0xff; eframe[CMD_BYTE(0, 2, 1)] = cmd->address & 0xff; /* Send/Get our data */ if (cmd->desc & __VPM150M_WR) { eframe[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1)) << 4); } else { eframe[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4); } eframe[CMD_BYTE(1, 1, 1)] = (cmd->data >> 8) & 0xff; eframe[CMD_BYTE(1, 2, 1)] = cmd->data & 0xff; if (cmd->desc & __VPM150M_WR) { /* Fill in */ eframe[CMD_BYTE(2, 0, 1)] = 0; eframe[CMD_BYTE(2, 1, 1)] = 0; eframe[CMD_BYTE(2, 2, 1)] = 0; } else { /* Do this again for reads b/c of the bug in vpmadt032 */ eframe[CMD_BYTE(2, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4); eframe[CMD_BYTE(2, 1, 1)] = (cmd->data >> 8) & 0xff; eframe[CMD_BYTE(2, 2, 1)] = cmd->data & 0xff; } /* Fill in the rest */ eframe[CMD_BYTE(3, 0, 1)] = 0; eframe[CMD_BYTE(3, 1, 1)] = 0; eframe[CMD_BYTE(3, 2, 1)] = 0; /* Fill in the rest */ eframe[CMD_BYTE(4, 0, 1)] = 0; eframe[CMD_BYTE(4, 1, 1)] = 0; eframe[CMD_BYTE(4, 2, 1)] = 0; } } else if (test_and_clear_bit(VPM150M_SWRESET, &vpm->control)) { for (x = 0; x < 7; x++) { if (0 == x) { eframe[CMD_BYTE(x, 0, 1)] = (0x8 << 4); } else { eframe[CMD_BYTE(x, 0, 1)] = 0x00; } eframe[CMD_BYTE(x, 1, 1)] = 0; if (0 == x) { eframe[CMD_BYTE(x, 2, 1)] = 0x01; } else { eframe[CMD_BYTE(x, 2, 1)] = 0x00; } } } else { for (x = 0; x < 7; x++) { eframe[CMD_BYTE(x, 0, 1)] = 0x00; eframe[CMD_BYTE(x, 1, 1)] = 0x00; eframe[CMD_BYTE(x, 2, 1)] = 0x00; } } /* Add our leds in */ for (x = 0; x < 7; x++) eframe[CMD_BYTE(x, 0, 1)] |= leds; } static inline int t1_setreg(struct t1 *wc, int addr, int val) { struct command *cmd; cmd = get_free_cmd(wc); if (!cmd) { WARN_ON(1); return -ENOMEM; } cmd->address = addr; cmd->data = val; cmd->flags |= __CMD_WR; submit_cmd(wc, cmd); return 0; } static int t1_getreg(struct t1 *wc, int addr) { struct command *cmd = NULL; unsigned long ret; unsigned long flags; might_sleep(); cmd = get_free_cmd(wc); if (!cmd) return -ENOMEM; cmd->address = addr; cmd->data = 0x00; cmd->flags = __CMD_RD; submit_cmd(wc, cmd); ret = wait_for_completion_interruptible_timeout(&cmd->complete, HZ*10); if (unlikely(!ret)) { spin_lock_irqsave(&wc->reglock, flags); if (!list_empty(&cmd->node)) { /* Since we've removed this command from the list, we * can go ahead and free it right away. */ list_del_init(&cmd->node); spin_unlock_irqrestore(&wc->reglock, flags); free_cmd(wc, cmd); if (-ERESTARTSYS != ret) { if (printk_ratelimit()) { dev_warn(&wc->vb.pdev->dev, "Timeout in %s\n", __func__); } ret = -EIO; } return ret; } else { /* Looks like this command was removed from the list by * someone else already. Let's wait for them to complete * it so that we don't free up the memory. */ spin_unlock_irqrestore(&wc->reglock, flags); ret = wait_for_completion_timeout(&cmd->complete, HZ*2); WARN_ON(!ret); ret = cmd->data; free_cmd(wc, cmd); return ret; } } ret = cmd->data; free_cmd(wc, cmd); return ret; } static void t1_setleds(struct t1 *wc, int leds) { struct command *cmd; leds = (~leds) & 0x0E; /* invert the LED bits (3 downto 1)*/ cmd = get_free_cmd(wc); if (!cmd) return; cmd->flags |= __CMD_LEDS; cmd->address = leds; submit_cmd(wc, cmd); } /** * t1_getpins - Returns the value of the jumpers on the card. * @wc: The card to read from. * @pins: Pointer to u8 character to hold the pins value. * * Returns 0 on success, otherwise an error code. * */ static int t1_getpins(struct t1 *wc, u8 *pins) { struct command *cmd; unsigned long flags; unsigned long ret; *pins = 0; cmd = get_free_cmd(wc); BUG_ON(!cmd); cmd->address = 0x00; cmd->data = 0x00; cmd->flags = __CMD_PINS; submit_cmd(wc, cmd); ret = wait_for_completion_interruptible_timeout(&cmd->complete, HZ*2); if (unlikely(!ret)) { spin_lock_irqsave(&wc->reglock, flags); list_del_init(&cmd->node); spin_unlock_irqrestore(&wc->reglock, flags); free_cmd(wc, cmd); if (-ERESTARTSYS != ret) { if (printk_ratelimit()) { dev_warn(&wc->vb.pdev->dev, "Timeout in %s\n", __func__); } ret = -EIO; } return ret; } *pins = cmd->data; free_cmd(wc, cmd); return 0; } static void __t1xxp_set_clear(struct t1 *wc) { int i, offset; int ret; unsigned short reg[3] = {0, 0, 0}; /* Calculate all states on all 24 channels using the channel flags, then write all 3 clear channel registers at once */ for (i = 0; i < 24; i++) { offset = i/8; if (wc->span.chans[i]->flags & DAHDI_FLAG_CLEAR) reg[offset] |= 1 << (7 - (i % 8)); else reg[offset] &= ~(1 << (7 - (i % 8))); } ret = t1_setreg(wc, CCB1, reg[0]); if (ret < 0) t1_info(wc, "Unable to set clear/rbs mode!\n"); ret = t1_setreg(wc, CCB2, reg[1]); if (ret < 0) t1_info(wc, "Unable to set clear/rbs mode!\n"); ret = t1_setreg(wc, CCB3, reg[2]); if (ret < 0) t1_info(wc, "Unable to set clear/rbs mode!\n"); } static void free_wc(struct t1 *wc) { unsigned int x; unsigned long flags; struct command *cmd; LIST_HEAD(list); for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { kfree(wc->chans[x]); kfree(wc->ec[x]); } spin_lock_irqsave(&wc->reglock, flags); list_splice_init(&wc->active_cmds, &list); list_splice_init(&wc->pending_cmds, &list); spin_unlock_irqrestore(&wc->reglock, flags); while (!list_empty(&list)) { cmd = list_entry(list.next, struct command, node); list_del_init(&cmd->node); free_cmd(wc, cmd); } if (wc->wq) destroy_workqueue(wc->wq); #ifdef CONFIG_VOICEBUS_ECREFERENCE for (x = 0; x < ARRAY_SIZE(wc->ec_reference); ++x) { if (wc->ec_reference[x]) dahdi_fifo_free(wc->ec_reference[x]); } #endif kfree(wc); } static void t4_serial_setup(struct t1 *wc) { t1_info(wc, "Setting up global serial parameters for %s\n", ((wc->spantype == TYPE_E1) ? "E1" : "T1")); t1_setreg(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */ t1_setreg(wc, 0x08, 0x05); /* IPC: Interrupt push/pull active low */ /* Global clocks (8.192 Mhz CLK) */ t1_setreg(wc, 0x92, 0x00); t1_setreg(wc, 0x93, 0x18); t1_setreg(wc, 0x94, 0xfb); t1_setreg(wc, 0x95, 0x0b); t1_setreg(wc, 0x96, 0x00); t1_setreg(wc, 0x97, 0x0b); t1_setreg(wc, 0x98, 0xdb); t1_setreg(wc, 0x99, 0xdf); /* Configure interrupts */ t1_setreg(wc, 0x46, 0xc0); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */ /* Configure system interface */ t1_setreg(wc, 0x3e, 0x0a /* 0x02 */); /* SIC1: 4.096 Mhz clock/bus, double buffer receive / transmit, byte interleaved */ t1_setreg(wc, 0x3f, 0x00); /* SIC2: No FFS, no center receive eliastic buffer, phase 0 */ t1_setreg(wc, 0x40, 0x04); /* SIC3: Edges for capture */ t1_setreg(wc, 0x44, 0x30); /* CMR1: RCLK is at 8.192 Mhz dejittered */ t1_setreg(wc, 0x45, 0x00); /* CMR2: We provide sync and clock for tx and rx. */ t1_setreg(wc, 0x22, 0x00); /* XC0: Normal operation of Sa-bits */ t1_setreg(wc, 0x23, 0x04); /* XC1: 0 offset */ t1_setreg(wc, 0x24, 0x00); /* RC0: Just shy of 255 */ t1_setreg(wc, 0x25, 0x05); /* RC1: The rest of RC0 */ /* Configure ports */ t1_setreg(wc, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */ t1_setreg(wc, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */ t1_setreg(wc, 0x82, 0x65); /* PC3: Some unused stuff */ t1_setreg(wc, 0x83, 0x35); /* PC4: Some more unused stuff */ t1_setreg(wc, 0x84, 0x31); /* PC5: XMFS active low, SCLKR is input, RCLK is output */ t1_setreg(wc, 0x86, 0x03); /* PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R */ t1_setreg(wc, 0x3b, 0x00); /* Clear LCR1 */ } static void t1_configure_t1(struct t1 *wc, int lineconfig, int txlevel) { unsigned int fmr4, fmr2, fmr1, fmr0, lim2; char *framing, *line; int mytxlevel; if ((txlevel > 7) || (txlevel < 4)) mytxlevel = 0; else mytxlevel = txlevel - 4; fmr1 = 0x9e; /* FMR1: Mode 0, T1 mode, CRC on for ESF, 2.048 Mhz system data rate, no XAIS */ fmr2 = 0x20; /* FMR2: no payload loopback, don't auto yellow alarm */ if (j1mode) fmr4 = 0x1c; else fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */ lim2 = 0x21; /* LIM2: 50% peak is a "1", Advanced Loss recovery */ lim2 |= (mytxlevel << 6); /* LIM2: Add line buildout */ t1_setreg(wc, 0x1d, fmr1); t1_setreg(wc, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; fmr0 = 0xa0; } else { line = "B8ZS"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_D4) { framing = "D4"; } else { framing = "ESF"; fmr4 |= 0x2; fmr2 |= 0xc0; } t1_setreg(wc, 0x1c, fmr0); t1_setreg(wc, 0x20, fmr4); t1_setreg(wc, 0x21, 0x40); /* FMR5: Enable RBS mode */ t1_setreg(wc, 0x37, 0xf8); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ t1_setreg(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ t1_setreg(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ t1_setreg(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ t1_setreg(wc, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */ t1_setreg(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ t1_setreg(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ if (j1mode) t1_setreg(wc, 0x24, 0x80); /* J1 overide */ /* Generate pulse mask for T1 */ switch (mytxlevel) { case 3: t1_setreg(wc, 0x26, 0x07); /* XPM0 */ t1_setreg(wc, 0x27, 0x01); /* XPM1 */ t1_setreg(wc, 0x28, 0x00); /* XPM2 */ break; case 2: t1_setreg(wc, 0x26, 0x8c); /* XPM0 */ t1_setreg(wc, 0x27, 0x11); /* XPM1 */ t1_setreg(wc, 0x28, 0x01); /* XPM2 */ break; case 1: t1_setreg(wc, 0x26, 0x8c); /* XPM0 */ t1_setreg(wc, 0x27, 0x01); /* XPM1 */ t1_setreg(wc, 0x28, 0x00); /* XPM2 */ break; case 0: default: t1_setreg(wc, 0x26, 0xd7); /* XPM0 */ t1_setreg(wc, 0x27, 0x22); /* XPM1 */ t1_setreg(wc, 0x28, 0x01); /* XPM2 */ break; } if (debug) t1_info(wc, "Span configured for %s/%s\n", framing, line); } static void t1_configure_e1(struct t1 *wc, int lineconfig) { unsigned int fmr2, fmr1, fmr0; unsigned int cas = 0; char *crc4 = ""; char *framing, *line; fmr1 = 0x46; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ fmr2 = 0x03; /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, no payload loopback */ if (lineconfig & DAHDI_CONFIG_CRC4) { fmr1 |= 0x08; /* CRC4 transmit */ fmr2 |= 0xc0; /* CRC4 receive */ crc4 = "/CRC4"; } t1_setreg(wc, 0x1d, fmr1); t1_setreg(wc, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; fmr0 = 0xa0; } else { line = "HDB3"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_CCS) { framing = "CCS"; } else { framing = "CAS"; cas = 0x40; } t1_setreg(wc, 0x1c, fmr0); t1_setreg(wc, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ t1_setreg(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ t1_setreg(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ t1_setreg(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ /* Condition receive line interface for E1 after reset */ t1_setreg(wc, 0xbb, 0x17); t1_setreg(wc, 0xbc, 0x55); t1_setreg(wc, 0xbb, 0x97); t1_setreg(wc, 0xbb, 0x11); t1_setreg(wc, 0xbc, 0xaa); t1_setreg(wc, 0xbb, 0x91); t1_setreg(wc, 0xbb, 0x12); t1_setreg(wc, 0xbc, 0x55); t1_setreg(wc, 0xbb, 0x92); t1_setreg(wc, 0xbb, 0x0c); t1_setreg(wc, 0xbb, 0x00); t1_setreg(wc, 0xbb, 0x8c); t1_setreg(wc, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */ t1_setreg(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ t1_setreg(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ t1_setreg(wc, 0x20, 0x9f); /* XSW: Spare bits all to 1 */ t1_setreg(wc, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */ /* Generate pulse mask for E1 */ t1_setreg(wc, 0x26, 0x54); /* XPM0 */ t1_setreg(wc, 0x27, 0x02); /* XPM1 */ t1_setreg(wc, 0x28, 0x00); /* XPM2 */ t1_info(wc, "Span configured for %s/%s%s\n", framing, line, crc4); } static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) { if (wc->spantype == TYPE_E1) { /* if this is an E1 card */ t1_configure_e1(wc, span->lineconfig); } else { /* is a T1 card */ t1_configure_t1(wc, span->lineconfig, span->txlevel); __t1xxp_set_clear(wc); } set_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags); } static void set_span_devicetype(struct t1 *wc) { strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1); #if defined(VPM_SUPPORT) if (wc->vpmadt032) strncat(wc->span.devicetype, " (VPMADT032)", sizeof(wc->span.devicetype) - 1); #endif } static int t1xxp_startup(struct file *file, struct dahdi_span *span) { struct t1 *wc = container_of(span, struct t1, span); #ifndef CONFIG_VOICEBUS_ECREFERENCE unsigned int i; #endif set_span_devicetype(wc); #ifndef CONFIG_VOICEBUS_ECREFERENCE /* initialize the start value for the entire chunk of last ec buffer */ for (i = 0; i < span->channels; i++) { memset(wc->ec_chunk1[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE); memset(wc->ec_chunk2[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE); } #endif /* Reset framer with proper parameters and start */ t1xxp_framer_start(wc, span); debug_printk(wc, 1, "Calling startup (flags is %lu)\n", span->flags); return 0; } static inline bool is_initialized(struct t1 *wc) { WARN_ON(wc->not_ready < 0); return (wc->not_ready == 0); } /** * t1_wait_for_ready * * Check if the board has finished any setup and is ready to start processing * calls. */ static int t1_wait_for_ready(struct t1 *wc) { while (!is_initialized(wc)) { if (fatal_signal_pending(current)) return -EIO; msleep_interruptible(250); } return 0; } static int t1xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { struct t1 *wc = chan->pvt; if (file->f_flags & O_NONBLOCK && !is_initialized(wc)) { return -EAGAIN; } else { t1_wait_for_ready(wc); } if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) && (wc->spantype != TYPE_E1)) { __t1xxp_set_clear(wc); } return 0; } static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) { u_char m,c; int n,b; struct t1 *wc = chan->pvt; unsigned long flags; debug_printk(wc, 2, "Setting bits to %d on channel %s\n", bits, chan->name); if (wc->spantype == TYPE_E1) { /* do it E1 way */ if (chan->chanpos == 16) return 0; n = chan->chanpos - 1; if (chan->chanpos > 15) n--; b = (n % 15); spin_lock_irqsave(&wc->reglock, flags); c = wc->txsigs[b]; m = (n / 15) << 2; /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ t1_setreg(wc, 0x71 + b, c); } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { n = chan->chanpos - 1; b = (n / 4); spin_lock_irqsave(&wc->reglock, flags); c = wc->txsigs[b]; m = ((3 - (n % 4)) << 1); /* nibble selector */ c &= ~(0x3 << m); /* keep the other nibble */ c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */ wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ t1_setreg(wc, 0x70 + b, c); t1_setreg(wc, 0x70 + b + 6, c); } else if (wc->span.lineconfig & DAHDI_CONFIG_ESF) { n = chan->chanpos - 1; b = (n / 2); spin_lock_irqsave(&wc->reglock, flags); c = wc->txsigs[b]; m = ((n % 2) << 2); /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ t1_setreg(wc, 0x70 + b, c); } debug_printk(wc, 2, "Finished setting RBS bits\n"); return 0; } static inline void t1_check_sigbits(struct t1 *wc) { int a,i,rxs; if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; if (wc->spantype == TYPE_E1) { for (i = 0; i < 15; i++) { a = t1_getreg(wc, 0x71 + i); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+16]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i+16], rxs); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i], rxs); } } } } } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { for (i = 0; i < 24; i+=4) { a = t1_getreg(wc, 0x70 + (i>>2)); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(wc->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+3]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i+3], rxs); } } rxs = (a & 0xc); if (!(wc->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+2]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i+2], rxs); } } rxs = (a >> 2) & 0xc; if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i+1], rxs); } } rxs = (a >> 4) & 0xc; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i], rxs); } } } } } else { for (i = 0; i < 24; i+=2) { a = t1_getreg(wc, 0x70 + (i>>1)); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i+1], rxs); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { dahdi_rbsbits(wc->span.chans[i], rxs); } } } } } } struct maint_work_struct { struct work_struct work; struct t1 *wc; int cmd; struct dahdi_span *span; }; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void t1xxp_maint_work(void *data) { struct maint_work_struct *w = data; #else static void t1xxp_maint_work(struct work_struct *work) { struct maint_work_struct *w = container_of(work, struct maint_work_struct, work); #endif struct t1 *wc = w->wc; struct dahdi_span *span = w->span; int reg = 0; int cmd = w->cmd; if (wc->spantype == TYPE_E1) { switch (cmd) { case DAHDI_MAINT_NONE: t1_info(wc, "Clearing all maint modes\n"); t1xxp_clear_maint(span); break; case DAHDI_MAINT_LOCALLOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM0); if (reg < 0) goto cleanup; t1_setreg(wc, LIM0, reg | LIM0_LL); break; case DAHDI_MAINT_REMOTELOOP: case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: t1_info(wc, "Only local loop supported in E1 mode\n"); goto cleanup; default: t1_info(wc, "Unknown E1 maint command: %d\n", cmd); goto cleanup; } } else { switch (cmd) { case DAHDI_MAINT_NONE: t1xxp_clear_maint(span); break; case DAHDI_MAINT_LOCALLOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM0); if (reg < 0) goto cleanup; t1_setreg(wc, LIM0, reg | LIM0_LL); break; case DAHDI_MAINT_NETWORKLINELOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM1); if (reg < 0) goto cleanup; t1_setreg(wc, LIM1, reg | LIM1_RL); break; case DAHDI_MAINT_NETWORKPAYLOADLOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM1); if (reg < 0) goto cleanup; t1_setreg(wc, LIM1, reg | (LIM1_RL | LIM1_JATT)); break; case DAHDI_MAINT_LOOPUP: t1xxp_clear_maint(span); t1_setreg(wc, 0x21, 0x50); break; case DAHDI_MAINT_LOOPDOWN: t1xxp_clear_maint(span); t1_setreg(wc, 0x21, 0x60); break; default: t1_info(wc, "Unknown T1 maint command: %d\n", cmd); return; } } cleanup: kfree(w); return; } static int t1xxp_maint(struct dahdi_span *span, int cmd) { struct maint_work_struct *work; struct t1 *wc = container_of(span, struct t1, span); if (wc->spantype == TYPE_E1) { switch (cmd) { case DAHDI_MAINT_NONE: case DAHDI_MAINT_LOCALLOOP: break; case DAHDI_MAINT_REMOTELOOP: case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: t1_info(wc, "Only local loop supported in E1 mode\n"); return -ENOSYS; default: t1_info(wc, "Unknown E1 maint command: %d\n", cmd); return -ENOSYS; } } else { switch (cmd) { case DAHDI_MAINT_NONE: case DAHDI_MAINT_LOCALLOOP: case DAHDI_MAINT_NETWORKLINELOOP: case DAHDI_MAINT_NETWORKPAYLOADLOOP: case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: break; default: t1_info(wc, "Unknown T1 maint command: %d\n", cmd); return -ENOSYS; } } work = kmalloc(sizeof(*work), GFP_ATOMIC); if (!work) { t1_info(wc, "Failed to allocate memory for workqueue\n"); return -ENOMEM; } work->span = span; work->wc = wc; work->cmd = cmd; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&work->work, t1xxp_maint_work, work); #else INIT_WORK(&work->work, t1xxp_maint_work); #endif queue_work(wc->wq, &work->work); return 0; } static int t1xxp_clear_maint(struct dahdi_span *span) { struct t1 *wc = container_of(span, struct t1, span); int reg = 0; /* Turn off local loop */ reg = t1_getreg(wc, LIM0); if (reg < 0) return -EIO; t1_setreg(wc, LIM0, reg & ~LIM0_LL); /* Turn off remote loop & jitter attenuator */ reg = t1_getreg(wc, LIM1); if (reg < 0) return -EIO; t1_setreg(wc, LIM1, reg & ~(LIM1_RL | LIM1_JATT)); /* Clear loopup/loopdown signals on the line */ t1_setreg(wc, 0x21, 0x40); return 0; } static int t1xxp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { struct t4_regs regs; unsigned int x; struct t1 *wc; switch (cmd) { case WCT4_GET_REGS: wc = chan->pvt; for (x = 0; x < sizeof(regs.regs) / sizeof(regs.regs[0]); x++) regs.regs[x] = t1_getreg(wc, x); if (copy_to_user((void __user *) data, ®s, sizeof(regs))) return -EFAULT; break; default: return -ENOTTY; } return 0; } static const char *t1xxp_echocan_name(const struct dahdi_chan *chan) { struct t1 *wc = chan->pvt; if (wc->vpmadt032) return vpmadt032_name; else if (wc->vpmoct) return vpmoct_name; return NULL; } static int t1xxp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct t1 *wc = chan->pvt; enum adt_companding comp; if (!vpmsupport || !test_bit(VPM150M_ACTIVE, &wc->ctlreg)) return -ENODEV; if (wc->vpmadt032) { *ec = wc->ec[chan->chanpos - 1]; (*ec)->ops = &vpm150m_ec_ops; (*ec)->features = vpm150m_ec_features; comp = (DAHDI_LAW_ALAW == chan->span->deflaw) ? ADT_COMP_ALAW : ADT_COMP_ULAW; return vpmadt032_echocan_create(wc->vpmadt032, chan->chanpos-1, comp, ecp, p); } else if (wc->vpmoct) { /* Hookup legacy callbacks */ *ec = wc->ec[chan->chanpos - 1]; (*ec)->ops = &vpm150m_ec_ops; (*ec)->features = vpm150m_ec_features; return vpmoct_echocan_create(wc->vpmoct, chan->chanpos-1, chan->span->deflaw); } else { return -ENODEV; } } static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct t1 *wc = chan->pvt; if (wc->vpmadt032) vpmadt032_echocan_free(wc->vpmadt032, chan->chanpos - 1, ec); else if (wc->vpmoct) vpmoct_echocan_free(wc->vpmoct, chan->chanpos - 1); } static void setchanconfig_from_state(struct vpmadt032 *vpm, int channel, GpakChannelConfig_t *chanconfig) { GpakEcanParms_t *p; BUG_ON(!vpm); chanconfig->PcmInPortA = 3; chanconfig->PcmInSlotA = (channel + 1) * 2; chanconfig->PcmOutPortA = SerialPortNull; chanconfig->PcmOutSlotA = (channel + 1) * 2; chanconfig->PcmInPortB = 2; chanconfig->PcmInSlotB = (channel + 1) * 2; chanconfig->PcmOutPortB = 3; chanconfig->PcmOutSlotB = (channel + 1) * 2; chanconfig->ToneTypesA = Null_tone; chanconfig->MuteToneA = Disabled; chanconfig->FaxCngDetA = Disabled; chanconfig->ToneTypesB = Null_tone; chanconfig->EcanEnableA = Enabled; chanconfig->EcanEnableB = Disabled; chanconfig->MuteToneB = Disabled; chanconfig->FaxCngDetB = Disabled; chanconfig->SoftwareCompand = cmpNone; chanconfig->FrameRate = rate10ms; p = &chanconfig->EcanParametersA; vpmadt032_get_default_parameters(p); p->EcanNlpType = vpm->curecstate[channel].nlp_type; p->EcanNlpThreshold = vpm->curecstate[channel].nlp_threshold; p->EcanNlpMaxSuppress = vpm->curecstate[channel].nlp_max_suppress; memcpy(&chanconfig->EcanParametersB, &chanconfig->EcanParametersA, sizeof(chanconfig->EcanParametersB)); } #ifdef VPM_SUPPORT struct vpm_load_work { struct work_struct work; struct t1 *wc; }; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void vpm_load_func(void *data) { struct maint_work_struct *w = data; #else static void vpm_load_func(struct work_struct *work) { struct vpm_load_work *w = container_of(work, struct vpm_load_work, work); #endif struct t1 *wc = w->wc; int res; res = vpmadt032_init(wc->vpmadt032); if (res) { /* There was some problem during initialization, but it passed * the address test, let's try again in a bit. */ wc->vpm_check = jiffies + HZ/2; return; } if (config_vpmadt032(wc->vpmadt032, wc)) { clear_bit(VPM150M_ACTIVE, &wc->ctlreg); wc->vpm_check = jiffies + HZ/2; return; } /* turn on vpm (RX audio from vpm module) */ set_bit(VPM150M_ACTIVE, &wc->ctlreg); wc->vpm_check = jiffies + HZ*5; if (vpmtsisupport) { debug_printk(wc, 1, "enabling VPM TSI pin\n"); /* turn on vpm timeslot interchange pin */ set_bit(0, &wc->ctlreg); } wc->not_ready--; kfree(w); } static int vpm_start_load(struct t1 *wc) { struct vpm_load_work *work; work = kzalloc(sizeof(*work), GFP_KERNEL); if (!work) return -ENOMEM; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&work->work, vpm_load_func, work); #else INIT_WORK(&work->work, vpm_load_func); #endif work->wc = wc; queue_work(wc->wq, &work->work); return 0; } static void t1_vpm_load_complete(struct device *dev, bool operational) { unsigned long flags; struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct t1 *wc = pci_get_drvdata(pdev); struct vpmoct *vpm = NULL; if (!wc || is_initialized(wc)) { WARN_ON(!wc); return; } spin_lock_irqsave(&wc->reglock, flags); wc->not_ready--; if (operational) { set_bit(VPM150M_ACTIVE, &wc->ctlreg); } else { clear_bit(VPM150M_ACTIVE, &wc->ctlreg); vpm = wc->vpmoct; wc->vpmoct = NULL; } spin_unlock_irqrestore(&wc->reglock, flags); if (vpm) vpmoct_free(vpm); } static void check_and_load_vpm(struct t1 *wc) { unsigned long flags; struct vpmadt032_options options; struct vpmadt032 *vpmadt = NULL; if (!vpmsupport) { t1_info(wc, "VPM Support Disabled via module parameter\n"); return; } memset(&options, 0, sizeof(options)); options.debug = debug; options.vpmnlptype = vpmnlptype; options.vpmnlpthresh = vpmnlpthresh; options.vpmnlpmaxsupp = vpmnlpmaxsupp; options.channels = (TYPE_T1 == wc->spantype) ? 24 : 32; /* We do not want to check that the VPM is alive until after we're * done setting it up here, an hour should cover it... */ wc->vpm_check = jiffies + HZ*3600; vpmadt = vpmadt032_alloc(&options); if (!vpmadt) return; vpmadt->setchanconfig_from_state = setchanconfig_from_state; spin_lock_irqsave(&wc->reglock, flags); wc->vpmadt032 = vpmadt; spin_unlock_irqrestore(&wc->reglock, flags); /* Probe for and attempt to load a vpmadt032 module */ if (vpmadt032_test(vpmadt, &wc->vb) || vpm_start_load(wc)) { /* There does not appear to be a VPMADT032 installed. */ clear_bit(VPM150M_ACTIVE, &wc->ctlreg); spin_lock_irqsave(&wc->reglock, flags); wc->vpmadt032 = NULL; spin_unlock_irqrestore(&wc->reglock, flags); vpmadt032_free(vpmadt); } /* Probe for and attempt to load a vpmoct032 module */ if (NULL == wc->vpmadt032) { struct vpmoct *vpmoct; /* Check for vpmoct */ vpmoct = vpmoct_alloc(); if (!vpmoct) return; vpmoct->dev = &wc->vb.pdev->dev; spin_lock_irqsave(&wc->reglock, flags); wc->vpmoct = vpmoct; wc->not_ready++; spin_unlock_irqrestore(&wc->reglock, flags); vpmoct_init(vpmoct, t1_vpm_load_complete); } } #else static inline void check_and_load_vpm(const struct t1 *wc) { return; } #endif static void t1_chan_set_sigcap(struct dahdi_span *span, int x) { struct t1 *wc = container_of(span, struct t1, span); struct dahdi_chan *chan = wc->chans[x]; chan->sigcap = DAHDI_SIG_CLEAR; /* E&M variant supported depends on span type */ if (wc->spantype == TYPE_E1) { /* E1 sigcap setup */ if (span->lineconfig & DAHDI_CONFIG_CCS) { /* CCS setup */ chan->sigcap |= DAHDI_SIG_MTP2 | DAHDI_SIG_SF; return; } /* clear out sig and sigcap for channel 16 on E1 CAS * lines, otherwise, set it correctly */ if (x == 15) { /* CAS signaling channel setup */ wc->chans[15]->sigcap = 0; wc->chans[15]->sig = 0; return; } /* normal CAS setup */ chan->sigcap |= DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_SF | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS; } else { /* T1 sigcap setup */ chan->sigcap |= DAHDI_SIG_EM | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_MTP2 | DAHDI_SIG_SF | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS; } } static int t1xxp_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct t1 *wc = container_of(span, struct t1, span); int i; if (file->f_flags & O_NONBLOCK) { if (!is_initialized(wc)) return -EAGAIN; } else { t1_wait_for_ready(wc); } /* Do we want to SYNC on receive or not */ if (lc->sync) { set_bit(7, &wc->ctlreg); span->syncsrc = span->spanno; } else { clear_bit(7, &wc->ctlreg); span->syncsrc = 0; } /* make sure that sigcaps gets updated if necessary */ for (i = 0; i < wc->span.channels; i++) t1_chan_set_sigcap(span, i); /* If already running, apply changes immediately */ if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags)) return t1xxp_startup(file, span); return 0; } static int t1xxp_enable_hw_preechocan(struct dahdi_chan *chan) { struct t1 *wc = chan->pvt; if (!wc->vpmoct) return 0; return vpmoct_preecho_enable(wc->vpmoct, chan->chanpos - 1); } static void t1xxp_disable_hw_preechocan(struct dahdi_chan *chan) { struct t1 *wc = chan->pvt; if (!wc->vpmoct) return; vpmoct_preecho_disable(wc->vpmoct, chan->chanpos - 1); } static const struct dahdi_span_ops t1_span_ops = { .owner = THIS_MODULE, .spanconfig = t1xxp_spanconfig, .chanconfig = t1xxp_chanconfig, .startup = t1xxp_startup, .rbsbits = t1xxp_rbsbits, .maint = t1xxp_maint, .ioctl = t1xxp_ioctl, #ifdef VPM_SUPPORT .enable_hw_preechocan = t1xxp_enable_hw_preechocan, .disable_hw_preechocan = t1xxp_disable_hw_preechocan, .echocan_create = t1xxp_echocan_create, .echocan_name = t1xxp_echocan_name, #endif }; static int t1_software_init(struct t1 *wc) { int x; int num; struct pci_dev *pdev = wc->vb.pdev; /* Find position */ for (x = 0; x < ARRAY_SIZE(ifaces); ++x) { if (ifaces[x] == wc) { debug_printk(wc, 1, "software init for card %d\n", x); break; } } if (x == ARRAY_SIZE(ifaces)) return -1; t4_serial_setup(wc); num = x; sprintf(wc->span.name, "WCT1/%d", num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num); wc->span.manufacturer = "Digium"; set_span_devicetype(wc); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI Bus %02d Slot %02d", pdev->bus->number, PCI_SLOT(pdev->devfn) + 1); wc->span.irq = pdev->irq; if (wc->spantype == TYPE_E1) { wc->span.channels = 31; wc->span.spantype = "E1"; wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; wc->span.deflaw = DAHDI_LAW_ALAW; } else { wc->span.channels = 24; wc->span.spantype = "T1"; wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; wc->span.deflaw = DAHDI_LAW_MULAW; } wc->span.chans = wc->chans; set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags); for (x = 0; x < wc->span.channels; x++) { sprintf(wc->chans[x]->name, "WCT1/%d/%d", num, x + 1); t1_chan_set_sigcap(&wc->span, x); wc->chans[x]->pvt = wc; wc->chans[x]->chanpos = x + 1; } check_and_load_vpm(wc); wc->span.ops = &t1_span_ops; if (dahdi_register(&wc->span, 0)) { t1_info(wc, "Unable to register span with DAHDI\n"); return -1; } return 0; } #if 0 #ifdef VPM_SUPPORT static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr) { return t1_getreg_full(wc, addr, unit); } static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val) { return t1_setreg(wc, addr, val, unit); } #endif #endif static int t1_hardware_post_init(struct t1 *wc) { int res; unsigned int reg; int x; /* T1 or E1 */ if (t1e1override > -1) { if (t1e1override) wc->spantype = TYPE_E1; else wc->spantype = TYPE_T1; } else { u8 pins; res = t1_getpins(wc, &pins); if (res) return res; wc->spantype = (pins & 0x01) ? TYPE_T1 : TYPE_E1; } debug_printk(wc, 1, "spantype: %s\n", 1 == wc->spantype ? "T1" : "E1"); /* what version of the FALC are we using? */ reg = t1_setreg(wc, 0x4a, 0xaa); reg = t1_getreg(wc, 0x4a); debug_printk(wc, 1, "FALC version: %08x\n", reg); /* make sure reads and writes work */ for (x = 0; x < 256; x++) { t1_setreg(wc, 0x14, x); reg = t1_getreg(wc, 0x14); if (reg != x) t1_info(wc, "Wrote '%x' but read '%x'\n", x, reg); } t1_setleds(wc, wc->ledstate); return 0; } static inline void t1_check_alarms(struct t1 *wc) { unsigned char c,d; int alarms; int x,j; unsigned char fmr4; /* must read this always */ if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; c = t1_getreg(wc, 0x4c); fmr4 = t1_getreg(wc, 0x20); /* must read this even if we don't use it */ d = t1_getreg(wc, 0x4d); /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); if (wc->spantype == TYPE_E1) { if (c & 0x04) { /* No multiframe found, force RAI high after 400ms only if we haven't found a multiframe since last loss of frame */ if (!wc->flags.nmf) { t1_setreg(wc, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ wc->flags.nmf = 1; t1_info(wc, "NMF workaround on!\n"); } t1_setreg(wc, 0x1e, 0xc3); /* Reset to CRC4 mode */ t1_setreg(wc, 0x1c, 0xf2); /* Force Resync */ t1_setreg(wc, 0x1c, 0xf0); /* Force Resync */ } else if (!(c & 0x02)) { if (wc->flags.nmf) { t1_setreg(wc, 0x20, 0x9f); /* LIM0: Clear forced RAI */ wc->flags.nmf = 0; t1_info(wc, "NMF workaround off!\n"); } } } else { /* Detect loopup code if we're not sending one */ if ((!wc->span.mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { t1_notice(wc, "Loopup detected,"\ " enabling remote loop\n"); t1_setreg(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ t1_setreg(wc, 0x37, 0xf6); /* LIM1: Enable remote loop */ wc->span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else wc->loopupcnt = 0; /* Same for loopdown code */ if ((!wc->span.mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { t1_notice(wc, "Loopdown detected,"\ " disabling remote loop\n"); t1_setreg(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ t1_setreg(wc, 0x37, 0xf0); /* LIM1: Disable remote loop */ wc->span.maintstat = DAHDI_MAINT_NONE; } } else wc->loopdowncnt = 0; } if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { for (x=0,j=0;x < wc->span.channels;x++) if ((wc->span.chans[x]->flags & DAHDI_FLAG_OPEN) || dahdi_have_netdev(wc->span.chans[x])) j++; if (!j) alarms |= DAHDI_ALARM_NOTOPEN; } if (c & 0x20) { /* LOF/LFA */ if (wc->alarmcount >= (alarmdebounce/100)) alarms |= DAHDI_ALARM_RED; else { if (unlikely(debug && !wc->alarmcount)) { /* starting to debounce LOF/LFA */ t1_info(wc, "LOF/LFA detected but " "debouncing for %d ms\n", alarmdebounce); } wc->alarmcount++; } } else wc->alarmcount = 0; if (c & 0x80) { /* LOS */ if (wc->losalarmcount >= (losalarmdebounce/100)) alarms |= DAHDI_ALARM_RED; else { if (unlikely(debug && !wc->losalarmcount)) { /* starting to debounce LOS */ t1_info(wc, "LOS detected but debouncing " "for %d ms\n", losalarmdebounce); } wc->losalarmcount++; } } else wc->losalarmcount = 0; if (c & 0x40) { /* AIS */ if (wc->aisalarmcount >= (aisalarmdebounce/100)) alarms |= DAHDI_ALARM_BLUE; else { if (unlikely(debug && !wc->aisalarmcount)) { /* starting to debounce AIS */ t1_info(wc, "AIS detected but debouncing " "for %d ms\n", aisalarmdebounce); } wc->aisalarmcount++; } } else wc->aisalarmcount = 0; /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) wc->alarmtimer = jiffies + 5*HZ; if (wc->alarmtimer) alarms |= DAHDI_ALARM_RECOVER; /* If receiving alarms, go into Yellow alarm state */ if (alarms && !wc->flags.sendingyellow) { t1_info(wc, "Setting yellow alarm\n"); /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ t1_setreg(wc, 0x20, fmr4 | 0x20); wc->flags.sendingyellow = 1; } else if (!alarms && wc->flags.sendingyellow) { t1_info(wc, "Clearing yellow alarm\n"); /* We manually do yellow alarm to handle RECOVER */ t1_setreg(wc, 0x20, fmr4 & ~0x20); wc->flags.sendingyellow = 0; } /* if ((c & 0x10)) alarms |= DAHDI_ALARM_YELLOW; */ if (c & 0x10) { /* receiving yellow (RAI) */ if (wc->yelalarmcount >= (yelalarmdebounce/100)) alarms |= DAHDI_ALARM_YELLOW; else { if (unlikely(debug && !wc->yelalarmcount)) { /* starting to debounce AIS */ t1_info(wc, "yelllow (RAI) detected but " "debouncing for %d ms\n", yelalarmdebounce); } wc->yelalarmcount++; } } else wc->yelalarmcount = 0; if (wc->span.mainttimer || wc->span.maintstat) alarms |= DAHDI_ALARM_LOOPBACK; wc->span.alarms = alarms; dahdi_alarm_notify(&wc->span); } static void handle_leds(struct t1 *wc) { unsigned char led; unsigned long flags; led = wc->ledstate; if ((wc->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) || wc->losalarmcount) { /* When we're in red alarm, blink the led once a second. */ if (time_after(jiffies, wc->blinktimer)) { led = (led & __LED_GREEN) ? SET_LED_RED(led) : UNSET_LED_REDGREEN(led); } } else if (wc->span.alarms & DAHDI_ALARM_YELLOW) { led = (led & __LED_RED) ? SET_LED_GREEN(led) : SET_LED_RED(led); } else { if (wc->span.maintstat != DAHDI_MAINT_NONE) led = SET_LED_ORANGE(led); else led = UNSET_LED_ORANGE(led); if (test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)) led = SET_LED_GREEN(led); else led = UNSET_LED_REDGREEN(led); } if (led != wc->ledstate) { struct command *cmd; cmd = get_free_cmd(wc); if (cmd) { wc->blinktimer = jiffies + HZ/2; cmd->flags |= __CMD_LEDS; cmd->address = ~led & 0x0E; submit_cmd(wc, cmd); spin_lock_irqsave(&wc->reglock, flags); wc->ledstate = led; spin_unlock_irqrestore(&wc->reglock, flags); } } } static void t1_do_counters(struct t1 *wc) { if (wc->alarmtimer && time_after(jiffies, wc->alarmtimer)) { wc->span.alarms &= ~(DAHDI_ALARM_RECOVER); wc->alarmtimer = 0; dahdi_alarm_notify(&wc->span); } } static void insert_tdm_data(const struct t1 *wc, u8 *sframe) { int i; register u8 *chanchunk; const int channels = wc->span.channels; for (i = 0; i < channels; ++i) { chanchunk = &wc->chans[i]->writechunk[0]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*3] = chanchunk[3]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*4] = chanchunk[4]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*5] = chanchunk[5]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6]; sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7]; } } static inline void t1_transmitprep(struct t1 *wc, u8 *sframe) { int x; int y; u8 *eframe = sframe; /* Calculate Transmission */ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) _dahdi_transmit(&wc->span); #ifdef CONFIG_VOICEBUS_ECREFERENCE for (chan = 0; chan < wc->span.channels; chan++) { __dahdi_fifo_put(wc->ec_reference[chan], wc->chans[chan]->writechunk, DAHDI_CHUNKSIZE); } #endif if (likely(test_bit(INITIALIZED, &wc->bit_flags))) insert_tdm_data(wc, sframe); spin_lock(&wc->reglock); for (x = 0; x < DAHDI_CHUNKSIZE; x++) { /* process the command queue */ for (y = 0; y < 7; y++) cmd_dequeue(wc, eframe, x, y); #ifdef VPM_SUPPORT if (wc->vpmadt032) { cmd_dequeue_vpmadt032(wc, eframe); } else if (wc->vpmoct) { cmd_dequeue_vpmoct(wc, eframe); } #endif if (x < DAHDI_CHUNKSIZE - 1) { eframe[EFRAME_SIZE] = wc->ctlreg; eframe[EFRAME_SIZE + 1] = wc->txident++; } eframe += (EFRAME_SIZE + EFRAME_GAP); } spin_unlock(&wc->reglock); } /** * is_good_frame() - Whether the SFRAME received was one sent. * */ static inline bool is_good_frame(const u8 *sframe) { const u8 a = sframe[0*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; const u8 b = sframe[1*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; return a != b; } /** * extract_tdm_data() - Move TDM data from sframe to channels. * */ static void extract_tdm_data(struct t1 *wc, const u8 *const sframe) { int i; register u8 *chanchunk; const int channels = wc->span.channels; for (i = 0; i < channels; ++i) { chanchunk = &wc->chans[i]->readchunk[0]; chanchunk[0] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[(i+1)*2 + (EFRAME_SIZE + EFRAME_GAP)*7]; } /* Pre-echo with the vpmoct overwrites the 24th timeslot with the * specified channel's pre-echo audio stream. This timeslot is unused * by the te12xp */ if (wc->vpmoct && wc->vpmoct->preecho_enabled) { chanchunk = &wc->vpmoct->preecho_buf[0]; chanchunk[0] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*7]; } } static inline void t1_receiveprep(struct t1 *wc, const u8* sframe) { int x; unsigned char expected; const u8 *eframe = sframe; if (!is_good_frame(sframe)) return; if (likely(test_bit(INITIALIZED, &wc->bit_flags))) extract_tdm_data(wc, sframe); spin_lock(&wc->reglock); for (x = 0; x < DAHDI_CHUNKSIZE; x++) { if (x < DAHDI_CHUNKSIZE - 1) { expected = wc->rxident+1; wc->rxident = eframe[EFRAME_SIZE + 1]; wc->statreg = eframe[EFRAME_SIZE + 2]; if (wc->rxident != expected) { wc->span.irqmisses++; _resend_cmds(wc); if (unlikely(debug)) { t1_info(wc, "oops: rxident=%d " "expected=%d x=%d\n", wc->rxident, expected, x); } } } cmd_decipher(wc, eframe); #ifdef VPM_SUPPORT if (wc->vpmadt032) cmd_decipher_vpmadt032(wc, eframe); else if (wc->vpmoct) cmd_decipher_vpmoct(wc, eframe); #endif eframe += (EFRAME_SIZE + EFRAME_GAP); } spin_unlock(&wc->reglock); /* echo cancel */ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) { for (x = 0; x < wc->span.channels; x++) { struct dahdi_chan *const c = wc->chans[x]; #ifdef CONFIG_VOICEBUS_ECREFERENCE unsigned char buffer[DAHDI_CHUNKSIZE]; __dahdi_fifo_get(wc->ec_reference[x], buffer, ARRAY_SIZE(buffer)); _dahdi_ec_chunk(c, c->readchunk, buffer); #else if ((wc->vpmoct) && (c->chanpos-1 == wc->vpmoct->preecho_timeslot) && (wc->vpmoct->preecho_enabled)) { __dahdi_ec_chunk(c, c->readchunk, wc->vpmoct->preecho_buf, c->writechunk); } else { _dahdi_ec_chunk(c, c->readchunk, wc->ec_chunk2[x]); memcpy(wc->ec_chunk2[x], wc->ec_chunk1[x], DAHDI_CHUNKSIZE); memcpy(wc->ec_chunk1[x], c->writechunk, DAHDI_CHUNKSIZE); } } #endif _dahdi_receive(&wc->span); } } static void t1_handle_transmit(struct voicebus *vb, struct list_head *buffers) { struct t1 *wc = container_of(vb, struct t1, vb); struct vbb *vbb; list_for_each_entry(vbb, buffers, entry) { memset(vbb->data, 0, sizeof(vbb->data)); atomic_inc(&wc->txints); t1_transmitprep(wc, vbb->data); handle_leds(wc); } } static void t1_handle_receive(struct voicebus *vb, struct list_head *buffers) { struct t1 *wc = container_of(vb, struct t1, vb); struct vbb *vbb; list_for_each_entry(vbb, buffers, entry) t1_receiveprep(wc, vbb->data); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void timer_work_func(void *param) { struct t1 *wc = param; #else static void timer_work_func(struct work_struct *work) { struct t1 *wc = container_of(work, struct t1, timer_work); #endif t1_do_counters(wc); t1_check_alarms(wc); t1_check_sigbits(wc); if (test_bit(INITIALIZED, &wc->bit_flags)) mod_timer(&wc->timer, jiffies + HZ/10); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void vpm_check_func(void *data) { struct t1 *wc = data; #else static void vpm_check_func(struct work_struct *work) { struct t1 *wc = container_of(work, struct t1, vpm_check_work); #endif int res; u16 version; const int MAX_CHECKS = 5; /* If there is a failed VPM module, do not block dahdi_cfg * indefinitely. */ if (++wc->vpm_check_count > MAX_CHECKS) { wc->not_ready--; wc->vpm_check = MAX_JIFFY_OFFSET; t1_info(wc, "Disabling VPMADT032 Checking.\n"); return; } if (!test_bit(INITIALIZED, &wc->bit_flags)) return; if (test_bit(VPM150M_ACTIVE, &wc->ctlreg)) { res = gpakPingDsp(wc->vpmadt032->dspid, &version); if (!res) { set_bit(VPM150M_ACTIVE, &wc->ctlreg); wc->vpm_check = jiffies + HZ*5; wc->vpm_check_count = 0; return; } clear_bit(VPM150M_ACTIVE, &wc->ctlreg); t1_info(wc, "VPMADT032 is non-responsive. Resetting.\n"); } if (!test_bit(INITIALIZED, &wc->bit_flags)) return; res = vpmadt032_reset(wc->vpmadt032); if (res) { t1_info(wc, "Failed VPMADT032 reset. VPMADT032 is disabled.\n"); wc->vpm_check = jiffies + HZ*5; return; } if (!test_bit(INITIALIZED, &wc->bit_flags)) return; res = config_vpmadt032(wc->vpmadt032, wc); if (res) { /* We failed the configuration, let's try again. */ t1_info(wc, "Failed to configure the ports. Retrying.\n"); if (!test_bit(INITIALIZED, &wc->bit_flags)) return; queue_work(wc->vpmadt032->wq, &wc->vpm_check_work); return; } if (!test_bit(INITIALIZED, &wc->bit_flags)) return; /* Looks like the reset went ok so we can put the VPM module back in * the TDM path. */ set_bit(VPM150M_ACTIVE, &wc->ctlreg); t1_info(wc, "VPMADT032 is reenabled.\n"); wc->vpm_check = jiffies + HZ*5; wc->not_ready--; return; } static void te12xp_timer(unsigned long data) { unsigned long flags; struct t1 *wc = (struct t1 *)data; if (unlikely(!test_bit(INITIALIZED, &wc->bit_flags))) return; queue_work(wc->wq, &wc->timer_work); spin_lock_irqsave(&wc->reglock, flags); if (!wc->vpmadt032) goto unlock_exit; if (time_after(wc->vpm_check, jiffies)) goto unlock_exit; queue_work(wc->vpmadt032->wq, &wc->vpm_check_work); unlock_exit: spin_unlock_irqrestore(&wc->reglock, flags); return; } static void t1_handle_error(struct voicebus *vb) { unsigned long flags; struct t1 *wc = container_of(vb, struct t1, vb); spin_lock_irqsave(&wc->reglock, flags); if (!wc->vpmadt032) goto unlock_exit; clear_bit(VPM150M_ACTIVE, &wc->ctlreg); queue_work(wc->vpmadt032->wq, &wc->vpm_check_work); unlock_exit: spin_unlock_irqrestore(&wc->reglock, flags); } static const struct voicebus_operations voicebus_operations = { .handle_receive = t1_handle_receive, .handle_transmit = t1_handle_transmit, .handle_error = t1_handle_error, }; #ifdef CONFIG_VOICEBUS_SYSFS static ssize_t voicebus_current_latency_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long flags; struct t1 *wc = dev_get_drvdata(dev); unsigned int current_latency; spin_lock_irqsave(&wc->vb.lock, flags); current_latency = wc->vb.min_tx_buffer_count; spin_unlock_irqrestore(&wc->vb.lock, flags); return sprintf(buf, "%d\n", current_latency); } static DEVICE_ATTR(voicebus_current_latency, 0400, voicebus_current_latency_show, NULL); static ssize_t vpm_firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) { int res; u16 version = 0; struct t1 *wc = dev_get_drvdata(dev); if (wc->vpmadt032) { res = gpakPingDsp(wc->vpmadt032->dspid, &version); if (res) { t1_info(wc, "Failed gpakPingDsp %d\n", res); version = -1; } } return sprintf(buf, "%x.%02x\n", (version & 0xff00) >> 8, (version & 0xff)); } static DEVICE_ATTR(vpm_firmware_version, 0400, vpm_firmware_version_show, NULL); static void create_sysfs_files(struct t1 *wc) { int ret; ret = device_create_file(&wc->vb.pdev->dev, &dev_attr_voicebus_current_latency); if (ret) { dev_info(&wc->vb.pdev->dev, "Failed to create device attributes.\n"); } ret = device_create_file(&wc->vb.pdev->dev, &dev_attr_vpm_firmware_version); if (ret) { dev_info(&wc->vb.pdev->dev, "Failed to create device attributes.\n"); } } static void remove_sysfs_files(struct t1 *wc) { device_remove_file(&wc->vb.pdev->dev, &dev_attr_vpm_firmware_version); device_remove_file(&wc->vb.pdev->dev, &dev_attr_voicebus_current_latency); } #else static inline void create_sysfs_files(struct t1 *wc) { return; } static inline void remove_sysfs_files(struct t1 *wc) { return; } #endif /* CONFIG_VOICEBUS_SYSFS */ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct t1 *wc; struct t1_desc *d = (struct t1_desc *) ent->driver_data; unsigned int x; int res; unsigned int index = -1; for (x = 0; x < ARRAY_SIZE(ifaces); x++) { if (!ifaces[x]) { index = x; break; } } if (-1 == index) { printk(KERN_INFO "%s: Too many interfaces\n", THIS_MODULE->name); return -EIO; } wc = kzalloc(sizeof(*wc), GFP_KERNEL); if (!wc) return -ENOMEM; wc->not_ready = 1; ifaces[index] = wc; wc->ledstate = -1; spin_lock_init(&wc->reglock); INIT_LIST_HEAD(&wc->active_cmds); INIT_LIST_HEAD(&wc->pending_cmds); wc->variety = d->name; wc->txident = 1; # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) wc->timer.function = te12xp_timer; wc->timer.data = (unsigned long)wc; init_timer(&wc->timer); # else setup_timer(&wc->timer, te12xp_timer, (unsigned long)wc); # endif # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&wc->timer_work, timer_work_func, wc); # else INIT_WORK(&wc->timer_work, timer_work_func); # endif # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&wc->vpm_check_work, vpm_check_func, wc); # else INIT_WORK(&wc->vpm_check_work, vpm_check_func); # endif #ifdef CONFIG_VOICEBUS_ECREFERENCE for (x = 0; x < ARRAY_SIZE(wc->ec_reference); ++x) { /* 256 is used here since it is the largest power of two that * will contain 8 * VOICBUS_DEFAULT_LATENCY */ wc->ec_reference[x] = dahdi_fifo_alloc(256, GFP_KERNEL); if (IS_ERR(wc->ec_reference[x])) { res = PTR_ERR(wc->ec_reference[x]); wc->ec_reference[x] = NULL; free_wc(wc); return res; } } #endif /* CONFIG_VOICEBUS_ECREFERENCE */ snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", index); pci_set_drvdata(pdev, wc); wc->vb.ops = &voicebus_operations; wc->vb.pdev = pdev; wc->vb.debug = &debug; res = voicebus_init(&wc->vb, wc->name); if (res) { free_wc(wc); ifaces[index] = NULL; return res; } wc->wq = create_singlethread_workqueue(wc->name); if (!wc->wq) { kfree(wc); return -ENOMEM; } voicebus_set_minlatency(&wc->vb, latency); voicebus_set_maxlatency(&wc->vb, max_latency); max_latency = wc->vb.max_latency; create_sysfs_files(wc); voicebus_lock_latency(&wc->vb); if (voicebus_start(&wc->vb)) { voicebus_release(&wc->vb); free_wc(wc); return -EIO; } res = t1_hardware_post_init(wc); if (res) { voicebus_release(&wc->vb); free_wc(wc); return res; } for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { wc->chans[x] = kzalloc(sizeof(*wc->chans[x]), GFP_KERNEL); if (!wc->chans[x]) { free_wc(wc); ifaces[index] = NULL; return -ENOMEM; } wc->ec[x] = kzalloc(sizeof(*wc->ec[x]), GFP_KERNEL); if (!wc->ec[x]) { free_wc(wc); ifaces[index] = NULL; return -ENOMEM; } } res = t1_software_init(wc); if (res) { voicebus_release(&wc->vb); free_wc(wc); return res; } set_bit(INITIALIZED, &wc->bit_flags); mod_timer(&wc->timer, jiffies + HZ/5); t1_info(wc, "Found a %s\n", wc->variety); voicebus_unlock_latency(&wc->vb); /* If there is VPMADT032 module attached to this device, it will * signal ready after the channels are configured and ready for use. */ if (!wc->vpmadt032) wc->not_ready--; return 0; } static void __devexit te12xp_remove_one(struct pci_dev *pdev) { struct t1 *wc = pci_get_drvdata(pdev); #ifdef VPM_SUPPORT unsigned long flags; struct vpmadt032 *vpmadt = wc->vpmadt032; struct vpmoct *vpmoct = wc->vpmoct; #endif if (!wc) return; dahdi_unregister(&wc->span); remove_sysfs_files(wc); clear_bit(INITIALIZED, &wc->bit_flags); smp_mb__after_clear_bit(); del_timer_sync(&wc->timer); flush_workqueue(wc->wq); #ifdef VPM_SUPPORT if (vpmadt) { clear_bit(VPM150M_ACTIVE, &vpmadt->control); flush_workqueue(vpmadt->wq); } else if (vpmoct) { while (t1_wait_for_ready(wc)) schedule(); } #endif del_timer_sync(&wc->timer); voicebus_release(&wc->vb); #ifdef VPM_SUPPORT if (vpmadt) { spin_lock_irqsave(&wc->reglock, flags); wc->vpmadt032 = NULL; spin_unlock_irqrestore(&wc->reglock, flags); vpmadt032_free(vpmadt); } else if (vpmoct) { spin_lock_irqsave(&wc->reglock, flags); wc->vpmoct = NULL; spin_unlock_irqrestore(&wc->reglock, flags); vpmoct_free(vpmoct); } #endif t1_info(wc, "Freed a Wildcard TE12xP.\n"); free_wc(wc); } static DEFINE_PCI_DEVICE_TABLE(te12xp_pci_tbl) = { { 0xd161, 0x0120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te120p}, { 0xd161, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te121}, { 0xd161, 0x8001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te122}, { 0 } }; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) static void te12xp_shutdown(struct pci_dev *pdev) { struct t1 *wc = pci_get_drvdata(pdev); voicebus_quiesce(&wc->vb); } #endif static int te12xp_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } MODULE_DEVICE_TABLE(pci, te12xp_pci_tbl); static struct pci_driver te12xp_driver = { .name = "wcte12xp", .probe = te12xp_init_one, .remove = __devexit_p(te12xp_remove_one), #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) .shutdown = te12xp_shutdown, #endif .suspend = te12xp_suspend, .id_table = te12xp_pci_tbl, }; static int __init te12xp_init(void) { int res; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0, #if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)) SLAB_HWCACHE_ALIGN | SLAB_STORE_USER, NULL, NULL); #else SLAB_HWCACHE_ALIGN, NULL, NULL); #endif #else cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0, SLAB_HWCACHE_ALIGN, NULL); #endif if (!cmd_cache) return -ENOMEM; res = dahdi_pci_module(&te12xp_driver); if (res) { kmem_cache_destroy(cmd_cache); return -ENODEV; } return 0; } static void __exit te12xp_cleanup(void) { pci_unregister_driver(&te12xp_driver); kmem_cache_destroy(cmd_cache); } module_param(debug, int, S_IRUGO | S_IWUSR); module_param(t1e1override, int, S_IRUGO | S_IWUSR); module_param(j1mode, int, S_IRUGO | S_IWUSR); module_param(alarmdebounce, int, S_IRUGO | S_IWUSR); module_param(losalarmdebounce, int, S_IRUGO | S_IWUSR); module_param(aisalarmdebounce, int, S_IRUGO | S_IWUSR); module_param(yelalarmdebounce, int, S_IRUGO | S_IWUSR); module_param(latency, int, S_IRUGO); module_param(max_latency, int, S_IRUGO); #ifdef VPM_SUPPORT module_param(vpmsupport, int, S_IRUGO); module_param(vpmtsisupport, int, S_IRUGO); module_param(vpmnlptype, int, S_IRUGO); module_param(vpmnlpthresh, int, S_IRUGO); module_param(vpmnlpmaxsupp, int, S_IRUGO); #endif MODULE_DESCRIPTION("Wildcard VoiceBus Digital Card Driver"); MODULE_AUTHOR("Digium Incorporated "); MODULE_LICENSE("GPL v2"); module_init(te12xp_init); module_exit(te12xp_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/wcte12xp/wcte12xp.h0000644000175000017500000001021711602452654022047 0ustar tzafrirtzafrir/* * Digium, Inc. Wildcard TE12xP T1/E1 card Driver * * Written by Michael Spiceland * * Adapted from the wctdm24xxp and wcte11xp drivers originally * written by Mark Spencer * Matthew Fredrickson * William Meadows * * Copyright (C) 2007-2010, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _WCTE12XP_H #define _WCTE12XP_H /* Comment to disable VPM support */ #define VPM_SUPPORT 1 #define WC_MAX_IFACES 8 #ifdef VPM_SUPPORT #define MAX_TDM_CHAN 31 #endif #define SDI_CLK (0x00010000) #define SDI_DOUT (0x00020000) #define SDI_DREAD (0x00040000) #define SDI_DIN (0x00080000) #define EFRAME_SIZE 108 #define ERING_SIZE 16 /* Maximum ring size */ #define EFRAME_GAP 20 #define SFRAME_SIZE ((EFRAME_SIZE * DAHDI_CHUNKSIZE) + (EFRAME_GAP * (DAHDI_CHUNKSIZE - 1))) #define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4)) #define MAX_COMMANDS 16 #define NUM_EC 4 #define __CMD_PINS (1 << 18) /* CPLD pin read */ #define __CMD_LEDS (1 << 19) /* LED Operation */ #define __CMD_RD (1 << 20) /* Read Operation */ #define __CMD_WR (1 << 21) /* Write Operation */ #define __LED_ORANGE (1<<3) #define __LED_GREEN (1<<2) #define __LED_RED (1<<1) #define SET_LED_ORANGE(a) (a | __LED_ORANGE) #define SET_LED_RED(a) ((a | __LED_RED) & ~__LED_GREEN) #define SET_LED_GREEN(a) ((a | __LED_GREEN) & ~__LED_RED) #define UNSET_LED_ORANGE(a) (a & ~__LED_ORANGE) #define UNSET_LED_REDGREEN(a) (a | __LED_RED | __LED_GREEN) #define CMD_BYTE(slot, a, is_vpm) (slot*6)+(a*2)+is_vpm /* only even slots */ //TODO: make a separate macro #define TYPE_T1 1 #define TYPE_E1 2 struct command { struct list_head node; struct completion complete; u8 data; u8 ident; u8 cs_slot; u16 address; u32 flags; }; struct vpm150m; struct t1 { spinlock_t reglock; unsigned char txident; unsigned char rxident; unsigned char statreg; /* bit 0 = vpmadt032 int */ int spantype; struct { unsigned int nmf:1; unsigned int sendingyellow:1; } flags; unsigned char txsigs[16]; /* Copy of tx sig registers */ int alarmcount; /* How much red alarm we've seen */ int losalarmcount; int aisalarmcount; int yelalarmcount; const char *variety; char name[80]; unsigned long blinktimer; int loopupcnt; int loopdowncnt; #define INITIALIZED 1 #define SHUTDOWN 2 #define READY 3 unsigned long bit_flags; unsigned long alarmtimer; unsigned char ledstate; unsigned char vpm_check_count; struct dahdi_span span; /* Span */ struct dahdi_chan *chans[32]; /* Channels */ struct dahdi_echocan_state *ec[32]; /* Echocan state for channels */ #ifdef CONFIG_VOICEBUS_ECREFERENCE struct dahdi_fifo *ec_reference[32]; #else unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE]; unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE]; #endif unsigned long ctlreg; struct voicebus vb; atomic_t txints; struct vpmadt032 *vpmadt032; struct vpmoct *vpmoct; unsigned long vpm_check; struct work_struct vpm_check_work; /* protected by t1.reglock */ struct list_head pending_cmds; struct list_head active_cmds; struct timer_list timer; struct work_struct timer_work; struct workqueue_struct *wq; unsigned int not_ready; /* 0 when entire card is ready to go */ }; #define t1_info(t1, format, arg...) \ dev_info(&t1->vb.pdev->dev , format , ## arg) #define t1_notice(t1, format, arg...) \ dev_notice(&t1->vb.pdev->dev , format , ## arg) /* Maintenance Mode Registers */ #define LIM0 0x36 #define LIM0_LL (1<<1) #define LIM1 0x37 #define LIM1_RL (1<<1) #define LIM1_JATT (1<<2) /* Clear Channel Registers */ #define CCB1 0x2f #define CCB2 0x30 #define CCB3 0x31 #endif dahdi-linux-2.5.0.1/drivers/dahdi/wcte12xp/Makefile0000644000175000017500000000026011026016414021644 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild endif dahdi-linux-2.5.0.1/drivers/dahdi/wcte12xp/Kbuild0000644000175000017500000000017611176111367021360 0ustar tzafrirtzafrirobj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp.o EXTRA_CFLAGS += -I$(src)/.. -Wno-undef wcte12xp-objs := base.o dahdi-linux-2.5.0.1/drivers/dahdi/wcb4xxp/0000755000175000017500000000000011631523355020141 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/wcb4xxp/base.c0000644000175000017500000025446211612334667021241 0ustar tzafrirtzafrir/* * WCB410P Quad-BRI PCI Driver * Written by Andrew Kohlsmith * * Copyright (C) 2009-2011 Digium, Inc. * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include /* printk() */ #include /* error codes */ #include #include /* size_t */ #include /* O_ACCMODE */ #include #include #include /* for PCI structures */ #include #include #include #include /* dev_err() */ #include #include /* cli(), *_flags */ #include /* copy_*_user */ #include /* work_struct */ #include /* timer_struct */ #include #include #include #include "wcb4xxp.h" #ifndef BIT /* added in 2.6.24 */ #define BIT(i) (1UL << (i)) #endif #define BIT_SET(x, i) ((x) |= BIT(i)) #define BIT_CLR(x, i) ((x) &= ~BIT(i)) #define IS_SET(x, i) (((x) & BIT(i)) != 0) #define BITMASK(i) (((u64)1 << (i)) - 1) #if (DAHDI_CHUNKSIZE != 8) #error Sorry, wcb4xxp does not support chunksize != 8 #endif //#define SIMPLE_BCHAN_FIFO //#define DEBUG_LOWLEVEL_REGS /* debug __pci_in/out, not b4xxp_setreg */ #define DEBUG_GENERAL (1 << 0) /* general debug messages */ #define DEBUG_DTMF (1 << 1) /* emit DTMF detector messages */ #define DEBUG_REGS (1 << 2) /* emit register read/write, but only if the kernel's DEBUG is defined */ #define DEBUG_FOPS (1 << 3) /* emit file operation messages */ #define DEBUG_ECHOCAN (1 << 4) #define DEBUG_ST_STATE (1 << 5) /* S/T state machine */ #define DEBUG_HDLC (1 << 6) /* HDLC controller */ #define DEBUG_ALARM (1 << 7) /* alarm changes */ #define DBG (debug & DEBUG_GENERAL) #define DBG_DTMF (debug & DEBUG_DTMF) #define DBG_REGS (debug & DEBUG_REGS) #define DBG_FOPS (debug & DEBUG_FOPS) #define DBG_EC (debug & DEBUG_ECHOCAN) #define DBG_ST (debug & DEBUG_ST_STATE) #define DBG_HDLC (debug & DEBUG_HDLC) #define DBG_ALARM (debug & DEBUG_ALARM) #define DBG_SPANFILTER (BIT(bspan->port) & spanfilter) static int debug = 0; static int spanfilter = 0xFF; /* Bitmap for ports 1-8 */ #ifdef LOOPBACK_SUPPORTED static int loopback = 0; #endif static int milliwatt = 0; static int pedanticpci = 0; static int teignorered = 0; static int alarmdebounce = 500; static int vpmsupport = 1; static int timer_1_ms = 2000; static int timer_3_ms = 30000; static char *companding = "alaw"; #if !defined(mmiowb) #define mmiowb() barrier() #endif #define MAX_B4_CARDS 64 static struct b4xxp *cards[MAX_B4_CARDS]; static int led_fader_table[] = { 0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, }; // #define CREATE_WCB4XXP_PROCFS_ENTRY #ifdef CREATE_WCB4XXP_PROCFS_ENTRY #define PROCFS_NAME "wcb4xxp" static struct proc_dir_entry *myproc; #endif /* Expansion; right now there's just one card and all of its idiosyncrasies. */ #define FLAG_yyy (1 << 0) #define FLAG_zzz (1 << 1) struct devtype { char *desc; unsigned int flags; int ports; /* Number of ports the card has */ enum cards_ids card_type; /* Card type - Digium B410P, ... */ }; static struct devtype wcb4xxp = {"Wildcard B410P", .ports = 4, .card_type = B410P }; static struct devtype hfc2s = {"HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .card_type = DUOBRI }; static struct devtype hfc4s = {"HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .card_type = QUADBRI }; static struct devtype hfc8s = {"HFC-8S Junghanns.NET octoBRI PCI", .ports = 8, .card_type = OCTOBRI }; static struct devtype hfc2s_OV = {"OpenVox B200P", .ports = 2, .card_type = B200P_OV }; static struct devtype hfc4s_OV = {"OpenVox B400P", .ports = 4, .card_type = B400P_OV }; static struct devtype hfc8s_OV = {"OpenVox B800P", .ports = 8, .card_type = B800P_OV }; static struct devtype hfc2s_BN = {"BeroNet BN2S0", .ports = 2, .card_type = BN2S0 }; static struct devtype hfc4s_BN = {"BeroNet BN4S0", .ports = 4, .card_type = BN4S0 }; static struct devtype hfc8s_BN = {"BeroNet BN8S0", .ports = 8, .card_type = BN8S0 }; static struct devtype hfc4s_SW = {"Swyx 4xS0 SX2 QuadBri", .ports = 4, .card_type = BSWYX_SX2 }; static struct devtype hfc4s_EV = {"CCD HFC-4S Eval. Board", .ports = 4, .card_type = QUADBRI_EVAL }; #define CARD_HAS_EC(card) ((card)->card_type == B410P) static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static const struct dahdi_echocan_features my_ec_features = { .NLP_automatic = 1, .CED_tx_detect = 1, .CED_rx_detect = 1, }; static const struct dahdi_echocan_ops my_ec_ops = { .echocan_free = echocan_free, }; #if 0 static const char *wcb4xxp_rcsdata = "$RCSfile: base.c,v $ $Revision: 10079 $"; static const char *build_stamp = "" __DATE__ " " __TIME__ ""; #endif /* * lowlevel PCI access functions * These are simply wrappers for the normal PCI access functions that the kernel provides, * except that they allow us to work around specific PCI quirks with module options. * Currently the only option supported is pedanticpci, which injects a (min.) 3us delay * after any PCI access to forcibly disable fast back-to-back transactions. * In the case of a PCI write, pedanticpci will also read from the status register, which * has the effect of flushing any pending PCI writes. */ static inline unsigned char __pci_in8(struct b4xxp *b4, const unsigned int reg) { unsigned char ret = ioread8(b4->addr + reg); #ifdef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { drv_dbg(&b4->pdev->dev, "read 0x%02x from 0x%p\n", ret, b4->addr + reg); } #endif if (unlikely(pedanticpci)) { udelay(3); } return ret; } static inline unsigned short __pci_in16(struct b4xxp *b4, const unsigned int reg) { unsigned short ret = ioread16(b4->addr + reg); #ifdef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { drv_dbg(&b4->pdev->dev, "read 0x%04x from 0x%p\n", ret, b4->addr + reg); } #endif if (unlikely(pedanticpci)) { udelay(3); } return ret; } static inline unsigned int __pci_in32(struct b4xxp *b4, const unsigned int reg) { unsigned int ret = ioread32(b4->addr + reg); #ifdef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { drv_dbg(&b4->pdev->dev, "read 0x%04x from 0x%p\n", ret, b4->addr + reg); } #endif if (unlikely(pedanticpci)) { udelay(3); } return ret; } static inline void __pci_out32(struct b4xxp *b4, const unsigned int reg, const unsigned int val) { #ifdef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { drv_dbg(&b4->pdev->dev, "writing 0x%02x to 0x%p\n", val, b4->addr + reg); } #endif iowrite32(val, b4->addr + reg); if (unlikely(pedanticpci)) { udelay(3); (void)ioread8(b4->addr + R_STATUS); } } static inline void __pci_out8(struct b4xxp *b4, const unsigned int reg, const unsigned char val) { #ifdef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { drv_dbg(&b4->pdev->dev, "writing 0x%02x to 0x%p\n", val, b4->addr + reg); } #endif iowrite8(val, b4->addr + reg); if (unlikely(pedanticpci)) { udelay(3); (void)ioread8(b4->addr + R_STATUS); } } /* * Standard I/O access functions * uses spinlocks to protect against multiple I/O accesses * DOES NOT automatically memory barrier */ static inline unsigned char b4xxp_getreg8(struct b4xxp *b4, const unsigned int reg) { unsigned int ret; unsigned long irq_flags; spin_lock_irqsave(&b4->reglock, irq_flags); #undef RETRY_REGISTER_READS #ifdef RETRY_REGISTER_READS switch (reg) { case A_Z1: case A_Z1H: case A_F2: case R_IRQ_OVIEW: case R_BERT_STA: case A_ST_RD_STA: case R_IRQ_FIFO_BL0: case A_Z2: case A_Z2H: case A_F1: case R_RAM_USE: case R_F0_CNTL: case A_ST_SQ_RD: case R_IRQ_FIFO_BL7: /* On pg 53 of the data sheet for the hfc, it states that we must * retry certain registers until we get two consecutive reads that are * the same. */ retry: ret = __pci_in8(b4, reg); if (ret != __pci_in8(b4, reg)) goto retry; break; default: #endif ret = __pci_in8(b4, reg); #ifdef RETRY_REGISTER_READS break; } #endif spin_unlock_irqrestore(&b4->reglock, irq_flags); #ifndef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { dev_dbg(&b4->pdev->dev, "read 0x%02x from 0x%p\n", ret, b4->addr + reg); } #endif return ret; } static inline unsigned int b4xxp_getreg32(struct b4xxp *b4, const unsigned int reg) { unsigned int ret; unsigned long irq_flags; spin_lock_irqsave(&b4->reglock, irq_flags); ret = __pci_in32(b4, reg); spin_unlock_irqrestore(&b4->reglock, irq_flags); #ifndef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { dev_dbg(&b4->pdev->dev, "read 0x%04x from 0x%p\n", ret, b4->addr + reg); } #endif return ret; } static inline unsigned short b4xxp_getreg16(struct b4xxp *b4, const unsigned int reg) { unsigned int ret; unsigned long irq_flags; spin_lock_irqsave(&b4->reglock, irq_flags); ret = __pci_in16(b4, reg); spin_unlock_irqrestore(&b4->reglock, irq_flags); #ifndef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { dev_dbg(&b4->pdev->dev, "read 0x%04x from 0x%p\n", ret, b4->addr + reg); } #endif return ret; } static inline void b4xxp_setreg32(struct b4xxp *b4, const unsigned int reg, const unsigned int val) { unsigned long irq_flags; #ifndef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { dev_dbg(&b4->pdev->dev, "writing 0x%02x to 0x%p\n", val, b4->addr + reg); } #endif spin_lock_irqsave(&b4->reglock, irq_flags); __pci_out32(b4, reg, val); spin_unlock_irqrestore(&b4->reglock, irq_flags); } static inline void b4xxp_setreg8(struct b4xxp *b4, const unsigned int reg, const unsigned char val) { unsigned long irq_flags; #ifndef DEBUG_LOWLEVEL_REGS if (unlikely(DBG_REGS)) { dev_dbg(&b4->pdev->dev, "writing 0x%02x to 0x%p\n", val, b4->addr + reg); } #endif spin_lock_irqsave(&b4->reglock, irq_flags); __pci_out8(b4, reg, val); spin_unlock_irqrestore(&b4->reglock, irq_flags); } /* * A lot of the registers in the HFC are indexed. * this function sets the index, and then writes to the indexed register in an ordered fashion. * memory barriers are useless unless spinlocked, so that's what these wrapper functions do. */ static void b4xxp_setreg_ra(struct b4xxp *b4, unsigned char r, unsigned char rd, unsigned char a, unsigned char ad) { unsigned long irq_flags; spin_lock_irqsave(&b4->seqlock, irq_flags); b4xxp_setreg8(b4, r, rd); wmb(); b4xxp_setreg8(b4, a, ad); mmiowb(); spin_unlock_irqrestore(&b4->seqlock, irq_flags); } static unsigned char b4xxp_getreg_ra(struct b4xxp *b4, unsigned char r, unsigned char rd, unsigned char a) { unsigned long irq_flags; unsigned char val; spin_lock_irqsave(&b4->seqlock, irq_flags); b4xxp_setreg8(b4, r, rd); wmb(); val = b4xxp_getreg8(b4, a); mmiowb(); spin_unlock_irqrestore(&b4->seqlock, irq_flags); return val; } /* * HFC-4S GPIO routines * * the B410P uses the HFC-4S GPIO as follows: * GPIO 8..10: output, CPLD register select * GPIO12..15: output, 1 = enable power for port 1-4 * GPI16: input, 0 = echo can #1 interrupt * GPI17: input, 0 = echo can #2 interrupt * GPI23: input, 1 = NT power module installed * GPI24..27: input, NT power module problem on port 1-4 * GPI28..31: input, 1 = port 1-4 in NT mode */ /* initialize HFC-4S GPIO. Set up pin drivers before setting GPIO mode */ static void hfc_gpio_init(struct b4xxp *b4) { unsigned long irq_flags; spin_lock_irqsave(&b4->seqlock, irq_flags); flush_pci(); /* flush any pending PCI writes */ mb(); b4xxp_setreg8(b4, R_GPIO_EN0, 0x00); /* GPIO0..7 input */ b4xxp_setreg8(b4, R_GPIO_EN1, 0xf7); /* GPIO8..10,12..15 outputs, GPIO11 input */ b4xxp_setreg8(b4, R_GPIO_OUT1, 0x00); /* disable power, CPLD reg 0 */ mb(); switch (b4->card_type) { case OCTOBRI: /* fall through */ case B800P_OV: /* fall through */ case BN8S0: /* GPIO0..15 S/T - HFC-8S uses GPIO8-15 for S/T ports 5-8 */ b4xxp_setreg8(b4, R_GPIO_SEL, 0x00); break; default: /* GPIO0..7 S/T, 8..15 GPIO */ b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); break; } mb(); spin_unlock_irqrestore(&b4->seqlock, irq_flags); } /* * HFC SRAM interface code. * This came from mattf, I don't even pretend to understand it, * It seems to be using undocumented features in the HFC. * I just added the __pci_in8() to ensure the PCI writes made it * to hardware by the time these functions return. */ static inline void enablepcibridge(struct b4xxp *b4) { b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x03); flush_pci(); } static inline void disablepcibridge(struct b4xxp *b4) { b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02); flush_pci(); } /* NOTE: read/writepcibridge do not use __pci_in/out because they are using b4->ioaddr not b4->addr */ static inline unsigned char readpcibridge(struct b4xxp *b4, unsigned char address) { unsigned short cipv; unsigned char data; /* slow down a PCI read access by 1 PCI clock cycle */ b4xxp_setreg8(b4, R_CTRL, 0x4); wmb(); if (address == 0) cipv=0x4000; else cipv=0x5800; /* select local bridge port address by writing to CIP port */ iowrite16(cipv, b4->ioaddr + 4); wmb(); data = ioread8(b4->ioaddr); /* restore R_CTRL for normal PCI read cycle speed */ b4xxp_setreg8(b4, R_CTRL, 0x0); wmb(); flush_pci(); return data; } static inline void writepcibridge(struct b4xxp *b4, unsigned char address, unsigned char data) { unsigned short cipv; unsigned int datav; if (address == 0) cipv=0x4000; else cipv=0x5800; /* select local bridge port address by writing to CIP port */ iowrite16(cipv, b4->ioaddr + 4); wmb(); /* define a 32 bit dword with 4 identical bytes for write sequence */ datav = data | ( (__u32) data <<8) | ( (__u32) data <<16) | ( (__u32) data <<24); /* * write this 32 bit dword to the bridge data port * this will initiate a write sequence of up to 4 writes to the same address on the local bus * interface * the number of write accesses is undefined but >=1 and depends on the next PCI transaction * during write sequence on the local bus */ iowrite32(datav, b4->ioaddr); wmb(); flush_pci(); } /* CPLD access code, more or less copied verbatim from code provided by mattf. */ static inline void cpld_select_reg(struct b4xxp *b4, unsigned char reg) { b4xxp_setreg8(b4, R_GPIO_OUT1, reg); flush_pci(); } static inline void cpld_setreg(struct b4xxp *b4, unsigned char reg, unsigned char val) { cpld_select_reg(b4, reg); enablepcibridge(b4); writepcibridge(b4, 1, val); disablepcibridge(b4); } static inline unsigned char cpld_getreg(struct b4xxp *b4, unsigned char reg) { unsigned char data; cpld_select_reg(b4, reg); enablepcibridge(b4); data = readpcibridge(b4, 1); disablepcibridge(b4); return data; } /* * echo canceller code, verbatim from mattf. * I don't pretend to understand it. */ static inline void ec_select_addr(struct b4xxp *b4, unsigned short addr) { cpld_setreg(b4, 0, 0xff & addr); cpld_setreg(b4, 1, 0x01 & (addr >> 8)); } static inline unsigned short ec_read_data(struct b4xxp *b4) { unsigned short addr; unsigned short highbit; addr = cpld_getreg(b4, 0); highbit = cpld_getreg(b4, 1); addr = addr | (highbit << 8); return addr & 0x1ff; } static inline unsigned char ec_read(struct b4xxp *b4, int which, unsigned short addr) { unsigned char data; unsigned long flags; spin_lock_irqsave(&b4->seqlock, flags); ec_select_addr(b4, addr); if (!which) cpld_select_reg(b4, 2); else cpld_select_reg(b4, 3); enablepcibridge(b4); data = readpcibridge(b4, 1); disablepcibridge(b4); cpld_select_reg(b4, 0); spin_unlock_irqrestore(&b4->seqlock, flags); return data; } static inline void ec_write(struct b4xxp *b4, int which, unsigned short addr, unsigned char data) { unsigned char in; unsigned long flags; spin_lock_irqsave(&b4->seqlock, flags); ec_select_addr(b4, addr); enablepcibridge(b4); if (!which) cpld_select_reg(b4, 2); else cpld_select_reg(b4, 3); writepcibridge(b4, 1, data); cpld_select_reg(b4, 0); disablepcibridge(b4); spin_unlock_irqrestore(&b4->seqlock, flags); in = ec_read(b4, which, addr); if ((in != data) && printk_ratelimit()) { dev_warn(&b4->pdev->dev, "ec_write: Wrote 0x%02x to register 0x%02x " "of VPM %d but got back 0x%02x\n", data, addr, which, in); } } #define NUM_EC 2 #define MAX_TDM_CHAN 32 #if 0 void ec_set_dtmf_threshold(struct b4xxp *b4, int threshold) { unsigned int x; for (x = 0; x < NUM_EC; x++) { ec_write(b4, x, 0xC4, (threshold >> 8) & 0xFF); ec_write(b4, x, 0xC5, (threshold & 0xFF)); } printk("VPM: DTMF threshold set to %d\n", threshold); } #endif static void ec_init(struct b4xxp *b4) { unsigned char b; unsigned int i, j, mask; if (!CARD_HAS_EC(b4)) return; /* Setup GPIO */ for (i=0; i < NUM_EC; i++) { b = ec_read(b4, i, 0x1a0); dev_info(&b4->pdev->dev, "VPM %d/%d init: chip ver %02x\n", i, NUM_EC - 1, b); for (j=0; j < b4->numspans; j++) { ec_write(b4, i, 0x1a8 + j, 0x00); /* GPIO out */ ec_write(b4, i, 0x1ac + j, 0x00); /* GPIO dir */ ec_write(b4, i, 0x1b0 + j, 0x00); /* GPIO sel */ } /* Setup TDM path - sets fsync and tdm_clk as inputs */ b = ec_read(b4, i, 0x1a3); /* misc_con */ ec_write(b4, i, 0x1a3, b & ~0x02); /* Setup Echo length (512 taps) */ ec_write(b4, i, 0x022, 1); ec_write(b4, i, 0x023, 0xff); /* Setup timeslots */ ec_write(b4, i, 0x02f, 0x00); mask = 0x02020202 << (i * 4); /* Setup the tdm channel masks for all chips*/ for (j=0; j < 4; j++) ec_write(b4, i, 0x33 - j, (mask >> (j << 3)) & 0xff); /* Setup convergence rate */ b = ec_read(b4, i, 0x20); b &= 0xe0; b |= 0x12; if (!strcasecmp(companding, "alaw")) { if (DBG) dev_info(&b4->pdev->dev, "Setting alaw mode\n"); b |= 0x01; } else { if (DBG) dev_info(&b4->pdev->dev, "Setting ulaw mode"); } ec_write(b4, i, 0x20, b); if (DBG) dev_info(&b4->pdev->dev, "reg 0x20 is 0x%02x\n", b); // ec_write(b4, i, 0x20, 0x38); #if 0 ec_write(b4, i, 0x24, 0x02); b = ec_read(b4, i, 0x24); #endif if (DBG) { dev_info(&b4->pdev->dev, "NLP threshold is set to %d (0x%02x)\n", b, b); } /* Initialize echo cans */ for (j=0; j < MAX_TDM_CHAN; j++) { if (mask & (0x00000001 << j)) ec_write(b4, i, j, 0x00); } mdelay(10); /* Put in bypass mode */ for (j=0; j < MAX_TDM_CHAN; j++) { if (mask & (0x00000001 << j)) { ec_write(b4, i, j, 0x01); } } /* Enable bypass */ for (j=0; j < MAX_TDM_CHAN; j++) { if (mask & (0x00000001 << j)) ec_write(b4, i, 0x78 + j, 0x01); } } #if 0 ec_set_dtmf_threshold(b4, 1250); #endif } /* performs a register write and then waits for the HFC "busy" bit to clear */ static void hfc_setreg_waitbusy(struct b4xxp *b4, const unsigned int reg, const unsigned int val) { int timeout = 0; unsigned long start; const int TIMEOUT = HZ/4; /* 250ms */ start = jiffies; while (unlikely((b4xxp_getreg8(b4, R_STATUS) & V_BUSY))) { if (time_after(jiffies, start + TIMEOUT)) { timeout = 1; break; } }; mb(); b4xxp_setreg8(b4, reg, val); mb(); start = jiffies; while (likely((b4xxp_getreg8(b4, R_STATUS) & V_BUSY))) { if (time_after(jiffies, start + TIMEOUT)) { timeout = 1; break; } }; if (timeout && printk_ratelimit()) { dev_warn(&b4->pdev->dev, "hfc_setreg_waitbusy(write 0x%02x to 0x%02x) timed " "out waiting for busy flag to clear!\n", val, reg); } } /* * reads an 8-bit register over over and over until the same value is read twice, then returns that value. */ static inline unsigned char hfc_readcounter8(struct b4xxp *b4, const unsigned int reg) { unsigned char r1, r2; unsigned long maxwait = 1048576; do { r1 = b4xxp_getreg8(b4, reg); r2 = b4xxp_getreg8(b4, reg); } while ((r1 != r2) && maxwait--); if (!maxwait && printk_ratelimit()) { dev_warn(&b4->pdev->dev, "hfc_readcounter8(reg 0x%02x) timed out waiting " "for data to settle!\n", reg); } return r1; } /* * reads a 16-bit register over over and over until the same value is read twice, then returns that value. */ static inline unsigned short hfc_readcounter16(struct b4xxp *b4, const unsigned int reg) { unsigned short r1, r2; unsigned long maxwait = 1048576; do { r1 = b4xxp_getreg16(b4, reg); r2 = b4xxp_getreg16(b4, reg); } while ((r1 != r2) && maxwait--); if (!maxwait && printk_ratelimit()) { dev_warn(&b4->pdev->dev, "hfc_readcounter16(reg 0x%02x) timed out waiting " "for data to settle!\n", reg); } return r1; } static inline unsigned int hfc_readcounter32(struct b4xxp *b4, const unsigned int reg) { unsigned int r1, r2; unsigned long maxwait = 1048576; do { r1 = b4xxp_getreg32(b4, reg); r2 = b4xxp_getreg32(b4, reg); } while ((r1 != r2) && maxwait--); if (!maxwait && printk_ratelimit()) { dev_warn(&b4->pdev->dev, "hfc_readcounter32(reg 0x%02x) timed out waiting " "for data to settle!\n", reg); } return r1; } /* performs a soft-reset of the HFC-4S. This is as clean-slate as you can get to a hardware reset. */ static void hfc_reset(struct b4xxp *b4) { int b, c; /* all 32 FIFOs the same size (384 bytes), channel select data flow mode, sized for internal RAM */ b4xxp_setreg8(b4, R_FIFO_MD, V_FIFO_MD_00 | V_DF_MD_CSM | V_FIFO_SZ_00); flush_pci(); /* reset everything, wait 500us, then bring everything BUT the PCM system out of reset */ b4xxp_setreg8(b4, R_CIRM, HFC_FULL_RESET); flush_pci(); udelay(500); b4xxp_setreg8(b4, R_CIRM, V_PCM_RES); flush_pci(); udelay(500); /* * Now bring PCM out of reset and do a very basic setup of the PCM system to allow it to finish resetting correctly. * set F0IO as an output, and set up a 32-timeslot PCM bus * See Section 8.3 in the HFC-4S datasheet for more details. */ b4xxp_setreg8(b4, R_CIRM, 0x00); b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1); flush_pci(); b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048); flush_pci(); /* now wait for R_F0_CNTL to reach at least 2 before continuing */ c=10; while ((b = b4xxp_getreg8(b4, R_F0_CNTL)) < 2 && c) { udelay(100); c--; } if (!c && b < 2) { dev_warn(&b4->pdev->dev, "hfc_reset() did not get the green light from the PCM system!\n"); } } static inline void hfc_enable_fifo_irqs(struct b4xxp *b4) { b4xxp_setreg8(b4, R_IRQ_CTRL, V_FIFO_IRQ | V_GLOB_IRQ_EN); flush_pci(); } static inline void hfc_disable_fifo_irqs(struct b4xxp *b4) { b4xxp_setreg8(b4, R_IRQ_CTRL, V_GLOB_IRQ_EN); flush_pci(); } static void hfc_enable_interrupts(struct b4xxp *b4) { b4->running = 1; /* clear any pending interrupts */ b4xxp_getreg8(b4, R_STATUS); b4xxp_getreg8(b4, R_IRQ_MISC); b4xxp_getreg8(b4, R_IRQ_FIFO_BL0); b4xxp_getreg8(b4, R_IRQ_FIFO_BL1); b4xxp_getreg8(b4, R_IRQ_FIFO_BL2); b4xxp_getreg8(b4, R_IRQ_FIFO_BL3); b4xxp_getreg8(b4, R_IRQ_FIFO_BL4); b4xxp_getreg8(b4, R_IRQ_FIFO_BL5); b4xxp_getreg8(b4, R_IRQ_FIFO_BL6); b4xxp_getreg8(b4, R_IRQ_FIFO_BL7); b4xxp_setreg8(b4, R_IRQMSK_MISC, V_TI_IRQ); hfc_enable_fifo_irqs(b4); } static void hfc_disable_interrupts(struct b4xxp *b4) { b4xxp_setreg8(b4, R_IRQMSK_MISC, 0); b4xxp_setreg8(b4, R_IRQ_CTRL, 0); flush_pci(); b4->running = 0; } /* * Connects an S/T port's B channel to a host-facing FIFO through the PCM busses. * This bchan flow plan should match up with the EC requirements. * TODO: Interrupts are only enabled on the host FIFO RX side, since everything is (should be) synchronous. * *** performs no error checking of parameters *** */ static void hfc_assign_bchan_fifo_ec(struct b4xxp *b4, int port, int bchan) { int fifo, hfc_chan, ts; unsigned long irq_flags; static int first=1; if (first) { first = 0; dev_info(&b4->pdev->dev, "Hardware echo cancellation enabled.\n"); } fifo = port * 2; hfc_chan = port * 4; ts = port * 8; if (bchan) { fifo += 1; hfc_chan += 1; ts += 4; } /* record the host's FIFO # in the span fifo array */ b4->spans[port].fifos[bchan] = fifo; spin_lock_irqsave(&b4->fifolock, irq_flags); if (DBG) { dev_info(&b4->pdev->dev, "port %d, B channel %d\n\tS/T -> PCM ts %d uses HFC " "chan %d via FIFO %d\n", port, bchan, ts + 1, hfc_chan, 16 + fifo); } /* S/T RX -> PCM TX FIFO, transparent mode, no IRQ. */ hfc_setreg_waitbusy(b4, R_FIFO, ((16 + fifo) << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_110); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT)); b4xxp_setreg8(b4, R_SLOT, ((ts + 1) << V_SL_NUM_SHIFT)); b4xxp_setreg8(b4, A_SL_CFG, V_ROUT_TX_STIO1 | (hfc_chan << V_CH_SNUM_SHIFT)); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tPCM ts %d -> host uses HFC chan %d via FIFO %d\n", ts + 1, 16 + hfc_chan, fifo); /* PCM RX -> Host TX FIFO, transparent mode, enable IRQ. */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_001); b4xxp_setreg8(b4, A_CHANNEL, ((16 + hfc_chan) << V_CH_FNUM_SHIFT) | V_CH_FDIR); b4xxp_setreg8(b4, R_SLOT, ((ts + 1) << V_SL_NUM_SHIFT) | 1); b4xxp_setreg8(b4, A_SL_CFG, V_ROUT_RX_STIO2 | ((16 + hfc_chan) << V_CH_SNUM_SHIFT) | 1); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); // b4xxp_setreg8(b4, A_IRQ_MSK, V_IRQ); if (DBG) pr_info("\thost -> PCM ts %d uses HFC chan %d via FIFO %d\n", ts, 16 + hfc_chan, fifo); /* Host FIFO -> PCM TX */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_001); b4xxp_setreg8(b4, A_CHANNEL, ((16 + hfc_chan) << V_CH_FNUM_SHIFT)); b4xxp_setreg8(b4, R_SLOT, (ts << V_SL_NUM_SHIFT)); b4xxp_setreg8(b4, A_SL_CFG, V_ROUT_RX_STIO2 | ((16 + hfc_chan) << V_CH_SNUM_SHIFT)); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tPCM ts %d -> S/T uses HFC chan %d via FIFO %d\n", ts, hfc_chan, 16 + fifo); /* PCM -> S/T */ hfc_setreg_waitbusy(b4, R_FIFO, ((16 + fifo) << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_110); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT) | V_CH_FDIR); b4xxp_setreg8(b4, R_SLOT, (ts << V_SL_NUM_SHIFT) | V_SL_DIR); b4xxp_setreg8(b4, A_SL_CFG, V_ROUT_TX_STIO2 | (hfc_chan << V_CH_SNUM_SHIFT) | V_CH_SDIR); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tPCM ts %d -> S/T uses HFC chan %d via FIFO %d\n", ts, hfc_chan, 16 + fifo); flush_pci(); /* ensure all those writes actually hit hardware */ spin_unlock_irqrestore(&b4->fifolock, irq_flags); } static void hfc_assign_bchan_fifo_noec(struct b4xxp *b4, int port, int bchan) { int fifo, hfc_chan, ts; unsigned long irq_flags; static int first=1; if (first) { first = 0; dev_info(&b4->pdev->dev, "NOTE: hardware echo cancellation has been disabled\n"); } fifo = port * 2; hfc_chan = port * 4; ts = port * 8; if (bchan) { fifo += 1; hfc_chan += 1; ts += 4; } /* record the host's FIFO # in the span fifo array */ b4->spans[port].fifos[bchan] = fifo; spin_lock_irqsave(&b4->fifolock, irq_flags); if (DBG) { dev_info(&b4->pdev->dev, "port %d, B channel %d\n\thost -> S/T " "uses HFC chan %d via FIFO %d\n", port, bchan, hfc_chan, fifo); } hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_000); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT)); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tS/T -> host uses HFC chan %d via FIFO %d\n", hfc_chan, fifo); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_000); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT) | V_CH_FDIR); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tPCM ts %d -> S/T uses HFC chan %d via FIFO %d\n", ts, hfc_chan, 16 + fifo); flush_pci(); /* ensure all those writes actually hit hardware */ spin_unlock_irqrestore(&b4->fifolock, irq_flags); } /* * Connects an S/T port's D channel to a host-facing FIFO. * Both TX and RX interrupts are enabled! * *** performs no error checking of parameters *** */ static void hfc_assign_dchan_fifo(struct b4xxp *b4, int port) { int fifo, hfc_chan; unsigned long irq_flags; switch (b4->card_type) { case B800P_OV: /* fall through */ case OCTOBRI: /* fall through */ case BN8S0: /* In HFC-8S cards we can't use ports 8-11 for dchan FIFOs */ fifo = port + 16; break; default: fifo = port + 8; break; } hfc_chan = (port * 4) + 2; /* record the host's FIFO # in the span fifo array */ b4->spans[port].fifos[2] = fifo; if (DBG) { dev_info(&b4->pdev->dev, "port %d, D channel\n\thost -> S/T uses HFC chan %d " "via FIFO %d\n", port, hfc_chan, fifo); } spin_lock_irqsave(&b4->fifolock, irq_flags); /* Host FIFO -> S/T TX, HDLC mode, no IRQ. */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_TRP_IRQ | V_DATA_FLOW_000); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT)); b4xxp_setreg8(b4, A_SUBCH_CFG, 0x02); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\tS/T -> host uses HFC chan %d via FIFO %d\n", hfc_chan, fifo); /* S/T RX -> Host FIFO, HDLC mode, IRQ will be enabled when port opened. */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_TRP_IRQ | V_DATA_FLOW_000); b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT) | V_CH_FDIR); b4xxp_setreg8(b4, A_SUBCH_CFG, 0x02); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); if (DBG) pr_info("\n"); flush_pci(); /* ensure all those writes actually hit hardware */ spin_unlock_irqrestore(&b4->fifolock, irq_flags); } /* takes a read/write fifo pair and optionally resets it, optionally enabling the rx/tx interrupt */ static void hfc_reset_fifo_pair(struct b4xxp *b4, int fifo, int reset, int force_no_irq) { unsigned long irq_flags; spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_IRQ_MSK, (!force_no_irq && b4->fifo_en_txint & (1 << fifo)) ? V_IRQ : 0); if (reset) hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_IRQ_MSK, (!force_no_irq && b4->fifo_en_rxint & (1 << fifo)) ? V_IRQ : 0); if (reset) hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO); spin_unlock_irqrestore(&b4->fifolock, irq_flags); } static void b4xxp_set_sync_src(struct b4xxp *b4, int port) { int b; #if 0 printk("Setting sync to be port %d\n", (port >= 0) ? port + 1 : port); #endif if (port == -1) /* automatic */ b = 0; else b = (port & V_SYNC_SEL_MASK) | V_MAN_SYNC; b4xxp_setreg8(b4, R_ST_SYNC, b); b4->syncspan = port; } /* * Finds the highest-priority sync span that is not in alarm and returns it. * Note: the span #s in b4->spans[].sync are 1-based, and this returns * a 0-based span, or -1 if no spans are found. */ static int b4xxp_find_sync(struct b4xxp *b4) { int i, psrc, src; src = -1; /* default to automatic */ for (i=0; i < b4->numspans; i++) { if (DBG) dev_info(&b4->pdev->dev, "Checking sync pos %d, have span %d\n", i, b4->spans[i].sync); psrc = b4->spans[i].sync; if (psrc > 0 && !b4->spans[psrc - 1].span.alarms) { if (DBG) dev_info(&b4->pdev->dev, "chosen\n"); src = psrc; break; } } if (src >= 0) return src - 1; else return src; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) static ssize_t b4_timing_master_show(struct device *dev, struct device_attribute *attr, char *buf) { struct b4xxp *b4 = dev_get_drvdata(dev); return sprintf(buf, "%d\n", b4->syncspan); } static DEVICE_ATTR(timing_master, 0400, b4_timing_master_show, NULL); static void create_sysfs_files(struct b4xxp *b4) { int ret; ret = device_create_file(&b4->pdev->dev, &dev_attr_timing_master); if (ret) { dev_info(&b4->pdev->dev, "Failed to create device attributes.\n"); } } static void remove_sysfs_files(struct b4xxp *b4) { device_remove_file(&b4->pdev->dev, &dev_attr_timing_master); } #else static inline void create_sysfs_files(struct b4xxp *b4) { return; } static inline void remove_sysfs_files(struct b4xxp *b4) { return; } #endif /* LINUX_KERNEL > 2.6.18 */ /* * allocates memory and pretty-prints a given S/T state engine state to it. * calling routine is responsible for freeing the pointer returned! * Performs no hardware access whatsoever, but does use GFP_KERNEL so do not call from IRQ context. * if full == 1, prints a "full" dump; otherwise just prints current state. */ static char *hfc_decode_st_state(struct b4xxp *b4, int port, unsigned char state, int full) { int nt, sta; char s[128], *str; const char *ststr[2][16] = { /* TE, NT */ { "RESET", "?", "SENSING", "DEACT.", "AWAIT.SIG", "IDENT.INPUT", "SYNCD", "ACTIVATED", "LOSTFRAMING", "?", "?", "?", "?", "?", "?", "?" }, { "RESET", "DEACT.", "PEND.ACT", "ACTIVE", "PEND.DEACT", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" } }; if (!(str = kmalloc(256, GFP_KERNEL))) { dev_warn(&b4->pdev->dev, "could not allocate mem for ST state decode string!\n"); return NULL; } nt = (b4->spans[port].te_mode == 0); sta = (state & V_ST_STA_MASK); sprintf(str, "P%d: %s state %c%d (%s)", port + 1, (nt ? "NT" : "TE"), (nt ? 'G' : 'F'), sta, ststr[nt][sta]); if (full) { sprintf(s, " SYNC: %s, RX INFO0: %s", ((state & V_FR_SYNC) ? "yes" : "no"), ((state & V_INFO0) ? "yes" : "no")); strcat(str, s); if (nt) { sprintf(s, ", T2 %s, auto G2->G3: %s", ((state & V_T2_EXP) ? "expired" : "OK"), ((state & V_G2_G3) ? "yes" : "no")); strcat(str, s); } } return str; } /* * sets an S/T port state machine to a given state. * if 'auto' is nonzero, will put the state machine back in auto mode after setting the state. */ static void hfc_handle_state(struct b4xxp_span *s); static void hfc_force_st_state(struct b4xxp *b4, int port, int state, int resume_auto) { b4xxp_setreg_ra(b4, R_ST_SEL, port, A_ST_RD_STA, state | V_ST_LD_STA); udelay(6); if (resume_auto) { b4xxp_setreg_ra(b4, R_ST_SEL, port, A_ST_RD_STA, state); } if (DBG_ST) { char *x; x = hfc_decode_st_state(b4, port, state, 1); dev_info(&b4->pdev->dev, "forced port %d to state %d (auto: %d), " "new decode: %s\n", port + 1, state, resume_auto, x); kfree(x); } /* make sure that we activate any timers/etc needed by this state change */ hfc_handle_state(&b4->spans[port]); } /* figures out what to do when an S/T port's timer expires. */ static void hfc_timer_expire(struct b4xxp_span *s, int t_no) { struct b4xxp *b4 = s->parent; if (DBG_ST) { dev_info(&b4->pdev->dev, "%lu: hfc_timer_expire, Port %d T%d expired " "(value=%lu ena=%d)\n", b4->ticks, s->port + 1, t_no + 1, s->hfc_timers[t_no], s->hfc_timer_on[t_no]); } /* * there are three timers associated with every HFC S/T port. * T1 is used by the NT state machine, and is the maximum time the NT side should wait for G3 (active) state. * T2 is not actually used in the driver, it is handled by the HFC-4S internally. * T3 is used by the TE state machine; it is the maximum time the TE side should wait for the INFO4 (activated) signal. */ /* First, disable the expired timer; hfc_force_st_state() may activate it again. */ s->hfc_timer_on[t_no] = 0; switch(t_no) { case HFC_T1: /* switch to G4 (pending deact.), resume auto mode */ hfc_force_st_state(b4, s->port, 4, 1); break; case HFC_T2: /* switch to G1 (deactivated), resume auto mode */ hfc_force_st_state(b4, s->port, 1, 1); break; case HFC_T3: /* switch to F3 (deactivated), resume auto mode */ hfc_force_st_state(b4, s->port, 3, 1); break; default: if (printk_ratelimit()) { dev_warn(&b4->pdev->dev, "hfc_timer_expire found an unknown expired " "timer (%d)??\n", t_no); } } } /* * Run through the active timers on a card and deal with any expiries. * Also see if the alarm debounce time has expired and if it has, tell DAHDI. */ static void hfc_update_st_timers(struct b4xxp *b4) { int i, j; struct b4xxp_span *s; for (i=0; i < b4->numspans; i++) { s = &b4->spans[i]; for (j=HFC_T1; j <= HFC_T3; j++) { /* we don't really do timer2, it is expired by the state change handler */ if (j == HFC_T2) continue; if (s->hfc_timer_on[j] && time_after_eq(b4->ticks, s->hfc_timers[j])) { hfc_timer_expire(s, j); } } if (s->newalarm != s->span.alarms && time_after_eq(b4->ticks, s->alarmtimer)) { s->span.alarms = s->newalarm; if ((!s->newalarm && teignorered) || (!teignorered)) { dahdi_alarm_notify(&s->span); } b4xxp_set_sync_src(b4, b4xxp_find_sync(b4)); if (DBG_ALARM) { dev_info(&b4->pdev->dev, "span %d: alarm %d " "debounced\n", i + 1, s->newalarm); } } } } /* this is the driver-level state machine for an S/T port */ static void hfc_handle_state(struct b4xxp_span *s) { struct b4xxp *b4; unsigned char state, sta; int nt, newsync, oldalarm; unsigned long oldtimer; b4 = s->parent; nt = !s->te_mode; state = b4xxp_getreg_ra(b4, R_ST_SEL, s->port, A_ST_RD_STA); sta = (state & V_ST_STA_MASK); if (DBG_ST) { char *x; x = hfc_decode_st_state(b4, s->port, state, 1); dev_info(&b4->pdev->dev, "port %d A_ST_RD_STA old=0x%02x now=0x%02x, " "decoded: %s\n", s->port + 1, s->oldstate, state, x); kfree(x); } oldalarm = s->newalarm; oldtimer = s->alarmtimer; if (nt) { switch(sta) { default: /* Invalid NT state */ case 0x0: /* NT state G0: Reset */ case 0x1: /* NT state G1: Deactivated */ case 0x4: /* NT state G4: Pending Deactivation */ s->newalarm = DAHDI_ALARM_RED; break; case 0x2: /* NT state G2: Pending Activation */ s->newalarm = DAHDI_ALARM_YELLOW; break; case 0x3: /* NT state G3: Active */ s->hfc_timer_on[HFC_T1] = 0; s->newalarm = 0; break; } } else { switch(sta) { default: /* Invalid TE state */ case 0x0: /* TE state F0: Reset */ case 0x2: /* TE state F2: Sensing */ case 0x3: /* TE state F3: Deactivated */ case 0x4: /* TE state F4: Awaiting Signal */ case 0x8: /* TE state F8: Lost Framing */ s->newalarm = DAHDI_ALARM_RED; break; case 0x5: /* TE state F5: Identifying Input */ case 0x6: /* TE state F6: Synchronized */ s->newalarm = DAHDI_ALARM_YELLOW; break; case 0x7: /* TE state F7: Activated */ s->hfc_timer_on[HFC_T3] = 0; s->newalarm = 0; break; } } s->alarmtimer = b4->ticks + alarmdebounce; s->oldstate = state; if (DBG_ALARM) { dev_info(&b4->pdev->dev, "span %d: old alarm %d expires %ld, new alarm %d expires %ld\n", s->port + 1, oldalarm, oldtimer, s->newalarm, s->alarmtimer); } /* we only care about T2 expiry in G4. */ if (nt && (sta == 4) && (state & V_T2_EXP)) { if (s->hfc_timer_on[HFC_T2]) hfc_timer_expire(s, HFC_T2); /* handle T2 expiry */ } /* If we're in F3 and receiving INFO0, start T3 and jump to F4 */ if (!nt && (sta == 3) && (state & V_INFO0)) { s->hfc_timers[HFC_T3] = b4->ticks + timer_3_ms; s->hfc_timer_on[HFC_T3] = 1; if (DBG_ST) { dev_info(&b4->pdev->dev, "port %d: receiving INFO0 in state 3, " "setting T3 and jumping to F4\n", s->port + 1); } hfc_force_st_state(b4, s->port, 4, 1); } /* read in R_BERT_STA to determine where our current sync source is */ newsync = b4xxp_getreg8(b4, R_BERT_STA) & 0x07; if (newsync != b4->syncspan) { if (printk_ratelimit() || DBG) { dev_info(&b4->pdev->dev, "new card sync source: port %d\n", newsync + 1); } b4->syncspan = newsync; } } /* * resets an S/T interface to a given NT/TE mode */ static void hfc_reset_st(struct b4xxp_span *s) { int b; struct b4xxp *b4; b4 = s->parent; /* force state G0/F0 (reset), then force state 1/2 (deactivated/sensing) */ b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_LD_STA); flush_pci(); /* make sure write hit hardware */ udelay(10); /* set up the clock control register. Must be done before we activate the interface. */ if (s->te_mode) b = 0x0e; else b = 0x0c | (6 << V_ST_SMPL_SHIFT); b4xxp_setreg8(b4, A_ST_CLK_DLY, b); /* set TE/NT mode, enable B and D channels. */ b4xxp_setreg8(b4, A_ST_CTRL0, V_B1_EN | V_B2_EN | (s->te_mode ? 0 : V_ST_MD)); b4xxp_setreg8(b4, A_ST_CTRL1, V_G2_G3_EN | V_E_IGNO); b4xxp_setreg8(b4, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); /* enable the state machine. */ b4xxp_setreg8(b4, A_ST_WR_STA, 0x00); flush_pci(); udelay(100); } static void hfc_start_st(struct b4xxp_span *s) { struct b4xxp *b4 = s->parent; b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_ACT_ACTIVATE); /* start T1 if in NT mode, T3 if in TE mode */ if (s->te_mode) { s->hfc_timers[HFC_T3] = b4->ticks + 500; /* 500ms wait first time, timer_t3_ms afterward. */ s->hfc_timer_on[HFC_T3] = 1; s->hfc_timer_on[HFC_T1] = 0; if (DBG_ST) { dev_info(&b4->pdev->dev, "setting port %d t3 timer to %lu\n", s->port + 1, s->hfc_timers[HFC_T3]); } } else { s->hfc_timers[HFC_T1] = b4->ticks + timer_1_ms; s->hfc_timer_on[HFC_T1] = 1; s->hfc_timer_on[HFC_T3] = 0; if (DBG_ST) { dev_info(&b4->pdev->dev, "setting port %d t1 timer to %lu\n", s->port + 1, s->hfc_timers[HFC_T1]); } } } #if 0 /* TODO: This function is not called anywhere */ static void hfc_stop_st(struct b4xxp_span *s) { b4xxp_setreg_ra(s->parent, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_ACT_DEACTIVATE); s->hfc_timer_on[HFC_T1] = 0; s->hfc_timer_on[HFC_T2] = 0; s->hfc_timer_on[HFC_T3] = 0; } #endif /* * read in the HFC GPIO to determine each port's mode (TE or NT). * Then, reset and start the port. * the flow controller should be set up before this is called. */ static void hfc_init_all_st(struct b4xxp *b4) { int i, gpio, nt; struct b4xxp_span *s; gpio = b4xxp_getreg8(b4, R_GPI_IN3); for (i=0; i < b4->numspans; i++) { s = &b4->spans[i]; s->parent = b4; s->port = i; /* The way the Digium B410P card reads the NT/TE mode * jumper is the oposite of how other HFC-4S cards do: * - In B410P: GPIO=0: NT * - In Junghanns: GPIO=0: TE */ if (b4->card_type == B410P) nt = ((gpio & (1 << (i + 4))) == 0); else nt = ((gpio & (1 << (i + 4))) != 0); s->te_mode = !nt; dev_info(&b4->pdev->dev, "Port %d: %s mode\n", i + 1, (nt ? "NT" : "TE")); hfc_reset_st(s); hfc_start_st(s); } } /* * Look at one B-channel FIFO and determine if we should exchange data with it. * It is assumed that the S/T port is active. * returns 1 if data was exchanged, 0 otherwise. */ static int hfc_poll_one_bchan_fifo(struct b4xxp_span *span, int c) { int fifo, zlen, z1, z2, ret; unsigned long irq_flags; struct b4xxp *b4; struct dahdi_chan *chan; ret = 0; b4 = span->parent; fifo = span->fifos[c]; chan = span->chans[c]; spin_lock_irqsave(&b4->fifolock, irq_flags); /* select RX FIFO */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR | V_REV); get_Z(z1, z2, zlen); /* TODO: error checking, full FIFO mostly */ if (zlen >= DAHDI_CHUNKSIZE) { *(unsigned int *)&chan->readchunk[0] = b4xxp_getreg32(b4, A_FIFO_DATA2); *(unsigned int *)&chan->readchunk[4] = b4xxp_getreg32(b4, A_FIFO_DATA2); /* * now TX FIFO * * Note that we won't write to the TX FIFO if there wasn't room in the RX FIFO. * The TX and RX sides should be kept pretty much lock-step. * * Write the last byte _NOINC so that if we don't get more data in time, we aren't leaking unknown data * (See HFC datasheet) */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_REV); b4xxp_setreg32(b4, A_FIFO_DATA2, *(unsigned int *) &chan->writechunk[0]); b4xxp_setreg32(b4, A_FIFO_DATA2, *(unsigned int *) &chan->writechunk[4]); ret = 1; } spin_unlock_irqrestore(&b4->fifolock, irq_flags); return ret; } /* * Run through all of the host-facing B-channel RX FIFOs, looking for at least 8 bytes available. * If a B channel RX fifo has enough data, perform the data transfer in both directions. * D channel is done in an interrupt handler. * The S/T port state must be active or we ignore the fifo. * Returns nonzero if there was at least DAHDI_CHUNKSIZE bytes in the FIFO */ static int hfc_poll_fifos(struct b4xxp *b4) { int ret=0, span; unsigned long irq_flags; for (span=0; span < b4->numspans; span++) { /* Make sure DAHDI's got this span up */ if (!(b4->spans[span].span.flags & DAHDI_FLAG_RUNNING)) continue; /* TODO: Make sure S/T port is in active state */ #if 0 if (span_not_active(s)) continue; #endif ret = hfc_poll_one_bchan_fifo(&b4->spans[span], 0); ret |= hfc_poll_one_bchan_fifo(&b4->spans[span], 1); } /* change the active FIFO one last time to make sure the last-changed FIFO updates its pointers (as per the datasheet) */ spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, R_FIFO, (31 << V_FIFO_NUM_SHIFT)); spin_unlock_irqrestore(&b4->fifolock, irq_flags); return ret; } /* NOTE: assumes fifo lock is held */ static inline void debug_fz(struct b4xxp *b4, int fifo, const char *prefix, char *buf) { int f1, f2, flen, z1, z2, zlen; get_F(f1, f2, flen); get_Z(z1, z2, zlen); sprintf(buf, "%s: (fifo %d): f1/f2/flen=%d/%d/%d, z1/z2/zlen=%d/%d/%d\n", prefix, fifo, f1, f2, flen, z1, z2, zlen); } /* enable FIFO RX int and reset the FIFO */ static int hdlc_start(struct b4xxp *b4, int fifo) { b4->fifo_en_txint |= (1 << fifo); b4->fifo_en_rxint |= (1 << fifo); hfc_reset_fifo_pair(b4, fifo, 1, 0); return 0; } /* disable FIFO ints and reset the FIFO */ static void hdlc_stop(struct b4xxp *b4, int fifo) { b4->fifo_en_txint &= ~(1 << fifo); b4->fifo_en_rxint &= ~(1 << fifo); hfc_reset_fifo_pair(b4, fifo, 1, 0); } /* * Inner loop for D-channel receive function. * Retrieves a full HDLC frame from the hardware. * If the hardware indicates that the frame is complete, * we check the HDLC engine's STAT byte and update DAHDI as needed. * * Returns the number of HDLC frames left in the FIFO. */ static int hdlc_rx_frame(struct b4xxp_span *bspan) { int fifo, i, j, zleft; int z1, z2, zlen, f1, f2, flen; unsigned char buf[WCB4XXP_HDLC_BUF_LEN]; char debugbuf[256]; unsigned long irq_flags; struct b4xxp *b4 = bspan->parent; unsigned char stat; fifo = bspan->fifos[2]; spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); get_F(f1, f2, flen); get_Z(z1, z2, zlen); debug_fz(b4, fifo, "hdlc_rx_frame", debugbuf); spin_unlock_irqrestore(&b4->fifolock, irq_flags); if (DBG_HDLC && DBG_SPANFILTER) { pr_info("%s", debugbuf); } /* first check to make sure we really do have HDLC frames available to retrieve */ if (flen == 0) { if (DBG_HDLC && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "hdlc_rx_frame(span %d): no frames available?\n", bspan->port + 1); } return flen; } zleft = zlen + 1; /* include STAT byte that the HFC injects after FCS */ do { int truncated; if (zleft > WCB4XXP_HDLC_BUF_LEN) { truncated = 1; j = WCB4XXP_HDLC_BUF_LEN; } else { truncated = 0; j = zleft; } spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); for (i=0; i < j; i++) buf[i] = b4xxp_getreg8(b4, A_FIFO_DATA0); spin_unlock_irqrestore(&b4->fifolock, irq_flags); /* don't send STAT byte to DAHDI */ if ((bspan->sigchan) && (j > 1)) dahdi_hdlc_putbuf(bspan->sigchan, buf, truncated ? j : j - 1); zleft -= j; if (DBG_HDLC && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "hdlc_rx_frame(span %d): z1/z2/zlen=%d/%d/%d, zleft=%d\n", bspan->port + 1, z1, z2, zlen, zleft); for (i=0; i < j; i++) printk("%02x%c", buf[i], (i < ( j - 1)) ? ' ':'\n'); } } while (zleft > 0); stat = buf[j - 1]; /* Frame received, increment F2 and get an updated count of frames left */ spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_INC_F); get_F(f1, f2, flen); spin_unlock_irqrestore(&b4->fifolock, irq_flags); /* If this channel is not configured with a signalling span we don't * need to notify the rest of dahdi about this frame. */ if (!bspan->sigchan) return flen; ++bspan->frames_in; if (zlen < 3) { if (DBG_HDLC && DBG_SPANFILTER) dev_notice(&b4->pdev->dev, "odd, zlen less then 3?\n"); dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_ABORT); } else { /* if STAT != 0, indicates bad frame */ if (stat != 0x00) { if (DBG_HDLC && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "(span %d) STAT=0x%02x indicates " "frame problem: ", bspan->port + 1, stat); } if (stat == 0xff) { if (DBG_HDLC && DBG_SPANFILTER) printk("HDLC Abort\n"); dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_ABORT); } else { if (DBG_HDLC && DBG_SPANFILTER) printk("Bad FCS\n"); dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_BADFCS); } /* STAT == 0, means frame was OK */ } else { if (DBG_HDLC && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "(span %d) Frame %d is good!\n", bspan->port + 1, bspan->frames_in); } dahdi_hdlc_finish(bspan->sigchan); } } return flen; } /* * Takes one blob of data from DAHDI and shoots it out to the hardware. * The blob may or may not be a complete HDLC frame. * If it isn't, the D-channel FIFO interrupt handler will take care of pulling the rest. * Returns nonzero if there is still data to send in the current HDLC frame. */ static int hdlc_tx_frame(struct b4xxp_span *bspan) { struct b4xxp *b4 = bspan->parent; int res, i, fifo; int z1, z2, zlen; unsigned char buf[WCB4XXP_HDLC_BUF_LEN]; unsigned int size = sizeof(buf) / sizeof(buf[0]); char debugbuf[256]; unsigned long irq_flags; /* if we're ignoring TE red alarms and we are in alarm, restart the S/T state machine */ if (bspan->te_mode && teignorered && bspan->newalarm == DAHDI_ALARM_RED) { hfc_force_st_state(b4, bspan->port, 3, 1); } fifo = bspan->fifos[2]; res = dahdi_hdlc_getbuf(bspan->sigchan, buf, &size); spin_lock_irqsave(&b4->fifolock, irq_flags); hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); get_Z(z1, z2, zlen); debug_fz(b4, fifo, "hdlc_tx_frame", debugbuf); /* TODO: check zlen, etc. */ if (size > 0) { bspan->sigactive = 1; for (i=0; i < size; i++) b4xxp_setreg8(b4, A_FIFO_DATA0, buf[i]); /* * If we got a full frame from DAHDI, increment F and decrement our HDLC pending counter. * Otherwise, select the FIFO again (to start transmission) and make sure the * TX IRQ is enabled so we will get called again to finish off the data */ if (res != 0) { ++bspan->frames_out; bspan->sigactive = 0; hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_INC_F); atomic_dec(&bspan->hdlc_pending); } else { hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_IRQ_MSK, V_IRQ); } } /* if there are no more frames pending, disable the interrupt. */ if (res == -1) { b4xxp_setreg8(b4, A_IRQ_MSK, 0); } spin_unlock_irqrestore(&b4->fifolock, irq_flags); if (DBG_HDLC && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "%s", debugbuf); dev_info(&b4->pdev->dev, "hdlc_tx_frame(span %d): DAHDI gave %d bytes for FIFO %d (res=%d)\n", bspan->port + 1, size, fifo, res); for (i=0; i < size; i++) printk("%02x%c", buf[i], (i < (size - 1)) ? ' ' : '\n'); if (size && res != 0) { pr_info("Transmitted frame %d on span %d\n", bspan->frames_out - 1, bspan->port + 1); } } return(res == 0); } /* * b4xxp lowlevel functions * These are functions which impact more than just the HFC controller. * (those are named hfc_xxx()) */ /* * Performs a total reset of the card, reinitializes GPIO. * The card is initialized enough to have LEDs running, and that's about it. * Anything to do with audio and enabling any kind of processing is done in stage2. */ static void b4xxp_init_stage1(struct b4xxp *b4) { int i; hfc_reset(b4); /* total reset of controller */ hfc_gpio_init(b4); /* initialize controller GPIO for CPLD access */ ec_init(b4); /* initialize VPM and VPM GPIO */ b4xxp_setreg8(b4, R_IRQ_CTRL, 0x00); /* make sure interrupts are disabled */ flush_pci(); /* make sure PCI write hits hardware */ /* disable all FIFO interrupts */ for (i=0; i < HFC_NR_FIFOS; i++) { hfc_setreg_waitbusy(b4, R_FIFO, (i << V_FIFO_NUM_SHIFT)); b4xxp_setreg8(b4, A_IRQ_MSK, 0x00); /* disable the interrupt */ hfc_setreg_waitbusy(b4, R_FIFO, (i << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b4xxp_setreg8(b4, A_IRQ_MSK, 0x00); /* disable the interrupt */ flush_pci(); } /* clear any pending FIFO interrupts */ b4xxp_getreg8(b4, R_IRQ_FIFO_BL0); b4xxp_getreg8(b4, R_IRQ_FIFO_BL1); b4xxp_getreg8(b4, R_IRQ_FIFO_BL2); b4xxp_getreg8(b4, R_IRQ_FIFO_BL3); b4xxp_getreg8(b4, R_IRQ_FIFO_BL4); b4xxp_getreg8(b4, R_IRQ_FIFO_BL5); b4xxp_getreg8(b4, R_IRQ_FIFO_BL6); b4xxp_getreg8(b4, R_IRQ_FIFO_BL7); b4xxp_setreg8(b4, R_SCI_MSK, 0x00); /* mask off all S/T interrupts */ b4xxp_setreg8(b4, R_IRQMSK_MISC, 0x00); /* nothing else can generate an interrupt */ /* * set up the clock controller B410P & Cologne Eval Board have a * 24.576MHz crystal, so the PCM clock is 2x the incoming clock. * Other cards have a 49.152Mhz crystal, so the PCM clock equals * incoming clock. */ if ((b4->card_type == B410P) || (b4->card_type == QUADBRI_EVAL)) b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02); else b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK); flush_pci(); udelay(100); /* wait a bit for clock to settle */ } /* * Stage 2 hardware init. * Sets up the flow controller, PCM and FIFOs. * Initializes the echo cancellers. * S/T interfaces are not initialized here, that is done later, in hfc_init_all_st(). * Interrupts are enabled and once the s/t interfaces are configured, chip should be pretty much operational. */ static void b4xxp_init_stage2(struct b4xxp *b4) { int span; /* * set up PCM bus. * HFC is PCM master. * C4IO, SYNC_I and SYNC_O unused. * 32 channels, frame signal positive polarity, active for 2 C4 clocks. * only the first two timeslots in each quad are active * STIO0 is transmit-only, STIO1 is receive-only. */ b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1); flush_pci(); b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048); b4xxp_setreg8(b4, R_PWM_MD, 0xa0); b4xxp_setreg8(b4, R_PWM0, 0x1b); /* * set up the flow controller. * B channel map: (4 ports cards with Hardware Echo Cancel present & active) * FIFO 0 connects Port 1 B0 using HFC channel 16 and PCM timeslots 0/1. * FIFO 1 connects Port 1 B1 using HFC channel 17 and PCM timeslots 4/5. * FIFO 2 connects Port 2 B0 using HFC channel 20 and PCM timeslots 8/9. * FIFO 3 connects Port 2 B1 using HFC channel 21 and PCM timeslots 12/13. * FIFO 4 connects Port 3 B0 using HFC channel 24 and PCM timeslots 16/17. * FIFO 5 connects Port 3 B1 using HFC channel 25 and PCM timeslots 20/21. * FIFO 6 connects Port 4 B0 using HFC channel 28 and PCM timeslots 24/25. * FIFO 7 connects Port 4 B1 using HFC channel 29 and PCM timeslots 28/29. * * All B channel FIFOs have their HDLC controller in transparent mode, * and only the FIFO for B0 on each port has its interrupt operational. * * D channels are handled by FIFOs 8-11. * FIFO 8 connects Port 1 D using HFC channel 3 * FIFO 9 connects Port 2 D using HFC channel 7 * FIFO 10 connects Port 3 D using HFC channel 11 * FIFO 11 connects Port 4 D using HFC channel 15 * * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. * * B channel map: (8 ports cards without Hardware Echo Cancel) * FIFO 0 connects Port 1 B0 using HFC channel 0 * FIFO 1 connects Port 1 B1 using HFC channel 1 * FIFO 2 connects Port 2 B0 using HFC channel 4 * FIFO 3 connects Port 2 B1 using HFC channel 5 * ......................... * FIFO 14 connects Port 8 B0 using HFC channel 28 * FIFO 15 connects Port 8 B1 using HFC channel 29 * * All B channel FIFOs have their HDLC controller in transparent mode, * and only the FIFO for B0 on each port has its interrupt operational. * * D channels are handled by FIFOs 16-23. * FIFO 16 connects Port 1 D using HFC channel 3 * FIFO 17 connects Port 2 D using HFC channel 7 * FIFO 18 connects Port 3 D using HFC channel 11 * FIFO 19 connects Port 4 D using HFC channel 15 * ................ * FIFO 23 connects Port 8 D using HFC channel 31 * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. */ for (span=0; span < b4->numspans; span++) { if ((vpmsupport) && (CARD_HAS_EC(b4))) { hfc_assign_bchan_fifo_ec(b4, span, 0); hfc_assign_bchan_fifo_ec(b4, span, 1); } else { hfc_assign_bchan_fifo_noec(b4, span, 0); hfc_assign_bchan_fifo_noec(b4, span, 1); } hfc_assign_dchan_fifo(b4, span); } /* set up the timer interrupt for 1ms intervals */ b4xxp_setreg8(b4, R_TI_WD, (2 << V_EV_TS_SHIFT)); /* * At this point, everything's set up and ready to go. * Don't actually enable the global interrupt pin. * DAHDI still needs to start up the spans, and we don't know exactly when. */ } static void b4xxp_setleds(struct b4xxp *b4, unsigned char val) { ec_write(b4, 0, 0x1a8 + 3, val); } static void b4xxp_update_leds_hfc_8s(struct b4xxp *b4) { unsigned long lled = 0; /* A bit set is a led OFF */ unsigned long leddw; int j; struct b4xxp_span *bspan; b4->blinktimer++; for (j = 7; j >= 0; j--) { bspan = &b4->spans[7 - j]; if (!(bspan->span.flags & DAHDI_FLAG_RUNNING) || bspan->span.alarms) { BIT_SET(lled, j); continue; /* Led OFF */ } if (bspan->span.mainttimer || bspan->span.maintstat) { /* Led Blinking in maint state */ if (b4->blinktimer >= 0x7f) BIT_SET(lled, j); } /* Else: Led on */ } /* Write Leds...*/ leddw = lled << 24 | lled << 16 | lled << 8 | lled; b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x21); iowrite16(0x4000, b4->ioaddr + 4); iowrite32(leddw, b4->ioaddr); b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x20); if (b4->blinktimer == 0xff) b4->blinktimer = -1; } /* So far only tested for OpenVox cards. Please test it for other hardware */ static void b4xxp_update_leds_hfc(struct b4xxp *b4) { int i; int leds = 0, green_leds = 0; /* Default: off */ struct b4xxp_span *bspan; b4->blinktimer++; for (i=0; i < b4->numspans; i++) { bspan = &b4->spans[i]; if (!(bspan->span.flags & DAHDI_FLAG_RUNNING)) continue; /* Leds are off */ if (bspan->span.alarms) { /* Red blinking -> Alarm */ if (b4->blinktimer >= 0x7f) BIT_SET(leds, i); } else if (bspan->span.mainttimer || bspan->span.maintstat) { /* Green blinking -> Maint status */ if (b4->blinktimer >= 0x7f) BIT_SET(green_leds, i); } else { /* Steady grean -> No Alarm */ BIT_SET(green_leds, i); } } /* Actually set them. for red: just set the bit in R_GPIO_EN1. For green: in both R_GPIO_EN1 and R_GPIO_OUT1. */ leds |= green_leds; b4xxp_setreg8(b4, R_GPIO_EN1, leds); b4xxp_setreg8(b4, R_GPIO_OUT1, green_leds); if (b4->blinktimer == 0xff) b4->blinktimer = -1; } static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val) { int shift, spanmask; shift = span << 1; spanmask = ~(0x03 << shift); b4->ledreg &= spanmask; b4->ledreg |= (val << shift); b4xxp_setleds(b4, b4->ledreg); } static void b4xxp_update_leds(struct b4xxp *b4) { int i; struct b4xxp_span *bspan; if (b4->numspans == 8) { /* Use the alternative function for non-Digium HFC-8S cards */ b4xxp_update_leds_hfc_8s(b4); return; } if (b4->card_type != B410P) { /* Use the alternative function for non-Digium HFC-4S cards */ b4xxp_update_leds_hfc(b4); return; } b4->blinktimer++; for (i=0; i < b4->numspans; i++) { bspan = &b4->spans[i]; if (bspan->span.flags & DAHDI_FLAG_RUNNING) { if (bspan->span.alarms) { if (b4->blinktimer == (led_fader_table[b4->alarmpos] >> 1)) b4xxp_set_span_led(b4, i, LED_RED); if (b4->blinktimer == 0xf) b4xxp_set_span_led(b4, i, LED_OFF); } else if (bspan->span.mainttimer || bspan->span.maintstat) { if (b4->blinktimer == (led_fader_table[b4->alarmpos] >> 1)) b4xxp_set_span_led(b4, i, LED_GREEN); if (b4->blinktimer == 0xf) b4xxp_set_span_led(b4, i, LED_OFF); } else { /* No Alarm */ b4xxp_set_span_led(b4, i, LED_GREEN); } } else b4xxp_set_span_led(b4, i, LED_OFF); } if (b4->blinktimer == 0xf) { b4->blinktimer = -1; b4->alarmpos++; if (b4->alarmpos >= (sizeof(led_fader_table) / sizeof(led_fader_table[0]))) b4->alarmpos = 0; } } static const char *b4xxp_echocan_name(const struct dahdi_chan *chan) { struct b4xxp_span *bspan = container_of(chan->span, struct b4xxp_span, span); if (bspan->parent->card_type == B410P) return "LASVEGAS2"; return NULL; } static int b4xxp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct b4xxp_span *bspan = container_of(chan->span, struct b4xxp_span, span); int channel; if (!vpmsupport || !CARD_HAS_EC(bspan->parent)) return -ENODEV; if (chan->chanpos == 3) { printk(KERN_WARNING "Cannot enable echo canceller on D channel of span %d; failing request\n", chan->span->offset); return -EINVAL; } if (ecp->param_count > 0) { printk(KERN_WARNING "wcb4xxp echo canceller does not support parameters; failing request\n"); return -EINVAL; } *ec = &bspan->ec[chan->chanpos]; (*ec)->ops = &my_ec_ops; (*ec)->features = my_ec_features; if (DBG_EC) printk("Enabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset); channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1; ec_write(bspan->parent, chan->chanpos - 1, channel, 0x7e); return 0; } static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct b4xxp_span *bspan = container_of(chan->span, struct b4xxp_span, span); int channel; memset(ec, 0, sizeof(*ec)); if (DBG_EC) printk("Disabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset); channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1; ec_write(bspan->parent, chan->chanpos - 1, channel, 0x01); } /* * Filesystem and DAHDI interfaces */ static int b4xxp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { switch(cmd) { default: return -ENOTTY; } return 0; } static int b4xxp_startup(struct file *file, struct dahdi_span *span) { struct b4xxp_span *bspan = container_of(span, struct b4xxp_span, span); struct b4xxp *b4 = bspan->parent; if (!b4->running) hfc_enable_interrupts(bspan->parent); return 0; } static int b4xxp_shutdown(struct dahdi_span *span) { struct b4xxp_span *bspan = container_of(span, struct b4xxp_span, span); hfc_disable_interrupts(bspan->parent); return 0; } /* resets all the FIFOs for a given span. Disables IRQs for the span FIFOs */ static void b4xxp_reset_span(struct b4xxp_span *bspan) { int i; struct b4xxp *b4 = bspan->parent; for (i=0; i < 3; i++) { hfc_reset_fifo_pair(b4, bspan->fifos[i], (i == 2) ? 1 : 0, 1); } b4xxp_set_sync_src(b4, b4xxp_find_sync(b4)); } /* spanconfig for us means to set up the HFC FIFO and channel mapping */ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { int i; struct b4xxp_span *bspan = container_of(span, struct b4xxp_span, span); struct b4xxp *b4 = bspan->parent; if (DBG) dev_info(&b4->pdev->dev, "Configuring span %d offset %d to be sync %d\n", span->spanno, span->offset, lc->sync); #if 0 if (lc->sync > 0 && !bspan->te_mode) { dev_info(&b4->pdev->dev, "Span %d is not in NT mode, removing " "from sync source list\n", span->spanno); lc->sync = 0; } #endif if (lc->sync < 0 || lc->sync > 4) { dev_info(&b4->pdev->dev, "Span %d has invalid sync priority (%d), removing " "from sync source list\n", span->spanno, lc->sync); lc->sync = 0; } /* remove this span number from the current sync sources, if there */ for (i = 0; i < b4->numspans; i++) { if (b4->spans[i].sync == (span->offset + 1)) { b4->spans[i].sync = 0; } } if (lc->sync) b4->spans[lc->sync - 1].sync = (span->offset + 1); b4xxp_reset_span(bspan); /* call startup() manually here, because DAHDI won't call the startup function unless it receives an IOCTL to do so, and dahdi_cfg doesn't. */ b4xxp_startup(file, &bspan->span); span->flags |= DAHDI_FLAG_RUNNING; return 0; } /* chanconfig for us means to configure the HDLC controller, if appropriate */ static int b4xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { int alreadyrunning; struct b4xxp *b4 = chan->pvt; struct b4xxp_span *bspan = &b4->spans[chan->span->offset]; int fifo = bspan->fifos[2]; alreadyrunning = bspan->span.flags & DAHDI_FLAG_RUNNING; if (DBG_FOPS) { dev_info(&b4->pdev->dev, "%s channel %d (%s) sigtype %08x\n", alreadyrunning ? "Reconfigured" : "Configured", chan->channo, chan->name, sigtype); } /* (re)configure signalling channel */ if ((sigtype == DAHDI_SIG_HARDHDLC) || (bspan->sigchan == chan)) { if (DBG_FOPS) dev_info(&b4->pdev->dev, "%sonfiguring hardware HDLC on %s\n", ((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : "Unc"), chan->name); if (alreadyrunning && bspan->sigchan) { hdlc_stop(b4, fifo); atomic_set(&bspan->hdlc_pending, 0); bspan->sigactive = 0; smp_mb(); bspan->sigchan = NULL; } if (sigtype == DAHDI_SIG_HARDHDLC) { if (hdlc_start(b4, fifo)) { dev_warn(&b4->pdev->dev, "Error initializing signalling controller\n"); return -1; } } bspan->sigchan = (sigtype == DAHDI_SIG_HARDHDLC) ? chan : NULL; bspan->sigactive = 0; atomic_set(&bspan->hdlc_pending, 0); } else { /* FIXME: shouldn't I be returning an error? */ } return 0; } static int b4xxp_open(struct dahdi_chan *chan) { struct b4xxp *b4 = chan->pvt; struct b4xxp_span *bspan = &b4->spans[chan->span->offset]; if (DBG_FOPS && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "open() on chan %s (%i/%i)\n", chan->name, chan->channo, chan->chanpos); } hfc_reset_fifo_pair(b4, bspan->fifos[chan->chanpos - 1], 0, 0); return 0; } static int b4xxp_close(struct dahdi_chan *chan) { struct b4xxp *b4 = chan->pvt; struct b4xxp_span *bspan = &b4->spans[chan->span->offset]; if (DBG_FOPS && DBG_SPANFILTER) { dev_info(&b4->pdev->dev, "close() on chan %s (%i/%i)\n", chan->name, chan->channo, chan->chanpos); } hfc_reset_fifo_pair(b4, bspan->fifos[chan->chanpos - 1], 1, 1); return 0; } /* DAHDI calls this when it has data it wants to send to the HDLC controller */ static void b4xxp_hdlc_hard_xmit(struct dahdi_chan *chan) { struct b4xxp *b4 = chan->pvt; int span = chan->span->offset; struct b4xxp_span *bspan = &b4->spans[span]; if ((DBG_FOPS || DBG_HDLC) && DBG_SPANFILTER) dev_info(&b4->pdev->dev, "hdlc_hard_xmit on chan %s (%i/%i), span=%i\n", chan->name, chan->channo, chan->chanpos, span + 1); /* * increment the hdlc_pending counter and trigger the bottom-half so it * will be picked up and sent. */ if (bspan->sigchan == chan) { atomic_inc(&bspan->hdlc_pending); } } /* internal functions, not specific to the hardware or DAHDI */ static const struct dahdi_span_ops b4xxp_span_ops = { .owner = THIS_MODULE, .spanconfig = b4xxp_spanconfig, .chanconfig = b4xxp_chanconfig, .startup = b4xxp_startup, .shutdown = b4xxp_shutdown, .open = b4xxp_open, .close = b4xxp_close, .ioctl = b4xxp_ioctl, .hdlc_hard_xmit = b4xxp_hdlc_hard_xmit, .echocan_create = b4xxp_echocan_create, .echocan_name = b4xxp_echocan_name, }; /* initialize the span/chan structures. Doesn't touch hardware, although the callbacks might. */ static void init_spans(struct b4xxp *b4) { int i, j; struct b4xxp_span *bspan; struct dahdi_chan *chan; /* for each span on the card */ for (i=0; i < b4->numspans; i++) { bspan = &b4->spans[i]; bspan->parent = b4; bspan->span.irq = b4->pdev->irq; bspan->span.spantype = (bspan->te_mode) ? "TE" : "NT"; bspan->span.offset = i; bspan->span.channels = WCB4XXP_CHANNELS_PER_SPAN; bspan->span.flags = 0; if (!strcasecmp(companding, "ulaw")) bspan->span.deflaw = DAHDI_LAW_MULAW; else bspan->span.deflaw = DAHDI_LAW_ALAW; /* For simplicty, we'll accept all line modes since BRI * ignores this setting anyway.*/ bspan->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF | DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; sprintf(bspan->span.name, "B4/%d/%d", b4->cardno, i+1); sprintf(bspan->span.desc, "B4XXP (PCI) Card %d Span %d", b4->cardno, i+1); bspan->span.manufacturer = "Digium"; strlcpy(bspan->span.devicetype, b4->variety, sizeof(bspan->span.devicetype)); sprintf(bspan->span.location, "PCI Bus %02d Slot %02d", b4->pdev->bus->number, PCI_SLOT(b4->pdev->devfn) + 1); bspan->span.ops = &b4xxp_span_ops; /* HDLC stuff */ bspan->sigchan = NULL; bspan->sigactive = 0; bspan->span.chans = bspan->chans; /* now initialize each channel in the span */ for (j=0; j < WCB4XXP_CHANNELS_PER_SPAN; j++) { bspan->chans[j] = &bspan->_chans[j]; chan = bspan->chans[j]; chan->pvt = b4; sprintf(chan->name, "B4/%d/%d/%d", b4->cardno, i + 1, j + 1); /* The last channel in the span is the D-channel */ if (j == WCB4XXP_CHANNELS_PER_SPAN - 1) { chan->sigcap = DAHDI_SIG_HARDHDLC; } else { chan->sigcap = DAHDI_SIG_CLEAR | DAHDI_SIG_DACS; } chan->chanpos = j + 1; chan->writechunk = (void *)(bspan->writechunk + j * DAHDI_CHUNKSIZE); chan->readchunk = (void *)(bspan->readchunk + j * DAHDI_CHUNKSIZE); } } } static void b4xxp_bottom_half(unsigned long data); /* top-half interrupt handler */ DAHDI_IRQ_HANDLER(b4xxp_interrupt) { struct b4xxp *b4 = dev_id; unsigned char status; int i; /* Make sure it's really for us */ status = __pci_in8(b4, R_STATUS); if (!(status & HFC_INTS)) return IRQ_NONE; /* * since the interrupt is for us, read in the FIFO and misc IRQ status registers. * Don't replace the struct copies; OR in the new bits instead. * That way if we get behind, we don't lose anything. * We don't actually do any processing here, we simply flag the bottom-half to do the heavy lifting. */ if (status & V_FR_IRQSTA) { b4->fifo_irqstatus[0] |= __pci_in8(b4, R_IRQ_FIFO_BL0); b4->fifo_irqstatus[1] |= __pci_in8(b4, R_IRQ_FIFO_BL1); b4->fifo_irqstatus[2] |= __pci_in8(b4, R_IRQ_FIFO_BL2); b4->fifo_irqstatus[3] |= __pci_in8(b4, R_IRQ_FIFO_BL3); b4->fifo_irqstatus[4] |= __pci_in8(b4, R_IRQ_FIFO_BL4); b4->fifo_irqstatus[5] |= __pci_in8(b4, R_IRQ_FIFO_BL5); b4->fifo_irqstatus[6] |= __pci_in8(b4, R_IRQ_FIFO_BL6); b4->fifo_irqstatus[7] |= __pci_in8(b4, R_IRQ_FIFO_BL7); } if (status & V_MISC_IRQSTA) { b4->misc_irqstatus |= __pci_in8(b4, R_IRQ_MISC); } /* * Well, that was the plan. It appears that I can't do this in the bottom half * or I start to see data corruption (too long a time between IRQ and tasklet??) * So, I do the B-channel stuff right here in interrupt context. yuck. */ if (b4->misc_irqstatus & V_TI_IRQ) { hfc_poll_fifos(b4); for (i=0; i < b4->numspans; i++) { if (b4->spans[i].span.flags & DAHDI_FLAG_RUNNING) { dahdi_ec_span(&b4->spans[i].span); dahdi_receive(&b4->spans[i].span); dahdi_transmit(&b4->spans[i].span); } } } /* kick off bottom-half handler */ /* tasklet_hi_schedule(&b4->b4xxp_tlet); */ b4xxp_bottom_half((unsigned long)b4); return IRQ_RETVAL(1); } /* * The bottom half of course does all the heavy lifting for the interrupt. * * The original plan was to have the B channel RX FIFO interrupts enabled, and * to do the actual work here. Since that doesn't seem to work so well, we * poll the B channel FIFOs right in the interrupt handler and take care of the B * channel stuff there. The bottom half works for the timer interrupt and D * channel stuff. * * The HFC-4S timer interrupt is used to for several things: * - Update the S/T state machines, expire their timers, etc. * - Provide DAHDI's timing source, if so configured * - Update LEDs */ static void b4xxp_bottom_half(unsigned long data) { struct b4xxp *b4 = (struct b4xxp *)data; int i, j, k, fifo, fifo_low, fifo_high; unsigned char b, b2; if (b4->shutdown) return; /* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */ if (b4->numspans == 8) { fifo_low = 16; fifo_high = 23; } else { fifo_low = 8; fifo_high = 11; } for (i=0; i < 8; i++) { b = b2 = b4->fifo_irqstatus[i]; for (j=0; j < b4->numspans; j++) { fifo = i*4 + j; if (b & V_IRQ_FIFOx_TX) { if (fifo >= fifo_low && fifo <= fifo_high) { /* d-chan fifos */ /* * WOW I don't like this. * It's bad enough that I have to send a fake frame to get an HDLC TX FIFO interrupt, * but now, I have to loop until the whole frame is read, or I get RX interrupts * (even though the chip says HDLC mode gives an IRQ when a *full frame* is received). * Yuck. It works well, but yuck. */ do { k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]); } while (k); } else { if (printk_ratelimit()) dev_warn(&b4->pdev->dev, "Got FIFO TX int from non-d-chan FIFO %d??\n", fifo); } } if (b & V_IRQ_FIFOx_RX) { if (fifo >= fifo_low && fifo <= fifo_high) { /* dchan fifos */ /* * I have to loop here until hdlc_rx_frame says there are no more frames waiting. * for whatever reason, the HFC will not generate another interrupt if there are * still HDLC frames waiting to be received. * i.e. I get an int when F1 changes, not when F1 != F2. */ do { k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]); } while (k); } else { if (printk_ratelimit()) dev_warn(&b4->pdev->dev, "Got FIFO RX int from non-d-chan FIFO %d??\n", fifo); } } b >>= 2; } /* zero the bits we just processed */ b4->fifo_irqstatus[i] &= ~b2; } /* * timer interrupt * every tick (1ms), check the FIFOs and run through the S/T port timers. * every 100ms or so, look for S/T state machine changes. */ if (b4->misc_irqstatus & V_TI_IRQ) { /* * We should check the FIFOs here, but I'm seeing this tasklet getting scheduled FAR too late to be useful. * For now, we're handling that in the IRQ handler itself. (ICK!!) */ b4->ticks++; hfc_update_st_timers(b4); b4xxp_update_leds(b4); /* every 100ms or so, look at the S/T interfaces to see if they changed state */ if (!(b4->ticks % 100)) { b = b4xxp_getreg8(b4, R_SCI); if (b) { for (i=0; i < b4->numspans; i++) { if (b & (1 << i)) hfc_handle_state(&b4->spans[i]); } } } /* We're supposed to kick DAHDI here, too, but again, seeing too much latency between the interrupt and the bottom-half. */ /* clear the timer interrupt flag. */ b4->misc_irqstatus &= ~V_TI_IRQ; } /* * Check for outgoing HDLC frame requests * The HFC does not generate TX interrupts when there is room to send, so * I use an atomic counter that is incremented every time DAHDI wants to send * a frame, and decremented every time I send a frame. It'd be better if I could * just use the interrupt handler, but the HFC seems to trigger a FIFO TX IRQ * only when it has finished sending a frame, not when one can be sent. */ for (i=0; i < b4->numspans; i++) { struct b4xxp_span *bspan = &b4->spans[i]; if (atomic_read(&bspan->hdlc_pending)) { do { k = hdlc_tx_frame(bspan); } while (k); } } } /********************************************************************************* proc stuff *****/ #ifdef CREATE_WCB4XXP_PROCFS_ENTRY static int b4xxp_proc_read_one(char *buf, struct b4xxp *b4) { struct dahdi_chan *chan; int len, i, j; char str[80], sBuf[4096]; *sBuf=0; sprintf(sBuf, "Card %d, PCI identifier %s, IRQ %d\n", b4->cardno + 1, b4->pdev->dev.bus_id, b4->irq); strcat(sBuf,"Tx:\n"); for (j=0; j<(b4->numspans * 2) ; j++) { /* B Channels */ for (i=0; i<(b4->numspans * 3) ; i++) { /* All Channels */ chan = b4->spans[i/3].chans[i%3]; sprintf(str, "%02x ", chan->writechunk[j]); strcat(sBuf, str); } strcat(sBuf, "\n"); } strcat(sBuf, "\nRx:\n"); for (j=0; j < (b4->numspans * 2); j++) { /* B Channels */ for (i=0; i < (b4->numspans * 3); i++) { /* All Channels */ chan = b4->spans[i / 3].chans[i % 3]; sprintf(str, "%02x%c", chan->readchunk[j], (i == 11) ? '\n' : ' '); strcat(sBuf, str); } } strcat(sBuf, "\nPort states:\n"); for (i=0; i < b4->numspans; i++) { int state; char *x; struct b4xxp_span *s = &b4->spans[i]; state = b4xxp_getreg_ra(b4, R_ST_SEL, s->port, A_ST_RD_STA); x = hfc_decode_st_state(b4, s->port, state, 0); sprintf(str, "%s\n", x); strcat(sBuf, str); kfree(x); } len = sprintf(buf, "%s\n%s\nTicks: %ld\n", sBuf, str, b4->ticks); return len; } static int b4xxp_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data) { struct b4xxp **b4_cards = data; char sBuf[256]; int i, len; len = sprintf(buf, "WCB4XXP Card Information\n"); for (i=0; b4_cards[i] != NULL; i++) { if (i) len += sprintf(buf + len, "\n-----\n"); len += b4xxp_proc_read_one(buf + len, b4_cards[i]); } *sBuf = 0; strcat(sBuf, "\n-----\n\nAudio: "); #ifdef LOOPBACK_SUPPORTED if (loopback >= 3) strcat(sBuf, "DAHDI and S/T"); else if (loopback == 2) strcat(sBuf, "DAHDI"); else if (loopback == 1) strcat(sBuf, "S/T"); else strcat(sBuf, "not"); strcat(sBuf, " looped back"); #else strcat(sBuf, "not looped back"); #endif if (milliwatt) strcat(sBuf, ", outgoing S/T replaced with mu-law milliwatt tone"); len += sprintf(buf + len, "%s\n", sBuf); if (alarmdebounce) sprintf(sBuf, "Alarms: debounced (%dms)", alarmdebounce); else strcpy(sBuf, "Alarms: not debounced"); len += sprintf(buf + len, "%s\nT1 timer period %dms\nT3 timer period %dms\n", sBuf, timer_1_ms, timer_3_ms); *eof = 1; return len; } #endif /* CREATE_WCB4XXP_PROCFS_ENTRY */ static int b4xxp_startdefaultspan(struct b4xxp *b4) { struct dahdi_lineconfig lc = {0,}; return b4xxp_spanconfig(NULL, &b4->spans[0].span, &lc); } static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int x, ret; struct b4xxp *b4; struct devtype *dt; dt = (struct devtype *)(ent->driver_data); dev_info(&pdev->dev, "probe called for b4xx...\n"); if ((ret = pci_enable_device(pdev))) goto err_out_disable_pdev; if ((ret = pci_request_regions(pdev, dt->desc))) { dev_err(&pdev->dev, "Unable to request regions!\n"); goto err_out_disable_pdev; } if (!pdev->irq) { /* we better have an IRQ */ dev_err(&pdev->dev, "Device has no associated IRQ?\n"); ret = -EIO; goto err_out_release_regions; } if (!(b4 = kzalloc(sizeof(struct b4xxp), GFP_KERNEL))) { dev_err(&pdev->dev, "Couldn't allocate memory for b4xxp structure!\n"); ret = -ENOMEM; goto err_out_release_regions; } /* card found, enabled and main struct allocated. Fill it out. */ b4->variety = dt->desc; b4->card_type = dt->card_type; b4->pdev = pdev; pci_set_drvdata(pdev, b4); b4->ioaddr = pci_iomap(pdev, 0, 0); b4->addr = pci_iomap(pdev, 1, 0); b4->irq = pdev->irq; spin_lock_init(&b4->reglock); spin_lock_init(&b4->seqlock); spin_lock_init(&b4->fifolock); x = b4xxp_getreg8(b4, R_CHIP_ID); if ((x != 0xc0) && (x != 0x80)) { /* wrong chip? */ dev_err(&pdev->dev, "Unknown/unsupported controller detected (R_CHIP_ID = 0x%02x)\n", x); goto err_out_free_mem; } /* future proofing */ b4->chiprev = b4xxp_getreg8(b4, R_CHIP_RV); /* check for various board-specific flags and modify init as necessary */ /* if (dt->flags & FLAG_XXX) use_flag_somehow(); */ /* TODO: determine whether this is a 2, 4 or 8 port card */ b4->numspans = dt->ports; b4->syncspan = -1; /* sync span is unknown */ if (b4->numspans > MAX_SPANS_PER_CARD) { dev_err(&b4->pdev->dev, "Driver does not know how to handle a %d span card!\n", b4->numspans); goto err_out_free_mem; } dev_info(&b4->pdev->dev, "Identified %s (controller rev %d) at %p, IRQ %i\n", b4->variety, b4->chiprev, b4->ioaddr, b4->irq); /* look for the next free card structure */ for (x=0; x < MAX_B4_CARDS; x++) { if (!cards[x]) break; } if (x >= MAX_B4_CARDS) { dev_err(&pdev->dev, "Attempt to register more than %i cards, aborting!\n", MAX_B4_CARDS); goto err_out_free_mem; } /* update the cards array, make sure the b4xxp struct knows where in the array it is */ b4->cardno = x; cards[x] = b4; b4xxp_init_stage1(b4); create_sysfs_files(b4); if (request_irq(pdev->irq, b4xxp_interrupt, DAHDI_IRQ_SHARED_DISABLED, "b4xxp", b4)) { dev_err(&b4->pdev->dev, "Unable to request IRQ %d\n", pdev->irq); ret = -EIO; goto err_out_del_from_card_array; } /* initialize the tasklet structure */ /* TODO: perhaps only one tasklet for any number of cards in the system... don't need one per card I don't think. */ tasklet_init(&b4->b4xxp_tlet, b4xxp_bottom_half, (unsigned long)b4); /* interrupt allocated and tasklet initialized, it's now safe to finish initializing the hardware */ b4xxp_init_stage2(b4); hfc_init_all_st(b4); /* initialize the DAHDI structures, and let DAHDI know it has some new hardware to play with */ init_spans(b4); for (x=0; x < b4->numspans; x++) { if (dahdi_register(&b4->spans[x].span, 0)) { dev_err(&b4->pdev->dev, "Unable to register span %s\n", b4->spans[x].span.name); goto err_out_unreg_spans; } } #if 0 /* Launch cards as appropriate */ for (;;) { /* Find a card to activate */ f = 0; for (x=0; cards[x]; x++) { if (cards[x]->order <= highestorder) { b4_launch(cards[x]); if (cards[x]->order == highestorder) f = 1; } } /* If we found at least one, increment the highest order and search again, otherwise stop */ if (f) highestorder++; else break; } #else dev_info(&b4->pdev->dev, "Did not do the highestorder stuff\n"); #endif ret = b4xxp_startdefaultspan(b4); if (ret) goto err_out_unreg_spans; ret = 0; return ret; /* 'x' will have the failing span #. (0-3). We need to unregister everything before it. */ err_out_unreg_spans: while (x) { dahdi_unregister(&b4->spans[x].span); x--; }; b4xxp_init_stage1(b4); /* full reset, re-init to "no-irq" state */ free_irq(pdev->irq, b4); err_out_del_from_card_array: for (x=0; x < MAX_B4_CARDS; x++) { if (cards[x] == b4) { b4->cardno = -1; cards[x] = NULL; break; } } if (x >= MAX_B4_CARDS) dev_err(&pdev->dev, "b4 struct @ %p should be in cards array but isn't?!\n", b4); err_out_free_mem: pci_set_drvdata(pdev, NULL); pci_iounmap(pdev, b4->ioaddr); pci_iounmap(pdev, b4->addr); kfree(b4); err_out_release_regions: pci_release_regions(pdev); err_out_disable_pdev: pci_disable_device(pdev); return ret; } static void __devexit b4xxp_remove(struct pci_dev *pdev) { struct b4xxp *b4 = pci_get_drvdata(pdev); int i; if (b4) { b4->shutdown = 1; for (i=b4->numspans - 1; i >= 0; i--) { dahdi_unregister(&b4->spans[i].span); } b4xxp_init_stage1(b4); remove_sysfs_files(b4); free_irq(pdev->irq, b4); pci_set_drvdata(pdev, NULL); pci_iounmap(pdev, b4->ioaddr); pci_iounmap(pdev, b4->addr); pci_release_regions(pdev); pci_disable_device(pdev); b4->ioaddr = b4->addr = NULL; tasklet_kill(&b4->b4xxp_tlet); kfree(b4); } dev_info(&pdev->dev, "Driver unloaded.\n"); return; } static DEFINE_PCI_DEVICE_TABLE(b4xx_ids) = { { 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp }, { 0x1397, 0x16b8, 0x1397, 0xb552, 0, 0, (unsigned long)&hfc8s }, { 0x1397, 0x16b8, 0x1397, 0xb55b, 0, 0, (unsigned long)&hfc8s }, { 0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s }, { 0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s }, { 0x1397, 0x08b4, 0x1397, 0xb752, 0, 0, (unsigned long)&hfc4s }, { 0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s }, { 0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV }, { 0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV }, { 0x1397, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV }, { 0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN }, { 0x1397, 0x08b4, 0x1397, 0xb761, 0, 0, (unsigned long)&hfc2s_BN }, { 0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN }, { 0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s_BN }, { 0x1397, 0x08b4, 0x1397, 0xb762, 0, 0, (unsigned long)&hfc4s_BN }, { 0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN }, { 0x1397, 0x16b8, 0x1397, 0xb56b, 0, 0, (unsigned long)&hfc8s_BN }, { 0x1397, 0x08b4, 0x1397, 0xb540, 0, 0, (unsigned long)&hfc4s_SW }, { 0x1397, 0x08b4, 0x1397, 0x08b4, 0, 0, (unsigned long)&hfc4s_EV }, {0, } }; static int b4xx_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } static struct pci_driver b4xx_driver = { .name = "wcb4xxp", .probe = b4xx_probe, .remove = __devexit_p(b4xxp_remove), .id_table = b4xx_ids, .suspend = b4xx_suspend, }; static int __init b4xx_init(void) { #ifdef CREATE_WCB4XXP_PROCFS_ENTRY if (!(myproc = create_proc_read_entry(PROCFS_NAME, 0444, NULL, b4xxp_proc_read, cards))) { printk(KERN_ERR "%s: ERROR: Could not initialize /proc/%s\n",THIS_MODULE->name, PROCFS_NAME); } #endif if (dahdi_pci_module(&b4xx_driver)) return -ENODEV; return 0; } static void __exit b4xx_exit(void) { #ifdef CREATE_WCB4XXP_PROCFS_ENTRY remove_proc_entry(PROCFS_NAME, NULL); #endif pci_unregister_driver(&b4xx_driver); } module_param(debug, int, S_IRUGO | S_IWUSR); module_param(spanfilter, int, S_IRUGO | S_IWUSR); #ifdef LOOPBACK_SUPPORTED module_param(loopback, int, S_IRUGO | S_IWUSR); #endif module_param(milliwatt, int, S_IRUGO | S_IWUSR); module_param(pedanticpci, int, S_IRUGO); module_param(teignorered, int, S_IRUGO | S_IWUSR); module_param(alarmdebounce, int, S_IRUGO | S_IWUSR); module_param(vpmsupport, int, S_IRUGO); module_param(timer_1_ms, int, S_IRUGO | S_IWUSR); module_param(timer_3_ms, int, S_IRUGO | S_IWUSR); module_param(companding, charp, S_IRUGO); MODULE_PARM_DESC(debug, "bitmap: 1=general 2=dtmf 4=regops 8=fops 16=ec 32=st state 64=hdlc 128=alarm"); MODULE_PARM_DESC(spanfilter, "debug filter for spans. bitmap: 1=port 1, 2=port 2, 4=port 3, 8=port 4"); #ifdef LOOPBACK_SUPPORTED MODULE_PARM_DESC(loopback, "TODO: bitmap: 1=loop back S/T port 2=loop back DAHDI"); #endif MODULE_PARM_DESC(milliwatt, "1=replace outgoing S/T data with mu-law milliwatt"); MODULE_PARM_DESC(pedanticpci, "1=disable PCI back-to-back transfers and flush all PCI writes immediately"); MODULE_PARM_DESC(teignorered, "1=ignore (do not inform DAHDI) if a red alarm exists in TE mode"); MODULE_PARM_DESC(alarmdebounce, "msec to wait before set/clear alarm condition"); MODULE_PARM_DESC(vpmsupport, "1=enable hardware EC, 0=disable hardware EC"); MODULE_PARM_DESC(timer_1_ms, "NT: msec to wait for link activation, TE: unused."); MODULE_PARM_DESC(timer_3_ms, "TE: msec to wait for link activation, NT: unused."); MODULE_PARM_DESC(companding, "Change the companding to \"alaw\" or \"ulaw\""\ "(alaw by default)"); MODULE_AUTHOR("Digium Incorporated "); MODULE_DESCRIPTION("B410P & Similars multi-port BRI module driver."); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, b4xx_ids); module_init(b4xx_init); module_exit(b4xx_exit); dahdi-linux-2.5.0.1/drivers/dahdi/wcb4xxp/wcb4xxp.h0000644000175000017500000004767711503731461021733 0ustar tzafrirtzafrir/* * Wilcard B410P Quad-BRI Interface Driver for Zapata Telephony interface * Written by Andrew Kohlsmith */ #ifndef _B4XX_H_ #define _B4XX_H_ #include #define HFC_NR_FIFOS 32 #define HFC_ZMIN 0x80 /* from datasheet */ #define HFC_ZMAX 0x1ff #define HFC_FMIN 0x00 #define HFC_FMAX 0x0f /* * yuck. Any reg which is not mandated read/write or read-only is write-only. * Also, there are dozens of registers with the same address. * Additionally, there are array registers (A_) which have an index register * These A_ registers require an index register to be written to indicate WHICH in the array you want. */ #define R_CIRM 0x00 /* WO */ #define R_CTRL 0x01 /* WO */ #define R_BRG_PCM_CFG 0x02 /* WO */ #define A_Z12 0x04 /* RO */ #define A_Z1L 0x04 /* RO */ #define A_Z1 0x04 /* RO */ #define A_Z1H 0x05 /* RO */ #define A_Z2L 0x06 /* RO */ #define A_Z2 0x06 /* RO */ #define A_Z2H 0x07 /* RO */ #define R_RAM_ADDR0 0x08 /* WO */ #define R_RAM_ADDR1 0x09 /* WO */ #define R_RAM_ADDR2 0x0a /* WO */ #define R_FIRST_FIFO 0x0b /* WO */ #define R_RAM_MISC 0x0c /* WO */ #define A_F1 0x0c /* RO */ #define A_F12 0x0c /* RO */ #define R_FIFO_MD 0x0d /* WO */ #define A_F2 0x0d /* RO */ #define A_INC_RES_FIFO 0x0e /* WO */ #define R_FSM_IDX 0x0f /* WO */ #define R_FIFO 0x0f /* WO */ #define R_SLOT 0x10 /* WO */ #define R_IRQ_OVIEW 0x10 /* RO */ #define R_IRQMSK_MISC 0x11 /* WO */ #define R_IRQ_MISC 0x11 /* RO */ #define R_SCI_MSK 0x12 /* WO */ #define R_SCI 0x12 /* RO */ #define R_IRQ_CTRL 0x13 /* WO */ #define R_PCM_MD0 0x14 /* WO */ #define R_CONF_OFLOW 0x14 /* RO */ #define R_PCM_MD1 0x15 /* WO */ #define R_PCM_MD2 0x15 /* WO */ #define R_SH0H 0x15 /* WO */ #define R_SH1H 0x15 /* WO */ #define R_SH0L 0x15 /* WO */ #define R_SH1L 0x15 /* WO */ #define R_SL_SEL0 0x15 /* WO */ #define R_SL_SEL1 0x15 /* WO */ #define R_SL_SEL2 0x15 /* WO */ #define R_SL_SEL3 0x15 /* WO */ #define R_SL_SEL4 0x15 /* WO */ #define R_SL_SEL5 0x15 /* WO */ #define R_SL_SEL6 0x15 /* WO */ #define R_SL_SEL7 0x15 /* WO */ #define R_RAM_USE 0x15 /* RO */ #define R_ST_SEL 0x16 /* WO */ #define R_CHIP_ID 0x16 /* RO */ #define R_ST_SYNC 0x17 /* WO */ #define R_BERT_STA 0x17 /* RO */ #define R_CONF_EN 0x18 /* WO */ #define R_F0_CNTL 0x18 /* RO */ #define R_F0_CNTH 0x19 /* RO */ #define R_TI_WD 0x1a /* WO */ #define R_BERT_ECL 0x1a /* RO */ #define R_BERT_WD_MD 0x1b /* WO */ #define R_BERT_ECH 0x1b /* RO */ #define R_DTMF 0x1c /* WO */ #define R_STATUS 0x1c /* RO */ #define R_DTMF_N 0x1d /* WO */ #define R_CHIP_RV 0x1f /* RO */ #define A_ST_WR_STA 0x30 /* WO */ #define A_ST_RD_STA 0x30 /* RO */ #define A_ST_CTRL0 0x31 /* WO */ #define A_ST_CTRL1 0x32 /* WO */ #define A_ST_CTRL2 0x33 /* WO */ #define A_ST_SQ_WR 0x34 /* WO */ #define A_ST_SQ_RD 0x34 /* RO */ #define A_ST_CLK_DLY 0x37 /* WO */ #define R_PWM0 0x38 /* WO */ #define R_PWM1 0x39 /* WO */ #define A_ST_B1_TX 0x3c /* WO */ #define A_ST_B1_RX 0x3c /* RO */ #define A_ST_B2_TX 0x3d /* WO */ #define A_ST_B2_RX 0x3d /* RO */ #define A_ST_D_TX 0x3e /* WO */ #define A_ST_D_RX 0x3e /* RO */ #define A_ST_E_RX 0x3f /* RO */ #define R_GPIO_OUT0 0x40 /* WO */ #define R_GPIO_IN0 0x40 /* RO */ #define R_GPIO_OUT1 0x41 /* WO */ #define R_GPIO_IN1 0x41 /* RO */ #define R_GPIO_EN0 0x42 /* WO */ #define R_GPIO_EN1 0x43 /* WO */ #define R_GPIO_SEL 0x44 /* WO */ #define R_GPI_IN0 0x44 /* RO */ #define R_GPI_IN1 0x45 /* RO */ #define R_PWM_MD 0x46 /* WO */ #define R_GPI_IN2 0x46 /* RO */ #define R_GPI_IN3 0x47 /* RO */ #define A_FIFO_DATA2 0x80 /* RW */ #define A_FIFO_DATA0 0x80 /* RW */ #define A_FIFO_DATA1 0x80 /* RW */ #define A_FIFO_DATA2_NOINC 0x84 /* WO */ #define A_FIFO_DATA0_NOINC 0x84 /* WO */ #define A_FIFO_DATA1_NOINC 0x84 /* WO */ #define R_INT_DATA 0x88 /* RO */ #define R_RAM_DATA 0xc0 /* RW */ #define R_IRQ_FIFO_BL0 0xc8 /* RO */ #define R_IRQ_FIFO_BL1 0xc9 /* RO */ #define R_IRQ_FIFO_BL2 0xca /* RO */ #define R_IRQ_FIFO_BL3 0xcb /* RO */ #define R_IRQ_FIFO_BL4 0xcc /* RO */ #define R_IRQ_FIFO_BL5 0xcd /* RO */ #define R_IRQ_FIFO_BL6 0xce /* RO */ #define R_IRQ_FIFO_BL7 0xcf /* RO */ #define A_SL_CFG 0xd0 /* WO */ #define A_CONF 0xd1 /* WO */ #define A_CH_MSK 0xf4 /* WO */ #define A_CON_HDLC 0xfa /* WO */ #define A_SUBCH_CFG 0xfb /* WO */ #define A_CHANNEL 0xfc /* WO */ #define A_FIFO_SEQ 0xfd /* WO */ #define A_IRQ_MSK 0xff /* WO */ /* R_CIRM bits */ #define V_SRES (1 << 3) /* soft reset (group 0) */ #define V_HFC_RES (1 << 4) /* HFC reset (group 1) */ #define V_PCM_RES (1 << 5) /* PCM reset (group 2) */ #define V_ST_RES (1 << 6) /* S/T reset (group 3) */ #define V_RLD_EPR (1 << 7) /* EEPROM reload */ #define HFC_FULL_RESET (V_SRES | V_HFC_RES | V_PCM_RES | V_ST_RES | V_RLD_EPR) /* A_IRQ_MSK bits */ #define V_IRQ (1 << 0) /* FIFO interrupt enable */ #define V_BERT_EN (1 << 1) /* enable BERT */ #define V_MIX_IRQ (1 << 2) /* mixed interrupt enable (frame + transparent mode) */ /* R_STATUS bits */ #define V_BUSY (1 << 0) /* 1=HFC busy, limited register access */ #define V_PROC (1 << 1) /* 1=HFC in processing phase */ #define V_LOST_STA (1 << 3) /* 1=frames have been lost */ #define V_SYNC_IN (1 << 4) /* level on SYNC_I pin */ #define V_EXT_IRQSTA (1 << 5) /* 1=external interrupt */ #define V_MISC_IRQSTA (1 << 6) /* 1=misc interrupt has occurred */ #define V_FR_IRQSTA (1 << 7) /* 1=fifo interrupt has occured */ #define HFC_INTS (V_EXT_IRQSTA | V_MISC_IRQSTA | V_FR_IRQSTA) /* R_SCI/R_SCI_MSK bits */ #define V_SCI_ST0 (1 << 0) /* state change for port 1 */ #define V_SCI_ST1 (1 << 1) /* state change for port 2 */ #define V_SCI_ST2 (1 << 2) /* state change for port 3 */ #define V_SCI_ST3 (1 << 3) /* state change for port 4 */ /* R_IRQ_FIFO_BLx bits */ #define V_IRQ_FIFOx_TX (1 << 0) /* FIFO TX interrupt occurred */ #define V_IRQ_FIFOx_RX (1 << 1) /* FIFO RX interrupt occurred */ #define IRQ_FIFOx_TXRX (V_IRQ_FIFOx_TX | V_IRQ_FIFOx_RX) /* R_IRQ_MISC / R_IRQMSK_MISC bits */ #define V_TI_IRQ (1 << 1) /* timer elapsed */ #define V_IRQ_PROC (1 << 2) /* processing/non-processing transition */ #define V_DTMF_IRQ (1 << 3) /* DTMF detection completed */ #define V_EXT_IRQ (1 << 5) /* external interrupt occured */ /* R_IRQ_CTRL bits */ #define V_FIFO_IRQ (1 << 0) /* enable any unmasked FIFO IRQs */ #define V_GLOB_IRQ_EN (1 << 3) /* enable any unmasked IRQs */ #define V_IRQ_POL (1 << 4) /* 1=IRQ active high */ /* R_BERT_WD_MD bits */ #define V_BERT_ERR (1 << 3) /* 1=generate an error bit in BERT stream */ #define V_AUTO_WD_RES (1 << 5) /* 1=automatically kick the watchdog */ #define V_WD_RES (1 << 7) /* 1=kick the watchdog (bit auto clears) */ /* R_TI_WS bits */ #define V_EV_TS_SHIFT (0) #define V_EV_TS_MASK (0x0f) #define V_WD_TS_SHIFT (4) #define V_WD_TS_MASK (0xf0) /* R_BRG_PCM_CFG bits */ #define V_PCM_CLK (1 << 5) /* 1=PCM clk = OSC, 0 = PCM clk is 2x OSC */ /* R_PCM_MD0 bits */ #define V_PCM_MD (1 << 0) /* 1=PCM master */ #define V_C4_POL (1 << 1) /* 1=F0IO sampled on rising edge of C4IO */ #define V_F0_NEG (1 << 2) /* 1=negative polarity of F0IO */ #define V_F0_LEN (1 << 3) /* 1=F0IO active for 2 C4IO clocks */ #define V_PCM_IDX_SEL0 (0x0 << 4) /* reg15 = R_SL_SEL0 */ #define V_PCM_IDX_SEL1 (0x1 << 4) /* reg15 = R_SL_SEL1 */ #define V_PCM_IDX_SEL2 (0x2 << 4) /* reg15 = R_SL_SEL2 */ #define V_PCM_IDX_SEL3 (0x3 << 4) /* reg15 = R_SL_SEL3 */ #define V_PCM_IDX_SEL4 (0x4 << 4) /* reg15 = R_SL_SEL4 */ #define V_PCM_IDX_SEL5 (0x5 << 4) /* reg15 = R_SL_SEL5 */ #define V_PCM_IDX_SEL6 (0x6 << 4) /* reg15 = R_SL_SEL6 */ #define V_PCM_IDX_SEL7 (0x7 << 4) /* reg15 = R_SL_SEL7 */ #define V_PCM_IDX_MD1 (0x9 << 4) /* reg15 = R_PCM_MD1 */ #define V_PCM_IDX_MD2 (0xa << 4) /* reg15 = R_PCM_MD2 */ #define V_PCM_IDX_SH0L (0xc << 4) /* reg15 = R_SH0L */ #define V_PCM_IDX_SH0H (0xd << 4) /* reg15 = R_SH0H */ #define V_PCM_IDX_SH1L (0xe << 4) /* reg15 = R_SH1L */ #define V_PCM_IDX_SH1H (0xf << 4) /* reg15 = R_SH1H */ #define V_PCM_IDX_MASK (0xf0) /* R_PCM_MD1 bits */ #define V_CODEC_MD (1 << 0) /* no damn idea */ #define V_PLL_ADJ_00 (0x0 << 2) /* adj 4 times by 0.5 system clk cycles */ #define V_PLL_ADJ_01 (0x1 << 2) /* adj 3 times by 0.5 system clk cycles */ #define V_PLL_ADJ_10 (0x2 << 2) /* adj 2 times by 0.5 system clk cycles */ #define V_PLL_ADJ_11 (0x3 << 2) /* adj 1 time by 0.5 system clk cycles */ #define V_PCM_DR_2048 (0x0 << 4) /* 2.048Mbps, 32 timeslots */ #define V_PCM_DR_4096 (0x1 << 4) /* 4.096Mbps, 64 timeslots */ #define V_PCM_DR_8192 (0x2 << 4) /* 8.192Mbps, 128 timeslots */ #define V_PCM_LOOP (1 << 6) /* 1=internal loopback */ #define V_PLL_ADJ_MASK (0x3 << 2) #define V_PCM_DR_MASK (0x3 << 4) /* A_SL_CFG bits */ #define V_CH_SDIR (1 << 0) /* 1=HFC channel receives data from PCM TS */ #define V_ROUT_TX_DIS (0x0 << 6) /* disabled, output disabled */ #define V_ROUT_TX_LOOP (0x1 << 6) /* internally looped, output disabled */ #define V_ROUT_TX_STIO1 (0x2 << 6) /* output data to STIO1 */ #define V_ROUT_TX_STIO2 (0x3 << 6) /* output data to STIO2 */ #define V_ROUT_RX_DIS (0x0 << 6) /* disabled, input data ignored */ #define V_ROUT_RX_LOOP (0x1 << 6) /* internally looped, input data ignored */ #define V_ROUT_RX_STIO2 (0x2 << 6) /* channel data comes from STIO1 */ #define V_ROUT_RX_STIO1 (0x3 << 6) /* channel data comes from STIO2 */ #define V_CH_SNUM_SHIFT (1) #define V_CH_SNUM_MASK (31 << 1) /* A_CON_HDLC bits */ #define V_IFF (1 << 0) /* Inter-Frame Fill: 0=0x7e, 1=0xff */ #define V_HDLC_TRP (1 << 1) /* 0=HDLC mode, 1=transparent */ #define V_TRP_IRQ_0 (0x0 << 2) /* FIFO enabled, no interrupt */ #define V_TRP_IRQ_64 (0x1 << 2) /* FIFO enabled, int @ 64 bytes */ #define V_TRP_IRQ_128 (0x2 << 2) /* FIFO enabled, int @ 128 bytes */ #define V_TRP_IRQ_256 (0x3 << 2) /* FIFO enabled, int @ 256 bytes */ #define V_TRP_IRQ_512 (0x4 << 2) /* FIFO enabled, int @ 512 bytes */ #define V_TRP_IRQ_1024 (0x5 << 2) /* FIFO enabled, int @ 1024 bytes */ #define V_TRP_IRQ_2048 (0x6 << 2) /* FIFO enabled, int @ 2048 bytes */ #define V_TRP_IRQ_4096 (0x7 << 2) /* FIFO enabled, int @ 4096 bytes */ #define V_TRP_IRQ (0x1 << 2) /* FIFO enabled, interrupt at end of frame (HDLC mode) */ #define V_DATA_FLOW_000 (0x0 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_001 (0x1 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_010 (0x2 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_011 (0x3 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_100 (0x4 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_101 (0x5 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_110 (0x6 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_111 (0x7 << 5) /* see A_CON_HDLC reg description in datasheet */ /* R_FIFO bits */ #define V_FIFO_DIR (1 << 0) /* 1=RX FIFO data */ #define V_REV (1 << 7) /* 1=MSB first */ #define V_FIFO_NUM_SHIFT (1) #define V_FIFO_NUM_MASK (0x3e) /* A_CHANNEL bits */ #define V_CH_FDIR (1 << 0) /* 1=HFC chan for RX data */ #define V_CH_FNUM_SHIFT (1) #define V_CH_FNUM_MASK (0x3e) /* R_SLOT bits */ #define V_SL_DIR (1 << 0) /* 1=timeslot will RX PCM data from bus */ #define V_SL_NUM_SHIFT (1) #define V_SL_NUM_MASK (0xfe) /* A_INC_RES_FIFO bits */ #define V_INC_F (1 << 0) /* 1=increment FIFO F-counter (bit auto-clears) */ #define V_RES_FIFO (1 << 1) /* 1=reset FIFO (bit auto-clears) */ #define V_RES_LOST (1 << 2) /* 1=reset LOST error (bit auto-clears) */ /* R_FIFO_MD bits */ #define V_FIFO_MD_00 (0x0 << 0) #define V_FIFO_MD_01 (0x1 << 0) #define V_FIFO_MD_10 (0x2 << 0) #define V_FIFO_MD_11 (0x3 << 0) #define V_DF_MD_SM (0x0 << 2) /* simple data flow mode */ #define V_DF_MD_CSM (0x1 << 2) /* channel select mode */ #define V_DF_MD_FSM (0x3 << 2) /* FIFO sequence mode */ #define V_FIFO_SZ_00 (0x0 << 4) #define V_FIFO_SZ_01 (0x1 << 4) #define V_FIFO_SZ_10 (0x2 << 4) #define V_FIFO_SZ_11 (0x3 << 4) /* A_SUBCH_CFG bits */ #define V_BIT_CNT_8BIT (0) /* process 8 bits */ #define V_BIT_CNT_1BIT (1) /* process 1 bit */ #define V_BIT_CNT_2BIT (2) /* process 2 bits */ #define V_BIT_CNT_3BIT (3) /* process 3 bits */ #define V_BIT_CNT_4BIT (4) /* process 4 bits */ #define V_BIT_CNT_5BIT (5) /* process 5 bits */ #define V_BIT_CNT_6BIT (6) /* process 6 bits */ #define V_BIT_CNT_7BIT (7) /* process 7 bits */ #define V_LOOP_FIFO (1 << 6) /* loop FIFO data */ #define V_INV_DATA (1 << 7) /* invert FIFO data */ #define V_START_BIT_SHIFT (3) #define V_START_BIT_MASK (0x38) /* R_ST_SYNC bits */ #define V_MAN_SYNC (1 << 3) /* 1=manual sync mode */ #define V_SYNC_SEL_MASK (0x03) /* A_ST_WR_STA bits */ #define V_ST_SET_STA_MASK (0x0f) #define V_ST_LD_STA (1 << 4) /* 1=force ST_SET_STA mode, must be manually cleared 6us later */ #define V_ST_ACT_NOP (0x0 << 5) /* NOP */ #define V_ST_ACT_DEACTIVATE (0x2 << 5) /* start deactivation. auto-clears */ #define V_ST_ACT_ACTIVATE (0x3 << 5) /* start activation. auto-clears. */ #define V_SET_G2_G3 (1 << 7) /* 1=auto G2->G3 in NT mode. auto-clears after transition. */ /* A_ST_RD_STA */ #define V_ST_STA_MASK (0x0f) #define V_FR_SYNC (1 << 4) /* 1=synchronized */ #define V_T2_EXP (1 << 5) /* 1=T2 expired (NT only) */ #define V_INFO0 (1 << 6) /* 1=INFO0 */ #define V_G2_G3 (1 << 7) /* 1=allows G2->G3 (NT only, auto-clears) */ /* A_ST_CLK_DLY bits */ #define V_ST_SMPL_SHIFT (4) /* A_ST_CTRL0 bits */ #define V_B1_EN (1 << 0) /* 1=B1-channel transmit */ #define V_B2_EN (1 << 1) /* 1=B2-channel transmit */ #define V_ST_MD (1 << 2) /* 0=TE, 1=NT */ #define V_D_PRIO (1 << 3) /* D-Chan priority 0=high, 1=low */ #define V_SQ_EN (1 << 4) /* S/Q bits transmit (1=enabled) */ #define V_96KHZ (1 << 5) /* 1=transmit test signal */ #define V_TX_LI (1 << 6) /* 0=capacitive line mode, 1=non-capacitive */ #define V_ST_STOP (1 << 7) /* 1=power down */ /* A_ST_CTRL1 bits */ #define V_G2_G3_EN (1 << 0) /* 1=G2->G3 allowed without V_SET_G2_G3 */ #define V_D_HI (1 << 2) /* 1=D-chan reset */ #define V_E_IGNO (1 << 3) /* TE:1=ignore Echan, NT:should always be 1. */ #define V_E_LO (1 << 4) /* NT only: 1=force Echan low */ #define V_B12_SWAP (1 << 7) /* 1=swap B1/B2 */ /* A_ST_CTRL2 bits */ #define V_B1_RX_EN (1 << 0) /* 1=enable B1 RX */ #define V_B2_RX_EN (1 << 1) /* 1=enable B2 RX */ #define V_ST_TRI (1 << 6) /* 1=tristate S/T output buffer */ #define NUM_REGS 0xff #define NUM_PCI 12 /* From this point down, things only the kernel needs to know about */ #ifdef __KERNEL__ #define HFC_T1 0 #define HFC_T2 1 #define HFC_T3 2 #define MAX_SPANS_PER_CARD 8 #define WCB4XXP_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */ #define WCB4XXP_HDLC_BUF_LEN 32 /* arbitrary, just the max # of byts we will send to DAHDI per call */ struct b4xxp_span { struct b4xxp *parent; int port; /* which S/T port this span belongs to */ unsigned char writechunk[WCB4XXP_CHANNELS_PER_SPAN * DAHDI_CHUNKSIZE]; unsigned char readchunk[WCB4XXP_CHANNELS_PER_SPAN * DAHDI_CHUNKSIZE]; int sync; /* sync priority */ int oldstate; /* old state machine state */ int newalarm; /* alarm to send to zaptel once alarm timer expires */ unsigned long alarmtimer; int te_mode; /* 1=TE, 0=NT */ unsigned long hfc_timers[WCB4XXP_CHANNELS_PER_SPAN]; /* T1, T2, T3 */ int hfc_timer_on[WCB4XXP_CHANNELS_PER_SPAN]; /* 1=timer active */ int fifos[WCB4XXP_CHANNELS_PER_SPAN]; /* B1, B2, D <--> host fifo numbers */ /* HDLC controller fields */ struct dahdi_chan *sigchan; /* pointer to the signalling channel for this span */ int sigactive; /* nonzero means we're in the middle of sending an HDLC frame */ atomic_t hdlc_pending; /* hdlc_hard_xmit() increments, hdlc_tx_frame() decrements */ int frames_out; int frames_in; struct dahdi_span span; /* zaptel span info for this span */ struct dahdi_chan *chans[WCB4XXP_CHANNELS_PER_SPAN]; /* Individual channels */ struct dahdi_echocan_state ec[WCB4XXP_CHANNELS_PER_SPAN]; /* echocan state for each channel */ struct dahdi_chan _chans[WCB4XXP_CHANNELS_PER_SPAN]; /* Backing memory */ }; enum cards_ids { /* Cards ==> Brand & Model */ B410P = 0, /* Digium B410P */ B200P_OV, /* OpenVox B200P */ B400P_OV, /* OpenVox B400P */ B800P_OV, /* OpenVox B800P */ DUOBRI, /* HFC-2S Junghanns.NET duoBRI PCI */ QUADBRI, /* HFC-4S Junghanns.NET quadBRI PCI */ OCTOBRI, /* HFC-8S Junghanns.NET octoBRI PCI */ BN2S0, /* BeroNet BN2S0 */ BN4S0, /* Beronet BN4S0 */ BN8S0, /* BeroNet BN8S0 */ BSWYX_SX2, /* Swyx 4xS0 SX2 QuadBri */ QUADBRI_EVAL /* HFC-4S CCD Eval. Board */ }; /* This structure exists one per card */ struct b4xxp { char *variety; int chiprev; /* revision of HFC-4S */ struct pci_dev *pdev; /* Pointer to PCI device */ void __iomem *addr; /* I/O address (memory mapped) */ void __iomem *ioaddr; /* I/O address (index based) */ int irq; /* IRQ used by device */ spinlock_t reglock; /* lock for all register accesses */ spinlock_t seqlock; /* lock for "sequence" accesses that must be ordered */ spinlock_t fifolock; /* lock for all FIFO accesses (reglock must be available) */ volatile unsigned long ticks; unsigned long fifo_en_rxint; /* each bit is the RX int enable for that FIFO */ unsigned long fifo_en_txint; /* each bit is the TX int enable for that FIFO */ unsigned char fifo_irqstatus[8]; /* top-half ORs in new interrupts, bottom-half ANDs them out */ unsigned char misc_irqstatus; /* same for this */ unsigned char st_irqstatus; /* same for this too */ unsigned int numspans; int blinktimer; /* for the fancy LED alarms */ int alarmpos; /* ditto */ int cardno; /* Which card we are */ int globalconfig; /* Whether global setup has been done */ int syncspan; /* span that HFC uses for sync on this card */ int running; /* interrupts are enabled */ struct b4xxp_span spans[MAX_SPANS_PER_CARD]; /* Individual spans */ int order; /* Order */ int flags; /* Device flags */ enum cards_ids card_type; /* For LED handling mostly */ int master; /* Are we master */ int ledreg; /* copy of the LED Register */ unsigned int gpio; unsigned int gpioctl; int spansstarted; /* number of spans started */ /* Flags for our bottom half */ unsigned int shutdown; /* 1=bottom half doesn't process anything, just returns */ struct tasklet_struct b4xxp_tlet; }; /* CPLD access bits */ #define B4_RDADDR 0 #define B4_WRADDR 1 #define B4_COUNT 2 #define B4_DMACTRL 3 #define B4_INTR 4 #define B4_VERSION 6 #define B4_LEDS 7 #define B4_GPIOCTL 8 #define B4_GPIO 9 #define B4_LADDR 10 #define B4_LDATA 11 #define B4_LCS (1 << 11) #define B4_LCS2 (1 << 12) #define B4_LALE (1 << 13) #define B4_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */ #define B4_ACTIVATE (1 << 12) #define B4_LREAD (1 << 15) #define B4_LWRITE (1 << 16) #define LED_OFF (0) #define LED_RED (1) #define LED_GREEN (2) #define get_F(f1, f2, flen) { \ f1 = hfc_readcounter8(b4, A_F1); \ f2 = hfc_readcounter8(b4, A_F2); \ flen = f1 - f2; \ \ if(flen < 0) \ flen += (HFC_FMAX - HFC_FMIN) + 1; \ } #define get_Z(z1, z2, zlen) { \ z1 = hfc_readcounter16(b4, A_Z1); \ z2 = hfc_readcounter16(b4, A_Z2); \ zlen = z1 - z2; \ \ if(zlen < 0) \ zlen += (HFC_ZMAX - HFC_ZMIN) + 1; \ } #define flush_pci() (void)ioread8(b4->addr + R_STATUS) #endif /* __KERNEL__ */ #endif /* _B4XX_H_ */ dahdi-linux-2.5.0.1/drivers/dahdi/wcb4xxp/Makefile0000644000175000017500000000026511424402220021567 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild else endif dahdi-linux-2.5.0.1/drivers/dahdi/wcb4xxp/Kbuild0000644000175000017500000000016411137730310021267 0ustar tzafrirtzafrirobj-m += wcb4xxp.o EXTRA_CFLAGS += -I$(src)/.. -Wno-undef wcb4xxp-objs := base.o $(obj)/base.o: $(src)/wcb4xxp.h dahdi-linux-2.5.0.1/drivers/dahdi/adt_lec.h0000644000175000017500000000206311261425376020312 0ustar tzafrirtzafrir/* * ADT Line Echo Canceller Parameter Parsing * * Copyright (C) 2008 Digium, Inc. * * Kevin P. Fleming * * All rights reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _ADT_LEC_H #define _ADT_LEC_H enum adt_lec_nlp_type { ADT_LEC_NLP_OFF = 0, ADT_LEC_NLP_MUTE, ADT_LEC_RANDOM_NOISE, ADT_LEC_HOTH_NOISE, ADT_LEC_SUPPRESS, }; enum adt_companding { ADT_COMP_ULAW = 0, ADT_COMP_ALAW, }; struct adt_lec_params { __u32 tap_length; enum adt_lec_nlp_type nlp_type; __u32 nlp_threshold; __u32 nlp_max_suppress; enum adt_companding companding; }; #endif /* _ADT_LEC_H */ dahdi-linux-2.5.0.1/drivers/dahdi/dahdi-version.c0000644000175000017500000000146511532727335021454 0ustar tzafrirtzafrir/* * Dahdi Version * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2011 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include "dahdi.h" const char *const dahdi_version = DAHDI_VERSION; MODULE_VERSION(DAHDI_VERSION); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_transcode.c0000644000175000017500000003215711510412325022017 0ustar tzafrirtzafrir/* * Transcoder Interface for DAHDI * * Written by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int debug; /* The registration list contains transcoders in the order in which they were * registered. */ static LIST_HEAD(registration_list); /* The active list is sorted by the most recently used transcoder is last. This * is used as a simplistic way to spread the load amongst the different hardware * transcoders in the system. */ static LIST_HEAD(active_list); static DEFINE_SPINLOCK(translock); EXPORT_SYMBOL(dahdi_transcoder_register); EXPORT_SYMBOL(dahdi_transcoder_unregister); EXPORT_SYMBOL(dahdi_transcoder_alert); EXPORT_SYMBOL(dahdi_transcoder_alloc); EXPORT_SYMBOL(dahdi_transcoder_free); struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans) { struct dahdi_transcoder *tc; unsigned int x; size_t size = sizeof(*tc) + (sizeof(tc->channels[0]) * numchans); if (!(tc = kmalloc(size, GFP_KERNEL))) return NULL; memset(tc, 0, size); strcpy(tc->name, ""); INIT_LIST_HEAD(&tc->registration_list_node); INIT_LIST_HEAD(&tc->active_list_node); tc->numchannels = numchans; for (x=0; x < tc->numchannels; x++) { init_waitqueue_head(&tc->channels[x].ready); tc->channels[x].parent = tc; } WARN_ON(!dahdi_transcode_fops); /* Individual transcoders should supply their own file_operations for * write and read. But they will by default use the file_operations * provided by the dahdi_transcode layer. */ memcpy(&tc->fops, dahdi_transcode_fops, sizeof(*dahdi_transcode_fops)); return tc; } void dahdi_transcoder_free(struct dahdi_transcoder *tc) { kfree(tc); } /* Returns 1 if the item is on the list pointed to by head, otherwise, returns * 0 */ static int is_on_list(struct list_head *entry, struct list_head *head) { struct list_head *cur; list_for_each(cur, head) { if (cur == entry) return 1; } return 0; } /* Register a transcoder */ int dahdi_transcoder_register(struct dahdi_transcoder *tc) { spin_lock(&translock); BUG_ON(is_on_list(&tc->registration_list_node, ®istration_list)); list_add_tail(&tc->registration_list_node, ®istration_list); list_add_tail(&tc->active_list_node, &active_list); spin_unlock(&translock); printk(KERN_INFO "%s: Registered codec translator '%s' " \ "with %d transcoders (srcs=%08x, dsts=%08x)\n", THIS_MODULE->name, tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts); return 0; } /* Unregister a transcoder */ int dahdi_transcoder_unregister(struct dahdi_transcoder *tc) { int res = -EINVAL; /* \todo Perhaps we should check to make sure there isn't a channel * that is still in use? */ spin_lock(&translock); if (!is_on_list(&tc->registration_list_node, ®istration_list)) { spin_unlock(&translock); printk(KERN_WARNING "%s: Failed to unregister %s, which is " \ "not currently registered.\n", THIS_MODULE->name, tc->name); return -EINVAL; } list_del_init(&tc->registration_list_node); list_del_init(&tc->active_list_node); spin_unlock(&translock); printk(KERN_INFO "Unregistered codec translator '%s' with %d " \ "transcoders (srcs=%08x, dsts=%08x)\n", tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts); res = 0; return res; } /* Alert a transcoder */ int dahdi_transcoder_alert(struct dahdi_transcoder_channel *chan) { wake_up_interruptible(&chan->ready); return 0; } static int dahdi_tc_open(struct inode *inode, struct file *file) { const struct file_operations *original_fops; BUG_ON(!dahdi_transcode_fops); original_fops = file->f_op; file->f_op = dahdi_transcode_fops; file->private_data = NULL; /* Under normal operation, this releases the reference on the DAHDI * module that was created when the file was opened. dahdi_open is * responsible for taking a reference out on this module before * calling this function. */ module_put(original_fops->owner); return 0; } static void dtc_release(struct dahdi_transcoder_channel *chan) { BUG_ON(!chan); if (chan->parent && chan->parent->release) { chan->parent->release(chan); } dahdi_tc_clear_busy(chan); } static int dahdi_tc_release(struct inode *inode, struct file *file) { struct dahdi_transcoder_channel *chan = file->private_data; /* There will not be a transcoder channel associated with this file if * the ALLOCATE ioctl never succeeded. */ if (chan) { dtc_release(chan); } return 0; } /* Find a free channel on the transcoder and mark it busy. */ static inline struct dahdi_transcoder_channel * get_free_channel(struct dahdi_transcoder *tc, const struct dahdi_transcoder_formats *fmts) { struct dahdi_transcoder_channel *chan; int i; /* Should be called with the translock held. */ #ifdef CONFIG_SMP WARN_ON(!spin_is_locked(&translock)); #endif for (i = 0; i < tc->numchannels; i++) { chan = &tc->channels[i]; if (!dahdi_tc_is_busy(chan)) { if (!dahdi_tc_is_built(chan)) { dahdi_tc_set_busy(chan); return chan; } else { /* If the channel is already built, we must * make sure that it can support the formats * that we're interested in. */ if ((fmts->srcfmt|fmts->dstfmt) == chan->built_fmts) { dahdi_tc_set_busy(chan); return chan; } } } } return NULL; } /* Search the list for a transcoder that supports the specified format, and * allocate and return an available channel on it. * * Returns either a pointer to the allocated channel, -EBUSY if the format is * supported but all the channels are busy, or -ENODEV if there are not any * transcoders that support the formats. */ static struct dahdi_transcoder_channel * __find_free_channel(struct list_head *list, const struct dahdi_transcoder_formats *fmts) { struct dahdi_transcoder *tc; struct dahdi_transcoder_channel *chan = NULL; unsigned int match = 0; list_for_each_entry(tc, list, active_list_node) { if ((tc->dstfmts & fmts->dstfmt) && (tc->srcfmts & fmts->srcfmt)) { /* We found a transcoder that can handle our formats. * Now look for an available channel. */ match = 1; if ((chan = get_free_channel(tc, fmts))) { /* transcoder tc has a free channel. In order * to spread the load among available * transcoders (when there are more than one * transcoder in the system) we'll move tc * to the end of the list. */ list_move_tail(&tc->active_list_node, list); return chan; } } } return (void*)((long)((match) ? -EBUSY : -ENODEV)); } static long dahdi_tc_allocate(struct file *file, unsigned long data) { struct dahdi_transcoder_channel *chan = NULL; struct dahdi_transcoder_formats fmts; if (copy_from_user(&fmts, (__user const void *) data, sizeof(fmts))) { return -EFAULT; } spin_lock(&translock); chan = __find_free_channel(&active_list, &fmts); spin_unlock(&translock); if (IS_ERR(chan)) { return PTR_ERR(chan); } /* Every transcoder channel must be associated with a parent * transcoder. */ BUG_ON(!chan->parent); chan->srcfmt = fmts.srcfmt; chan->dstfmt = fmts.dstfmt; if (file->private_data) { /* This open file is moving to a new channel. Cleanup and * close the old channel here. */ dtc_release(file->private_data); } file->private_data = chan; if (chan->parent->fops.owner != file->f_op->owner) { if (!try_module_get(chan->parent->fops.owner)) { /* Failed to get a reference on the driver for the * actual transcoding hardware. */ return -EINVAL; } /* Release the reference on the existing driver. */ module_put(file->f_op->owner); file->f_op = &chan->parent->fops; } if (file->f_flags & O_NONBLOCK) { dahdi_tc_set_nonblock(chan); } else { dahdi_tc_clear_nonblock(chan); } /* Actually reset the transcoder channel */ if (chan->parent->allocate) return chan->parent->allocate(chan); return -EINVAL; } static long dahdi_tc_getinfo(unsigned long data) { struct dahdi_transcoder_info info; struct dahdi_transcoder *cur; struct dahdi_transcoder *tc = NULL; unsigned int count = 0; if (copy_from_user(&info, (__user const void *) data, sizeof(info))) { return -EFAULT; } spin_lock(&translock); list_for_each_entry(cur, ®istration_list, registration_list_node) { if (info.tcnum == count++) { tc = cur; break; } } spin_unlock(&translock); if (!tc) { return -ENOSYS; } strlcpy(info.name, tc->name, sizeof(info.name)); info.numchannels = tc->numchannels; info.srcfmts = tc->srcfmts; info.dstfmts = tc->dstfmts; return copy_to_user((__user void *) data, &info, sizeof(info)) ? -EFAULT : 0; } static ssize_t dahdi_tc_write(struct file *file, __user const char *usrbuf, size_t count, loff_t *ppos) { if (file->private_data) { /* file->private_data will not be NULL if DAHDI_TC_ALLOCATE was * called, and therefore indicates that the transcoder driver * did not export a read function. */ WARN_ON(1); return -ENOSYS; } else { printk(KERN_INFO "%s: Attempt to write to unallocated " \ "channel.\n", THIS_MODULE->name); return -EINVAL; } } static ssize_t dahdi_tc_read(struct file *file, __user char *usrbuf, size_t count, loff_t *ppos) { if (file->private_data) { /* file->private_data will not be NULL if DAHDI_TC_ALLOCATE was * called, and therefore indicates that the transcoder driver * did not export a write function. */ WARN_ON(1); return -ENOSYS; } else { printk(KERN_INFO "%s: Attempt to read from unallocated " \ "channel.\n", THIS_MODULE->name); return -EINVAL; } } static long dahdi_tc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data) { switch (cmd) { case DAHDI_TC_ALLOCATE: return dahdi_tc_allocate(file, data); case DAHDI_TC_GETINFO: return dahdi_tc_getinfo(data); case DAHDI_TRANSCODE_OP: /* This is a deprecated call from the previous transcoder * interface, which was all routed through the dahdi_ioctl in * dahdi-base.c, and this ioctl request was used to indicate * that the call should be forwarded to this function. Now * when the file is opened, the f_ops pointer is updated to * point directly to this function, and we don't need a * general indication that the ioctl is destined for the * transcoder. * * I'm keeping this ioctl here in order to explain why there * might be a hole in the ioctl numbering scheme in the header * files. */ printk(KERN_WARNING "%s: DAHDI_TRANSCODE_OP is no longer " \ "supported. Please call DAHDI_TC ioctls directly.\n", THIS_MODULE->name); return -EINVAL; default: return -EINVAL; }; } #ifndef HAVE_UNLOCKED_IOCTL static int dahdi_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { return (int)dahdi_tc_unlocked_ioctl(file, cmd, data); } #endif static unsigned int dahdi_tc_poll(struct file *file, struct poll_table_struct *wait_table) { int ret; struct dahdi_transcoder_channel *chan = file->private_data; if (!chan) { /* This is because the DAHDI_TC_ALLOCATE ioctl was not called * before calling poll, which is invalid. */ return -EINVAL; } poll_wait(file, &chan->ready, wait_table); ret = dahdi_tc_is_busy(chan) ? 0 : POLLPRI; ret |= dahdi_tc_is_built(chan) ? POLLOUT : 0; ret |= dahdi_tc_is_data_waiting(chan) ? POLLIN : 0; return ret; } static struct file_operations __dahdi_transcode_fops = { .owner = THIS_MODULE, .open = dahdi_tc_open, .release = dahdi_tc_release, #ifdef HAVE_UNLOCKED_IOCTL .unlocked_ioctl = dahdi_tc_unlocked_ioctl, #else .ioctl = dahdi_tc_ioctl, #endif .read = dahdi_tc_read, .write = dahdi_tc_write, .poll = dahdi_tc_poll, }; static struct dahdi_chardev transcode_chardev = { .name = "transcode", .minor = DAHDI_TRANSCODE, }; static int dahdi_transcode_init(void) { int res; if (dahdi_transcode_fops) { printk(KERN_WARNING "dahdi_transcode_fops already set.\n"); return -EBUSY; } dahdi_transcode_fops = &__dahdi_transcode_fops; if ((res = dahdi_register_chardev(&transcode_chardev))) return res; printk(KERN_INFO "%s: Loaded.\n", THIS_MODULE->name); return 0; } static void dahdi_transcode_cleanup(void) { dahdi_unregister_chardev(&transcode_chardev); dahdi_transcode_fops = NULL; printk(KERN_DEBUG "%s: Unloaded.\n", THIS_MODULE->name); } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI Transcoder Support"); MODULE_AUTHOR("Mark Spencer "); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif module_init(dahdi_transcode_init); module_exit(dahdi_transcode_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/arith.h0000644000175000017500000002047611046164220020023 0ustar tzafrirtzafrir/* * Handy add/subtract functions to operate on chunks of shorts. * Feel free to add customizations for additional architectures * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _DAHDI_ARITH_H #define _DAHDI_ARITH_H #ifdef CONFIG_DAHDI_MMX #ifdef DAHDI_CHUNKSIZE static inline void __ACSS(volatile short *dst, const short *src) { __asm__ __volatile__ ( "movq 0(%0), %%mm0;\n" "movq 0(%1), %%mm1;\n" "movq 8(%0), %%mm2;\n" "movq 8(%1), %%mm3;\n" "paddsw %%mm1, %%mm0;\n" "paddsw %%mm3, %%mm2;\n" "movq %%mm0, 0(%0);\n" "movq %%mm2, 8(%0);\n" : "=r" (dst) : "r" (src), "0" (dst) : "memory" #ifdef CLOBBERMMX , "%mm0", "%mm1", "%mm2", "%mm3" #endif ); } static inline void __SCSS(volatile short *dst, const short *src) { __asm__ __volatile__ ( "movq 0(%0), %%mm0;\n" "movq 0(%1), %%mm1;\n" "movq 8(%0), %%mm2;\n" "movq 8(%1), %%mm3;\n" "psubsw %%mm1, %%mm0;\n" "psubsw %%mm3, %%mm2;\n" "movq %%mm0, 0(%0);\n" "movq %%mm2, 8(%0);\n" : "=r" (dst) : "r" (src), "0" (dst) : "memory" #ifdef CLOBBERMMX , "%mm0", "%mm1", "%mm2", "%mm3" #endif ); } #if (DAHDI_CHUNKSIZE == 8) #define ACSS(a,b) __ACSS(a,b) #define SCSS(a,b) __SCSS(a,b) #elif (DAHDI_CHUNKSIZE > 8) static inline void ACSS(volatile short *dst, const short *src) { int x; for (x=0;x>= 4; /* Clear our accumulator, mm4 */ /* For every set of eight... Load 16 coefficients into four registers... Shift each word right 16 to make them shorts... Pack the resulting shorts into two registers... With the coefficients now in mm0 and mm2, load the history into mm1 and mm3... Multiply/add mm1 into mm0, and mm3 into mm2... Add mm2 into mm0 (without saturation, alas). Now we have two half-results. Accumulate in mm4 (again, without saturation, alas) */ __asm__ ( "pxor %%mm4, %%mm4;\n" "mov %1, %%edi;\n" "mov %2, %%esi;\n" "mov %3, %%ecx;\n" "1:" "movq 0(%%edi), %%mm0;\n" "movq 8(%%edi), %%mm1;\n" "movq 16(%%edi), %%mm2;\n" "movq 24(%%edi), %%mm3;\n" /* can't use 4/5 since 4 is the accumulator for us */ "movq 32(%%edi), %%mm6;\n" "movq 40(%%edi), %%mm7;\n" "psrad $16, %%mm0;\n" "psrad $16, %%mm1;\n" "psrad $16, %%mm2;\n" "psrad $16, %%mm3;\n" "psrad $16, %%mm6;\n" "psrad $16, %%mm7;\n" "packssdw %%mm1, %%mm0;\n" "packssdw %%mm3, %%mm2;\n" "packssdw %%mm7, %%mm6;\n" "movq 0(%%esi), %%mm1;\n" "movq 8(%%esi), %%mm3;\n" "movq 16(%%esi), %%mm7;\n" "pmaddwd %%mm1, %%mm0;\n" "pmaddwd %%mm3, %%mm2;\n" "pmaddwd %%mm7, %%mm6;\n" "paddd %%mm6, %%mm4;\n" "paddd %%mm2, %%mm4;\n" "paddd %%mm0, %%mm4;\n" /* Come back and do for the last few bytes */ "movq 48(%%edi), %%mm6;\n" "movq 56(%%edi), %%mm7;\n" "psrad $16, %%mm6;\n" "psrad $16, %%mm7;\n" "packssdw %%mm7, %%mm6;\n" "movq 24(%%esi), %%mm7;\n" "pmaddwd %%mm7, %%mm6;\n" "paddd %%mm6, %%mm4;\n" "add $64, %%edi;\n" "add $32, %%esi;\n" "dec %%ecx;\n" "jnz 1b;\n" "movq %%mm4, %%mm0;\n" "psrlq $32, %%mm0;\n" "paddd %%mm0, %%mm4;\n" "movd %%mm4, %0;\n" : "=r" (sum) : "r" (coeffs), "r" (hist), "r" (len) : "%ecx", "%edi", "%esi" ); return sum; } static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps) { int i; int correction; for (i=0;i>= 4; /* First, load up taps, */ __asm__ ( "pxor %%mm4, %%mm4;\n" "mov %0, %%edi;\n" "mov %1, %%esi;\n" "mov %3, %%ecx;\n" "1:" "jnz 1b;\n" "movq %%mm4, %%mm0;\n" "psrlq $32, %%mm0;\n" "paddd %%mm0, %%mm4;\n" "movd %%mm4, %0;\n" : "=r" (taps), "=r" (taps_short) : "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps) : "%ecx", "%edi", "%esi" ); #endif #if 1 for (i=0;i> 16; } #endif } static inline int CONVOLVE2(const short *coeffs, const short *hist, int len) { int sum; /* Divide length by 16 */ len >>= 4; /* Clear our accumulator, mm4 */ /* For every set of eight... Load in eight coefficients and eight historic samples, multliply add and accumulate the result */ __asm__ ( "pxor %%mm4, %%mm4;\n" "mov %1, %%edi;\n" "mov %2, %%esi;\n" "mov %3, %%ecx;\n" "1:" "movq 0(%%edi), %%mm0;\n" "movq 8(%%edi), %%mm2;\n" "movq 0(%%esi), %%mm1;\n" "movq 8(%%esi), %%mm3;\n" "pmaddwd %%mm1, %%mm0;\n" "pmaddwd %%mm3, %%mm2;\n" "paddd %%mm2, %%mm4;\n" "paddd %%mm0, %%mm4;\n" "movq 16(%%edi), %%mm0;\n" "movq 24(%%edi), %%mm2;\n" "movq 16(%%esi), %%mm1;\n" "movq 24(%%esi), %%mm3;\n" "pmaddwd %%mm1, %%mm0;\n" "pmaddwd %%mm3, %%mm2;\n" "paddd %%mm2, %%mm4;\n" "paddd %%mm0, %%mm4;\n" "add $32, %%edi;\n" "add $32, %%esi;\n" "dec %%ecx;\n" "jnz 1b;\n" "movq %%mm4, %%mm0;\n" "psrlq $32, %%mm0;\n" "paddd %%mm0, %%mm4;\n" "movd %%mm4, %0;\n" : "=r" (sum) : "r" (coeffs), "r" (hist), "r" (len) : "%ecx", "%edi", "%esi" ); return sum; } static inline short MAX16(const short *y, int len, int *pos) { int k; short max = 0; int bestpos = 0; for (k=0;k 32767) sum = 32767; else if (sum < -32768) sum = -32768; dst[x] = sum; } #endif } static inline void SCSS(short *dst, short *src) { int x; /* Subtract src from dst with saturation, storing in dst */ #ifdef BFIN for (x = 0; x < DAHDI_CHUNKSIZE; x++) dst[x] = __builtin_bfin_sub_fr1x16(dst[x], src[x]); #else int sum; for (x = 0; x < DAHDI_CHUNKSIZE; x++) { sum = dst[x] - src[x]; if (sum > 32767) sum = 32767; else if (sum < -32768) sum = -32768; dst[x] = sum; } #endif } #endif /* DAHDI_CHUNKSIZE */ static inline int CONVOLVE(const int *coeffs, const short *hist, int len) { int x; int sum = 0; for (x=0;x> 16) * hist[x]; return sum; } static inline int CONVOLVE2(const short *coeffs, const short *hist, int len) { int x; int sum = 0; for (x=0;x> 16; } } static inline short MAX16(const short *y, int len, int *pos) { int k; short max = 0; int bestpos = 0; for (k=0;k #include #include #include #include #include #include #include static int debug; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk(KERN_DEBUG "%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) #include "hpec_user.h" #include "hpec.h" static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, __u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static const char *name = "HPEC"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_features my_features = { .NLP_automatic = 1, .CED_tx_detect = 1, .CED_rx_detect = 1, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, }; struct ec_pvt { struct hpec_state *hpec; struct dahdi_echocan_state dahdi; }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static int __attribute__((regparm(0), format(printf, 1, 2))) logger(const char *format, ...) { int res; va_list args; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) va_start(args, format); res = vprintk(format, args); va_end(args); #else char buf[256]; va_start(args, format); res = vsnprintf(buf, sizeof(buf), format, args); va_end(args); printk(KERN_INFO "%s" buf); #endif return res; } static void *memalloc(size_t len) { return kmalloc(len, GFP_KERNEL); } static void memfree(void *ptr) { kfree(ptr); } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); hpec_channel_free(pvt->hpec); kfree(pvt); } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, __u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); hpec_channel_update(pvt->hpec, isig, iref); } DEFINE_SEMAPHORE(license_lock); static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct ec_pvt *pvt; if (ecp->param_count > 0) { printk(KERN_WARNING "HPEC does not support parameters; failing request\n"); return -EINVAL; } pvt = kzalloc(sizeof(*pvt), GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; pvt->dahdi.features = my_features; if (down_interruptible(&license_lock)) return -ENOTTY; pvt->hpec = hpec_channel_alloc(ecp->tap_length); up(&license_lock); if (!pvt->hpec) { kfree(pvt); *ec = NULL; return -ENOTTY; } else { *ec = &pvt->dahdi; return 0; } } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { return 1; } static int hpec_license_ioctl(unsigned int cmd, unsigned long data) { struct hpec_challenge challenge; struct hpec_license license; int result = 0; switch (cmd) { case DAHDI_EC_LICENSE_CHALLENGE: if (down_interruptible(&license_lock)) return -EINTR; memset(&challenge, 0, sizeof(challenge)); if (hpec_license_challenge(&challenge)) result = -ENODEV; if (!result && copy_to_user((unsigned char *) data, &challenge, sizeof(challenge))) result = -EFAULT; up(&license_lock); return result; case DAHDI_EC_LICENSE_RESPONSE: if (down_interruptible(&license_lock)) return -EINTR; if (copy_from_user(&license, (unsigned char *) data, sizeof(license))) result = -EFAULT; if (!result && hpec_license_check(&license)) result = -EACCES; up(&license_lock); return result; default: return -ENOSYS; } } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); hpec_init(logger, debug, DAHDI_CHUNKSIZE, memalloc, memfree); dahdi_set_hpec_ioctl(hpec_license_ioctl); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); dahdi_set_hpec_ioctl(NULL); hpec_shutdown(); } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI High Performance Echo Canceller"); MODULE_AUTHOR("Kevin P. Fleming "); MODULE_LICENSE("Digium Commercial"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/hpec/hpec_user.h0000644000175000017500000000200011046336665021605 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface to Digium High-Performance Echo Canceller * * Copyright (C) 2006 Digium, Inc. * * All rights reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #if !defined(_HPEC_USER_H) #define _HPEC_USER_H struct hpec_challenge { __u8 challenge[16]; }; struct hpec_license { __u32 numchannels; __u8 userinfo[256]; __u8 response[16]; }; #define DAHDI_EC_LICENSE_CHALLENGE _IOR(DAHDI_CODE, 60, struct hpec_challenge) #define DAHDI_EC_LICENSE_RESPONSE _IOW(DAHDI_CODE, 61, struct hpec_license) #endif /* !defined(_HPEC_USER_H) */ dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_jpah.c0000644000175000017500000000727711500234716022451 0ustar tzafrirtzafrir/* * ECHO_CAN_JPAH * * by Jason Parker * * Based upon mg2ec.h - sort of. * This "echo can" will completely hose your audio. * Don't use it unless you're absolutely sure you know what you're doing. * * Copyright (C) 2007-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include static int debug; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk("%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static const char *name = "JPAH"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, }; struct ec_pvt { struct dahdi_echocan_state dahdi; int blah; }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct ec_pvt *pvt; if (ecp->param_count > 0) { printk(KERN_WARNING "JPAH does not support parameters; failing request\n"); return -EINVAL; } pvt = kzalloc(sizeof(*pvt), GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; *ec = &pvt->dahdi; return 0; } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); kfree(pvt); } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 x; for (x = 0; x < size; x++) { if (pvt->blah < 2) { pvt->blah++; *isig++ = 0; } else { pvt->blah = 0; isig++; } } } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { return 0; } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI Jason Parker Audio Hoser"); MODULE_AUTHOR("Jason Parker "); MODULE_LICENSE("GPL v2"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/0000755000175000017500000000000011631523356017751 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/get_discards0000755000175000017500000000253511431317470022333 0ustar tzafrirtzafrir#!/usr/bin/php dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/test.c0000644000175000017500000000337611431317470021101 0ustar tzafrirtzafrir/* NOTE: This is not intended to be a functional program. Its only purpose is to act as a tool to find out what portions of the Octasic API kit we actually need to link into our drivers. As such, it references every API call that the actual drivers use, and we let the compiler and linker tell us what parts of each API module are actually needed to successfully build this program. */ #include "oct6100api/oct6100_api.h" int main(int argc, char **argv) { tPOCT6100_INSTANCE_API pApiInstance; UINT32 ulResult; tOCT6100_CHANNEL_MODIFY modify; tOCT6100_INTERRUPT_FLAGS InterruptFlags; tOCT6100_TONE_EVENT tonefound; tOCT6100_EVENT_GET_TONE tonesearch; tOCT6100_CHIP_OPEN ChipOpen; tOCT6100_GET_INSTANCE_SIZE InstanceSize; tOCT6100_CHANNEL_OPEN ChannelOpen; tOCT6100_TONE_DETECTION_ENABLE enable; tOCT6100_CHIP_CLOSE ChipClose; tOCT6100_API_GET_CAPACITY_PINS CapacityPins; Oct6100ChannelModifyDef(&modify); ulResult = Oct6100ChannelModify(pApiInstance, &modify); Oct6100InterruptServiceRoutineDef(&InterruptFlags); Oct6100InterruptServiceRoutine(pApiInstance, &InterruptFlags); Oct6100EventGetToneDef(&tonesearch); ulResult = Oct6100EventGetTone(pApiInstance, &tonesearch); Oct6100ChipOpenDef(&ChipOpen); Oct6100GetInstanceSizeDef(&InstanceSize); ulResult = Oct6100GetInstanceSize(&ChipOpen, &InstanceSize); ulResult = Oct6100ChipOpen(pApiInstance, &ChipOpen); Oct6100ChannelOpenDef(&ChannelOpen); ulResult = Oct6100ChannelOpen(pApiInstance, &ChannelOpen); Oct6100ToneDetectionEnableDef(&enable); Oct6100ToneDetectionEnable(pApiInstance, &enable); Oct6100ChipCloseDef(&ChipClose); ulResult = Oct6100ChipClose(pApiInstance, &ChipClose); Oct6100ApiGetCapacityPinsDef(&CapacityPins); ulResult = Oct6100ApiGetCapacityPins(&CapacityPins); return 0; } dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/0000755000175000017500000000000011631523356021374 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octtypevx.h0000644000175000017500000000617711431317470023621 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octtypevx.h Copyright (c) 2001-2007 Octasic Inc. Description: This file defines the base storage types for the VxWorks environment. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 9 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTTYPEVX_H__ #define __OCTTYPEVX_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif #include "vxWorks.h" /* 16-bit pointer integer */ typedef unsigned short *PUINT16; typedef signed short *PINT16; /* 8-bit integer pointer */ typedef unsigned char *PUINT8; typedef signed char *PINT8; /* 32-bit integer pointer */ typedef INT32 * PINT32; typedef UINT32 * PUINT32; /* Long integer pointer */ /*Intel library for file system definition*/ #ifndef DATATYPE_H typedef long LONG; #endif typedef long * PLONG; typedef unsigned long * PULONG; /* Short integer pointer */ typedef short SHORT; typedef short * PSHORT; typedef unsigned short *PUSHORT; /* 8-bit integer*/ #if (CPU!=SIMNT) && !defined(DATATYPE_H) typedef char BYTE; #endif typedef BYTE * PBYTE; /* Character and strings */ /*Intel library for file system definition*/ #ifndef DATATYPE_H typedef char CHAR; #endif typedef char * PCHAR; typedef CHAR SZ; typedef CHAR * PSZ; typedef signed char OCT_INT8; /* Double integers */ typedef double DOUBLE; typedef double * PDOUBLE; typedef float FLOAT; typedef float * PFLOAT; typedef void * PVOID; /* Booleans */ typedef BOOL * PBOOL; /* Integers */ typedef int INT; typedef int * PINT; typedef unsigned int PUINT; /* Define pseudo-keywords IN and OUT if not defined yet */ #ifndef IN #define IN /* IN param */ #endif #ifndef OUT #define OUT /* OUT param */ #endif /* LONG LONG */ #define LLONG signed long long #define PLLONG signed long long * #define ULLONG unsigned long long #define PULLONG unsigned long long * #ifndef OPT #define OPT /* OPT param */ #endif typedef PSZ * PPSZ; /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTTYPEVX_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octosdependant.h0000644000175000017500000001110211431317470024546 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octosdependant.h Copyright (c) 2001-2007 Octasic Inc. Description: This file is included to set target-specific constants. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 18 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTOSDEPENDANT_H__ #define __OCTOSDEPENDANT_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif /***************************************************************************** Known define values MSDEV: WIN32 == WINDOWS 32 bit app __WIN32__ == WINDOWS 32 bit app _Windows == WINDOWS 16 bit app _WINDOWS == Windows application .. not console _DLL == Dll Application _CONSOLE == Console Application .. no windows BORLANDC __TURBOC__ == Turbo Compiler __BORLANDC__ == Borland compiler __OS2__ == Borland OS2 compiler _Windows == Windows 16 bit app GCC Compiler __GNUC__ == GCC Compiler __unix__ == Unix system __vax__ == Unix system unix == Unix system vax == vax system TORNADO _VXWORKS_ == VXWORK ECOS/CYGWIN _ECOS_ == eCos SOLARIS _SOLARIS_ == Solaris *****************************************************************************/ /* Machine endian type */ #define OCT_MACH_LITTLE_ENDIAN 1 #define OCT_MACH_BIG_ENDIAN 2 /* Try to find current OCT_MACH_ENDIAN from compiler define values */ #if !defined( MACH_TYPE_BIG_ENDIAN ) && !defined( MACH_TYPE_LITTLE_ENDIAN ) /* Does GNU defines the endian ? */ #if defined(__GNU_C__) #if defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN__) #define OCT_MACH_ENDIAN OCT_MACH_BIG_ENDIAN #elif defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN #endif #endif /* Try with cpu type */ #if !defined(OCT_MACH_ENDIAN) /* Look for intel */ #if defined( _M_IX86 ) #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN /* Look for PowerPC */ #elif defined( _M_MPPC ) || defined( _M_PPC ) || defined(PPC) || defined(__PPC) || defined(_ARCH_PPC) #define OCT_MACH_ENDIAN OCT_MACH_BIG_ENDIAN /* Look for Blackfin */ #elif defined( __bfin__ ) #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN #elif defined( CPU ) #if CPU==PPC860 || CPU==SIMNT #define OCT_MACH_ENDIAN OCT_MACH_BIG_ENDIAN #else #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN #endif #else #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN #endif #endif #else #if defined( MACH_TYPE_BIG_ENDIAN ) #define OCT_MACH_ENDIAN OCT_MACH_BIG_ENDIAN #else #define OCT_MACH_ENDIAN OCT_MACH_LITTLE_ENDIAN #endif #endif /* Find system type if not already defined */ #if !defined( OCT_NTDRVENV ) && !defined( OCT_VXENV ) && !defined( OCT_WINENV ) #if defined( WIN32 ) || defined( __WIN32__ ) || defined( _WIN32_ ) || defined( WIN32S ) /* Verif if building a win32 driver */ #if ( defined( WIN32 ) && WIN32==100 ) #define OCT_NTDRVENV #else #define OCT_WINENV #endif #elif defined( _VXWORKS_ ) #define OCT_VXENV #elif defined( _ECOS_ ) #ifndef OCT_ECOSENV #define OCT_ECOSENV #endif /* OCT_ECOSENV */ #elif defined( _SOLARIS_ ) #define OCT_SOLARISENV #elif defined( _LINUX_ ) #define OCT_LINUXENV #else /* Unknown environment */ #define OCT_UNKNOWNENV #endif /* WIN env */ #endif /* Already defined */ #if defined( __KERNEL__ ) && defined( OCT_LINUXENV ) #define OCT_LINUXDRVENV #endif #ifdef _DEBUG #define OCT_OPT_USER_DEBUG #endif /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTOSDEPENDANT_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octdef.h0000644000175000017500000000633711431317470023016 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octdef.h Copyright (c) 2001-2007 Octasic Inc. Description: Common system definitions. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 12 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTDEF_H__ #define __OCTDEF_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif /***************************** INCLUDE FILES *******************************/ /*-------------------------------------------------------------------------- Get Platform Dependency headers ----------------------------------------------------------------------------*/ #include "octosdependant.h" /*-------------------------------------------------------------------------- Common Type definitions ----------------------------------------------------------------------------*/ #include "octtype.h" /***************************** DEFINES *************************************/ /* List of functions to skip compiling since we don't use them */ #include "digium_unused.h" /*-------------------------------------------------------------------------- Miscellaneous constants ----------------------------------------------------------------------------*/ #ifndef PROTO #define PROTO extern #endif /* Generic return codes. */ #define cOCTDEF_RC_OK 0 /* Generic Ok */ #define cOCTDEF_RC_ERROR 1 /* Generic Error */ /* Default return values of all OCTAPI functions. */ #ifndef GENERIC_OK #define GENERIC_OK 0x00000000 #endif #ifndef GENERIC_ERROR #define GENERIC_ERROR 0x00000001 #endif #ifndef GENERIC_BAD_PARAM #define GENERIC_BAD_PARAM 0x00000002 #endif /* Defines of boolean expressions (TRUE/FALSE) */ #ifndef FALSE #define FALSE (BOOL)0 #endif #ifndef TRUE #define TRUE (BOOL)1 #endif /*-------------------------------------------------------------------------- DLL Import-Export ----------------------------------------------------------------------------*/ #ifdef OCT_WINENV #define DLLIMP __declspec( dllimport ) #define DLLEXP __declspec( dllexport ) #else #define DLLIMP #define DLLEXP #endif /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTDEF_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octmac.h0000644000175000017500000000666411431317470023023 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octmac.h Copyright (c) 2001-2007 Octasic Inc. Description: Common macro definitions. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTMAC_H__ #define __OCTMAC_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif /***************************** DEFINES *************************************/ /* Combine l & h to form a 32 bit quantity. */ #define mMAKEULONG(l, h) ((ULONG)(((USHORT)(l)) | (((ULONG)((USHORT)(h))) << 16))) #define mLOUCHAR(w) ((UCHAR)(w)) #define mHIUCHAR(w) ((UCHAR)(((USHORT)(w) >> 8) & 0xff)) #define mLOUSHORT(l) ((USHORT)((ULONG)l)) #define mHIUSHORT(l) ((USHORT)(((ULONG)(l) >> 16) & 0xffff)) #define mLOSHORT(l) ((SHORT)((ULONG)l)) #define mHISHORT(l) ((SHORT)(((ULONG)(l) >> 16) & 0xffff)) /* Combine l & h to form a 16 bit quantity. */ #define mMAKEUSHORT(l, h) (((USHORT)(l)) | ((USHORT)(h)) << 8) #define mMAKESHORT(l, h) ((SHORT)mMAKEUSHORT(l, h)) /* Extract high and low order parts of 16 and 32 bit quantity */ #define mLOBYTE(w) mLOUCHAR(w) #define mHIBYTE(w) mHIUCHAR(w) #define mMAKELONG(l, h) ((LONG)mMAKEULONG(l, h)) /*-------------------------------------------------------------------------- Bite conversion macro ----------------------------------------------------------------------------*/ #define mSWAP_INT16(x) mMAKEUSHORT( mHIBYTE(x), mLOBYTE(x) ) #define mSWAP_INT32(x) mMAKEULONG( mSWAP_INT16(mHIUSHORT(x)), mSWAP_INT16(mLOUSHORT(x)) ) /* Cast any variable to an instance of the specified type. */ #define mMAKETYPE(v, type) (*((type *)&v)) /* Calculate the byte offset of a field in a structure of type type. */ #define mFIELDOFFSET(type, field) ((UINT32)&(((type *)0)->field)) #define mCOUNTOF(array) (sizeof(array)/sizeof(array[0])) #define mMAX(a,b) (((a) > (b)) ? (a) : (b)) #define mMIN(a,b) (((a) < (b)) ? (a) : (b)) #define mDIM(x) (sizeof(x) / sizeof(x[0])) #define mFROMDIGIT(ch) ((ch) - 0x30) /* digit to char */ #define mTODIGIT(ch) ((ch) + 0x30) /* int to char */ #define mISLEAP(a) ( !( a % 400 ) || ( ( a % 100 ) && !( a % 4 ) ) ) #define mFOREVER for( ;; ) #define mROUND_TO_NEXT_4( a ) ( ((a) % 4) ? ( (a) + 4 - ((a)%4) ) : (a) ) /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTMAC_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/digium_unused.h0000644000175000017500000003036111431317470024405 0ustar tzafrirtzafrir/* Define macros here to suppress functions from the API being built */ #if 1 #define SKIP_Oct6100AdpcmChanOpenDef 1 #define SKIP_Oct6100AdpcmChanOpen 1 #define SKIP_Oct6100AdpcmChanCloseDef 1 #define SKIP_Oct6100AdpcmChanClose 1 #define SKIP_Oct6100AdpcmChanOpenSer 1 #define SKIP_Oct6100ApiCheckAdpcmChanParams 1 #define SKIP_Oct6100ApiReserveAdpcmChanResources 1 #define SKIP_Oct6100ApiWriteAdpcmChanStructs 1 #define SKIP_Oct6100ApiUpdateAdpcmChanEntry 1 #define SKIP_Oct6100AdpcmChanCloseSer 1 #define SKIP_Oct6100ApiAssertAdpcmChanParams 1 #define SKIP_Oct6100ApiInvalidateAdpcmChanStructs 1 #define SKIP_Oct6100ApiReleaseAdpcmChanResources 1 #define SKIP_Oct6100ApiReserveAdpcmChanEntry 1 #define SKIP_Oct6100ApiReleaseAdpcmChanEntry 1 #define SKIP_Oct6100ChannelCloseDef 1 #define SKIP_Oct6100ChannelClose 1 #define SKIP_Oct6100ChannelCreateBiDirDef 1 #define SKIP_Oct6100ChannelCreateBiDir 1 #define SKIP_Oct6100ChannelDestroyBiDirDef 1 #define SKIP_Oct6100ChannelDestroyBiDir 1 #define SKIP_Oct6100ChannelBroadcastTsstAddDef 1 #define SKIP_Oct6100ChannelBroadcastTsstAdd 1 #define SKIP_Oct6100ChannelBroadcastTsstRemove 1 #define SKIP_Oct6100ChannelGetStatsDef 1 #define SKIP_Oct6100ChannelGetStats 1 #define SKIP_Oct6100ChannelMuteDef 1 #define SKIP_Oct6100ChannelMute 1 #define SKIP_Oct6100ChannelUnMuteDef 1 #define SKIP_Oct6100ChannelUnMute 1 #define SKIP_Oct6100ChannelCloseSer 1 #define SKIP_Oct6100ApiAssertChannelParams 1 #define SKIP_Oct6100ApiInvalidateChannelStructs 1 #define SKIP_Oct6100ApiReleaseChannelResources 1 #define SKIP_Oct6100ChannelBroadcastTsstAddSer 1 #define SKIP_Oct6100ApiCheckChanTsstAddParams 1 #define SKIP_Oct6100ApiReserveTsstAddResources 1 #define SKIP_Oct6100ApiWriteTsstAddStructs 1 #define SKIP_Oct6100ApiUpdateTsstAddChanEntry 1 #define SKIP_Oct6100ApiChannelGetStatsSer 1 #define SKIP_Oct6100ApiReserveBiDirChanEntry 1 #define SKIP_Oct6100ApiReleaseBiDirChanEntry 1 #define SKIP_Oct6100ApiRetrieveNlpConfDword 1 #define SKIP_Oct6100ApiSaveNlpConfDword 1 #define SKIP_Oct6100ChannelCreateBiDirSer 1 #define SKIP_Oct6100ApiCheckChannelCreateBiDirParams 1 #define SKIP_Oct6100ApiReserveChannelCreateBiDirResources 1 #define SKIP_Oct6100ApiWriteChannelCreateBiDirStructs 1 #define SKIP_Oct6100ApiUpdateBiDirChannelEntry 1 #define SKIP_Oct6100ChannelDestroyBiDirSer 1 #define SKIP_Oct6100ApiAssertDestroyBiDirChanParams 1 #define SKIP_Oct6100ApiInvalidateBiDirChannelStructs 1 #define SKIP_Oct6100ApiReleaseBiDirChannelResources 1 #define SKIP_Oct6100ApiOctFloatToDbEnergyByte 1 #define SKIP_Oct6100ApiOctFloatToDbEnergyHalf 1 #define SKIP_Oct6100ChannelMuteSer 1 #define SKIP_Oct6100ApiAssertChannelMuteParams 1 #define SKIP_Oct6100ChannelUnMuteSer 1 #define SKIP_Oct6100ApiAssertChannelUnMuteParams 1 #define SKIP_Oct6100ApiMuteSinWithFeatures 1 #define SKIP_Oct6100ApiMuteChannelPorts 1 #define SKIP_Oct6100CreateLocalInstanceDef 1 #define SKIP_Oct6100CreateLocalInstance 1 #define SKIP_Oct6100DestroyLocalInstanceDef 1 #define SKIP_Oct6100DestroyLocalInstance 1 #define SKIP_Oct6100GetHwRevisionDef 1 #define SKIP_Oct6100GetHwRevision 1 #define SKIP_Oct6100FreeResourcesDef 1 #define SKIP_Oct6100FreeResources 1 #define SKIP_Oct6100ProductionBistDef 1 #define SKIP_Oct6100ProductionBist 1 #define SKIP_Oct6100ApiGetVersionDef 1 #define SKIP_Oct6100ApiGetVersion 1 #define SKIP_Oct6100FreeResourcesSer 1 #define SKIP_Oct6100ProductionBistSer 1 #define SKIP_Oct6100ChipGetStatsDef 1 #define SKIP_Oct6100ChipGetStats 1 #define SKIP_Oct6100ChipGetImageInfoDef 1 #define SKIP_Oct6100ChipGetImageInfo 1 #define SKIP_Oct6100ChipGetStatsSer 1 #define SKIP_Oct6100ConfBridgeOpenDef 1 #define SKIP_Oct6100ConfBridgeOpen 1 #define SKIP_Oct6100ConfBridgeClose 1 #define SKIP_Oct6100ConfBridgeChanAddDef 1 #define SKIP_Oct6100ConfBridgeChanAdd 1 #define SKIP_Oct6100ConfBridgeChanRemove 1 #define SKIP_Oct6100ConfBridgeChanMuteDef 1 #define SKIP_Oct6100ConfBridgeChanMute 1 #define SKIP_Oct6100ConfBridgeChanUnMuteDef 1 #define SKIP_Oct6100ConfBridgeChanUnMute 1 #define SKIP_Oct6100ConfBridgeDominantSpeakerSetDef 1 #define SKIP_Oct6100ConfBridgeDominantSpeakerSet 1 #define SKIP_Oct6100ConfBridgeMaskChangeDef 1 #define SKIP_Oct6100ConfBridgeMaskChange 1 #define SKIP_Oct6100ConfBridgeGetStatsDef 1 #define SKIP_Oct6100ConfBridgeGetStats 1 #define SKIP_Oct6100ConfBridgeOpenSer 1 #define SKIP_Oct6100ApiCheckBridgeParams 1 #define SKIP_Oct6100ApiReserveBridgeResources 1 #define SKIP_Oct6100ApiUpdateBridgeEntry 1 #define SKIP_Oct6100ConfBridgeChanAddSer 1 #define SKIP_Oct6100ApiCheckBridgeAddParams 1 #define SKIP_Oct6100ApiReserveBridgeAddResources 1 #define SKIP_Oct6100ApiBridgeEventAdd 1 #define SKIP_Oct6100ApiBridgeAddParticipantToChannel 1 #define SKIP_Oct6100ConfBridgeChanMuteSer 1 #define SKIP_Oct6100ApiCheckBridgeMuteParams 1 #define SKIP_Oct6100ApiUpdateBridgeMuteResources 1 #define SKIP_Oct6100ConfBridgeChanUnMuteSer 1 #define SKIP_Oct6100ApiCheckBridgeUnMuteParams 1 #define SKIP_Oct6100ApiUpdateBridgeUnMuteResources 1 #define SKIP_Oct6100ConfBridgeDominantSpeakerSetSer 1 #define SKIP_Oct6100ApiCheckBridgeDominantSpeakerParams 1 #define SKIP_Oct6100ApiUpdateBridgeDominantSpeakerResources 1 #define SKIP_Oct6100ConfBridgeMaskChangeSer 1 #define SKIP_Oct6100ApiCheckBridgeMaskChangeParams 1 #define SKIP_Oct6100ApiUpdateMaskModifyResources 1 #define SKIP_Oct6100ApiBridgeUpdateMask 1 #define SKIP_Oct6100ConfBridgeGetStatsSer 1 #define SKIP_Oct6100ApiReserveBridgeEntry 1 #define SKIP_Oct6100ApiReserveFlexConfParticipantEntry 1 #define SKIP_Oct6100DebugSelectChannelDef 1 #define SKIP_Oct6100DebugSelectChannel 1 #define SKIP_Oct6100DebugGetDataDef 1 #define SKIP_Oct6100DebugGetData 1 #define SKIP_Oct6100DebugSelectChannelSer 1 #define SKIP_Oct6100DebugGetDataSer 1 #define SKIP_Oct6100BufferPlayoutGetEventDef 1 #define SKIP_Oct6100BufferPlayoutGetEvent 1 #define SKIP_Oct6100BufferPlayoutGetEventSer 1 #define SKIP_Oct6100InterruptConfigureDef 1 #define SKIP_Oct6100InterruptConfigure 1 #define SKIP_Oct6100ApiReserveBufferPlayoutMemoryNode 1 #define SKIP_Oct6100ApiReleaseBufferPlayoutMemoryNode 1 #define SKIP_Oct6100ApiReserveBufferPlayoutMemory 1 #define SKIP_Oct6100ApiReleaseBufferPlayoutMemory 1 #define SKIP_Oct6100ApiCreateFeatureMask 1 #define SKIP_Oct6100MixerCopyEventCreateDef 1 #define SKIP_Oct6100MixerCopyEventCreate 1 #define SKIP_Oct6100MixerCopyEventDestroyDef 1 #define SKIP_Oct6100MixerCopyEventDestroy 1 #define SKIP_Oct6100MixerCopyEventCreateSer 1 #define SKIP_Oct6100ApiCheckCopyEventCreateParams 1 #define SKIP_Oct6100ApiReserveCopyEventCreateResources 1 #define SKIP_Oct6100ApiWriteCopyEventCreateStructs 1 #define SKIP_Oct6100ApiUpdateCopyEventCreateEntry 1 #define SKIP_Oct6100MixerCopyEventDestroySer 1 #define SKIP_Oct6100ApiAssertCopyEventDestroyParams 1 #define SKIP_Oct6100ApiInvalidateCopyEventStructs 1 #define SKIP_Oct6100ApiReleaseCopyEventResources 1 #define SKIP_Oct6100ApiReserveCopyEventEntry 1 #define SKIP_Oct6100ApiReleaseCopyEventEntry 1 #define SKIP_Oct6100PhasingTsstOpenDef 1 #define SKIP_Oct6100PhasingTsstOpen 1 #define SKIP_Oct6100PhasingTsstCloseDef 1 #define SKIP_Oct6100PhasingTsstClose 1 #define SKIP_Oct6100PhasingTsstOpenSer 1 #define SKIP_Oct6100ApiCheckPhasingParams 1 #define SKIP_Oct6100ApiReservePhasingResources 1 #define SKIP_Oct6100ApiWritePhasingStructs 1 #define SKIP_Oct6100ApiUpdatePhasingEntry 1 #define SKIP_Oct6100PhasingTsstCloseSer 1 #define SKIP_Oct6100ApiAssertPhasingParams 1 #define SKIP_Oct6100ApiInvalidatePhasingStructs 1 #define SKIP_Oct6100ApiReleasePhasingResources 1 #define SKIP_Oct6100ApiReservePhasingEntry 1 #define SKIP_Oct6100ApiReleasePhasingEntry 1 #define SKIP_Oct6100BufferPlayoutLoadDef 1 #define SKIP_Oct6100BufferPlayoutLoad 1 #define SKIP_Oct6100BufferPlayoutLoadBlockInitDef 1 #define SKIP_Oct6100BufferPlayoutLoadBlockInit 1 #define SKIP_Oct6100BufferPlayoutLoadBlockDef 1 #define SKIP_Oct6100BufferPlayoutLoadBlock 1 #define SKIP_Oct6100BufferPlayoutUnloadDef 1 #define SKIP_Oct6100BufferPlayoutUnload 1 #define SKIP_Oct6100BufferPlayoutAddDef 1 #define SKIP_Oct6100BufferPlayoutAdd 1 #define SKIP_Oct6100BufferPlayoutStartDef 1 #define SKIP_Oct6100BufferPlayoutStart 1 #define SKIP_Oct6100BufferPlayoutStop 1 #define SKIP_Oct6100BufferLoadSer 1 #define SKIP_Oct6100BufferLoadBlockInitSer 1 #define SKIP_Oct6100BufferLoadBlockSer 1 #define SKIP_Oct6100ApiCheckBufferParams 1 #define SKIP_Oct6100ApiCheckBufferLoadBlockParams 1 #define SKIP_Oct6100ApiReserveBufferResources 1 #define SKIP_Oct6100ApiWriteBufferInMemory 1 #define SKIP_Oct6100ApiUpdateBufferEntry 1 #define SKIP_Oct6100BufferUnloadSer 1 #define SKIP_Oct6100ApiAssertBufferParams 1 #define SKIP_Oct6100ApiReleaseBufferResources 1 #define SKIP_Oct6100BufferPlayoutAddSer 1 #define SKIP_Oct6100ApiCheckPlayoutAddParams 1 #define SKIP_Oct6100ApiWriteBufferAddStructs 1 #define SKIP_Oct6100BufferPlayoutStartSer 1 #define SKIP_Oct6100ApiCheckPlayoutStartParams 1 #define SKIP_Oct6100ApiWriteChanPlayoutStructs 1 #define SKIP_Oct6100ApiReserveBufPlayoutListEntry 1 #define SKIP_Oct6100ApiReleaseBufPlayoutListEntry 1 #define SKIP_Oct6100RemoteDebugDef 1 #define SKIP_Oct6100RemoteDebug 1 #define SKIP_Oct6100ApiCheckEndianDetectField 1 #define SKIP_Oct6100ApiCalculateChecksum 1 #define SKIP_Oct6100ApiFormResponsePkt 1 #define SKIP_Oct6100ApiCheckPktCommands 1 #define SKIP_Oct6100ApiExecutePktCommands 1 #define SKIP_Oct6100ApiCheckSessionNum 1 #define SKIP_Oct6100ApiRpcReadWord 1 #define SKIP_Oct6100ApiRpcReadBurst 1 #define SKIP_Oct6100ApiRpcReadArray 1 #define SKIP_Oct6100ApiRpcWriteWord 1 #define SKIP_Oct6100ApiRpcWriteSmear 1 #define SKIP_Oct6100ApiRpcWriteBurst 1 #define SKIP_Oct6100ApiRpcSetHotChannel 1 #define SKIP_Oct6100ApiRpcGetDebugChanIndex 1 #define SKIP_Oct6100ApiRpcDisconnect 1 #define SKIP_Oct6100ToneDetectionDisable 1 #define SKIP_Oct6100TsiCnctOpenDef 1 #define SKIP_Oct6100TsiCnctOpen 1 #define SKIP_Oct6100TsiCnctCloseDef 1 #define SKIP_Oct6100TsiCnctClose 1 #define SKIP_Oct6100TsiCnctOpenSer 1 #define SKIP_Oct6100ApiCheckTsiParams 1 #define SKIP_Oct6100ApiReserveTsiResources 1 #define SKIP_Oct6100ApiWriteTsiStructs 1 #define SKIP_Oct6100ApiUpdateTsiEntry 1 #define SKIP_Oct6100TsiCnctCloseSer 1 #define SKIP_Oct6100ApiAssertTsiParams 1 #define SKIP_Oct6100ApiInvalidateTsiStructs 1 #define SKIP_Oct6100ApiReleaseTsiResources 1 #define SKIP_Oct6100ApiReserveTsiCnctEntry 1 #define SKIP_Oct6100ApiReleaseTsiCnctEntry 1 #define SKIP_Oct6100UserDriverWriteOs 1 #define SKIP_Oct6100UserDriverWriteSmearOs 1 #define SKIP_Oct6100UserDriverWriteBurstOs 1 #define SKIP_Oct6100UserDriverReadOs 1 #define SKIP_Oct6100UserDriverReadBurstOs 1 #define SKIP_OctApiBt0AddNode 1 #define SKIP_OctApiBt0AddNode2 1 #define SKIP_OctApiBt0AddNode3 1 #define SKIP_OctApiBt0AddNode4 1 #define SKIP_OctApiBt0KeyCompare 1 #define SKIP_OctApiBt0UpdateLinkDepth 1 #define SKIP_OctApiBt0Rebalance 1 #define SKIP_OctApiBt0ExternalHeavy 1 #define SKIP_OctApiBt0RemoveNode2 1 #define SKIP_OctApiBt0RemoveNode3 1 #define SKIP_OctApiBt0RemoveNode 1 #define SKIP_OctApiBt0QueryNode2 1 #define SKIP_OctApiBt0QueryNode 1 #define SKIP_OctApiBt0GetFirstNode 1 #define SKIP_OctApiBt0FindOrAddNode 1 #define SKIP_OctApiBt0AddNodeReportPrevNodeData 1 #define SKIP_OctApiLmCompare 1 #define SKIP_OctApiLmMultiply 1 #define SKIP_OctApiLmDivide 1 #define SKIP_OctApiLmShiftRight1 1 #define SKIP_OctApiLmShiftn 1 #define SKIP_OctApiLmGetMsb 1 #define SKIP_OctApiTllmAllocGetSize 1 #define SKIP_OctApiTllmAllocInit 1 #define SKIP_OctApiTllmAllocInfo 1 #define SKIP_OctApiTllmAllocAlloc 1 #define SKIP_OctApiTllmAllocDealloc 1 #define SKIP_OctApiTllmCheckTimeoutList 1 #define SKIP_OctApiLlmListGetSize 1 #define SKIP_OctApiLlmListGetItemPointer 1 #define SKIP_OctApiLlmListInit 1 #define SKIP_OctApiLlmListInfo 1 #define SKIP_OctApiLlmListCreate 1 #define SKIP_OctApiLlmListDelete 1 #define SKIP_OctApiLlmListLength 1 #define SKIP_OctApiLlmListItemData 1 #define SKIP_OctApiLlmListInsertItem 1 #define SKIP_OctApiLlmListCreateFull 1 #define SKIP_OctApiLlmListAppendItems 1 #define SKIP_OctApiLlmListAppendAndSetItems 1 #define SKIP_OctApiLlmListSetItems 1 #define SKIP_OctApiLlmListCopyData 1 #define SKIP_OctApiLlmListRemoveItem 1 #define SKIP_OctApiLlm2ListGetSize 1 #define SKIP_OctApiLlm2ListGetItemPointer 1 #define SKIP_OctApiLlm2ListInit 1 #define SKIP_OctApiLlm2ListCreate 1 #define SKIP_OctApiLlm2ListDelete 1 #define SKIP_OctApiLlm2ListLength 1 #define SKIP_OctApiLlm2ListItemData 1 #define SKIP_OctApiLlm2ListInsertItem 1 #define SKIP_OctApiLlm2ListRemoveItem 1 #define SKIP_OctApiLlmMemCpy 1 #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/0000755000175000017500000000000011631523356023162 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_remote_debug_inst.h0000644000175000017500000000443411431317470030206 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_remote_debug_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_remote_debug.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_remote_debug_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_REMOTE_DEBUG_INST_H__ #define __OCT6100_REMOTE_DEBUG_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_REMOTE_DEBUG_INFO_ { UINT32 ulSessionTreeOfst; UINT32 ulSessionListOfst; UINT32 ulSessionListHead; UINT32 ulSessionListTail; UINT32 ulPktCacheOfst; UINT32 ulDataBufOfst; UINT32 ulNumSessionsOpen; UINT32 ulMaxSessionsOpen; } tOCT6100_API_REMOTE_DEBUG_INFO, *tPOCT6100_API_REMOTE_DEBUG_INFO; typedef struct _OCT6100_API_REMOTE_DEBUG_SESSION_ { UINT32 ulSessionNum; UINT32 ulTransactionNum; UINT32 ulPktRetryNum; UINT32 ulPktByteSize; UINT32 aulLastPktTime[ 2 ]; UINT32 ulForwardLink; UINT32 ulBackwardLink; } tOCT6100_API_REMOTE_DEBUG_SESSION, *tPOCT6100_API_REMOTE_DEBUG_SESSION; #endif /* __OCT6100_REMOTE_DEBUG_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tlv_inst.h0000644000175000017500000000451211431317470026347 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tlv_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tlv.c. All elements defined in this file are for public usage of the API. All instate elements are defined in the oct6100_tlv_inst.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 7 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TLV_INST_H__ #define __OCT6100_TLV_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_TLV_OFFSET_ { /* The dword offset contain the number of dword from a base address to reach the desired dword. i.e. usDwordOffset = (total bit offset) / 32; */ UINT16 usDwordOffset; /* The bit offset will contain the bit offset required to right shift the DWORD read and obtain the desired value. This field is depend on the field size. i.e. byBitOffset = 31 - ((total bit offset) % 32) - byFieldSize; */ UINT8 byBitOffset; UINT8 byFieldSize; } tOCT6100_TLV_OFFSET, *tPOCT6100_TLV_OFFSET; typedef struct _OCT6100_TLV_TONE_INFO_ { UINT32 ulToneID; UINT32 ulDetectionPort; UINT8 aszToneName[ cOCT6100_TLV_MAX_TONE_NAME_SIZE ]; } tOCT6100_TLV_TONE_INFO, *tPOCT6100_TLV_TONE_INFO; #endif /* __OCT6100_TLV_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tsi_cnct_pub.h0000644000175000017500000000475611431317470027173 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsi_cnct_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tsi_cnct.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_tsi_cnct_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 11 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TSI_CNCT_PUB_H__ #define __OCT6100_TSI_CNCT_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_TSI_CNCT_OPEN_ { PUINT32 pulTsiCnctHndl; UINT32 ulInputTimeslot; UINT32 ulInputStream; UINT32 ulOutputTimeslot; UINT32 ulOutputStream; } tOCT6100_TSI_CNCT_OPEN, *tPOCT6100_TSI_CNCT_OPEN; typedef struct _OCT6100_TSI_CNCT_CLOSE_ { UINT32 ulTsiCnctHndl; } tOCT6100_TSI_CNCT_CLOSE, *tPOCT6100_TSI_CNCT_CLOSE; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100TsiCnctOpenDef( OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ); UINT32 Oct6100TsiCnctOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ); UINT32 Oct6100TsiCnctCloseDef( OUT tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ); UINT32 Oct6100TsiCnctClose( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ); #endif /* __OCT6100_TSI_CNCT_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tsst_inst.h0000644000175000017500000000374111431317470026542 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsst_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tsst.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_tsst_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 5 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TSST_INST_H__ #define __OCT6100_TSST_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_TSST_ENTRY_ { UINT16 usTsstMemoryIndex; /* Index in the TSST memory of the TSST */ UINT16 usTsstValue; /* Tsst value given by the user. */ /* bit 5:0 = stream value, bit 13:6 = timeslot value. */ UINT16 usNextEntry; /* Pointer to the next entry in the list. */ } tOCT6100_API_TSST_ENTRY, *tPOCT6100_API_TSST_ENTRY; #endif /* __OCT6100_TSST_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_playout_buf_inst.h0000644000175000017500000000557011431317470030100 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_playout_buf_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_playout_buf.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_playout_buf_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 10 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PLAYOUT_BUF_INST_H__ #define __OCT6100_PLAYOUT_BUF_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_BUFFER_MEMORY_NODE_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE )(( PUINT8 )pSharedInfo + pSharedInfo->ulPlayoutBufMemoryNodeListOfst ); #define mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE )(( PUINT8 )pSharedInfo + pSharedInfo->ulPlayoutBufMemoryNodeListOfst)) + ulIndex; /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE_ { /* Next node. */ UINT32 ulNext; /* Previous node. */ UINT32 ulPrevious; /* Start address of this node. */ UINT32 ulStartAddress; /* Size of this node. */ UINT32 ulSize; /* Allocated node? Free node? */ UINT8 fAllocated; } tOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE, *tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE; typedef struct _OCT6100_API_BUFFER_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Pcm law of the buffer. */ UINT8 byBufferPcmLaw; /* Number of channels currently playing this buffer.*/ UINT16 usDependencyCnt; /* Length of the buffer ( in bytes ).*/ UINT32 ulBufferSize; /* Address in external memory of the buffer. */ UINT32 ulBufferBase; } tOCT6100_API_BUFFER, *tPOCT6100_API_BUFFER; #endif /* __OCT6100_PLAYOUT_BUF_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_phasing_tsst_inst.h0000644000175000017500000000441711431317470030254 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_phasing_tsst_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_phasing_tsst.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_phasing_tsst_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 11 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PHASING_TSST_INST_H__ #define __OCT6100_PHASING_TSST_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_PHASING_TSST_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt; /* Count of number of resources connected in some way to this buffer. */ UINT16 usDependencyCnt; /* TDM timeslot and stream where the counter is read. */ UINT16 usStream; UINT16 usTimeslot; /* Length of the phasing TSST counter. */ UINT16 usPhasingLength; /* TSST control index where the counter comes from. */ UINT16 usPhasingTsstIndex; } tOCT6100_API_PHASING_TSST, *tPOCT6100_API_PHASING_TSST; #endif /* __OCT6100_PHASING_TSST_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_debug_inst.h0000644000175000017500000000720011431317470026625 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_debug_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_debug.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_debug_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 10 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_DEBUG_INST_H__ #define __OCT6100_DEBUG_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_DEBUG_ { /* Information from the TLVs. */ UINT32 ulDebugEventSize; UINT32 ulMatrixBaseAddress; UINT32 ulDebugChanStatsByteSize; UINT32 ulDebugChanLiteStatsByteSize; UINT32 ulHotChannelSelectBaseAddress; UINT32 ulMatrixTimestampBaseAddress; UINT32 ulAfWritePtrByteOffset; UINT32 ulRecordedPcmEventByteSize; UINT32 ulMatrixWpBaseAddress; /* Pouch counter presence in the image. */ UINT8 fPouchCounter; /* Record channel indexes. */ UINT16 usRecordMemIndex; UINT16 usRecordChanIndex; UINT16 usRecordRinRoutTsiMemIndex; UINT16 usRecordSinSoutTsiMemIndex; /* Debug channel information.*/ UINT16 usCurrentDebugChanIndex; /* Matrix event mask. */ UINT16 usMatrixCBMask; /* If data is being dumped now. */ UINT8 fDebugDataBeingDumped; /* Index of the last event retrieved. */ UINT16 usLastDebugEventIndex; /* Number of events to retrieve. */ UINT16 usNumEvents; /* Chip debug event write ptr. */ UINT16 usChipDebugEventWritePtr; /* Hot channel read data. */ UINT16 ausHotChannelData[ 2 ]; /* Last PCM sample index. */ UINT32 ulLastPcmSampleIndex; /* Last AF log read pointer. */ UINT16 usLastAfLogReadPtr; /* AF log hardware write pointer. */ UINT16 usAfLogWritePtr; /* Last tone event index retrieved. */ UINT16 usLastToneEventIndex; /* Whether the image version string has been copied in the user buffer. */ BOOL fImageVersionCopied; /* Whether the api version string has been copied in the user buffer. */ BOOL fApiVersionCopied; /* Total number of bytes that will be returned for the current dump. */ UINT32 ulDebugDataTotalNumBytes; /* Field to detect if the ISR is called present? */ BOOL fIsIsrCalledField; /* Remaining number of bytes that will be returned for the current dump. */ UINT32 ulDebugDataRemainingNumBytes; /* AF events control block size. */ UINT32 ulAfEventCbByteSize; /* Current user selected data mode. Must be kept constant throughout a debug session. */ UINT32 ulCurrentGetDataMode; } tOCT6100_API_DEBUG, *tPOCT6100_API_DEBUG; #endif /* __OCT6100_DEBUG_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_events_inst.h0000644000175000017500000000425011431317470027045 0ustar tzafrirtzafrir /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_events_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_events.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_events_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 12 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_EVENTS_INST_H__ #define __OCT6100_EVENTS_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_TONE_EVENT_ { UINT32 ulChannelHandle; UINT32 ulUserChanId; UINT32 ulToneDetected; /* Tone number of the tone detected. */ UINT32 ulTimestamp; UINT32 ulEventType; UINT32 ulExtToneDetectionPort; } tOCT6100_API_TONE_EVENT, *tPOCT6100_API_TONE_EVENT; typedef struct _OCT6100_API_BUFFER_PLAYOUT_EVENT_ { UINT32 ulChannelHandle; UINT32 ulUserChanId; UINT32 ulChannelPort; UINT32 ulTimestamp; UINT32 ulUserEventId; UINT32 ulEventType; } tOCT6100_API_BUFFER_PLAYOUT_EVENT, *tPOCT6100_API_BUFFER_PLAYOUT_EVENT; #endif /* __OCT6100_EVENTS_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_conf_bridge_inst.h0000644000175000017500000000637511431317470030014 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_conf_bridge_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_conf_bridge.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_conf_bridge_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 19 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CONF_BRIDGE_INST_H__ #define __OCT6100_CONF_BRIDGE_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_CONF_BRIDGE_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Entry counter for the resources. */ UINT8 byEntryOpenCnt; /* Next bridge pointer. */ UINT16 usNextBridgePtr; /* Previous bridge pointer. */ UINT16 usPrevBridgePtr; /* Number of clients connected to the bridge. */ UINT16 usNumClients; /* Store the index of the load event, to diffentiate him form the accumulate. */ UINT16 usLoadIndex; /* Pointer to the first bridge events.*/ UINT16 usFirstLoadEventPtr; UINT16 usFirstSubStoreEventPtr; UINT16 usLastSubStoreEventPtr; /* Pointer to the silence load event, if it exists. */ UINT16 usSilenceLoadEventPtr; /* Flag specifying whether the dominant speaker is set or not. */ UINT16 usDominantSpeakerChanIndex; UINT8 fDominantSpeakerSet; /* Flag specifying if this is flexible conferencing bridge. */ UINT8 fFlexibleConferencing; /* Number of clients being tapped. */ UINT16 usNumTappedClients; } tOCT6100_API_CONF_BRIDGE, *tPOCT6100_API_CONF_BRIDGE; typedef struct _OCT6100_API_FLEX_CONF_PARTICIPANT_ { /* Input port of the conferencing for this participant. */ UINT32 ulInputPort; /* Whether the flexible mixer has been created. */ UINT8 fFlexibleMixerCreated; /* Listener mask ( who can hear us ). */ UINT32 ulListenerMask; /* Our index in the listener mask. */ UINT32 ulListenerMaskIndex; /* Mixer event indexes for this participant's mixer. */ UINT16 ausLoadOrAccumulateEventIndex[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ]; } tOCT6100_API_FLEX_CONF_PARTICIPANT, *tPOCT6100_API_FLEX_CONF_PARTICIPANT; #endif /* __OCT6100_CONF_BRIDGE_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_events_pub.h0000644000175000017500000000621511431317470026661 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_events_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_events.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_events_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_EVENTS_PUB_H__ #define __OCT6100_EVENTS_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_TONE_EVENT_ { UINT32 ulChannelHndl; UINT32 ulUserChanId; UINT32 ulToneDetected; UINT32 ulTimestamp; UINT32 ulEventType; UINT32 ulExtToneDetectionPort; } tOCT6100_TONE_EVENT, *tPOCT6100_TONE_EVENT; typedef struct _OCT6100_EVENT_GET_TONE_ { BOOL fMoreEvents; BOOL fResetBufs; UINT32 ulMaxToneEvent; UINT32 ulNumValidToneEvent; tPOCT6100_TONE_EVENT pToneEvent; } tOCT6100_EVENT_GET_TONE, *tPOCT6100_EVENT_GET_TONE; typedef struct _OCT6100_BUFFER_PLAYOUT_EVENT_ { UINT32 ulChannelHndl; UINT32 ulUserChanId; UINT32 ulChannelPort; UINT32 ulTimestamp; UINT32 ulUserEventId; UINT32 ulEventType; } tOCT6100_BUFFER_PLAYOUT_EVENT, *tPOCT6100_BUFFER_PLAYOUT_EVENT; typedef struct _OCT6100_BUFFER_PLAYOUT_GET_EVENT_ { BOOL fMoreEvents; BOOL fResetBufs; UINT32 ulMaxEvent; UINT32 ulNumValidEvent; tPOCT6100_BUFFER_PLAYOUT_EVENT pBufferPlayoutEvent; } tOCT6100_BUFFER_PLAYOUT_GET_EVENT, *tPOCT6100_BUFFER_PLAYOUT_GET_EVENT; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100EventGetToneDef( OUT tPOCT6100_EVENT_GET_TONE f_pEventGetTone ); UINT32 Oct6100EventGetTone( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_EVENT_GET_TONE f_pEventGetTone ); UINT32 Oct6100BufferPlayoutGetEventDef( OUT tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ); UINT32 Oct6100BufferPlayoutGetEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ); #endif /* __OCT6100_EVENTS_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_adpcm_chan_pub.h0000644000175000017500000000540611431317470027433 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_adpcm_chan_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_adpcm_chan.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_adpcm_chan_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 5 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_ADPCM_CHAN_PUB_H__ #define __OCT6100_ADPCM_CHAN_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_ADPCM_CHAN_OPEN_ { PUINT32 pulChanHndl; UINT32 ulInputTimeslot; UINT32 ulInputStream; UINT32 ulInputNumTssts; UINT32 ulInputPcmLaw; UINT32 ulOutputTimeslot; UINT32 ulOutputStream; UINT32 ulOutputNumTssts; UINT32 ulOutputPcmLaw; UINT32 ulChanMode; /* Encoding or decoding. */ UINT32 ulEncodingRate; UINT32 ulDecodingRate; UINT32 ulAdpcmNibblePosition; } tOCT6100_ADPCM_CHAN_OPEN, *tPOCT6100_ADPCM_CHAN_OPEN; typedef struct _OCT6100_ADPCM_CHAN_CLOSE_ { UINT32 ulChanHndl; } tOCT6100_ADPCM_CHAN_CLOSE, *tPOCT6100_ADPCM_CHAN_CLOSE; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100AdpcmChanOpenDef( OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ); UINT32 Oct6100AdpcmChanOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ); UINT32 Oct6100AdpcmChanCloseDef( OUT tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ); UINT32 Oct6100AdpcmChanClose( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ); #endif /* __OCT6100_ADPCM_CHAN_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_phasing_tsst_pub.h0000644000175000017500000000505511431317470030064 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_phasing_tsst_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_phasing_tsst.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_phasing_tsst_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 10 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PHASING_TSST_PUB_H__ #define __OCT6100_PHASING_TSST_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_PHASING_TSST_OPEN_ { PUINT32 pulPhasingTsstHndl; UINT32 ulPhasingLength; UINT32 ulTimeslot; UINT32 ulStream; } tOCT6100_PHASING_TSST_OPEN, *tPOCT6100_PHASING_TSST_OPEN; typedef struct _OCT6100_PHASING_TSST_CLOSE_ { UINT32 ulPhasingTsstHndl; } tOCT6100_PHASING_TSST_CLOSE, *tPOCT6100_PHASING_TSST_CLOSE; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100PhasingTsstOpenDef( OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ); UINT32 Oct6100PhasingTsstOpen( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ); UINT32 Oct6100PhasingTsstCloseDef( OUT tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ); UINT32 Oct6100PhasingTsstClose( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ); #endif /* __OCT6100_PHASING_TSST_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_defines.h0000644000175000017500000006137111603154003026120 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_defines.h Copyright (c) 2001-2007 Octasic Inc. Description: Header file containing all defines used throughout the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.7 $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 171 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_DEFINES_H__ #define __OCT6100_DEFINES_H__ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" /***************************** DEFINES *************************************/ /* 32-bits values. */ #define cOCT6100_FFFFFFFF 0xFFFFFFFF #define cOCT6100_FFFFFFFE 0xFFFFFFFE #define cOCT6100_7FFFFFFF 0x7FFFFFFF /* 16-bits values. */ #define cOCT6100_FFFD 0xFFFD #define cOCT6100_FFFE 0xFFFE #define cOCT6100_FFFF 0xFFFF #define cOCT6100_7FFF 0x7FFF /* 8-bits values. */ #define cOCT6100_FF 0xFF #define cOCT6100_CURRENT_VALUE cOCT6100_FFFFFFFF #define cOCT6100_INVALID_CHIP_ID cOCT6100_FFFFFFFF #define cOCT6100_INVALID_HANDLE cOCT6100_FFFFFFFF #define cOCT6100_INVALID_TIMESLOT cOCT6100_FFFFFFFF #define cOCT6100_INVALID_STREAM cOCT6100_FFFFFFFF #define cOCT6100_INVALID_VALUE cOCT6100_FFFFFFFF #define cOCT6100_INVALID_STAT cOCT6100_FFFFFFFF #define cOCT6100_INVALID_STAT_W cOCT6100_FFFF #define cOCT6100_INVALID_PCM_LAW cOCT6100_FF #define cOCT6100_INVALID_EVENT cOCT6100_FFFF #define cOCT6100_INVALID_INDEX cOCT6100_FFFF #define cOCT6100_INVALID_TONE cOCT6100_FFFFFFFF #define cOCT6100_INVALID_PORT cOCT6100_FF #define cOCT6100_AUTO_SELECT cOCT6100_FFFFFFFE #define cOCT6100_AUTO_SELECT_TAIL cOCT6100_FFFE #define cOCT6100_INVALID_BOOL 2 #define cOCT6100_KEEP_PREVIOUS_SETTING 0x70100000 #define cOCT6100_INVALID_SIGNED_STAT cOCT6100_7FFFFFFF #define cOCT6100_INVALID_SIGNED_STAT_W cOCT6100_7FFF #define cOCT6100_INVALID_ECHO_DELAY 0x400 #define cOCT6100_SIZE_128 128 #define cOCT6100_SIZE_256 256 #define cOCT6100_SIZE_512 512 #define cOCT6100_SIZE_1K 1024 #define cOCT6100_SIZE_2K 2048 #define cOCT6100_SIZE_4K 4096 #define cOCT6100_SIZE_8K 8192 #define cOCT6100_SIZE_16K 16384 #define cOCT6100_SIZE_32K 32768 #define cOCT6100_SIZE_64K 65536 #define cOCT6100_SIZE_128K 131072 #define cOCT6100_SIZE_256K 262144 #define cOCT6100_SIZE_512K 524288 #define cOCT6100_SIZE_1M 1048576 #define cOCT6100_SIZE_2M 2097152 #define cOCT6100_SIZE_4M 4194304 #define cOCT6100_SIZE_8M 8388608 #define cOCT6100_SIZE_16M 16777216 #define cOCT6100_SIZE_32M 33554432 #define cOCT6100_SIZE_64M 67108864 #define cOCT6100_SIZE_128M 134217728 #define cOCT6100_SIZE_256M 268435456 #define cOCT6100_SIZE_512M 536870912 #define cOCT6100_SIZE_1G 1073741824 #define cOCT6100_SIZE_2G 2147483648 #define cOCT6100_HNDL_TAG_MASK 0xFF000000 #define cOCT6100_HNDL_INDEX_MASK 0x0000FFFF #define cOCT6100_ENTRY_OPEN_CNT_MASK 0x000000FF #define cOCT6100_ENTRY_OPEN_CNT_SHIFT 16 #define cOCT6100_HNDL_TAG_INVALID 0xFF000000 #define cOCT6100_HNDL_TAG_CHANNEL 0x01000000 #define cOCT6100_HNDL_TAG_TSI_CNCT 0x02000000 #define cOCT6100_HNDL_TAG_CONF_BRIDGE 0x03000000 #define cOCT6100_HNDL_TAG_PHASING_TSST 0x04000000 #define cOCT6100_HNDL_TAG_BIDIR_CHANNEL 0x05000000 #define cOCT6100_HNDL_TAG_COPY_EVENT 0x06000000 #define cOCT6100_HNDL_TAG_ADPCM_CHANNEL 0x07000000 #define cOCT6100_INVALID_HANDLE_TYPE cOCT6100_INVALID_VALUE #define cOCT6100_MEMORY_ROUND_SIZE 16 #define mOCT6100_ROUND_MEMORY_SIZE( ulMemorySize, ulTempVar ) \ if ((ulTempVar = ulMemorySize % cOCT6100_MEMORY_ROUND_SIZE) != 0) \ ulMemorySize += cOCT6100_MEMORY_ROUND_SIZE - ulTempVar; #define mOCT6100_ROUND_ADDRESS( ulAddress, ulBoundary, ulTempVar ) \ if ((ulTempVar = ulAddress % ulBoundary) != 0) \ ulAddress += ulBoundary - ulTempVar; #define cOCT6100_INTERNAL_CLOCK_SOURCE 0 #define cOCT6100_EXTERNAL_CLOCK_SOURCE 1 #define cOCT6100_ACTIVE_HIGH_POLARITY 0 #define cOCT6100_ACTIVE_LOW_POLARITY 1 #define cOCT6100_TDM_SAMPLE_AT_3_QUARTERS 0 #define cOCT6100_TDM_SAMPLE_AT_RISING_EDGE 1 #define cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE 2 #define cOCT6100_TDM_STREAM_FREQ_2MHZ 0 #define cOCT6100_TDM_STREAM_FREQ_4MHZ 1 #define cOCT6100_TDM_STREAM_FREQ_8MHZ 2 #define cOCT6100_TDM_STREAM_FREQ_16MHZ 3 #define cOCT6100_TDM_STREAM_MAX_GROUPS 8 #define cOCT6100_PCM_U_LAW 0 #define cOCT6100_PCM_A_LAW 1 #define cOCT6100_PCM_UNCHANGED 2 #define cOCT6100_ADPCM_ENCODED 3 #define cOCT6100_INTERRUPT_DISABLE 0 #define cOCT6100_INTERRUPT_NO_TIMEOUT 1 #define cOCT6100_INTERRUPT_TIMEOUT 2 #define cOCT6100_NUMBER_TSSTS_1 1 #define cOCT6100_NUMBER_TSSTS_2 2 #define cOCT6100_G711_64KBPS 1 #define cOCT6100_G726_40KBPS 2 #define cOCT6100_G726_32KBPS 3 #define cOCT6100_G726_24KBPS 4 #define cOCT6100_G726_16KBPS 5 #define cOCT6100_G727_40KBPS_4_1 6 #define cOCT6100_G727_40KBPS_3_2 7 #define cOCT6100_G727_40KBPS_2_3 8 #define cOCT6100_G727_32KBPS_4_0 9 #define cOCT6100_G727_32KBPS_3_1 10 #define cOCT6100_G727_32KBPS_2_2 11 #define cOCT6100_G727_24KBPS_3_0 12 #define cOCT6100_G727_24KBPS_2_1 13 #define cOCT6100_G727_16KBPS_2_0 14 #define cOCT6100_G726_ENCODED 15 #define cOCT6100_G711_G726_ENCODED 16 #define cOCT6100_G711_G727_2C_ENCODED 17 #define cOCT6100_G711_G727_3C_ENCODED 18 #define cOCT6100_G711_G727_4C_ENCODED 19 #define cOCT6100_G727_2C_ENCODED 20 #define cOCT6100_G727_3C_ENCODED 21 #define cOCT6100_G727_4C_ENCODED 22 #define cOCT6100_ADPCM_IN_HIGH_BITS 0 #define cOCT6100_ADPCM_IN_LOW_BITS 1 /* The values of these defines must not change. */ #define cOCT6100_H100_TRACKA 0 #define cOCT6100_H100_TRACKB 1 #define cOCT6100_H100_TRACKA_FALLBACKB 2 #define cOCT6100_H100_TRACKB_FALLBACKA 3 #define cOCT6100_H100_DISABLED 4 #define cOCT6100_H100_MASTERA 5 #define cOCT6100_H100_BACKUPA 6 #define cOCT6100_H100_MASTERB 7 #define cOCT6100_H100_BACKUPB 8 #define cOCT6100_FREE_TSST 0 #define cOCT6100_RX_TSST 16 #define cOCT6100_TX_TSST 32 #define cOCT6100_INTRPT_ACTIVE 0 #define cOCT6100_INTRPT_WILL_TIMEOUT 1 #define cOCT6100_INTRPT_IN_TIMEOUT 2 #define cOCT6100_INTRPT_DISABLED 3 #define cOCT6100_EXTERNAL_MEM_BIST_TIMEOUT 1000000 /* Clocks defines */ #define cOCT6100_UPCLK_FREQ_33_33_MHZ 33333333 #define cOCT6100_MCLK_FREQ_133_MHZ 133000000 #define cOCT6100_MCLK_FREQ_125_MHZ 125000000 #define cOCT6100_MCLK_FREQ_117_MHZ 117000000 #define cOCT6100_MCLK_FREQ_108_MHZ 108000000 #define cOCT6100_MCLK_FREQ_100_MHZ 100000000 #define cOCT6100_MCLK_FREQ_92_MHZ 92000000 #define cOCT6100_MCLK_FREQ_83_MHZ 83000000 #define cOCT6100_MCLK_FREQ_75_MHZ 75000000 /* Tone buffer defines.*/ #define cOCT6100_MAX_NUM_TONE_BUFFERS 1344 #define cOCT6100_MAX_TONES_PER_CALL 32 /* Memory defines.*/ #define cOCT6100_MEM_TYPE_SDR 0 #define cOCT6100_MEM_TYPE_DDR 1 #define cOCT6100_MEM_TYPE_SDR_PLL_BYPASS 2 #define cOCT6100_MEMORY_CHIP_SIZE_8MB cOCT6100_SIZE_8M #define cOCT6100_MEMORY_CHIP_SIZE_16MB cOCT6100_SIZE_16M #define cOCT6100_MEMORY_CHIP_SIZE_32MB cOCT6100_SIZE_32M #define cOCT6100_MEMORY_CHIP_SIZE_64MB cOCT6100_SIZE_64M #define cOCT6100_MEMORY_CHIP_SIZE_128MB cOCT6100_SIZE_128M #define cOCT6100_MAX_NUM_MEMORY_CHIP 2 #define cOCT6100_16MB_MEMORY_BANKS 0 #define cOCT6100_32MB_MEMORY_BANKS 1 #define cOCT6100_64MB_MEMORY_BANKS 2 #define cOCT6100_128MB_MEMORY_BANKS 3 #define cOCT6100_1_MEMORY_BANKS 0 #define cOCT6100_2_MEMORY_BANKS 1 #define cOCT6100_3_MEMORY_BANKS 2 #define cOCT6100_4_MEMORY_BANKS 3 /* Chip open defines.*/ #define cOCT6100_INTERNAL_TONE_ARRAY_SIZE 256 /* in words.*/ #ifndef cOCT6100_INTERNAL_SUPER_ARRAY_SIZE #define cOCT6100_INTERNAL_SUPER_ARRAY_SIZE 128 /* in words.*/ #endif /* Internal memory mapping.*/ /*=======================================================================*/ #define cOCT6100_TSST_CONTROL_MEM_BASE 0x26000 #define cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE 2 /* Each entries are 2 bytes.*/ #define cOCT6100_TSST_CONTROL_MEM_INPUT_TSST 0x0800 #define cOCT6100_TSST_CONTROL_MEM_OUTPUT_TSST 0x2000 #define cOCT6100_TSST_CONTROL_MEM_PCM_LAW_OFFSET 12 #define cOCT6100_TSST_CONTROL_MEM_NIBBLE_POS_OFFSET 11 #define cOCT6100_TSST_CONTROL_MEM_TSST_NUM_OFFSET 12 #define cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK 0x7FF #define cOCT6100_TSST_CONTROL_PHASING_TSST_BASE_ENTRY 1344 #define cOCT6100_TSST_CONTROL_TIMESTAMP_BASE_ENTRY 1516 /*=======================================================================*/ #define cOCT6100_CONVERSION_CONTROL_MEM_BASE 0x28000 /* Each entries are 8 bytes but an 8 bytes mixer entry is located inbetween each entry.*/ #define cOCT6100_CONVERSION_CONTROL_MEM_ENTRY_SIZE 16 #define cOCT6100_CONVERSION_CONTROL_MEM_ENCODER 0x0000 #define cOCT6100_CONVERSION_CONTROL_MEM_DECODER 0x8000 #define cOCT6100_CONVERSION_CONTROL_MEM_ACTIVATE_ENTRY 0x8000 #define cOCT6100_CONVERSION_CONTROL_MEM_RST_ON_NEXT_FR 0x8000 #define cOCT6100_CONVERSION_CONTROL_MEM_PHASE_OFFSET 12 #define cOCT6100_CONVERSION_CONTROL_MEM_NIBBLE_POS_OFFSET 9 #define cOCT6100_CONVERSION_CONTROL_MEM_COMP_OFFSET 11 #define cOCT6100_CONVERSION_CONTROL_MEM_LAW_OFFSET 8 #define cOCT6100_CONVERSION_CONTROL_MEM_SIL_SUP_OFFSET 8 #define cOCT6100_CONVERSION_CONTROL_PHASE_SIZE_BASE_ADD 0x5400 /*=======================================================================*/ #define cOCT6100_MIXER_CONTROL_MEM_BASE 0x28008 /* Each entries are 8 bytes but an 8 bytes mixer entry is located inbetween each entry.*/ #define cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE 16 #define cOCT6100_MIXER_CONTROL_MEM_SUB_STORE 0xA000 #define cOCT6100_MIXER_CONTROL_MEM_STORE 0x8000 #define cOCT6100_MIXER_CONTROL_MEM_LOAD 0x4000 #define cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE 0x6000 #define cOCT6100_MIXER_CONTROL_MEM_COPY 0x2000 #define cOCT6100_MIXER_CONTROL_MEM_NO_OP 0x0000 #define cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET 11 #define cOCT6100_MIXER_HEAD_NODE 0 #define cOCT6100_MIXER_TAIL_NODE 1 #define cOCT6100_MIXER_RECORD_COPY_NODE 2 /*=======================================================================*/ #define cOCT6100_ECHO_CONTROL_MEM_BASE 0x14000 #define cOCT6100_ECHO_CONTROL_MEM_ENTRY_SIZE 4 /* Each entries are 8 bytes.*/ #define cOCT6100_ECHO_CONTROL_MEM_ACTIVATE_ENTRY 0x8000 #define cOCT6100_ECHO_CONTROL_MEM_EXTERNAL_AF_CTRL 0x2000 #define cOCT6100_ECHO_CONTROL_MEM_DEBUG_OFFSET 14 #define cOCT6100_ECHO_CONTROL_MEM_AF_CONTROL 14 #define cOCT6100_ECHO_CONTROL_MEM_INPUT_LAW_OFFSET 12 #define cOCT6100_ECHO_CONTROL_MEM_OUTPUT_LAW_OFFSET 11 #define cOCT6100_ECHO_CONTROL_MEM_TSI_MEM_MASK 0x7FF /*=======================================================================*/ #define cOCT6100_ST_CONTROL_MEM_BASE 0x2000000 #define cOCT6100_ST_CONTROL_MEM_ENTRY_SIZE 16 /* Each entries are 8 bytes.*/ /*=======================================================================*/ #define cOCT6100_PART1_BASE 0x00080000 #define cOCT6100_PART1_CPU_LSU_CB_BASE cOCT6100_PART1_BASE+0x0000E3C0 /* 8 * 8 = 64 bytes */ #define cOCT6100_PART1_HW_LSU_CB_BASE cOCT6100_PART1_BASE+0x0000E400 /* 8 * 128 = 1K byte */ #define cOCT6100_PART1_END_STATICS_BASE cOCT6100_PART1_BASE+0x0000E9F0 /* 912 bytes available for your viewing pleasure. */ #define cOCT6100_PART1_API_SCRATCH_PAD cOCT6100_PART1_END_STATICS_BASE+4+(12*8) #define cOCT6100_PART1_EGO_REG cOCT6100_PART1_BASE+0x0007FF00 /* External Memory mapping. */ #define cOCT6100_EXTERNAL_MEM_BLOCK_SIZE 1024 #define cOCT6100_EXTERNAL_MEM_BASE_ADDRESS 0x08000000 #define cOCT6100_TLV_BASE ( 0x00016000 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) #define cOCT6100_CHANNEL_ROOT_BASE ( 0x00020000 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) #define cOCT6100_PGSP_EVENT_OUT_BASE ( 0x002C0000 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) #define cOCT6100_POUCH_BASE ( 0x002E0000 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) #define cOCT6100_IMAGE_FILE_BASE ( 0x00300000 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) #define cOCT6100_CHANNEL_ROOT_SIZE 4096 #define cOCT6100_CHANNEL_ROOT_TOTAL_SIZE ( 672 * cOCT6100_CHANNEL_ROOT_SIZE ) #define cOCT6100_PGSP_EVENT_OUT_SIZE 131072 #define cOCT6100_PGSP_TONE_EVENT_SIZE 0x40 #define cOCT6100_IMAGE_FILE_SIZE 0x100000 #define cOCT6100_MATRIX_TIMESTAMP_DWORD_ADD cOCT6100_POUCH_BASE + 0x8 #define cOCT6100_MATRIX_CHAN_SELECT_DWORD_ADD cOCT6100_POUCH_BASE + 0x14 #define cOCT6100_MATRIX_WRITE_PTR_DWORD_ADD cOCT6100_POUCH_BASE + 0x4 #define cOCT6100_MATRIX_PLL_JITTER_COUNT_ADD cOCT6100_POUCH_BASE + 0x1C #define cOCT6100_MATRIX_DWORD_BASE cOCT6100_POUCH_BASE + 0xE0000 #define cOCT6100_CHANNEL_ROOT_GLOBAL_CONF_OFFSET 0x0000 #define cOCT6100_NUM_WORDS_PER_TONE_EVENT 32 #define cOCT6100_NUM_PGSP_EVENT_OUT 2048 /* CPTAG: Must not be modified, represents number of events stored in hardware. */ #define cOCT6100_VALID_TONE_EVENT 0x8000 #define cOCT6100_LOCAL_TIMESTAMP_INCREMENT 32 /* 4 ms increment. */ #define cOCT6100_ABSOLUTE_MAX_NUM_PGSP_EVENT_OUT 65535 #define cOCT6100_MIN_TIMESLOT_FOR_TIMESTAMP 5 /*=======================================================================*/ #define cOCT6100_GSC_PGSP_CONTEXT_BASE_ADD_OFFSET 0x0C #define cOCT6100_GSC_PGSP_INIT_CONTEXT_BASE_ADD_OFFSET 0x10 #define cOCT6100_GSC_RIN_CIRC_BUFFER_BASE_ADD_OFFSET 0x14 #define cOCT6100_GSC_SIN_CIRC_BUFFER_BASE_ADD_OFFSET 0x18 #define cOCT6100_GSC_SOUT_CIRC_BUFFER_BASE_ADD_OFFSET 0x1C #define cOCT6100_GSC_BUFFER_LAW_OFFSET 27 /*=======================================================================*/ #define cOCT6100_CH_MAIN_PGSP_CONTEXT_OFFSET 0x00000 #define cOCT6100_CH_MAIN_TONE_EVENT_OFFSET 0x00488 /*=======================================================================*/ #define cOCT6100_PLAYOUT_EVENT_REPEAT_OFFSET 31 #define cOCT6100_PLAYOUT_EVENT_LAW_OFFSET 30 #define cOCT6100_PLAYOUT_EVENT_MIX_OFFSET 28 #define cOCT6100_PLAYOUT_EVENT_LOOP_TIMES_OFFSET 27 #define cOCT6100_PLAYOUT_EVENT_GAIN_OFFSET 24 #define cOCT6100_PLAYOUT_EVENT_MEM_SIZE 16 /* Image related defines.*/ #define cOCT6100_MIN_IMAGE_SIZE 0x001000 #define cOCT6100_MAX_IMAGE_SIZE 0x100000 #define cOCT6100_MAX_IMAGE_REGION 60 #define cOCT6100_IMAGE_AF_CST_OFFSET 0x1000; /* Max defines.*/ #ifndef cOCT6100_MAX_ECHO_CHANNELS #define cOCT6100_MAX_ECHO_CHANNELS 128 #endif #define cOCT6100_MAX_TSI_CNCTS 1530 #define cOCT6100_MAX_CALLER_ID_PLAYOUT_BUFFERS ( 3328 + 6 ) #define cOCT6100_MAX_PLAYOUT_BUFFERS ( 1344 + cOCT6100_MAX_CALLER_ID_PLAYOUT_BUFFERS ) #define cOCT6100_MAX_CONF_BRIDGE 672 #define cOCT6100_MAX_FLEX_CONF_PARTICIPANTS cOCT6100_MAX_ECHO_CHANNELS #define cOCT6100_MAX_PHASING_TSST 16 #define cOCT6100_MAX_ADPCM_CHANNELS 672 #define cOCT6100_NUM_TSI_B4_PHASING 1344 #define cOCT6100_TOTAL_TSI_CONTROL_MEM_ENTRY 1534 #define cOCT6100_MAX_TSI_CONTROL_MEM_ENTRY 1344 #define cOCT6100_MAX_ECHO_CONTROL_MEM_ENTRY 672 #define cOCT6100_MAX_TSI_B4_TIMESTAMP 172 #define cOCT6100_TSI_MEM_FOR_TIMESTAMP 4 #define cOCT6100_API_EXT_TONE_EXTRA_TSI 1533 /* Echo channel ports */ #define cOCT6100_CHANNEL_PORT_RIN 0 #define cOCT6100_CHANNEL_PORT_ROUT 1 #define cOCT6100_CHANNEL_PORT_SIN 2 #define cOCT6100_CHANNEL_PORT_SOUT 3 #define cOCT6100_CHANNEL_PORT_ROUT_SOUT 4 #define cOCT6100_NO_ENCODING 10 #define cOCT6100_NO_DECODING 11 /* Buffer playout defines */ #define cOCT6100_NO_SKIP 0 #define cOCT6100_BUFFER_PLAYOUT_MIN_SIZE 1024 #define cOCT6100_DEFAULT_TIMESTAMP 0 #define cOCT6100_MIXING_0_DB 0 #define cOCT6100_MIXING_MINUS_6_DB 1 #define cOCT6100_MIXING_MINUS_12_DB 2 #define cOCT6100_MIXING_MUTE 3 #define cOCT6100_PLAYOUT_GAIN 0x41000000 #define cOCT6100_PLAYOUT_EVENT 1 #define cOCT6100_MINIMUM_BUFFER_SIZE 64 #define cOCT6100_BUFFER_SIZE_GRANULARITY 16 #define cOCT6100_REPEAT_INFINITELY cOCT6100_INVALID_VALUE #define cOCT6100_REPEAT_MAX 32767 #define cOCT6100_SAMPLES_PER_MS 8 /* For the playout events. */ #define cOCT6100_MAX_BUFFER_PLAYOUT_EVENT_PER_CALL 32 #define cOCT6100_MIN_BUFFER_PLAYOUT_EVENT 128 #define cOCT6100_MAX_BUFFER_PLAYOUT_EVENT 65535 /* Event types */ #define cOCT6100_BUFFER_PLAYOUT_EVENT_INVALID cOCT6100_INVALID_VALUE #define cOCT6100_BUFFER_PLAYOUT_EVENT_STOP 1 /* Phasing defines.*/ #define cOCT6100_SINGLE_PHASING 0 #define cOCT6100_DUAL_PHASING 1 #define cOCT6100_NO_PHASING 2 /* Echo canceller mode.*/ #define cOCT6100_ELECTRIC_EC 0 #define cOCT6100_ELECTRIC_EC_DISPLACEMENT 1 #define cOCT6100_ACCOUSTIC_ES 2 /* Echo control modes.*/ #define cOCT6100_ECHO_OP_MODE_NORMAL 0 #define cOCT6100_ECHO_OP_MODE_HT_FREEZE 1 #define cOCT6100_ECHO_OP_MODE_HT_RESET 2 #define cOCT6100_ECHO_OP_MODE_POWER_DOWN 3 #define cOCT6100_ECHO_OP_MODE_EXTERNAL 4 #define cOCT6100_ECHO_OP_MODE_NO_ECHO 5 #define cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION 6 #define cOCT6100_ECHO_OP_MODE_G169_ALC cOCT6100_ECHO_OP_MODE_NO_ECHO /* 2100 Hz disabling configuration. */ #define cOCT6100_NEVER_DISABLED 0 #define cOCT6100_G164_2100_HZ 1 #define cOCT6100_G165_2100_HZ_WITH_PHASE_REV 2 /* TSST defines.*/ #define cOCT6100_UNASSIGNED cOCT6100_FFFD #define cOCT6100_MAX_TSSTS (cOCT6100_MAX_ECHO_CHANNELS*4) /* cOCT6100_MAX_ECHO_CHANNELS channels, 4 TSSTs per channel. */ #define cOCT6100_TWO_TSSTS_INDEX_MASK 0x8000 #define cOCT6100_TSST_INDEX_MASK 0x7FFF #define cOCT6100_INPUT_TSST 0 #define cOCT6100_OUTPUT_TSST 1 /* Conference bridges defines.*/ /* CPTAG: No application needs for mixer events. */ /* 2 needed for head and tail nodes. 2 more needed to get through channel modify function. */ /* Careful. This value cannot be zero. */ #ifndef cOCT6100_MAX_MIXER_EVENTS #define cOCT6100_MAX_MIXER_EVENTS 4 #endif #define cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE 32 #define cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED 672 #define cOCT6100_CONF_NO_DOMINANT_SPEAKER_HNDL cOCT6100_FFFFFFFE /* Conversion memory defines.*/ #define cOCT6100_MAX_CONVERSION_MEMORY_BLOCKS (cOCT6100_MAX_ECHO_CHANNELS*2) /* CPTAG: Max this out to the expected max number of channels * 2, was 1344 */ /* Tone detection defines.*/ #define cOCT6100_MAX_TONE_NUMBER 55 /* Register definition and address. */ #define cOCT6100_TONE_EVENT_WRITE_PTR_REG 0x722 #define cOCT6100_TONE_EVENT_READ_PTR_REG 0x720 /* Special Signaling tone IDs. */ #define cOCT6100_TONE_SIN_SYSTEM7_2000 0x20000023 #define cOCT6100_TONE_SIN_SYSTEM7_1780 0x20000024 #define cOCT6100_TONE_ROUT_G168_2100GB_ON 0x10000000 #define cOCT6100_TONE_ROUT_G168_2100GB_WSPR 0x10000002 #define cOCT6100_TONE_ROUT_G168_1100GB_ON 0x10000004 #define cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_A 0x10000005 #define cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_B 0x10000006 #define cOCT6100_TONE_ROUT_G168_2100GB_WSPR_WIDE 0x10000008 #define cOCT6100_TONE_SOUT_G168_2100GB_ON 0x40000000 #define cOCT6100_TONE_SOUT_G168_2100GB_WSPR 0x40000002 #define cOCT6100_TONE_SOUT_G168_1100GB_ON 0x40000004 #define cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_A 0x40000005 #define cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_B 0x40000006 #define cOCT6100_TONE_SOUT_G168_2100GB_WSPR_WIDE 0x40000008 #define cOCT6100_TONE_SIN_SYSTEM5_2400 0x20000020 #define cOCT6100_TONE_SIN_SYSTEM5_2600 0x20000021 #define cOCT6100_TONE_SIN_SYSTEM5_2400_2600 0x20000022 #define cOCT6100_CHIP_ID_REVISION_REG 0x17E /* BOOT type. */ #define cOCT6100_AF_BOOT_TYPE 0x5 #define cOCT6100_PRODUCTION_BOOT_TYPE 0x7 #define cOCT6100_PRODUCTION_SHORT_BOOT_TYPE 0x8 /*Production Bist Modes*/ #define cOCT6100_PRODUCTION_BIST_STANDARD 0x0 #define cOCT6100_PRODUCTION_BIST_SHORT 0x1 /* Interrupt register masks.*/ #define cOCT6100_INTRPT_MASK_REG_102H 0x0001 #define cOCT6100_INTRPT_MASK_REG_202H 0x1C01 #define cOCT6100_INTRPT_MASK_REG_302H 0xF100 #define cOCT6100_INTRPT_MASK_REG_502H 0x0002 #define cOCT6100_INTRPT_MASK_REG_702H 0x0002 #define cOCT6100_DECODER_MEMORY_OFFSET 672 /* Debug defines.*/ #define cOCT6100_DEBUG_MAX_READ_LENGTH 10240 #define cOCT6100_DEBUG_SOUT_MAX_READ_LENGTH 2560 #define cOCT6100_DEBUG_CHAN_RECORD_INDEX 64 #define cOCT6100_DEBUG_RECORD_BUFFER_BYTE_SIZE 0x20000 #define cOCT6100_DEBUG_RECORD_MATRIX_SIZE 0x8000 #define cOCT6100_DEBUG_RECORD_READ_DATA_BYTE_SIZE 1024 #define cOCT6100_DEBUG_RECORD_BLOCK_BYTE_SIZE 0x1000 /* Tone event defines.*/ #define cOCT6100_MAX_TONE_EVENT 56 #define cOCT6100_TONE_PRESENT 0 #define cOCT6100_TONE_STOP 1 #define cOCT6100_TONE_REFRESH 2 /* TLV defines.*/ #define cOCT6100_TLV_MAX_ADDRESS 0x10000000 #define cOCT6100_TLV_MAX_TONE_NAME_SIZE 64 #define cOCT6100_VERSION_NUMBER_MAX_SIZE 1016 /* Echo Tail defines.*/ #define cOCT6100_TAIL_LENGTH_32MS 32 #define cOCT6100_TAIL_LENGTH_64MS 64 #define cOCT6100_TAIL_LENGTH_128MS 128 #define cOCT6100_MAX_ECHO_TAIL_DISPLACEMENT 5600 /* In milliseconds */ /* Generic loop counter.*/ #define cOCT6100_MAX_LOOP 0x2000 /* CPU boot timeout counter. */ #define cOCT6100_MAX_LOOP_CPU_TIMEOUT 0x20000 /* Automatic level control */ #define cOCT6100_PASS_THROUGH_LEVEL_CONTROL 0x90 /* Channel stats debug info */ #define cOCT6100_DEBUG_CHAN_STATS_EVENT_BYTE_SIZE 1024 #define cOCT6100_DEBUG_CHAN_STATS_LITE_EVENT_BYTE_SIZE 720 /* Image start string define */ #define cOCT6100_IMAGE_START_STRING "EDS3_IMAGE_NAME" /* Tone image info defines.*/ #define cOCT6100_TONE_INFO_START_STRING "[ToneDetectorInfo]" #define cOCT6100_TONE_INFO_STOP_STRING "[~ToneDetectorInfo]" #define cOCT6100_TONE_INFO_EVENT_STRING "TONEEVENT=0x" #define cOCT6100_MAX_NLP_CONF_DWORD 20 /* Tail displacement info.*/ #define cOCT6100_MAX_TAIL_DISPLACEMENT 896 /* Comfort noise define */ #define cOCT6100_COMFORT_NOISE_NORMAL 0x0 #define cOCT6100_COMFORT_NOISE_EXTENDED 0x3 #define cOCT6100_COMFORT_NOISE_OFF 0x2 #define cOCT6100_COMFORT_NOISE_FAST_LATCH 0x1 /* Mixer event type.*/ #define cOCT6100_EVENT_TYPE_SOUT_COPY 0x0 #define cOCT6100_EVENT_TYPE_SIN_COPY 0x1 /* Tone disabler status.*/ #define cOCT6100_TONE_DISABLER_EC_ENABLED 0 #define cOCT6100_TONE_DISABLER_EC_DISABLED 1 /* ADPCM Channel defines */ #define cOCT6100_ADPCM_ENCODING 0 #define cOCT6100_ADPCM_DECODING 1 /* Double talk behavior modes. */ #define cOCT6100_DOUBLE_TALK_BEH_NORMAL 0x0 #define cOCT6100_DOUBLE_TALK_BEH_LESS_AGGRESSIVE 0x1 /* Api Version string length.*/ #define cOCT6100_API_VERSION_STRING_LENGTH 32 /* Extended tone detection information. */ #define cOCT6100_API_EXT_TONE_DISABLED 0 #define cOCT6100_API_EXT_TONE_SIN_PORT_MODE 1 #define cOCT6100_API_EXT_TONE_RIN_PORT_MODE 2 /* Mute/UnMute defines. */ #define cOCT6100_CHANNEL_MUTE_PORT_NONE 0x00 #define cOCT6100_CHANNEL_MUTE_PORT_RIN 0x01 #define cOCT6100_CHANNEL_MUTE_PORT_ROUT 0x02 #define cOCT6100_CHANNEL_MUTE_PORT_SIN 0x04 #define cOCT6100_CHANNEL_MUTE_PORT_SOUT 0x08 #define cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES 0x10 /* Debug get data dump modes. */ #define cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE 0x0 #define cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE 0x1 #define cOCT6100_DEBUG_GET_DATA_MODE_16S 0x2 #define cOCT6100_DEBUG_GET_DATA_MODE_120S 0x3 /* Debug get data dump content. */ #define cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE 0x0 /* Full binary dump to be sent for support. */ #define cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM 0x1 /* Only Rin PCM stream data. */ #define cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM 0x2 /* Only Sin PCM stream data. */ #define cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM 0x3 /* Only Sout PCM stream data. */ #define cOCT6100_BIST_IN_PROGRESS 0x0 #define cOCT6100_BIST_CONFIGURATION_FAILED 0x1 #define cOCT6100_BIST_STATUS_CRC_FAILED 0x2 #define cOCT6100_BIST_MEMORY_FAILED 0x3 #define cOCT6100_BIST_SUCCESS 0x4 /* Image types. */ #define cOCT6100_IMAGE_TYPE_WIRELINE 0x0 #define cOCT6100_IMAGE_TYPE_COMBINED 0x1 /* Fatal general error types. */ #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_1 0x0001 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_2 0x0002 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_3 0x0004 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_4 0x0008 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_5 0x0010 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_6 0x0020 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_7 0x0040 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_8 0x0080 #define cOCT6100_FATAL_GENERAL_ERROR_TYPE_9 0x0100 #endif /* __OCT6100_DEFINES_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_pub.h0000644000175000017500000003313711431317470026770 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_channel_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_channel.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_channel_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 84 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHANNEL_PUB_H__ #define __OCT6100_CHANNEL_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ /* Channel open structures. */ typedef struct _OCT6100_CHANNEL_OPEN_TDM_ { UINT32 ulRinNumTssts; UINT32 ulSinNumTssts; UINT32 ulRoutNumTssts; UINT32 ulSoutNumTssts; UINT32 ulSinTimeslot; UINT32 ulSinStream; UINT32 ulSinPcmLaw; UINT32 ulSoutTimeslot; UINT32 ulSoutStream; UINT32 ulSoutPcmLaw; UINT32 ulRinTimeslot; UINT32 ulRinStream; UINT32 ulRinPcmLaw; UINT32 ulRoutTimeslot; UINT32 ulRoutStream; UINT32 ulRoutPcmLaw; } tOCT6100_CHANNEL_OPEN_TDM, *tPOCT6100_CHANNEL_OPEN_TDM; typedef struct _OCT6100_CHANNEL_OPEN_VQE_ { BOOL fEnableNlp; BOOL fEnableTailDisplacement; UINT32 ulTailDisplacement; UINT32 ulTailLength; BOOL fSinDcOffsetRemoval; BOOL fRinDcOffsetRemoval; BOOL fRinLevelControl; BOOL fSoutLevelControl; BOOL fRinAutomaticLevelControl; BOOL fSoutAutomaticLevelControl; BOOL fRinHighLevelCompensation; BOOL fAcousticEcho; BOOL fSoutAdaptiveNoiseReduction; BOOL fDtmfToneRemoval; BOOL fSoutNoiseBleaching; BOOL fSoutConferencingNoiseReduction; UINT32 ulComfortNoiseMode; UINT32 ulNonLinearityBehaviorA; UINT32 ulNonLinearityBehaviorB; INT32 lRinLevelControlGainDb; INT32 lSoutLevelControlGainDb; INT32 lRinAutomaticLevelControlTargetDb; INT32 lSoutAutomaticLevelControlTargetDb; INT32 lRinHighLevelCompensationThresholdDb; INT32 lDefaultErlDb; INT32 lAecDefaultErlDb; UINT32 ulAecTailLength; UINT32 ulSoutAutomaticListenerEnhancementGainDb; UINT32 ulSoutNaturalListenerEnhancementGainDb; BOOL fSoutNaturalListenerEnhancement; BOOL fRoutNoiseReduction; INT32 lRoutNoiseReductionLevelGainDb; INT32 lAnrSnrEnhancementDb; UINT32 ulAnrVoiceNoiseSegregation; UINT32 ulDoubleTalkBehavior; UINT32 ulToneDisablerVqeActivationDelay; BOOL fEnableMusicProtection; BOOL fIdleCodeDetection; } tOCT6100_CHANNEL_OPEN_VQE, *tPOCT6100_CHANNEL_OPEN_VQE; typedef struct _OCT6100_CHANNEL_OPEN_CODEC_ { UINT32 ulAdpcmNibblePosition; UINT32 ulEncoderPort; UINT32 ulEncodingRate; UINT32 ulDecoderPort; UINT32 ulDecodingRate; BOOL fEnableSilenceSuppression; UINT32 ulPhase; UINT32 ulPhasingType; UINT32 ulPhasingTsstHndl; } tOCT6100_CHANNEL_OPEN_CODEC, *tPOCT6100_CHANNEL_OPEN_CODEC; typedef struct _OCT6100_CHANNEL_OPEN_ { PUINT32 pulChannelHndl; UINT32 ulUserChanId; UINT32 ulEchoOperationMode; BOOL fEnableToneDisabler; BOOL fEnableExtToneDetection; tOCT6100_CHANNEL_OPEN_TDM TdmConfig; tOCT6100_CHANNEL_OPEN_VQE VqeConfig; tOCT6100_CHANNEL_OPEN_CODEC CodecConfig; } tOCT6100_CHANNEL_OPEN, *tPOCT6100_CHANNEL_OPEN; /* Channel close structure. */ typedef struct _OCT6100_CHANNEL_CLOSE_ { UINT32 ulChannelHndl; } tOCT6100_CHANNEL_CLOSE, *tPOCT6100_CHANNEL_CLOSE; /* Channel modify structures. */ typedef struct _OCT6100_CHANNEL_MODIFY_TDM_ { UINT32 ulRinNumTssts; UINT32 ulSinNumTssts; UINT32 ulRoutNumTssts; UINT32 ulSoutNumTssts; UINT32 ulSinTimeslot; UINT32 ulSinStream; UINT32 ulSinPcmLaw; UINT32 ulSoutTimeslot; UINT32 ulSoutStream; UINT32 ulSoutPcmLaw; UINT32 ulRinTimeslot; UINT32 ulRinStream; UINT32 ulRinPcmLaw; UINT32 ulRoutTimeslot; UINT32 ulRoutStream; UINT32 ulRoutPcmLaw; } tOCT6100_CHANNEL_MODIFY_TDM, *tPOCT6100_CHANNEL_MODIFY_TDM; typedef struct _OCT6100_CHANNEL_MODIFY_VQE_ { BOOL fEnableNlp; BOOL fEnableTailDisplacement; UINT32 ulTailDisplacement; BOOL fSinDcOffsetRemoval; BOOL fRinDcOffsetRemoval; BOOL fRinLevelControl; BOOL fSoutLevelControl; BOOL fRinAutomaticLevelControl; BOOL fSoutAutomaticLevelControl; BOOL fRinHighLevelCompensation; BOOL fAcousticEcho; BOOL fSoutAdaptiveNoiseReduction; BOOL fDtmfToneRemoval; BOOL fSoutConferencingNoiseReduction; BOOL fSoutNoiseBleaching; UINT32 ulNonLinearityBehaviorA; UINT32 ulNonLinearityBehaviorB; UINT32 ulComfortNoiseMode; INT32 lRinLevelControlGainDb; INT32 lSoutLevelControlGainDb; INT32 lRinAutomaticLevelControlTargetDb; INT32 lSoutAutomaticLevelControlTargetDb; INT32 lRinHighLevelCompensationThresholdDb; INT32 lDefaultErlDb; INT32 lAecDefaultErlDb; UINT32 ulAecTailLength; UINT32 ulSoutAutomaticListenerEnhancementGainDb; UINT32 ulSoutNaturalListenerEnhancementGainDb; BOOL fSoutNaturalListenerEnhancement; BOOL fRoutNoiseReduction; INT32 lRoutNoiseReductionLevelGainDb; INT32 lAnrSnrEnhancementDb; UINT32 ulAnrVoiceNoiseSegregation; UINT32 ulDoubleTalkBehavior; UINT32 ulToneDisablerVqeActivationDelay; BOOL fEnableMusicProtection; BOOL fIdleCodeDetection; } tOCT6100_CHANNEL_MODIFY_VQE, *tPOCT6100_CHANNEL_MODIFY_VQE; typedef struct _OCT6100_CHANNEL_MODIFY_CODEC_ { UINT32 ulEncoderPort; UINT32 ulEncodingRate; UINT32 ulDecoderPort; UINT32 ulDecodingRate; BOOL fEnableSilenceSuppression; UINT32 ulPhase; UINT32 ulPhasingType; UINT32 ulPhasingTsstHndl; } tOCT6100_CHANNEL_MODIFY_CODEC, *tPOCT6100_CHANNEL_MODIFY_CODEC; typedef struct _OCT6100_CHANNEL_MODIFY_ { UINT32 ulChannelHndl; UINT32 ulUserChanId; UINT32 ulEchoOperationMode; BOOL fEnableToneDisabler; BOOL fApplyToAllChannels; BOOL fDisableToneDetection; BOOL fStopBufferPlayout; BOOL fRemoveConfBridgeParticipant; BOOL fRemoveBroadcastTssts; BOOL fTdmConfigModified; /* TRUE/FALSE */ BOOL fVqeConfigModified; /* TRUE/FALSE */ BOOL fCodecConfigModified; /* TRUE/FALSE */ tOCT6100_CHANNEL_MODIFY_TDM TdmConfig; tOCT6100_CHANNEL_MODIFY_VQE VqeConfig; tOCT6100_CHANNEL_MODIFY_CODEC CodecConfig; } tOCT6100_CHANNEL_MODIFY, *tPOCT6100_CHANNEL_MODIFY; typedef struct _OCT6100_CHANNEL_BROADCAST_TSST_ADD_ { UINT32 ulChannelHndl; UINT32 ulPort; UINT32 ulTimeslot; UINT32 ulStream; } tOCT6100_CHANNEL_BROADCAST_TSST_ADD, *tPOCT6100_CHANNEL_BROADCAST_TSST_ADD; typedef struct _OCT6100_CHANNEL_BROADCAST_TSST_REMOVE_ { UINT32 ulChannelHndl; UINT32 ulPort; UINT32 ulTimeslot; UINT32 ulStream; BOOL fRemoveAll; } tOCT6100_CHANNEL_BROADCAST_TSST_REMOVE, *tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE; /* Channel open structures.*/ typedef struct _OCT6100_CHANNEL_STATS_TDM_ { UINT32 ulMaxBroadcastTssts; UINT32 ulNumRoutBroadcastTssts; BOOL fMoreRoutBroadcastTssts; UINT32 ulNumSoutBroadcastTssts; BOOL fMoreSoutBroadcastTssts; UINT32 ulSinNumTssts; UINT32 ulSoutNumTssts; UINT32 ulRinNumTssts; UINT32 ulRoutNumTssts; UINT32 ulSinTimeslot; UINT32 ulSinStream; UINT32 ulSinPcmLaw; UINT32 ulSoutTimeslot; UINT32 ulSoutStream; UINT32 ulSoutPcmLaw; PUINT32 pulSoutBroadcastTimeslot; PUINT32 pulSoutBroadcastStream; UINT32 ulRinTimeslot; UINT32 ulRinStream; UINT32 ulRinPcmLaw; UINT32 ulRoutTimeslot; UINT32 ulRoutStream; UINT32 ulRoutPcmLaw; PUINT32 pulRoutBroadcastTimeslot; PUINT32 pulRoutBroadcastStream; } tOCT6100_CHANNEL_STATS_TDM, *tPOCT6100_CHANNEL_STATS_TDM; typedef struct _OCT6100_CHANNEL_STATS_VQE_ { BOOL fEnableNlp; BOOL fEnableTailDisplacement; UINT32 ulTailDisplacement; UINT32 ulTailLength; BOOL fSinDcOffsetRemoval; BOOL fRinDcOffsetRemoval; BOOL fRinLevelControl; BOOL fSoutLevelControl; BOOL fRinAutomaticLevelControl; BOOL fSoutAutomaticLevelControl; BOOL fRinHighLevelCompensation; BOOL fAcousticEcho; BOOL fSoutAdaptiveNoiseReduction; BOOL fDtmfToneRemoval; BOOL fSoutConferencingNoiseReduction; BOOL fSoutNoiseBleaching; UINT32 ulComfortNoiseMode; UINT32 ulNonLinearityBehaviorA; UINT32 ulNonLinearityBehaviorB; INT32 lRinLevelControlGainDb; INT32 lSoutLevelControlGainDb; INT32 lRinAutomaticLevelControlTargetDb; INT32 lSoutAutomaticLevelControlTargetDb; INT32 lRinHighLevelCompensationThresholdDb; INT32 lDefaultErlDb; INT32 lAecDefaultErlDb; UINT32 ulAecTailLength; UINT32 ulSoutAutomaticListenerEnhancementGainDb; UINT32 ulSoutNaturalListenerEnhancementGainDb; BOOL fSoutNaturalListenerEnhancement; BOOL fRoutNoiseReduction; INT32 lRoutNoiseReductionLevelGainDb; INT32 lAnrSnrEnhancementDb; UINT32 ulAnrVoiceNoiseSegregation; UINT32 ulDoubleTalkBehavior; UINT32 ulToneDisablerVqeActivationDelay; BOOL fEnableMusicProtection; BOOL fIdleCodeDetection; } tOCT6100_CHANNEL_STATS_VQE, *tPOCT6100_CHANNEL_STATS_VQE; typedef struct _OCT6100_CHANNEL_STATS_CODEC_ { UINT32 ulAdpcmNibblePosition; UINT32 ulEncoderPort; UINT32 ulEncodingRate; UINT32 ulDecoderPort; UINT32 ulDecodingRate; BOOL fEnableSilenceSuppression; UINT32 ulPhase; UINT32 ulPhasingType; UINT32 ulPhasingTsstHndl; } tOCT6100_CHANNEL_STATS_CODEC, *tPOCT6100_CHANNEL_STATS_CODEC; typedef struct _OCT6100_CHANNEL_STATS_ { BOOL fResetStats; UINT32 ulChannelHndl; UINT32 ulUserChanId; UINT32 ulEchoOperationMode; BOOL fEnableToneDisabler; UINT32 ulMutePortsMask; BOOL fEnableExtToneDetection; tOCT6100_CHANNEL_STATS_TDM TdmConfig; tOCT6100_CHANNEL_STATS_VQE VqeConfig; tOCT6100_CHANNEL_STATS_CODEC CodecConfig; /* Real stats. */ UINT32 ulNumEchoPathChanges; UINT32 ulToneDisablerStatus; INT32 lCurrentERL; INT32 lCurrentERLE; UINT32 ulCurrentEchoDelay; INT32 lMaxERL; INT32 lMaxERLE; UINT32 ulMaxEchoDelay; INT32 lRinLevel; INT32 lSinLevel; INT32 lRinAppliedGain; INT32 lSoutAppliedGain; INT32 lComfortNoiseLevel; BOOL fEchoCancellerConverged; BOOL fSinVoiceDetected; } tOCT6100_CHANNEL_STATS, *tPOCT6100_CHANNEL_STATS; typedef struct _OCT6100_CHANNEL_CREATE_BIDIR_ { PUINT32 pulBiDirChannelHndl; UINT32 ulFirstChannelHndl; UINT32 ulSecondChannelHndl; } tOCT6100_CHANNEL_CREATE_BIDIR, *tPOCT6100_CHANNEL_CREATE_BIDIR; typedef struct _OCT6100_CHANNEL_DESTROY_BIDIR_ { UINT32 ulBiDirChannelHndl; } tOCT6100_CHANNEL_DESTROY_BIDIR, *tPOCT6100_CHANNEL_DESTROY_BIDIR; typedef struct _OCT6100_CHANNEL_MUTE_ { UINT32 ulChannelHndl; UINT32 ulPortMask; } tOCT6100_CHANNEL_MUTE, *tPOCT6100_CHANNEL_MUTE; typedef struct _OCT6100_CHANNEL_UNMUTE_ { UINT32 ulChannelHndl; UINT32 ulPortMask; } tOCT6100_CHANNEL_UNMUTE, *tPOCT6100_CHANNEL_UNMUTE; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ChannelOpenDef( OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ); UINT32 Oct6100ChannelOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ); UINT32 Oct6100ChannelCloseDef( OUT tPOCT6100_CHANNEL_CLOSE f_pChannelClose ); UINT32 Oct6100ChannelClose( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_CLOSE f_pChannelClose ); UINT32 Oct6100ChannelModifyDef( OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify ); UINT32 Oct6100ChannelModify( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify ); UINT32 Oct6100ChannelBroadcastTsstAddDef( OUT tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd ); UINT32 Oct6100ChannelBroadcastTsstAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd ); UINT32 Oct6100ChannelBroadcastTsstRemoveDef( OUT tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove ); UINT32 Oct6100ChannelBroadcastTsstRemove( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove ); UINT32 Oct6100ChannelGetStatsDef( OUT tPOCT6100_CHANNEL_STATS f_pChannelStats ); UINT32 Oct6100ChannelGetStats( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_STATS f_pChannelStats ); UINT32 Oct6100ChannelCreateBiDirDef( OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ); UINT32 Oct6100ChannelCreateBiDir( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ); UINT32 Oct6100ChannelDestroyBiDirDef( OUT tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ); UINT32 Oct6100ChannelDestroyBiDir( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ); UINT32 Oct6100ChannelMuteDef( OUT tPOCT6100_CHANNEL_MUTE f_pChannelMute ); UINT32 Oct6100ChannelMute( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MUTE f_pChannelMute ); UINT32 Oct6100ChannelUnMuteDef( OUT tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ); UINT32 Oct6100ChannelUnMute( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ); #endif /* __OCT6100_CHANNEL_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_mixer_pub.h0000644000175000017500000000507011431317470026477 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_mixer_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_mixer.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_mixer_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 7 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_MIXER_PUB_H__ #define __OCT6100_MIXER_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_COPY_EVENT_CREATE_ { PUINT32 pulCopyEventHndl; UINT32 ulSourceChanHndl; UINT32 ulSourcePort; UINT32 ulDestinationChanHndl; UINT32 ulDestinationPort; } tOCT6100_COPY_EVENT_CREATE, *tPOCT6100_COPY_EVENT_CREATE; typedef struct _OCT6100_COPY_EVENT_DESTROY_ { UINT32 ulCopyEventHndl; } tOCT6100_COPY_EVENT_DESTROY, *tPOCT6100_COPY_EVENT_DESTROY; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100MixerCopyEventCreateDef( OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ); UINT32 Oct6100MixerCopyEventCreate( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ); UINT32 Oct6100MixerCopyEventDestroyDef( OUT tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ); UINT32 Oct6100MixerCopyEventDestroy( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ); #endif /* __OCT6100_MIXER_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_interrupts_pub.h0000644000175000017500000000600311431317470027567 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_interrupts_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_interrupts.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_interrupts_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 23 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_INTERRUPTS_PUB_H__ #define __OCT6100_INTERRUPTS_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_INTERRUPT_CONFIGURE_ { UINT32 ulFatalGeneralConfig; UINT32 ulFatalMemoryConfig; UINT32 ulErrorMemoryConfig; UINT32 ulErrorOverflowToneEventsConfig; UINT32 ulErrorH100Config; UINT32 ulFatalMemoryTimeout; UINT32 ulErrorMemoryTimeout; UINT32 ulErrorOverflowToneEventsTimeout; UINT32 ulErrorH100Timeout; } tOCT6100_INTERRUPT_CONFIGURE, *tPOCT6100_INTERRUPT_CONFIGURE; typedef struct _OCT6100_INTERRUPT_FLAGS_ { BOOL fFatalGeneral; UINT32 ulFatalGeneralFlags; BOOL fFatalReadTimeout; BOOL fErrorRefreshTooLate; BOOL fErrorPllJitter; BOOL fErrorOverflowToneEvents; BOOL fErrorH100OutOfSync; BOOL fErrorH100ClkA; BOOL fErrorH100ClkB; BOOL fErrorH100FrameA; BOOL fToneEventsPending; BOOL fBufferPlayoutEventsPending; BOOL fApiSynch; } tOCT6100_INTERRUPT_FLAGS, *tPOCT6100_INTERRUPT_FLAGS; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100InterruptConfigureDef( OUT tPOCT6100_INTERRUPT_CONFIGURE f_pConfigInts ); UINT32 Oct6100InterruptConfigure( IN tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_INTERRUPT_CONFIGURE f_pConfigInts ); UINT32 Oct6100InterruptServiceRoutineDef( OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ); UINT32 Oct6100InterruptServiceRoutine( IN tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ); #endif /* __OCT6100_INTERRUPTS_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_adpcm_chan_inst.h0000644000175000017500000000460111431317470027616 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_adpcm_chan_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_adpcm_chan.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_adpcm_chan_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_ADPCM_CHAN_INST_H__ #define __OCT6100_ADPCM_CHAN_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_ADPCM_CHAN_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt; /* TSI chariot memory entry. */ UINT16 usTsiMemIndex; /* ADPCM memory entry. */ UINT16 usAdpcmMemIndex; /* Input and output timeslot information. */ UINT16 usInputTimeslot; UINT16 usInputStream; UINT8 byInputNumTssts; UINT8 byInputPcmLaw; UINT16 usOutputTimeslot; UINT16 usOutputStream; UINT8 byOutputNumTssts; UINT8 byOutputPcmLaw; /* Internal info for quick access to structures associated to this TSI cnct. */ UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; } tOCT6100_API_ADPCM_CHAN, *tPOCT6100_API_ADPCM_CHAN; #endif /* __OCT6100_ADPCM_CHAN_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_interrupts_inst.h0000644000175000017500000001054711431317470027766 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_interrupts_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_interrupts.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_interrupts_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 16 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_INTERRUPTS_INST_H__ #define __OCT6100_INTERRUPTS_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_INTRPT_CONFIG_ { /* The configuration of each group of interrupts. Each can have one of the following values: cOCT6100_INTRPT_DISABLE, cOCT6100_INTRPT_NO_TIMEOUT, cOCT6100_INTRPT_TIMEOUT. */ UINT8 byFatalGeneralConfig; UINT8 byFatalMemoryConfig; UINT8 byErrorMemoryConfig; UINT8 byErrorOverflowToneEventsConfig; UINT8 byErrorH100Config; /* The timeout value for each interrupt group, if the corresponding configuration variable is set to cOCT6100_INTRPT_TIMEOUT. This value is kept in mclk cycles. */ UINT32 ulFatalMemoryTimeoutMclk; UINT32 ulErrorMemoryTimeoutMclk; UINT32 ulErrorOverflowToneEventsTimeoutMclk; UINT32 ulErrorH100TimeoutMclk; } tOCT6100_API_INTRPT_CONFIG, *tPOCT6100_API_INTRPT_CONFIG; typedef struct _OCT6100_API_INTRPT_MANAGE_ { /* Number of mclk cycles in 1ms. */ UINT32 ulNumMclkCyclesIn1Ms; /* Whether the mclk interrupt is active. */ UINT8 fMclkIntrptActive; UINT32 ulNextMclkIntrptTimeHigh; UINT32 ulNextMclkIntrptTimeLow; /* Mclk time read from registers. */ UINT32 ulRegMclkTimeHigh; UINT32 ulRegMclkTimeLow; /* Used by the interrupt service routine. */ UINT16 usRegister102h; UINT16 usRegister202h; UINT16 usRegister302h; UINT16 usRegister502h; UINT16 usRegister702h; /* The state of each interrupt group. Can be one of the following: cOCT6100_INTRPT_ACTIVE, cOCT6100_INTRPT_WILL_TIMEOUT, cOCT6100_INTRPT_IN_TIMEOUT, cOCT6100_INTRPT_WILL_DISABLED. */ UINT16 byFatalGeneralState; UINT16 byFatalMemoryState; UINT16 byErrorMemoryState; UINT16 byErrorOverflowToneEventsState; UINT16 byErrorH100State; /* The time at which each disabled interrupt was disabled, in mclk cycles. */ UINT32 ulFatalMemoryDisableMclkHigh; UINT32 ulFatalMemoryDisableMclkLow; UINT32 ulErrorMemoryDisableMclkHigh; UINT32 ulErrorMemoryDisableMclkLow; UINT32 ulErrorOverflowToneEventsDisableMclkHigh; UINT32 ulErrorOverflowToneEventsDisableMclkLow; UINT32 ulErrorH100DisableMclkHigh; UINT32 ulErrorH100DisableMclkLow; /* The time at which each disabled interrupt group is to be reenabled, in number of mclk cycles. */ UINT32 ulFatalGeneralEnableMclkHigh; UINT32 ulFatalGeneralEnableMclkLow; UINT32 ulFatalMemoryEnableMclkHigh; UINT32 ulFatalMemoryEnableMclkLow; UINT32 ulErrorMemoryEnableMclkHigh; UINT32 ulErrorMemoryEnableMclkLow; UINT32 ulErrorOverflowToneEventsEnableMclkHigh; UINT32 ulErrorOverflowToneEventsEnableMclkLow; UINT32 ulErrorH100EnableMclkHigh; UINT32 ulErrorH100EnableMclkLow; /* If this is set, buffer playout events are pending. */ UINT8 fBufferPlayoutEventsPending; /* If this is set, tone events are pending. */ UINT8 fToneEventsPending; UINT8 fIsrCalled; } tOCT6100_API_INTRPT_MANAGE, *tPOCT6100_API_INTRPT_MANAGE; #endif /* __OCT6100_INTERRUPTS_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_stats_pub.h0000644000175000017500000001026311431317470027514 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_stats_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_chip_stats.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_chip_stats_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 59 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_STATS_PUB_H__ #define __OCT6100_CHIP_STATS_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_CHIP_STATS_ { BOOL fResetChipStats; UINT32 ulNumberChannels; UINT32 ulNumberTsiCncts; UINT32 ulNumberConfBridges; UINT32 ulNumberPlayoutBuffers; UINT32 ulPlayoutFreeMemSize; UINT32 ulNumberPhasingTssts; UINT32 ulNumberAdpcmChannels; UINT32 ulH100OutOfSynchCount; UINT32 ulH100ClockABadCount; UINT32 ulH100FrameABadCount; UINT32 ulH100ClockBBadCount; UINT32 ulInternalReadTimeoutCount; UINT32 ulSdramRefreshTooLateCount; UINT32 ulPllJitterErrorCount; UINT32 ulOverflowToneEventsCount; UINT32 ulSoftOverflowToneEventsCount; UINT32 ulSoftOverflowBufferPlayoutEventsCount; } tOCT6100_CHIP_STATS, *tPOCT6100_CHIP_STATS; typedef struct _OCT6100_CHIP_TONE_INFO_ { UINT32 ulToneID; UINT32 ulDetectionPort; UINT8 aszToneName[ cOCT6100_TLV_MAX_TONE_NAME_SIZE ]; } tOCT6100_CHIP_TONE_INFO, *tPOCT6100_CHIP_TONE_INFO; typedef struct _OCT6100_CHIP_IMAGE_INFO_ { BOOL fBufferPlayout; BOOL fAdaptiveNoiseReduction; BOOL fSoutNoiseBleaching; BOOL fAutoLevelControl; BOOL fHighLevelCompensation; BOOL fSilenceSuppression; BOOL fAdpcm; BOOL fConferencing; BOOL fConferencingNoiseReduction; BOOL fDominantSpeaker; BOOL fAcousticEcho; BOOL fAecTailLength; BOOL fToneRemoval; BOOL fDefaultErl; BOOL fNonLinearityBehaviorA; BOOL fNonLinearityBehaviorB; BOOL fPerChannelTailDisplacement; BOOL fPerChannelTailLength; BOOL fListenerEnhancement; BOOL fRoutNoiseReduction; BOOL fRoutNoiseReductionLevel; BOOL fAnrSnrEnhancement; BOOL fAnrVoiceNoiseSegregation; BOOL fToneDisablerVqeActivationDelay; BOOL fMusicProtection; BOOL fDoubleTalkBehavior; BOOL fIdleCodeDetection; BOOL fSinLevel; UINT32 ulMaxChannels; UINT32 ulNumTonesAvailable; UINT32 ulToneProfileNumber; UINT32 ulMaxTailDisplacement; UINT32 ulMaxTailLength; UINT32 ulDebugEventSize; UINT32 ulMaxPlayoutEvents; UINT32 ulImageType; UINT8 szVersionNumber[ cOCT6100_VERSION_NUMBER_MAX_SIZE ]; UINT32 ulBuildId; tOCT6100_CHIP_TONE_INFO aToneInfo[ cOCT6100_MAX_TONE_EVENT ]; } tOCT6100_CHIP_IMAGE_INFO, *tPOCT6100_CHIP_IMAGE_INFO; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ChipGetStatsDef( OUT tPOCT6100_CHIP_STATS f_pChipStats ); UINT32 Oct6100ChipGetStats( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_CHIP_STATS f_pChipStats ); UINT32 Oct6100ChipGetImageInfoDef( OUT tPOCT6100_CHIP_IMAGE_INFO f_pChipImageInfo ); UINT32 Oct6100ChipGetImageInfo( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, OUT tPOCT6100_CHIP_IMAGE_INFO f_pChipImageInfo ); #endif /* __OCT6100_CHIP_STATS_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tone_detection_inst.h0000644000175000017500000000327011431317470030545 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tone_detection_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tone_detection_buf.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_tone_detection_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 8 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TONE_DETECTION_INST_H__ #define __OCT6100_TONE_DETECTION_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ #endif /* __OCT6100_TONE_DETECTION_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_playout_buf_pub.h0000644000175000017500000001656411431317470027716 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_playout_buf_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_playout_buf.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_playout_buf_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 21 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PLAYOUT_BUF_PUB_H__ #define __OCT6100_PLAYOUT_BUF_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_BUFFER_LOAD_ { PUINT32 pulBufferIndex; /* Index identifying the buffer. */ PUINT32 pulPlayoutFreeMemSize; /* Amount of free memory available for other buffers. */ PUINT8 pbyBufferPattern; /* A byte pointer pointing to a valid buffer to be loaded into the chip's external memory. */ UINT32 ulBufferSize; /* Size of the buffer loaded into external memory. */ UINT32 ulBufferPcmLaw; /* Buffer PCM law. */ } tOCT6100_BUFFER_LOAD, *tPOCT6100_BUFFER_LOAD; typedef struct _OCT6100_BUFFER_LOAD_BLOCK_INIT_ { PUINT32 pulBufferIndex; /* Index identifying the buffer. */ PUINT32 pulPlayoutFreeMemSize; /* Amount of free memory available for other buffers. */ UINT32 ulBufferSize; /* Size of the buffer to be loaded in memory. This space will be reserved. */ UINT32 ulBufferPcmLaw; /* Buffer PCM law. */ } tOCT6100_BUFFER_LOAD_BLOCK_INIT, *tPOCT6100_BUFFER_LOAD_BLOCK_INIT; typedef struct _OCT6100_BUFFER_LOAD_BLOCK_ { UINT32 ulBufferIndex; /* Index identifying the buffer. */ /* Offset, in bytes, of the first byte in the block to be loaded. */ /* This offset is with respect to the beginning of the buffer. */ /* This value must be modulo 2 */ UINT32 ulBlockOffset; /* Size of the block to be loaded into external memory. */ /* This value must be modulo 2. */ UINT32 ulBlockLength; /* A pointer pointing to a valid buffer block to be loaded */ /* into the chip's external memory. This is a pointer to the entire */ /* buffer. The API uses the ulBlockOffset and ulBlockLength to index */ /* within this buffer and obtain the block to be loaded. */ PUINT8 pbyBufferPattern; } tOCT6100_BUFFER_LOAD_BLOCK, *tPOCT6100_BUFFER_LOAD_BLOCK; typedef struct _OCT6100_BUFFER_UNLOAD_ { UINT32 ulBufferIndex; /* Index identifying the buffer. */ } tOCT6100_BUFFER_UNLOAD, *tPOCT6100_BUFFER_UNLOAD; typedef struct _OCT6100_BUFFER_PLAYOUT_ADD_ { UINT32 ulChannelHndl; /* Echo cancelling channel on which to play the buffer. */ UINT32 ulBufferIndex; /* Index identifying the buffer. */ UINT32 ulPlayoutPort; /* Selected channel port where to play to tone. */ UINT32 ulMixingMode; /* Weither or not the voice stream will be muted while playing the buffer. */ INT32 lGainDb; /* Gain applied to the buffer that will be played on the specified port. */ BOOL fRepeat; /* Use ulRepeatCount variable. */ UINT32 ulRepeatCount; /* Number of times to repeat playing the selected buffer. */ UINT32 ulDuration; /* Duration in millisecond that this buffer should play. Setting this overrides fRepeat. */ UINT32 ulBufferLength; /* Length of the buffer to play (starting at the beginning), AUTO_SELECT for all. */ } tOCT6100_BUFFER_PLAYOUT_ADD, *tPOCT6100_BUFFER_PLAYOUT_ADD; typedef struct _OCT6100_BUFFER_PLAYOUT_START_ { UINT32 ulChannelHndl; /* Echo cancelling channel on which to play the buffer. */ UINT32 ulPlayoutPort; /* Selected channel port where to play to tone. */ BOOL fNotifyOnPlayoutStop; /* Check if the buffers have finished playing on this channel/port. */ /* The events are queued in a soft buffer that the user must empty regularly. */ UINT32 ulUserEventId; /* Returned to the user when the playout is finished and the user has set the fNotifyOnPlayoutStop flag. */ BOOL fAllowStartWhileActive; /* Use this to add buffers to something that is already playing on the channel/port. */ } tOCT6100_BUFFER_PLAYOUT_START, *tPOCT6100_BUFFER_PLAYOUT_START; typedef struct _OCT6100_BUFFER_PLAYOUT_STOP_ { UINT32 ulChannelHndl; /* Echo cancelling channel on which to play the buffer. */ UINT32 ulPlayoutPort; /* Selected channel port where to play to tone. */ BOOL fStopCleanly; /* Whether or not the skip will be clean. */ PBOOL pfAlreadyStopped; /* Whether playout was already stopped or not. */ PBOOL pfNotifyOnPlayoutStop; /* Whether the user chosed to receive an event on playout stop. */ } tOCT6100_BUFFER_PLAYOUT_STOP, *tPOCT6100_BUFFER_PLAYOUT_STOP; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100BufferPlayoutLoadDef( OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad ); UINT32 Oct6100BufferPlayoutLoad( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad ); UINT32 Oct6100BufferPlayoutLoadBlockInitDef( OUT tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ); UINT32 Oct6100BufferPlayoutLoadBlockInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ); UINT32 Oct6100BufferPlayoutLoadBlockDef( OUT tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ); UINT32 Oct6100BufferPlayoutLoadBlock( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ); UINT32 Oct6100BufferPlayoutUnloadDef( OUT tPOCT6100_BUFFER_UNLOAD f_pBufferUnload ); UINT32 Oct6100BufferPlayoutUnload( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_UNLOAD f_pBufferUnload ); UINT32 Oct6100BufferPlayoutAddDef( OUT tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ); UINT32 Oct6100BufferPlayoutAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ); UINT32 Oct6100BufferPlayoutStartDef( OUT tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart ); UINT32 Oct6100BufferPlayoutStart( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart ); UINT32 Oct6100BufferPlayoutStopDef( OUT tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ); UINT32 Oct6100BufferPlayoutStop( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ); #endif /* __OCT6100_PLAYOUT_BUF_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tone_detection_pub.h0000644000175000017500000000513711431317470030362 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tone_detection_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tone_detection.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_tone_detection_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 10 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TONE_DETECTION_PUB_H__ #define __OCT6100_TONE_DETECTION_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_TONE_DETECTION_ENABLE_ { UINT32 ulChannelHndl; UINT32 ulToneNumber; } tOCT6100_TONE_DETECTION_ENABLE, *tPOCT6100_TONE_DETECTION_ENABLE; typedef struct _OCT6100_TONE_DETECTION_DISABLE_ { UINT32 ulChannelHndl; UINT32 ulToneNumber; BOOL fDisableAll; } tOCT6100_TONE_DETECTION_DISABLE, *tPOCT6100_TONE_DETECTION_DISABLE; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ToneDetectionEnableDef( OUT tPOCT6100_TONE_DETECTION_ENABLE f_pBufferLoad ); UINT32 Oct6100ToneDetectionEnable( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TONE_DETECTION_ENABLE f_pBufferLoad ); UINT32 Oct6100ToneDetectionDisableDef( OUT tPOCT6100_TONE_DETECTION_DISABLE f_pBufferUnload ); UINT32 Oct6100ToneDetectionDisable( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TONE_DETECTION_DISABLE f_pBufferUnload ); #endif /* __OCT6100_TONE_DETECTION_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h0000644000175000017500000002152111431317470025606 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_apiud.h Copyright (c) 2001-2007 Octasic Inc. Description: Header file containing the definitions and prototypes that are to be completed by the user. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 16 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_APIUD_H__ #define __OCT6100_APIUD_H__ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" /***************************** DEFINES *************************************/ /* Determines the maximum length of a burst of reads/writes. This value must be in the range 8 - 1024. This value obtains best performance if set to a power of 2 (i.e. 2^n). */ #define cOCT6100_MAX_RW_ACCESSES 32 /* The define used to specify that the Oct6100SeizeSerializeObject function is not to return until the specified serialization object has been seized. */ #define cOCT6100_WAIT_INFINITELY 0xFFFFFFFF /* Compile option: enabling this compile option inserts code to check every call to a user provided function to make sure the function parameters are not changed, as required by the API specification. */ #define cOCT6100_USER_FUNCTION_CHECK #define cOCT6100_GET_TIME_FAILED_0 0xFFFF0000 #define cOCT6100_GET_TIME_FAILED_1 0xFFFF0001 #define cOCT6100_GET_TIME_FAILED_2 0xFFFF0002 #define cOCT6100_GET_TIME_FAILED_3 0xFFFF0003 #define cOCT6100_GET_TIME_FAILED_4 0xFFFF0004 #define cOCT6100_CREATE_SERIAL_FAILED_0 0xFFFF0010 #define cOCT6100_CREATE_SERIAL_FAILED_1 0xFFFF0011 #define cOCT6100_CREATE_SERIAL_FAILED_2 0xFFFF0012 #define cOCT6100_CREATE_SERIAL_FAILED_3 0xFFFF0013 #define cOCT6100_CREATE_SERIAL_FAILED_4 0xFFFF0014 #define cOCT6100_DESTROY_SERIAL_FAILED_0 0xFFFF0020 #define cOCT6100_DESTROY_SERIAL_FAILED_1 0xFFFF0021 #define cOCT6100_DESTROY_SERIAL_FAILED_2 0xFFFF0022 #define cOCT6100_DESTROY_SERIAL_FAILED_3 0xFFFF0023 #define cOCT6100_DESTROY_SERIAL_FAILED_4 0xFFFF0024 #define cOCT6100_INVALID_SERIAL_HANDLE_0 0xFFFF0030 #define cOCT6100_INVALID_SERIAL_HANDLE_1 0xFFFF0031 #define cOCT6100_INVALID_SERIAL_HANDLE_2 0xFFFF0032 #define cOCT6100_INVALID_SERIAL_HANDLE_3 0xFFFF0033 #define cOCT6100_INVALID_SERIAL_HANDLE_4 0xFFFF0034 #define cOCT6100_RELEASE_SERIAL_FAILED_0 0xFFFF0040 #define cOCT6100_RELEASE_SERIAL_FAILED_1 0xFFFF0041 #define cOCT6100_RELEASE_SERIAL_FAILED_2 0xFFFF0042 #define cOCT6100_RELEASE_SERIAL_FAILED_3 0xFFFF0043 #define cOCT6100_RELEASE_SERIAL_FAILED_4 0xFFFF0044 #define cOCT6100_SEIZE_SERIAL_FAILED_0 0xFFFF0050 #define cOCT6100_SEIZE_SERIAL_FAILED_1 0xFFFF0051 #define cOCT6100_SEIZE_SERIAL_FAILED_2 0xFFFF0052 #define cOCT6100_SEIZE_SERIAL_FAILED_3 0xFFFF0053 #define cOCT6100_SEIZE_SERIAL_FAILED_4 0xFFFF0054 #define cOCT6100_DRIVER_WRITE_FAILED_0 0xFFFF0060 #define cOCT6100_DRIVER_WRITE_FAILED_1 0xFFFF0061 #define cOCT6100_DRIVER_WRITE_FAILED_2 0xFFFF0062 #define cOCT6100_DRIVER_WRITE_FAILED_3 0xFFFF0063 #define cOCT6100_DRIVER_WRITE_FAILED_4 0xFFFF0064 #define cOCT6100_DRIVER_WSMEAR_FAILED_0 0xFFFF0070 #define cOCT6100_DRIVER_WSMEAR_FAILED_1 0xFFFF0071 #define cOCT6100_DRIVER_WSMEAR_FAILED_2 0xFFFF0072 #define cOCT6100_DRIVER_WSMEAR_FAILED_3 0xFFFF0073 #define cOCT6100_DRIVER_WSMEAR_FAILED_4 0xFFFF0074 #define cOCT6100_DRIVER_WBURST_FAILED_0 0xFFFF0080 #define cOCT6100_DRIVER_WBURST_FAILED_1 0xFFFF0081 #define cOCT6100_DRIVER_WBURST_FAILED_2 0xFFFF0082 #define cOCT6100_DRIVER_WBURST_FAILED_3 0xFFFF0083 #define cOCT6100_DRIVER_WBURST_FAILED_4 0xFFFF0084 #define cOCT6100_DRIVER_READ_FAILED_0 0xFFFF0090 #define cOCT6100_DRIVER_READ_FAILED_1 0xFFFF0091 #define cOCT6100_DRIVER_READ_FAILED_2 0xFFFF0092 #define cOCT6100_DRIVER_READ_FAILED_3 0xFFFF0093 #define cOCT6100_DRIVER_READ_FAILED_4 0xFFFF0094 #define cOCT6100_DRIVER_RBURST_FAILED_0 0xFFFF00A0 #define cOCT6100_DRIVER_RBURST_FAILED_1 0xFFFF00A1 #define cOCT6100_DRIVER_RBURST_FAILED_2 0xFFFF00A2 #define cOCT6100_DRIVER_RBURST_FAILED_3 0xFFFF00A3 #define cOCT6100_DRIVER_RBURST_FAILED_4 0xFFFF00A4 /***************************** TYPES ***************************************/ /*Change this type if your platform uses 64bits semaphores/locks */ typedef UINT32 tOCT6100_USER_SERIAL_OBJECT; typedef struct _OCT6100_GET_TIME_ { PVOID pProcessContext; UINT32 aulWallTimeUs[ 2 ]; } tOCT6100_GET_TIME, *tPOCT6100_GET_TIME; typedef struct _OCT6100_CREATE_SERIALIZE_OBJECT_ { PVOID pProcessContext; PSZ pszSerialObjName; tOCT6100_USER_SERIAL_OBJECT ulSerialObjHndl; } tOCT6100_CREATE_SERIALIZE_OBJECT, *tPOCT6100_CREATE_SERIALIZE_OBJECT; typedef struct _OCT6100_DESTROY_SERIALIZE_OBJECT_ { PVOID pProcessContext; tOCT6100_USER_SERIAL_OBJECT ulSerialObjHndl; } tOCT6100_DESTROY_SERIALIZE_OBJECT, *tPOCT6100_DESTROY_SERIALIZE_OBJECT; typedef struct _OCT6100_SEIZE_SERIALIZE_OBJECT_ { PVOID pProcessContext; tOCT6100_USER_SERIAL_OBJECT ulSerialObjHndl; UINT32 ulTryTimeMs; } tOCT6100_SEIZE_SERIALIZE_OBJECT, *tPOCT6100_SEIZE_SERIALIZE_OBJECT; typedef struct _OCT6100_RELEASE_SERIALIZE_OBJECT_ { PVOID pProcessContext; tOCT6100_USER_SERIAL_OBJECT ulSerialObjHndl; } tOCT6100_RELEASE_SERIALIZE_OBJECT, *tPOCT6100_RELEASE_SERIALIZE_OBJECT; typedef struct _OCT6100_WRITE_PARAMS_ { PVOID pProcessContext; UINT32 ulUserChipId; UINT32 ulWriteAddress; UINT16 usWriteData; } tOCT6100_WRITE_PARAMS, *tPOCT6100_WRITE_PARAMS; typedef struct _OCT6100_WRITE_SMEAR_PARAMS_ { PVOID pProcessContext; UINT32 ulUserChipId; UINT32 ulWriteAddress; UINT32 ulWriteLength; UINT16 usWriteData; } tOCT6100_WRITE_SMEAR_PARAMS, *tPOCT6100_WRITE_SMEAR_PARAMS; typedef struct _OCT6100_WRITE_BURST_PARAMS_ { PVOID pProcessContext; UINT32 ulUserChipId; UINT32 ulWriteAddress; UINT32 ulWriteLength; PUINT16 pusWriteData; } tOCT6100_WRITE_BURST_PARAMS, *tPOCT6100_WRITE_BURST_PARAMS; typedef struct _OCT6100_READ_PARAMS_ { PVOID pProcessContext; UINT32 ulUserChipId; UINT32 ulReadAddress; PUINT16 pusReadData; } tOCT6100_READ_PARAMS, *tPOCT6100_READ_PARAMS; typedef struct _OCT6100_READ_BURST_PARAMS_ { PVOID pProcessContext; UINT32 ulUserChipId; UINT32 ulReadAddress; UINT32 ulReadLength; PUINT16 pusReadData; } tOCT6100_READ_BURST_PARAMS, *tPOCT6100_READ_BURST_PARAMS; /************************** FUNCTION PROTOTYPES *****************************/ /* Time function. */ UINT32 Oct6100UserGetTime( IN OUT tPOCT6100_GET_TIME f_pTime ); /* Memory management functions. */ UINT32 Oct6100UserMemSet( IN PVOID f_pAddress, IN UINT32 f_ulPattern, IN UINT32 f_ulLength ); UINT32 Oct6100UserMemCopy( IN PVOID f_pDestination, IN const void *f_pSource, IN UINT32 f_ulLength ); /* Serialization functions. */ UINT32 Oct6100UserCreateSerializeObject( IN OUT tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate); UINT32 Oct6100UserDestroySerializeObject( IN tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy); UINT32 Oct6100UserSeizeSerializeObject( IN tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize); UINT32 Oct6100UserReleaseSerializeObject( IN tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease); /* Read/Write functions.*/ UINT32 Oct6100UserDriverWriteApi( IN tPOCT6100_WRITE_PARAMS f_pWriteParams ); UINT32 Oct6100UserDriverWriteOs( IN tPOCT6100_WRITE_PARAMS f_pWriteParams ); UINT32 Oct6100UserDriverWriteSmearApi( IN tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams ); UINT32 Oct6100UserDriverWriteSmearOs( IN tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams ); UINT32 Oct6100UserDriverWriteBurstApi( IN tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams ); UINT32 Oct6100UserDriverWriteBurstOs( IN tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams ); UINT32 Oct6100UserDriverReadApi( IN OUT tPOCT6100_READ_PARAMS f_pReadParams ); UINT32 Oct6100UserDriverReadOs( IN OUT tPOCT6100_READ_PARAMS f_pReadParams ); UINT32 Oct6100UserDriverReadBurstApi( IN OUT tPOCT6100_READ_BURST_PARAMS f_pBurstParams ); UINT32 Oct6100UserDriverReadBurstOs( IN OUT tPOCT6100_READ_BURST_PARAMS f_pBurstParams ); #endif /* __OCT6100_APIUD_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_debug_pub.h0000644000175000017500000000474311431317470026447 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_debug_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_debug.c. All elements defined in this file are for public usage of the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_DEBUG_PUB_H__ #define __OCT6100_DEBUG_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_DEBUG_SELECT_CHANNEL_ { UINT32 ulChannelHndl; } tOCT6100_DEBUG_SELECT_CHANNEL, *tPOCT6100_DEBUG_SELECT_CHANNEL; typedef struct _OCT6100_DEBUG_GET_DATA_ { UINT32 ulGetDataMode; UINT32 ulGetDataContent; UINT32 ulRemainingNumBytes; UINT32 ulTotalNumBytes; UINT32 ulMaxBytes; UINT32 ulValidNumBytes; PUINT8 pbyData; } tOCT6100_DEBUG_GET_DATA, *tPOCT6100_DEBUG_GET_DATA; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100DebugSelectChannelDef( OUT tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan ); UINT32 Oct6100DebugSelectChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan ); UINT32 Oct6100DebugGetDataDef( OUT tPOCT6100_DEBUG_GET_DATA f_pGetData ); UINT32 Oct6100DebugGetData( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_DEBUG_GET_DATA f_pGetData ); #endif /* __OCT6100_DEBUG_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_conf_bridge_pub.h0000644000175000017500000001331711431317470027617 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_conf_bridge_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_conf_bridge.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_conf_bridge_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 22 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CONF_BRIDGE_PUB_H__ #define __OCT6100_CONF_BRIDGE_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_CONF_BRIDGE_OPEN_ { PUINT32 pulConfBridgeHndl; /* Handle returned when the bridge is opened. */ BOOL fFlexibleConferencing; } tOCT6100_CONF_BRIDGE_OPEN, *tPOCT6100_CONF_BRIDGE_OPEN; typedef struct _OCT6100_CONF_BRIDGE_CLOSE_ { UINT32 ulConfBridgeHndl; } tOCT6100_CONF_BRIDGE_CLOSE, *tPOCT6100_CONF_BRIDGE_CLOSE; typedef struct _OCT6100_CONF_BRIDGE_CHAN_ADD_ { UINT32 ulConfBridgeHndl; UINT32 ulChannelHndl; UINT32 ulInputPort; UINT32 ulListenerMaskIndex; UINT32 ulListenerMask; BOOL fMute; UINT32 ulTappedChannelHndl; } tOCT6100_CONF_BRIDGE_CHAN_ADD, *tPOCT6100_CONF_BRIDGE_CHAN_ADD; typedef struct _OCT6100_CONF_BRIDGE_CHAN_REMOVE_ { UINT32 ulConfBridgeHndl; UINT32 ulChannelHndl; BOOL fRemoveAll; } tOCT6100_CONF_BRIDGE_CHAN_REMOVE, *tPOCT6100_CONF_BRIDGE_CHAN_REMOVE; typedef struct _OCT6100_CONF_BRIDGE_CHAN_MUTE_ { UINT32 ulChannelHndl; } tOCT6100_CONF_BRIDGE_CHAN_MUTE, *tPOCT6100_CONF_BRIDGE_CHAN_MUTE; typedef struct _OCT6100_CONF_BRIDGE_CHAN_UNMUTE_ { UINT32 ulChannelHndl; } tOCT6100_CONF_BRIDGE_CHAN_UNMUTE, *tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE; typedef struct _OCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET_ { UINT32 ulConfBridgeHndl; UINT32 ulChannelHndl; } tOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET, *tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET; typedef struct _OCT6100_CONF_BRIDGE_MASK_CHANGE_ { UINT32 ulChannelHndl; UINT32 ulNewListenerMask; } tOCT6100_CONF_BRIDGE_MASK_CHANGE, *tPOCT6100_CONF_BRIDGE_MASK_CHANGE; typedef struct _OCT6100_CONF_BRIDGE_STATS_ { UINT32 ulConfBridgeHndl; UINT32 ulNumChannels; UINT32 ulNumTappedChannels; BOOL fFlexibleConferencing; } tOCT6100_CONF_BRIDGE_STATS, *tPOCT6100_CONF_BRIDGE_STATS; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ConfBridgeOpenDef( OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ); UINT32 Oct6100ConfBridgeOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ); UINT32 Oct6100ConfBridgeCloseDef( OUT tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ); UINT32 Oct6100ConfBridgeClose( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ); UINT32 Oct6100ConfBridgeChanAddDef( OUT tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ); UINT32 Oct6100ConfBridgeChanAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ); UINT32 Oct6100ConfBridgeChanRemoveDef( OUT tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ); UINT32 Oct6100ConfBridgeChanRemove( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ); UINT32 Oct6100ConfBridgeChanMuteDef( OUT tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ); UINT32 Oct6100ConfBridgeChanMute( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ); UINT32 Oct6100ConfBridgeChanUnMuteDef( OUT tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ); UINT32 Oct6100ConfBridgeChanUnMute( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ); UINT32 Oct6100ConfBridgeDominantSpeakerSetDef( OUT tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ); UINT32 Oct6100ConfBridgeDominantSpeakerSet( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ); UINT32 Oct6100ConfBridgeMaskChangeDef( OUT tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ); UINT32 Oct6100ConfBridgeMaskChange( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ); UINT32 Oct6100ConfBridgeGetStatsDef( OUT tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ); UINT32 Oct6100ConfBridgeGetStats( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ); #endif /* __OCT6100_CONF_BRIDGE_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_open_inst.h0000644000175000017500000003244511525010331027502 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_open_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_chip_open.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_chip_open_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 122 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_OPEN_INST_H__ #define __OCT6100_CHIP_OPEN_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_CHIP_CONFIG_ { UINT32 ulUserChipId; PVOID pProcessContext; unsigned char const *pbyImageFile; /* Byte pointer to the image file to be uploaded into the chip. */ UINT32 ulImageSize; /* Size of the image file (in bytes). */ UINT32 ulMemClkFreq; UINT32 ulUpclkFreq; /* 33.33 or 66.66 MHz. */ UINT8 fEnableMemClkOut; /* TRUE/FALSE */ UINT8 fMultiProcessSystem; UINT8 byMemoryType; /* SDRAM or DDR */ UINT8 byNumMemoryChips; /* Number of memory chips present. */ UINT32 ulMemoryChipSize; /* The size of the memory chips. */ UINT16 usMaxRwAccesses; UINT16 usTailDisplacement; /* Resource allocation parameters. */ UINT16 usMaxChannels; UINT16 usMaxBiDirChannels; UINT32 aulTdmStreamFreqs[ cOCT6100_TDM_STREAM_MAX_GROUPS ]; UINT8 byMaxTdmStreams; UINT8 byTdmSampling; UINT8 fEnableFastH100Mode; UINT8 fEnableAcousticEcho; /* Acoustic echo enabled. */ UINT16 ausTimestampTimeslots[ 4 ]; UINT16 ausTimestampStreams[ 4 ]; UINT8 fUseSynchTimestamp; /* Debug feature used to record stream information from a channel.*/ UINT8 fEnableChannelRecording; UINT16 usMaxRemoteDebugSessions; UINT8 byInterruptPolarity; UINT16 usMaxTsiCncts; UINT8 fEnableExtToneDetection; UINT8 fEnable2100StopEvent; UINT16 usMaxConfBridges; UINT16 usMaxFlexibleConfParticipants; UINT16 usMaxPlayoutBuffers; /* Playout event software buffer size. */ UINT32 ulSoftBufPlayoutEventsBufSize; /* Soft buffer size. */ UINT32 ulSoftToneEventsBufSize; UINT16 usMaxPhasingTssts; UINT16 usMaxAdpcmChannels; UINT8 fEnableProductionBist; UINT32 ulProductionBistMode; UINT32 ulNumProductionBistLoops; } tOCT6100_API_CHIP_CONFIG, *tPOCT6100_API_CHIP_CONFIG; typedef struct _OCT6100_API_MISCELLANEOUS_ { /* Total size of external memories. */ UINT32 ulTotalMemSize; UINT32 ulH100SlaveMode; /* Mclk frequency generated by the chip. */ UINT32 ulMclkFreq; /* Array of UINT32s used to perform a burst of writes (avoids having to allocate on the stack. The size of this array MUST NOT CHANGE (it's used everywhere). */ UINT16 ausSuperArray[ cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ]; /* Chip ID and revision.*/ UINT16 usChipId; UINT16 usChipRevision; /* Lsu CPU access variables.*/ UINT16 usCpuLsuWritePtr; UINT16 usCodepoint; /* Max number of channel supported.*/ UINT16 usMaxNumberOfChannels; UINT16 usMaxH100Speed; UINT16 usTdmClkBoundary; UINT16 usNumBridgesOpened; UINT16 usFirstBridge; } tOCT6100_API_MISCELLANEOUS, *tPOCT6100_API_MISCELLANEOUS; typedef struct _OCT6100_API_MEMORY_MAP_ { /*-----------------------------------------------------------------------------*/ /* Structure contained in external memory. */ /* Memory mapping filled using TLV information from the chip. */ /* Main channel memory. */ UINT32 ulChanMainMemBase; UINT32 ulChanMainMemSize; UINT32 ulChanMainIoMemOfst; UINT32 ulChanMainRinCBMemOfst; UINT32 ulChanMainRinCBMemSize; UINT32 ulChanMainSinCBMemOfst; UINT32 ulChanMainSinCBMemSize; UINT32 ulChanMainSoutCBMemOfst; UINT32 ulChanMainSoutCBMemSize; /* Free memory base address. */ UINT32 ulFreeMemBaseAddress; /* Root channel config offset. */ UINT32 ulChanRootConfOfst; /* Playout buffer info. */ UINT32 ulChanMainRinPlayoutMemOfst; UINT32 ulChanMainRinPlayoutMemSize; UINT32 ulChanMainSoutPlayoutMemOfst; UINT32 ulChanMainSoutPlayoutMemSize; /* Channel Stats location */ UINT32 ulChanMainIoStatsOfst; UINT32 ulChanMainIoStatsSize; /* Buffer playout fields. */ tOCT6100_TLV_OFFSET PlayoutRinWritePtrOfst; tOCT6100_TLV_OFFSET PlayoutRinIgnoreSkipCleanOfst; tOCT6100_TLV_OFFSET PlayoutRinSkipPtrOfst; tOCT6100_TLV_OFFSET PlayoutSoutWritePtrOfst; tOCT6100_TLV_OFFSET PlayoutSoutIgnoreSkipCleanOfst; tOCT6100_TLV_OFFSET PlayoutSoutSkipPtrOfst; tOCT6100_TLV_OFFSET PlayoutRinReadPtrOfst; tOCT6100_TLV_OFFSET PlayoutSoutReadPtrOfst; tOCT6100_TLV_OFFSET PlayoutRinHardSkipOfst; tOCT6100_TLV_OFFSET PlayoutSoutHardSkipOfst; /* Adaptive noise reduction. */ tOCT6100_TLV_OFFSET AdaptiveNoiseReductionOfst; /* DC offset removal. */ tOCT6100_TLV_OFFSET RinDcOffsetRemovalOfst; tOCT6100_TLV_OFFSET SinDcOffsetRemovalOfst; /* Level control. */ tOCT6100_TLV_OFFSET RinLevelControlOfst; tOCT6100_TLV_OFFSET SoutLevelControlOfst; /* Auto level control. */ tOCT6100_TLV_OFFSET RinAutoLevelControlTargetOfst; tOCT6100_TLV_OFFSET SoutAutoLevelControlTargetOfst; /* High level compensation. */ tOCT6100_TLV_OFFSET RinHighLevelCompensationThresholdOfst; tOCT6100_TLV_OFFSET SoutHighLevelCompensationThresholdOfst; /* Auto level control and high level compensation status. */ tOCT6100_TLV_OFFSET AlcHlcStatusOfst; /* Confort Noise Mode. */ tOCT6100_TLV_OFFSET ComfortNoiseModeOfst; /* NLP control field. */ tOCT6100_TLV_OFFSET NlpControlFieldOfst; /* VAD control field offset.*/ tOCT6100_TLV_OFFSET VadControlFieldOfst; /* NLP Trivial field offset. */ tOCT6100_TLV_OFFSET NlpTrivialFieldOfst; /* Acoustic echo field offset. */ tOCT6100_TLV_OFFSET AecFieldOfst; /* Acoustic echo default ERL field offset. */ tOCT6100_TLV_OFFSET AecDefaultErlFieldOfst; /* Non-linearity behavior A and B field offset. */ tOCT6100_TLV_OFFSET PcmLeakFieldOfst; tOCT6100_TLV_OFFSET NlpConvCapFieldOfst; /* Default ERL field offset. */ tOCT6100_TLV_OFFSET DefaultErlFieldOfst; /* Tone Removal field offset.*/ tOCT6100_TLV_OFFSET ToneRemovalFieldOfst; /* Channel config fields offset. */ tOCT6100_TLV_OFFSET ChanMainIoMaxEchoPointOfst; tOCT6100_TLV_OFFSET TailDisplEnableOfst; /* Pouch fields offset. */ tOCT6100_TLV_OFFSET PouchBootInstructionOfst; tOCT6100_TLV_OFFSET PouchBootResultOfst; tOCT6100_TLV_OFFSET PouchTailDisplOfst; /* 2100 Hz Auto disabling fields offset. */ tOCT6100_TLV_OFFSET ToneDisablerControlOfst; /* Conferencing dominant speaker field offset. */ tOCT6100_TLV_OFFSET DominantSpeakerFieldOfst; /* Conferencing noise reduction field offset. */ tOCT6100_TLV_OFFSET ConferencingNoiseReductionOfst; /* Per channel tail displacement field offset. */ tOCT6100_TLV_OFFSET PerChanTailDisplacementFieldOfst; /* Per channel tail length field offset. */ tOCT6100_TLV_OFFSET PerChanTailLengthFieldOfst; /* AF control/echo cancellation bypass. */ tOCT6100_TLV_OFFSET AftControlOfst; /* Voice detected stat field offset. */ tOCT6100_TLV_OFFSET SinVoiceDetectedStatOfst; /* Rin currently applied gain field offset. */ tOCT6100_TLV_OFFSET RinAppliedGainStatOfst; /* Sout currently applied gain field offset. */ tOCT6100_TLV_OFFSET SoutAppliedGainStatOfst; /* Adaptive listener enhancement field offset. */ tOCT6100_TLV_OFFSET AdaptiveAleOfst; /* Rin NR field offset. */ tOCT6100_TLV_OFFSET RinAnrOfst; /* Rin NR value field offset. */ tOCT6100_TLV_OFFSET RinAnrValOfst; /* Sin Mute field offset. */ tOCT6100_TLV_OFFSET SinMuteOfst; /* Rin Mute field offset. */ tOCT6100_TLV_OFFSET RinMuteOfst; /* Sout ANR SNR enhancement offset. */ tOCT6100_TLV_OFFSET AnrSnrEnhancementOfst; /* Sout ANR voice-noise segregation offset. */ tOCT6100_TLV_OFFSET AnrVoiceNoiseSegregationOfst; /* Tone disabler VQE activation delay offset. */ tOCT6100_TLV_OFFSET ToneDisablerVqeActivationDelayOfst; /* AF tail displacement value configuration offset. */ tOCT6100_TLV_OFFSET AfTailDisplacementFieldOfst; /* Pouch counter field offset. */ tOCT6100_TLV_OFFSET PouchCounterFieldOfst; /* Acoustic echo tail length. */ tOCT6100_TLV_OFFSET AecTailLengthFieldOfst; /* Is ISR called field offset. */ tOCT6100_TLV_OFFSET IsIsrCalledFieldOfst; /* Music protection enable field offset. */ tOCT6100_TLV_OFFSET MusicProtectionFieldOfst; /* Rin port energy level statistics field offset. */ tOCT6100_TLV_OFFSET RinEnergyStatFieldOfst; /* Sout port energy level statistics field offset. */ tOCT6100_TLV_OFFSET SoutEnergyStatFieldOfst; /* Double talk behavior field offset. */ tOCT6100_TLV_OFFSET DoubleTalkBehaviorFieldOfst; /* Idle code detection field offset. */ tOCT6100_TLV_OFFSET IdleCodeDetectionFieldOfst; /* TSI memory mapping information.*/ UINT32 ulNumTsiEntries; /*-----------------------------------------------------------------------------*/ } tOCT6100_API_MEMORY_MAP, *tPOCT6100_API_MEMORY_MAP; typedef struct _OCT6100_API_SOFT_BUFS_ { /* To avoid compilation errors. */ UINT32 ulDummyVariable; /* Tone events buffer pointers. */ UINT32 ulToneEventBufferWritePtr; UINT32 ulToneEventBufferReadPtr; UINT32 ulToneEventBufferSize; UINT32 ulToneEventBufferMemOfst; UINT32 ulToneEventBufferOverflowCnt; /* Playout events buffer pointers. */ UINT32 ulBufPlayoutEventBufferWritePtr; UINT32 ulBufPlayoutEventBufferReadPtr; UINT32 ulBufPlayoutEventBufferSize; UINT32 ulBufPlayoutEventBufferMemOfst; UINT32 ulBufPlayoutEventBufferOverflowCnt; } tOCT6100_API_SOFT_BUFS, *tPOCT6100_API_SOFT_BUFS; typedef struct _OCT6100_API_IMAGE_REGION_ { UINT32 ulPart1Size; UINT32 ulPart2Size; UINT32 ulClockInfo; UINT32 ulReserved; UINT32 ulPart1BaseAddress; UINT32 ulPart2BaseAddress; } tOCT6100_API_IMAGE_REGION, *tPOCT6100_API_IMAGE_REGION; typedef struct _OCT6100_API_IMAGE_INFO_ { UINT8 fBufferPlayout; UINT8 fAdaptiveNoiseReduction; UINT8 fRinDcOffsetRemoval; UINT8 fSinDcOffsetRemoval; UINT8 fRinAutoLevelControl; UINT8 fSoutAutoLevelControl; UINT8 fRinHighLevelCompensation; UINT8 fSoutHighLevelCompensation; UINT8 fAlcHlcStatus; UINT8 fComfortNoise; UINT8 fNlpControl; UINT8 fSilenceSuppression; UINT8 fToneDisabler; UINT8 fTailDisplacement; UINT8 fPerChannelTailDisplacement; UINT8 fAcousticEcho; UINT8 fAecEnabled; UINT8 fToneRemoval; UINT8 fDefaultErl; UINT8 fMaxEchoPoint; UINT8 fNonLinearityBehaviorA; UINT8 fNonLinearityBehaviorB; UINT8 fAecDefaultErl; UINT8 fAdpcm; UINT8 fConferencing; UINT8 fConferencingNoiseReduction; UINT8 fMusicProtection; UINT8 fDominantSpeakerEnabled; UINT8 fAftControl; UINT8 fSinVoiceDetectedStat; UINT8 fRinAppliedGainStat; UINT8 fSoutAppliedGainStat; UINT8 fListenerEnhancement; UINT8 fRoutNoiseReduction; UINT8 fRoutNoiseReductionLevel; UINT8 fRinMute; UINT8 fSinMute; UINT8 fAnrSnrEnhancement; UINT8 fAnrVoiceNoiseSegregation; UINT8 fRinBufferPlayoutHardSkip; UINT8 fSoutBufferPlayoutHardSkip; UINT16 usMaxNumberOfChannels; UINT8 fPerChannelTailLength; UINT8 fToneDisablerVqeActivationDelay; UINT32 ulToneProfileNumber; UINT16 usMaxTailDisplacement; UINT16 usMaxTailLength; UINT8 byNumToneDetectors; UINT8 byMaxNumberPlayoutEvents; UINT8 fAfTailDisplacement; UINT8 fAecTailLength; UINT8 fMusicProtectionConfiguration; UINT8 byImageType; UINT8 fBufferPlayoutSkipInEvents; UINT8 fSoutNoiseBleaching; UINT8 fRinEnergyStat; UINT8 fSoutEnergyStat; UINT8 fDoubleTalkBehavior; UINT8 fDoubleTalkBehaviorFieldOfst; UINT8 fIdleCodeDetection; UINT8 fIdleCodeDetectionConfiguration; UINT8 fSinLevel; UINT8 szVersionNumber[ cOCT6100_VERSION_NUMBER_MAX_SIZE ]; UINT32 ulBuildId; tOCT6100_TLV_TONE_INFO aToneInfo[ cOCT6100_MAX_TONE_EVENT ]; } tOCT6100_API_IMAGE_INFO, *tPOCT6100_API_IMAGE_INFO; typedef struct _OCT6100_API_MIXER_ { /* Pointer to the various event region. */ UINT16 usFirstSoutCopyEventPtr; UINT16 usLastSoutCopyEventPtr; UINT16 usFirstBridgeEventPtr; UINT16 usLastBridgeEventPtr; UINT16 usFirstSinCopyEventPtr; UINT16 usLastSinCopyEventPtr; /* Recording event info. */ UINT16 usRecordCopyEventIndex; UINT16 usRecordSinEventIndex; } tOCT6100_API_MIXER, tPOCT6100_API_MIXER; typedef struct _OCT6100_API_BUFFER_PLAYOUT_MALLOC_INFO_ { /* Next node to be checked for free memory. */ UINT32 ulRovingNode; /* First unused node in the unused list. */ UINT32 ulFirstUnusedNode; /* Last unused node in the unused list. */ UINT32 ulLastUnusedNode; /* Count of unused nodes. */ UINT32 ulUnusedNodeCnt; } tOCT6100_API_BUFFER_PLAYOUT_MALLOC_INFO, *tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_INFO; #endif /* __OCT6100_CHIP_OPEN_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_apimi.h0000644000175000017500000000426611431317470025612 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_apimi.h Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the declaration of all functions exported from the APIMI block. The APIMI block contains only one function: Oct6100InterruptMask. The function is used to mask out the interrupt pin of the chip. This function is used when a deferred procedure call treats the interrupt (new interrupts must not be generated until the signalled interrupt is treated). This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_APIMI_H__ #define __OCT6100_APIMI_H__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" /***************************** TYPES ***************************************/ typedef struct _OCT6100_INTERRUPT_MASK_ { UINT32 ulUserChipIndex; PVOID pProcessContext; } tOCT6100_INTERRUPT_MASK, *tPOCT6100_INTERRUPT_MASK; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100InterruptMaskDef( OUT tPOCT6100_INTERRUPT_MASK f_pInterruptMask ); UINT32 Oct6100InterruptMask( IN tPOCT6100_INTERRUPT_MASK f_pInterruptMask ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __OCT6100_APIMI_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_api.h0000644000175000017500000000475711431317470025271 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_api.h Copyright (c) 2001-2007 Octasic Inc. Description: Header file containing all definitions used throughout the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 23 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_API_H__ #define __OCT6100_API_H__ #ifdef __cplusplus extern "C" { #endif /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100_defines.h" #include "oct6100_errors.h" #include "oct6100_apiud.h" #include "oct6100_tlv_inst.h" #include "oct6100_chip_stats_inst.h" #include "oct6100_tsi_cnct_inst.h" #include "oct6100_mixer_inst.h" #include "oct6100_events_inst.h" #include "oct6100_tone_detection_inst.h" #include "oct6100_conf_bridge_inst.h" #include "oct6100_playout_buf_inst.h" #include "oct6100_adpcm_chan_inst.h" #include "oct6100_phasing_tsst_inst.h" #include "oct6100_channel_inst.h" #include "oct6100_interrupts_inst.h" #include "oct6100_remote_debug_inst.h" #include "oct6100_debug_inst.h" #include "oct6100_chip_open_inst.h" #include "oct6100_api_inst.h" #include "oct6100_interrupts_pub.h" #include "oct6100_tsi_cnct_pub.h" #include "oct6100_events_pub.h" #include "oct6100_tone_detection_pub.h" #include "oct6100_mixer_pub.h" #include "oct6100_conf_bridge_pub.h" #include "oct6100_playout_buf_pub.h" #include "oct6100_channel_pub.h" #include "oct6100_remote_debug_pub.h" #include "oct6100_debug_pub.h" #include "oct6100_chip_open_pub.h" #include "oct6100_chip_stats_pub.h" #include "oct6100_adpcm_chan_pub.h" #include "oct6100_phasing_tsst_pub.h" #ifdef __cplusplus } #endif #endif /* __OCT6100_API_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_tsi_cnct_inst.h0000644000175000017500000000441011431317470027345 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsi_cnct_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_tsi_cnct.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_tsi_cnct_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 9 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TSI_CNCT_INST_H__ #define __OCT6100_TSI_CNCT_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_TSI_CNCT_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt; /* Input PCM law. */ UINT8 byInputPcmLaw; /* TSI chariot memory entry. */ UINT16 usTsiMemIndex; /* Input and output timeslot information. */ UINT16 usInputTimeslot; UINT16 usInputStream; UINT16 usOutputTimeslot; UINT16 usOutputStream; /* Internal info for quick access to structures associated to this TSI cnct. */ UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; } tOCT6100_API_TSI_CNCT, *tPOCT6100_API_TSI_CNCT; #endif /* __OCT6100_TSI_CNCT_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_remote_debug_pub.h0000644000175000017500000000427311431317470030020 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_remote_debug_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_remote_debug.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_remote_debug_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_REMOTE_DEBUG_PUB_H__ #define __OCT6100_REMOTE_DEBUG_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_REMOTE_DEBUG_ { PUINT32 pulReceivedPktPayload; UINT32 ulReceivedPktLength; PUINT32 pulResponsePktPayload; UINT32 ulMaxResponsePktLength; UINT32 ulResponsePktLength; } tOCT6100_REMOTE_DEBUG, *tPOCT6100_REMOTE_DEBUG; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100RemoteDebugDef( OUT tPOCT6100_REMOTE_DEBUG f_pRemoteDebug ); UINT32 Oct6100RemoteDebug( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_REMOTE_DEBUG f_pRemoteDebug ); #endif /* __OCT6100_REMOTE_DEBUG_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_stats_inst.h0000644000175000017500000000477211431317470027713 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_stats_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_chip_stats.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_chip_stats_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 21 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_STATS_INST_H__ #define __OCT6100_CHIP_STATS_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_CHIP_ERROR_STATS_ { UINT8 fFatalChipError; UINT32 ulInternalReadTimeoutCnt; UINT32 ulSdramRefreshTooLateCnt; UINT32 ulPllJitterErrorCnt; /* Internal tone detector error counter. */ UINT32 ulToneDetectorErrorCnt; UINT32 ulOverflowToneEventsCnt; UINT32 ulH100OutOfSyncCnt; UINT32 ulH100ClkABadCnt; UINT32 ulH100ClkBBadCnt; UINT32 ulH100FrameABadCnt; } tOCT6100_API_CHIP_ERROR_STATS, *tPOCT6100_API_CHIP_ERROR_STATS; typedef struct _OCT6100_API_CHIP_STATS_ { UINT16 usNumberChannels; UINT16 usNumberBiDirChannels; UINT16 usNumberTsiCncts; UINT16 usNumberConfBridges; UINT16 usNumberPlayoutBuffers; UINT16 usNumEcChanUsingMixer; UINT32 ulPlayoutMemUsed; UINT16 usNumberActiveBufPlayoutPorts; UINT16 usNumberPhasingTssts; UINT16 usNumberAdpcmChans; } tOCT6100_API_CHIP_STATS, *tPOCT6100_API_CHIP_STATS; #endif /* __OCT6100_CHIP_STATS_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_channel_inst.h0000644000175000017500000002277511611607513027165 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_channel_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_channel.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_channel_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 90 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHANNEL_INST_H__ #define __OCT6100_CHANNEL_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ #ifndef __KERNEL__ #include #endif #ifndef PTR_TYPE #define PTR_TYPE UINT16 #endif typedef struct _OCT6100_API_CHANNEL_TDM_ { /* Laws. */ UINT8 byRinPcmLaw : 1; UINT8 bySinPcmLaw : 1; UINT8 byRoutPcmLaw : 1; UINT8 bySoutPcmLaw : 1; UINT8 byRinNumTssts : 2; UINT8 bySinNumTssts : 2; UINT8 byRoutNumTssts : 2; UINT8 bySoutNumTssts : 2; /* RIN port. */ UINT16 usRinTimeslot; UINT16 usRinStream; /* SIN port. */ UINT16 usSinTimeslot; UINT16 usSinStream; /* ROUT port. */ UINT16 usRoutTimeslot; UINT16 usRoutStream; /* SOUT port. */ UINT16 usSoutTimeslot; UINT16 usSoutStream; /* ROUT broadcast info. */ UINT16 usRoutBrdcastTsstFirstEntry; UINT16 usRoutBrdcastTsstNumEntry; /* SOUT broadcast info. */ UINT16 usSoutBrdcastTsstFirstEntry; UINT16 usSoutBrdcastTsstNumEntry; } tOCT6100_API_CHANNEL_TDM, *tPOCT6100_API_CHANNEL_TDM; typedef struct _OCT6100_API_CHANNEL_VQE_ { UINT8 fEnableNlp : 1; UINT8 fEnableTailDisplacement : 1; UINT8 fSinDcOffsetRemoval : 1; UINT8 fRinDcOffsetRemoval : 1; UINT8 fRinLevelControl : 1; UINT8 fSoutLevelControl : 1; UINT8 fRinAutomaticLevelControl : 1; UINT8 fSoutAutomaticLevelControl : 1; UINT8 fRinHighLevelCompensation : 1; UINT8 fSoutAdaptiveNoiseReduction : 1; UINT8 fDtmfToneRemoval : 1; UINT8 fAcousticEcho : 1; UINT8 byComfortNoiseMode : 2; UINT8 fSoutNaturalListenerEnhancement : 1; UINT8 fRoutNoiseReduction : 1; UINT8 fEnableMusicProtection : 1; UINT8 fIdleCodeDetection : 1; UINT8 byAnrVoiceNoiseSegregation : 4; UINT8 byDoubleTalkBehavior : 1; UINT8 fSoutNoiseBleaching : 1; UINT8 fSoutConferencingNoiseReduction : 1; UINT8 byNonLinearityBehaviorA : 4; UINT8 byNonLinearityBehaviorB : 4; UINT8 bySoutAutomaticListenerEnhancementGainDb; UINT8 bySoutNaturalListenerEnhancementGainDb; OCT_INT8 chRinAutomaticLevelControlTargetDb; OCT_INT8 chSoutAutomaticLevelControlTargetDb; OCT_INT8 chRinHighLevelCompensationThresholdDb; OCT_INT8 chRinLevelControlGainDb; OCT_INT8 chSoutLevelControlGainDb; OCT_INT8 chDefaultErlDb; OCT_INT8 chAecDefaultErlDb; OCT_INT8 chRoutNoiseReductionLevelGainDb; OCT_INT8 chAnrSnrEnhancementDb; UINT16 usToneDisablerVqeActivationDelay; UINT16 usAecTailLength; UINT16 usTailDisplacement; UINT16 usTailLength; } tOCT6100_API_CHANNEL_VQE, *tPOCT6100_API_CHANNEL_VQE; typedef struct _OCT6100_API_CHANNEL_CODEC_ { UINT8 byAdpcmNibblePosition : 1; UINT8 fEnableSilenceSuppression : 1; UINT8 byEncoderPort : 4; UINT8 byDecoderPort : 4; UINT8 byPhasingType : 2; UINT8 byEncodingRate; UINT8 byDecodingRate; UINT16 byPhase; } tOCT6100_API_CHANNEL_CODEC, *tPOCT6100_API_CHANNEL_CODEC; typedef struct _OCT6100_API_CHANNEL_ { /*=======================================================================*/ /* Channel configuration. */ /* Flag specifying whether the entry is used or not. */ UINT8 fReserved : 1; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt : 1; /* Is this a bidirectionnal channel? */ UINT8 fBiDirChannel : 1; /* Enable tone disabler? */ UINT8 fEnableToneDisabler : 1; /* Current echo operation mode. */ UINT8 byEchoOperationMode : 3; UINT8 byToneDisablerStatus : 1; UINT8 fMute : 1; UINT8 fTap : 1; UINT8 fBeingTapped : 1; UINT8 fCopyEventCreated : 1; UINT8 fSoutBufPlaying : 1; UINT8 fRinBufPlaying : 1; UINT8 fRinBufPlayoutNotifyOnStop : 1; UINT8 fRinBufPlayoutRepeatUsed : 1; UINT8 fSoutBufPlayoutNotifyOnStop : 1; UINT8 fSoutBufPlayoutRepeatUsed : 1; UINT8 fRinHardStop : 1; UINT8 fSoutHardStop : 1; UINT8 byRinPlayoutStopEventType : 1; UINT8 bySoutPlayoutStopEventType : 1; UINT8 fRinBufAdded : 1; UINT8 fSoutBufAdded : 1; UINT8 fBufPlayoutActive : 1; /* Enable extended tone detection. */ UINT8 fEnableExtToneDetection : 1; /* State of the codec structure associated to this channel. */ UINT8 fSinSoutCodecActive : 1; UINT8 fRinRoutCodecActive : 1; /* TSI chariot memory entry for the Rin/Rout stream. */ UINT16 usRinRoutTsiMemIndex; /* TSI chariot memory entry for the Sin/Sout stream. */ UINT16 usSinSoutTsiMemIndex; /* Additional TSI entry used to temporarily store the SIN signal. */ UINT16 usExtraSinTsiMemIndex; UINT16 usExtraSinTsiDependencyCnt; /* Additional TSI entry used to temporarily store the RIN signal. */ UINT16 usExtraRinTsiMemIndex; UINT16 usExtraRinTsiDependencyCnt; /* Conversion chariot memory entry. */ UINT16 usRinRoutConversionMemIndex; UINT16 usSinSoutConversionMemIndex; /* TSST control memory entry. */ UINT16 usRinTsstIndex; UINT16 usSinTsstIndex; UINT16 usRoutTsstIndex; UINT16 usSoutTsstIndex; /* SSPX memory entry. */ UINT16 usEchoMemIndex; /* Active mixer events count to test for last event. */ UINT16 usMixerEventCnt; /* Copy events. */ UINT16 usSinCopyEventIndex; UINT16 usSoutCopyEventIndex; /* Silence events. */ UINT16 usRinSilenceEventIndex; UINT16 usSinSilenceEventIndex; /* TDM configuration. */ tOCT6100_API_CHANNEL_TDM TdmConfig; /* VQE configuration. */ tOCT6100_API_CHANNEL_VQE VqeConfig; /* Currently muted ports. */ UINT16 usMutedPorts; /*=======================================================================*/ /*=======================================================================*/ /* Statistics section. */ INT16 sComfortNoiseLevel; UINT16 usCurrentEchoDelay; UINT16 usMaxEchoDelay; UINT16 usNumEchoPathChanges; UINT16 usNumEchoPathChangesOfst; INT16 sCurrentERL; INT16 sCurrentERLE; INT16 sMaxERL; INT16 sMaxERLE; INT16 sRinLevel; INT16 sSinLevel; INT16 sRinAppliedGain; INT16 sSoutAppliedGain; /*=======================================================================*/ /*=======================================================================*/ /* Bridge information. */ UINT16 usBridgeIndex; UINT16 usLoadEventIndex; UINT16 usSubStoreEventIndex; UINT16 usFlexConfParticipantIndex; UINT16 usTapBridgeIndex; UINT16 usTapChanIndex; /*=======================================================================*/ /*=======================================================================*/ /* Buffer playout information. */ PTR_TYPE ulRinBufWritePtr; PTR_TYPE ulRinBufSkipPtr; PTR_TYPE ulSoutBufWritePtr; PTR_TYPE ulSoutBufSkipPtr; /* User channel ID, transparently passed to the user. */ /*=======================================================================*/ /*=======================================================================*/ /* Copy events information. */ /* Number of copy events created. */ UINT16 usCopyEventCnt; /*=======================================================================*/ /*=======================================================================*/ /* Extended tone detection info. */ UINT16 usExtToneChanIndex; UINT16 usExtToneMixerIndex; UINT16 usExtToneTsiIndex; /* Index of the phasing TSST */ UINT16 usPhasingTsstIndex; /* Mode of operation of the channel based on the extended tone detection configuration. */ PTR_TYPE ulExtToneChanMode; /*=======================================================================*/ /* Tone detection state. */ /* This array is configured as follow. */ /* Index 0 contain event 0 to 31 and Index 1 contains event 32 - 55 */ PTR_TYPE ulLastSSToneDetected; PTR_TYPE ulLastSSToneTimestamp; PTR_TYPE ulRinUserBufPlayoutEventId; PTR_TYPE ulSoutUserBufPlayoutEventId; UINT32 aulToneConf[2]; UINT32 ulUserChanId; /*=======================================================================*/ /*=======================================================================*/ /* Codec configuration. */ tOCT6100_API_CHANNEL_CODEC CodecConfig; } tOCT6100_API_CHANNEL, *tPOCT6100_API_CHANNEL; typedef struct _OCT6100_API_BIDIR_CHANNEL_ { UINT16 usFirstChanIndex; UINT16 usSecondChanIndex; /* Flag specifying whether the entry is used or not. */ UINT8 fReserved : 1; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt; } tOCT6100_API_BIDIR_CHANNEL, *tPOCT6100_API_BIDIR_CHANNEL; #endif /* __OCT6100_CHANNEL_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_chip_open_pub.h0000644000175000017500000001626011431317470027322 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_open_pub.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_chip_open.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_chip_open_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 54 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_OPEN_PUB_H__ #define __OCT6100_CHIP_OPEN_PUB_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_CHIP_OPEN_ { UINT32 ulUserChipId; BOOL fMultiProcessSystem; PVOID pProcessContext; UINT32 ulMaxRwAccesses; unsigned char const *pbyImageFile; /* Byte pointer to the image file to be uploaded into the chip. */ UINT32 ulImageSize; /* Size of the image file (in bytes). */ UINT32 ulMemClkFreq; /* 10 - 133.3 MHz. */ UINT32 ulUpclkFreq; /* 1 - 66.6 MHz. */ BOOL fEnableMemClkOut; UINT32 ulMemoryType; /* SDRAM or DDR type external memory. */ UINT32 ulNumMemoryChips; /* Number of memory chips present. */ UINT32 ulMemoryChipSize; /* The size of the memory chips. */ UINT32 ulTailDisplacement; /* Tail displacement supported by the chip. */ BOOL fEnableAcousticEcho;/* Acoustic echo cancellation enabled. */ /* Resource allocation parameters. */ UINT32 ulMaxChannels; UINT32 ulMaxTsiCncts; UINT32 ulMaxBiDirChannels; UINT32 ulMaxConfBridges; UINT32 ulMaxFlexibleConfParticipants; UINT32 ulMaxPlayoutBuffers; UINT32 ulMaxPhasingTssts; UINT32 ulMaxAdpcmChannels; BOOL fUseSynchTimestamp; UINT32 aulTimestampTimeslots[ 4 ]; UINT32 aulTimestampStreams[ 4 ]; UINT32 ulInterruptPolarity; tOCT6100_INTERRUPT_CONFIGURE InterruptConfig; UINT32 aulTdmStreamFreqs[ cOCT6100_TDM_STREAM_MAX_GROUPS ]; UINT32 ulMaxTdmStreams; UINT32 ulTdmSampling; BOOL fEnableFastH100Mode; UINT32 ulSoftToneEventsBufSize; /* In events. */ BOOL fEnableExtToneDetection; BOOL fEnable2100StopEvent; UINT32 ulSoftBufferPlayoutEventsBufSize; /* In events. */ UINT32 ulMaxRemoteDebugSessions; BOOL fEnableChannelRecording; BOOL fEnableProductionBist; UINT32 ulProductionBistMode; UINT32 ulNumProductionBistLoops; } tOCT6100_CHIP_OPEN, *tPOCT6100_CHIP_OPEN; typedef struct _OCT6100_GET_INSTANCE_SIZE_ { UINT32 ulApiInstanceSize; } tOCT6100_GET_INSTANCE_SIZE, *tPOCT6100_GET_INSTANCE_SIZE; typedef struct _OCT6100_CHIP_CLOSE_ { UINT32 ulDummyVariable; } tOCT6100_CHIP_CLOSE, *tPOCT6100_CHIP_CLOSE; typedef struct _OCT6100_CREATE_LOCAL_INSTANCE_ { tPOCT6100_INSTANCE_API pApiInstShared; tPOCT6100_INSTANCE_API pApiInstLocal; PVOID pProcessContext; UINT32 ulUserChipId; } tOCT6100_CREATE_LOCAL_INSTANCE, *tPOCT6100_CREATE_LOCAL_INSTANCE; typedef struct _OCT6100_DESTROY_LOCAL_INSTANCE_ { UINT32 ulDummy; } tOCT6100_DESTROY_LOCAL_INSTANCE, *tPOCT6100_DESTROY_LOCAL_INSTANCE; typedef struct _OCT6100_GET_HW_REVISION_ { UINT32 ulUserChipId; PVOID pProcessContext; UINT32 ulRevisionNum; } tOCT6100_GET_HW_REVISION, *tPOCT6100_GET_HW_REVISION; typedef struct _OCT6100_FREE_RESOURCES_ { BOOL fFreeTsiConnections; BOOL fFreeConferenceBridges; BOOL fFreePlayoutBuffers; BOOL fFreePhasingTssts; BOOL fFreeAdpcmChannels; } tOCT6100_FREE_RESOURCES, *tPOCT6100_FREE_RESOURCES; typedef struct _OCT6100_PRODUCTION_BIST_ { UINT32 ulCurrentAddress; UINT32 ulCurrentLoop; UINT32 ulCurrentTest; UINT32 ulBistStatus; UINT32 ulFailedAddress; UINT32 ulReadValue; UINT32 ulExpectedValue; } tOCT6100_PRODUCTION_BIST, *tPOCT6100_PRODUCTION_BIST; typedef struct _OCT6100_API_GET_VERSION_ { UINT8 achApiVersion[ cOCT6100_API_VERSION_STRING_LENGTH ]; } tOCT6100_API_GET_VERSION, *tPOCT6100_API_GET_VERSION; typedef struct _OCT6100_API_GET_CAPACITY_PINS_ { UINT32 ulUserChipId; PVOID pProcessContext; UINT32 ulMemoryType; /* SDRAM or DDR type external memory. */ BOOL fEnableMemClkOut; UINT32 ulMemClkFreq; UINT32 ulCapacityValue; } tOCT6100_API_GET_CAPACITY_PINS, *tPOCT6100_API_GET_CAPACITY_PINS; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ChipOpenDef( OUT tPOCT6100_CHIP_OPEN f_pChipOpen ); UINT32 Oct6100ChipOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHIP_OPEN f_pChipOpen ); UINT32 Oct6100ChipCloseDef( OUT tPOCT6100_CHIP_CLOSE f_pChipClose ); UINT32 Oct6100ChipClose( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHIP_CLOSE f_pChipClose ); UINT32 Oct6100GetInstanceSizeDef( OUT tPOCT6100_GET_INSTANCE_SIZE f_pInstanceSize ); UINT32 Oct6100GetInstanceSize( IN OUT tPOCT6100_CHIP_OPEN f_pChipOpen, IN OUT tPOCT6100_GET_INSTANCE_SIZE f_pInstanceSize ); UINT32 Oct6100CreateLocalInstanceDef( OUT tPOCT6100_CREATE_LOCAL_INSTANCE f_pCreateLocal ); UINT32 Oct6100CreateLocalInstance( IN OUT tPOCT6100_CREATE_LOCAL_INSTANCE f_pCreateLocal ); UINT32 Oct6100DestroyLocalInstanceDef( OUT tPOCT6100_DESTROY_LOCAL_INSTANCE f_pDestroyLocal ); UINT32 Oct6100DestroyLocalInstance( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_DESTROY_LOCAL_INSTANCE f_pDestroyLocal ); UINT32 Oct6100ApiGetVersionDef( OUT tPOCT6100_API_GET_VERSION f_pApiGetVersion ); UINT32 Oct6100ApiGetVersion( IN OUT tPOCT6100_API_GET_VERSION f_pApiGetVersion ); UINT32 Oct6100GetHwRevisionDef( OUT tPOCT6100_GET_HW_REVISION f_pRevision ); UINT32 Oct6100GetHwRevision( IN OUT tPOCT6100_GET_HW_REVISION f_pRevision ); UINT32 Oct6100FreeResourcesDef( OUT tPOCT6100_FREE_RESOURCES f_pFreeResources ); UINT32 Oct6100FreeResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_FREE_RESOURCES f_pFreeResources ); UINT32 Oct6100ProductionBistDef( OUT tPOCT6100_PRODUCTION_BIST f_pProductionBist ); UINT32 Oct6100ProductionBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PRODUCTION_BIST f_pProductionBist ); UINT32 Oct6100ApiGetCapacityPinsDef( tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins); UINT32 Oct6100ApiGetCapacityPins( tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ); #endif /* __OCT6100_CHIP_OPEN_PUB_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_errors.h0000644000175000017500000016600511431317470026027 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_errors.h Copyright (c) 2001-2007 Octasic Inc. Description: Header file containing all defines used for error codes. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 205 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_ERRORS_H__ #define __OCT6100_ERRORS_H__ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" /***************************** DEFINES *************************************/ #define cOCT6100_ERR_OK 0x00000000 #define cOCT6100_ERR_BASE 0x00100000 #define cOCT6100_NOT_SUPPORTED_BASE (0xFF000 + cOCT6100_ERR_BASE) /* Not supported defines. */ #define cOCT6100_ERR_NOT_SUPPORTED_OPEN_DEBUG_RECORD (0x00000 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NLP_CONTROL (0x00001 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_BKG_NOISE_FREEZE (0x00002 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIN_DC_OFFSET_REM (0x00003 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_DC_OFFSET_REM (0x00004 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_AUTO_LC (0x00005 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SOUT_AUTO_LC (0x00006 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR (0x00007 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TAIL_DISPLACEMENT (0x00008 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ENCODING (0x00009 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DECODING (0x0000A + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_LAW_TRANSLATION (0x0000B + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ACOUSTIC_ECHO (0x0000C + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DEFAULT_ERL (0x0000D + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DOUBLE_TALK (0x0000E + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NON_LINEARITY_B (0x0000F + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_AEC_DEFAULT_ERL (0x00010 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_HIGH_LEVEL_COMP (0x00011 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_PER_CHAN_TAIL (0x00012 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIL_SUP (0x00013 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_OPEN_ACOUSTIC_ECHO (0x00014 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_OPEN_TAIL_DISPLACEMENT_VALUE (0x00015 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_OPEN_MAX_ECHO_CHANNELS_VALUE (0x00016 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ALE (0x00017 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NLE (0x00018 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ROUT_NR (0x00019 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIN_MUTE_FEATURES (0x0001A + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR_SNR_ENHANCEMENT (0x0001B + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR_SEGREGATION (0x0001C + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_OPEN_USE_SYNCH_TIMESTAMP (0x0001D + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TAIL_LENGTH (0x0001E + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TONE_DISABLER_ACTIVATION_DELAY (0x0001F + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ACOUSTIC_ECHO_TAIL_LENGTH (0x00020 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_MUSIC_PROTECTION (0x00021 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_DEBUG_DATA_MODE_120S (0x00022 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_TONE_NOT_PRESENT_IN_FIRMWARE (0x00023 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_DOUBLE_TALK_BEHAVIOR_MODE (0x00024 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_IDLE_CODE_DETECTION (0x00025 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_IDLE_CODE_DETECTION_CONFIG (0x00026 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ROUT_NOISE_REDUCTION_GAIN (0x0002B + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_BUFFER_PLAYOUT (0x00100 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_CNR (0x00101 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CONF_BRIDGE (0x00102 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CALLER_ID (0x00104 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NOISE_BLEACHING (0x00105 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TONE_REMOVAL (0x00300 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_NOT_SUPPORTED_DOMINANT_SPEAKER (0x00301 + cOCT6100_NOT_SUPPORTED_BASE) #define cOCT6100_ERR_OPEN_INVALID_DEVICE (0x03000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INSUFFICIENT_EXTERNAL_MEMORY (0x03001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MEMORY_CHIP_SIZE (0x03002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_UP_CLK_FREQ (0x03003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_USER_CHIP_ID (0x03004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MULTI_PROCESS_SYSTEM (0x03005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_RW_ACCESSES (0x03006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_IMAGE_SIZE (0x03007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_IMAGE_FILE (0x03008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MEM_CLK_FREQ (0x03009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MEMORY_CHIPS_NUMBER (0x0300A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TOTAL_MEMORY_SIZE (0x0300B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_USE_SYNCH_TIMESTAMP (0x0300C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TIMESTAMP_STREAM (0x0300D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TIMESTAMP_TIMESLOT (0x0300E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TIMESTAMP_TSSTS (0x0300F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TDM_STREAM_FREQS (0x03010 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TDM_SAMPLING (0x03011 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_FAST_H100_MODE (0x03012 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_ECHO_CHANNELS (0x03013 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_PLAYOUT_BUFFERS (0x03014 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_TSI_CNCTS (0x03015 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_PHASING_TSSTS (0x03016 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_EXTERNAL_MEM_BIST_FAILED (0x03017 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_EXTERNAL_MEM_BIST_TIMEOUT (0x03018 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_SDRAM_BIST_FAILED (0x03019 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_CORRUPTED_IMAGE (0x0301A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR (0x0301B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_SOFT_TONE_EVENT_SIZE (0x0301C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INTERRUPT_POLARITY (0x0301D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_FATAL_GENERAL_CONFIG (0x0301E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_REMOTE_DEBUG_SESSIONS (0x0301F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_MEM_CLK_OUT (0x03020 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_TDM_STREAM (0x03021 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_CONF_BRIDGES (0x03022 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_AF_CPU_TIMEOUT (0x03024 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MEMORY_TYPE (0x03025 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_FATAL_MEMORY_CONFIG (0x03026 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_MEMORY_CONFIG (0x03027 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_OVERFLOW_TONE_EVENTS_CONFIG (0x03028 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_H100_CONFIG (0x03029 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_FATAL_MEMORY_TIMEOUT (0x0302A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_MEMORY_TIMEOUT (0x0302B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_OVERFLOW_TONE_EVENTS_TIMEOUT (0x0302C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ERROR_H100_TIMEOUT (0x0302D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_IMAGE_WRITE_FAILED (0x0302E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_CRC_ERROR (0x0302F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_EGO_TIMEOUT (0x03030 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_SOFT_DEBUG_EVENT_BUF_SIZE (0x03031 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TONE_INFO_START_TAG_NOT_FOUND (0x03032 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TONE_INFO_STOP_TAG_NOT_FOUND (0x03033 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INVALID_TONE_EVENT (0x03034 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INVALID_TONE_NAME (0x03035 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INVALID_EVENT_NUMBER_SIZE (0x03036 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INTERNAL_MEMORY_BIST (0x03037 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_TAIL_DISPLACEMENT (0x03038 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_DEBUG_CHANNEL_RECORDING (0x03039 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_BIDIR_CHANNELS (0x0303A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_FUNCTIONAL_BIST_FAILED (0x0303C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_ADPCM_CHANNELS (0x0303E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_EXT_TONE_DETECTION (0x03040 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_SOFT_PLAYOUT_STOP_EVENT_SIZE (0x03041 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INVALID_FIRMWARE_OR_CAPACITY_PINS (0x03042 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_ACOUSTIC_ECHO (0x03043 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_USER_WRITE_BURST_FAILED (0x03045 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_USER_WRITE_SMEAR_FAILED (0x03046 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_USER_READ_BURST_FAILED (0x03047 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_MAX_FLEXIBLE_CONF_PARTICIPANTS (0x03048 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_DEBUG_MEM_INDEX (0x03051 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_CALLER_ID (0x03052 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_CALLER_ID_PLAYOUT_BUFFERS (0x03053 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_PRODUCTION_BIST (0x03055 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_PRODUCTION_BIST_ACTIVATED (0x03056 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_NUM_PRODUCTION_BIST_LOOPS (0x03057 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_PRODUCTION_BOOT_FAILED (0x03058 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_PRODUCTION_BIST_CONF_FAILED (0x03059 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_PRODUCTION_BIST_POUCH_ERROR (0x0305A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_INVALID_TLV_LENGTH (0x0305B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_PRODUCTION_BIST_MODE (0x0305C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_OPEN_ENABLE_2100_STOP_EVENT (0x03060 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CAP_PINS_INVALID_CHIP_STATE (0x03081 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CAP_PINS_INVALID_CAPACITY_VALUE (0x03082 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_ALL_CHANNELS_ARE_OPENED (0x04000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_DISABLED (0x04001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_INVALID_HANDLE (0x04002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_INPUT_TIMESLOT (0x04003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_INPUT_STREAM (0x04004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_OUTPUT_TIMESLOT (0x04005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_OUTPUT_STREAM (0x04006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_INPUT_PCM_LAW (0x04007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_TIMESLOT (0x04008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_STREAM (0x04009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_TSST_RESERVED (0x0400A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_NOT_OPEN (0x0400B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_ASSOCIATED_TSST_RESERVED (0x0400C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSI_CNCT_NO_MORE_TSI_AVAILABLE (0x0400D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED (0x05000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_PATTERN (0x05001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_TOO_SMALL (0x05002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_PCM_LAW (0x05003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ALL_BUFFERS_OPEN (0x05004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE (0x05005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX (0x05006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN (0x05007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ACTIVE_DEPENDENCIES (0x05008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID (0x05009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN (0x0500A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ROUT_PORT_PLAYING (0x0500B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_SOUT_PORT_PLAYING (0x0500C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_PORT_INVALID (0x0500D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT (0x0500E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL (0x0500F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT (0x05010 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ADD_MIXING (0x05011 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_STOP_CLEANLY (0x05012 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED (0x05013 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_WRITE_BYTE_COUNT (0x05015 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ECHO_OP_MODE (0x05016 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_LENGTH_INVALID (0x05017 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_OFFSET_INVALID (0x05018 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_RESET (0x05019 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_BUF_EMPTY (0x0501A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_MAX_EVENT (0x0501B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_DISABLED (0x0501C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_NOTIFY_ON_STOP (0x0501D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ALLOW_ACTIVE (0x0501E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_STILL_ACTIVE (0x0501F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_REPEAT_USED (0x05020 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_NLP_DISABLED (0x05021 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_MALLOC_ZERO (0x05022 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_NO_MEMORY (0x05023 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_MALLOC_POINT_NOT_FOUND (0x05024 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT_COUNT (0x05025 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_ADD_GAIN_DB (0x05026 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_BUFFER_PLAYOUT_LIST_EMPTY (0x05027 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MEMORY_ALL_TSI_MEM_ENTRY_RESERVED (0x06000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MEMORY_ALL_ECHO_MEM_ENTRY_RESERVED (0x06002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MEMORY_EXTERNAL_MEMORY_FULL (0x06003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MEMORY_ALL_CONVERSION_MEM_ENTRY_RESERVED (0x06004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DISABLED (0x07000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_INVALID_HANDLE (0x07001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_NUM_TSSTS (0x07002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_NUM_TSSTS (0x07003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_NUM_TSSTS (0x07004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_NUM_TSSTS (0x07005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_TIMESLOT (0x07006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_STREAM (0x07007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_TIMESLOT (0x07008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_STREAM (0x07009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_TIMESLOT (0x0700A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_STREAM (0x0700B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT (0x0700C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_STREAM (0x0700D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MISSING_TSST (0x07012 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIL_SUP_ENABLE (0x07013 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PHASING_TYPE (0x07014 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_INVALID_PHASING_HANDLE (0x07015 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PHASING_TSST_NOT_OPEN (0x07016 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PHASING_INVALID_PHASE (0x07017 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DEBUG (0x07018 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ECHO_OP_MODE (0x0701F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_DC_OFFSET_REM (0x07020 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_DC_OFFSET_REM (0x07021 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_LEVEL_CONTROL (0x07022 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_LEVEL_CONTROL (0x07023 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_LEVEL_CONTROL_GAIN (0x07024 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_LEVEL_CONTROL_GAIN (0x07025 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_ADAPT_NOISE_REDUCTION (0x07026 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ALL_CHANNELS_ARE_OPENED (0x07027 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NOT_OPEN (0x07029 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ADPCM_NIBBLE (0x0702A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_ADD_PORT (0x0702B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_ADD_TIMESLOT (0x0702C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_ADD_STREAM (0x0702D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_INVALID (0x0702E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_PCM_LAW (0x0702F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_PCM_LAW (0x07030 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_PCM_LAW (0x07031 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_PCM_LAW (0x07032 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DECODER_PORT (0x07033 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENCODER_PORT (0x07034 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DECODING_RATE (0x07035 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENCODING_RATE (0x07036 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENABLE_NLP (0x07037 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_COMFORT_NOISE_MODE (0x07038 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PHASING_TSST_REQUIRED (0x07039 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIL_SUP_INVALID_ENCODER_PORT (0x0703A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MODIFY_CODEC_CONFIG (0x0703B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MODIFY_VQE_CONFIG (0x0703C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MODIFY_TDM_CONFIG (0x0703D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_RIN_PORT_INVALID (0x0703E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_SIN_PORT_INVALID (0x0703F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_REMOVE_PORT (0x07041 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_REMOVE_TIMESLOT (0x07042 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_REMOVE_STREAM (0x07043 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_REMOVE_INVALID_TSST (0x07044 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_GET_STATS_MAX_BROADCAST_TSST (0x07045 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_BROADCAST_TIMESLOT (0x07046 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_BROADCAST_STREAM (0x07047 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_BROADCAST_TIMESLOT (0x07048 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_BROADCAST_STREAM (0x07049 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ACTIVE_DEPENDENCIES (0x0704A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TONE_DISABLER_ENABLE (0x0704B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TAIL_LENGTH (0x07053 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TAIL_DISPLACEMENT (0x07054 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_INVALID_RIN_CB_SIZE (0x07058 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TSST_REMOVE_NO_BROADCAST_TSST (0x07059 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_INVALID_CODEC_POSITION (0x0705A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_STATS_RESET (0x0705B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENABLE_TAIL_DISPLACEMENT (0x0705C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_CHANNEL_HANDLE (0x0705E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_FIRST_CHANNEL_HANDLE (0x0705F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_SECOND_CHANNEL_HANDLE (0x07060 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_CODEC_ACTIVATED (0x07061 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ALREADY_BIDIR (0x07062 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ALL_BIDIR_CHANNELS_ARE_OPENED (0x07063 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_FIRST_CHAN_SOUT_PORT (0x07064 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_FIRST_CHAN_RIN_PORT (0x07065 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SECOND_CHAN_SOUT_PORT (0x07066 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SECOND_CHAN_RIN_PORT (0x07067 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_PCM_LAW (0x07068 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_CHAN_NOT_OPEN (0x07069 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_ROUT_LAW_CONVERSION (0x0706A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_SOUT_LAW_CONVERSION (0x0706B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PART_OF_BIDIR_CHANNEL (0x0706C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NO_VALID_TDM_CLOCKS (0x0706E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_OUT_OF_TSI_MEMORY (0x07073 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TONE_REMOVAL (0x07075 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO (0x07077 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DEFAULT_ERL (0x07079 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DOUBLE_TALK (0x0707B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PHASE_TYPE_REQUIRED (0x0707C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIL_SUP_NLP_MUST_BE_ENABLED (0x0707D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENABLE_EXT_TONE_DETECTION (0x0707E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_EXT_TONE_DETECTION_DECODER_PORT (0x0707F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_EXT_TONE_DETECTION_DISABLED (0x07080 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NON_LINEARITY_B (0x07082 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_FIRST_CHAN_IN_CONFERENCE (0x07083 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SECOND_CHAN_IN_CONFERENCE (0x07084 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TAIL_DISPLACEMENT_CANNOT_MODIFY (0x07085 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NON_LINEARITY_B_CANNOT_MODIFY (0x07086 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO_NOT_ENABLED (0x07087 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_BIDIR_DISABLED (0x0708B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TAIL_DISPLACEMENT_INVALID (0x0708D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_PER_CHAN_TAIL_DISPLACEMENT (0x0708E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_CONFERENCE_NOISE_REDUCTION (0x0708F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_AEC_DEFAULT_ERL (0x07092 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_NLP_REQUIRED (0x07093 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_CONTROL (0x07094 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_CONTROL (0x07095 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_CONTROL_TARGET (0x07096 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_CONTROL_TARGET (0x07097 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_MANUAL (0x07098 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_MANUAL (0x07099 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP (0x0709A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_HIGH_LEVEL_COMP (0x0709C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP_MANUAL (0x0709D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP_THRESHOLD (0x0709E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MUTE_MASK (0x0709F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MUTE_MASK_SIN (0x070A0 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ALE_RATIO (0x070A1 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NLE_FLAG (0x070A2 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ALE_NLE_SIMULTANEOUSLY (0x070A3 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_NOISE_REDUCTION (0x070A4 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ANR_SNR_ENHANCEMENT (0x070A5 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ANR_SEGREGATION (0x070A6 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_NLE_RATIO (0x070A7 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_APPLY_TO_ALL_CHANNELS (0x070A8 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_STREAM_UNASSIGN (0x070A9 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_TIMESLOT_UNASSIGN (0x070AA + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_STREAM_UNASSIGN (0x070AB + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_TIMESLOT_UNASSIGN (0x070AC + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_STREAM_UNASSIGN (0x070AD + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT_UNASSIGN (0x070AE + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_STREAM_UNASSIGN (0x070AF + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SIN_TIMESLOT_UNASSIGN (0x070B0 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DISABLE_TONE_DETECTION (0x070B1 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_STOP_BUFFER_PLAYOUT (0x070B2 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_REMOVE_CONF_BRIDGE_PARTICIPANT (0x070B3 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_REMOVE_BROADCAST_TSSTS (0x070B4 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TONE_DISABLER_ACTIVATION_DELAY (0x070B5 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_OUT_OF_MIXER_EVENTS (0x070B8 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO_TAIL_LENGTH (0x070B9 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ENABLE_MUSIC_PROTECTION (0x070BA + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_TAIL_LENGTH_INVALID (0x070BB + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO_TAIL_SUM (0x070BC + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_DOUBLE_TALK_MODE (0x070BD + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_NOISE_BLEACHING (0x070BE + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_NOISE_BLEACHING_NR (0x070BF + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ANR_CNR_SIMULTANEOUSLY (0x070C0 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_IDLE_CODE_DETECTION (0x070C1 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_MUST_ENABLE_TONE_DISABLER (0x070C2 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_CONTROL_REQUIRED (0x070C5 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_CONTROL_REQUIRED (0x070C6 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_AUTO_LEVEL_CONTROL_REQUIRED (0x070C8 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_COMFORT_NOISE_REQUIRED (0x070CB + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHANNEL_ROUT_NOISE_REDUCTION_GAIN (0x070CC + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_ALL_ENTRIES_ARE_OPENED (0x08000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_DISABLED (0x08001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_INVALID_HANDLE (0x08002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_TIMESLOT (0x08003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_STREAM (0x08004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_PHASING_LENGTH (0x08005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_NOT_OPEN (0x08006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PHASING_TSST_ACTIVE_DEPENDENCIES (0x08007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE (0x09000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_DISABLED (0x09001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN (0x09002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_ACTIVE_DEPENDENCIES (0x09003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE (0x09004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND (0x09005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_ALL_BUFFERS_OPEN (0x09006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_REMOVE_INVALID_HANDLE (0x09007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE (0x09008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_MUTE (0x09009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE (0x0900A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_ALREADY_MUTED (0x0900B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_NOT_MUTED (0x0900C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_CODEC_ACTIVE (0x0900D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_MIXER_FULL (0x0900E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ALREADY_ON_BRIDGE (0x0900F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_REMOVE_ALL (0x09010 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_EXT_TONE_ENABLED (0x09011 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_INVALID_INPUT_PORT (0x09012 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_DOMINANT_SPEAKER (0x09013 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_BIDIR (0x09015 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CNR_MUST_BE_ENABLED (0x09016 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_NLP_MUST_BE_ENABLED (0x09017 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF (0x09018 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_PARTICIPANT_CNT (0x09019 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_MASK_INDEX (0x0901A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_ALL_BUFFERS_OPEN (0x0901B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_DISABLED (0x0901C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_INDEX_USED (0x0901D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_SIMPLE_BRIDGE (0x0901E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_COPY_EVENTS (0x0901F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE (0x09020 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_TAP_NOT_SUPPORTED (0x09021 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_BRIDGE (0x09022 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_DEPENDENCY (0x09023 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_SAME_BRIDGE (0x09024 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_TAP_SOUT_ONLY (0x09025 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_ALREADY_TAPPED (0x09026 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_ALWAYS_MUTE (0x09027 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CONF_BRIDGE_CHANNEL_LAW_CONVERSION (0x09028 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MISC_CANNOT_ROUND_UP_NUMBER (0x0A000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MISC_ASCII_CONVERSION_FAILED (0x0A001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID (0x0B000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_CHANNEL_NOT_OPEN (0x0B001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_TONE_NUMBER_INVALID (0x0B002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_TONE_NOT_ACTIVATED (0x0B003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_TONE_ACTIVATED (0x0B004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_TONE_NOT_AVAILABLE (0x0B005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TONE_DETECTION_DISABLE_ALL (0x0B006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_EVENTS_GET_TONE_RESET_BUFS (0x0C000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_EVENTS_TONE_BUF_EMPTY (0x0C001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_EVENTS_MAX_TONES (0x0C002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_RW_ERROR (0x0D000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_NOT_ACTIVE (0x0D001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_FATAL_GENERAL_CONFIG (0x0D002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_FATAL_MEMORY_CONFIG (0x0D003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_DATA_ERR_MEMORY_CONFIG (0x0D004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_OVERFLOW_TONE_EVENTS_CONFIG (0x0D005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_H100_ERROR_CONFIG (0x0D006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_FATAL_GENERAL_TIMEOUT (0x0D007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_FATAL_MEMORY_TIMEOUT (0x0D008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_DATA_ERR_MEMORY_TIMEOUT (0x0D009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_OVERFLOW_TONE_EVENTS_TIMEOUT (0x0D00A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_H100_ERROR_TIMEOUT (0x0D00B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_AF_TIMESTAMP_READ_TIMEOUT (0x0D00C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_INTRPTS_NLP_TIMESTAMP_READ_TIMEOUT (0x0D00D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSST_TIMESLOT (0x0E000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSST_STREAM (0x0E001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSST_TSST_RESERVED (0x0E002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSST_ASSOCIATED_TSST_RESERVED (0x0E003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TSST_ALL_TSSTS_ARE_OPENED (0x0E004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MULTIPROC_API_INST_SHARED (0x10000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MULTIPROC_API_INST_LOCAL (0x10001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_CHANNEL_INVALID_HANDLE (0x11000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_PORT (0x11001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_READ_LENGTH (0x11002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_SOUT_READ_LENGTH (0x11003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_READ_DATA (0x11004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_EVENTS_RESET_BUFS (0x11005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_EVENTS_BUF_EMPTY (0x11006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_RIN_PTR_INVALID (0x11007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_SIN_PTR_INVALID (0x11008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_ROUT_PTR_INVALID (0x11009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_SOUT_PTR_INVALID (0x1100A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_RAW_DATA_PTR_INVALID (0x1100B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_LENGTH_INVALID (0x1100C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RECORD_NO_CHAN_SELECTED (0x1100D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_PCM_LAW (0x1100E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_CHANNEL_RECORDING_DISABLED (0x1100F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_DATA_MAX_BYTES (0x11010 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_DATA_PTR_INVALID (0x11011 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_RC_CHANNEL_RECORDING_DISABLED (0x11012 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_DATA_MODE (0x11013 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_CHANNEL_IN_POWER_DOWN (0x11014 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_DATA_CONTENT (0x11015 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_DEBUG_GET_DATA_MODE_CANNOT_CHANGE (0x11016 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_ALL_COPY_EVENT_ENTRY_OPENED (0x12000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_COPY_EVENT_HANDLE (0x12001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_SOURCE_CHAN_HANDLE (0x12002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_DESTINATION_CHAN_HANDLE (0x12003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_SOURCE_PORT (0x12004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_DESTINATION_PORT (0x12005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_EVENT_NOT_OPEN (0x12006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_SOURCE_ADPCM_RESOURCES_ACTIVATED (0x12007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_DEST_ADPCM_RESOURCES_ACTIVATED (0x12008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_MIXER_ALL_MIXER_EVENT_ENTRY_OPENED (0x12009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_DISABLED (0x13000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INVALID_HANDLE (0x13001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INPUT_TIMESLOT (0x13002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INPUT_STREAM (0x13003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_OUTPUT_TIMESLOT (0x13004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_OUTPUT_STREAM (0x13005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INPUT_NUM_TSSTS (0x13006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_OUTPUT_NUM_TSSTS (0x13007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INPUT_PCM_LAW (0x13008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_MODE (0x13009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_ENCODING_RATE (0x1300A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_DECODING_RATE (0x1300B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_INCOMPATIBLE_NUM_TSSTS (0x1300C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_NO_MORE_TSI_AVAILABLE (0x1300D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_OUTPUT_PCM_LAW (0x1300E + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_ADPCM_NIBBLE_POSITION (0x1300F + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_NOT_OPEN (0x13010 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_ADPCM_CHAN_ALL_ADPCM_CHAN_ARE_OPENED (0x13011 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_CHIP_STATS_RESET (0x14000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_PRODUCTION_BIST_DISABLED (0x16000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_PAYLOAD (0x2C000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_RESPONSE_PKT_PAYLOAD (0x2C001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_LENGTH (0x2C002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_RESPONSE_PKT_LENGTH (0x2C003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_ENDIAN_DETECTION_FIELD (0x2C004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_CHECKSUM (0x2C005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTE_DEBUG_PARSING_ERROR (0x2C006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_ALL_SESSIONS_OPEN (0x2C007 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_INVALID_PACKET (0x2C008 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_TRANSACTION_ANSWERED (0x2C009 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_INAVLID_SESSION_NUMBER (0x2C00A + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_INVALID_HOT_CHAN_INDEX (0x2C00B + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_DISABLED (0x2C00C + cOCT6100_ERR_BASE) #define cOCT6100_ERR_REMOTEDEBUG_INVALID_RPC_COMMAND_NUM (0x2C00D + cOCT6100_ERR_BASE) #define cOCT6100_ERR_TLV_TIMEOUT (0x31000 + cOCT6100_ERR_BASE) /* Fatal errors must always be greater or equal to 0xE000. */ #define cOCT6100_ERR_FATAL (0xDE000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_WRITE_API (0xDE000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_WRITE_EXT_API (0xDE001 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_WRITE_SMEAR_API (0xDE002 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_WRITE_BURST_API (0xDE003 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_READ_API (0xDE004 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_READ_BURST_API (0xDE005 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_READ_DEBUG_API (0xDE006 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_DRIVER_WRITE_ARRAY_API (0xDE007 + cOCT6100_ERR_BASE) #define cOCT6100_FATAL_BASE (0xDF000 + cOCT6100_ERR_BASE) #define cOCT6100_ERR_FATAL_0 (0x00000 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1 (0x00001 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2 (0x00002 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3 (0x00003 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4 (0x00004 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5 (0x00005 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6 (0x00006 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7 (0x00007 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8 (0x00008 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9 (0x00009 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A (0x0000A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B (0x0000B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C (0x0000C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D (0x0000D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E (0x0000E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_F (0x0000F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_10 (0x00010 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_11 (0x00011 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_12 (0x00012 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_13 (0x00013 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_14 (0x00014 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_15 (0x00015 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_16 (0x00016 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_17 (0x00017 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_18 (0x00018 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_19 (0x00019 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1A (0x0001A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1B (0x0001B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1C (0x0001C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1D (0x0001D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1E (0x0001E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_1F (0x0001F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_20 (0x00020 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_21 (0x00021 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_22 (0x00022 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_23 (0x00023 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_24 (0x00024 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_25 (0x00025 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_26 (0x00026 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_27 (0x00027 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_28 (0x00028 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_29 (0x00029 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2A (0x0002A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2B (0x0002B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2C (0x0002C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2D (0x0002D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2E (0x0002E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_2F (0x0002F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_30 (0x00030 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_31 (0x00031 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_32 (0x00032 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_33 (0x00033 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_34 (0x00034 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_35 (0x00035 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_36 (0x00036 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_37 (0x00037 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_38 (0x00038 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_39 (0x00039 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3A (0x0003A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3B (0x0003B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3C (0x0003C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3D (0x0003D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3E (0x0003E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_3F (0x0003F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_40 (0x00040 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_41 (0x00041 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_42 (0x00042 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_43 (0x00043 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_44 (0x00044 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_45 (0x00045 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_46 (0x00046 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_47 (0x00047 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_48 (0x00048 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_49 (0x00049 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4A (0x0004A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4B (0x0004B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4C (0x0004C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4D (0x0004D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4E (0x0004E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_4F (0x0004F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_50 (0x00050 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_51 (0x00051 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_52 (0x00052 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_53 (0x00053 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_54 (0x00054 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_55 (0x00055 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_56 (0x00056 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_57 (0x00057 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_58 (0x00058 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_59 (0x00059 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5A (0x0005A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5B (0x0005B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5C (0x0005C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5D (0x0005D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5E (0x0005E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_5F (0x0005F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_60 (0x00060 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_61 (0x00061 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_62 (0x00062 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_63 (0x00063 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_64 (0x00064 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_65 (0x00065 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_66 (0x00066 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_67 (0x00067 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_68 (0x00068 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_69 (0x00069 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6A (0x0006A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6B (0x0006B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6C (0x0006C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6D (0x0006D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6E (0x0006E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_6F (0x0006F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_70 (0x00070 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_71 (0x00071 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_72 (0x00072 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_73 (0x00073 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_74 (0x00074 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_75 (0x00075 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_76 (0x00076 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_77 (0x00077 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_78 (0x00078 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_79 (0x00079 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7A (0x0007A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7B (0x0007B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7C (0x0007C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7D (0x0007D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7E (0x0007E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_7F (0x0007F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_80 (0x00080 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_81 (0x00081 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_82 (0x00082 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_83 (0x00083 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_84 (0x00084 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_85 (0x00085 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_86 (0x00086 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_87 (0x00087 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_88 (0x00088 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_89 (0x00089 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8A (0x0008A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8B (0x0008B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8C (0x0008C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8D (0x0008D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8E (0x0008E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_8F (0x0008F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_90 (0x00090 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_91 (0x00091 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_92 (0x00092 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_93 (0x00093 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_94 (0x00094 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_95 (0x00095 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_96 (0x00096 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_97 (0x00097 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_98 (0x00098 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_99 (0x00099 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9A (0x0009A + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9B (0x0009B + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9C (0x0009C + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9D (0x0009D + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9E (0x0009E + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_9F (0x0009F + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A0 (0x000A0 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A1 (0x000A1 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A2 (0x000A2 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A3 (0x000A3 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A4 (0x000A4 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A5 (0x000A5 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A6 (0x000A6 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A7 (0x000A7 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A8 (0x000A8 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_A9 (0x000A9 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AA (0x000AA + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AB (0x000AB + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AC (0x000AC + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AD (0x000AD + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AE (0x000AE + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_AF (0x000AF + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B0 (0x000B0 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B1 (0x000B1 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B2 (0x000B2 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B3 (0x000B3 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B4 (0x000B4 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B5 (0x000B5 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B6 (0x000B6 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B7 (0x000B7 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B8 (0x000B8 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_B9 (0x000B9 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BA (0x000BA + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BB (0x000BB + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BC (0x000BC + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BD (0x000BD + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BE (0x000BE + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_BF (0x000BF + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C0 (0x000C0 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C1 (0x000C1 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C2 (0x000C2 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C3 (0x000C3 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C4 (0x000C4 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C5 (0x000C5 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C6 (0x000C6 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C7 (0x000C7 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C8 (0x000C8 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_C9 (0x000C9 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CA (0x000CA + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CB (0x000CB + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CC (0x000CC + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CD (0x000CD + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CE (0x000CE + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_CF (0x000CF + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D0 (0x000D0 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D1 (0x000D1 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D2 (0x000D2 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D3 (0x000D3 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D4 (0x000D4 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D5 (0x000D5 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D6 (0x000D6 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D7 (0x000D7 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D8 (0x000D8 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_D9 (0x000D9 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DA (0x000DA + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DB (0x000DB + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DC (0x000DC + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DD (0x000DD + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DE (0x000DE + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_DF (0x000DF + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E0 (0x000E0 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E1 (0x000E1 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E2 (0x000E2 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E3 (0x000E3 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E4 (0x000E4 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E5 (0x000E5 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E6 (0x000E6 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E7 (0x000E7 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E8 (0x000E8 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_E9 (0x000E9 + cOCT6100_FATAL_BASE) #define cOCT6100_ERR_FATAL_EA (0x000EA + cOCT6100_FATAL_BASE) #endif /* __OCT6100_ERRORS_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_api_inst.h0000644000175000017500000000763311431317470026322 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_api_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing the definition of the API instance structure. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 40 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_API_INST_H__ #define __OCT6100_API_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_SHARED_INFO_ { /* Local copy of chip configuration structure. */ tOCT6100_API_CHIP_CONFIG ChipConfig; /* Miscellaneous calculations and mapping of static structures in external memory. */ tOCT6100_API_MISCELLANEOUS MiscVars; tOCT6100_API_MEMORY_MAP MemoryMap; /* Error stats structure. */ tOCT6100_API_CHIP_ERROR_STATS ErrorStats; tOCT6100_API_CHIP_STATS ChipStats; /* Mixer information. */ tOCT6100_API_MIXER MixerInfo; /* Image breakdown information. */ tOCT6100_API_IMAGE_REGION ImageRegion[ cOCT6100_MAX_IMAGE_REGION ]; tOCT6100_API_IMAGE_INFO ImageInfo; /* Configuration and management of interrupts. */ tOCT6100_API_INTRPT_CONFIG IntrptConfig; tOCT6100_API_INTRPT_MANAGE IntrptManage; /* Remote debugging. */ tOCT6100_API_REMOTE_DEBUG_INFO RemoteDebugInfo; /* Chip debugging information. */ tOCT6100_API_DEBUG DebugInfo; /* Management variables of software and hardware buffers. */ tOCT6100_API_SOFT_BUFS SoftBufs; /* Caller buffer playout memory management structure. */ tOCT6100_API_BUFFER_PLAYOUT_MALLOC_INFO PlayoutInfo; UINT32 ulChannelListOfst; UINT32 ulChannelAllocOfst; UINT32 ulConversionMemoryAllocOfst; UINT32 ulTsiMemoryAllocOfst; UINT32 ulExtraTsiMemoryAllocOfst; UINT32 ulEchoMemoryAllocOfst; UINT32 ulTsstAllocOfst; UINT32 ulTsstListOfst; UINT32 ulTsstListAllocOfst; UINT32 ulTsiCnctListOfst; UINT32 ulTsiCnctAllocOfst; UINT32 ulMixerEventListOfst; UINT32 ulMixerEventAllocOfst; UINT32 ulCopyEventListOfst; UINT32 ulCopyEventAllocOfst; UINT32 ulBiDirChannelListOfst; UINT32 ulBiDirChannelAllocOfst; UINT32 ulConfBridgeListOfst; UINT32 ulConfBridgeAllocOfst; UINT32 ulFlexConfParticipantListOfst; UINT32 ulFlexConfParticipantAllocOfst; UINT32 ulPlayoutBufListOfst; UINT32 ulPlayoutBufAllocOfst; UINT32 ulPlayoutBufMemoryNodeListOfst; UINT32 ulAdpcmChanListOfst; UINT32 ulAdpcmChanAllocOfst; UINT32 ulPhasingTsstListOfst; UINT32 ulPhasingTsstAllocOfst; } tOCT6100_SHARED_INFO, *tPOCT6100_SHARED_INFO; typedef struct _OCT6100_INSTANCE_API_ { /* Pointer to portion of API instance structure shared amongst all processes. */ tPOCT6100_SHARED_INFO pSharedInfo; /* Pointer to user-supplied, process context structure. The structure is a parameter to all user-supplied functions. */ PVOID pProcessContext; /* Handles to all serialization objects used by the API. */ tOCT6100_USER_SERIAL_OBJECT ulApiSerObj; } tOCT6100_INSTANCE_API, *tPOCT6100_INSTANCE_API; #endif /* __OCT6100_API_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/oct6100api/oct6100_mixer_inst.h0000644000175000017500000000476711431317470026702 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_mixer_inst.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines, macros, and structures pertaining to the file oct6100_mixer.c. All elements defined in this file are for public usage of the API. All private elements are defined in the oct6100_mixer_priv.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 13 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_MIXER_INST_H__ #define __OCT6100_MIXER_INST_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_MIXER_EVENT_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Type of the event.*/ UINT16 usEventType; /* Source channel index */ UINT16 usSourceChanIndex; /* Destination channel index */ UINT16 usDestinationChanIndex; /* Pointer to the next entry.*/ UINT16 usNextEventPtr; } tOCT6100_API_MIXER_EVENT, *tPOCT6100_API_MIXER_EVENT; typedef struct _OCT6100_API_COPY_EVENT_ { /* Flag specifying whether the entry is used or not. */ UINT8 fReserved; /* Count used to manage entry handles allocated to user. */ UINT8 byEntryOpenCnt; /* Source + destination ports. */ UINT8 bySourcePort; UINT8 byDestinationPort; /* Index of the channels associated to this event.*/ UINT16 usSourceChanIndex; UINT16 usDestinationChanIndex; UINT16 usMixerEventIndex; } tOCT6100_API_COPY_EVENT, *tPOCT6100_API_COPY_EVENT; #endif /* __OCT6100_MIXER_INST_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/apilib/0000755000175000017500000000000011631523356022634 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/apilib/octapi_bt0.h0000644000175000017500000000660411431317470025033 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_bt0.h Copyright (c) 2001-2007 Octasic Inc. Description: Library used to manage a binary tree of variable max size. Library is made to use one block of contiguous memory to manage the tree. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 11 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTAPI_BT0_H__ #define __OCTAPI_BT0_H__ #include "octdef.h" #define OCTAPI_BT0_BASE 0xFFFF0000 #define OCTAPI_BT0_KEY_SIZE_NOT_MUTLIPLE_OF_UINT32 OCTAPI_BT0_BASE+0x0001 #define OCTAPI_BT0_DATA_SIZE_NOT_MUTLIPLE_OF_UINT32 OCTAPI_BT0_BASE+0x0002 #define OCTAPI_BT0_MALLOC_FAILED OCTAPI_BT0_BASE+0x0003 #define OCTAPI_BT0_NO_NODES_AVAILABLE OCTAPI_BT0_BASE+0x0004 #define OCTAPI_BT0_KEY_ALREADY_IN_TREE OCTAPI_BT0_BASE+0x0005 #define OCTAPI_BT0_KEY_NOT_IN_TREE OCTAPI_BT0_BASE+0x0006 /* Possible result for Find Or Add function. */ #define OCTAPI0_BT0_NODE_FOUND 0 #define OCTAPI0_BT0_NODE_ADDDED 1 #define OCTAPI_BT0_NO_SMALLER_KEY 0xAAAAAAAA #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define octapi_bt0_get_size( number_of_items, key_size, data_size, b_size ) OctApiBt0GetSize( (UINT32) number_of_items,(UINT32) key_size, (UINT32) data_size, (PUINT32) b_size ) #define octapi_bt0_init( b, number_of_items, key_size, data_size ) OctApiBt0Init( (void **) b,(UINT32) number_of_items,(UINT32) key_size, (UINT32) data_size ) #define octapi_bt0_add_node( b, key, data ) OctApiBt0AddNode( (void *) b,(void *) key,(void **) data ) #define octapi_bt0_remove_node( b, key ) OctApiBt0RemoveNode( (void *) b,(void *) key ) #define octapi_bt0_query_node( b, key, data ) OctApiBt0QueryNode( (void *) b,(void *) key,(void **) data ) #define octapi_bt0_get_first_node( b, key, data ) OctApiBt0GetFirstNode( (void *) b,(void **) key, (void **) data ) UINT32 OctApiBt0GetSize( UINT32 number_of_items, UINT32 key_size, UINT32 data_size, UINT32 * b_size ); UINT32 OctApiBt0Init( void ** b, UINT32 number_of_items, UINT32 key_size, UINT32 data_size ); UINT32 OctApiBt0AddNode( void * b, void * key, void ** data ); UINT32 OctApiBt0RemoveNode( void * b, void * key ); UINT32 OctApiBt0QueryNode( void * b, void * key, void ** data ); UINT32 OctApiBt0GetFirstNode( void * b, void ** key, void ** data ); UINT32 OctApiBt0FindOrAddNode( void * b, void * key, void ** data, UINT32 *fnct_result ); UINT32 OctApiBt0AddNodeReportPrevNodeData( void * b, void * key, void ** data, void ** prev_data, UINT32 *fnct_result ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /*__OCTAPI_BT0_H__*/ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/apilib/octapi_llman.h0000644000175000017500000002226411431317470025451 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_llman.h Copyright (c) 2001-2007 Octasic Inc. Description: Library used to manage allocation tables and linked lists. The library is made such that only a block of contiguous memory is needed for the management of the linked list/allocation table. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 8 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTAPI_LLMAN_H__ #define __OCTAPI_LLMAN_H__ #include "octdef.h" /* Error defines. */ #define OCTAPI_LLM_MEMORY_NOT_ALLOCATED 0xFFFFFFFF #define OCTAPI_LLM_NO_STRUCTURES_LEFT 0xFFFFFFFE #define OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE 0xFFFFFFFD #define OCTAPI_LLM_ELEMENT_ALREADY_ASSIGNED 0xFFFFFFFC #define OCTAPI_LLM_ELEMENT_NOT_FOUND 0xFFFFFFFB #define OCTAPI_LLM_LIST_EMPTY 0xFFFFFFFA #define OCTAPI_LLM_INVALID_LIST_HANDLE 0xFFFFFFF9 #define OCTAPI_LLM_TREE_NODE_ABSENT 0xFFFFFFF8 #define OCTAPI_LLM_INTERNAL_ERROR0 0xFFFFFFF7 #define OCTAPI_LLM_INTERNAL_ERROR1 0xFFFFFFF6 #define OCTAPI_LLM_INVALID_PARAMETER 0xFFFFFFF5 #define OCTAPI_LLM2_MEMORY_NOT_ALLOCATED 0xFEFFFFFF #define OCTAPI_LLM2_NO_STRUCTURES_LEFT 0xFEFFFFFE #define OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE 0xFEFFFFFD #define OCTAPI_LLM2_ELEMENT_ALREADY_ASSIGNED 0xFEFFFFFC #define OCTAPI_LLM2_ELEMENT_NOT_FOUND 0xFEFFFFFB #define OCTAPI_LLM2_LIST_EMPTY 0xFEFFFFFA #define OCTAPI_LLM2_INVALID_LIST_HANDLE 0xFEFFFFF9 #define OCTAPI_LLM2_TREE_NODE_ABSENT 0xFEFFFFF8 #define OCTAPI_LLM2_INTERNAL_ERROR0 0xFEFFFFF7 #define OCTAPI_LLM2_INTERNAL_ERROR1 0xFEFFFFF6 #define OCTAPI_LLM2_INVALID_PARAMETER 0xFEFFFFF5 /* Other defines. */ #define OCTAPI_LLM_LIST_APPEND 0xFFFFFFFF #define OCTAPI_LLM2_INSERT_ERROR 0xFFFFFFFF #define OCTAPI_LLM2_INSERT_FIRST_NODE 0xFFFF0000 #define OCTAPI_LLM2_INSERT_LIST_NODE 0xFFFF0001 #define OCTAPI_LLM2_INSERT_LAST_NODE 0xFFFF0002 #define OCTAPI_LLM2_INSERT_BEFORE_LAST_NODE 0xFFFF0003 #define OCTAPI_LLM2_REMOVE_ERROR 0xFFFFFFFF #define OCTAPI_LLM2_REMOVE_FIRST_NODE 0xFFFF0004 #define OCTAPI_LLM2_REMOVE_LIST_NODE 0xFFFF0005 #define OCTAPI_LLM2_REMOVE_LAST_NODE 0xFFFF0006 #define OCTAPI_LLM2_REMOVE_BEFORE_LAST_NODE 0xFFFF0007 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define octapi_llm_alloc_get_size( number_of_items, l_size ) OctapiLlmAllocGetSize( (UINT32) number_of_items,(PUINT32) l_size ) #define octapi_llm_alloc_init( l, number_of_items ) OctapiLlmAllocInit( (PVOID*) l,(UINT32) number_of_items ) #define octapi_llm_alloc_info( l, allocated_items, available_items ) OctapiLlmAllocInfo( (PVOID) l, (PUINT32) allocated_items, (PUINT32) available_items ) #define octapi_llm_alloc_alloc( l, blocknum ) OctapiLlmAllocAlloc( (PVOID) l, (PUINT32) blocknum ) #define octapi_llm_alloc_dealloc( l, blocknum ) OctapiLlmAllocDealloc( (PVOID) l,(UINT32) blocknum ) #define octapi_llm_list_get_size( number_of_items, number_of_lists, user_info_size, l_size ) OctApiLlmListGetSize( (UINT32) number_of_items,(UINT32) number_of_lists,(UINT32) user_info_size,(PUINT32) l_size ) #define octapi_llm_list_init( l, number_of_items, number_of_lists, user_info_size ) OctApiLlmListInit( (PVOID*) l,(UINT32) number_of_items,(UINT32) number_of_lists,(UINT32) user_info_size ) #define octapi_llm_list_info( l, allocated_lists, allocated_items, free_lists, free_items ) OctApiLlmListInfo( (PVOID) l,(PUINT32) allocated_lists,(PUINT32) allocated_items,(PUINT32) free_lists,(PUINT32) free_items ) #define octapi_llm_list_create( l, list_handle ) OctApiLlmListCreate( (PVOID) l,(PUINT32) list_handle ) #define octapi_llm_list_create_full( l, list_length, plist_handle ) OctApiLlmListCreateFull( (PVOID) l, (UINT32) list_length, (PUINT32) plist_handle ) #define octapi_llm_list_append_items( l, list_handle, num_items ) OctApiLlmListAppendItems( (PVOID) l, (UINT32) list_handle, (UINT32) num_items ) #define octapi_llm_list_append_and_set_items( l, list_handle, num_items, data_list ) OctApiLlmListAppendAndSetItems( (PVOID) l, (UINT32) list_handle, (UINT32) num_items, (PVOID) data_list ) #define octapi_llm_list_delete( l, list_handle ) OctApiLlmListDelete( (PVOID) l,(UINT32) list_handle ) #define octapi_llm_list_length( l, list_handle, number_of_items_in_list ) OctApiLlmListLength( (PVOID) l,(UINT32) list_handle, (PUINT32) number_of_items_in_list ) #define octapi_llm_list_insert_item( l, list_handle, item_number, item_data_pnt ) OctApiLlmListInsertItem( (PVOID) l,(UINT32) list_handle,(UINT32) item_number,(PVOID*) item_data_pnt ) #define octapi_llm_list_remove_item( l, list_handle, item_number ) OctApiLlmListRemoveItem( (PVOID) l,(UINT32) list_handle,(UINT32) item_number ) #define octapi_llm_list_item_data( l, list_handle, item_number, item_data_pnt ) OctApiLlmListItemData( (PVOID) l,(UINT32) list_handle,(UINT32) item_number,(PVOID*) item_data_pnt ) #define octapi_llm_list_copy_data( l, list_handle, start_item, data_length, pdata_list ) OctApiLlmListCopyData( (PVOID) l, (UINT32) list_handle, (UINT32) start_item, (UINT32) data_length, (PVOID) pdata_list ) #define octapi_llm_list_set_items( l, list_handle, start_item, data_length, pdata_list ) OctApiLlmListSetItems( (PVOID) l, (UINT32) list_handle, (UINT32) start_item, (UINT32) data_length, (PVOID) pdata_list ) /* Alloc man. */ UINT32 OctapiLlmAllocGetSize( UINT32 number_of_items,PUINT32 l_size ); UINT32 OctapiLlmAllocInit( PVOID* l,UINT32 number_of_items ); UINT32 OctapiLlmAllocInfo( PVOID l, PUINT32 allocated_items, PUINT32 available_items ); UINT32 OctapiLlmAllocAlloc( PVOID l, PUINT32 blocknum ); UINT32 OctapiLlmAllocDealloc( PVOID l,UINT32 blocknum ); /* Time managed alloc man. */ UINT32 OctApiTllmAllocGetSize( UINT32 number_of_items, PUINT32 l_size ); UINT32 OctApiTllmAllocInit( PVOID* l, UINT32 number_of_items ); UINT32 OctApiTllmAllocInfo( PVOID l, PUINT32 allocated_items, PUINT32 available_items ); UINT32 OctApiTllmAllocAlloc( PVOID l, PUINT32 blocknum, UINT32 current_time[2] ); UINT32 OctApiTllmAllocDealloc( PVOID l, UINT32 blocknum, UINT32 timeout_value, UINT32 current_time[2] ); /* List man. */ UINT32 OctApiLlmListGetSize( UINT32 number_of_items, UINT32 number_of_lists, UINT32 user_info_size, PUINT32 l_size ); UINT32 OctApiLlmListInit( PVOID* l, UINT32 number_of_items, UINT32 number_of_lists, UINT32 user_info_size ); UINT32 OctApiLlmListInfo( PVOID l, PUINT32 allocated_lists, PUINT32 allocated_items, PUINT32 free_lists, PUINT32 free_items ); UINT32 OctApiLlmListCreate( PVOID l, PUINT32 list_handle ); UINT32 OctApiLlmListCreateFull( PVOID l, UINT32 list_length, UINT32* plist_handle ); UINT32 OctApiLlmListAppendItems( PVOID l, UINT32 list_handle, UINT32 num_items ); UINT32 OctApiLlmListAppendAndSetItems( PVOID l, UINT32 list_handle, UINT32 num_items, PVOID data_list ); UINT32 OctApiLlmListDelete( PVOID l, UINT32 list_handle ); UINT32 OctApiLlmListLength( PVOID l, UINT32 list_handle, PUINT32 number_of_items_in_list ); UINT32 OctApiLlmListInsertItem( PVOID l, UINT32 list_handle, UINT32 item_number, PVOID* item_data_pnt ); UINT32 OctApiLlmListRemoveItem( PVOID l, UINT32 list_handle, UINT32 item_number ); UINT32 OctApiLlmListItemData( PVOID l, UINT32 list_handle, UINT32 item_number, PVOID* item_data_pnt ); UINT32 OctApiLlmListCopyData( PVOID l, UINT32 list_handle, UINT32 start_item, UINT32 data_length, PVOID pdata_list ); UINT32 OctApiLlmListSetItems( PVOID l, UINT32 list_handle, UINT32 start_item, UINT32 data_length, PVOID pdata_list ); /* Second list manager using a key to order info in the list. */ UINT32 OctApiLlm2ListGetSize( UINT32 number_of_items, UINT32 number_of_lists, UINT32 user_info_size, PUINT32 l_size ); UINT32 OctApiLlm2ListInit( PVOID* l,UINT32 number_of_items, UINT32 number_of_lists, UINT32 user_info_size ); UINT32 OctApiLlm2ListCreate( PVOID l, PUINT32 list_handle ); UINT32 OctApiLlm2ListLength( PVOID l, UINT32 list_handle, PUINT32 number_of_items_in_list ); UINT32 OctApiLlm2ListInsertItem(void * l, UINT32 list_handle, UINT32 item_key, void ** item_data_pnt, void ** prev_item_data_pnt, void ** prev_prev_item_data_pnt, PUINT32 insert_status_pnt ); UINT32 OctApiLlm2ListRemoveItem(void * l, UINT32 list_handle, UINT32 item_key, PUINT32 prev_item_key_pnt, PUINT32 prev_prev_item_key_pnt, PUINT32 remove_status_pnt ); UINT32 OctApiLlm2ListItemData( PVOID l, UINT32 list_handle, UINT32 item_key, PVOID* item_data_pnt, PUINT32 item_number ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __OCTAPI_LLMAN_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/apilib/octapi_largmath.h0000644000175000017500000000637011431317470026145 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_largmath.h Copyright (c) 2001-2007 Octasic Inc. Description: Library used to perform arithmetic on integer values of an integer multiple of 32-bits. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTAPI_LARGMATH_H__ #define __OCTAPI_LARGMATH_H__ #include "octdef.h" #define OCTAPI_LM_DIVISION_BY_ZERO 0xFFFF #define OCTAPI_LM_OVERFLOW 0xFFFE #define OCTAPI_LM_ARRAY_SIZE_MISMATCH 0xFFFD #define OCTAPI_LM_MAX_OPTIMIZE_MUL 10 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define octapi_lm_add( a, alen, b, blen, z, zlen ) OctApiLmAdd( (PUINT32) a, (USHORT) alen, (PUINT32) b, (USHORT) blen, (PUINT32) z, (USHORT) zlen ) #define octapi_lm_subtract( a, alen, bneg, blen, z, zlen, neg ) OctApiLmSubtract( (PUINT32) a, (USHORT) alen, (PUINT32) bneg, (USHORT) blen, (PUINT32) z, (USHORT) zlen, (USHORT*) neg ) #define octapi_lm_compare( a, alen, bneg, blen, neg ) OctApiLmCompare( (PUINT32) a, (USHORT) alen, (PUINT32) bneg, (USHORT) blen, (USHORT*) neg ) #define octapi_lm_multiply( a, b, ablen, z ) OctApiLmMultiply( (PUINT32) a, (PUINT32) b, (USHORT) ablen, (PUINT32) z ) #define octapi_lm_divide( n, d, q, r, ndqrlen ) OctApiLmDivide( (PUINT32) n, (PUINT32) d, (PUINT32) q, (PUINT32) r, (USHORT) ndqrlen ) #define octapi_lm_shiftright1( a, alen ) OctApiLmShiftRight1( (PUINT32) a, (USHORT) alen ) #define octapi_lm_shiftn( a, alen, shiftleft, shiftn ) OctApiLmShiftn( (PUINT32) a, (USHORT) alen, (USHORT) shiftleft, (USHORT) shiftn ) #define octapi_lm_getmsb( a, alen, msb_pos ) OctApiLmGetMsb( (PUINT32) a, (USHORT) alen, (USHORT*) msb_pos ) UINT32 OctApiLmAdd( PUINT32 a, USHORT alen, PUINT32 b, USHORT blen, PUINT32 z, USHORT zlen ); UINT32 OctApiLmSubtract( PUINT32 a, USHORT alen, PUINT32 bneg, USHORT blen, PUINT32 z, USHORT zlen, PUSHORT neg ); UINT32 OctApiLmCompare( PUINT32 a, USHORT alen, PUINT32 bneg, USHORT blen, PUSHORT neg ); UINT32 OctApiLmMultiply( PUINT32 a, PUINT32 b, USHORT ablen, PUINT32 z ); UINT32 OctApiLmDivide( PUINT32 n, PUINT32 d, PUINT32 q, PUINT32 r, USHORT ndqrlen ); UINT32 OctApiLmShiftRight1( PUINT32 a, USHORT alen ); UINT32 OctApiLmShiftn( PUINT32 a, USHORT alen, USHORT shiftleft, USHORT shiftn ); UINT32 OctApiLmGetMsb( PUINT32 a, USHORT alen, PUSHORT msb_pos ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __OCTAPI_LARGMATH_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octtypewin.h0000644000175000017500000000555511431317470023760 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octtypewin.h Copyright (c) 2001-2007 Octasic Inc. Description: This file defines the base storage types for the Windows environment. Includes the Windows definition file and add the missing ones here. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 16 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTTYPEWIN_H__ #define __OCTTYPEWIN_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #define WIN32_LEAN_AND_MEAN /* just get the base type definition from Windows */ #include /* Disable argument not used warning */ #pragma warning( disable : 4100 ) /* Disable Level 4 warning: nonstandard extension used : translation unit is empty */ #pragma warning( disable : 4206 ) #ifdef __cplusplus extern "C" { #endif /* 16-bit integer */ typedef unsigned short UINT16; typedef signed short INT16; typedef unsigned short *PUINT16; typedef signed short *PINT16; /* 8-bit integer */ typedef unsigned char UINT8; typedef signed char INT8; typedef signed char OCT_INT8; typedef unsigned char *PUINT8; typedef signed char *PINT8; typedef double DOUBLE; /* 32 bit integer */ #if ( defined( _MSC_VER ) && _MSC_VER == 1100 ) /* MFC5 compiler does not define UINT32 */ typedef unsigned int UINT32; typedef signed int INT32; typedef INT32 * PINT32; typedef UINT32 * PUINT32; #endif /* _MSC_VER */ /* LONG LONG */ #define LLONG signed __int64 #define PLLONG signed __int64 * #define ULLONG unsigned __int64 #define PULLONG unsigned __int64 * /* Double integers */ typedef double DOUBLE; typedef double * PDOUBLE; typedef float FLOAT; typedef float * PFLOAT; #ifndef OPT #define OPT /* OPT param */ #endif typedef PSZ * PPSZ; /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTTYPEWIN_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octtype.h0000644000175000017500000000777611431317470023251 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octtype.h Copyright (c) 2001-2007 Octasic Inc. Description: This file defines the base storage types. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 18 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTTYPE_H__ #define __OCTTYPE_H__ /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------- Include target-specific header if available ----------------------------------------------------------------------------*/ #if defined( OCT_NTDRVENV ) #include "octtypentdrv.h" /* All NT driver typedef */ #elif defined( OCT_WINENV ) #include "octtypewin.h" /* All Win32 typedef */ #elif defined( OCT_VXENV ) #include "octtypevx.h" /* All VxWorks typedef */ #else /*-------------------------------------------------------------------------- No target-specific header available ----------------------------------------------------------------------------*/ #ifdef SZ #undef SZ #endif /***************************** DEFINES *************************************/ /* 16-bit integer */ typedef unsigned short UINT16; typedef signed short INT16; typedef unsigned short *PUINT16; typedef signed short *PINT16; /* 8-bit integer */ typedef unsigned char UINT8; typedef signed char INT8; typedef signed char OCT_INT8; typedef unsigned char *PUINT8; typedef signed char *PINT8; /* 32 bit integer */ typedef unsigned int UINT32; typedef signed int INT32; typedef INT32 * PINT32; typedef UINT32 * PUINT32; /* Long integer */ typedef signed long LONG; typedef unsigned long ULONG; typedef long * PLONG; typedef unsigned long * PULONG; /* Short integer */ typedef short SHORT; typedef unsigned short USHORT; typedef short * PSHORT; typedef unsigned short *PUSHORT; /* 8-bit integer*/ typedef unsigned char BYTE; typedef BYTE * PBYTE; typedef unsigned char UCHAR; /* Character and strings */ typedef char CHAR; typedef CHAR SZ; typedef CHAR * PSZ; typedef CHAR * PCHAR; /* Double integers */ typedef double DOUBLE; typedef double * PDOUBLE; typedef float FLOAT; typedef float * PFLOAT; typedef void VOID; typedef void * PVOID; /* Booleans */ typedef int BOOL; typedef BOOL * PBOOL; /* Integers */ typedef int INT; typedef int * PINT; typedef unsigned int UINT; typedef unsigned int * PUINT; /* Define pseudo-keywords IN and OUT if not defined yet */ #ifndef IN #define IN /* IN param */ #endif #ifndef OUT #define OUT /* OUT param */ #endif /* LONG LONG */ #define LLONG signed long long #define PLLONG signed long long * #define ULLONG unsigned long long #define PULLONG unsigned long long * #ifndef OPT #define OPT /* OPT param */ #endif typedef PSZ * PPSZ; #if defined(__FreeBSD__) #include #else #include #endif #endif /*-------------------------------------------------------------------------- C language ----------------------------------------------------------------------------*/ #ifdef __cplusplus } #endif #endif /* __OCTTYPE_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octrpc/0000755000175000017500000000000011631523356022666 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octrpc/rpc_protocol.h0000644000175000017500000000773211431317470025551 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: rpc_protocol.h Copyright (c) 2001-2007 Octasic Inc. Description: This file contains RPC related definitions and prototypes. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 23 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __RPC_PROTOCOL_H__ #define __RPC_PROTOCOL_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define cOCTRPC_ENDIAN_DETECT 0x27182819 #define cOCTRPC_ENDIAN_DETECT_BYTE_W 0x19 #define cOCTRPC_ENDIAN_DETECT_BYTE_X 0x28 #define cOCTRPC_ENDIAN_DETECT_BYTE_Y 0x18 #define cOCTRPC_ENDIAN_DETECT_BYTE_Z 0x27 #define cOCTRPC_ECHO_PROTOCOL 0x00000000 #define cOCTRPC_MIN_PACKET_BYTE_LENGTH (sizeof( tOCTRPC_OGRDTP_HEADER )) #define cOCTRPC_FIRST_COMMAND_BYTE_OFFSET (sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) #define cOCTRPC_GENERIC_HEADERS_BYTE_SIZE (sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER ) + sizeof( tOCTRPC_COMMAND_HEADER )) #define cOCTRPC_MAX_PACKET_BYTE_LENGTH 32768 /* Protocol versions */ #define cOCTRPC_PROTOCOL_V1_0 0x00010000 #define cOCTRPC_PROTOCOL_V1_1 0x00010001 #define cOCTRPC_PROTOCOL_V1_2 0x00010002 #define cOCTRPC_PROTOCOL_V1_3 0x00010003 #define cOCTRPC_OCTASIC_PROTOCOL_V1_0 0xFF010000 #define cOCTRPC_OCTASIC_PROTOCOL_V1_1 0xFF010001 #define cOCTRPC_OCTASIC_PROTOCOL_V1_2 0xFF010002 #define cOCTRPC_OCTASIC_PROTOCOL_V1_3 0xFF010003 /* Chips */ #define cOCTRPC_OCT8304_INTERFACE 0x00000000 #define cOCTRPC_OCT6100_INTERFACE 0x00000001 /* Timeout values. */ #define cOCTRPC_SESSION_TIMEOUT 30 /* Generic errors */ #define cOCTRPC_RDBGERR_OK 0x00000000 #define cOCTRPC_RDBGERR_NO_ANSWER 0xFFFF0000 #define cOCTRPC_RDBGERR_ALL_SESSIONS_OPEN 0xFFFF0001 #define cOCTRPC_RDBGERR_PROTOCOL_NUMBER 0xFFFF0002 #define cOCTRPC_RDBGERR_NO_COMMAND_HEADER 0xFFFF0003 #define cOCTRPC_RDBGERR_INTERFACE_TYPE 0xFFFF0004 #define cOCTRPC_RDBGERR_INTERFACE_VERSION 0xFFFF0005 #define cOCTRPC_RDBGERR_INVALID_PACKET_LENGTH 0xFFFF0006 #define cOCTRPC_RDBGERR_INVALID_COMMAND_LENGTH 0xFFFF0007 #define cOCTRPC_RDBGERR_INVALID_COMMAND_NUMBER 0xFFFF0008 #define cOCTRPC_RDBGERR_PACKET_TOO_LARGE 0xFFFF0009 #define cOCTRPC_RDBGERR_LIST_EMPTY 0xFFFF000A #define cOCTRPC_RDBGERR_FATAL 0xFFFFFFFF /***************************** TYPES ***************************************/ typedef struct _OCTRPC_OGRDTP_HEADER_ { UINT32 IN ulEndianDetect; UINT32 IN ulDebugSessionNum; UINT32 IN ulTransactionNum; UINT32 IN ulPktRetryNum; UINT32 IN ulPktByteSize; UINT32 IN ulChecksum; UINT32 OUT ulParsingError; UINT32 IN ulRpcProtocolNum; } tOCTRPC_OGRDTP_HEADER, *tPOCTRPC_OGRDTP_HEADER; typedef struct _OCTRPC_INTERFACE_HEADER_ { UINT32 IN ulInterfaceType; UINT32 IN ulInterfaceVersion; } tOCTRPC_INTERFACE_HEADER, *tPOCTRPC_INTERFACE_HEADER; typedef struct _OCTRPC_COMMAND_HEADER_ { UINT32 IN ulCommandByteSize; UINT32 IN OUT ulRpcCommandNum; UINT32 OUT ulFunctionResult; } tOCTRPC_COMMAND_HEADER, *tPOCTRPC_COMMAND_HEADER; #endif /* __RPC_PROTOCOL_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/include/octrpc/oct6100_rpc_protocol.h0000644000175000017500000003054611431317470026724 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_rpc_protocol.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all defines and prototypes related to the OCT6100 RPC protocol for exchanging debug commands. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 6 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_RPC_PROTOCOL_H__ #define __OCT6100_RPC_PROTOCOL_H__ /***************************** DEFINES *************************************/ #define cOCTRPC_INTERFACE_VERSION 0x00010002 /* Octasic commands. */ #define cOCT6100_RPC_CHIP_LIST 0xFF000000 #define cOCT6100_RPC_CHIP_CHOICE 0xFF000001 #define cOCT6100_RPC_ENV_DISCONNECT 0xFF000002 /* Commands */ /* Read commands */ #define cOCT6100_RPC_READ_WORD 0x00000000 #define cOCT6100_RPC_READ_BURST 0x00000001 #define cOCT6100_RPC_READ_DEBUG 0x00000002 #define cOCT6100_RPC_READ_ARRAY 0x00000003 #define cOCT6100_RPC_API_DISCONNECT 0x00000004 /* Write commands */ #define cOCT6100_RPC_WRITE_WORD 0x00000010 #define cOCT6100_RPC_WRITE_BURST 0x00000011 #define cOCT6100_RPC_WRITE_SMEAR 0x00000012 #define cOCT6100_RPC_WRITE_INC 0x00000013 /* Debug commands.*/ #define cOCT6100_RPC_SET_HOT_CHANNEL 0x00000014 #define cOCT6100_RPC_GET_DEBUG_CHAN_INDEX 0x00000015 #define cOCTRPC_UNKNOWN_COMMAND_NUM 0xFFFFFFFF /* Errors */ #define cOCT6100_RPCERR_OK 0x00000000 #define cOCT6100_RPCERR_INVALID_COMMAND_NUMBER 0x00000001 #define cOCT6100_RPCERR_INVALID_COMMAND_PAYLOAD 0x00000002 #define cOCT6100_RPCERR_INVALID_COMMAND_LENGTH 0x00000003 /***************************** TYPES ***************************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_READ_WORD Description: Command structure for the read of one word. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress Address at which to read. OUT ulReadData The word read, returned. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_READ_WORD_ { UINT32 IN ulAddress; UINT32 OUT ulReadData; } tOCT6100_RPC_READ_WORD, *tPOCT6100_RPC_READ_WORD; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_READ_BURST Description: Command structure for a read burst. The burst starts at the given address and reads the specified number of consecutive words. Whereas every command structure uses a complete dword for every member, irrespective of the size of data unit needed, this structure does not do so for the read data. To save bandwidth the read data words are returned two per dword. Example packet: 31 16 15 0 ------------------------------------------- | ulAddress = 0x100 | ------------------------------------------- | ulBurstLength = 0x3 | ------------------------------------------- aulReadData -> | D0 | D1 | ------------------------------------------- | D2 | xx | ------------------------------------------- Dy is the read data at ulAddress + 2 * y. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress Address at which to read. IN ulBurstLength The number of consecutive words to be read. OUT aulReadData The read data returned. The dwords of the structure starting at this address are arranged as indicated in the example packet above. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_READ_BURST_ { UINT32 IN ulAddress; UINT32 IN ulBurstLength; UINT32 OUT aulReadData[ 1 ]; } tOCT6100_RPC_READ_BURST, *tPOCT6100_RPC_READ_BURST; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_READ_ARRAY Description: Command structure for a variable number of reads. The reads do not have to be at contiguous addresses. Whereas every command structure uses a complete dword for every member, irrespective of the size of data unit needed, this structure does not do so for the read data. To save bandwidth the read data words are returned two per dword, and the parity bits are returned 16 per dword (two parity bits per read access). Example packet: 31 16 15 0 ------------------------------------------- | ulArrayLength = 0x3 | ------------------------------------------- aulArrayData ->| A0 | ------------------------------------------- | A1 | ------------------------------------------- | A2 | ------------------------------------------- | D0 | D1 | ------------------------------------------- | D2 | xx | ------------------------------------------- Ay is the address for access y. Dy is the read data at Ay. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulArrayLength Number of reads to do. IN OUT aulArrayData The addresses at which to read (IN) and the read data returned (OUT). The dwords of the command structure starting at this address are arranged as indicated in the example packet above. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_READ_ARRAY { UINT32 IN ulArrayLength; UINT32 IN OUT aulArrayData[ 1 ]; } tOCT6100_RPC_READ_ARRAY, *tPOCT6100_RPC_READ_ARRAY; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_WRITE_WORD Description: Command structure for the write of one word. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress Address at which to write. IN ulWriteData The word to write. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_WRITE_WORD_ { UINT32 IN ulAddress; UINT32 IN ulParity; UINT32 IN ulWriteData; } tOCT6100_RPC_WRITE_WORD, *tPOCT6100_RPC_WRITE_WORD; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_WRITE_SMEAR Description: Command structure for the write of one word at one or many consecutive addresses. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress Address of first write. IN ulSmearLength Number of consecutive addresses to write. IN ulWriteData The word to write at each address. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_WRITE_SMEAR_ { UINT32 IN ulAddress; UINT32 IN ulSmearLength; UINT32 IN ulParity; UINT32 IN ulWriteData; } tOCT6100_RPC_WRITE_SMEAR, *tPOCT6100_RPC_WRITE_SMEAR; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_WRITE_INC Description: Command structure for the write of an incremental pattern at one or many consecutive addresses. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress Address of first write. IN ulIncLength Number of consecutive addresses to write. IN ulWriteData The first word of the incremental pattern. For each consecutive write the word will be incremented by 1. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_WRITE_INC_ { UINT32 IN ulAddress; UINT32 IN ulIncLength; UINT32 IN ulParity; UINT32 IN ulWriteData; } tOCT6100_RPC_WRITE_INC, *tPOCT6100_RPC_WRITE_INC; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_WRITE_BURST Description: Command structure for a write burst. The burst starts at the given address and writes a given word for each address. Whereas every command structure uses a complete dword for every member, irrespective of the size of data unit needed, this structure does not do so for the write data. To save bandwidth the write data words are sent two per dword. Example packet: 31 16 15 0 ------------------------------------------- | ulAddress = 0x100 | ------------------------------------------- | ulBurstLength = 0x3 | ------------------------------------------- aulWriteData ->| D0 | D1 | ------------------------------------------- | D2 | xx | ------------------------------------------- Dy is the write data for ulAddress + 2 * y. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulAddress First address at which to write. IN ulBurstLength The number of consecutive addresses to be write. IN aulWriteData The write data words. The dwords of the structure starting at this address are arranged as indicated in the example packet above. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_WRITE_BURST_ { UINT32 IN ulAddress; UINT32 IN ulBurstLength; UINT32 IN ulParity; UINT32 IN aulWriteData[ 1 ]; } tOCT6100_RPC_WRITE_BURST, *tPOCT6100_RPC_WRITE_BURST; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_SET_HOT_CHANNEL Description: Command structure to set the hot channel. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulDebugChannel Index of the channel to debug. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_SET_HOT_CHANNEL_ { UINT32 IN ulHotChannel; UINT32 IN ulPcmLaw; } tOCT6100_RPC_SET_HOT_CHANNEL, *tPOCT6100_RPC_SET_HOT_CHANNEL; /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Structure: OCT6100_RPC_GET_DEBUG_CHAN_INDEX Description: Command structure to get the debug channel index used by the API. ------------------------------------------------------------------------------- | Member | Description ------------------------------------------------------------------------------- IN ulDebugChannel Index of the channel to debug. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ typedef struct _OCT6100_RPC_GET_DEBUG_CHAN_INDEX_ { UINT32 OUT ulDebugChanIndex; } tOCT6100_RPC_GET_DEBUG_CHAN_INDEX, *tPOCT6100_RPC_GET_DEBUG_CHAN_INDEX; #endif /* __OCT6100_RPC_PROTOCOL_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octasic-helper0000755000175000017500000000177311431317470022605 0ustar tzafrirtzafrir#!/bin/sh # # Jeffrey C. Ollie # # $1 == information requested # $2 == path to octasic directory # APIDIR=$2/octdeviceapi/oct6100api/oct6100_api case $1 in objects) echo $APIDIR/oct6100_adpcm_chan.o \ $APIDIR/oct6100_channel.o \ $APIDIR/oct6100_chip_open.o \ $APIDIR/oct6100_chip_stats.o \ $APIDIR/oct6100_conf_bridge.o \ $APIDIR/oct6100_debug.o \ $APIDIR/oct6100_events.o \ $APIDIR/oct6100_interrupts.o \ $APIDIR/oct6100_memory.o \ $APIDIR/oct6100_miscellaneous.o \ $APIDIR/oct6100_mixer.o \ $APIDIR/oct6100_phasing_tsst.o \ $APIDIR/oct6100_playout_buf.o \ $APIDIR/oct6100_remote_debug.o \ $APIDIR/oct6100_tlv.o \ $APIDIR/oct6100_tone_detection.o \ $APIDIR/oct6100_tsi_cnct.o \ $APIDIR/oct6100_tsst.o \ $2/apilib/bt/octapi_bt0.o \ $2/apilib/largmath/octapi_largmath.o \ $2/apilib/llman/octapi_llman.o ;; cflags) echo -I$2/include -I$2/octdeviceapi -I$2/octdeviceapi/oct6100api ;; esac dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/0000755000175000017500000000000011631523356021211 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/bt/0000755000175000017500000000000011631523356021616 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/bt/octapi_bt0.c0000644000175000017500000011067611431317470024015 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_bt0.c Copyright (c) 2001-2007 Octasic Inc. Description: Library used to manage a binary tree of variable max size. Library is made to use one block of contiguous memory to manage the tree. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 18 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #include "apilib/octapi_bt0.h" #include "octapi_bt0_private.h" #if !SKIP_OctApiBt0GetSize UINT32 OctApiBt0GetSize(UINT32 number_of_items,UINT32 key_size, UINT32 data_size, UINT32 * b_size) { if ((key_size % 4) != 0) return(OCTAPI_BT0_KEY_SIZE_NOT_MUTLIPLE_OF_UINT32); if ((data_size % 4) != 0) return(OCTAPI_BT0_DATA_SIZE_NOT_MUTLIPLE_OF_UINT32); *b_size = 0; *b_size += sizeof(OCTAPI_BT0); *b_size += sizeof(OCTAPI_BT0_NODE) * number_of_items; *b_size += key_size * number_of_items; *b_size += data_size * number_of_items; return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0Init UINT32 OctApiBt0Init(void ** b,UINT32 number_of_items,UINT32 key_size, UINT32 data_size) { UINT32 i; OCTAPI_BT0 * bb; /* Check input parameters.*/ if ((key_size % 4) != 0) return(OCTAPI_BT0_KEY_SIZE_NOT_MUTLIPLE_OF_UINT32); if ((data_size % 4) != 0) return(OCTAPI_BT0_DATA_SIZE_NOT_MUTLIPLE_OF_UINT32); /* If b is not already allocated.*/ if (*b == NULL) return(OCTAPI_BT0_MALLOC_FAILED); bb = (OCTAPI_BT0 *)(*b); /* Initialize the tree to an empty one!*/ bb->root_link.node_number = 0xFFFFFFFF; bb->root_link.depth = 0; /* Initialize tree parameters.*/ bb->number_of_items = number_of_items; bb->key_size = key_size / 4; bb->data_size = data_size / 4; /* Initialize the next free node pointer.*/ if (number_of_items != 0) bb->next_free_node = 0; else bb->next_free_node = 0xFFFFFFFF; /* Setup the arrays.*/ OctApiBt0CorrectPointers(bb); /* Initialize the Nodes to unused!*/ for(i=0;inode[i].next_free_node = i + 1; } /* Last empty node points to invalid node.*/ bb->node[number_of_items-1].next_free_node = 0xFFFFFFFF; bb->invalid_value = 0xFFFFFFFF; bb->no_smaller_key = OCTAPI_BT0_NO_SMALLER_KEY; return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0CorrectPointers void OctApiBt0CorrectPointers(OCTAPI_BT0 * bb) { bb->node = (OCTAPI_BT0_NODE *)(((BYTE *)bb) + sizeof(OCTAPI_BT0)); bb->key = (UINT32 *)(((BYTE *)bb->node) + (sizeof(OCTAPI_BT0_NODE) * bb->number_of_items)); bb->data = (UINT32 *)(((BYTE *)bb->key) + (sizeof(UINT32) * bb->number_of_items * bb->key_size)); } #endif #if !SKIP_OctApiBt0AddNode UINT32 OctApiBt0AddNode(void * b,void * key,void ** data) { OCTAPI_BT0 * bb; OCTAPI_BT0_NODE * new_node; UINT32 * lkey; UINT32 * nkey; UINT32 i; UINT32 new_node_number; UINT32 result; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Check that there is at least one block left.*/ if (bb->next_free_node == 0xFFFFFFFF) return(OCTAPI_BT0_NO_NODES_AVAILABLE); /* Seize the node!*/ new_node_number = bb->next_free_node; new_node = &(bb->node[new_node_number]); bb->next_free_node = new_node->next_free_node; /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Find the first UINT32 of the key.*/ nkey = &(bb->key[bb->key_size * new_node_number]); /* Copy the key.*/ for(i=0;ikey_size;i++) nkey[i] = lkey[i]; /* Attempt to place the node. Only a "multiple hit" will cause an error.*/ result = OctApiBt0AddNode2(bb,&(bb->root_link), lkey, new_node_number); if (result != GENERIC_OK) { /* This attempt failed. Refree the node!*/ bb->next_free_node = new_node_number; /* Return the error code.*/ return(result); } /* Return the address of the data to the user.*/ if ( bb->data_size > 0 ) *data = (void *)(&(bb->data[bb->data_size * new_node_number])); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0AddNode2 UINT32 OctApiBt0AddNode2(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link,UINT32 * lkey,UINT32 new_node_number) { UINT32 result; if (link->node_number == 0xFFFFFFFF) /* We have an empty node. Here, we shall place the new node.*/ { bb->node[new_node_number].l[0].node_number = 0xFFFFFFFF; bb->node[new_node_number].l[0].depth = 0; bb->node[new_node_number].l[1].node_number = 0xFFFFFFFF; bb->node[new_node_number].l[1].depth = 0; /* OCTAPI_BT0_LINK to parent!*/ link->node_number = new_node_number; link->depth = 1; /* We are a leaf, last OCTAPI_BT0_LINK depth is 1.*/ return(GENERIC_OK); } else /* Current node is used, check for a match and a direction.*/ { OCTAPI_BT0_NODE * this_node; UINT32 compare; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { result = OctApiBt0AddNode2(bb,&(this_node->l[0]), lkey, new_node_number); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { result = OctApiBt0AddNode2(bb,&(this_node->l[1]), lkey, new_node_number); if (result != GENERIC_OK) return(result); } else { return(OCTAPI_BT0_KEY_ALREADY_IN_TREE); } /* Check if this node is unbalanced by 2. If so, rebalance it:*/ if (this_node->l[0].depth > (this_node->l[1].depth + 1) || this_node->l[1].depth > (this_node->l[0].depth + 1)) { OctApiBt0Rebalance(bb,link); } /* Always update the OCTAPI_BT0_LINK depth before exiting.*/ OctApiBt0UpdateLinkDepth(bb,link); return(GENERIC_OK); } } #endif #if !SKIP_OctApiBt0AddNode3 UINT32 OctApiBt0AddNode3(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link,UINT32 * lkey,UINT32 *p_new_node_number) { UINT32 result; if (link->node_number == 0xFFFFFFFF) /* We have an empty node. Here, we shall place the new node.*/ { if ( *p_new_node_number == 0xFFFFFFFF ) return(OCTAPI_BT0_NO_NODES_AVAILABLE); bb->node[*p_new_node_number].l[0].node_number = 0xFFFFFFFF; bb->node[*p_new_node_number].l[0].depth = 0; bb->node[*p_new_node_number].l[1].node_number = 0xFFFFFFFF; bb->node[*p_new_node_number].l[1].depth = 0; /* OCTAPI_BT0_LINK to parent!*/ link->node_number = *p_new_node_number; link->depth = 1; /* We are a leaf, last OCTAPI_BT0_LINK depth is 1.*/ return(GENERIC_OK); } else /* Current node is used, check for a match and a direction.*/ { OCTAPI_BT0_NODE * this_node; UINT32 compare; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { result = OctApiBt0AddNode3(bb,&(this_node->l[0]), lkey, p_new_node_number); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { result = OctApiBt0AddNode3(bb,&(this_node->l[1]), lkey, p_new_node_number); if (result != GENERIC_OK) return(result); } else { *p_new_node_number = link->node_number; return(OCTAPI_BT0_KEY_ALREADY_IN_TREE); } /* Check if this node is unbalanced by 2. If so, rebalance it:*/ if (this_node->l[0].depth > (this_node->l[1].depth + 1) || this_node->l[1].depth > (this_node->l[0].depth + 1)) { OctApiBt0Rebalance(bb,link); } /* Always update the OCTAPI_BT0_LINK depth before exiting.*/ OctApiBt0UpdateLinkDepth(bb,link); return(GENERIC_OK); } } #endif /* state 0 -> first call to the function. 1 -> recursive call.*/ #if !SKIP_OctApiBt0AddNode4 UINT32 OctApiBt0AddNode4(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link,UINT32 * lkey,UINT32 *p_new_node_number, UINT32 *p_prev_node_number, UINT32 state ) { UINT32 result; UINT32 *nkey; UINT32 *okey; if (link->node_number == 0xFFFFFFFF) /* We have an empty node. Here, we shall place the new node.*/ { bb->node[*p_new_node_number].l[0].node_number = 0xFFFFFFFF; bb->node[*p_new_node_number].l[0].depth = 0; bb->node[*p_new_node_number].l[1].node_number = 0xFFFFFFFF; bb->node[*p_new_node_number].l[1].depth = 0; /* OCTAPI_BT0_LINK to parent!*/ link->node_number = *p_new_node_number; link->depth = 1; /* We are a leaf, last OCTAPI_BT0_LINK depth is 1.*/ if ( state == 0 ) *p_prev_node_number = 0xFFFFFFFF; return(GENERIC_OK); } else /* Current node is used, check for a match and a direction.*/ { OCTAPI_BT0_NODE * this_node; UINT32 compare; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { if ( state == 0 ) *p_prev_node_number = OCTAPI_BT0_NO_SMALLER_KEY; if ( *p_prev_node_number != OCTAPI_BT0_NO_SMALLER_KEY ) { /* Check if the key is the smallest one encountered yet.*/ okey = &(bb->key[bb->key_size * (*p_prev_node_number)]); nkey = &(bb->key[bb->key_size * link->node_number]); /* If the node is key smaller then the old small one, change the value.*/ if ( *nkey > *okey ) { if ( *nkey < *lkey ) *p_prev_node_number = link->node_number; } } result = OctApiBt0AddNode4(bb,&(this_node->l[0]), lkey, p_new_node_number, p_prev_node_number, 1); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { if ( state == 0 ) *p_prev_node_number = link->node_number; else { if ( *p_prev_node_number == OCTAPI_BT0_NO_SMALLER_KEY ) *p_prev_node_number = link->node_number; else { /* Check if the key is the smallest one encountered yet.*/ okey = &(bb->key[bb->key_size * (*p_prev_node_number)]); nkey = &(bb->key[bb->key_size * link->node_number]); /* If the node is key smaller then the old small one, change the value.*/ if ( *nkey > *okey ) { if ( *nkey < *lkey ) *p_prev_node_number = link->node_number; } } } result = OctApiBt0AddNode4(bb,&(this_node->l[1]), lkey, p_new_node_number, p_prev_node_number, 1); if (result != GENERIC_OK) return(result); } else { *p_new_node_number = link->node_number; return(OCTAPI_BT0_KEY_ALREADY_IN_TREE); } /* Check if this node is unbalanced by 2. If so, rebalance it:*/ if (this_node->l[0].depth > (this_node->l[1].depth + 1) || this_node->l[1].depth > (this_node->l[0].depth + 1)) { OctApiBt0Rebalance(bb,link); } /* Always update the OCTAPI_BT0_LINK depth before exiting.*/ OctApiBt0UpdateLinkDepth(bb,link); return(GENERIC_OK); } } #endif #if !SKIP_OctApiBt0KeyCompare UINT32 OctApiBt0KeyCompare(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link, UINT32 * lkey) { UINT32 * nkey; UINT32 i; /* Find the first UINT32 of the key.*/ nkey = &(bb->key[bb->key_size * link->node_number]); for(i=0;ikey_size;i++) { if (lkey[i] < nkey[i]) return(OCTAPI_BT0_LKEY_SMALLER); else if (lkey[i] > nkey[i]) return(OCTAPI_BT0_LKEY_LARGER); } return(OCTAPI_BT0_LKEY_EQUAL); } #endif #if !SKIP_OctApiBt0UpdateLinkDepth void OctApiBt0UpdateLinkDepth(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link) { OCTAPI_BT0_NODE * this_node; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); if (this_node->l[0].depth > this_node->l[1].depth) link->depth = this_node->l[0].depth + 1; else link->depth = this_node->l[1].depth + 1; } #endif #if !SKIP_OctApiBt0Rebalance void OctApiBt0Rebalance(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * root_link) { if (bb->node[root_link->node_number].l[0].depth > (bb->node[root_link->node_number].l[1].depth + 1)) /* Heavy to the left.*/ { /* Check if the right child of the heavy child node is causing a problem.*/ /* If so, do a left rotate in order to make the left most child the longer one.*/ { OCTAPI_BT0_LINK * heavy_link; heavy_link = &(bb->node[root_link->node_number].l[0]); if (bb->node[heavy_link->node_number].l[1].depth > bb->node[heavy_link->node_number].l[0].depth) { OctApiBt0ExternalHeavy(bb,heavy_link); } } /* Ready to do super rotation!*/ { OCTAPI_BT0_LINK init_root_link; OCTAPI_BT0_LINK init_heavy_link; OCTAPI_BT0_LINK init_leaf_tree[3]; /* Save pertinent initial OCTAPI_BT0_LINK information.*/ init_root_link = *root_link; init_heavy_link = bb->node[root_link->node_number].l[0]; init_leaf_tree[2] = bb->node[root_link->node_number].l[1]; init_leaf_tree[0] = bb->node[bb->node[root_link->node_number].l[0].node_number].l[0]; init_leaf_tree[1] = bb->node[bb->node[root_link->node_number].l[0].node_number].l[1]; /* Restructure the tree.*/ *root_link = init_heavy_link; bb->node[init_heavy_link.node_number].l[1] = init_root_link; bb->node[init_root_link.node_number].l[0] = init_leaf_tree[1]; /* Reconstruct the depth of the branches.*/ OctApiBt0UpdateLinkDepth(bb,&(bb->node[root_link->node_number].l[1])); OctApiBt0UpdateLinkDepth(bb,root_link); } } else if (bb->node[root_link->node_number].l[1].depth > (bb->node[root_link->node_number].l[0].depth + 1)) /* Heavy to the right.*/ { /* Check if the right child of the heavy child node is causing a problem.*/ /* If so, do a left rotate in order to make the left most child the longer one.*/ { OCTAPI_BT0_LINK * heavy_link; heavy_link = &(bb->node[root_link->node_number].l[1]); if (bb->node[heavy_link->node_number].l[0].depth > bb->node[heavy_link->node_number].l[1].depth) { OctApiBt0ExternalHeavy(bb,heavy_link); } } /* Ready to do super rotation!*/ { OCTAPI_BT0_LINK init_root_link; OCTAPI_BT0_LINK init_heavy_link; OCTAPI_BT0_LINK init_leaf_tree[3]; /* Save pertinent initial OCTAPI_BT0_LINK information.*/ init_root_link = *root_link; init_heavy_link = bb->node[root_link->node_number].l[1]; init_leaf_tree[2] = bb->node[root_link->node_number].l[0]; init_leaf_tree[0] = bb->node[bb->node[root_link->node_number].l[1].node_number].l[1]; init_leaf_tree[1] = bb->node[bb->node[root_link->node_number].l[1].node_number].l[0]; /* Restructure the tree.*/ *root_link = init_heavy_link; bb->node[init_heavy_link.node_number].l[0] = init_root_link; bb->node[init_root_link.node_number].l[1] = init_leaf_tree[1]; /* Reconstruct the depth of the branches.*/ OctApiBt0UpdateLinkDepth(bb,&(bb->node[root_link->node_number].l[0])); OctApiBt0UpdateLinkDepth(bb,root_link); } } } #endif /* This function does a rotation towards the outside of the tree*/ /* in order to keep the heavy branches towards the outside.*/ #if !SKIP_OctApiBt0ExternalHeavy void OctApiBt0ExternalHeavy(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * root_link) { if (bb->node[root_link->node_number].l[1].depth > bb->node[root_link->node_number].l[0].depth) /* Exterior of tree is towards the left.*/ { OCTAPI_BT0_LINK init_root_link; OCTAPI_BT0_LINK init_heavy_link; OCTAPI_BT0_LINK init_leaf_tree[3]; /* Save pertinent initial OCTAPI_BT0_LINK information.*/ init_root_link = *root_link; init_leaf_tree[0] = bb->node[root_link->node_number].l[0]; init_heavy_link = bb->node[root_link->node_number].l[1]; init_leaf_tree[1] = bb->node[bb->node[root_link->node_number].l[1].node_number].l[0]; init_leaf_tree[2] = bb->node[bb->node[root_link->node_number].l[1].node_number].l[1]; /* Restructure the tree.*/ *root_link = init_heavy_link; bb->node[init_heavy_link.node_number].l[0] = init_root_link; bb->node[init_root_link.node_number].l[1] = init_leaf_tree[1]; /* Reconstruct the depth of the branches.*/ OctApiBt0UpdateLinkDepth(bb,&(bb->node[root_link->node_number].l[0])); OctApiBt0UpdateLinkDepth(bb,root_link); } else if (bb->node[root_link->node_number].l[0].depth > bb->node[root_link->node_number].l[1].depth) /* Exterior of tree is towards the right.*/ { OCTAPI_BT0_LINK init_root_link; OCTAPI_BT0_LINK init_heavy_link; OCTAPI_BT0_LINK init_leaf_tree[3]; /* Save pertinent initial OCTAPI_BT0_LINK information.*/ init_root_link = *root_link; init_leaf_tree[0] = bb->node[root_link->node_number].l[1]; init_heavy_link = bb->node[root_link->node_number].l[0]; init_leaf_tree[1] = bb->node[bb->node[root_link->node_number].l[0].node_number].l[1]; init_leaf_tree[2] = bb->node[bb->node[root_link->node_number].l[0].node_number].l[0]; /* Restructure the tree.*/ *root_link = init_heavy_link; bb->node[init_heavy_link.node_number].l[1] = init_root_link; bb->node[init_root_link.node_number].l[0] = init_leaf_tree[1]; /* Reconstruct the depth of the branches.*/ OctApiBt0UpdateLinkDepth(bb,&(bb->node[root_link->node_number].l[1])); OctApiBt0UpdateLinkDepth(bb,root_link); } } #endif /* State:*/ /* 0 = seeking node to be removed.*/ /* 1 = node found, left branch taken.*/ /* 2 = node found, right branch taken.*/ #if !SKIP_OctApiBt0RemoveNode2 UINT32 OctApiBt0RemoveNode2(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link, UINT32 * lkey, OCTAPI_BT0_LINK * link_to_removed_node, UINT32 state, OCTAPI_BT0_LINK * volatile_grandparent_link) { UINT32 result; OCTAPI_BT0_NODE * this_node; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); if (state == 0) { if (link->node_number == 0xFFFFFFFF) /* We have an empty node. The node we were looking for does not exist.*/ { return(OCTAPI_BT0_KEY_NOT_IN_TREE); } else /* Current node is used, check for a match and a direction.*/ { UINT32 compare; /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[0]), lkey, link_to_removed_node, 0, NULL); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[1]), lkey, link_to_removed_node, 0, NULL); if (result != GENERIC_OK) return(result); } else { link_to_removed_node = link; /* Keep on going down to find a replacement node.*/ if (bb->node[link->node_number].l[0].node_number == 0xFFFFFFFF && bb->node[link->node_number].l[1].node_number == 0xFFFFFFFF) { /* Doe! No tree left! WHAT TO DO? */ /* Just delete the current node. That's it.*/ /* Release the current node (restore free node link-list)*/ bb->node[link->node_number].next_free_node = bb->next_free_node; bb->next_free_node = link->node_number; link->node_number = 0xFFFFFFFF; link->depth = 0; return(GENERIC_OK); } else if (bb->node[link->node_number].l[0].node_number != 0xFFFFFFFF) /* Left node is present. Go left, then permanently right.*/ { OCTAPI_BT0_NODE * removed_node_pnt; removed_node_pnt = &(bb->node[link->node_number]); result = OctApiBt0RemoveNode2(bb,&(removed_node_pnt->l[0]), lkey, link_to_removed_node, 1, link); if (result != GENERIC_OK) return(result); /* Caution! Once we are here, the link->node_pnt->l[0] has been modified,*/ /* but is about to be discarded! Save it quickly!*/ /* bb->node[link->node_number].l[0] = removed_node_pnt->l[0];*/ } else /* Right node is present. Go right, then permanently left.*/ { OCTAPI_BT0_NODE * removed_node_pnt; removed_node_pnt = &(bb->node[link->node_number]); result = OctApiBt0RemoveNode2(bb,&(removed_node_pnt->l[1]), lkey, link_to_removed_node, 2, link); if (result != GENERIC_OK) return(result); /* Caution! Once we are here, the link->node_pnt->l[0] has been modified,*/ /* but is about to be discarded! Save it quickly!*/ /* bb->node[link->node_number].l[1] = removed_node_pnt->l[1];*/ } } } } else { /* Left side, Right-most node found! OR*/ /* Right side, Left-most node found!*/ if ((state == 1 && bb->node[link->node_number].l[1].node_number == 0xFFFFFFFF) || (state == 2 && bb->node[link->node_number].l[0].node_number == 0xFFFFFFFF)) { OCTAPI_BT0_LINK init_chosen_link; /* Release the current node (restore free node link-list)*/ bb->node[link_to_removed_node->node_number].next_free_node = bb->next_free_node; bb->next_free_node = link_to_removed_node->node_number; /* Save the link to the chosen node, because it is about to be deleted.*/ init_chosen_link = *link; /* Remove this node, and allow the tree to go on:*/ { OCTAPI_BT0_LINK init_child_link[2]; init_child_link[0] = bb->node[link->node_number].l[0]; init_child_link[1] = bb->node[link->node_number].l[1]; if (state == 1) *link = init_child_link[0]; else *link = init_child_link[1]; } /* Replace the removed node by this node.*/ { OCTAPI_BT0_LINK init_removed_child_link[2]; init_removed_child_link[0] = bb->node[link_to_removed_node->node_number].l[0]; init_removed_child_link[1] = bb->node[link_to_removed_node->node_number].l[1]; *link_to_removed_node = init_chosen_link; bb->node[init_chosen_link.node_number].l[0] = init_removed_child_link[0]; bb->node[init_chosen_link.node_number].l[1] = init_removed_child_link[1]; } return(GENERIC_OK); } else { /* Keep on going, we have not found the center most node yet!*/ if (state == 1) { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[1]), lkey, link_to_removed_node, state, NULL); if (result != GENERIC_OK) return(result); /* Refresh the link if our link is volatile.*/ if (volatile_grandparent_link != NULL) { link = &(bb->node[volatile_grandparent_link->node_number].l[0]); } } else { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[0]), lkey, link_to_removed_node, state, NULL); if (result != GENERIC_OK) return(result); /* Refresh the link if our link is volatile.*/ if (volatile_grandparent_link != NULL) { link = &(bb->node[volatile_grandparent_link->node_number].l[1]); } } } } /* We may have messed up the tree. So patch it!*/ /* Check if this node is unbalanced by 2. If so, rebalance it:*/ if (this_node->l[0].depth > (this_node->l[1].depth + 1) || this_node->l[1].depth > (this_node->l[0].depth + 1)) { OctApiBt0Rebalance(bb,link); } /* Always update the OCTAPI_BT0_LINK depth before exiting.*/ OctApiBt0UpdateLinkDepth(bb,link); return(GENERIC_OK); } #endif /* State:*/ /* 0 = seeking node to be removed.*/ /* 1 = node found, left branch taken.*/ /* 2 = node found, right branch taken.*/ #if !SKIP_OctApiBt0RemoveNode3 UINT32 OctApiBt0RemoveNode3(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link, UINT32 * lkey, OCTAPI_BT0_LINK * link_to_removed_node, UINT32 state, OCTAPI_BT0_LINK * volatile_grandparent_link, UINT32 *p_prev_node_number ) { UINT32 result; UINT32 *nkey; UINT32 *okey; OCTAPI_BT0_NODE * this_node; /* Get a pointer to this node.*/ this_node = &(bb->node[link->node_number]); if (state == 0) { if (link->node_number == 0xFFFFFFFF) /* We have an empty node. The node we were looking for does not exist.*/ { return(OCTAPI_BT0_KEY_NOT_IN_TREE); } else /* Current node is used, check for a match and a direction.*/ { UINT32 compare; /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { /* Check if the key is the biggest one encountered yet.*/ okey = &(bb->key[bb->key_size * (*p_prev_node_number)]); nkey = &(bb->key[bb->key_size * link->node_number]); /* If the node is key bigger then the old one, change the value.*/ if ( *nkey > *okey ) { if ( *nkey < *lkey ) *p_prev_node_number = link->node_number; } result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[0]), lkey, link_to_removed_node, 0, NULL); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { /* Check if the key is the biggest one encountered yet.*/ okey = &(bb->key[bb->key_size * (*p_prev_node_number)]); nkey = &(bb->key[bb->key_size * link->node_number]); /* If the node is key bigger then the old one, change the value.*/ if ( *nkey > *okey ) { if ( *nkey < *lkey ) *p_prev_node_number = link->node_number; } result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[1]), lkey, link_to_removed_node, 0, NULL); if (result != GENERIC_OK) return(result); } else { link_to_removed_node = link; /* Keep on going down to find a replacement node.*/ if (bb->node[link->node_number].l[0].node_number == 0xFFFFFFFF && bb->node[link->node_number].l[1].node_number == 0xFFFFFFFF) { /* Doe! No tree left! WHAT TO DO? */ /* Just delete the current node. That's it.*/ /* Release the current node (restore free node link-list)*/ bb->node[link->node_number].next_free_node = bb->next_free_node; bb->next_free_node = link->node_number; link->node_number = 0xFFFFFFFF; link->depth = 0; return(GENERIC_OK); } else if (bb->node[link->node_number].l[0].node_number != 0xFFFFFFFF) /* Left node is present. Go left, then permanently right.*/ { OCTAPI_BT0_NODE * removed_node_pnt; removed_node_pnt = &(bb->node[link->node_number]); result = OctApiBt0RemoveNode2(bb,&(removed_node_pnt->l[0]), lkey, link_to_removed_node, 1, link); if (result != GENERIC_OK) return(result); /* Caution! Once we are here, the link->node_pnt->l[0] has been modified,*/ /* but is about to be discarded! Save it quickly!*/ /* bb->node[link->node_number].l[0] = removed_node_pnt->l[0];*/ } else /* Right node is present. Go right, then permanently left.*/ { OCTAPI_BT0_NODE * removed_node_pnt; removed_node_pnt = &(bb->node[link->node_number]); result = OctApiBt0RemoveNode2(bb,&(removed_node_pnt->l[1]), lkey, link_to_removed_node, 2, link); if (result != GENERIC_OK) return(result); /* Caution! Once we are here, the link->node_pnt->l[0] has been modified,*/ /* but is about to be discarded! Save it quickly!*/ /* bb->node[link->node_number].l[1] = removed_node_pnt->l[1];*/ } } } } else { /* Check if the key is the biggest one encountered yet.*/ okey = &(bb->key[bb->key_size * (*p_prev_node_number)]); nkey = &(bb->key[bb->key_size * link->node_number]); /* If the node is key bigger then the old one, change the value.*/ if ( *nkey > *okey ) { if ( *nkey < *lkey ) *p_prev_node_number = link->node_number; } /* Left side, Right-most node found! OR*/ /* Right side, Left-most node found!*/ if ((state == 1 && bb->node[link->node_number].l[1].node_number == 0xFFFFFFFF) || (state == 2 && bb->node[link->node_number].l[0].node_number == 0xFFFFFFFF)) { OCTAPI_BT0_LINK init_chosen_link; /* Release the current node (restore free node link-list)*/ bb->node[link_to_removed_node->node_number].next_free_node = bb->next_free_node; bb->next_free_node = link_to_removed_node->node_number; /* Save the link to the chosen node, because it is about to be deleted.*/ init_chosen_link = *link; /* Remove this node, and allow the tree to go on:*/ { OCTAPI_BT0_LINK init_child_link[2]; init_child_link[0] = bb->node[link->node_number].l[0]; init_child_link[1] = bb->node[link->node_number].l[1]; if (state == 1) *link = init_child_link[0]; else *link = init_child_link[1]; } /* Replace the removed node by this node.*/ { OCTAPI_BT0_LINK init_removed_child_link[2]; init_removed_child_link[0] = bb->node[link_to_removed_node->node_number].l[0]; init_removed_child_link[1] = bb->node[link_to_removed_node->node_number].l[1]; *link_to_removed_node = init_chosen_link; bb->node[init_chosen_link.node_number].l[0] = init_removed_child_link[0]; bb->node[init_chosen_link.node_number].l[1] = init_removed_child_link[1]; } return(GENERIC_OK); } else { /* Keep on going, we have not found the center most node yet!*/ if (state == 1) { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[1]), lkey, link_to_removed_node, state, NULL); if (result != GENERIC_OK) return(result); /* Refresh the link if our link is volatile.*/ if (volatile_grandparent_link != NULL) { link = &(bb->node[volatile_grandparent_link->node_number].l[0]); } } else { result = OctApiBt0RemoveNode2(bb,&(bb->node[link->node_number].l[0]), lkey, link_to_removed_node, state, NULL); if (result != GENERIC_OK) return(result); /* Refresh the link if our link is volatile.*/ if (volatile_grandparent_link != NULL) { link = &(bb->node[volatile_grandparent_link->node_number].l[1]); } } } } /* We may have messed up the tree. So patch it!*/ /* Check if this node is unbalanced by 2. If so, rebalance it:*/ if (this_node->l[0].depth > (this_node->l[1].depth + 1) || this_node->l[1].depth > (this_node->l[0].depth + 1)) { OctApiBt0Rebalance(bb,link); } /* Always update the OCTAPI_BT0_LINK depth before exiting.*/ OctApiBt0UpdateLinkDepth(bb,link); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0RemoveNode UINT32 OctApiBt0RemoveNode(void * b,void * key) { OCTAPI_BT0 * bb; UINT32 result; UINT32 * lkey; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Attempt to remove the node. Only a "no hit" will cause an error.*/ result = OctApiBt0RemoveNode2(bb,&(bb->root_link), lkey, NULL, 0, NULL); if (result != GENERIC_OK) return(result); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0QueryNode2 UINT32 OctApiBt0QueryNode2(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link,UINT32 * lkey,UINT32 * node_number) { UINT32 result; if (link->node_number == 0xFFFFFFFF) /* We have an empty node. The node we were looking for does not exist.*/ { return(OCTAPI_BT0_KEY_NOT_IN_TREE); } else /* Current node is used, check for a match and a direction.*/ { UINT32 compare; /* Compare this node to the lkey.*/ compare = OctApiBt0KeyCompare(bb,link,lkey); if (compare == OCTAPI_BT0_LKEY_SMALLER) /* Go left.*/ { result = OctApiBt0QueryNode2(bb,&(bb->node[link->node_number].l[0]), lkey, node_number); if (result != GENERIC_OK) return(result); } else if (compare == OCTAPI_BT0_LKEY_LARGER) /* Go right.*/ { result = OctApiBt0QueryNode2(bb,&(bb->node[link->node_number].l[1]), lkey, node_number); if (result != GENERIC_OK) return(result); } else { /* A match!*/ *node_number = link->node_number; } } return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0QueryNode UINT32 OctApiBt0QueryNode(void * b,void * key,void ** data) { OCTAPI_BT0 * bb; UINT32 node_number; UINT32 result; UINT32 * lkey; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Get the node number.*/ result = OctApiBt0QueryNode2(bb,&(bb->root_link),lkey,&node_number); if (result != GENERIC_OK) return(result); /* Return the address of the data to the user.*/ if ( bb->data_size > 0 ) *data = (void *)(&(bb->data[bb->data_size * node_number])); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0GetFirstNode UINT32 OctApiBt0GetFirstNode(void * b,void ** key, void ** data) { OCTAPI_BT0 * bb; OCTAPI_BT0_NODE * node; UINT32 node_number; UINT32 * lkey; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Check if there are any keys present in the tree. */ if (bb->root_link.node_number == 0xFFFFFFFF) return OCTAPI_BT0_NO_NODES_AVAILABLE; node_number = bb->root_link.node_number; node = &bb->node[node_number]; /* Make our way down to the left-most node. */ while (node->l[0].node_number != 0xFFFFFFFF) { node_number = node->l[0].node_number; node = &bb->node[node_number]; } /* Return the address of the data to the user.*/ if ( bb->key_size > 0 ) *key = (void *)(&(bb->key[bb->key_size * node_number])); if ( bb->data_size > 0 ) *data = (void *)(&(bb->data[bb->data_size * node_number])); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0FindOrAddNode UINT32 OctApiBt0FindOrAddNode(void * b,void * key,void ** data, UINT32 *fnct_result) { OCTAPI_BT0 * bb; OCTAPI_BT0_NODE * new_node; UINT32 * lkey; UINT32 * nkey; UINT32 i; UINT32 new_node_number; UINT32 temp_node_number = 0; UINT32 result; UINT32 tree_already_full = FALSE; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Seize the node!*/ new_node_number = bb->next_free_node; /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Check that there is at least one block left.*/ if (bb->next_free_node != 0xFFFFFFFF) { temp_node_number = new_node_number; new_node = &(bb->node[new_node_number]); bb->next_free_node = new_node->next_free_node; /* Find the first UINT32 of the key.*/ nkey = &(bb->key[bb->key_size * new_node_number]); /* Copy the key.*/ for(i=0;ikey_size;i++) nkey[i] = lkey[i]; } else tree_already_full = TRUE; /* Signal that the tree was already full when the function was called.*/ /* Attempt to place the node. Only a "multiple hit" will cause an error.*/ result = OctApiBt0AddNode3(bb,&(bb->root_link), lkey, &new_node_number); switch( result ) { case GENERIC_OK: *fnct_result = OCTAPI0_BT0_NODE_ADDDED; break; case OCTAPI_BT0_KEY_ALREADY_IN_TREE: *fnct_result = OCTAPI0_BT0_NODE_FOUND; /* This attempt did not add a new node. Refree the node!*/ if ( tree_already_full == FALSE ) bb->next_free_node = temp_node_number; result = GENERIC_OK; break; default: break; } if (result != GENERIC_OK) { /* This attempt failed. Refree the node!*/ if ( tree_already_full == FALSE ) bb->next_free_node = new_node_number; /* Return the error code.*/ return(result); } /* Return the address of the data to the user.*/ if ( bb->data_size > 0 ) *data = (void *)(&(bb->data[bb->data_size * new_node_number])); return(GENERIC_OK); } #endif #if !SKIP_OctApiBt0AddNodeReportPrevNodeData UINT32 OctApiBt0AddNodeReportPrevNodeData(void * b,void * key,void ** data, void ** prev_data, PUINT32 fnct_result ) { OCTAPI_BT0 * bb; OCTAPI_BT0_NODE * new_node; UINT32 * lkey; UINT32 * nkey; UINT32 i; UINT32 new_node_number; UINT32 temp_node_number; UINT32 prev_node_number; UINT32 result; /* Load all!*/ bb = (OCTAPI_BT0 *)(b); OctApiBt0CorrectPointers(bb); /* Check that there is at least one block left.*/ if (bb->next_free_node == 0xFFFFFFFF) return(OCTAPI_BT0_NO_NODES_AVAILABLE); /* Seize the node!*/ new_node_number = bb->next_free_node; temp_node_number = new_node_number; new_node = &(bb->node[new_node_number]); bb->next_free_node = new_node->next_free_node; /* Set the previous node value */ prev_node_number = 0xFFFFFFFF; /* Register in the key and the data.*/ lkey = ((UINT32 *)key); /* Find the first UINT32 of the key.*/ nkey = &(bb->key[bb->key_size * new_node_number]); /* Copy the key.*/ for(i=0;ikey_size;i++) nkey[i] = lkey[i]; /* Attempt to place the node. Only a "multiple hit" will cause an error.*/ result = OctApiBt0AddNode4(bb,&(bb->root_link), lkey, &new_node_number, &prev_node_number, 0); switch( result ) { case GENERIC_OK: *fnct_result = OCTAPI0_BT0_NODE_ADDDED; break; case OCTAPI_BT0_KEY_ALREADY_IN_TREE: *fnct_result = OCTAPI0_BT0_NODE_FOUND; /* This attempt did not add a new node. Refree the node!*/ bb->next_free_node = temp_node_number; result = GENERIC_OK; break; default: break; } if (result != GENERIC_OK) { /* This attempt failed. Refree the node!*/ bb->next_free_node = new_node_number; /* Return the error code.*/ return(result); } /* Return the address of the data to the user.*/ if ( bb->data_size > 0 ) *data = (void *)(&(bb->data[bb->data_size * new_node_number])); if ( bb->data_size > 0 ) { if ( (prev_node_number != 0xFFFFFFFF) && (prev_node_number != OCTAPI_BT0_NO_SMALLER_KEY) && (*fnct_result == OCTAPI0_BT0_NODE_ADDDED)) *prev_data = ( void* )(&(bb->data[bb->data_size * prev_node_number])); else if ( prev_node_number == 0xFFFFFFFF ) *prev_data = ( void* )(&bb->invalid_value); else if ( prev_node_number == OCTAPI_BT0_NO_SMALLER_KEY ) *prev_data = ( void* )(&bb->no_smaller_key); } return(GENERIC_OK); } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/bt/octapi_bt0_private.h0000644000175000017500000000644211431317470025547 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_bt0_private.h Copyright (c) 2001 Octasic Inc. All rights reserved. Description: Library used to manage a binary tree of variable max size. Library is made to use one block of contiguous memory to manage the tree. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 11 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTAPI_BT0_PRIVATE_H__ #define __OCTAPI_BT0_PRIVATE_H__ #include "octdef.h" #define OCTAPI_BT0_LKEY_LARGER 0x0 #define OCTAPI_BT0_LKEY_SMALLER 0x1 #define OCTAPI_BT0_LKEY_EQUAL 0x2 typedef struct __OCTAPI_BT0_LINK__ { UINT32 node_number; UINT32 depth; } OCTAPI_BT0_LINK; typedef struct __OCTAPI_BT0_NODE__ { UINT32 next_free_node; /* Number of the next node in the free node link-list.*/ OCTAPI_BT0_LINK l[2]; /* 0 = left link; 1 = right link.*/ } OCTAPI_BT0_NODE; typedef struct __OCTAPI_BT0__ { UINT32 number_of_items; /* Number of items on total that can be allocated in the tree.*/ UINT32 key_size; /* Size is in UINT32s*/ UINT32 data_size; /* Size is in UINT32s*/ /* Empty node linked-list:*/ UINT32 next_free_node; /* 0xFFFFFFFF means that no nodes are free.*/ /* Tree as such:*/ OCTAPI_BT0_NODE * node; /* Array of nodes (number_of_items in size).*/ /* Tree root:*/ OCTAPI_BT0_LINK root_link; /* Associated key structure*/ UINT32 * key; /* Array of keys associated to NODEs.*/ /* Associated data structure.*/ UINT32 * data; /* Array of data associated to NODEs.*/ UINT32 invalid_value; UINT32 no_smaller_key; } OCTAPI_BT0; void OctApiBt0CorrectPointers( OCTAPI_BT0 * bb ); UINT32 OctApiBt0AddNode2( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * link, UINT32 * lkey, UINT32 new_node_number ); UINT32 OctApiBt0AddNode3( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * link, UINT32 * lkey, UINT32 *p_new_node_number ); UINT32 OctApiBt0AddNode4(OCTAPI_BT0 * bb,OCTAPI_BT0_LINK * link,UINT32 * lkey,UINT32 *p_new_node_number, UINT32 *p_prev_node_number, UINT32 state ); UINT32 OctApiBt0KeyCompare( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * link, UINT32 * lkey ); void OctApiBt0UpdateLinkDepth( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * link ); void OctApiBt0Rebalance( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * root_link ); void OctApiBt0ExternalHeavy( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * root_link ); UINT32 OctApiBt0RemoveNode2( OCTAPI_BT0 * bb, OCTAPI_BT0_LINK * link, UINT32 * lkey, OCTAPI_BT0_LINK * link_to_removed_node, UINT32 state, OCTAPI_BT0_LINK * volatile_grandparent_link ); #endif /*__OCTAPI_BT0_PRIVATE_H__*/ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/largmath/0000755000175000017500000000000011631523356023010 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/largmath/octapi_largmath.c0000644000175000017500000004215511431317470026315 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_largmath.h Copyright (c) 2001-2007 Octasic Inc. Description: Library used to perform arithmetic on integer values of an integer multiple of 32-bits. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 10 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #include "apilib/octapi_largmath.h" /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmAdd. | | Description: This function adds 2 numbers, a and b. Number a is | (alen + 1) * 32 bits long; b is (blen + 1) * 32 bits long. The | result is (zlen + 1) * 32 bits long. It the function succeeds it returns | GENERIC_OK, else GENERIC_ERROR. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *a UINT32 The array containing the first number. | alen USHORT The length of array a, minus 1 (0 - 99). | *b UINT32 The array containing the second number. | blen USHORT The length of array b, minus 1 (0 - 99). | *z UINT32 The array containing the resulting number. | zlen USHORT The length of array z, minus 1 (0 - 99). | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmAdd UINT32 OctApiLmAdd(UINT32 * a,USHORT alen,UINT32 * b,USHORT blen,UINT32 * z, USHORT zlen) { USHORT i; UINT32 temp; UINT32 carry=0; UINT32 aprim; UINT32 bprim; /* Check for array lengths.*/ if (alen > zlen || blen > zlen) return(OCTAPI_LM_ARRAY_SIZE_MISMATCH); for(i=0;i<=zlen;i++) { if (i <= alen) aprim = *(a+i); else aprim = 0; if (i <= blen) bprim = *(b+i); else bprim = 0; temp = aprim + bprim + carry; /* Calculate carry for next time.*/ if (carry == 0) if (temp < aprim) carry = 1; else carry = 0; else if (temp <= aprim) carry = 1; else carry = 0; /* Write new value.*/ *(z+i) = temp; } /* Check for overflow.*/ if (carry == 1) return(OCTAPI_LM_OVERFLOW); /* All is well.*/ return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmSubtract. | | Description: This function subtracts 2 numbers, a and b. Number a is | (alen + 1) * 32 bits long; b is (blen + 1) * 32 bits long. The result | is (zlen + 1) * 32 bits long. It the function succeeds it returns | GENERIC_OK, else GENERIC_ERROR. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *a UINT32 The array containing the first number. | alen USHORT The length of array a, minus 1 (0 - 99). | *bneg UINT32 The array containing the second number. | blen USHORT The length of array b, minus 1 (0 - 99). | *z UINT32 The array containing the resulting number. | zlen USHORT The length of array z, minus 1 (0 - 99). | *neg USHORT Indicates if the result is negative | (TRUE/FALSE). | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmSubtract UINT32 OctApiLmSubtract(UINT32 * a,USHORT alen,UINT32 * bneg,USHORT blen,UINT32 * z,USHORT zlen,USHORT * neg) { USHORT i; UINT32 temp; UINT32 carry=1; UINT32 aprim; UINT32 bprim; /* Check for array lengths.*/ if (alen > zlen || blen > zlen) return(OCTAPI_LM_ARRAY_SIZE_MISMATCH); for(i=0;i<=zlen;i++) { if (i <= alen) aprim = *(a+i); else aprim = 0; if (i <= blen) bprim = ~(*(bneg+i)); else bprim = 0xFFFFFFFF; temp = aprim + bprim + carry; /* Calculate carry for next time.*/ if (carry == 0) if (temp < aprim) carry = 1; else carry = 0; else if (temp <= aprim) carry = 1; else carry = 0; /* Write new value.*/ *(z+i) = temp; } /* Check for overflow, which means negative number!*/ if (carry == 0) { /* Number is not of right neg. Invert and add one to correct neg.*/ for(i=0;i<=zlen;i++) *(z+i) = ~(*(z+i)); temp = 1; OctApiLmAdd(&temp,0,z,zlen,z,zlen); *neg = TRUE; return(GENERIC_OK); } /* Result is positive.*/ *neg = FALSE; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmCompare. | | Description: This function compares two numbers (arrays) of equal lengths. | Number a is (alen + 1) * 32 bits long; b is (blen + 1) * 32 bits long. The result | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *a UINT32 The array containing the first number. | alen USHORT The length of array a, minus 1 (0 - 99). | *b UINT32 The array containing the second number. | blen USHORT The length of array b, minus 1 (0 - 99). | *neg USHORT Result of compare. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmCompare UINT32 OctApiLmCompare(UINT32 * a,USHORT alen,UINT32 * bneg,USHORT blen,USHORT * neg) { USHORT i; UINT32 temp; UINT32 carry=1; UINT32 aprim; UINT32 bprim; UINT32 zlen; /* Set zlen to alen or blen (which ever is longer)*/ if (alen < blen) zlen = blen; else zlen = alen; for(i=0;i<=zlen;i++) { if (i <= alen) aprim = *(a+i); else aprim = 0; if (i <= blen) bprim = ~(*(bneg+i)); else bprim = 0xFFFFFFFF; temp = aprim + bprim + carry; /* Calculate carry for next time.*/ if (carry == 0) if (temp < aprim) carry = 1; else carry = 0; else if (temp <= aprim) carry = 1; else carry = 0; } /* Check for overflow, which means negative number!*/ if (carry == 0) { *neg = TRUE; return(GENERIC_OK); } /* Result is positive.*/ *neg = FALSE; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmSubtract. | | Description: This function multiplies 2 numbers, a and b. Number a and | b are both (ablen + 1) * 32 bits long. The result is twice as | long. If the functions succeeds if returns GENERIC_OK, | else GENERIC_ERROR. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *a UINT32 The array containing the first number. | *b UINT32 The array containing the second number. | ablen USHORT The length of arrays a and b, minus 1 (0 - 99). | *z UINT32 The array containing the resulting number. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmMultiply UINT32 OctApiLmMultiply(UINT32 * a,UINT32 * b,USHORT ablen,UINT32 * z) { USHORT i,j,k; USHORT nos; UINT32 lownum; UINT32 highnum; USHORT longnumi; USHORT longnumj; USHORT indentw,indentl; /* Caculate number of shorts in a and b.*/ nos = (USHORT)((ablen+1) * 2); /* Clear answer word.*/ for(i=0;i OCTAPI_LM_MAX_OPTIMIZE_MUL) optimizea = FALSE; if(*b > OCTAPI_LM_MAX_OPTIMIZE_MUL) optimizeb = FALSE; if(optimizea == TRUE) { for(l = 0; l < *a; l++) OctApiLmAdd(z, (USHORT)(nos-1), b, ablen, z, (USHORT)(nos-1)); return(GENERIC_OK); } if(optimizeb == TRUE) { for(l = 0; l < *b; l++) OctApiLmAdd(z, (USHORT)(nos-1), a, ablen, z, (USHORT)(nos-1)); return(GENERIC_OK); } } for(i=0;i>16; /* Odd word. Upper part of long.*/ for(j=0;j>16; /* Odd word. Upper part of long.*/ /* Find the word indent of the answer. 0 = no indent. 1 = one word indent.*/ indentw = (USHORT)( j+i ); indentl = (USHORT)( indentw / 2 ); /* Multiply both numbers.*/ product = highnum * lownum; /* After multiplying both numbers, add result to end result.*/ if ((indentw % 2) == 0) /* Even word boundary, addition in one shot!*/ { UINT32 carry=0; UINT32 temp; UINT32 addme; for(k=indentl;k>16; else addme = 0; temp = *(z+k) + addme + carry; /* Calculate carry for next time.*/ if (carry == 0) if (temp < addme) carry = 1; else carry = 0; else if (temp <= addme) carry = 1; else carry = 0; /* Set value.*/ *(z+k) = temp; } /* Carry should always be 0.*/ if (carry == 1) return(GENERIC_ERROR); } } } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmDivide. | | Description: This function divides the number n by the number d. The | quotient is placed in q and the remainder in r. The arrays | n, d, q and r are all of the same length, namely (ndqrlen + 1). | If the functions succeeds if returns GENERIC_OK, else | GENERIC_ERROR. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *a UINT32 The array containing the first number. | *b UINT32 The array containing the second number. | ablen USHORT The length of arrays a and b, minus 1 (0 - 99). | *z UINT32 The array containing the resulting number. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmDivide UINT32 OctApiLmDivide(UINT32 * n,UINT32 * d,UINT32 * q,UINT32 * r,USHORT ndqrlen) { /* Proceedure for division:*/ /* r = n*/ /* q = 0*/ /* shift = initial_denominator_shift (for upper '1's to be in same bit position).*/ /* d <<= shift;*/ /* Start loop:*/ /* compare r and d*/ /* if r > d then*/ /* r -= d;*/ /* write a '1' to bit "shift" of array q.*/ /* end if;*/ /* if shift == 0 then*/ /* return;*/ /* else*/ /* shift--;*/ /* d>>=1;*/ /* goto "Start loop:"*/ /* end if;*/ UINT32 i; UINT32 result; USHORT shift,n_msb,d_msb; USHORT neg; USHORT ConditionFlag = TRUE; /* r = n*/ for(i=0;i<=ndqrlen;i++) *(r+i) = *(n+i); /* q = 0*/ for(i=0;i<=ndqrlen;i++) *(q+i) = 0; /* shift = initial_denominator_shift (for upper '1's to be in same bit position).*/ result = OctApiLmGetMsb(d,ndqrlen,&d_msb); if (result != GENERIC_OK) return(result); result = OctApiLmGetMsb(n,ndqrlen,&n_msb); if (result != GENERIC_OK) return(result); if (d_msb == 0xFFFF) /* Division by 0.*/ return(OCTAPI_LM_DIVISION_BY_ZERO); if (n_msb == 0xFFFF) /* 0/n, returns 0 R 0.*/ return(GENERIC_OK); if (n_msb < d_msb) /* x/y, where x is smaller than y, returns 0 R x.*/ return(GENERIC_OK); shift = (USHORT)( n_msb - d_msb ); /* Shift d to match n highest bit position.*/ result = OctApiLmShiftn(d,ndqrlen,TRUE,shift); if (result != GENERIC_OK) return(result); /* Start loop:*/ while( ConditionFlag == TRUE ) { /* compare r and d*/ result = OctApiLmCompare(r,ndqrlen,d,ndqrlen,&neg); if (result != GENERIC_OK) return(result); if (neg == FALSE) /* Subtraction can be done(do it).*/ { /* r -= d;*/ result = OctApiLmSubtract(r,ndqrlen,d,ndqrlen,r,ndqrlen,&neg); if (result != GENERIC_OK) return(result); /* write a '1' to bit "shift" of array q.*/ *(q+(shift/32)) |= (UINT32)0x1 << (shift%32); } /* if shift == 0 then*/ /* return;*/ if (shift == 0) return(GENERIC_OK); /* shift--;*/ /* d>>=1;*/ /* goto "Start loop:"*/ shift--; OctApiLmShiftRight1(d,ndqrlen); } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: octapi_lm_shifright1. | | Description: The function is for internal use only. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | N/A. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmShiftRight1 UINT32 OctApiLmShiftRight1(UINT32 * a,USHORT alen) { UINT32 i; /* Start with lower long and move up by one long each time,*/ /* shifting each long to the right by one bit. The upper bit*/ /* of the next long will have to be concatenated each time a*/ /* loop is executed. For the last long, leave the highest bit*/ /* intact.*/ for(i=0;i>=1; /* Shift long by one to the right.*/ *(a+i)|=*(a+i+1)<<31; } *(a+alen)>>=1; /* Shift last long, leaving it's highest bit at 0.*/ return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmShiftn. | | Description: The function is for internal use only. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | N/A. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmShiftn UINT32 OctApiLmShiftn(UINT32 * a,USHORT alen,USHORT shiftleft,USHORT shiftn) { UINT32 i; USHORT long_offset; USHORT bit_offset; long_offset = (USHORT)( shiftn / 32 ); bit_offset = (USHORT)( shiftn % 32 ); if (shiftleft == TRUE) /* Shift left.*/ { for(i=alen;i<=alen;i--) { /* Fill upper bits of long.*/ if (i >= long_offset) *(a+i) = *(a+i-long_offset) << bit_offset; else *(a+i) = 0; /* Fill lower bits of long.*/ if (i > long_offset && bit_offset != 0) *(a+i) |= *(a+i-long_offset-1) >> (32-bit_offset); } } else /* Shift right.*/ { for(i=0;i<=alen;i++) { /* Fill lower bits of long.*/ if ((alen-i) >= long_offset) *(a+i) = *(a+i+long_offset) >> bit_offset; else *(a+i) = 0; /* Fill upper bits of long.*/ if ((alen-i) > long_offset && bit_offset != 0) *(a+i) |= *(a+i+long_offset+1) << (32-bit_offset); } } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLmGetMsb. | | Description: The function is for internal use only. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | N/A. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLmGetMsb UINT32 OctApiLmGetMsb(UINT32 * a,USHORT alen,USHORT * msb_pos) { UINT32 i,j; UINT32 x; for(i=alen;i<=alen;i--) { if (*(a+i) == 0) continue; x = *(a+i); for(j=31;j<=31;j--) { /* Test for bit being '1'.*/ if ((x & 0x80000000) != 0) { *msb_pos=(USHORT)(j+(32*i)); return(GENERIC_OK); } /* Shift bit one bit position, and try again.*/ x<<=1; } } /* MSB not found.*/ *msb_pos = 0xFFFF; return(GENERIC_OK); } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/llman/0000755000175000017500000000000011631523356022314 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/llman/octapi_llman.c0000644000175000017500000026256111431317470025132 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_llman.c Copyright (c) 2001-2007 Octasic Inc. Description: Library used to manage allocation tables and linked lists. The library is made such that only a block of contiguous memory is needed for the management of the linked list/allocation table. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 22 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #include "octapi_llman_private.h" #include "apilib/octapi_llman.h" #include "apilib/octapi_largmath.h" /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctapiLlmAllocGetSize. | | Description: This function determines the amount of memory needed to | manage the allocation of a fixed amount of resources. | The memory is measured in bytes. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | number_of_items UINT32 The number of resources to be allocated. | *l_size UINT32 UINT32 The amount of memory needed, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctapiLlmAllocGetSize UINT32 OctapiLlmAllocGetSize(UINT32 number_of_items,UINT32 * l_size) { if (number_of_items == 0) return(GENERIC_BAD_PARAM); *l_size = (sizeof(LLM_ALLOC)) + (number_of_items * sizeof(UINT32)); return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctapiLlmAllocInit. | | Description: This function intializes the LLM_ALLOC structure. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | **l void The memory used by the LLM_ALLOC structure. | number_of_items UINT32 The number of resources to be allocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctapiLlmAllocInit UINT32 OctapiLlmAllocInit(void ** l,UINT32 number_of_items) { LLM_ALLOC* ls; UINT32 i; /* Check the number of items required.*/ if (number_of_items == 0) return(GENERIC_BAD_PARAM); /* If no memory has been allocated yet:*/ if (*l == NULL) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Build the structure before starting.*/ ls = (LLM_ALLOC *)(*l); ls->linked_list = (UINT32 *)((BYTE *)ls + sizeof(LLM_ALLOC)); ls->number_of_items = number_of_items; /* Linked list links all structures in ascending order.*/ for(i=0;ilinked_list[i] = i+1; } ls->linked_list[number_of_items - 1] = 0xFFFFFFFF; /* Invalid link.*/ /* Next avail is 0.*/ ls->next_avail_num = 0; /* Number of allocated items is null.*/ ls->allocated_items = 0; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctapiLlmAllocInfo. | | Description: This function returns the number of free and allocated | block in the LLMAN list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | *allocated_items UINT32 Number of allocated items. | *available_items UINT32 Number of available items. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctapiLlmAllocInfo UINT32 OctapiLlmAllocInfo(void * l,UINT32 * allocated_items,UINT32 * available_items) { LLM_ALLOC* ls; /* Build the structure before starting.*/ ls = (LLM_ALLOC *)l; ls->linked_list = (UINT32 *)((BYTE *)ls + sizeof(LLM_ALLOC)); *allocated_items = ls->allocated_items; *available_items = ls->number_of_items - ls->allocated_items; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctapiLlmAllocInfo. | | Description: This function allocates the resource indicated by blocknum. | If the resource can be allocated then GENERIC_OK is returned. | Else an error. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | *block_num UINT32 The resource to be allocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctapiLlmAllocAlloc UINT32 OctapiLlmAllocAlloc(void * l,UINT32 * blocknum) { LLM_ALLOC* ls; UINT32 allocated_block; UINT32* node; /* Build the structure before starting.*/ ls = (LLM_ALLOC *)l; ls->linked_list = (UINT32 *)((BYTE *)ls + sizeof(LLM_ALLOC)); /* Get next available block number.*/ allocated_block = ls->next_avail_num; /* Check if block is invalid.*/ if (allocated_block == 0xFFFFFFFF) { /* Make blocknum NULL.*/ *blocknum = 0xFFFFFFFF; return(OCTAPI_LLM_NO_STRUCTURES_LEFT); } node = &ls->linked_list[allocated_block]; /* Copy next block number.*/ ls->next_avail_num = *node; /* Tag as used the current block number.*/ *node = 0xFFFFFFFE; /* Return proper block number.*/ *blocknum = allocated_block; /* Update block usage number.*/ ls->allocated_items++; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctapiLlmAllocDealloc. | | Description: This function deallocates the resource indicated by blocknum. | If the resource is not already allocated an error is returned. | Else GENERIC_OK is returned. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | block_num UINT32 The resource to be deallocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctapiLlmAllocDealloc UINT32 OctapiLlmAllocDealloc(void * l,UINT32 blocknum) { LLM_ALLOC* ls; UINT32* node; /* Build the structure before starting.*/ ls = (LLM_ALLOC *)l; ls->linked_list = (UINT32 *)((BYTE *)ls + sizeof(LLM_ALLOC)); /* Check for null item pointer.*/ if (blocknum == 0xFFFFFFFF) return(GENERIC_OK); /* Check if blocknum is within specified item range.*/ if (blocknum >= ls->number_of_items) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); node = &ls->linked_list[blocknum]; /* Check if block is really used as of now.*/ if (*node != 0xFFFFFFFE) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Add link to list.*/ *node = ls->next_avail_num; /* Point to returned block.*/ ls->next_avail_num = blocknum; /* Update block usage number.*/ ls->allocated_items--; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmAllocGetSize. | | Description: This function determines the amount of memory needed to | manage the allocation of a fixed amount of resources. | The memory is measured in bytes. | | This version is a time manage version of llman. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | number_of_items UINT32 The number of resources to be allocated. | *l_size UINT32 UINT32 The amount of memory needed, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmAllocGetSize UINT32 OctApiTllmAllocGetSize(UINT32 number_of_items,UINT32 * l_size) { if (number_of_items == 0) return(GENERIC_BAD_PARAM); *l_size = (sizeof(TLLM_ALLOC)) + (number_of_items * sizeof(TLLM_ALLOC_NODE)); return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmAllocInit. | | Description: This function intializes the TLLM_ALLOC structure. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | **l void The memory used by the LLM_ALLOC structure. | number_of_items UINT32 The number of resources to be allocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmAllocInit UINT32 OctApiTllmAllocInit(void ** l,UINT32 number_of_items) { TLLM_ALLOC* ls; UINT32 i; /* Check the number of items required.*/ if (number_of_items == 0) return(GENERIC_BAD_PARAM); /* If no memory has been allocated yet.*/ if (*l == NULL) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Build the structure before starting.*/ ls = (TLLM_ALLOC *)(*l); ls->linked_list = (TLLM_ALLOC_NODE *)((BYTE *)ls + sizeof(TLLM_ALLOC)); ls->number_of_items = number_of_items; /* Linked list links all structures in ascending order.*/ for(i=0;ilinked_list[i].value = i+1; } ls->linked_list[number_of_items - 1].value = 0xFFFFFFFF; /* Invalid link.*/ /* Next avail is 0.*/ ls->next_avail_num = 0; /* Number of allocated items is null.*/ ls->allocated_items = 0; /* Set the number of timeout entry.*/ ls->number_of_timeout = 0; /* Next timeout is 0.*/ ls->next_timeout_num = 0xFFFFFFFF; ls->last_timeout_num = 0xFFFFFFFF; /* Set the known time to 0.*/ ls->last_known_time[ 0 ] = 0; ls->last_known_time[ 1 ] = 0; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmAllocInfo. | | Description: This function returns the number of free and allocated | block in the TLLMAN list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | *allocated_items UINT32 Number of allocated items. | *available_items UINT32 Number of available items. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmAllocInfo UINT32 OctApiTllmAllocInfo(void * l,UINT32 * allocated_items,UINT32 * available_items) { TLLM_ALLOC* ls; /* Build the structure before starting.*/ ls = (TLLM_ALLOC *)l; *allocated_items = ls->allocated_items; *available_items = ls->number_of_items - ls->allocated_items; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmAllocAlloc. | | Description: This function allocates the resource indicated by blocknum. | If the resource can be allocated then GENERIC_OK is returned. | Else an error. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | *block_num UINT32 The resource to be allocated. | *current_time UINT32 | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmAllocAlloc UINT32 OctApiTllmAllocAlloc(void * l,UINT32 * blocknum, UINT32 *current_time) { TLLM_ALLOC* ls; UINT32 allocated_block; TLLM_ALLOC_NODE* node; /* Build the structure before starting.*/ ls = (TLLM_ALLOC *)l; ls->linked_list = (TLLM_ALLOC_NODE *)((BYTE *)ls + sizeof(TLLM_ALLOC)); if ( ls->allocated_items == ls->number_of_items && ls->next_timeout_num != 0xFFFFFFFF ) { UINT32 l_ulResult; l_ulResult = OctApiTllmCheckTimeoutList( ls, current_time ); if ( l_ulResult != GENERIC_OK ) return l_ulResult; } /* Get next available block number.*/ allocated_block = ls->next_avail_num; /* Check if block is invalid.*/ if (allocated_block == 0xFFFFFFFF) { /* Make blocknum NULL.*/ *blocknum = 0xFFFFFFFF; return(OCTAPI_LLM_NO_STRUCTURES_LEFT); } node = &ls->linked_list[allocated_block]; /* Copy next block number.*/ ls->next_avail_num = node->value; /* Tag as used the current block number.*/ node->value = 0xFFFFFFFE; /* Return proper block number.*/ *blocknum = allocated_block; /* Update block usage number.*/ ls->allocated_items++; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmAllocDealloc. | | Description: This function deallocates the resource indicated by blocknum. | If the resource is not already allocated an error is returned. | Else GENERIC_OK is returned. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_ALLOC structure. | block_num UINT32 The resource to be deallocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmAllocDealloc UINT32 OctApiTllmAllocDealloc(void * l,UINT32 blocknum, UINT32 timeout_value, UINT32 current_time[2]) { TLLM_ALLOC* ls; TLLM_ALLOC_NODE* node; UINT32 l_ulResult; /* Build the structure before starting.*/ ls = (TLLM_ALLOC *)l; ls->linked_list = (TLLM_ALLOC_NODE *)((BYTE *)ls + sizeof(TLLM_ALLOC)); /* Check for null item pointer.*/ if (blocknum == 0xFFFFFFFF) return(GENERIC_OK); /* Check if blocknum is within specified item range.*/ if (blocknum >= ls->number_of_items) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if ( ls->next_timeout_num != 0xFFFFFFFF ) { l_ulResult = OctApiTllmCheckTimeoutList( ls, current_time ); if ( l_ulResult != GENERIC_OK ) return l_ulResult; } node = &ls->linked_list[blocknum]; /* Check if block is really used as of now.*/ if (node->value != 0xFFFFFFFE) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Add link to timeout list.*/ if ( ls->last_timeout_num != 0xFFFFFFFF ) { TLLM_ALLOC_NODE* last_node; /* insert the node at the end of the list.*/ node->value = 0xFFFFFFFF; last_node = &ls->linked_list[ ls->last_timeout_num ]; last_node->value = blocknum; } else { /* The node is alone in the list.*/ node->value = 0xFFFFFFFF; ls->next_timeout_num = blocknum; } ls->last_timeout_num = blocknum; ls->number_of_timeout++; /* Set the timeout time of the node.*/ l_ulResult = OctApiLmAdd( current_time, 1, &timeout_value, 0, node->timeout, 1 ); if (l_ulResult != GENERIC_OK) return(l_ulResult); return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiTllmCheckTimeoutList. | | Description: This function will verify if the timeout time | of all the node present in the timeout list are bigger | then the current time. If so the node will be returned | ot the free node list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *ls TLLM_ALLOC The memory used by the TLLM_ALLOC structure. | current_time UINT32[2] The current time in msec. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiTllmCheckTimeoutList UINT32 OctApiTllmCheckTimeoutList(TLLM_ALLOC *ls, UINT32 current_time[2]) { UINT32 result; UINT32 fConditionFlag = TRUE; /* Free-up any pending memory before trying the allocation:*/ if ((ls->last_known_time[0] != current_time[0] || ls->last_known_time[1] != current_time[1]) && (current_time[1] != 0 || current_time[0] != 0)) /* Time has changed.*/ { TLLM_ALLOC_NODE *pcurrent_node; UINT32 current_num; USHORT neg; /* Remember time for next time!*/ ls->last_known_time[0] = current_time[0]; ls->last_known_time[1] = current_time[1]; while ( fConditionFlag == TRUE ) { /* Get a node from the timeout list.*/ pcurrent_node = &ls->linked_list[ ls->next_timeout_num ]; current_num = ls->next_timeout_num; /* Check if first node has timeout.*/ result = OctApiLmCompare(current_time,1,pcurrent_node->timeout ,1,&neg); if (result != GENERIC_OK) return(result); /* if the timeout tiem was exceeded, set the block as free.*/ if ( neg == FALSE ) { /* set the next node pointer.*/ ls->next_timeout_num = pcurrent_node->value; ls->number_of_timeout--; /* reset the last pointer of the timeout list.*/ if ( ls->number_of_timeout == 0 ) ls->last_timeout_num = 0xFFFFFFFF; /* return the node the free list.*/ pcurrent_node->value = ls->next_avail_num; ls->next_avail_num = current_num; ls->allocated_items--; } else /* node not in timeout */ { fConditionFlag = FALSE; break; } if ( ls->next_timeout_num == 0xFFFFFFFF ) { fConditionFlag = FALSE; break; /* end of timeout list.*/ } } } return(GENERIC_OK); } #endif /**************************************** llm_alloc section **********************************************/ /**************************************** llm_list section **********************************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListGetSize | | Description: This function determines the amount of memory needed by | the LLM_LIST structure to manage the allocation of | number_of_items number of resources. The memory is | measured in bytes. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | number_of_items UINT32 The number of resources to be allocated | amongst all linked-lists. | number_of_lists UINT32 The maximum number of linked-lists that | can be allocated. | *l_size UINT32 UINT32 The amount of memory needed, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListGetSize UINT32 OctApiLlmListGetSize(UINT32 number_of_items,UINT32 number_of_lists,UINT32 user_info_size,UINT32 * l_size) { UINT32 head_alloc_size; UINT32 result; UINT32 user_info_size_roundup; if (number_of_items == 0) return(GENERIC_BAD_PARAM); if (number_of_lists == 0) return(GENERIC_BAD_PARAM); if (user_info_size == 0) return(GENERIC_BAD_PARAM); user_info_size_roundup = ((user_info_size + 3) / 4) * 4; result = OctapiLlmAllocGetSize(number_of_lists,&head_alloc_size); if(result != GENERIC_OK) return(result); *l_size = sizeof(LLM_LIST) + (number_of_lists * sizeof(LLM_LIST_HEAD)) + head_alloc_size + (number_of_items * (sizeof(LLM_LIST_ITEM) + user_info_size_roundup - 4)); return(GENERIC_OK); } #endif #if !SKIP_OctApiLlmListGetItemPointer LLM_LIST_ITEM * OctApiLlmListGetItemPointer(LLM_LIST * ls, UINT32 item_number) { return (LLM_LIST_ITEM *) (((BYTE *)ls->li) + (ls->item_size * item_number)) ; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListInit. | | Description: This function intializes the LLM_TALLOC structure. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | number_of_items UINT32 The number of resources to be allocated | amongst all linked-lists. | number_of_lists UINT32 The maximum number of linked-lists that | can be allocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListInit UINT32 OctApiLlmListInit(void ** l,UINT32 number_of_items,UINT32 number_of_lists,UINT32 user_info_size) { LLM_LIST* ls; LLM_LIST_ITEM* item; UINT32 i; UINT32 head_alloc_size; UINT32 result; UINT32 user_info_size_roundup; UINT32 total_lists; BYTE* lsbyte; if (number_of_items == 0) return(GENERIC_BAD_PARAM); if (number_of_lists == 0) return(GENERIC_BAD_PARAM); if (user_info_size == 0) return(GENERIC_BAD_PARAM); user_info_size_roundup = ((user_info_size + 3) / 4) * 4; /* Get the size of the Alloc structure used to manage head of list structures.*/ result = OctapiLlmAllocGetSize(number_of_lists,&head_alloc_size); if(result != GENERIC_OK) return(result); if (*l == NULL) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Built the structure based on the base address:*/ ls = (LLM_LIST *)(*l); lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /* Initialize parameters in the structure.*/ ls->head_alloc_size = head_alloc_size; ls->user_info_bytes = user_info_size; ls->user_info_size = user_info_size_roundup; ls->total_items = number_of_items; ls->assigned_items = 0; ls->total_lists = number_of_lists; ls->assigned_lists = 0; ls->next_empty_item = 0; ls->item_size = sizeof(LLM_LIST_ITEM) + user_info_size_roundup - 4; /* Complete the build!*/ ls = (LLM_LIST *)(*l); lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /* Initialize the head of queue Alloc structure.*/ result = OctapiLlmAllocInit(&(ls->list_head_alloc),number_of_lists); if(result != GENERIC_OK) return(result); /* Initialize the linked list of the items:*/ for(i=0; ili + ls->item_size * i); if (i == (number_of_items - 1)) item->forward_link = 0xFFFFFFFF; else item->forward_link = i + 1; } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListInfo. | | Description: This function returns the status of the LLM_LIST structure. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *allocated_lists UINT32 The number of linked_lists allocated. | *free_lists UINT32 The number of linked_lists still free. | *allocated_items UINT32 The number of items allocated to lists. | *free_items UINT32 The number of items still free. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListInfo UINT32 OctApiLlmListInfo(void * l,UINT32 * allocated_lists,UINT32 * allocated_items, UINT32 * free_lists,UINT32 * free_items) { LLM_LIST* ls; BYTE* lsbyte; UINT32 total_lists; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); *allocated_items = ls->assigned_items; *free_items = ls->total_items - ls->assigned_items; *allocated_lists = ls->assigned_lists; *free_lists = ls->total_lists - ls->assigned_lists; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListCreate. | | Description: This function creates a linked list. The target which is | allocated the newly created list can request additions | or removals from the list later on. To target identifies | its list with the returned list handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the new list, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListCreate UINT32 OctApiLlmListCreate(void * l,UINT32 * list_handle) { LLM_LIST* ls; LLM_LIST_HEAD* lh; UINT32 blocknum; UINT32 total_lists; UINT32 result; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /* Get a list using the list head alloc structure.*/ result = OctapiLlmAllocAlloc(ls->list_head_alloc, &blocknum); if (result != GENERIC_OK) return(result); /* The handle is the block number.*/ *list_handle = blocknum; /* Initialize the list head structure.*/ lh = &ls->lh[blocknum]; lh->list_length = 0; lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; lh->cache_item_number = 0xFFFFFFFF; lh->cache_item_pointer = 0xFFFFFFFF; ls->assigned_lists++; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListDelete. | | Description: This function deletes the linked list indicated by the | handle list_handle. Any items which are still allocated | to the list are first deallocated. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the list. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListDelete UINT32 OctApiLlmListDelete(void * l,UINT32 list_handle) { LLM_LIST* ls; LLM_LIST_HEAD* lh; UINT32 total_lists; UINT32 result; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); if (list_handle >= ls->total_lists) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (ls->lh[list_handle].list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /* Release internal list header handle...*/ result = OctapiLlmAllocDealloc(ls->list_head_alloc,list_handle); if (result != GENERIC_OK) return(result); lh = &ls->lh[list_handle]; /* Deallocate all items in the list!*/ if (lh->list_length != 0) { LLM_LIST_ITEM * item; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->tail_pointer); /* Release the items using only the links.*/ item->forward_link = ls->next_empty_item; ls->next_empty_item = lh->head_pointer; /* Remove items from item counter.*/ ls->assigned_items -= lh->list_length; } lh->list_length = 0xFFFFFFFF; lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; lh->cache_item_number = 0xFFFFFFFF; lh->cache_item_pointer = 0xFFFFFFFF; ls->assigned_lists--; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListLength. | | Description: This function returns the number of items allocated to the | list indicated by the handle list_handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | list_handle UINT32 The handle to the list. | *number_of_items UINT32 The number of items in the list, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListLength UINT32 OctApiLlmListLength(void * l,UINT32 list_handle, UINT32 * number_of_items_in_list) { LLM_LIST* ls; LLM_LIST_HEAD* lh; UINT32 total_lists; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; if (list_handle >= ls->total_lists) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); *number_of_items_in_list = lh->list_length; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListItemData | | Description: This function returns a pointer to the user data associated | with an item. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | list_handle UINT32 The handle to the list. | item_number UINT32 The number of the list node in question. | **item_data_pnt void The pointer to the user data, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListItemData UINT32 OctApiLlmListItemData(void * l,UINT32 list_handle,UINT32 item_number,void ** item_data_pnt) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* item; UINT32 cur_list_pnt; UINT32 cur_list_num; UINT32 total_lists; UINT32 list_length; BYTE* lsbyte; UINT32 fConditionFlag = TRUE; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; list_length = lh->list_length; *item_data_pnt = NULL; if (list_handle >= ls->total_lists) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); if (list_length <= item_number) return(OCTAPI_LLM_ELEMENT_NOT_FOUND); /* Determine where the search will start.*/ if (list_length == (item_number + 1)) /* Last item in list:*/ { cur_list_pnt = lh->tail_pointer; cur_list_num = item_number; } else if (lh->cache_item_number <= item_number) /* Start at cache:*/ { cur_list_pnt = lh->cache_item_pointer; cur_list_num = lh->cache_item_number; } else /* Start at beginning:*/ { cur_list_pnt = lh->head_pointer; cur_list_num = 0; } /* Start search from cur_list_pnt and cur_list_num.*/ while ( fConditionFlag == TRUE ) { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); if (cur_list_num == item_number) /* Item number found.*/ { /* Write new cache entry.*/ lh->cache_item_pointer = cur_list_pnt; lh->cache_item_number = cur_list_num; /* Get item info.*/ *item_data_pnt = (void *)item->user_info; return(GENERIC_OK); } else if(item->forward_link == 0xFFFFFFFF) /* End of list found?!?*/ { return(OCTAPI_LLM_INTERNAL_ERROR0); } else /* Item was not found, but continue searching.*/ { cur_list_pnt = item->forward_link; } cur_list_num++; } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListInsertItem. | | Description: This function allocates a node to the linked list specified | by the handle list_handle. The position of the new item | can be specified. A position of 0xFFFFFFFF means append to the | list( use the OCTAPI_LLM_LIST_APPEND define for clarity); | a position of 0 mean insert at the begining of the list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the list. | **item_data void Address of the user data space for this item. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListInsertItem UINT32 OctApiLlmListInsertItem(void * l,UINT32 list_handle,UINT32 item_number,void ** item_data_pnt) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* free_item; UINT32 free_item_pnt; UINT32 total_lists; BYTE* lsbyte; UINT32 fConditionFlag = TRUE; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; *item_data_pnt = NULL; if (list_handle >= ls->total_lists) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); if (lh->list_length < item_number && item_number != 0xFFFFFFFF) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (ls->next_empty_item == 0xFFFFFFFF) return(OCTAPI_LLM_NO_STRUCTURES_LEFT); /* Get a free item from the free item list!*/ free_item_pnt = ls->next_empty_item; free_item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * free_item_pnt); ls->next_empty_item = free_item->forward_link; if (item_number == 0xFFFFFFFF) item_number = lh->list_length; if (lh->list_length == 0) /* First item and only item:*/ { free_item->forward_link = 0xFFFFFFFF; lh->tail_pointer = free_item_pnt; lh->head_pointer = free_item_pnt; } else if (item_number == 0) /* First item and but list not empty:*/ { free_item->forward_link = lh->head_pointer; lh->head_pointer = free_item_pnt; } else if (item_number == lh->list_length) /* Append:*/ { LLM_LIST_ITEM * last_item; last_item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->tail_pointer); last_item->forward_link = free_item_pnt; free_item->forward_link = 0xFFFFFFFF; lh->tail_pointer = free_item_pnt; } else /* Insert:*/ { LLM_LIST_ITEM * last_item = NULL; LLM_LIST_ITEM * item; UINT32 last_list_pnt; UINT32 cur_list_pnt; UINT32 cur_list_num; if (lh->cache_item_number < item_number) /* Start at cache:*/ { cur_list_pnt = lh->cache_item_pointer; cur_list_num = lh->cache_item_number; } else /* Start at beginning:*/ { cur_list_pnt = lh->head_pointer; cur_list_num = 0; } last_list_pnt = 0xFFFFFFFF; /* Start search from cur_list_pnt and cur_list_num.*/ while ( fConditionFlag == TRUE ) { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); if (cur_list_num == item_number) /* Item number found.*/ { if (last_list_pnt == 0xFFFFFFFF) return(OCTAPI_LLM_INTERNAL_ERROR1); free_item->forward_link = cur_list_pnt; last_item->forward_link = free_item_pnt; fConditionFlag = FALSE; break; } else if (item->forward_link == 0xFFFFFFFF) /* End of list found?!?*/ { return(OCTAPI_LLM_INTERNAL_ERROR0); } else /* Item was not found, but continue searching.*/ { last_item = item; last_list_pnt = cur_list_pnt; cur_list_pnt = item->forward_link; } cur_list_num++; } } /* Increase the list length.*/ lh->list_length++; ls->assigned_items++; *item_data_pnt = (void *)free_item->user_info; /* Write new cache entry.*/ lh->cache_item_pointer = free_item_pnt; lh->cache_item_number = item_number; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListCreateFull. | | Description: This function allocates the desired number of nodes to | the linked list specified by the handle list_handle. | The position of the new item can be specified. A | position of 0xFFFFFFFF means append to the list (use the | OCTAPI_LLM_LIST_APPEND define for clarity); a position | of 0 means insert at the begining of the list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the list. | **item_data void Address of the user data space for this item. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListCreateFull UINT32 OctApiLlmListCreateFull(void* l, UINT32 list_length, UINT32* plist_handle) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* free_item; LLM_LIST_ITEM* last_item = NULL; UINT32 free_item_pnt = 0xFFFFFFFF; UINT32 total_lists; UINT32 list_handle; UINT32 list_length_m1; UINT32 next_empty_item; UINT32 result; UINT32 i; BYTE* lsbyte; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Build the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Make sure another list can be created.*/ if (ls->assigned_lists == ls->total_lists) return(OCTAPI_LLM_ELEMENT_ALREADY_ASSIGNED); /* Make sure there are enough free nodes to fill the new list.*/ if (list_length > (ls->total_items - ls->assigned_items)) return(OCTAPI_LLM_ELEMENT_ALREADY_ASSIGNED); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Create list (i.e. get a list using the list head alloc structure.*/ result = OctapiLlmAllocAlloc(ls->list_head_alloc, &list_handle); if (result != GENERIC_OK) return(result); /* Initialize the list head structure.*/ lh = &ls->lh[list_handle]; lh->list_length = 0; lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; lh->cache_item_number = 0xFFFFFFFF; lh->cache_item_pointer = 0xFFFFFFFF; ls->assigned_lists++; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Add the number of requested nodes to the list.*/ lh = &ls->lh[list_handle]; list_length_m1 = list_length - 1; next_empty_item = ls->next_empty_item; for (i=0; ili + ls->item_size * free_item_pnt); next_empty_item = free_item->forward_link; /* Branch according to whether the node is the first in list, last, or in the middle.*/ if (i == 0) { /* First item.*/ free_item->forward_link = 0xFFFFFFFF; lh->head_pointer = free_item_pnt; lh->tail_pointer = free_item_pnt; } else if (i == list_length_m1) { /* Last item.*/ last_item->forward_link = free_item_pnt; free_item->forward_link = 0xFFFFFFFF; lh->tail_pointer = free_item_pnt; } else { /* Node somewhere in the middle.*/ last_item->forward_link = free_item_pnt; } /* Store pointer to free item as pointer to last item (for next iteration).*/ last_item = free_item; } /* Store new value of next_empty_item.*/ ls->next_empty_item = next_empty_item; /* Write new cache entry.*/ lh->cache_item_pointer = free_item_pnt; lh->cache_item_number = list_length_m1; /* Set the list length.*/ lh->list_length = list_length; ls->assigned_items += list_length; /* Return pointer to new list.*/ *plist_handle = list_handle; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListAppendItems. | | Description: This function allocates the desired number of nodes to | the linked list specified by the handle list_handle. | The position of the new item can be specified. A | position of 0xFFFFFFFF means append to the list (use the | OCTAPI_LLM_LIST_APPEND define for clarity); a position | of 0 means insert at the begining of the list. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the list. | **item_data void Address of the user data space for this item. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListAppendItems UINT32 OctApiLlmListAppendItems(void* l, UINT32 list_handle, UINT32 num_items) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* item_list; LLM_LIST_ITEM* curr_item = NULL; LLM_LIST_ITEM* free_item; UINT32 curr_item_pnt = 0xFFFFFFFF; UINT32 total_lists; UINT32 next_empty_item; UINT32 item_size; UINT32 i; BYTE* lsbyte; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Build the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Make sure list handle is valid.*/ if (list_handle >= ls->total_lists) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /* Make sure there is at least one item.*/ if (num_items == 0) return(OCTAPI_LLM_INVALID_PARAMETER); /* Make sure there are enough free nodes.*/ if (num_items > (ls->total_items - ls->assigned_items)) return(OCTAPI_LLM_NO_STRUCTURES_LEFT); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Get pointer to list structure.*/ lh = &ls->lh[list_handle]; if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Add the number of requested nodes to the list.*/ item_list = ls->li; item_size = ls->item_size; next_empty_item = ls->next_empty_item; for (i=0; ihead_pointer == 0xFFFFFFFF) { /* Current and next items are one and the same!*/ curr_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Set new head and tail pointers.*/ lh->head_pointer = next_empty_item; lh->tail_pointer = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next item.*/ next_empty_item = curr_item->forward_link; /* Set first item to be only item in list.*/ curr_item->forward_link = 0xFFFFFFFF; } else { /* Get a free item from the free item list!*/ curr_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * lh->tail_pointer); free_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Have current item point to next empty item.*/ curr_item->forward_link = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next_empty_item.*/ next_empty_item = free_item->forward_link; /* Update pointers to current item and free item.*/ curr_item = free_item; } } else { /* Update pointers to current item and free item.*/ free_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Have current item point to next empty item.*/ curr_item->forward_link = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next_empty_item.*/ next_empty_item = free_item->forward_link; /* Update pointers to current item and free item.*/ curr_item = free_item; } } /* Terminate list.*/ if ( curr_item != NULL ) curr_item->forward_link = 0xFFFFFFFF; /* Update llman structure variables.*/ ls->next_empty_item = next_empty_item; ls->assigned_items += num_items; /* Update list variables.*/ lh->list_length += num_items; lh->cache_item_pointer = curr_item_pnt; lh->cache_item_number = lh->list_length - 1; lh->tail_pointer = curr_item_pnt; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListAppendAndSetItems. | | Description: | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListAppendAndSetItems UINT32 OctApiLlmListAppendAndSetItems(void* l, UINT32 list_handle, UINT32 num_items, void* data_list) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* item_list; LLM_LIST_ITEM* curr_item = NULL; LLM_LIST_ITEM* free_item; UINT32 curr_item_pnt = 0xFFFFFFFF; UINT32 total_lists; UINT32 next_empty_item; UINT32 user_info_bytes; UINT32 item_size; UINT32 i; BYTE* lsbyte; void* data_item; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Build the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Make sure list handle is valid.*/ if (list_handle >= ls->total_lists) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /* Make sure there is at least one item.*/ if (num_items == 0) return(OCTAPI_LLM_INVALID_PARAMETER); /* Make sure there are enough free nodes.*/ if (num_items > (ls->total_items - ls->assigned_items)) return(OCTAPI_LLM_NO_STRUCTURES_LEFT); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Get pointer to list structure.*/ lh = &ls->lh[list_handle]; if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Add the number of requested nodes to the list.*/ item_list = ls->li; user_info_bytes = ls->user_info_bytes; item_size = ls->item_size; next_empty_item = ls->next_empty_item; data_item = data_list; for (i=0; ihead_pointer == 0xFFFFFFFF) { /* Current and next items are one and the same!*/ curr_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Set new head and tail pointers.*/ lh->head_pointer = next_empty_item; lh->tail_pointer = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next item.*/ next_empty_item = curr_item->forward_link; /* Set first item to be only item in list.*/ curr_item->forward_link = 0xFFFFFFFF; } else { /* Get a free item from the free item list!*/ curr_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * lh->tail_pointer); free_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Have current item point to next empty item.*/ curr_item->forward_link = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next_empty_item.*/ next_empty_item = free_item->forward_link; /* Update pointers to current item and free item.*/ curr_item = free_item; } } else { /* Update pointers to current item and free item.*/ free_item = (LLM_LIST_ITEM *)((BYTE *)item_list + item_size * next_empty_item); /* Have current item point to next empty item.*/ curr_item->forward_link = next_empty_item; /* Update current item pnt.*/ curr_item_pnt = next_empty_item; /* Update next_empty_item.*/ next_empty_item = free_item->forward_link; /* Update pointers to current item and free item.*/ curr_item = free_item; } /* Copy data to new item.*/ OctApiLlmMemCpy(curr_item->user_info, data_item, user_info_bytes); /* Update data_item pointer for next iteration (item).*/ data_item = (void *)((BYTE *)data_item + user_info_bytes); } /* Terminate list.*/ if ( curr_item != NULL ) curr_item->forward_link = 0xFFFFFFFF; /* Update llman structure variables.*/ ls->next_empty_item = next_empty_item; ls->assigned_items += num_items; /* Update list variables.*/ lh->list_length += num_items; lh->cache_item_pointer = curr_item_pnt; lh->cache_item_number = lh->list_length - 1; lh->tail_pointer = curr_item_pnt; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListSetItems. | | Description: This function takes a start entry (0 to length - 1), | a pointer to a list of data (each item of list is the | size of one data unit, specified at init), and the | length of the data list. From this, the data will be | copied from the data list to the linked list, from | entry start_entry to (start_entry + data_length - 1). | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListSetItems UINT32 OctApiLlmListSetItems(void* l, UINT32 list_handle, UINT32 start_item, UINT32 data_length, void* pdata_list) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* item = NULL; UINT32 total_lists; UINT32 item_pnt = 0xFFFFFFFF; UINT32 i, j; BYTE* lsbyte; void* pdata_item = NULL; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Build the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Make sure list handle is valid.*/ if (list_handle >= ls->total_lists) return(OCTAPI_LLM_INVALID_LIST_HANDLE); lh = &ls->lh[list_handle]; if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /* Make sure the start_entry is within limits.*/ if (start_item >= lh->list_length) return(OCTAPI_LLM_INVALID_PARAMETER); /* Make sure the end_entry is within limits.*/ lh = &ls->lh[list_handle]; if ((start_item + data_length) > lh->list_length) return(OCTAPI_LLM_INVALID_PARAMETER); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Set the data of each node.*/ for (i=0; icache_item_number + 1)) { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->cache_item_pointer); item_pnt = item->forward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); } else { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->head_pointer); item_pnt = lh->head_pointer; for (j=0; jforward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); } } pdata_item = (void *)((BYTE *)pdata_list + (i * ls->user_info_bytes)); } else { item_pnt = item->forward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); pdata_item = (void *)((BYTE *)pdata_item + ls->user_info_bytes); } /* Set the value of the item's user data.*/ OctApiLlmMemCpy(item->user_info, pdata_item, ls->user_info_bytes); } /* Write new cache entry.*/ lh->cache_item_pointer = item_pnt; lh->cache_item_number = start_item + data_length - 1; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListCopyData. | | Description: This function takes a start entry (0 to length - 1), | a pointer to a list of data (each item of list is the | size of one data unit, specified at init), and the | length of the data list. From this, the data will be | copied from the linked list to the data list, from | entry start_entry of the linked list to | (start_entry + data_length - 1). | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListCopyData UINT32 OctApiLlmListCopyData(void* l, UINT32 list_handle, UINT32 start_item, UINT32 data_length, void* pdata_list) { LLM_LIST* ls; LLM_LIST_HEAD* lh; LLM_LIST_ITEM* item = NULL; UINT32 item_pnt = 0xFFFFFFFF; UINT32 total_lists; UINT32 i, j; BYTE* lsbyte; void* pdata_item = NULL; /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Build the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Make sure list handle is valid.*/ if (list_handle >= ls->total_lists) return(OCTAPI_LLM_INVALID_LIST_HANDLE); lh = &ls->lh[list_handle]; if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); /* Make sure the start_entry is within limits.*/ if (start_item >= lh->list_length) return(OCTAPI_LLM_INVALID_PARAMETER); /* Make sure the end_entry is within limits.*/ lh = &ls->lh[list_handle]; if ((start_item + data_length) > lh->list_length) return(OCTAPI_LLM_INVALID_PARAMETER); /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /* Set the data of each node.*/ for (i=0; icache_item_number + 1)) { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->cache_item_pointer); item_pnt = item->forward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); } else { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->head_pointer); for (j=0; jforward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); } } pdata_item = (void *)((BYTE *)pdata_list + (i * ls->user_info_bytes)); } else { item_pnt = item->forward_link; item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * item_pnt); pdata_item = (void *)((BYTE *)pdata_item + ls->user_info_bytes); } /* Set the value of the item's user data.*/ OctApiLlmMemCpy(pdata_item, item->user_info, ls->user_info_bytes); } /* Write new cache entry.*/ lh->cache_item_pointer = item_pnt; lh->cache_item_number = start_item + data_length - 1; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListRemoveItem. | | Description: This function deallocates a node of the linked list specified | by the handle list_handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | list_handle UINT32 The handle to the list. | item_number UINT32 The number of the item to be removed. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmListRemoveItem UINT32 OctApiLlmListRemoveItem(void * l,UINT32 list_handle,UINT32 item_number) { LLM_LIST* ls; LLM_LIST_ITEM* freed_item = NULL; LLM_LIST_HEAD* lh; UINT32 freed_item_pnt = 0xFFFFFFFF; UINT32 total_lists; BYTE* lsbyte; UINT32 fConditionFlag = TRUE; /* Built the structure based on the base address:*/ ls = (LLM_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM_LIST_HEAD *)(lsbyte + sizeof(LLM_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD))); ls->li = (LLM_LIST_ITEM *)(lsbyte + sizeof(LLM_LIST) + (total_lists * sizeof(LLM_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; if (list_handle >= ls->total_lists) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM_INVALID_LIST_HANDLE); if (lh->list_length <= item_number) return(OCTAPI_LLM_BLOCKNUM_OUT_OF_RANGE); if (item_number == 0 && lh->list_length == 1)/* First item and only item:*/ { freed_item_pnt = lh->head_pointer; freed_item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * freed_item_pnt); lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; lh->cache_item_number = 0xFFFFFFFF; lh->cache_item_pointer = 0xFFFFFFFF; } else if (item_number == 0) /* First item and but list not empty:*/ { freed_item_pnt = ls->lh[list_handle].head_pointer; freed_item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * freed_item_pnt); lh->head_pointer = freed_item->forward_link; lh->cache_item_number = 0; lh->cache_item_pointer = freed_item->forward_link; } else /* Discard non-first item! (Caution: this could be the last item!)*/ { LLM_LIST_ITEM * last_item = NULL; LLM_LIST_ITEM * item; UINT32 last_list_pnt; UINT32 cur_list_pnt; UINT32 cur_list_num; if (lh->cache_item_number < item_number) /* Start at cache:*/ { cur_list_pnt = lh->cache_item_pointer; cur_list_num = lh->cache_item_number; } else /* Start at beginning:*/ { cur_list_pnt = lh->head_pointer; cur_list_num = 0; } last_list_pnt = 0xFFFFFFFF; /* Start search from cur_list_pnt and cur_list_num.*/ while( fConditionFlag == TRUE ) { item = (LLM_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); if (cur_list_num == item_number) /* Item number found.*/ { if (last_list_pnt == 0xFFFFFFFF) return(OCTAPI_LLM_INTERNAL_ERROR1); if ((item_number + 1) == lh->list_length) { lh->tail_pointer = last_list_pnt; last_item->forward_link = 0xFFFFFFFF; } else { last_item->forward_link = item->forward_link; } freed_item_pnt = cur_list_pnt; freed_item = item; /* Reset cache entry.*/ lh->cache_item_pointer = last_list_pnt; lh->cache_item_number = cur_list_num - 1; fConditionFlag = FALSE; break; } else if (item->forward_link == 0xFFFFFFFF) /* End of list found?!?*/ { return(OCTAPI_LLM_INTERNAL_ERROR0); } else /* Item was not found, but continue searching.*/ { last_item = item; last_list_pnt = cur_list_pnt; cur_list_pnt = item->forward_link; } cur_list_num++; } } /* Decrease the list length.*/ lh->list_length--; ls->assigned_items--; /* Return free block to free block list:*/ freed_item->forward_link = ls->next_empty_item; ls->next_empty_item = freed_item_pnt; return(GENERIC_OK); } #endif /**************************************** llm2 function section *****************************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListGetSize | | Description: This function determines the amount of memory needed by | the LLM2_LIST structure to manage the allocation of | number_of_items number of resources. The memory is | measured in bytes. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | number_of_items UINT32 The number of resources to be allocated | amongst all linked-lists. | number_of_lists UINT32 The maximum number of linked-lists that | can be allocated. | *l_size UINT32 UINT32 The amount of memory needed, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListGetSize UINT32 OctApiLlm2ListGetSize(UINT32 number_of_items,UINT32 number_of_lists,UINT32 user_info_size,UINT32 * l_size) { UINT32 head_alloc_size; UINT32 result; UINT32 user_info_size_roundup; if (number_of_items == 0) return(GENERIC_BAD_PARAM); if (number_of_lists == 0) return(GENERIC_BAD_PARAM); if (user_info_size == 0) return(GENERIC_BAD_PARAM); user_info_size_roundup = ((user_info_size + 3) / 4) * 4; result = OctapiLlmAllocGetSize(number_of_lists,&head_alloc_size); if(result != GENERIC_OK) return(result); *l_size = sizeof(LLM2_LIST) + (number_of_lists * sizeof(LLM2_LIST_HEAD)) + head_alloc_size + (number_of_items * (sizeof(LLM2_LIST_ITEM) + user_info_size_roundup - 4)); return(GENERIC_OK); } #endif #if !SKIP_OctApiLlm2ListGetItemPointer LLM2_LIST_ITEM * OctApiLlm2ListGetItemPointer(LLM2_LIST * ls, UINT32 item_number) { return (LLM2_LIST_ITEM *) (((BYTE *)ls->li) + (ls->item_size * item_number)) ; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListInit. | | Description: This function intializes the LLM2_TALLOC structure. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | number_of_items UINT32 The number of resources to be allocated | amongst all linked-lists. | number_of_lists UINT32 The maximum number of linked-lists that | can be allocated. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListInit UINT32 OctApiLlm2ListInit(void ** l,UINT32 number_of_items,UINT32 number_of_lists,UINT32 user_info_size) { LLM2_LIST* ls; LLM2_LIST_ITEM* item; UINT32 i; UINT32 head_alloc_size; UINT32 result; UINT32 user_info_size_roundup; UINT32 total_lists; BYTE* lsbyte; if (number_of_items == 0) return(GENERIC_BAD_PARAM); if (number_of_lists == 0) return(GENERIC_BAD_PARAM); if (user_info_size == 0) return(GENERIC_BAD_PARAM); user_info_size_roundup = ((user_info_size + 3) / 4) * 4; /* Get the size of the Alloc structure used to manage head of list structures.*/ result = OctapiLlmAllocGetSize(number_of_lists,&head_alloc_size); if(result != GENERIC_OK) return(result); if (*l == NULL) return(OCTAPI_LLM_MEMORY_NOT_ALLOCATED); /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)(*l); lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); /* Initialize parameters in the structure.*/ ls->head_alloc_size = head_alloc_size; ls->user_info_bytes = user_info_size; ls->user_info_size = user_info_size_roundup; ls->total_items = number_of_items; ls->assigned_items = 0; ls->total_lists = number_of_lists; ls->assigned_lists = 0; ls->next_empty_item = 0; ls->item_size = sizeof(LLM2_LIST_ITEM) + user_info_size_roundup - 4; /* Complete the build!*/ ls = (LLM2_LIST *)(*l); lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); /* Initialize the head of queue Alloc structure.*/ result = OctapiLlmAllocInit(&(ls->list_head_alloc),number_of_lists); if(result != GENERIC_OK) return(result); /* Initialize the linked list of the items:*/ for(i=0; ili + ls->item_size * i); if (i == (number_of_items - 1)) item->forward_link = 0xFFFFFFFF; else item->forward_link = i + 1; } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListCreate. | | Description: This function creates a linked list. The target which is | allocated the newly created list can request additions | or removals from the list later on. To target identifies | its list with the returned list handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM_LIST structure. | *list_handle UINT32 The handle to the new list, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListCreate UINT32 OctApiLlm2ListCreate(void * l,UINT32 * list_handle) { LLM2_LIST* ls; LLM2_LIST_HEAD* lh; UINT32 blocknum; UINT32 total_lists; UINT32 result; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); /* Get a list using the list head alloc structure.*/ result = OctapiLlmAllocAlloc(ls->list_head_alloc, &blocknum); if (result != GENERIC_OK) return(result); /* The handle is the block number.*/ *list_handle = blocknum; /* Initialize the list head structure.*/ lh = &ls->lh[blocknum]; lh->list_length = 0; lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; ls->assigned_lists++; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListDelete. | | Description: This function deletes the linked list indicated by the | handle list_handle. Any items which are still allocated | to the list are first deallocated. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | *list_handle UINT32 The handle to the list. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListDelete UINT32 OctApiLlm2ListDelete(void * l,UINT32 list_handle) { LLM2_LIST* ls; LLM2_LIST_HEAD* lh; UINT32 total_lists; UINT32 result; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); if (list_handle >= ls->total_lists) return(OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE); if (ls->lh[list_handle].list_length == 0xFFFFFFFF) return(OCTAPI_LLM2_INVALID_LIST_HANDLE); /* Release internal list header handle...*/ result = OctapiLlmAllocDealloc(ls->list_head_alloc,list_handle); if (result != GENERIC_OK) return(result); lh = &ls->lh[list_handle]; /* Deallocate all items in the list!*/ if (lh->list_length != 0) { LLM2_LIST_ITEM * item; item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * lh->tail_pointer); /* Release the items using only the links.*/ item->forward_link = ls->next_empty_item; ls->next_empty_item = lh->head_pointer; /* Remove items from item counter.*/ ls->assigned_items -= lh->list_length; } lh->list_length = 0xFFFFFFFF; lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; ls->assigned_lists--; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmListLength. | | Description: This function returns the number of items allocated to the | list indicated by the handle list_handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | list_handle UINT32 The handle to the list. | *number_of_items UINT32 The number of items in the list, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListLength UINT32 OctApiLlm2ListLength(void * l,UINT32 list_handle, UINT32 * number_of_items_in_list) { LLM2_LIST* ls; LLM2_LIST_HEAD* lh; UINT32 total_lists; BYTE* lsbyte; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; if (list_handle >= ls->total_lists) return(OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM2_INVALID_LIST_HANDLE); *number_of_items_in_list = lh->list_length; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListItemData | | Description: This function returns a pointer to the user data associated | with an item. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | list_handle UINT32 The handle to the list. | item_number UINT32 The number of the list node in question. | **item_data_pnt void The pointer to the user data, returned. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListItemData UINT32 OctApiLlm2ListItemData(void * l,UINT32 list_handle,UINT32 item_key,void ** item_data_pnt, PUINT32 item_number_pnt) { LLM2_LIST* ls; LLM2_LIST_HEAD* lh; LLM2_LIST_ITEM* item; UINT32 cur_list_pnt; UINT32 cur_list_key = 0xFFFFFFFF; UINT32 total_lists; UINT32 list_length; BYTE* lsbyte; UINT32 fConditionFlag = TRUE; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; list_length = lh->list_length; *item_data_pnt = NULL; *item_number_pnt = 0; if (list_handle >= ls->total_lists) return(OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE); if (list_length == 0xFFFFFFFF) return(OCTAPI_LLM2_INVALID_LIST_HANDLE); /* Determine where the search will start.*/ /* Start at beginning:*/ cur_list_pnt = lh->head_pointer; item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; /* Start search from cur_list_pnt and cur_list_num.*/ while ( fConditionFlag == TRUE ) { if (cur_list_key == item_key) /* Item key found.*/ { /* Get item info.*/ *item_data_pnt = (void *)item->user_info; return(GENERIC_OK); } else if(item->forward_link == 0xFFFFFFFF) /* End of list found?!?*/ { return(OCTAPI_LLM2_INTERNAL_ERROR0); } else /* Item was not found, but continue searching.*/ { cur_list_pnt = item->forward_link; } item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; (*item_number_pnt)++; } return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListInsertItem. | | Description: This function allocates a node to the linked list specified | by the handle list_handle. The position of the new item | will be defined based on the key value. All entry are inserted | in the list in incremental Key value. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | *list_handle UINT32 The handle to the list. | **item_data void Address of the user data space for this item. | **prev_item_data void Address of the user data space for the previous item. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListInsertItem UINT32 OctApiLlm2ListInsertItem(void * l,UINT32 list_handle,UINT32 item_key,void ** item_data_pnt, void ** prev_item_data_pnt, void ** prev_prev_item_data_pnt, PUINT32 insert_status_pnt ) { LLM2_LIST* ls; LLM2_LIST_HEAD* lh; LLM2_LIST_ITEM* free_item; UINT32 free_item_pnt; UINT32 total_lists; BYTE* lsbyte; UINT32 ulPassCount = 0; UINT32 fConditionFlag = TRUE; /* Set the status of the insertion.*/ *insert_status_pnt = OCTAPI_LLM2_INSERT_ERROR; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; *item_data_pnt = NULL; if (list_handle >= ls->total_lists) return(OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM2_INVALID_LIST_HANDLE); if (ls->next_empty_item == 0xFFFFFFFF) return(OCTAPI_LLM2_NO_STRUCTURES_LEFT); /* Get a free item from the free item list!*/ free_item_pnt = ls->next_empty_item; free_item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * free_item_pnt); free_item->key = item_key; ls->next_empty_item = free_item->forward_link; if (lh->list_length == 0) /* First item and only item:*/ { free_item->forward_link = 0xFFFFFFFF; lh->tail_pointer = free_item_pnt; lh->head_pointer = free_item_pnt; *insert_status_pnt = OCTAPI_LLM2_INSERT_FIRST_NODE; /* There is no previous node information to return.*/ *prev_item_data_pnt = NULL; *prev_prev_item_data_pnt = NULL; } else /* Insert:*/ { LLM2_LIST_ITEM * last_last_item = NULL; LLM2_LIST_ITEM * last_item = NULL; LLM2_LIST_ITEM * item; UINT32 last_list_pnt; UINT32 cur_list_pnt; UINT32 cur_list_key = 0xFFFFFFFF; /* Start at beginning:*/ cur_list_pnt = lh->head_pointer; item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; last_list_pnt = 0xFFFFFFFF; /* Start search from cur_list_pnt and cur_list_num.*/ while ( fConditionFlag == TRUE ) { /* Increment the pass count to determine if the addition will happen next to last.*/ ulPassCount++; if (cur_list_key >= item_key) /* Item new node between the last and the curent. */ { if (last_list_pnt == 0xFFFFFFFF) /* Must insert at the head of the list.*/ { free_item->forward_link = cur_list_pnt; lh->head_pointer = free_item_pnt; } else /* Standard insertion.*/ { free_item->forward_link = cur_list_pnt; last_item->forward_link = free_item_pnt; } /* Check if the entry was made before the last one.*/ if ( ulPassCount == lh->list_length ) *insert_status_pnt = OCTAPI_LLM2_INSERT_BEFORE_LAST_NODE; else *insert_status_pnt = OCTAPI_LLM2_INSERT_LIST_NODE; fConditionFlag = FALSE; break; } else if (item->forward_link == 0xFFFFFFFF) /* End of list found, must insert at the end.*/ { free_item->forward_link = 0xFFFFFFFF; item->forward_link = free_item_pnt; lh->tail_pointer = free_item_pnt; *insert_status_pnt = OCTAPI_LLM2_INSERT_LAST_NODE; fConditionFlag = FALSE; break; } else /* Item was not found, but continue searching.*/ { last_last_item = last_item; last_item = item; last_list_pnt = cur_list_pnt; cur_list_pnt = item->forward_link; } item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; } /* Return the previous node if possible.*/ if ( *insert_status_pnt == OCTAPI_LLM2_INSERT_LIST_NODE || *insert_status_pnt == OCTAPI_LLM2_INSERT_BEFORE_LAST_NODE ) { if ( last_item != NULL ) *prev_item_data_pnt = (void *)last_item->user_info; if ( last_last_item != NULL ) *prev_prev_item_data_pnt = (void *)last_last_item->user_info; else *prev_prev_item_data_pnt = NULL; } else { *prev_item_data_pnt = (void *)item->user_info; if ( ( last_last_item != NULL ) && ( last_item != NULL ) ) *prev_prev_item_data_pnt = (void *)last_item->user_info; else *prev_prev_item_data_pnt = NULL; } } /* Increase the list length.*/ lh->list_length++; ls->assigned_items++; *item_data_pnt = (void *)free_item->user_info; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlm2ListRemoveItem. | | Description: This function deallocates a node of the linked list specified | by the handle list_handle. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *l void The memory used by the LLM2_LIST structure. | list_handle UINT32 The handle to the list. | item_key UINT32 The key of the item to be removed. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlm2ListRemoveItem UINT32 OctApiLlm2ListRemoveItem(void * l,UINT32 list_handle,UINT32 item_key, PUINT32 prev_item_key_pnt, PUINT32 prev_prev_item_key_pnt, PUINT32 remove_status_pnt ) { LLM2_LIST* ls; LLM2_LIST_ITEM* freed_item = NULL; LLM2_LIST_HEAD* lh; UINT32 freed_item_pnt = 0xFFFFFFFF; UINT32 total_lists; BYTE* lsbyte; UINT32 fConditionFlag = TRUE; UINT32 ulPassCount = 0; /* Built the structure based on the base address:*/ ls = (LLM2_LIST *)l; lsbyte = (BYTE *)ls; total_lists = ls->total_lists; /* Set the status of the removal to error as a default value.*/ *remove_status_pnt = OCTAPI_LLM2_REMOVE_ERROR; ls->lh = (LLM2_LIST_HEAD *)(lsbyte + sizeof(LLM2_LIST)); ls->list_head_alloc = (void *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD))); ls->li = (LLM2_LIST_ITEM *)(lsbyte + sizeof(LLM2_LIST) + (total_lists * sizeof(LLM2_LIST_HEAD)) + ls->head_alloc_size); lh = &ls->lh[list_handle]; if (list_handle >= ls->total_lists) return(OCTAPI_LLM2_BLOCKNUM_OUT_OF_RANGE); if (lh->list_length == 0xFFFFFFFF) return(OCTAPI_LLM2_INVALID_LIST_HANDLE); if (lh->list_length == 1)/* First item and only item if he matches.*/ { freed_item_pnt = lh->head_pointer; freed_item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * freed_item_pnt); if ( freed_item->key == item_key ) { lh->head_pointer = 0xFFFFFFFF; lh->tail_pointer = 0xFFFFFFFF; } else return(OCTAPI_LLM2_INTERNAL_ERROR1); /* Indicate that there was no node prior to the one removed.*/ *prev_item_key_pnt = 0xFFFFFFFF; *prev_prev_item_key_pnt = 0xFFFFFFFF; *remove_status_pnt = OCTAPI_LLM2_REMOVE_FIRST_NODE; } else /* Discard non-first item! (Caution: this could be the last item!)*/ { LLM2_LIST_ITEM * last_last_item = NULL; LLM2_LIST_ITEM * last_item = NULL; LLM2_LIST_ITEM * item; UINT32 last_list_pnt; UINT32 cur_list_pnt; UINT32 cur_list_key; /* Start at beginning:*/ cur_list_pnt = lh->head_pointer; item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; last_list_pnt = 0xFFFFFFFF; /* Start search from cur_list_pnt and cur_list_num.*/ while( fConditionFlag == TRUE ) { ulPassCount++; if (cur_list_key == item_key) /* Item number found.*/ { if (last_list_pnt == 0xFFFFFFFF) /* First item in the list.*/ { lh->head_pointer = item->forward_link; *remove_status_pnt = OCTAPI_LLM2_REMOVE_FIRST_NODE; } else if ( item->forward_link == 0xFFFFFFFF) /* Last item of the list.*/ { last_item->forward_link = 0xFFFFFFFF; lh->tail_pointer = last_list_pnt; *remove_status_pnt = OCTAPI_LLM2_REMOVE_LAST_NODE; } else { last_item->forward_link = item->forward_link; if ( ulPassCount == ( lh->list_length - 1 ) ) *remove_status_pnt = OCTAPI_LLM2_REMOVE_BEFORE_LAST_NODE; else *remove_status_pnt = OCTAPI_LLM2_REMOVE_LIST_NODE; } freed_item_pnt = cur_list_pnt; freed_item = item; fConditionFlag = FALSE; break; } else if (item->forward_link == 0xFFFFFFFF) /* End of list found?!?*/ { return(OCTAPI_LLM2_INTERNAL_ERROR0); } else /* Item was not found, but continue searching.*/ { last_last_item = last_item; last_item = item; last_list_pnt = cur_list_pnt; cur_list_pnt = item->forward_link; } item = (LLM2_LIST_ITEM *)((BYTE *)ls->li + ls->item_size * cur_list_pnt); cur_list_key = item->key; } /* Return the key of the node before the node removed if possible.*/ if ( last_list_pnt == 0xFFFFFFFF ) *prev_item_key_pnt = 0xFFFFFFFF; else if ( last_item != NULL ) *prev_item_key_pnt = last_item->key; /* Return the key of the node before before the node removed if possible.*/ if ( last_last_item == NULL ) *prev_prev_item_key_pnt = 0xFFFFFFFF; else *prev_prev_item_key_pnt = last_last_item->key; } /* Decrease the list length.*/ lh->list_length--; ls->assigned_items--; /* Return free block to free block list:*/ freed_item->forward_link = ls->next_empty_item; ls->next_empty_item = freed_item_pnt; return(GENERIC_OK); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ | API UTILITIES | | Function: OctApiLlmMemCpy. | | Description: This function copies data from a source to a destination. | | ----------------------------------------------------------------------- | | Variable | Type | Description | ----------------------------------------------------------------------- | *f_pvDestination VOID The destination where to copy the data. | *f_pvSource VOID The source where to copy the data from. | f_ulSize UINT32 The number of bytes to copy. | \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OctApiLlmMemCpy VOID * OctApiLlmMemCpy( VOID *f_pvDestination, const VOID * f_pvSource, UINT32 f_ulSize ) { CHAR * pbyDst; const CHAR * pbySrc; UINT32 * f_pulAlignedDst; const UINT32 * f_pulAlignedSrc; pbyDst = (CHAR *)f_pvDestination; pbySrc = (const CHAR *)f_pvSource; /* * If the size is small, or either SRC or DST is unaligned, * then punt into the byte copy loop. This should be rare. */ if ( ( f_ulSize < sizeof(UINT32) ) || ( ( (unsigned long)( pbySrc ) & ( sizeof(UINT32) - 1 ) ) | ( (unsigned long)( pbyDst ) & ( sizeof(UINT32) - 1 ) ) ) ) { while ( f_ulSize-- ) *pbyDst++ = *pbySrc++; return f_pvDestination; } f_pulAlignedDst = (UINT32 *)pbyDst; f_pulAlignedSrc = (const UINT32 *)pbySrc; /* Copy 4X long words at a time if possible. */ while ( f_ulSize >= 4 * sizeof(UINT32) ) { *f_pulAlignedDst++ = *f_pulAlignedSrc++; *f_pulAlignedDst++ = *f_pulAlignedSrc++; *f_pulAlignedDst++ = *f_pulAlignedSrc++; *f_pulAlignedDst++ = *f_pulAlignedSrc++; f_ulSize -= 4 * sizeof(UINT32); } /* Copy one long word at a time if possible. */ while ( f_ulSize >= sizeof(UINT32) ) { *f_pulAlignedDst++ = *f_pulAlignedSrc++; f_ulSize -= sizeof(UINT32); } /* Pick up any residual with a byte copier. */ pbyDst = (CHAR *)f_pulAlignedDst; pbySrc = (const CHAR *)f_pulAlignedSrc; while ( f_ulSize-- ) *pbyDst++ = *pbySrc++; return f_pvDestination; } #endif /**************************************** llm_list section **********************************************/ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/apilib/llman/octapi_llman_private.h0000644000175000017500000001655611431317470026672 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: octapi_llman_private.h Copyright (c) 2001 Octasic Inc. All rights reserved. Description: Library used to manage allocation tables and linked lists. The library is made such that only a block of contiguous memory is needed for the management of the linked list/allocation table. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 13 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCTAPI_LLMAN_PRIVATE_H__ #define __OCTAPI_LLMAN_PRIVATE_H__ #include "octdef.h" /**************************************** llm_alloc section **********************************************/ /* Most basic linked list model. LLM_STR contains a list of "number_of_items" that are each "unassigned" or "assigned". When requesting a new element, llm_alloc must choose an "unassigned" element. An element that is deallocated will be last to be allocated. */ typedef struct _LLM_ALLOC { UINT32 *linked_list; /* Each item is either used (0xFFFFFFFE)*/ /* or unused (pointer to next unused item, 0xFFFFFFFF means last item reached).*/ UINT32 next_avail_num; /* Points to the next available item in linked list. (0xFFFFFFFF means none available)*/ UINT32 number_of_items; /* Total number of items in linked list.*/ UINT32 allocated_items; /* Allocated items in linked list.*/ } LLM_ALLOC; typedef struct _TLLM_ALLOC_NODE_ { UINT32 value; /* Each item is either used (0xFFFFFFFE)*/ /* or unused (pointer to next unused item, 0xFFFFFFFF means last item reached).*/ UINT32 timeout[2]; /* Timeout value that must be exceeded for the node to be considered free again.*/ } TLLM_ALLOC_NODE; typedef struct _TLLM_ALLOC_ { TLLM_ALLOC_NODE *linked_list; /* List of nodes used by the link list.*/ UINT32 next_avail_num; /* Points to the next available item in linked list. (0xFFFFFFFF means none available)*/ UINT32 number_of_items; /* Total number of items in linked list.*/ UINT32 allocated_items; /* Allocated items in linked list.*/ UINT32 number_of_timeout; /* Number of block currently in timeout.*/ UINT32 next_timeout_num; /* Points to the next block currently in timeout.*/ UINT32 last_timeout_num; /* Last node of the timeout list.*/ UINT32 last_known_time[2]; /* last known time.*/ } TLLM_ALLOC; /* void octapi_llm_alloc_build_structure(void *l, LLM_ALLOC ** ls); */ /**************************************** llm_alloc section **********************************************/ /**************************************** llm_list section **********************************************/ /* This section contains memory structures and functions used to maintain a variable number of lists (FIFOs) that each have a variable amount of items. A total amount of items can be assigned through-out all the lists. Each item in each list contains a UINT32 specified by the software using the lists. Each used item in the list is accessible through it's position in the list. */ typedef struct _LLM_LIST_HEAD { UINT32 list_length; /* Current number of items in the list.*/ /* 0xFFFFFFFF means that the list is not used.*/ UINT32 head_pointer; /* Number of the item in the item pool that is the first of this list.*/ /* 0xFFFFFFFF indicates end-of-list link.*/ UINT32 tail_pointer; /* Number of the item in the item pool that is the last of this list.*/ /* Item cache (pointer within the list of the last accessed item):*/ UINT32 cache_item_number; /* Number of the last accessed item in the list. 0xFFFFFFFF indicates invalid cache.*/ UINT32 cache_item_pointer; /* Number of the last accessed item in the item pool.*/ } LLM_LIST_HEAD; typedef struct _LLM_LIST_ITEM { UINT32 forward_link; /* Number of the item in the item pool that is next in this list.*/ /* 0xFFFFFFFF indicates end-of-list link.*/ /* User item info (variable size)*/ UINT32 user_info[1]; } LLM_LIST_ITEM; typedef struct _LLM_LIST { UINT32 user_info_bytes; /* In bytes, size of the user info in a single item.*/ UINT32 user_info_size; /* In bytes, size of the user info in a single item.*/ UINT32 item_size; UINT32 head_alloc_size; UINT32 total_items; UINT32 assigned_items; UINT32 total_lists; UINT32 assigned_lists; UINT32 next_empty_item; /* Contains a pointer to the next empty item in the*/ /* item pool.*/ /* Table of all the possible list heads:*/ LLM_LIST_HEAD * lh; void * list_head_alloc; /* LLM_ALLOC structure used for list head allocation!*/ /* Table of the list items:*/ LLM_LIST_ITEM * li; } LLM_LIST; /**********************************************************************************/ /* These structures are are used by the Llm2 functions to creates lists of ordered items based on a key given by the user when a new node is inserted in a list. */ typedef struct _LLM2_LIST_HEAD { UINT32 list_length; /* Current number of items in the list.*/ /* 0xFFFFFFFF means that the list is not used.*/ UINT32 head_pointer; /* Number of the item in the item pool that is the first of this list.*/ /* 0xFFFFFFFF indicates end-of-list link.*/ UINT32 tail_pointer; /* Number of the item in the item pool that is the last of this list.*/ } LLM2_LIST_HEAD; typedef struct _LLM2_LIST_ITEM { UINT32 forward_link; /* Number of the item in the item pool that is next in this list.*/ /* 0xFFFFFFFF indicates end-of-list link.*/ UINT32 key; /* Key used to order the entries.*/ /* User item info (variable size)*/ UINT32 user_info[1]; } LLM2_LIST_ITEM; typedef struct _LLM2_LIST { UINT32 user_info_bytes; /* In bytes, size of the user info in a single item.*/ UINT32 user_info_size; /* In bytes, size of the user info in a single item.*/ UINT32 item_size; UINT32 head_alloc_size; UINT32 total_items; UINT32 assigned_items; UINT32 total_lists; UINT32 assigned_lists; UINT32 next_empty_item; /* Contains a pointer to the next empty item in the*/ /* item pool.*/ /* Table of all the possible list heads:*/ LLM2_LIST_HEAD * lh; void * list_head_alloc; /* LLM_ALLOC structure used for list head allocation!*/ /* Table of the list items:*/ LLM2_LIST_ITEM * li; } LLM2_LIST; /*void octapi_llm_list_build_structure(void *l, LLM_LIST ** ls);*/ LLM_LIST_ITEM * OctApiLlmListGetItemPointer( LLM_LIST * ls, UINT32 item_number ); LLM2_LIST_ITEM * OctApiLlm2ListGetItemPointer( LLM2_LIST * ls, UINT32 item_number ); UINT32 OctApiTllmCheckTimeoutList( TLLM_ALLOC *ls, UINT32 current_time[2] ); VOID * OctApiLlmMemCpy( VOID *f_pvDestination, const VOID * f_pvSource, UINT32 f_ulSize ); /**************************************** llm_list section **********************************************/ #endif /*__OCTAPI_LLMAN_PRIVATE_H__*/ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/Makefile0000644000175000017500000000224511431317470021410 0ustar tzafrirtzafrirCFLAGS=-V3.4 -ffunction-sections -I/lib/modules/$(shell uname -r)/build/include -Iinclude -Ioctdeviceapi -Ioctdeviceapi/oct6100api -DGFP_ATOMIC=0 -Dkmalloc=calloc -Dkfree=free LDFLAGS=-V3.4 -Wl,-Map -Wl,test.map -Wl,--gc-sections APIDIR=octdeviceapi/oct6100api/oct6100_api OCTASIC_OBJS=$(APIDIR)/oct6100_adpcm_chan.o \ $(APIDIR)/oct6100_channel.o \ $(APIDIR)/oct6100_chip_open.o \ $(APIDIR)/oct6100_chip_stats.o \ $(APIDIR)/oct6100_conf_bridge.o \ $(APIDIR)/oct6100_debug.o \ $(APIDIR)/oct6100_events.o \ $(APIDIR)/oct6100_interrupts.o \ $(APIDIR)/oct6100_memory.o \ $(APIDIR)/oct6100_miscellaneous.o \ $(APIDIR)/oct6100_mixer.o \ $(APIDIR)/oct6100_phasing_tsst.o \ $(APIDIR)/oct6100_playout_buf.o \ $(APIDIR)/oct6100_remote_debug.o \ $(APIDIR)/oct6100_tlv.o \ $(APIDIR)/oct6100_tone_detection.o \ $(APIDIR)/oct6100_tsi_cnct.o \ $(APIDIR)/oct6100_tsst.o \ $(APIDIR)/oct6100_user.o \ apilib/bt/octapi_bt0.o \ apilib/largmath/octapi_largmath.o \ apilib/llman/octapi_llman.o all: test test.o: test.c test: test.o $(OCTASIC_OBJS) clean: rm -rf test test.o rm -rf $(OCTASIC_OBJS) dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/0000755000175000017500000000000011631523355022407 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/0000755000175000017500000000000011631523356024176 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_channel_priv.h0000644000175000017500000004724111431317470030177 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_channel_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_channel.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_channel_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 62 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHANNEL_PRIV_H__ #define __OCT6100_CHANNEL_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* ECHO channel list pointer macros. */ #define mOCT6100_GET_CHANNEL_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_CHANNEL )(( PUINT8 )pSharedInfo + pSharedInfo->ulChannelListOfst ); #define mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_CHANNEL )(( PUINT8 )pSharedInfo + pSharedInfo->ulChannelListOfst)) + ulIndex; #define mOCT6100_GET_CHANNEL_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulChannelAllocOfst); #define mOCT6100_GET_BIDIR_CHANNEL_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_BIDIR_CHANNEL )(( PUINT8 )pSharedInfo + pSharedInfo->ulBiDirChannelListOfst ); #define mOCT6100_GET_BIDIR_CHANNEL_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_BIDIR_CHANNEL )(( PUINT8 )pSharedInfo + pSharedInfo->ulBiDirChannelListOfst)) + ulIndex; #define mOCT6100_GET_BIDIR_CHANNEL_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulBiDirChannelAllocOfst ); /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_ECHO_CHAN_INDEX_ { /* Index of the channel in the API echo channel list.*/ UINT16 usEchoChanIndex; /* TSI chariot memory entry for the Rin/Rout stream. */ UINT16 usRinRoutTsiMemIndex; /* TSI chariot memory entry for the Sin/Sout stream. */ UINT16 usSinSoutTsiMemIndex; /* SSPX memory entry. */ UINT16 usEchoMemIndex; /* TDM sample conversion control memory entry. */ UINT16 usRinRoutConversionMemIndex; UINT16 usSinSoutConversionMemIndex; /* Internal info for quick access to structures associated to this TSI cnct. */ UINT16 usRinTsstIndex; UINT16 usSinTsstIndex; UINT16 usRoutTsstIndex; UINT16 usSoutTsstIndex; /* Index of the phasing TSST */ UINT16 usPhasingTsstIndex; UINT8 fSinSoutCodecActive; UINT8 fRinRoutCodecActive; /* Extended Tone Detection resources.*/ UINT16 usExtToneChanIndex; UINT16 usExtToneMixerIndex; UINT16 usExtToneTsiIndex; } tOCT6100_API_ECHO_CHAN_INDEX, *tPOCT6100_API_ECHO_CHAN_INDEX; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetChannelsEchoSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiChannelsEchoSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ChannelOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ); UINT32 Oct6100ApiCheckChannelParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ); UINT32 Oct6100ApiReserveChannelResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ); UINT32 Oct6100ApiWriteChannelStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ); UINT32 Oct6100ApiUpdateChannelEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ); UINT32 Oct6100ChannelCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CLOSE f_pChannelClose ); UINT32 Oct6100ApiAssertChannelParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CLOSE f_pChannelClose, IN OUT PUINT16 f_pusChanIndex ); UINT32 Oct6100ApiInvalidateChannelStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex ); UINT32 Oct6100ApiReleaseChannelResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChannelIndex ); UINT32 Oct6100ChannelModifySer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify ); UINT32 Oct6100ApiCheckChannelModify( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN OUT tPOCT6100_CHANNEL_OPEN f_pTempChanOpen, OUT PUINT16 f_pusNewPhasingTsstIndex, OUT PUINT16 f_pusChanIndex ); UINT32 Oct6100ApiModifyChannelResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN UINT16 f_usChanIndex, OUT PUINT16 f_pusNewRinTsstIndex, OUT PUINT16 f_pusNewSinTsstIndex, OUT PUINT16 f_pusNewRoutTsstIndex, OUT PUINT16 f_pusNewSoutTsstIndex ); UINT32 Oct6100ApiModifyChannelStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usNewPhasingTsstIndex, OUT PUINT8 f_pfSinSoutCodecActive, OUT PUINT8 f_pfRinRoutCodecActive, IN UINT16 f_usNewRinTsstIndex, IN UINT16 f_uslNewSinTsstIndex, IN UINT16 f_usNewRoutTsstIndex, IN UINT16 f_usNewSoutTsstIndex ); UINT32 Oct6100ApiModifyChannelEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usNewPhasingTsstIndex, IN UINT8 f_fSinSoutCodecActive, IN UINT8 f_fRinRoutCodecActive, IN UINT16 f_usNewRinTsstIndex, IN UINT16 f_usNewSinTsstIndex, IN UINT16 f_usNewRoutTsstIndex, IN UINT16 f_usNewSoutTsstIndex ); UINT32 Oct6100ChannelBroadcastTsstAddSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd ); UINT32 Oct6100ApiCheckChanTsstAddParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstRemove, OUT PUINT16 f_pusChanIndex ); UINT32 Oct6100ApiReserveTsstAddResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstRemove, IN UINT16 f_usChanIndex, OUT PUINT16 f_pusNewTsstIndex, OUT PUINT16 f_pusNewTsstEntry ); UINT32 Oct6100ApiWriteTsstAddStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstRemove, IN UINT16 f_usChanIndex, IN UINT16 f_usNewTsstIndex ); UINT32 Oct6100ApiUpdateTsstAddChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstRemove, IN UINT16 f_usChanIndex, IN UINT16 f_usNewTsstIndex, IN UINT16 f_usNewTsstEntry ); UINT32 Oct6100ChannelBroadcastTsstRemoveSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove); UINT32 Oct6100ApiAssertChanTsstRemoveParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusTsstIndex, OUT PUINT16 f_pusTsstEntry, OUT PUINT16 f_pusPrevTsstEntry ); UINT32 Oct6100ApiInvalidateTsstRemoveStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usTsstIndex, IN UINT32 f_ulPort, IN BOOL f_fRemoveAll ); UINT32 Oct6100ApiReleaseTsstRemoveResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove, IN UINT16 f_usChanIndex, IN UINT16 f_usTsstIndex, IN UINT16 f_usTsstEntry, IN UINT16 f_usPrevTsstEntry ); UINT32 Oct6100ApiChannelGetStatsSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_STATS f_pChannelStats ); UINT32 Oct6100ApiReserveEchoEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEchoIndex ); UINT32 Oct6100ApiReleaseEchoEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEchoChanIndex ); UINT32 Oct6100ApiCheckTdmConfig( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig ); UINT32 Oct6100ApiCheckVqeConfig( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN BOOL f_fEnableToneDisabler ); UINT32 Oct6100ApiCheckCodecConfig( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_CODEC f_pCodecConfig, IN UINT32 f_ulDecoderNumTssts, OUT PUINT16 f_pusPhasingTsstIndex ); UINT32 Oct6100ApiWriteInputTsstControlMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulTsstInputLaw ); UINT32 Oct6100ApiWriteOutputTsstControlMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex, IN UINT32 f_ulAdpcmNibblePosition, IN UINT32 f_ulNumTssts, IN UINT16 f_usTsiMemIndex ); UINT32 Oct6100ApiWriteEncoderMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulEncoderIndex, IN UINT32 f_ulCompType, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulEnableSilenceSuppression, IN UINT32 f_ulAdpcmNibblePosition, IN UINT16 f_usPhasingTsstIndex, IN UINT32 f_ulPhasingType, IN UINT32 f_ulPhase ); UINT32 Oct6100ApiWriteDecoderMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usDecoderIndex, IN UINT32 f_ulCompType, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulPcmLaw, IN UINT32 f_ulAdpcmNibblePosition ); UINT32 Oct6100ApiClearConversionMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usConversionMemIndex ); UINT32 Oct6100ApiWriteVqeMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ); UINT32 Oct6100ApiWriteVqeNlpMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ); UINT32 Oct6100ApiWriteVqeAfMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ); UINT32 Oct6100ApiWriteEchoMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usEchoIndex, IN UINT16 f_usRinRoutTsiIndex, IN UINT16 f_usSinSoutTsiIndex ); UINT32 Oct6100ApiUpdateOpenStruct( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChanModify, IN OUT tPOCT6100_CHANNEL_OPEN f_pChanOpen, IN tPOCT6100_API_CHANNEL f_pChanEntry ); UINT32 Oct6100ApiRetrieveNlpConfDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_CHANNEL f_pChanEntry, IN UINT32 f_ulAddress, OUT PUINT32 f_pulConfigDword ); UINT32 Oct6100ApiSaveNlpConfDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_CHANNEL f_pChanEntry, IN UINT32 f_ulAddress, IN UINT32 f_ulConfigDword ); UINT32 Oct6100ChannelCreateBiDirSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT IN OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ); UINT32 Oct6100ApiCheckChannelCreateBiDirParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir, OUT PUINT16 f_pusFirstChanIndex, OUT PUINT16 f_pusFirstChanExtraTsiIndex, OUT PUINT16 f_pusFirstChanSinCopyEventIndex, OUT PUINT16 f_pusSecondChanIndex, OUT PUINT16 f_pusSecondChanExtraTsiIndex, OUT PUINT16 f_pusSecondChanSinCopyEventIndex ); UINT32 Oct6100ApiReserveChannelCreateBiDirResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusBiDirChanIndex, IN OUT PUINT16 f_pusFirstChanExtraTsiIndex, IN OUT PUINT16 f_pusFirstChanSinCopyEventIndex, OUT PUINT16 f_pusFirstChanSoutCopyEventIndex, IN OUT PUINT16 f_pusSecondChanExtraTsiIndex, IN OUT PUINT16 f_pusSecondChanSinCopyEventIndex, OUT PUINT16 f_pusSecondChanSoutCopyEventIndex ); UINT32 Oct6100ApiWriteChannelCreateBiDirStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usFirstChanExtraTsiIndex, IN UINT16 f_usFirstChanSinCopyEventIndex, IN UINT16 f_usFirstChanSoutCopyEventIndex, IN UINT16 f_usSecondChanIndex, IN UINT16 f_usSecondChanExtraTsiIndex, IN UINT16 f_usSecondChanSinCopyEventIndex, IN UINT16 f_usSecondChanSoutCopyEventIndex ); UINT32 Oct6100ApiUpdateBiDirChannelEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir, IN UINT16 f_usBiDirChanIndex, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usFirstChanExtraTsiIndex, IN UINT16 f_usFirstChanSinCopyEventIndex, IN UINT16 f_usFirstChanSoutCopyEventIndex, IN UINT16 f_usSecondChanIndex, IN UINT16 f_usSecondChanExtraTsiIndex, IN UINT16 f_usSecondChanSinCopyEventIndex, IN UINT16 f_usSecondChanSoutCopyEventIndex ); UINT32 Oct6100ChannelDestroyBiDirSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ); UINT32 Oct6100ApiAssertDestroyBiDirChanParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir, IN OUT PUINT16 f_pusBiDirChanIndex, IN OUT PUINT16 f_pusFirstChanIndex, IN OUT PUINT16 f_pusSecondChanIndex ); UINT32 Oct6100ApiInvalidateBiDirChannelStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usSecondChanIndex ); UINT32 Oct6100ApiReleaseBiDirChannelResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBiDirChanIndex, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usSecondChanIndex ); UINT32 Oct6100ApiWriteDebugChanMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN UINT16 f_usRinRoutTsiIndex, IN UINT16 f_usSinSoutTsiIndex ); UINT32 Oct6100ApiDebugChannelOpen( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiMutePorts( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEchoIndex, IN UINT16 f_usRinTsstIndex, IN UINT16 f_usSinTsstIndex, IN BOOL f_fCheckBridgeIndex ); UINT32 Oct6100ApiSetChannelLevelControl( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearAlcHlcStatusBit ); UINT32 Oct6100ApiSetChannelTailConfiguration( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fModifyOnly ); UINT32 Oct6100ChannelMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MUTE f_pChannelMute ); UINT32 Oct6100ApiAssertChannelMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MUTE f_pChannelMute, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusPorts ); UINT32 Oct6100ChannelUnMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ); UINT32 Oct6100ApiAssertChannelUnMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusPorts ); UINT32 Oct6100ApiMuteSinWithFeatures( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN BOOL f_fEnableSinWithFeatures ); UINT32 Oct6100ApiMuteChannelPorts( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usPortMask, IN BOOL f_fMute ); INT32 Oct6100ApiOctFloatToDbEnergyByte( IN UINT8 x ); INT32 Oct6100ApiOctFloatToDbEnergyHalf( IN UINT16 x ); UINT16 Oct6100ApiDbAmpHalfToOctFloat( IN INT32 x ); #endif /* __OCT6100_CHANNEL_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tsi_cnct_priv.h0000644000175000017500000001122511431317470030366 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsi_cnct_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_tsi_cnct.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_tsi_cnct_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TSI_CNCT_PRIV_H__ #define __OCT6100_TSI_CNCT_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* TSI connection list pointer macros. */ #define mOCT6100_GET_TSI_CNCT_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_TSI_CNCT )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsiCnctListOfst ); #define mOCT6100_GET_TSI_CNCT_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_TSI_CNCT )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsiCnctListOfst)) + ulIndex; #define mOCT6100_GET_TSI_CNCT_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsiCnctAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetTsiCnctSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiTsiCnctSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100TsiCnctOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ); UINT32 Oct6100ApiCheckTsiParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ); UINT32 Oct6100ApiReserveTsiResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ); UINT32 Oct6100ApiWriteTsiStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100ApiUpdateTsiEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100TsiCnctCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ); UINT32 Oct6100ApiAssertTsiParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ); UINT32 Oct6100ApiInvalidateTsiStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100ApiReleaseTsiResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usTsiMemIndex ); UINT32 Oct6100ApiReserveTsiCnctEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusTsiChanIndex ); UINT32 Oct6100ApiReleaseTsiCnctEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiChanIndex ); #endif /* __OCT6100_TSI_CNCT_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_events_priv.h0000644000175000017500000000602711431317470030070 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_events_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_events.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_events_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_EVENTS_PRIV_H__ #define __OCT6100_EVENTS_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftBuf ) \ pSoftBuf = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->SoftBufs.ulToneEventBufferMemOfst ); #define mOCT6100_GET_BUFFER_PLAYOUT_EVENT_BUF_PNT( pSharedInfo, pSoftBuf ) \ pSoftBuf = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferMemOfst ); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetEventsSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100EventGetToneSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_EVENT_GET_TONE f_pEventGetTone ); UINT32 Oct6100ApiTransferToneEvents( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulResetBuf ); UINT32 Oct6100BufferPlayoutGetEventSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ); UINT32 Oct6100BufferPlayoutTransferEvents( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulResetBuf ); UINT32 Oct6100BufferPlayoutCheckForSpecificEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulChannelPort, IN BOOL f_fSaveToSoftBuffer, OUT PBOOL f_pfEventDetected ); #endif /* __OCT6100_EVENTS_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tone_detection_priv.h0000644000175000017500000001001311431317470031555 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tone_detection_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_tone_detection.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_tone_detection_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TONE_DETECTION_PRIV_H__ #define __OCT6100_TONE_DETECTION_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ToneDetectionEnableSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable ); UINT32 Oct6100ApiCheckToneEnableParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulToneEventNumber, OUT PUINT32 f_pulExtToneChanIndex ); UINT32 Oct6100ApiWriteToneDetectEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex ); UINT32 Oct6100ApiUpdateChanToneDetectEntry ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex ); UINT32 Oct6100ToneDetectionDisableSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable ); UINT32 Oct6100ApiAssertToneDetectionParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulToneEventNumber, OUT PUINT32 f_pulExtToneChanIndex, OUT PBOOL f_pfDisableAll ); UINT32 Oct6100ApiClearToneDetectionEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex, IN BOOL f_fDisableAll ); UINT32 Oct6100ApiReleaseToneDetectionEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex, IN BOOL f_fDisableAll ); UINT32 Oct6100ApiIsSSTone( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulToneEventNumber, OUT PBOOL f_fSSTone ); UINT32 Oct6100ApiIs2100Tone( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulToneEventNumber, OUT PBOOL f_fIs2100Tone ); #endif /* __OCT6100_TONE_DETECTION_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_playout_buf_priv.h0000644000175000017500000001734411431317470031121 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_playout_buf_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_playout_buf.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_playout_buf_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 22 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PLAYOUT_BUF_PRIV_H__ #define __OCT6100_PLAYOUT_BUF_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* Playout buffer list pointer macros. */ #define mOCT6100_GET_BUFFER_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_BUFFER )(( PUINT8 )pSharedInfo + pSharedInfo->ulPlayoutBufListOfst ); #define mOCT6100_GET_BUFFER_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_BUFFER )(( PUINT8 )pSharedInfo + pSharedInfo->ulPlayoutBufListOfst)) + ulIndex; #define mOCT6100_GET_BUFFER_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulPlayoutBufAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetPlayoutBufferSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiPlayoutBufferSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100BufferLoadSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fReserveListStruct, IN UINT32 f_ulBufIndex ); UINT32 Oct6100BufferLoadBlockInitSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ); UINT32 Oct6100BufferLoadBlockSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ); UINT32 Oct6100ApiCheckBufferParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fCheckBufferPtr ); UINT32 Oct6100ApiCheckBufferLoadBlockParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock, OUT PUINT32 f_pulBufferBase ); UINT32 Oct6100ApiReserveBufferResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fReserveListStruct, IN UINT32 f_ulBufIndex, OUT PUINT32 f_pulBufIndex, OUT PUINT32 f_pulBufBase ); UINT32 Oct6100ApiWriteBufferInMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufferBase, IN UINT32 f_ulBufferLength, IN PUINT8 f_pbyBuffer ); UINT32 Oct6100ApiUpdateBufferEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN UINT32 f_ulBufIndex, IN UINT32 f_ulBufBase ); UINT32 Oct6100BufferUnloadSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_UNLOAD f_pBufferUnload, IN BOOL f_fReleaseListStruct ); UINT32 Oct6100ApiAssertBufferParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_UNLOAD f_pBufferUnload, OUT PUINT32 f_pulBufIndex, OUT PUINT32 f_pulBufBase ); UINT32 Oct6100ApiReleaseBufferResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufIndex, IN UINT32 f_ulBufBase, IN BOOL f_fReleaseListStruct ); UINT32 Oct6100BufferPlayoutAddSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ); UINT32 Oct6100ApiCheckPlayoutAddParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulBufferIndex ); UINT32 Oct6100ApiWriteBufferAddStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulBufferIndex ); UINT32 Oct6100BufferPlayoutStartSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, IN UINT32 f_ulPlayoutStopEventType ); UINT32 Oct6100ApiCheckPlayoutStartParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulBufferIndex, OUT PBOOL f_pfNotifyOnPlayoutStop, OUT PUINT32 f_pulUserEventId, OUT PBOOL f_pfAllowStartIfActive ); UINT32 Oct6100ApiWriteChanPlayoutStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulBufferIndex, IN BOOL f_fNotifyOnPlayoutStop, IN UINT32 f_ulUserEventId, IN BOOL f_fAllowStartIfActive, IN UINT32 f_ulPlayoutStopEventType ); UINT32 Oct6100ApiUpdateChanPlayoutEntry ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulBufferIndex ); UINT32 Oct6100BufferPlayoutStopSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ); UINT32 Oct6100ApiAssertPlayoutStopParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop, OUT PUINT32 f_pulChannelIndex, OUT PUINT16 f_pusEchoMemIndex ); UINT32 Oct6100ApiInvalidateChanPlayoutStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop, IN UINT32 f_ulChannelIndex, IN UINT16 f_usEchoMemIndex ); UINT32 Oct6100ApiReleaseChanPlayoutResources ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop, IN UINT32 f_ulChannelIndex ); UINT32 Oct6100ApiReserveBufPlayoutListEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulBufIndex ); UINT32 Oct6100ApiReleaseBufPlayoutListEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufIndex ); #endif /* __OCT6100_PLAYOUT_BUF_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_interrupts_priv.h0000644000175000017500000001375111431317470031005 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_interrupts_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_interrupts.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_interrupts_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 11 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_INTERRUPTS_PRIV_H__ #define __OCT6100_INTERRUPTS_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_INTRPT_ENABLE_TIME( \ ulRegMclkTimeHigh, \ ulRegMclkTimeLow, \ ulIntrptState, \ ulIntrptEnableMclkHigh, \ ulIntrptEnableMclkLow, \ ulIntrptTimeoutMclk, \ ulTimeDiff ) \ if ( ulIntrptState == cOCT6100_INTRPT_WILL_TIMEOUT ) \ { \ ulIntrptEnableMclkLow = ulRegMclkTimeLow + ulIntrptTimeoutMclk; \ if ( ulIntrptEnableMclkLow < ulRegMclkTimeLow ) \ ulIntrptEnableMclkHigh = (ulRegMclkTimeHigh + 1) & 0xFF; \ else \ ulIntrptEnableMclkHigh = ulRegMclkTimeHigh; \ \ ulIntrptState = cOCT6100_INTRPT_IN_TIMEOUT; \ } \ \ if ( ulIntrptEnableMclkLow < ulRegMclkTimeLow ) \ { \ ulTimeDiff = (cOCT6100_FFFFFFFF - ulRegMclkTimeLow - 1) + ulIntrptEnableMclkLow; \ } \ else \ { \ ulTimeDiff = ulIntrptEnableMclkLow - ulRegMclkTimeLow; \ } #define mOCT6100_CHECK_INTRPT_TIMEOUT( \ ulRegMclkTimePlus5MsHigh, \ ulRegMclkTimePlus5MsLow, \ ulIntrptDisableMclkHigh, \ ulIntrptDisableMclkLow, \ ulIntrptEnableMclkHigh, \ ulIntrptEnableMclkLow, \ ulIntrptState, \ fIntrptChange ) \ /* Branch depending on whether the disable time is lesser or greater than the timeout time. */ \ if ( ulIntrptDisableMclkLow < ulIntrptEnableMclkLow ) \ { \ /* Disable period is over if mclk is greater than timeout time or less than disabled time. */ \ if ( ulRegMclkTimePlus5MsLow > ulIntrptEnableMclkLow || \ ulRegMclkTimePlus5MsLow < ulIntrptDisableMclkLow || \ ulRegMclkTimePlus5MsHigh != ulIntrptEnableMclkHigh ) \ { \ fIntrptChange = TRUE; \ ulIntrptState = cOCT6100_INTRPT_ACTIVE; \ } \ } \ else \ { \ /* Disable period is over if mclk is lesser than disable time and greater than timeout. */ \ if ( (ulRegMclkTimePlus5MsLow > ulIntrptEnableMclkLow && ulRegMclkTimePlus5MsLow < ulIntrptDisableMclkLow) || \ (ulRegMclkTimePlus5MsHigh != ulIntrptDisableMclkHigh && ulRegMclkTimePlus5MsHigh != ulIntrptEnableMclkHigh) ) \ { \ fIntrptChange = TRUE; \ ulIntrptState = cOCT6100_INTRPT_ACTIVE; \ } \ } /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiIsrSwInit( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiIsrHwInit( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig ); UINT32 Oct6100InterruptConfigureSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig, IN BOOL f_fCheckParams ); UINT32 Oct6100ApiClearEnabledInterrupts( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100InterruptServiceRoutineSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ); UINT32 Oct6100ApiWriteIeRegs( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiReadIntrptRegs( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags, IN UINT32 f_ulRegister210h ); UINT32 Oct6100ApiUpdateIntrptStates( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ); UINT32 Oct6100ApiWriteIntrptRegs( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiReadChipMclkTime( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiUpdateIntrptTimeouts( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiScheduleNextMclkIntrpt( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulIntrptToSet ); UINT32 Oct6100ApiScheduleNextMclkIntrptSer( IN tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiCheckProcessorState( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ); #endif /* __OCT6100_INTERRUPTS_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_conf_bridge_priv.h0000644000175000017500000003130211431317470031017 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_conf_bridge_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_conf_bridge.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_conf_bridge_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 30 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CONF_BRIDGE_PRIV_H__ #define __OCT6100_CONF_BRIDGE_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_CONF_BRIDGE_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_CONF_BRIDGE )(( PUINT8 )pSharedInfo + pSharedInfo->ulConfBridgeListOfst); #define mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_CONF_BRIDGE )(( PUINT8 )pSharedInfo + pSharedInfo->ulConfBridgeListOfst)) + ulIndex; #define mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulConfBridgeAllocOfst); #define mOCT6100_GET_FLEX_CONF_PARTICIPANT_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_FLEX_CONF_PARTICIPANT )(( PUINT8 )pSharedInfo + pSharedInfo->ulFlexConfParticipantListOfst); #define mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_FLEX_CONF_PARTICIPANT )(( PUINT8 )pSharedInfo + pSharedInfo->ulFlexConfParticipantListOfst)) + ulIndex; #define mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulFlexConfParticipantAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetConfBridgeSwSizes( IN OUT tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiConfBridgeSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInst ); UINT32 Oct6100ConfBridgeOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ); UINT32 Oct6100ApiCheckBridgeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ); UINT32 Oct6100ApiReserveBridgeResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, OUT PUINT16 f_pusBridgeIndex ); UINT32 Oct6100ApiUpdateBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen, IN UINT16 f_usBridgeIndex ); UINT32 Oct6100ConfBridgeCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ); UINT32 Oct6100ApiAssertBridgeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose, OUT PUINT16 f_pusBridgeIndex ); UINT32 Oct6100ApiReleaseBridgeResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex ); UINT32 Oct6100ConfBridgeChanAddSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ); UINT32 Oct6100ApiCheckBridgeAddParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd, OUT PUINT16 f_pusBridgeIndex, OUT PUINT16 f_pusChannelIndex, OUT PUINT8 f_pfMute, OUT PUINT32 f_pulInputPort, OUT PUINT8 f_pfFlexibleConfBridge, OUT PUINT32 f_pulListenerMaskIndex, OUT PUINT32 f_pulListenerMask, OUT PUINT8 f_pfTap, OUT PUINT16 f_pusTapChannelIndex ); UINT32 Oct6100ApiReserveBridgeAddResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulInputPort, IN UINT8 f_fFlexibleConfBridge, IN UINT32 f_ulListenerMaskIndex, IN UINT32 f_ulListenerMask, IN UINT8 f_fTap, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT16 f_pusCopyEventIndex, OUT PUINT16 f_pusTapBridgeIndex ); UINT32 Oct6100ApiBridgeEventAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChannelIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT32 f_ulInputPort, IN UINT8 f_fMute, IN UINT32 f_ulListenerMaskIndex, IN UINT32 f_ulListenerMask, IN UINT8 f_fTap, IN UINT16 f_usTapBridgeIndex, IN UINT16 f_usTapChanIndex ); UINT32 Oct6100ApiBridgeAddParticipantToChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usSourceChannelIndex, IN UINT16 f_usDestinationChannelIndex, IN UINT16 f_usLoadOrAccumulateEventIndex, IN UINT16 f_usStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT32 f_ulSourceInputPort, IN UINT32 f_ulDestinationInputPort ); UINT32 Oct6100ConfBridgeChanRemoveSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ); UINT32 Oct6100ApiCheckChanRemoveParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, OUT PUINT16 f_pusBridgeIndex, OUT PUINT16 f_pusChannelIndex, OUT PUINT8 f_pfFlexibleConfBridge, OUT PUINT8 f_pfTap, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT16 f_pusCopyEventIndex ); UINT32 Oct6100ApiReleaseChanEventResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex ); UINT32 Oct6100ApiBridgeEventRemove ( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChannelIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT8 f_fTap ); UINT32 Oct6100ApiBridgeRemoveParticipantFromChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usSourceChannelIndex, IN UINT16 f_usDestinationChannelIndex, IN UINT8 f_fRemovePermanently ); UINT32 Oct6100ConfBridgeChanMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ); UINT32 Oct6100ApiUpdateBridgeMuteResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usChanIndex, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT8 f_fFlexibleConfBridge ); UINT32 Oct6100ApiCheckBridgeMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT8 f_pfFlexibleConfBridge ); UINT32 Oct6100ConfBridgeChanUnMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ); UINT32 Oct6100ApiCheckBridgeUnMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT8 f_pfFlexibleConfBridge ); UINT32 Oct6100ApiUpdateBridgeUnMuteResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usChanIndex, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT8 f_fFlexibleConfBridge ); UINT32 Oct6100ConfBridgeDominantSpeakerSetSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ); UINT32 Oct6100ApiCheckBridgeDominantSpeakerParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusBridgeIndex ); UINT32 Oct6100ApiUpdateBridgeDominantSpeakerResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usChanIndex, IN UINT16 f_usBridgeIndex ); UINT32 Oct6100ConfBridgeMaskChangeSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ); UINT32 Oct6100ApiCheckBridgeMaskChangeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusBridgeIndex, OUT PUINT32 f_pulNewParticipantMask ); UINT32 Oct6100ApiUpdateMaskModifyResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulNewListenerMask ); UINT32 Oct6100ApiBridgeUpdateMask( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulNewListenerMask ); UINT32 Oct6100ConfBridgeGetStatsSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN OUT tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ); UINT32 Oct6100ApiReserveBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, OUT PUINT16 f_pusConfBridgeIndex ); UINT32 Oct6100ApiReleaseBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usConfBridgeIndex ); UINT32 Oct6100ApiGetPrevLastSubStoreEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usBridgeIndex, IN UINT16 f_usBridgeFirstLoadEventPtr, OUT PUINT16 f_pusLastSubStoreEventIndex ); UINT32 Oct6100ApiGetPreviousEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usStartIndex, IN UINT16 f_usSearchedIndex, IN UINT16 f_usLoopCnt, OUT PUINT16 f_pusPreviousIndex ); UINT32 Oct6100ApiBridgeSetDominantSpeaker( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usChannelIndex, IN UINT16 f_usDominantSpeakerIndex ); UINT32 Oct6100ApiReserveFlexConfParticipantEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, OUT PUINT16 f_pusParticipantIndex ); UINT32 Oct6100ApiReleaseFlexConfParticipantEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInst, IN UINT16 f_usParticipantIndex ); #endif /* __OCT6100_CONF_BRIDGE_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_miscellaneous_priv.h0000644000175000017500000002576111525010337031431 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_miscellaneous_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_miscellaneous.c. All elements defined in this file are for private usage of the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 20 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_MISCELLANEOUS_PRIV_H__ #define __OCT6100_MISCELLANEOUS_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /*---------------------------------------------------------------------------*\ Macros used to shell the user function calls. These macros are used to assert that the user does not change any of the members of the function's parameter structure, as required and indicated in the API specification. Ofcourse, these macros make the code heavier and thus slower. That is why there is a compile option for disabling the extra checking. These can be very helpful tools in debugging. \*---------------------------------------------------------------------------*/ #ifndef cOCT6100_REMOVE_USER_FUNCTION_CHECK #define mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) \ { \ PVOID _pProcessContext; \ UINT32 _ulUserChipId; \ UINT32 _ulWriteAddress; \ UINT16 _usWriteData; \ \ /* Store the data that is to be passed to the user. */ \ _pProcessContext = WriteParams.pProcessContext; \ _ulUserChipId = WriteParams.ulUserChipId; \ _ulWriteAddress = WriteParams.ulWriteAddress; \ _usWriteData = WriteParams.usWriteData; \ \ /* Call user function. */ \ ulResult = Oct6100UserDriverWriteApi( &WriteParams ); \ \ /* Check if user changed members of function's parameter structure. */ \ if ( WriteParams.pProcessContext != _pProcessContext || \ WriteParams.ulUserChipId != _ulUserChipId || \ WriteParams.ulWriteAddress != _ulWriteAddress || \ WriteParams.ulWriteAddress != _ulWriteAddress || \ WriteParams.usWriteData != _usWriteData ) \ ulResult = cOCT6100_ERR_FATAL_DRIVER_WRITE_API; \ } #else #define mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) \ ulResult = Oct6100UserDriverWriteApi( &WriteParams ); #endif /* cOCT6100_REMOVE_USER_FUNCTION_CHECK */ #ifndef cOCT6100_REMOVE_USER_FUNCTION_CHECK #define mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ) \ { \ PVOID _pProcessContext; \ UINT32 _ulUserChipId; \ UINT32 _ulWriteAddress; \ UINT16 _usWriteData; \ UINT32 _ulWriteLength; \ \ /* Store the data that is to be passed to the user. */ \ _pProcessContext = SmearParams.pProcessContext; \ _ulUserChipId = SmearParams.ulUserChipId; \ _ulWriteAddress = SmearParams.ulWriteAddress; \ _usWriteData = SmearParams.usWriteData; \ _ulWriteLength = SmearParams.ulWriteLength; \ \ /* Call user function. */ \ ulResult = Oct6100UserDriverWriteSmearApi( &SmearParams ); \ \ /* Check if user changed members of function's paraeter structure. */ \ if ( SmearParams.pProcessContext != _pProcessContext || \ SmearParams.ulUserChipId != _ulUserChipId || \ SmearParams.usWriteData != _usWriteData || \ SmearParams.ulWriteLength != _ulWriteLength) \ ulResult = cOCT6100_ERR_FATAL_DRIVER_WRITE_SMEAR_API; \ } #else #define mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ) \ ulResult = Oct6100UserDriverWriteSmearApi( &SmearParams ); #endif /* cOCT6100_REMOVE_USER_FUNCTION_CHECK */ #ifndef cOCT6100_REMOVE_USER_FUNCTION_CHECK #define mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ) \ { \ PVOID _pProcessContext; \ UINT32 _ulUserChipId; \ UINT32 _ulWriteAddress; \ PUINT16 _pusWriteData; \ UINT32 _ulWriteLength; \ \ /* Store the data that is to be passed to the user. */ \ _pProcessContext = BurstParams.pProcessContext; \ _ulUserChipId = BurstParams.ulUserChipId; \ _ulWriteAddress = BurstParams.ulWriteAddress; \ _pusWriteData = BurstParams.pusWriteData; \ _ulWriteLength = BurstParams.ulWriteLength; \ \ /* Call user function. */ \ ulResult = Oct6100UserDriverWriteBurstApi( &BurstParams ); \ \ /* Check if user changed members of function's parameter structure. */ \ if ( BurstParams.pProcessContext != _pProcessContext || \ BurstParams.ulUserChipId != _ulUserChipId || \ BurstParams.ulWriteAddress != _ulWriteAddress || \ BurstParams.pusWriteData != _pusWriteData || \ BurstParams.ulWriteLength != _ulWriteLength ) \ ulResult = cOCT6100_ERR_FATAL_DRIVER_WRITE_BURST_API; \ } #else #define mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ) \ ulResult = Oct6100UserDriverWriteBurstApi( &BurstParams ); #endif /* cOCT6100_REMOVE_USER_FUNCTION_CHECK */ #ifndef cOCT6100_REMOVE_USER_FUNCTION_CHECK #define mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) \ { \ PVOID _pProcessContext; \ UINT32 _ulUserChipId; \ UINT32 _ulReadAddress; \ PUINT16 _pusReadData; \ \ /* Store the data that is to be passed to the user. */ \ _pProcessContext = ReadParams.pProcessContext; \ _ulUserChipId = ReadParams.ulUserChipId; \ _ulReadAddress = ReadParams.ulReadAddress; \ _pusReadData = ReadParams.pusReadData; \ \ /* Call user function. */ \ ulResult = Oct6100UserDriverReadApi( &ReadParams ); \ \ /* Check if user changed members of function's parameter structure. */ \ if ( ReadParams.pProcessContext != _pProcessContext || \ ReadParams.ulUserChipId != _ulUserChipId || \ ReadParams.ulReadAddress != _ulReadAddress || \ ReadParams.pusReadData != _pusReadData ) \ ulResult = cOCT6100_ERR_FATAL_DRIVER_READ_API; \ } #else #define mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) \ ulResult = Oct6100UserDriverReadApi( &ReadParams ); #endif /* cOCT6100_REMOVE_USER_FUNCTION_CHECK */ #ifndef cOCT6100_REMOVE_USER_FUNCTION_CHECK #define mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ) \ { \ PVOID _pProcessContext; \ UINT32 _ulUserChipId; \ UINT32 _ulReadAddress; \ PUINT16 _pusReadData; \ UINT32 _ulReadLength; \ \ /* Store the data that is to be passed to the user. */ \ _pProcessContext = BurstParams.pProcessContext; \ _ulUserChipId = BurstParams.ulUserChipId; \ _ulReadAddress = BurstParams.ulReadAddress; \ _pusReadData = BurstParams.pusReadData; \ _ulReadLength = BurstParams.ulReadLength; \ \ /* Call user function. */ \ ulResult = Oct6100UserDriverReadBurstApi( &BurstParams ); \ \ /* Check if user changed members of function's parameter structure. */ \ if ( BurstParams.pProcessContext != _pProcessContext || \ BurstParams.ulUserChipId != _ulUserChipId || \ BurstParams.ulReadAddress != _ulReadAddress || \ BurstParams.pusReadData != _pusReadData || \ BurstParams.ulReadLength != _ulReadLength ) \ ulResult = cOCT6100_ERR_FATAL_DRIVER_READ_BURST_API; \ } #else #define mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ) \ ulResult = Oct6100UserDriverReadBurstApi( &BurstParams ); #endif /* cOCT6100_REMOVE_USER_FUNCTION_CHECK */ #define mOCT6100_ASSIGN_USER_READ_WRITE_OBJ( f_pApiInst, Params ) #define mOCT6100_CREATE_FEATURE_MASK( f_ulFieldSize, f_ulFieldBitOffset, f_pulFieldMask ) \ { \ (*f_pulFieldMask) = ( 1 << f_ulFieldSize ); \ (*f_pulFieldMask) --; \ (*f_pulFieldMask) <<= f_ulFieldBitOffset; \ } /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiWaitForTime( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_aulWaitTime[ 2 ] ); UINT32 Oct6100ApiWaitForPcRegisterBit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulPcRegAdd, IN UINT32 f_ulPcBitNum, IN UINT32 f_ulValue, IN UINT32 f_ulTimeoutUs, OUT PBOOL f_pfBitEqual ); UINT32 Oct6100ApiWriteDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, IN UINT32 f_ulWriteData ); UINT32 Oct6100ApiReadDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, OUT PUINT32 f_pulReadData ); VOID Oct6100ApiCreateFeatureMask( IN UINT32 f_ulFieldSize, IN UINT32 f_ulFieldBitOffset, OUT PUINT32 f_pulFieldMask ); unsigned char const *Oct6100ApiStrStr( IN unsigned char const *f_pszSource, IN unsigned char const *f_pszString, IN unsigned char const *f_pszLastCharPtr ); UINT32 Oct6100ApiStrLen( IN unsigned char const *f_pszString ); UINT32 Oct6100ApiAsciiToHex( IN UINT8 f_chCharacter, IN PUINT32 f_pulValue ); UINT8 Oct6100ApiHexToAscii( IN UINT32 f_ulNumber ); UINT32 Oct6100ApiRand( IN UINT32 f_ulRange ); UINT32 oct6100_retrieve_nlp_conf_dword(tPOCT6100_INSTANCE_API f_pApiInst, tPOCT6100_API_CHANNEL f_pChanEntry, UINT32 f_ulAddress, UINT32 *f_pulConfigDword); UINT32 oct6100_save_nlp_conf_dword(tPOCT6100_INSTANCE_API f_pApiInst, tPOCT6100_API_CHANNEL f_pChanEntry, UINT32 f_ulAddress, UINT32 f_ulConfigDword); #endif /* __OCT6100_MISCELLANEOUS_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_debug_priv.h0000644000175000017500000000406511431317470027652 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_debug_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_debug.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_debug_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 12 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_DEBUG_PRIV_H__ #define __OCT6100_DEBUG_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100DebugSelectChannelSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan, IN BOOL f_fCheckChannelRecording ); UINT32 Oct6100DebugGetDataSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_DEBUG_GET_DATA f_pGetData ); #endif /* __OCT6100_DEBUG_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_memory_priv.h0000644000175000017500000000676711431317470030107 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_memory_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_memory.c. All elements defined in this file are for private usage of the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 17 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_MEMORY_PRIV_H__ #define __OCT6100_MEMORY_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* TSI allocation pointer macros. */ #define mOCT6100_GET_TSI_MEMORY_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsiMemoryAllocOfst ); /* Conversion memory allocation pointer macros. */ #define mOCT6100_GET_CONVERSION_MEMORY_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulConversionMemoryAllocOfst ); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetMemorySwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiMemorySwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiBufferPlayoutMemorySwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiReserveBufferPlayoutMemoryNode( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulNewNode ); UINT32 Oct6100ApiReleaseBufferPlayoutMemoryNode( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulOldNode ); UINT32 Oct6100ApiReserveBufferPlayoutMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulSize, OUT PUINT32 f_pulMallocAddress ); UINT32 Oct6100ApiReleaseBufferPlayoutMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulMallocAddress ); UINT32 Oct6100ApiReserveTsiMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusTsiMemIndex ); UINT32 Oct6100ApiReleaseTsiMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiMemIndex ); UINT32 Oct6100ApiReserveConversionMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusConversionMemIndex ); UINT32 Oct6100ApiReleaseConversionMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usConversionMemIndex ); #endif /* __OCT6100_MEMORY_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_remote_debug_priv.h0000644000175000017500000001276411431317470031232 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_remote_debug_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_remote_debug.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_remote_debug_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 13 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_REMOTE_DEBUG_PRIV_H__ #define __OCT6100_REMOTE_DEBUG_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, ulIndex, pEntry ) \ pEntry = ( tPOCT6100_API_REMOTE_DEBUG_SESSION )(( PUINT8 )pSharedInfo + pSharedInfo->RemoteDebugInfo.ulSessionListOfst) + ulIndex; #define mOCT6100_GET_REMOTE_DEBUG_TREE_PNT( pSharedInfo, pList ) \ pList = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->RemoteDebugInfo.ulSessionTreeOfst); #define mOCT6100_GET_REMOTE_DEBUG_DATA_BUF_PNT( pSharedInfo, pulDataBuf ) \ pulDataBuf = ( PUINT16 )(( PUINT8 )pSharedInfo + pSharedInfo->RemoteDebugInfo.ulDataBufOfst); #define mOCT6100_GET_REMOTE_DEBUG_SESSION_PKT_CACHE_PNT( pSharedInfo, pulPktCache, ulSessionIndex ) \ pulPktCache = ( PUINT32 )(( PUINT8 )pSharedInfo + pSharedInfo->RemoteDebugInfo.ulPktCacheOfst) + (ulSessionIndex * (cOCTRPC_MAX_PACKET_BYTE_LENGTH / 4)); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetRemoteDebugSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiRemoteDebuggingSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiCheckEndianDetectField( IN tPOCTRPC_OGRDTP_HEADER f_pOgrdtpHeader, IN UINT32 f_ulPktLengthDword ); VOID Oct6100ApiCalculateChecksum( IN PUINT32 f_pulPktPayload, IN UINT32 f_ulPktLengthDword, OUT PUINT32 f_pulChecksum ); VOID Oct6100ApiFormResponsePkt( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, IN OUT PUINT32 f_pulRspPktPayload, IN UINT32 f_ulPktLengthDword, IN BOOL f_fRetryPktResponse, IN BOOL f_fReplaceProtocolNum, IN BOOL f_fReplaceInterfaceType, IN BOOL f_fReplaceInterfaceVersion, IN UINT32 f_ulSessionIndex, IN UINT32 f_ulParsingErrorValue, IN UINT32 f_ulPayloadDwordIndex, IN UINT32 f_ulChecksum ); UINT32 Oct6100ApiCheckPktCommands( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, IN OUT PUINT32 f_pulRspPktPayload, IN UINT32 f_ulSessionIndex, IN UINT32 f_ulPktLengthDword, IN UINT32 f_ulChecksum ); VOID Oct6100ApiExecutePktCommands( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, IN UINT32 f_ulPktLengthDword ); UINT32 Oct6100ApiCheckSessionNum( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCTRPC_OGRDTP_HEADER f_pOgrdtpHeader, OUT PUINT32 f_pulSessionIndex ); VOID Oct6100ApiRpcReadWord( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcReadBurst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcReadArray( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcWriteWord( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcWriteSmear( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcWriteBurst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcSetHotChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcGetDebugChanIndex( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ); VOID Oct6100ApiRpcDisconnect( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader, IN OUT UINT32 f_ulSessionNumber ); #endif /* __OCT6100_REMOTE_DEBUG_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_version.h0000644000175000017500000000256711431317470027216 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_version.h Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the version of API. To obtain that version number, the user must call the API function Oct6100ApiGetVersion(). This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 52 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_VERSION_H__ #define __OCT6100_VERSION_H__ /* String version of the OCT6100 API.*/ #define cOCT6100_API_VERSION "OCT6100API-01.00-PR49" #endif /* __OCT6100_VERSION_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_phasing_tsst_priv.h0000644000175000017500000001056611431317470031275 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_phasing_tsst_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_phasing_tsst.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_phasing_tsst_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 12 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_PHASING_TSST_PRIV_H__ #define __OCT6100_PHASING_TSST_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_PHASING_TSST_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_PHASING_TSST )(( PUINT8 )pSharedInfo + pSharedInfo->ulPhasingTsstListOfst); #define mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_PHASING_TSST )(( PUINT8 )pSharedInfo + pSharedInfo->ulPhasingTsstListOfst)) + ulIndex; #define mOCT6100_GET_PHASING_TSST_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulPhasingTsstAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetPhasingTsstSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiPhasingTsstSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100PhasingTsstOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ); UINT32 Oct6100ApiCheckPhasingParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ); UINT32 Oct6100ApiReservePhasingResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, OUT PUINT16 f_pusPhasingIndex, OUT PUINT16 f_pusTsstIndex ); UINT32 Oct6100ApiWritePhasingStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, IN UINT16 f_usPhasingIndex, IN UINT16 f_usTsstIndex ); UINT32 Oct6100ApiUpdatePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, IN UINT16 f_usPhasingIndex, IN UINT16 f_usTsstIndex ); UINT32 Oct6100PhasingTsstCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ); UINT32 Oct6100ApiAssertPhasingParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose, OUT PUINT16 f_pusPhasingIndex, OUT PUINT16 f_pusTsstIndex ); UINT32 Oct6100ApiInvalidatePhasingStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex ); UINT32 Oct6100ApiReleasePhasingResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT UINT16 f_usPhasingIndex ); UINT32 Oct6100ApiReservePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusPhasingIndex ); UINT32 Oct6100ApiReleasePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usPhasingIndex ); #endif /* #ifndef cOCT6100_REMOVE_PHASING_TSST */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_chip_stats_priv.h0000644000175000017500000000373611431317470030731 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_stats_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_chip_stats.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_chip_stats_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 8 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_STATS_PRIV_H__ #define __OCT6100_CHIP_STATS_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiChipStatsSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ChipGetStatsSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_CHIP_STATS f_pChipStats ); #endif /* __OCT6100_CHIP_STATS_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_mixer_priv.h0000644000175000017500000001363511431317470027713 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_mixer_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_mixer.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_mixer_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 18 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_MIXER_PRIV_H__ #define __OCT6100_MIXER_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ #define mOCT6100_GET_MIXER_EVENT_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_MIXER_EVENT )(( PUINT8 )pSharedInfo + pSharedInfo->ulMixerEventListOfst); #define mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_MIXER_EVENT )(( PUINT8 )pSharedInfo + pSharedInfo->ulMixerEventListOfst)) + ulIndex; #define mOCT6100_GET_MIXER_EVENT_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulMixerEventAllocOfst); #define mOCT6100_GET_COPY_EVENT_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_COPY_EVENT )(( PUINT8 )pSharedInfo + pSharedInfo->ulCopyEventListOfst); #define mOCT6100_GET_COPY_EVENT_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_COPY_EVENT )(( PUINT8 )pSharedInfo + pSharedInfo->ulCopyEventListOfst)) + ulIndex; #define mOCT6100_GET_COPY_EVENT_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulCopyEventAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetMixerSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiMixerSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiMixerEventAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex, IN UINT16 f_usEventType, IN UINT16 f_usDestinationChanIndex ); UINT32 Oct6100ApiMixerEventRemove( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex, IN UINT16 f_usEventType ); UINT32 Oct6100MixerCopyEventCreateSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ); UINT32 Oct6100ApiCheckCopyEventCreateParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, OUT PUINT16 f_pusSourceChanIndex, OUT PUINT16 f_pusDestinationChanIndex ); UINT32 Oct6100ApiReserveCopyEventCreateResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusCopyEntryIndex, IN OUT PUINT16 f_pusCopyEventIndex ); UINT32 Oct6100ApiWriteCopyEventCreateStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, IN UINT16 f_usMixerEventIndex, IN UINT16 f_usSourceChanIndex, IN UINT16 f_usDestinationChanIndex ); UINT32 Oct6100ApiUpdateCopyEventCreateEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex, IN UINT16 f_usSourceChanIndex, IN UINT16 f_usDestinationChanIndex ); UINT32 Oct6100MixerCopyEventDestroySer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ); UINT32 Oct6100ApiAssertCopyEventDestroyParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy, IN OUT PUINT16 f_pusCopyEventIndex, IN OUT PUINT16 f_pusMixerEventIndex ); UINT32 Oct6100ApiInvalidateCopyEventStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex ); UINT32 Oct6100ApiReleaseCopyEventResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex ); UINT32 Oct6100ApiReserveMixerEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEventIndex ); UINT32 Oct6100ApiReleaseMixerEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex ); UINT32 Oct6100ApiGetFreeMixerEventCnt( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulFreeEventCnt ); UINT32 Oct6100ApiReserveCopyEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEventIndex ); UINT32 Oct6100ApiReleaseCopyEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex ); #endif /* __OCT6100_MIXER_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_chip_open_priv.h0000644000175000017500000001746211431317470030535 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_open_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_chip_open.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_chip_open_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 63 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_CHIP_OPEN_PRIV_H__ #define __OCT6100_CHIP_OPEN_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /***************************** TYPES ***************************************/ typedef struct _OCT6100_API_INSTANCE_SIZES_ { /* Each of the following elements indicates the size of the instance memory */ /* needed by the corresponding API module. All sizes are in bytes. */ UINT32 ulChannelList; UINT32 ulChannelAlloc; UINT32 ulTsiCnctList; UINT32 ulTsiCnctAlloc; UINT32 ulMixerEventList; UINT32 ulMixerEventAlloc; UINT32 ulBiDirChannelList; UINT32 ulBiDirChannelAlloc; UINT32 ulAdpcmChannelList; UINT32 ulAdpcmChannelAlloc; UINT32 ulSoftBufPlayoutEventsBuffer; UINT32 ulCopyEventList; UINT32 ulCopyEventAlloc; UINT32 ulConfBridgeList; UINT32 ulConfBridgeAlloc; UINT32 ulFlexConfParticipantsList; UINT32 ulFlexConfParticipantsAlloc; UINT32 ulPlayoutBufList; UINT32 ulPlayoutBufAlloc; UINT32 ulPlayoutBufMemoryNodeList; UINT32 ulSoftToneEventsBuffer; UINT32 ulPhasingTsstList; UINT32 ulPhasingTsstAlloc; UINT32 ulConversionMemoryAlloc; UINT32 ulTsiMemoryAlloc; UINT32 ulTsstAlloc; UINT32 ulTsstEntryList; UINT32 ulTsstEntryAlloc; UINT32 ulRemoteDebugList; UINT32 ulRemoteDebugTree; UINT32 ulRemoteDebugPktCache; UINT32 ulRemoteDebugDataBuf; /* Memory consumed by static members of API instance. */ UINT32 ulApiInstStatic; /* Total memory size for API instance. */ UINT32 ulApiInstTotal; } tOCT6100_API_INSTANCE_SIZES, *tPOCT6100_API_INSTANCE_SIZES; /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiCheckChipConfiguration( IN tPOCT6100_CHIP_OPEN f_pOpenChip ); UINT32 Oct6100ApiCheckImageFileHeader( IN tPOCT6100_CHIP_OPEN f_pChipOpen ); UINT32 Oct6100ApiCopyChipConfiguration( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHIP_OPEN f_pOpenChip ); UINT32 Oct6100ApiInitializeMiscellaneousVariables( IN OUT tPOCT6100_INSTANCE_API f_pInstance ); UINT32 Oct6100ApiCalculateInstanceSizes( IN OUT tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstanceSizes ); UINT32 Oct6100ApiAllocateInstanceMemory( IN OUT tPOCT6100_INSTANCE_API f_pInstance, IN tPOCT6100_API_INSTANCE_SIZES f_pInstanceSizes ); UINT32 Oct6100ApiInitializeInstanceMemory( IN OUT tPOCT6100_INSTANCE_API f_pInstance ); UINT32 Oct6100ApiGetChipRevisionNum( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiMapExternalMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiDecodeKeyAndBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiBootFc2Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiProgramFc1Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiBootFc1Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiWriteH100Registers( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiExternalMemoryBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiExternalMemoryInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiLoadImage( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiCpuRegisterBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiBootSdram( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiEnableClocks( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiProgramNLP( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiSetH100Register( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiWriteMiscellaneousRegisters( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT16 Oct6100ApiGenerateNumber( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulIndex, IN UINT32 f_ulDataMask ); UINT32 Oct6100ApiRandomMemoryWrite( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulMemBase, IN UINT32 f_ulMemSize, IN UINT32 f_ulNumDataBits, IN UINT32 f_ulNumAccesses, IN UINT32 f_ulErrorCode ); UINT32 Oct6100ApiUserIoTest( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiCreateSerializeObjects( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulUserChipId ); UINT32 Oct6100ApiDestroySerializeObjects( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiRunEgo( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN BOOL f_fStoreFlag, IN UINT32 f_ulNumEntry, OUT PUINT32 f_aulEntry ); UINT32 Oct6100ApiCreateEgoEntry( IN OUT UINT32 f_ulExternalAddress, IN UINT32 f_ulInternalAddress, IN UINT32 f_ulNumBytes, IN UINT32 f_aulEntry[ 2 ] ); UINT32 Oct6100ApiInitChannels( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiInitMixer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiInitRecordResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100FreeResourcesSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_FREE_RESOURCES f_pFreeResources ); UINT32 Oct6100ProductionBistSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PRODUCTION_BIST f_pProductionBist ); UINT32 Oct6100ApiProductionCrc( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulMessage, IN UINT32 f_ulMessageLength, OUT PUINT32 f_pulCrcResult ); UINT32 Oct6100ApiReadCapacity( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ); UINT32 Oct6100ApiCpuRegisterBistReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ); UINT32 Oct6100ApiBootFc2PllReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ); UINT32 Oct6100ApiProgramFc1PllReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ); UINT32 Oct6100ApiInitToneInfo( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiClearInterrupts( IN tPOCT6100_INSTANCE_API f_pApiInstance ); #endif /* __OCT6100_CHIP_OPEN_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tlv_priv.h0000644000175000017500000005366511431317470027403 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tlv_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_tlv.c. All elements defined in this file are for private usage of the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 58 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TLV_PRIV_H__ #define __OCT6100_TLV_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* List of TLV types supported by this API. */ #define cOCT6100_TLV_TYPE_VERSION_NUMBER 0 #define cOCT6100_TLV_TYPE_CUSTOMER_PROJECT_ID 2 #define cOCT6100_TLV_TYPE_POUCH_BASE_ADDRESS 3 #define cOCT6100_TLV_TYPE_CH0_MAIN_BASE_ADDRESS 4 #define cOCT6100_TLV_TYPE_CH_MAIN_SIZE 5 #define cOCT6100_TLV_TYPE_CH_MAIN_IO_OFFSET 6 #define cOCT6100_TLV_TYPE_CH_MAIN_ZCB_OFFSET 7 #define cOCT6100_TLV_TYPE_CH_MAIN_ZCB_SIZE 8 #define cOCT6100_TLV_TYPE_CH_MAIN_XCB_OFFSET 9 #define cOCT6100_TLV_TYPE_CH_MAIN_XCB_SIZE 10 #define cOCT6100_TLV_TYPE_CH_MAIN_YCB_OFFSET 11 #define cOCT6100_TLV_TYPE_CH_MAIN_YCB_SIZE 12 #define cOCT6100_TLV_TYPE_FREE_MEM_BASE_ADDRESS 13 #define cOCT6100_TLV_TYPE_CH_ROOT_CONF_OFFSET 14 #define cOCT6100_TLV_TYPE_POA_CH_MAIN_ZPO_OFFSET 15 #define cOCT6100_TLV_TYPE_POA_CH_MAIN_ZPO_SIZE 16 #define cOCT6100_TLV_TYPE_POA_CH_MAIN_YPO_OFFSET 17 #define cOCT6100_TLV_TYPE_POA_CH_MAIN_YPO_SIZE 18 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_ZWP 19 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_ZIS 20 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_ZSP 21 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_YWP 22 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_YIS 23 #define cOCT6100_TLV_TYPE_POA_BOFF_RW_YSP 24 #define cOCT6100_TLV_TYPE_POA_BOFF_RO_ZRP 25 #define cOCT6100_TLV_TYPE_POA_BOFF_RO_YRP 26 #define cOCT6100_TLV_TYPE_CNR_CONF_BOFF_RW_ENABLE 27 #define cOCT6100_TLV_TYPE_ANR_CONF_BOFF_RW_ENABLE 28 #define cOCT6100_TLV_TYPE_HZ_CONF_BOFF_RW_ENABLE 29 #define cOCT6100_TLV_TYPE_HX_CONF_BOFF_RW_ENABLE 30 #define cOCT6100_TLV_TYPE_LCA_Z_CONF_BOFF_RW_GAIN 31 #define cOCT6100_TLV_TYPE_LCA_Y_CONF_BOFF_RW_GAIN 32 #define cOCT6100_TLV_TYPE_CNA_CONF_BOFF_RW_ENABLE 33 #define cOCT6100_TLV_TYPE_NOA_CONF_BOFF_RW_ENABLE 34 #define cOCT6100_TLV_TYPE_VFA_CONF_BOFF_RW_ENABLE 35 #define cOCT6100_TLV_TYPE_TLA_MAIN_IO_BOFF_RW_TAIL_DISP 37 #define cOCT6100_TLV_TYPE_STATSA_MAIN_IO_BOFF_RO_EPC 38 #define cOCT6100_TLV_TYPE_BOOTA_POUCH_BOFF_RW_BOOT_INST 39 #define cOCT6100_TLV_TYPE_BOOTA_POUCH_BOFF_RW_BOOT_RESULT 40 #define cOCT6100_TLV_TYPE_DIS_CONF_BOFF_RW_ENABLE 41 #define cOCT6100_TLV_TYPE_TDM_CONF_BOFF_RW_ENABLE 42 #define cOCT6100_TLV_TYPE_NT_CONF_BOFF_RW_ENABLE 43 #define cOCT6100_TLV_TYPE_AEC_CONF_BOFF_RW_ENABLE 44 #define cOCT6100_TLV_TYPE_PCM_LEAK_CONF_BOFF_RW 45 #define cOCT6100_TLV_TYPE_DEFAULT_ERL_CONF_BOFF_RW 46 #define cOCT6100_TLV_TYPE_TONE_REM_CONF_BOFF_RW_ENABLE 47 #define cOCT6100_TLV_TYPE_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT 48 #define cOCT6100_TLV_TYPE_NLP_CONV_CAP_CONF_BOFF_RW 49 #define cOCT6100_TLV_TYPE_MATRIX_EVENT_SIZE 50 #define cOCT6100_TLV_TYPE_CNR_RW_ENABLE 51 #define cOCT6100_TLV_TYPE_MAX_TAIL_LENGTH_RW_ENABLE 52 #define cOCT6100_TLV_TYPE_PLAYOUT_ENABLE 53 #define cOCT6100_TLV_TYPE_DOMINANT_SPEAKER_BOFF_RW_ENABLE 54 #define cOCT6100_TLV_TYPE_ANR_RW_ENABLE 57 #define cOCT6100_TLV_TYPE_TONE_REMOVAL_ENABLE 58 #define cOCT6100_TLV_TYPE_MUSIC_PROTECTION_RW_ENABLE 59 #define cOCT6100_TLV_TYPE_TAIL_DISP_CONF_BOFF_RW_ENABLE 60 #define cOCT6100_TLV_TYPE_IDLE_CODE_DETECTION_ENABLE 62 #define cOCT6100_TLV_TYPE_AEC_DEFAULT_ERL_BOFF 64 #define cOCT6100_TLV_TYPE_Z_ALC_TARGET_BOFF 65 #define cOCT6100_TLV_TYPE_Y_ALC_TARGET_BOFF 66 #define cOCT6100_TLV_TYPE_Z_HLC_TARGET_BOFF 67 #define cOCT6100_TLV_TYPE_Y_HLC_TARGET_BOFF 68 #define cOCT6100_TLV_TYPE_ALC_HLC_STATUS_BOFF 69 #define cOCT6100_TLV_TYPE_Z_PLAYOUT_HARD_SKIP_BOFF 70 #define cOCT6100_TLV_TYPE_Y_PLAYOUT_HARD_SKIP_BOFF 71 #define cOCT6100_TLV_TYPE_AFT_FIELD_BOFF 72 #define cOCT6100_TLV_TYPE_VOICE_DETECTED_STAT_BOFF 73 #define cOCT6100_TLV_TYPE_GAIN_APPLIED_RIN_STAT_BOFF 74 #define cOCT6100_TLV_TYPE_GAIN_APPLIED_SOUT_STAT_BOFF 75 #define cOCT6100_TLV_TYPE_MAX_ADAPT_ALE_BOFF 77 #define cOCT6100_TLV_TYPE_RIN_ANR_BOFF 78 #define cOCT6100_TLV_TYPE_NUMBER_PLAYOUT_EVENTS 79 #define cOCT6100_TLV_TYPE_RIN_MUTE_BOFF 80 #define cOCT6100_TLV_TYPE_SIN_MUTE_BOFF 81 #define cOCT6100_TLV_TYPE_CHAN_TAIL_LENGTH_BOFF 82 #define cOCT6100_TLV_TYPE_CHAN_VQE_TONE_DISABLING_BOFF 83 #define cOCT6100_TLV_TYPE_ANR_SNR_IMPROVEMENT_BOFF 84 #define cOCT6100_TLV_TYPE_ANR_AGRESSIVITY_BOFF 85 #define cOCT6100_TLV_TYPE_RIN_TONE_REM_CONF_BOFF_RW_ENABLE 86 #define cOCT6100_TLV_TYPE_RIN_TONE_REM_COUNTER_BOFF 87 #define cOCT6100_TLV_TYPE_AF_TAIL_DISP_VALUE_BOFF 88 #define cOCT6100_TLV_TYPE_POUCH_COUNTER_BOFF 89 #define cOCT6100_TLV_TYPE_AEC_TAIL_LENGTH_BOFF 90 #define cOCT6100_TLV_TYPE_MATRIX_DWORD_BASE 91 #define cOCT6100_TLV_TYPE_DEBUG_CHAN_STATS_BYTE_SIZE 92 #define cOCT6100_TLV_TYPE_RECORDED_PCM_EVENT_BYTE_SIZE 93 #define cOCT6100_TLV_TYPE_HOT_CHANNEL_SELECT_DWORD_BASE 94 #define cOCT6100_TLV_TYPE_IS_ISR_CALLED_BOFF 95 #define cOCT6100_TLV_TYPE_MATRIX_TIMESTAMP_DWORD_BASE 96 #define cOCT6100_TLV_TYPE_CHAN_MAIN_IO_STATS_OFFSET 100 #define cOCT6100_TLV_TYPE_CHAN_MAIN_IO_STATS_SIZE 101 #define cOCT6100_TLV_TYPE_AF_WRITE_PTR_BYTE_OFFSET 104 #define cOCT6100_TLV_TYPE_MATRIX_WP_DWORD_BASE 105 #define cOCT6100_TLV_TYPE_DEBUG_CHAN_LITE_STATS_BYTE_SIZE 106 #define cOCT6100_TLV_TYPE_MUSIC_PROTECTION_ENABLE_BOFF 107 #define cOCT6100_TLV_TYPE_IMAGE_TYPE 108 #define cOCT6100_TLV_TYPE_MAX_WIRELINE_CHANNELS 111 #define cOCT6100_TLV_TYPE_AF_EVENT_CB_SIZE 112 #define cOCT6100_TLV_TYPE_ZZ_ENERGY_CHAN_STATS_BOFF 116 #define cOCT6100_TLV_TYPE_YY_ENERGY_CHAN_STATS_BOFF 117 #define cOCT6100_TLV_TYPE_BUFFER_PLAYOUT_SKIP_IN_EVENTS 119 #define cOCT6100_TLV_TYPE_SOUT_NOISE_BLEACHING 121 #define cOCT6100_TLV_TYPE_DOUBLE_TALK_BEH_MODE 124 #define cOCT6100_TLV_TYPE_DOUBLE_TALK_BEH_MODE_BOFF 125 #define cOCT6100_TLV_TYPE_IDLE_CODE_DETECTION_BOFF 136 #define cOCT6100_TLV_TYPE_NLP_STATISTICS 138 #define cOCT6100_TLV_TYPE_RIN_ANR_VALUE 147 #define cOCT6100_TLV_TYPE_ADPCM_ENABLE 150 #define cOCT6100_TLV_TYPE_NUM_TONE_DETECTOR 151 #define cOCT6100_TLV_TYPE_CONFERENCING_ENABLE 152 #define cOCT6100_TLV_TYPE_MAX_NUMBER_OF_CHANNELS 153 #define cOCT6100_TLV_TYPE_DEBUG_CHAN_INDEX_VALUE 154 #define cOCT6100_TLV_TYPE_TONE_DETECTOR_PROFILE 155 #define cOCT6100_TLV_TYPE_TEST_MODE_ENABLE 156 #define cOCT6100_TLV_TYPE_MAX_TAIL_DISPLACEMENT 157 /* TLV length defines. */ #define cOCT6100_TLV_MIN_LENGTH_DEFAULT 4 #define cOCT6100_TLV_MAX_LENGTH_DEFAULT 0xFFFFFFFF #define cOCT6100_TLV_MIN_LENGTH_VERSION_NUMBER 4 #define cOCT6100_TLV_MAX_LENGTH_VERSION_NUMBER 1016 #define cOCT6100_TLV_MIN_LENGTH_CUSTOMER_PROJECT_ID 4 #define cOCT6100_TLV_MAX_LENGTH_CUSTOMER_PROJECT_ID 4 #define cOCT6100_TLV_MIN_LENGTH_CH0_MAIN_BASE_ADDRESS 4 #define cOCT6100_TLV_MAX_LENGTH_CH0_MAIN_BASE_ADDRESS 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_IO_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_IO_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_ZCB_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_ZCB_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_ZCB_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_ZCB_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_XCB_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_XCB_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_XCB_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_XCB_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_YCB_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_YCB_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_CH_MAIN_YCB_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_CH_MAIN_YCB_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_FREE_MEM_BASE_ADDRESS 4 #define cOCT6100_TLV_MAX_LENGTH_FREE_MEM_BASE_ADDRESS 4 #define cOCT6100_TLV_MIN_LENGTH_CH_ROOT_CONF_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CH_ROOT_CONF_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_ZPO_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_ZPO_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_ZPO_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_ZPO_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_YPO_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_YPO_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_YPO_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_YPO_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZWP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZWP 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZIS 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZIS 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZSP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZSP 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YWP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YWP 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YIS 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YIS 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YSP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YSP 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RO_ZRP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RO_ZRP 8 #define cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RO_YRP 8 #define cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RO_YRP 8 #define cOCT6100_TLV_MIN_LENGTH_CNR_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_CNR_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_ANR_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_ANR_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_HZ_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_HZ_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_HX_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_HX_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_LCA_Z_CONF_BOFF_RW_GAIN 8 #define cOCT6100_TLV_MAX_LENGTH_LCA_Z_CONF_BOFF_RW_GAIN 8 #define cOCT6100_TLV_MIN_LENGTH_LCA_Y_CONF_BOFF_RW_GAIN 8 #define cOCT6100_TLV_MAX_LENGTH_LCA_Y_CONF_BOFF_RW_GAIN 8 #define cOCT6100_TLV_MIN_LENGTH_CNA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_CNA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_NOA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_NOA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_VFA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_VFA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_TLA_MAIN_IO_BOFF_RW_TAIL_DISP 8 #define cOCT6100_TLV_MAX_LENGTH_TLA_MAIN_IO_BOFF_RW_TAIL_DISP 8 #define cOCT6100_TLV_MIN_LENGTH_STATSA_MAIN_IO_BOFF_RO_EPC 8 #define cOCT6100_TLV_MAX_LENGTH_STATSA_MAIN_IO_BOFF_RO_EPC 8 #define cOCT6100_TLV_MIN_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_INST 8 #define cOCT6100_TLV_MAX_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_INST 8 #define cOCT6100_TLV_MIN_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_RESULT 8 #define cOCT6100_TLV_MAX_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_RESULT 8 #define cOCT6100_TLV_MIN_LENGTH_CHAN_MAIN_IO_STATS_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_CHAN_MAIN_IO_STATS_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_CHAN_MAIN_IO_STATS_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_CHAN_MAIN_IO_STATS_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_CDA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_CDA_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_TDM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_TDM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_DIS_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_DIS_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_NT_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_NT_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_AEC_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_AEC_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_PCM_LEAK_CONF_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_PCM_LEAK_CONF_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_DEFAULT_ERL_CONF_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_DEFAULT_ERL_CONF_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_TONE_REM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_TONE_REM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_NLP_CONV_CAP_CONF_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_NLP_CONV_CAP_CONF_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT 8 #define cOCT6100_TLV_MAX_LENGTH_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT 8 #define cOCT6100_TLV_MIN_LENGTH_DOMINANT_SPEAKER_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_DOMINANT_SPEAKER_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_TAIL_DISP_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_TAIL_DISP_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_AEC_DEFAULT_ERL_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_AEC_DEFAULT_ERL_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_Z_ALC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_Z_ALC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_Y_ALC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_Y_ALC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_Z_HLC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_Z_HLC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_Y_HLC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_Y_HLC_TARGET_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_ALC_HLC_STATUS_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_ALC_HLC_STATUS_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_Z_PLAYOUT_HARD_SKIP_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_Z_PLAYOUT_HARD_SKIP_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_Y_PLAYOUT_HARD_SKIP_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_Y_PLAYOUT_HARD_SKIP_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_AFT_FIELD_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_AFT_FIELD_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_VOICE_DETECTED_STAT_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_VOICE_DETECTED_STAT_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_GAIN_APPLIED_RIN_STAT_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_GAIN_APPLIED_RIN_STAT_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_GAIN_APPLIED_SOUT_STAT_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_GAIN_APPLIED_SOUT_STAT_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_MAX_ADAPT_ALE_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_MAX_ADAPT_ALE_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_RIN_ANR_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_RIN_ANR_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_RIN_ANR_VALUE_RW 8 #define cOCT6100_TLV_MAX_LENGTH_RIN_ANR_VALUE_RW 8 #define cOCT6100_TLV_MIN_LENGTH_RIN_MUTE_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_RIN_MUTE_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_SIN_MUTE_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_SIN_MUTE_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_ANR_SNR_IMPROVEMENT_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_ANR_SNR_IMPROVEMENT_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_ANR_AGRESSIVITY_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_ANR_AGRESSIVITY_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_CHAN_TAIL_LENGTH_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_CHAN_TAIL_LENGTH_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_CHAN_VQE_TONE_DIS_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_CHAN_VQE_TONE_DIS_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_RIN_TONE_REM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MAX_LENGTH_RIN_TONE_REM_CONF_BOFF_RW_ENABLE 8 #define cOCT6100_TLV_MIN_LENGTH_RIN_TONE_REM_COUNTER_BOFF_RW 8 #define cOCT6100_TLV_MAX_LENGTH_RIN_TONE_REM_COUNTER_BOFF_RW 8 #define cOCT6100_TLV_MIN_LENGTH_AF_TAIL_DISP_VALUE_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_AF_TAIL_DISP_VALUE_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_POUCH_COUNTER_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_POUCH_COUNTER_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_AEC_TAIL_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_AEC_TAIL_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_IS_ISR_CALLED_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_IS_ISR_CALLED_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_MUSIC_PROTECTION_ENABLE_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_MUSIC_PROTECTION_ENABLE_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_ZZ_ENERGY_CHAN_STATS_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_ZZ_ENERGY_CHAN_STATS_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_YY_ENERGY_CHAN_STATS_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_YY_ENERGY_CHAN_STATS_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_DOUBLE_TALK_BEH_MODE_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_DOUBLE_TALK_BEH_MODE_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_IDLE_CODE_DETECTION_BOFF 8 #define cOCT6100_TLV_MAX_LENGTH_IDLE_CODE_DETECTION_BOFF 8 #define cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_INDEX_VALUE 4 #define cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_INDEX_VALUE 4 #define cOCT6100_TLV_MIN_LENGTH_ADPCM_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_ADPCM_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_NUM_TONE_DETECTOR 4 #define cOCT6100_TLV_MAX_LENGTH_NUM_TONE_DETECTOR 4 #define cOCT6100_TLV_MIN_LENGTH_CONFERENCING_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_CONFERENCING_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_MAX_NUMBER_OF_CHANNELS 4 #define cOCT6100_TLV_MAX_LENGTH_MAX_NUMBER_OF_CHANNELS 4 #define cOCT6100_TLV_MIN_LENGTH_TONE_DETECTOR_PROFILE 4 #define cOCT6100_TLV_MAX_LENGTH_TONE_DETECTOR_PROFILE 4 #define cOCT6100_TLV_MIN_LENGTH_TEST_MODE_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_TEST_MODE_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_MAX_TAIL_DISPLACEMENT 4 #define cOCT6100_TLV_MAX_LENGTH_MAX_TAIL_DISPLACEMENT 4 #define cOCT6100_TLV_MIN_LENGTH_MATRIX_EVENT_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_MATRIX_EVENT_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_CNR_RW_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_CNR_RW_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_ANR_RW_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_ANR_RW_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_MAX_TAIL_LENGTH_RW_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_MAX_TAIL_LENGTH_RW_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_PLAYOUT_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_PLAYOUT_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_MUSIC_PROTECTION_RW_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_MUSIC_PROTECTION_RW_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_TONE_REMOVAL_ENABLE 4 #define cOCT6100_TLV_MAX_LENGTH_TONE_REMOVAL_ENABLE 4 #define cOCT6100_TLV_MIN_LENGTH_NUMBER_PLAYOUT_EVENTS 4 #define cOCT6100_TLV_MAX_LENGTH_NUMBER_PLAYOUT_EVENTS 4 #define cOCT6100_TLV_MIN_LENGTH_MATRIX_DWORD_BASE 4 #define cOCT6100_TLV_MAX_LENGTH_MATRIX_DWORD_BASE 4 #define cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_STATS_BYTE_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_STATS_BYTE_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_HOT_CHANNEL_SELECT_DWORD_BASE 4 #define cOCT6100_TLV_MAX_LENGTH_HOT_CHANNEL_SELECT_DWORD_BASE 4 #define cOCT6100_TLV_MIN_LENGTH_TIMESTAMP_DWORD_BASE 4 #define cOCT6100_TLV_MAX_LENGTH_TIMESTAMP_DWORD_BASE 4 #define cOCT6100_TLV_MIN_LENGTH_AF_WRITE_PTR_BYTE_OFFSET 4 #define cOCT6100_TLV_MAX_LENGTH_AF_WRITE_PTR_BYTE_OFFSET 4 #define cOCT6100_TLV_MIN_LENGTH_RECORDED_PCM_EVENT_BYTE_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_RECORDED_PCM_EVENT_BYTE_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_MATRIX_WP_DWORD_BASE 4 #define cOCT6100_TLV_MAX_LENGTH_MATRIX_WP_DWORD_BASE 4 #define cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_LITE_STATS_BYTE_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_LITE_STATS_BYTE_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_IMAGE_TYPE 4 #define cOCT6100_TLV_MAX_LENGTH_IMAGE_TYPE 4 #define cOCT6100_TLV_MIN_LENGTH_MAX_WIRELINE_CHANNELS 4 #define cOCT6100_TLV_MAX_LENGTH_MAX_WIRELINE_CHANNELS 4 #define cOCT6100_TLV_MIN_LENGTH_AF_EVENT_CB_BYTE_SIZE 4 #define cOCT6100_TLV_MAX_LENGTH_AF_EVENT_CB_BYTE_SIZE 4 #define cOCT6100_TLV_MIN_LENGTH_BUFFER_PLAYOUT_SKIP_IN_EVENTS 4 #define cOCT6100_TLV_MAX_LENGTH_BUFFER_PLAYOUT_SKIP_IN_EVENTS 4 #define cOCT6100_TLV_MIN_LENGTH_DOUBLE_TALK_BEH_MODE 4 #define cOCT6100_TLV_MAX_LENGTH_DOUBLE_TALK_BEH_MODE 4 #define cOCT6100_TLV_MIN_LENGTH_SOUT_NOISE_BLEACHING 4 #define cOCT6100_TLV_MAX_LENGTH_SOUT_NOISE_BLEACHING 4 #define cOCT6100_TLV_MIN_LENGTH_IDLE_CODE_DETECTION 4 #define cOCT6100_TLV_MAX_LENGTH_IDLE_CODE_DETECTION 4 #define cOCT6100_TLV_MIN_LENGTH_NLP_STATISTICS 4 #define cOCT6100_TLV_MAX_LENGTH_NLP_STATISTICS 4 /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiProcessTlvRegion( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiInterpretTlvEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTlvFieldType, IN UINT32 f_ulTlvFieldLength, IN UINT32 f_ulTlvValueAddress ); UINT32 Oct6100ApiTlvCheckLengthField( IN OUT UINT32 f_ulTlvFieldLength, IN UINT32 f_ulMinLengthValue, IN UINT32 f_ulMaxLengthValue ); UINT32 Oct6100ApiTlvReadDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, OUT PUINT32 f_pulReadData ); UINT32 Oct6100ApiTlvReadBitOffsetStruct( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, OUT tPOCT6100_TLV_OFFSET f_pBitOffsetStruct ); #endif /* __OCT6100_TLV_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_apimi/0000755000175000017500000000000011631523356026451 5ustar tzafrirtzafrir././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_apimi/oct6100_mask_interrupts.cdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_apimi/oct6100_mask_interru0000644000175000017500000000756111431317470032260 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_mask_interrupts.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the mask interrupts function. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 8 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "oct6100api/oct6100_apimi.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_defines.h" /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100InterruptMask Description: The function is used to mask out the interrupt pin of the chip. This function is used when a deferred procedure call treats the interrupt (new interrupts must not be generated until the signaled interrupt is treated). Which chip is to have its interrupts masked is determined by the mask structure, f_pInterruptMask. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pInterruptMask Pointer to the interrupt masking structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ UINT32 Oct6100InterruptMaskDef( OUT tPOCT6100_INTERRUPT_MASK f_pInterruptMask ) { f_pInterruptMask->ulUserChipIndex = cOCT6100_INVALID_VALUE; f_pInterruptMask->pProcessContext = NULL; return cOCT6100_ERR_OK; } UINT32 Oct6100InterruptMask( IN tPOCT6100_INTERRUPT_MASK f_pInterruptMask ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 result; UINT16 usReadData; /* Determine if the chip's interrupt pin is active.*/ ReadParams.ulReadAddress = 0x210; ReadParams.pusReadData = &usReadData; ReadParams.pProcessContext = f_pInterruptMask->pProcessContext; ReadParams.ulUserChipId = f_pInterruptMask->ulUserChipIndex; result = Oct6100UserDriverReadOs( &ReadParams ); if ( result != cOCT6100_ERR_OK ) return cOCT6100_ERR_INTRPTS_RW_ERROR; if ( (usReadData & 0xFFFF) != 0 ) { /* Chip's interrupt pin is active, so mask interrupt pin. */ ReadParams.ulReadAddress = 0x214; result = Oct6100UserDriverReadOs( &ReadParams ); if ( result != cOCT6100_ERR_OK ) return cOCT6100_ERR_INTRPTS_RW_ERROR; /* Determine if the chip's interrupt pin is active. */ WriteParams.pProcessContext = f_pInterruptMask->pProcessContext; WriteParams.ulUserChipId = f_pInterruptMask->ulUserChipIndex; WriteParams.ulWriteAddress = 0x214; WriteParams.usWriteData = (UINT16)( (usReadData & 0xC000) | 0x3FFF ); result = Oct6100UserDriverWriteOs( &WriteParams ); if ( result != cOCT6100_ERR_OK ) return cOCT6100_ERR_INTRPTS_RW_ERROR; WriteParams.ulWriteAddress = 0x212; WriteParams.usWriteData = 0x8000; result = Oct6100UserDriverWriteOs( &WriteParams ); if ( result != cOCT6100_ERR_OK ) return cOCT6100_ERR_INTRPTS_RW_ERROR; return cOCT6100_ERR_OK; } return cOCT6100_ERR_INTRPTS_NOT_ACTIVE; } dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_tsst_priv.h0000644000175000017500000000642011431317470027556 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsst_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_tsst.c. All elements defined in this file are for private usage of the API. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 14 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_TSST_PRIV_H__ #define __OCT6100_TSST_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* TSST allocation and serialization pointer macros. */ #define mOCT6100_GET_TSST_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PUINT32 )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsstAllocOfst); #define mOCT6100_GET_TSST_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_TSST_ENTRY )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsstListOfst ); #define mOCT6100_GET_TSST_LIST_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_TSST_ENTRY )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsstListOfst)) + ulIndex; #define mOCT6100_GET_TSST_LIST_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulTsstListAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetTsstSwSizes( OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiTsstSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100ApiValidateTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulNumTssts, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulDirection ); UINT32 Oct6100ApiReserveTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulNumTsst, IN UINT32 f_ulDirection, OUT PUINT16 f_pusTsstMemIndex, OUT PUINT16 f_pusTsstListIndex ); UINT32 Oct6100ApiReleaseTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulNumTsst, IN UINT32 f_ulDirection, IN UINT16 f_usTsstListIndex ); #endif /* __OCT6100_TSST_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/0000755000175000017500000000000011631523356026123 5ustar tzafrirtzafrir././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_miscellaneous.cdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_miscellaneous.0000644000175000017500000004277611431317470032157 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_miscellaneous.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains miscellaneous functions used in various files. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 35 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_largmath.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_miscellaneous_priv.h" /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWaitForTime Description: Waits for the specified amount of time. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_aulWaitTime[ 2 ] The amout of time to be waited. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWaitForTime UINT32 Oct6100ApiWaitForTime( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_aulWaitTime[ 2 ] ) { tOCT6100_GET_TIME StartTime; tOCT6100_GET_TIME CurrentTime; UINT32 aulTimeDelta[ 2 ]; UINT32 ulResult; UINT16 usTempVar; BOOL fConditionFlag = TRUE; /* Copy the process context. */ StartTime.pProcessContext = f_pApiInstance->pProcessContext; CurrentTime.pProcessContext = f_pApiInstance->pProcessContext; ulResult = Oct6100UserGetTime( &StartTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; while ( fConditionFlag ) { ulResult = Oct6100UserGetTime( &CurrentTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = octapi_lm_subtract( CurrentTime.aulWallTimeUs, 1, StartTime.aulWallTimeUs, 1, aulTimeDelta, 1, &usTempVar ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_37; if ( aulTimeDelta[ 1 ] >= f_aulWaitTime[ 1 ] && aulTimeDelta[ 0 ] >= f_aulWaitTime[ 0 ] ) fConditionFlag = FALSE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWaitForPcRegisterBit Description: Polls the specified PC register bit. The function exits once the bit is cleared by hardware, or when the specified timeout period has been expired. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulPcRegAdd Address of the register containing the PC bit. f_ulPcBitNum Number of the PC bit within the register. f_ulValue Expected value of the bit. f_ulTimeoutUs The timeout period, in usec. f_pfBitEqual Pointer to the result of the bit comparison. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWaitForPcRegisterBit UINT32 Oct6100ApiWaitForPcRegisterBit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulPcRegAdd, IN UINT32 f_ulPcBitNum, IN UINT32 f_ulValue, IN UINT32 f_ulTimeoutUs, OUT PBOOL f_pfBitEqual ) { tOCT6100_READ_PARAMS ReadParams; tOCT6100_GET_TIME StartTime; tOCT6100_GET_TIME TimeoutTime; tOCT6100_GET_TIME CurrentTime; UINT32 ulResult; UINT16 usReadData; BOOL fConditionFlag = TRUE; /* Copy the process context. */ StartTime.pProcessContext = f_pApiInstance->pProcessContext; CurrentTime.pProcessContext = f_pApiInstance->pProcessContext; /* Get the current system time. */ ulResult = Oct6100UserGetTime( &StartTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Mark the bit as not being equal, for now. */ *f_pfBitEqual = FALSE; /* Determine the time at which the timeout has expired. */ ulResult = octapi_lm_add( StartTime.aulWallTimeUs, 1, &f_ulTimeoutUs, 0, TimeoutTime.aulWallTimeUs, 1 ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Prepare read structure. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.ulReadAddress = f_ulPcRegAdd; ReadParams.pusReadData = &usReadData; /* Read the PC bit while the timeout period hasn't expired. */ while ( fConditionFlag ) { /* Read the current time again to check for timeout. */ ulResult = Oct6100UserGetTime( &CurrentTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100UserDriverReadApi( &ReadParams ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( ( UINT16 )((usReadData >> f_ulPcBitNum) & 0x1) == ( UINT16 )f_ulValue ) { /* Mark the bit as being equal. */ *f_pfBitEqual = TRUE; fConditionFlag = FALSE; } if ( CurrentTime.aulWallTimeUs[ 1 ] > TimeoutTime.aulWallTimeUs[ 1 ] || (CurrentTime.aulWallTimeUs[ 1 ] == TimeoutTime.aulWallTimeUs[ 1 ] && CurrentTime.aulWallTimeUs[ 0 ] >= TimeoutTime.aulWallTimeUs[ 0 ]) ) fConditionFlag = FALSE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReadDword Description: Read a DWORD at specified address in external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulAddress DWORD address where to read. f_pulReadData Resulting data. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReadDword UINT32 Oct6100ApiReadDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, OUT PUINT32 f_pulReadData ) { tOCT6100_READ_PARAMS ReadParams; UINT16 usReadData; UINT32 ulResult; UINT32 ulTempData; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /*==================================================================================*/ /* Read the first 16 bits. */ ReadParams.ulReadAddress = f_ulAddress; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTempData = usReadData << 16; /* Read the last 16 bits. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTempData |= usReadData; /*==================================================================================*/ /* Return the read value.*/ *f_pulReadData = ulTempData; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteDword Description: Write a DWORD at specified address in external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulAddress DWORD address where to write. f_ulWriteData DWORD data to write. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteDword UINT32 Oct6100ApiWriteDword( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, IN UINT32 f_ulWriteData ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Write the first 16 bits. */ WriteParams.ulWriteAddress = f_ulAddress; WriteParams.usWriteData = (UINT16)((f_ulWriteData >> 16) & 0xFFFF); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the last word. */ WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)(f_ulWriteData & 0xFFFF); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCreateFeatureMask Description: ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_ulFieldSize Size of the field, in bits. f_ulFieldBitOffset Bit offset, from the least significant bit. f_pulFieldMask Resulting mask. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCreateFeatureMask VOID Oct6100ApiCreateFeatureMask( IN UINT32 f_ulFieldSize, IN UINT32 f_ulFieldBitOffset, OUT PUINT32 f_pulFieldMask ) { UINT32 ulMask; UINT32 i; ulMask = 0; /* Create the mask based on the field size. */ for ( i = 0; i < f_ulFieldSize; i++ ) { ulMask <<= 1; ulMask |= 1; } /* Once the mask is of the desired size, offset it to fit the field */ /* within the DWORD read. */ ulMask <<= f_ulFieldBitOffset; /* Return the mask. */ *f_pulFieldMask = ulMask; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiStrStr Description: OCT6100 API version of strstr() ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pszSource Source string to analyze. f_pszString String to look for. f_pszLastCharPtr Last character in the source string. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiStrStr unsigned char const *Oct6100ApiStrStr( IN unsigned char const *f_pszSource, IN unsigned char const *f_pszString, IN unsigned char const *f_pszLastCharPtr ) { UINT32 ulCurrentPos; UINT32 ulStringLength; UINT32 ulNumMatchingCharFound = 0; unsigned char const *pchFirstChar = NULL; UINT32 ulSourceLength; if ( f_pszLastCharPtr < f_pszSource ) return NULL; ulSourceLength = (UINT32)( f_pszLastCharPtr - f_pszSource ); ulStringLength = Oct6100ApiStrLen( f_pszString ); for ( ulCurrentPos = 0; ulCurrentPos < ulSourceLength; ulCurrentPos++ ) { /* Check if the character matches. */ if ( f_pszSource[ ulCurrentPos ] == f_pszString[ ulNumMatchingCharFound ] ) { if ( ulNumMatchingCharFound == 0 ) pchFirstChar = ( f_pszSource + ulCurrentPos ); ulNumMatchingCharFound++; /* Check if the whole string matched. */ if ( ulNumMatchingCharFound == ulStringLength ) break; } else if ( ulNumMatchingCharFound != 0 ) { ulNumMatchingCharFound = 0; /* Reset the search, but take a look at the current character. It might */ /* be the beginning of the string we are looking for. */ if ( f_pszSource[ ulCurrentPos ] == f_pszString[ ulNumMatchingCharFound ] ) { pchFirstChar = ( f_pszSource + ulCurrentPos ); ulNumMatchingCharFound++; /* Check if the whole string matched. */ /* This check must be done in case we have the 1 character strstr */ if ( ulNumMatchingCharFound == ulStringLength ) break; } } } if ( ulCurrentPos == ulSourceLength ) return NULL; else return pchFirstChar; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiStrLen Description: OCT6100 API version of strlen() ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pszString Source string to count length of. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiStrLen UINT32 Oct6100ApiStrLen( IN unsigned char const *f_pszString ) { UINT32 ulCount = 0; while( f_pszString[ ulCount ] != '\0' ) ulCount++; return ulCount; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAsciiToHex Description: Convert an ASCII character to an hexadecimal value. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_chCharacter ASCII character to convert. f_pulValue Resulting hexadecimal value. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAsciiToHex UINT32 Oct6100ApiAsciiToHex( IN UINT8 f_chCharacter, OUT PUINT32 f_pulValue ) { switch ( f_chCharacter ) { case '0': (*f_pulValue) = 0x0; break; case '1': (*f_pulValue) = 0x1; break; case '2': (*f_pulValue) = 0x2; break; case '3': (*f_pulValue) = 0x3; break; case '4': (*f_pulValue) = 0x4; break; case '5': (*f_pulValue) = 0x5; break; case '6': (*f_pulValue) = 0x6; break; case '7': (*f_pulValue) = 0x7; break; case '8': (*f_pulValue) = 0x8; break; case '9': (*f_pulValue) = 0x9; break; case 'A': case 'a': (*f_pulValue) = 0xA; break; case 'B': case 'b': (*f_pulValue) = 0xB; break; case 'C': case 'c': (*f_pulValue) = 0xC; break; case 'D': case 'd': (*f_pulValue) = 0xD; break; case 'E': case 'e': (*f_pulValue) = 0xE; break; case 'F': case 'f': (*f_pulValue) = 0xF; break; default: (*f_pulValue) = 0x0; return cOCT6100_ERR_MISC_ASCII_CONVERSION_FAILED; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiHexToAscii Description: Convert an hexadecimal value to an ASCII character. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_ulNumber Hexadecimal value to convert. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiHexToAscii UINT8 Oct6100ApiHexToAscii( IN UINT32 f_ulNumber ) { if ( f_ulNumber >= 0xA ) return (UINT8)( 55 + f_ulNumber ); /* Hex values from 0xA to 0xF */ else return (UINT8)( 48 + f_ulNumber ); /* Hex values from 0x0 to 0x9 */ } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRand Description: Random number generator. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_ulRange Range of the random number to be generated. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRand UINT32 Oct6100ApiRand( IN UINT32 f_ulRange ) { static UINT32 ulRandomSeed = 0x12345678; UINT32 ulBit0; UINT32 i, j; UINT16 ulWithinRange = FALSE; UINT32 ulResult = cOCT6100_ERR_OK; UINT16 ulLoop; UINT32 ulRangeMask; UINT32 ulAddedValue; ulRangeMask = 1; ulLoop = TRUE; i = 1; while ( ulLoop ) { ulAddedValue = 2; for ( j = 1; j < i; j++ ) ulAddedValue *= 2; ulRangeMask = ulRangeMask + ulAddedValue; if ( ulRangeMask >= f_ulRange ) ulLoop = FALSE; i++; } while ( !ulWithinRange ) { ulBit0 = ((ulRandomSeed >> 19) & 0x1) ^ ((ulRandomSeed >> 16) & 0x1); ulRandomSeed = ((ulRandomSeed << 1) & 0xFFFFF) | ulBit0; ulResult = ulRandomSeed & ulRangeMask; if ( ulResult <= f_ulRange ) ulWithinRange = TRUE; } return ulResult; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_playout_buf.c0000644000175000017500000035512111525010337031773 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_playout_buf.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to manage buffer playout. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 109 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_playout_buf_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_events_pub.h" #include "oct6100api/oct6100_playout_buf_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_events_priv.h" #include "oct6100_playout_buf_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutLoad Description: This function loads a playout buffer into external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoad Pointer to buffer playout load structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutLoadDef UINT32 Oct6100BufferPlayoutLoadDef( tPOCT6100_BUFFER_LOAD f_pBufferLoad ) { f_pBufferLoad->pbyBufferPattern = NULL; f_pBufferLoad->ulBufferSize = 128; f_pBufferLoad->ulBufferPcmLaw = cOCT6100_PCM_U_LAW; f_pBufferLoad->pulBufferIndex = NULL; f_pBufferLoad->pulPlayoutFreeMemSize = NULL; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutLoad UINT32 Oct6100BufferPlayoutLoad( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_LOAD f_pBufferLoad ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferLoadSer( f_pApiInstance, f_pBufferLoad, TRUE, cOCT6100_INVALID_INDEX ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutLoadBlockInit Description: This function allows the user to initialize loading a buffer into external memory using blocks. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoadBlockInit Pointer to buffer playout load block init structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutLoadBlockInitDef UINT32 Oct6100BufferPlayoutLoadBlockInitDef( tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ) { f_pBufferLoadBlockInit->ulBufferSize = 128; f_pBufferLoadBlockInit->ulBufferPcmLaw = cOCT6100_PCM_U_LAW; f_pBufferLoadBlockInit->pulBufferIndex = NULL; f_pBufferLoadBlockInit->pulPlayoutFreeMemSize = NULL; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutLoadBlockInit UINT32 Oct6100BufferPlayoutLoadBlockInit( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferLoadBlockInitSer( f_pApiInstance, f_pBufferLoadBlockInit ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutLoadBlock Description: This function allows the user to load a buffer block into external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoadBlock Pointer to buffer playout load block structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutLoadBlockDef UINT32 Oct6100BufferPlayoutLoadBlockDef( tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ) { f_pBufferLoadBlock->ulBufferIndex = cOCT6100_INVALID_VALUE; f_pBufferLoadBlock->ulBlockLength = cOCT6100_INVALID_VALUE; f_pBufferLoadBlock->ulBlockOffset = cOCT6100_INVALID_VALUE; f_pBufferLoadBlock->pbyBufferPattern = NULL; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutLoadBlock UINT32 Oct6100BufferPlayoutLoadBlock( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferLoadBlockSer( f_pApiInstance, f_pBufferLoadBlock ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutUnload Description: This function unloads a playout buffer from external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferUnload Pointer to buffer playout unload structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutUnloadDef UINT32 Oct6100BufferPlayoutUnloadDef( tPOCT6100_BUFFER_UNLOAD f_pBufferUnload ) { f_pBufferUnload->ulBufferIndex = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutUnload UINT32 Oct6100BufferPlayoutUnload( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_UNLOAD f_pBufferUnload ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferUnloadSer( f_pApiInstance, f_pBufferUnload, TRUE ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutAdd Description: This function adds a buffer to a port's playout list on the selected channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutAdd Pointer to buffer playout add structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutAddDef UINT32 Oct6100BufferPlayoutAddDef( tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ) { f_pBufferPlayoutAdd->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pBufferPlayoutAdd->ulBufferIndex = cOCT6100_INVALID_VALUE; f_pBufferPlayoutAdd->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; f_pBufferPlayoutAdd->ulMixingMode = cOCT6100_MIXING_MINUS_6_DB; f_pBufferPlayoutAdd->lGainDb = 0; f_pBufferPlayoutAdd->fRepeat = FALSE; f_pBufferPlayoutAdd->ulRepeatCount = cOCT6100_REPEAT_INFINITELY; f_pBufferPlayoutAdd->ulDuration = cOCT6100_INVALID_VALUE; f_pBufferPlayoutAdd->ulBufferLength = cOCT6100_AUTO_SELECT; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutAdd UINT32 Oct6100BufferPlayoutAdd( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferPlayoutAddSer( f_pApiInstance, f_pBufferPlayoutAdd ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutStart Description: This function enables playout of the specified buffer on the requested channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStart Pointer to buffer playout start structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutStartDef UINT32 Oct6100BufferPlayoutStartDef( tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart ) { f_pBufferPlayoutStart->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pBufferPlayoutStart->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; f_pBufferPlayoutStart->fNotifyOnPlayoutStop = FALSE; f_pBufferPlayoutStart->ulUserEventId = cOCT6100_INVALID_VALUE; f_pBufferPlayoutStart->fAllowStartWhileActive = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutStart UINT32 Oct6100BufferPlayoutStart( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferPlayoutStartSer( f_pApiInstance, f_pBufferPlayoutStart, cOCT6100_BUFFER_PLAYOUT_EVENT_STOP ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutStop Description: This function disables playout of a buffer on the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStop Pointer to buffer playout stop structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutStopDef UINT32 Oct6100BufferPlayoutStopDef( tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ) { f_pBufferPlayoutStop->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pBufferPlayoutStop->ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; f_pBufferPlayoutStop->fStopCleanly = TRUE; f_pBufferPlayoutStop->pfAlreadyStopped = NULL; f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = NULL; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutStop UINT32 Oct6100BufferPlayoutStop( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferPlayoutStopSer( f_pApiInstance, f_pBufferPlayoutStop ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetPlayoutBufferSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of playout buffers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetPlayoutBufferSwSizes UINT32 Oct6100ApiGetPlayoutBufferSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Calculate memory needed for playout buffer list. */ f_pInstSizes->ulPlayoutBufList = f_pOpenChip->ulMaxPlayoutBuffers * sizeof( tOCT6100_API_BUFFER ); f_pInstSizes->ulPlayoutBufMemoryNodeList = 0; /* Calculate memory needed for playout buffer allocation software. */ if ( f_pOpenChip->ulMaxPlayoutBuffers > 0 ) { ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxPlayoutBuffers, &f_pInstSizes->ulPlayoutBufAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_3C; f_pInstSizes->ulPlayoutBufMemoryNodeList = 2 * f_pOpenChip->ulMaxPlayoutBuffers * sizeof( tOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE ); } else { f_pInstSizes->ulPlayoutBufAlloc = 0; } /* Calculate memory needed for list and allocation software serialization. */ mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulPlayoutBufList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulPlayoutBufAlloc, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulPlayoutBufMemoryNodeList, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiPlayoutBufferSwInit Description: Initializes all elements of the instance structure associated to playout buffers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiPlayoutBufferSwInit UINT32 Oct6100ApiPlayoutBufferSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER pBufferList; PVOID pBufferPlayoutAlloc; UINT32 ulMaxBufferPlayout; UINT32 ulResult, i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get the maximum number of buffer playout. */ ulMaxBufferPlayout = pSharedInfo->ChipConfig.usMaxPlayoutBuffers; /* Set all entries in the buffer playout list to unused. */ mOCT6100_GET_BUFFER_LIST_PNT( pSharedInfo, pBufferList ) for ( i = 0; i < ulMaxBufferPlayout; i++ ) { pBufferList[ i ].fReserved = FALSE; pBufferList[ i ].ulBufferSize = 0; pBufferList[ i ].ulBufferBase = cOCT6100_INVALID_VALUE; pBufferList[ i ].usDependencyCnt = 0; pBufferList[ i ].byBufferPcmLaw = cOCT6100_PCM_U_LAW; } /* Initialize the buffer playout allocation software to "all free". */ if ( ulMaxBufferPlayout > 0 ) { mOCT6100_GET_BUFFER_ALLOC_PNT( pSharedInfo, pBufferPlayoutAlloc ) ulResult = OctapiLlmAllocInit( &pBufferPlayoutAlloc, ulMaxBufferPlayout ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_3D; } /* Initialize the amount of free memory used by playout. */ f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed = 0; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferLoadSer Description: Loads a buffer in external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoad Pointer to buffer configuration structure. The handle identifying the buffer in all future function calls is returned in this structure. f_fReserveListStruct Flag indicating if a list structure should be reserved or if the structure has been reserved before. If this is set, the f_ulBufIndex variable must also be set. f_ulBufIndex If the f_fReserveListStruct flag is set, this index will identify the buffer playout list structure that must be used to load the specified buffer. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferLoadSer UINT32 Oct6100BufferLoadSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fReserveListStruct, IN UINT32 f_ulBufIndex ) { UINT32 ulBufferIndex; UINT32 ulBufferBase; UINT32 ulResult; /* Check the user's configuration of the buffer for errors. */ ulResult = Oct6100ApiCheckBufferParams( f_pApiInstance, f_pBufferLoad, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the buffer. */ ulResult = Oct6100ApiReserveBufferResources( f_pApiInstance, f_pBufferLoad, f_fReserveListStruct, f_ulBufIndex, &ulBufferIndex, &ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the buffer in external memory. */ ulResult = Oct6100ApiWriteBufferInMemory( f_pApiInstance, ulBufferBase, f_pBufferLoad->ulBufferSize, f_pBufferLoad->pbyBufferPattern ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new buffer's entry in the buffer list. */ ulResult = Oct6100ApiUpdateBufferEntry( f_pApiInstance, f_pBufferLoad, ulBufferIndex, ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferLoadBlockInitSer Description: Reserve resources for loading a buffer into external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoadBlockInit Pointer to buffer configuration structure. The handle identifying the buffer in all future function calls is returned in this structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferLoadBlockInitSer UINT32 Oct6100BufferLoadBlockInitSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK_INIT f_pBufferLoadBlockInit ) { UINT32 ulBufferIndex; UINT32 ulBufferBase; UINT32 ulResult; tOCT6100_BUFFER_LOAD BufferLoad; Oct6100BufferPlayoutLoadDef( &BufferLoad ); /* Not to replicate the code, we use the BufferLoad functions directly. */ BufferLoad.pulBufferIndex = f_pBufferLoadBlockInit->pulBufferIndex; BufferLoad.pulPlayoutFreeMemSize = f_pBufferLoadBlockInit->pulPlayoutFreeMemSize; BufferLoad.ulBufferPcmLaw = f_pBufferLoadBlockInit->ulBufferPcmLaw; BufferLoad.ulBufferSize = f_pBufferLoadBlockInit->ulBufferSize; BufferLoad.pbyBufferPattern = NULL; /* Must not check this for now */ /* Check the user's configuration of the buffer for errors, but do */ /* not check if the buffer pointer is NULL. It is NULL for sure! */ ulResult = Oct6100ApiCheckBufferParams( f_pApiInstance, &BufferLoad, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the buffer. */ ulResult = Oct6100ApiReserveBufferResources( f_pApiInstance, &BufferLoad, TRUE, cOCT6100_INVALID_INDEX, &ulBufferIndex, &ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new buffer's entry in the buffer list. */ ulResult = Oct6100ApiUpdateBufferEntry( f_pApiInstance, &BufferLoad, ulBufferIndex, ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferLoadBlockSer Description: Loads a buffer in external memory using blocks. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoadBlock Pointer to buffer block to be loaded into external memory descriptor. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferLoadBlockSer UINT32 Oct6100BufferLoadBlockSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock ) { UINT32 ulBufferBase; UINT32 ulResult; /* Check the user's configuration for errors. */ ulResult = Oct6100ApiCheckBufferLoadBlockParams( f_pApiInstance, f_pBufferLoadBlock, &ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the buffer in external memory at the appropriate offset - must do some pointer arithmetic. */ ulResult = Oct6100ApiWriteBufferInMemory( f_pApiInstance, ulBufferBase + f_pBufferLoadBlock->ulBlockOffset, f_pBufferLoadBlock->ulBlockLength, f_pBufferLoadBlock->pbyBufferPattern + f_pBufferLoadBlock->ulBlockOffset ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBufferParams Description: Checks the user's buffer playout load configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoad Pointer to buffer configuration structure. f_fCheckBufferPtr Check if the buffer pointer is NULL or not. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBufferParams UINT32 Oct6100ApiCheckBufferParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fCheckBufferPtr ) { /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED; if ( f_pApiInstance->pSharedInfo->ImageInfo.fBufferPlayout == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_BUFFER_PLAYOUT; if ( f_pBufferLoad->pulBufferIndex == NULL ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX; if( f_fCheckBufferPtr ) { if ( f_pBufferLoad->pbyBufferPattern == NULL ) return cOCT6100_ERR_BUFFER_PLAYOUT_PATTERN; } if ( f_pBufferLoad->ulBufferSize < cOCT6100_MINIMUM_BUFFER_SIZE ) return cOCT6100_ERR_BUFFER_PLAYOUT_TOO_SMALL; if ( ( f_pBufferLoad->ulBufferSize % cOCT6100_BUFFER_SIZE_GRANULARITY ) != 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE; if ( f_pBufferLoad->ulBufferPcmLaw != cOCT6100_PCM_U_LAW && f_pBufferLoad->ulBufferPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_BUFFER_PLAYOUT_PCM_LAW; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBufferLoadBlockParams Description: Checks the user's buffer playout load block configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoadBlock Pointer to buffer block descriptor. f_pulBufferBase Pointer to the base address of the buffer in external memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBufferLoadBlockParams UINT32 Oct6100ApiCheckBufferLoadBlockParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_LOAD_BLOCK f_pBufferLoadBlock, OUT PUINT32 f_pulBufferBase ) { /* Check for errors. */ tPOCT6100_API_BUFFER pBufEntry; if ( f_pBufferLoadBlock->ulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX; mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_pBufferLoadBlock->ulBufferIndex ) if ( pBufEntry->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN; if ( ( f_pBufferLoadBlock->ulBlockLength % 2 ) != 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_LENGTH_INVALID; if ( ( f_pBufferLoadBlock->ulBlockOffset % 2 ) != 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_BLOCK_OFFSET_INVALID; if ( f_pBufferLoadBlock->pbyBufferPattern == NULL ) return cOCT6100_ERR_BUFFER_PLAYOUT_PATTERN; /* Check boundaries */ if ( ( f_pBufferLoadBlock->ulBlockLength + f_pBufferLoadBlock->ulBlockOffset ) > pBufEntry->ulBufferSize ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE; *f_pulBufferBase = pBufEntry->ulBufferBase; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBufferResources Description: Reserves all resources needed for the new buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoad Pointer to buffer configuration structure. f_fReserveListStruct Flag indicating if a list structure should be reserved or if the structure has been reserved before. f_ulBufIndex If the f_fReserveListStruct flag is set, this index will identifying the buffer playout list structure that must be used to load the specified buffer. f_pulBufferIndex Allocated entry in buffer playout list. f_pulBufferBase Allocated external memory block for the buffer. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBufferResources UINT32 Oct6100ApiReserveBufferResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN BOOL f_fReserveListStruct, IN UINT32 f_ulBufIndex, OUT PUINT32 f_pulBufferIndex, OUT PUINT32 f_pulBufferBase ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Reserve an entry in the buffer list. */ if ( f_fReserveListStruct == TRUE ) { ulResult = Oct6100ApiReserveBufPlayoutListEntry( f_pApiInstance, f_pulBufferIndex ); } else { *f_pulBufferIndex = f_ulBufIndex; } if ( ulResult == cOCT6100_ERR_OK ) { /* Find a free block to store the buffer. */ ulResult = Oct6100ApiReserveBufferPlayoutMemory( f_pApiInstance, f_pBufferLoad->ulBufferSize, f_pulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) { /* Release the list entry. */ if ( f_fReserveListStruct == TRUE ) { ulTempVar = Oct6100ApiReleaseBufPlayoutListEntry( f_pApiInstance, *f_pulBufferIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } } } return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteBufferInMemory Description: Writes the buffer in external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulBufferBase Allocated external memory address for the buffer. f_ulBufferLength Length in bytes of the buffer to be copied in memory. f_pbyBuffer Address where the buffer should be copied from. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteBufferInMemory UINT32 Oct6100ApiWriteBufferInMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufferBase, IN UINT32 f_ulBufferLength, IN PUINT8 f_pbyBuffer ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_BURST_PARAMS BurstParams; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulNumWrites; PUINT16 pusSuperArray; PUINT8 pbyPlayoutBuffer; UINT32 ulByteCount = 0; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Write the buffer in external memory. */ ulNumWrites = f_ulBufferLength / 2; BurstParams.ulWriteAddress = f_ulBufferBase; BurstParams.pusWriteData = pSharedInfo->MiscVars.ausSuperArray; pusSuperArray = pSharedInfo->MiscVars.ausSuperArray; pbyPlayoutBuffer = f_pbyBuffer; /* Check if we can maximize the bandwidth through the CPU port. */ if ( f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels == 0 ) { WriteParams.ulWriteAddress = 0x234; WriteParams.usWriteData = 0x08ff; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } while ( ulNumWrites != 0 ) { if ( ulNumWrites >= pSharedInfo->ChipConfig.usMaxRwAccesses ) BurstParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else BurstParams.ulWriteLength = ulNumWrites; for ( i = 0; i < BurstParams.ulWriteLength; i++ ) { pusSuperArray[ i ] = ( UINT16 )(( pbyPlayoutBuffer [ ulByteCount++ ]) << 8); pusSuperArray[ i ] |= ( UINT16 )pbyPlayoutBuffer [ ulByteCount++ ]; } mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BurstParams.ulWriteAddress += 2 * BurstParams.ulWriteLength; ulNumWrites -= BurstParams.ulWriteLength; } /* Make sure we revert back the changes made to the CPU bandwidth register. */ if ( f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels == 0 ) { WriteParams.ulWriteAddress = 0x234; WriteParams.usWriteData = 0x0804; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBufferEntry Description: Updates the new buffer's entry in the buffer playout list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferLoad Pointer to buffer configuration structure. f_ulBufferIndex Allocated entry in buffer playout list. f_ulBufferBase Allocated external memory block for the buffer. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBufferEntry UINT32 Oct6100ApiUpdateBufferEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_LOAD f_pBufferLoad, IN UINT32 f_ulBufferIndex, IN UINT32 f_ulBufferBase ) { tPOCT6100_API_BUFFER pBufEntry; UINT32 ulBufferSize = f_pBufferLoad->ulBufferSize; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_ulBufferIndex ) /* Copy the buffer's configuration and allocated resources. */ pBufEntry->ulBufferSize = f_pBufferLoad->ulBufferSize; pBufEntry->byBufferPcmLaw = (UINT8)( f_pBufferLoad->ulBufferPcmLaw & 0xFF ); pBufEntry->ulBufferBase = f_ulBufferBase; /* Update the entries flags. */ pBufEntry->usDependencyCnt = 0; /* Mark the buffer as opened. */ pBufEntry->fReserved = TRUE; /* Increment the number of buffer loaded into the chip.*/ f_pApiInstance->pSharedInfo->ChipStats.usNumberPlayoutBuffers++; /* Refresh the amount of memory used by buffer playout. */ /* Reserved size is divisible by 64. */ if ( ulBufferSize % 64 ) ulBufferSize = ulBufferSize + ( 64 - ( ulBufferSize % 64 ) ); f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed += ulBufferSize; /* Return the buffer index to the user. */ *f_pBufferLoad->pulBufferIndex = f_ulBufferIndex; /* Return the amount of free memory left in the chip. */ /* Note that this value does not give the "fragmentation" state of the available memory. */ /* This value only gives the amount of free memory */ if( f_pBufferLoad->pulPlayoutFreeMemSize ) *f_pBufferLoad->pulPlayoutFreeMemSize = ( f_pApiInstance->pSharedInfo->MiscVars.ulTotalMemSize - ( f_pApiInstance->pSharedInfo->MemoryMap.ulFreeMemBaseAddress - cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) ) - ( f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferUnloadSer Description: Unloads a buffer from external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferUnload Pointer to buffer unload structure. f_fReleaseListStruct Whether to release the buffer playout list structure or not. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferUnloadSer UINT32 Oct6100BufferUnloadSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_UNLOAD f_pBufferUnload, IN BOOL f_fReleaseListStruct ) { UINT32 ulBufferIndex; UINT32 ulBufferBase; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertBufferParams( f_pApiInstance, f_pBufferUnload, &ulBufferIndex, &ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the unloaded buffer. */ ulResult = Oct6100ApiReleaseBufferResources( f_pApiInstance, ulBufferIndex, ulBufferBase, f_fReleaseListStruct ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertBufferParams Description: Checks the buffer playout unload configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferUnload Pointer to buffer unload structure. f_pulBufferIndex Pointer to the index of the buffer in the API's buffers list. f_pulBufferBase Pointer to the base address of the buffer in external memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertBufferParams UINT32 Oct6100ApiAssertBufferParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_UNLOAD f_pBufferUnload, OUT PUINT32 f_pulBufferIndex, OUT PUINT32 f_pulBufferBase ) { tPOCT6100_API_BUFFER pBufEntry; *f_pulBufferIndex = f_pBufferUnload->ulBufferIndex; if ( *f_pulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX; mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, *f_pulBufferIndex ) /* Check for errors. */ if ( pBufEntry->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN; if ( pBufEntry->usDependencyCnt != 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_ACTIVE_DEPENDENCIES; /* Return all info needed to invalidate buffer. */ *f_pulBufferBase = pBufEntry->ulBufferBase; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBufferResources Description: Release resources needed by the buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulBufferIndex Allocated entry in buffer playout list. f_ulBufferBase Allocated external memory block for the buffer. f_fReleaseListStruct Free the list structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBufferResources UINT32 Oct6100ApiReleaseBufferResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufferIndex, IN UINT32 f_ulBufferBase, IN BOOL f_fReleaseListStruct ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER pBufEntry; UINT32 ulResult; UINT32 ulBufferSize; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Free the external memory reserved for the buffer. */ ulResult = Oct6100ApiReleaseBufferPlayoutMemory( f_pApiInstance, f_ulBufferBase ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_3E; /* Release the entry from the buffer list. */ if ( f_fReleaseListStruct == TRUE ) ulResult = Oct6100ApiReleaseBufPlayoutListEntry( f_pApiInstance, f_ulBufferIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufEntry, f_ulBufferIndex ); /* Save buffer size before releasing that entry, will be needed to calculate the amount of */ /* free memory left for the user. */ ulBufferSize = pBufEntry->ulBufferSize; /* Flag the buffer entry as free. */ pBufEntry->fReserved = FALSE; /* Decrement the number of buffer loaded into the chip. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberPlayoutBuffers--; /* Refresh the amount of memory used by buffer playout. */ /* Reserved size is divisible by 64. */ if ( ulBufferSize % 64 ) ulBufferSize = ulBufferSize + ( 64 - ( ulBufferSize % 64 ) ); f_pApiInstance->pSharedInfo->ChipStats.ulPlayoutMemUsed -= ulBufferSize; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutAddSer Description: This function adds a buffer to a channel buffer list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutAdd Pointer to buffer playout add structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutAddSer UINT32 Oct6100BufferPlayoutAddSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd ) { UINT32 ulBufferIndex; UINT32 ulChannelIndex; UINT32 ulResult; /* Check the user's configuration of the buffer for errors. */ ulResult = Oct6100ApiCheckPlayoutAddParams( f_pApiInstance, f_pBufferPlayoutAdd, &ulChannelIndex, &ulBufferIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write to all resources needed to activate buffer playout. */ ulResult = Oct6100ApiWriteBufferAddStructs( f_pApiInstance, f_pBufferPlayoutAdd, ulChannelIndex, ulBufferIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckPlayoutAddParams Description: Check the validity of the channel and buffer requested. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutAdd Pointer to buffer playout add structure. f_pulChannelIndex Pointer to the channel index of the selected channel. f_pulBufferIndex Pointer to the buffer index within the API's buffer list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckPlayoutAddParams UINT32 Oct6100ApiCheckPlayoutAddParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulBufferIndex ) { tPOCT6100_API_BUFFER pBufferEntry; tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED; if ( f_pBufferPlayoutAdd->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; if ( f_pBufferPlayoutAdd->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && f_pBufferPlayoutAdd->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT; if ( f_pBufferPlayoutAdd->fRepeat != TRUE && f_pBufferPlayoutAdd->fRepeat != FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT; if ( f_pBufferPlayoutAdd->fRepeat == TRUE ) { if ( f_pBufferPlayoutAdd->ulRepeatCount != cOCT6100_REPEAT_INFINITELY ) { if ( f_pBufferPlayoutAdd->ulRepeatCount == 0x0 || f_pBufferPlayoutAdd->ulRepeatCount > cOCT6100_REPEAT_MAX) { return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_REPEAT_COUNT; } } } if ( f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_0_DB && f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MINUS_6_DB && f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MINUS_12_DB && f_pBufferPlayoutAdd->ulMixingMode != cOCT6100_MIXING_MUTE ) return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_MIXING; if ( ( f_pBufferPlayoutAdd->lGainDb < -24 ) || ( f_pBufferPlayoutAdd->lGainDb > 24 ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_GAIN_DB; /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pBufferPlayoutAdd->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; *f_pulChannelIndex = f_pBufferPlayoutAdd->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK; if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pBufferPlayoutAdd->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChannel->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; /* Check if repeat flag has been used for this port. */ if ( ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinBufPlayoutRepeatUsed == TRUE ) ) || ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutBufPlayoutRepeatUsed == TRUE ) ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_REPEAT_USED; /*=====================================================================*/ /*=====================================================================*/ /* Check the buffer information. */ *f_pulBufferIndex = f_pBufferPlayoutAdd->ulBufferIndex; if ( *f_pulBufferIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_INDEX; mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, *f_pulBufferIndex ) if ( pBufferEntry->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN; /* Check if the play length is not larger then the currently uploaded buffer. */ if ( ( f_pBufferPlayoutAdd->ulBufferLength > pBufferEntry->ulBufferSize ) && ( f_pBufferPlayoutAdd->ulBufferLength != cOCT6100_AUTO_SELECT ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE; if( f_pBufferPlayoutAdd->ulBufferLength != cOCT6100_AUTO_SELECT ) { if ( f_pBufferPlayoutAdd->ulBufferLength < cOCT6100_MINIMUM_BUFFER_SIZE ) return cOCT6100_ERR_BUFFER_PLAYOUT_TOO_SMALL; if ( ( f_pBufferPlayoutAdd->ulBufferLength % cOCT6100_BUFFER_SIZE_GRANULARITY ) != 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_BUF_SIZE; } /*=====================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteBufferAddStructs Description: Write the buffer playout event in the channel's port playout circular buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutAdd Pointer to buffer playout add structure. f_ulChannelIndex Index of the channel on which the buffer is to be added. f_ulBufferIndex Index of the buffer structure within the API's buffer list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteBufferAddStructs UINT32 Oct6100ApiWriteBufferAddStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_ADD f_pBufferPlayoutAdd, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulBufferIndex ) { tPOCT6100_API_BUFFER pBufferEntry; tPOCT6100_API_CHANNEL pEchoChannel; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 ulTempData; UINT32 ulEventBuffer; UINT32 ulReadPtrBytesOfst; UINT32 ulReadPtrBitOfst; UINT32 ulReadPtrFieldSize; UINT32 ulWritePtrBytesOfst; UINT32 ulWritePtrBitOfst; UINT32 ulWritePtrFieldSize; UINT32 ulWritePtr; UINT32 ulReadPtr; UINT32 ulPlayoutBaseAddress; UINT32 ulAddress; UINT32 ulEventIndex; UINT32 ulMask; UINT32 ulRepeatCount = 0; BOOL fRepeatCountSet = FALSE; UINT32 ulDurationModulo = 0; UINT32 ulEventsToCreate = 1; UINT32 ulBufferDurationMs; UINT32 ulBufferLength; UINT16 usTempData = 0; UINT16 usReadData; UINT32 ulChipWritePtr; UINT32 ulReadData; UINT32 ulLoopCnt = 0; BOOL fStillPlaying = TRUE; BOOL fCheckHardStop = FALSE; BOOL fOldBufferPlayoutVersion = FALSE; UINT32 aulWaitTime[ 2 ]; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex ); mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, f_ulBufferIndex ); /* Select the buffer of interest. */ if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst; ulWritePtr = pEchoChannel->ulRinBufWritePtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize; } else /* f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst; ulWritePtr = pEchoChannel->ulSoutBufWritePtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize; } /*=======================================================================*/ /* Calculate the repeat count. */ /* The buffer length is either the total buffer size or the value specified by the user */ if ( f_pBufferPlayoutAdd->ulBufferLength == cOCT6100_AUTO_SELECT ) { ulBufferLength = pBufferEntry->ulBufferSize; } else { ulBufferLength = f_pBufferPlayoutAdd->ulBufferLength; } if ( f_pBufferPlayoutAdd->ulDuration != cOCT6100_INVALID_VALUE ) { /* With duration and buffer length, we can find the number of times we must repeat playing this buffer. */ ulBufferDurationMs = ulBufferLength / cOCT6100_SAMPLES_PER_MS; ulRepeatCount = f_pBufferPlayoutAdd->ulDuration / ulBufferDurationMs; fRepeatCountSet = TRUE; /* Check if buffer is larger then asked duration. */ if ( ulRepeatCount != 0x0 ) { /* We might have to create more then 1 event to accomodate for the repeat-max limit. */ ulEventsToCreate = ( ulRepeatCount / cOCT6100_REPEAT_MAX ) + 1; } else { /* No repeat event. Maybe only the duration modulo! */ ulEventsToCreate = 0x0; } /* Check if must create a second event for a buffer that cannot be played completely. */ ulDurationModulo = f_pBufferPlayoutAdd->ulDuration % ulBufferDurationMs; if ( ulDurationModulo != 0x0 ) { ulDurationModulo *= cOCT6100_SAMPLES_PER_MS; if ( ulDurationModulo / cOCT6100_BUFFER_SIZE_GRANULARITY ) { /* Round the modulo to be on a buffer size granularity. */ /* This will round down. */ ulDurationModulo = ( ulDurationModulo / cOCT6100_BUFFER_SIZE_GRANULARITY ) * cOCT6100_BUFFER_SIZE_GRANULARITY; /* If the event about to be created is smaller then the minimum buffer size, */ /* round up to the minimum required by the hardware. */ if ( ulDurationModulo < cOCT6100_MINIMUM_BUFFER_SIZE ) ulDurationModulo = cOCT6100_MINIMUM_BUFFER_SIZE; ulEventsToCreate++; } else { /* The modulo is too small to be played. Skip. */ ulDurationModulo = 0; } } } else if ( f_pBufferPlayoutAdd->fRepeat == TRUE && f_pBufferPlayoutAdd->ulRepeatCount != cOCT6100_REPEAT_INFINITELY ) { /* The repeat count is set directly from the user. */ ulRepeatCount = f_pBufferPlayoutAdd->ulRepeatCount; fRepeatCountSet = TRUE; } /*=======================================================================*/ /* Set the playout feature base address. */ ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Read the read pointer. */ ulAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; /* Must read in memory directly since this value is changed by hardware. */ ulResult = Oct6100ApiReadDword( f_pApiInstance, ulAddress, &ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); /* Store the read pointer. */ ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; /* Compare the pointers... Are they different? If so, there is something already in the list. */ if ( ulReadPtr != ulWritePtr ) { /* Check if there is enough room for the playout events. */ if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE ) && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) ) { /* 127 or 31 events image. */ if ( (UINT8)( ( ulWritePtr - ulReadPtr ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ) ) >= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - (UINT8)ulEventsToCreate ) ) fCheckHardStop = TRUE; } else { /* Old 31 events image. */ if ( ( ( ulWritePtr - ulReadPtr ) & 0x1F ) >= ( 0x20 - ulEventsToCreate ) ) fCheckHardStop = TRUE; fOldBufferPlayoutVersion = TRUE; } if ( fCheckHardStop == TRUE ) { /* Ok. From what was read, the list is full. But we might still have a chance if the hard-stop */ /* version was used. In this case, some of the buffers in the list might */ /* become free in a couple of milliseconds, so try to wait for this. */ if ( ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinHardStop == TRUE ) ) || ( ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutHardStop == TRUE ) ) ) { /* Read the 'chip' write pointer in the hardware. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; /* Get the write pointer in the chip. */ ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulReadData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); /* Store the write pointer. */ ulChipWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst; /* Optimize this access by only reading the word we are interested in. */ if ( ulReadPtrBitOfst < 16 ) ReadParams.ulReadAddress += 2; while( fStillPlaying == TRUE ) { /* Read the read pointer until equals to the write pointer. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulReadPtrBitOfst < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); /* Store the read pointer.*/ ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; /* Playout has finished when the read pointer reaches the write pointer. */ if ( ulReadPtr == ulChipWritePtr ) break; ulLoopCnt++; if ( ulLoopCnt > cOCT6100_MAX_LOOP ) { return cOCT6100_ERR_FATAL_E7; } aulWaitTime[ 0 ] = 100; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Clear hard-stop flag. */ if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* No hard stop for now. */ pEchoChannel->fRinHardStop = FALSE; } else /* if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */ { /* No hard stop for now. */ pEchoChannel->fSoutHardStop = FALSE; } /* Now check again if the event can be added... */ if ( fOldBufferPlayoutVersion == FALSE ) { if ( (UINT8)( ( ulWritePtr - ulReadPtr ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ) ) >= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - (UINT8)ulEventsToCreate ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL; } else /* if ( fOldBufferPlayoutVersion == TRUE ) */ { /* Old 31 events image. */ if ( ( ( ulWritePtr - ulReadPtr ) & 0x1F ) >= ( 0x20 - ulEventsToCreate ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL; } /* Good, at least another buffer can be added! Add the buffer to the list. */ } else { /* Well the list is full! */ return cOCT6100_ERR_BUFFER_PLAYOUT_ADD_EVENT_BUF_FULL; } } } /*=======================================================================*/ /* Write the events. */ for ( ulEventIndex = 0; ulEventIndex < ulEventsToCreate; ulEventIndex ++ ) { /* Set the playout event base address. */ if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE ) && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) ) { /* 127 or 31 events image. */ ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + (f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * (ulWritePtr & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ))); } else { /* Old 31 events image. */ ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + (f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * (ulWritePtr & 0x1F)); } /* EVENT BASE + 0 */ /* Make sure the xIS and xHS bits are cleared. */ ulTempData = 0; /* Set the repeat count. */ if ( fRepeatCountSet == TRUE ) { if ( ( ulRepeatCount != 0x0 ) && ( ulRepeatCount <= cOCT6100_REPEAT_MAX ) ) { /* Use repeat count directly. */ ulTempData |= ulRepeatCount; /* Will be used later when creating the duration modulo event. */ ulRepeatCount = 0; } else if ( ulRepeatCount != 0x0 ) { /* Get ready for next event. */ ulRepeatCount -= cOCT6100_REPEAT_MAX; /* Set maximum for this event. */ ulTempData |= cOCT6100_REPEAT_MAX; } else { /* Duration modulo case. Nothing to set here. */ } } else /* if ( fRepeatCountSet != TRUE ) */ { /* Repeat only once. */ ulTempData |= 0x1; } ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* EVENT BASE + 4 */ /* Set the buffer base address and playout configuration. */ ulAddress += 4; ulTempData = pBufferEntry->ulBufferBase & 0x07FFFFFF; /* Set play indefinitely or loop N times. */ if ( ( fRepeatCountSet == FALSE ) && ( f_pBufferPlayoutAdd->fRepeat == TRUE ) ) { /* Repeat indefinitely. */ ulTempData |= 0x1 << cOCT6100_PLAYOUT_EVENT_REPEAT_OFFSET; if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) pEchoChannel->fRinBufPlayoutRepeatUsed = TRUE; else /* if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */ pEchoChannel->fSoutBufPlayoutRepeatUsed = TRUE; } /* Use loop N times feature. */ ulTempData |= 0x1 << cOCT6100_PLAYOUT_EVENT_LOOP_TIMES_OFFSET; /* Set the law.*/ ulTempData |= ( pBufferEntry->byBufferPcmLaw << cOCT6100_PLAYOUT_EVENT_LAW_OFFSET ); /* Set the mixing configuration.*/ ulTempData |= f_pBufferPlayoutAdd->ulMixingMode << cOCT6100_PLAYOUT_EVENT_MIX_OFFSET; ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* EVENT BASE + 8 */ /* Set the buffer size and playout gain. */ ulAddress += 4; /* Check if we are setting the duration modulo. This would be the last event and this */ /* event is of a very specific size. */ if ( ( fRepeatCountSet == TRUE ) && ( ulEventIndex == ( ulEventsToCreate - 1 ) ) && ( ulDurationModulo != 0x0 ) ) { /* The duration modulo variable contains all that is needed here. */ ulBufferLength = ulDurationModulo; } ulTempData = ulBufferLength; /* Adjust playout gain. */ if ( f_pBufferPlayoutAdd->lGainDb != 0 ) { /* Convert the dB value into OctFloat format. */ usTempData = Oct6100ApiDbAmpHalfToOctFloat( f_pBufferPlayoutAdd->lGainDb ); ulTempData |= ( usTempData & 0xFF00 ) << 16; } else { ulTempData |= cOCT6100_PLAYOUT_GAIN; } ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* EVENT BASE + 0xC */ ulAddress += 4; ulTempData = ( ulBufferLength - 1 ) & 0xFFFFFFC0; /* Must be multiple of 64 bytes */ /* Adjust playout gain. */ if ( f_pBufferPlayoutAdd->lGainDb != 0 ) { ulTempData |= ( usTempData & 0xFF ) << 24; } ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulAddress, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Next event. */ ulWritePtr++; } /*=======================================================================*/ /*=======================================================================*/ /* Increment the write pointer to make it point to the next empty entry. */ if ( f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { pEchoChannel->ulRinBufWritePtr = ( pEchoChannel->ulRinBufWritePtr + ulEventsToCreate ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ); /* Remember that a buffer was added on the rin port. */ pEchoChannel->fRinBufAdded = TRUE; } else /* f_pBufferPlayoutAdd->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { pEchoChannel->ulSoutBufWritePtr = ( pEchoChannel->ulSoutBufWritePtr + ulEventsToCreate ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ); /* Remember that a buffer was added on the sout port. */ pEchoChannel->fSoutBufAdded = TRUE; } /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutStartSer Description: Starts buffer playout on a channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStart Pointer to buffer playout start structure. f_ulPlayoutStopEventType Playout stop event type to be generated if required. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutStartSer UINT32 Oct6100BufferPlayoutStartSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, IN UINT32 f_ulPlayoutStopEventType ) { UINT32 ulBufferIndex = 0; UINT32 ulChannelIndex; BOOL fNotifyOnPlayoutStop; UINT32 ulUserEventId; BOOL fAddToCurrentlyPlayingList; UINT32 ulResult; /* Check the user's configuration of the buffer for errors. */ ulResult = Oct6100ApiCheckPlayoutStartParams( f_pApiInstance, f_pBufferPlayoutStart, &ulChannelIndex, &ulBufferIndex, &fNotifyOnPlayoutStop, &ulUserEventId, &fAddToCurrentlyPlayingList ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write to all resources needed to activate buffer playout. */ ulResult = Oct6100ApiWriteChanPlayoutStructs( f_pApiInstance, f_pBufferPlayoutStart, ulChannelIndex, ulBufferIndex, fNotifyOnPlayoutStop, ulUserEventId, fAddToCurrentlyPlayingList, f_ulPlayoutStopEventType ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckPlayoutStartParams Description: Check the validity of the channel and buffer requested. Check the validity of the flags requested. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStart Pointer to buffer playout start structure. f_pulChannelIndex Pointer to the channel index of the selected channel. f_pulBufferIndex Pointer to the buffer index within the API's buffer list. f_pfNotifyOnPlayoutStop Pointer to the notify on playout stop flag. f_pulUserEventId Pointer to the user event id specified. f_pfAllowStartIfActive Pointer to the add to currently playing list flag. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckPlayoutStartParams UINT32 Oct6100ApiCheckPlayoutStartParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulBufferIndex, OUT PBOOL f_pfNotifyOnPlayoutStop, OUT PUINT32 f_pulUserEventId, OUT PBOOL f_pfAllowStartIfActive ) { tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED; if ( f_pBufferPlayoutStart->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; if ( f_pBufferPlayoutStart->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && f_pBufferPlayoutStart->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT; if ( f_pBufferPlayoutStart->fNotifyOnPlayoutStop != FALSE && f_pBufferPlayoutStart->fNotifyOnPlayoutStop != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOTIFY_ON_STOP; if ( f_pBufferPlayoutStart->fAllowStartWhileActive != FALSE && f_pBufferPlayoutStart->fAllowStartWhileActive != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_ALLOW_ACTIVE; /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pBufferPlayoutStart->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; *f_pulChannelIndex = f_pBufferPlayoutStart->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK; if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pBufferPlayoutStart->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChannel->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; /* The channel cannot be in POWER_DOWN or HT_FREEZE to start the playout. */ if ( ( pEchoChannel->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN ) || ( pEchoChannel->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_HT_FREEZE ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_ECHO_OP_MODE; /* The channel's NLP must be enabled for playout to occur. */ if ( pEchoChannel->VqeConfig.fEnableNlp == FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_NLP_DISABLED; /*=====================================================================*/ /*=====================================================================*/ /* Check if the user activated the buffer playout events. */ if ( f_pBufferPlayoutStart->fNotifyOnPlayoutStop == TRUE && f_pApiInstance->pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_DISABLED; /*=====================================================================*/ /*=====================================================================*/ /* Check if there is actually a buffer added in the list. */ if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { if ( pEchoChannel->fRinBufAdded == FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_LIST_EMPTY; } else /* if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */ { if ( pEchoChannel->fSoutBufAdded == FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_LIST_EMPTY; } /*=====================================================================*/ /* Return the requested information. */ *f_pfNotifyOnPlayoutStop = f_pBufferPlayoutStart->fNotifyOnPlayoutStop; *f_pulUserEventId = f_pBufferPlayoutStart->ulUserEventId; *f_pfAllowStartIfActive = f_pBufferPlayoutStart->fAllowStartWhileActive; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteChanPlayoutStructs Description: Write the buffer playout event in the channel main structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStart Pointer to buffer playout start structure. f_ulChannelIndex Index of the channel within the API's channel list. f_ulBufferIndex Index of the buffer within the API's buffer list. f_fNotifyOnPlayoutStop Flag for the notify on playout stop. f_ulUserEventId User event id passed to the user when a playout event is generated. f_fAllowStartIfActive Add to currently playing list flag. f_ulPlayoutStopEventType Playout stop event type to be generated if required. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteChanPlayoutStructs UINT32 Oct6100ApiWriteChanPlayoutStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_START f_pBufferPlayoutStart, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulBufferIndex, IN BOOL f_fNotifyOnPlayoutStop, IN UINT32 f_ulUserEventId, IN BOOL f_fAllowStartIfActive, IN UINT32 f_ulPlayoutStopEventType ) { tPOCT6100_API_BUFFER pBufferEntry; tPOCT6100_API_CHANNEL pEchoChannel; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 ulWritePtr; UINT32 ulChipWritePtr; PUINT32 pulSkipPtr; UINT32 ulWritePtrBytesOfst; UINT32 ulSkipPtrBytesOfst; UINT32 ulWritePtrBitOfst; UINT32 ulSkipPtrBitOfst; UINT32 ulWritePtrFieldSize; UINT32 ulSkipPtrFieldSize; UINT32 ulIgnoreBytesOfst; UINT32 ulIgnoreBitOfst; UINT32 ulIgnoreFieldSize; UINT32 ulHardSkipBytesOfst; UINT32 ulHardSkipBitOfst; UINT32 ulHardSkipFieldSize; UINT32 ulReadPtrBytesOfst; UINT32 ulReadPtrBitOfst; UINT32 ulReadPtrFieldSize; UINT32 ulPlayoutBaseAddress; UINT32 ulAddress; UINT32 ulTempData; UINT32 ulMask; UINT32 ulReadData; UINT32 ulReadPtr; UINT32 ulLoopCnt = 0; UINT16 usReadData; BOOL fBufferPlayoutStopDetected; BOOL fWriteSkipPtr = FALSE; BOOL fStillPlaying = TRUE; UINT32 aulWaitTime[ 2 ]; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex ); mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBufferEntry, f_ulBufferIndex ); /* First off, check for buffer playout events, if requested for this channel/port. */ /* At the same time, if requested, check that the playout has stopped for this channel/port. */ if ( ( ( pEchoChannel->fRinBufPlaying == TRUE ) && ( ( pEchoChannel->fRinBufPlayoutNotifyOnStop == TRUE ) || ( f_fAllowStartIfActive == FALSE ) ) && ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) ) || ( ( ( pEchoChannel->fSoutBufPlaying == TRUE ) || ( f_fAllowStartIfActive == FALSE ) ) && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == TRUE ) && ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) ) ) { /* Buffer playout might still be going on for this channel/port. */ ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, f_ulChannelIndex, f_pBufferPlayoutStart->ulPlayoutPort, pEchoChannel->fRinBufPlayoutNotifyOnStop, &fBufferPlayoutStopDetected ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the user requested to only start if playout is over. Return an error if */ /* buffer playout is still going on on this channel/port. */ if ( ( f_fAllowStartIfActive == FALSE ) && ( fBufferPlayoutStopDetected == FALSE ) ) { /* No go! User should wait for the current list to stop, or call the */ /* Oct6100BufferPlayoutStop function. */ return cOCT6100_ERR_BUFFER_PLAYOUT_STILL_ACTIVE; } } /* Select the buffer of interest. */ if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { ulWritePtr = pEchoChannel->ulRinBufWritePtr; pulSkipPtr = &pEchoChannel->ulRinBufSkipPtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4; ulSkipPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.usDwordOffset * 4; ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.usDwordOffset * 4; ulHardSkipBytesOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.usDwordOffset * 4; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset; ulSkipPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byBitOffset; ulIgnoreBitOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byBitOffset; ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byBitOffset; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize; ulSkipPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byFieldSize; ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byFieldSize; ulHardSkipFieldSize = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byFieldSize; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize; } else /* f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { ulWritePtr = pEchoChannel->ulSoutBufWritePtr; pulSkipPtr = &pEchoChannel->ulSoutBufSkipPtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4; ulSkipPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.usDwordOffset * 4; ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.usDwordOffset * 4; ulHardSkipBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.usDwordOffset * 4; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset; ulSkipPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byBitOffset; ulIgnoreBitOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byBitOffset; ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byBitOffset; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize; ulSkipPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byFieldSize; ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byFieldSize; ulHardSkipFieldSize = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byFieldSize; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize; } /* Set the playout feature base address. */ ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Check if we must wait for stop to complete before starting a new list. */ if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) { if ( ( ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinHardStop == TRUE ) ) || ( ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutHardStop == TRUE ) ) ) { /* Read the read pointer. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; /* Get the write pointer in the chip. */ ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulReadData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); /* Store the write pointer. */ ulChipWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst; /* Optimize this access by only reading the word we are interested in. */ if ( ulReadPtrBitOfst < 16 ) ReadParams.ulReadAddress += 2; while( fStillPlaying == TRUE ) { /* Read the read pointer until equals to the write pointer. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulReadPtrBitOfst < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); /* Store the read pointer. */ ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; /* Playout has finished when the read pointer reaches the write pointer. */ if ( ulReadPtr == ulChipWritePtr ) break; ulLoopCnt++; if( ulLoopCnt > cOCT6100_MAX_LOOP ) { return cOCT6100_ERR_FATAL_E6; } aulWaitTime[ 0 ] = 100; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Check if must clear the skip bit. */ if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) { if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE ) && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) ) { /* Make sure the skip bit is cleared to start playout! */ ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask ); /* Cleared! */ ulTempData &= ( ~ulMask ); ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Make sure the hard skip bit is cleared to start playout! */ ulAddress = ulPlayoutBaseAddress + ulHardSkipBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulHardSkipBitOfst, &ulMask ); /* Cleared! */ ulTempData &= ( ~ulMask ); ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Write the skip and write pointer to activate buffer playout. */ /* Update the skip pointer. */ if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == FALSE ) || ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == FALSE ) ) { /* Old 31 events image. */ if ( ( ( ulWritePtr - *pulSkipPtr ) & 0x7F ) > 63 ) { *pulSkipPtr = ( ulWritePtr - 63 ) & 0x7F; fWriteSkipPtr = TRUE; } } else { /* No need to update the skip pointer, a bit needs to be set when skipping. */ /* fWriteSkipPtr set to FALSE from variable declaration. */ } if ( fWriteSkipPtr == TRUE ) { /*=======================================================================*/ /* Fetch and modify the skip pointer. */ ulAddress = ulPlayoutBaseAddress + ulSkipPtrBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulSkipPtrFieldSize, ulSkipPtrBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); ulTempData |= *pulSkipPtr << ulSkipPtrBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ } /*=======================================================================*/ /* Fetch and modify the write pointer. */ ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst; mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, pEchoChannel, ulAddress, &ulTempData, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); ulTempData |= ulWritePtr << ulWritePtrBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Now update the state of the channel stating that the buffer playout is activated. */ /* Select the buffer of interest.*/ if ( f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Check if the global ports active stat must be incremented. */ if ( pEchoChannel->fRinBufPlaying == FALSE ) { /* Increment the number of active buffer playout ports. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts++; } pEchoChannel->fRinBufPlaying = TRUE; /* Keep the new notify on event flag. */ pEchoChannel->fRinBufPlayoutNotifyOnStop = (UINT8)( f_fNotifyOnPlayoutStop & 0xFF ); /* Keep the specified user event id. */ pEchoChannel->ulRinUserBufPlayoutEventId = f_ulUserEventId; /* Keep type of event to be generated. */ pEchoChannel->byRinPlayoutStopEventType = (UINT8)( f_ulPlayoutStopEventType & 0xFF ); /* No hard stop for now. */ pEchoChannel->fRinHardStop = FALSE; /* No buffer added in the rin list for now. */ pEchoChannel->fRinBufAdded = FALSE; /* Buffer playout is active on this channel. */ pEchoChannel->fBufPlayoutActive = TRUE; } else /* f_pBufferPlayoutStart->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { /* Check if the global ports active stat must be incremented. */ if ( pEchoChannel->fSoutBufPlaying == FALSE ) { /* Increment the number of active buffer playout ports. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts++; } pEchoChannel->fSoutBufPlaying = TRUE; /* Keep the new notify on event flag. */ pEchoChannel->fSoutBufPlayoutNotifyOnStop = (UINT8)( f_fNotifyOnPlayoutStop & 0xFF ); /* Keep the specified user event id. */ pEchoChannel->ulSoutUserBufPlayoutEventId = f_ulUserEventId; /* Keep type of event to be generated. */ pEchoChannel->bySoutPlayoutStopEventType = (UINT8)( f_ulPlayoutStopEventType & 0xFF ); /* No hard stop for now. */ pEchoChannel->fSoutHardStop = FALSE; /* No buffer added in the sout list for now. */ pEchoChannel->fSoutBufAdded = FALSE; /* Buffer playout is active on this channel. */ pEchoChannel->fBufPlayoutActive = TRUE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutStopSer Description: Stops buffer playout on a channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStop Pointer to buffer playout stop structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutStopSer UINT32 Oct6100BufferPlayoutStopSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop ) { UINT32 ulChannelIndex; UINT16 usEchoMemIndex; UINT32 ulResult; /* Check the user's configuration of the buffer for errors. */ ulResult = Oct6100ApiAssertPlayoutStopParams( f_pApiInstance, f_pBufferPlayoutStop, &ulChannelIndex, &usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write to all resources needed to deactivate buffer playout. */ ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, f_pBufferPlayoutStop, ulChannelIndex, usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertPlayoutStopParams Description: Check the validity of the channel and buffer requested. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStop Pointer to buffer playout stop structure. f_pulChannelIndex Pointer to the channel index on which playout is to be stopped. f_pusEchoMemIndex Pointer to the echo mem index on which playout is to be stopped. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertPlayoutStopParams UINT32 Oct6100ApiAssertPlayoutStopParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop, OUT PUINT32 f_pulChannelIndex, OUT PUINT16 f_pusEchoMemIndex ) { tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPlayoutBuffers == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_DISABLED; if ( f_pBufferPlayoutStop->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; if ( f_pBufferPlayoutStop->ulPlayoutPort != cOCT6100_CHANNEL_PORT_ROUT && f_pBufferPlayoutStop->ulPlayoutPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_BUFFER_PLAYOUT_PLAYOUT_PORT; if ( f_pBufferPlayoutStop->fStopCleanly != TRUE && f_pBufferPlayoutStop->fStopCleanly != FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_STOP_CLEANLY; /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pBufferPlayoutStop->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; *f_pulChannelIndex = f_pBufferPlayoutStop->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK; if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pBufferPlayoutStop->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChannel->fReserved != TRUE ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt ) return cOCT6100_ERR_BUFFER_PLAYOUT_CHANNEL_HANDLE_INVALID; /* Return echo memory index. */ *f_pusEchoMemIndex = pEchoChannel->usEchoMemIndex; /* Check if buffer playout is active for the selected port. */ if ( ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) && ( pEchoChannel->fRinBufPlaying == FALSE ) && ( pEchoChannel->fRinBufAdded == FALSE ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED; if ( ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChannel->fSoutBufPlaying == FALSE ) && ( pEchoChannel->fSoutBufAdded == FALSE ) ) return cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED; /*=====================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateChanPlayoutStructs Description: Write the buffer playout event in the channel main structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufferPlayoutStop Pointer to buffer playout stop structure. f_ulChannelIndex Index of the channel within the API's channel list. f_usEchoMemIndex Index of the echo channel in hardware memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateChanPlayoutStructs UINT32 Oct6100ApiInvalidateChanPlayoutStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_BUFFER_PLAYOUT_STOP f_pBufferPlayoutStop, IN UINT32 f_ulChannelIndex, IN UINT16 f_usEchoMemIndex ) { tPOCT6100_API_CHANNEL pEchoChannel; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulWritePtrBytesOfst; UINT32 ulWritePtrBitOfst; UINT32 ulWritePtrFieldSize; UINT32 ulSkipPtrBytesOfst; UINT32 ulSkipPtrBitOfst; UINT32 ulSkipPtrFieldSize; UINT32 ulIgnoreBytesOfst; UINT32 ulIgnoreBitOfst; UINT32 ulIgnoreFieldSize; UINT32 ulHardSkipBytesOfst; UINT32 ulHardSkipBitOfst; UINT32 ulHardSkipFieldSize; UINT32 ulReadPtrBytesOfst; UINT32 ulReadPtrBitOfst; UINT32 ulReadPtrFieldSize; UINT32 ulSkipPtr; UINT32 ulWritePtr; UINT32 ulReadPtr = 0; UINT32 ulCurrentPtr; UINT32 ulPlayoutBaseAddress; UINT32 ulAddress; UINT32 ulTempData; UINT32 ulMask; UINT32 ulReadData; UINT16 usReadData; BOOL fCheckStop = FALSE; UINT32 ulEventBuffer; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex ); /* Select the port of interest. */ if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { ulWritePtr = pEchoChannel->ulRinBufWritePtr; ulSkipPtr = ulWritePtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize; ulSkipPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.usDwordOffset * 4; ulSkipPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byBitOffset; ulSkipPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst.byFieldSize; ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.usDwordOffset * 4; ulIgnoreBitOfst = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byBitOffset; ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst.byFieldSize; ulHardSkipBytesOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.usDwordOffset * 4; ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byBitOffset; ulHardSkipFieldSize = pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize; } else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { ulWritePtr = pEchoChannel->ulSoutBufWritePtr; ulSkipPtr = ulWritePtr; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize; ulSkipPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.usDwordOffset * 4; ulSkipPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byBitOffset; ulSkipPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst.byFieldSize; ulIgnoreBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.usDwordOffset * 4; ulIgnoreBitOfst = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byBitOffset; ulIgnoreFieldSize = pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst.byFieldSize; ulHardSkipBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.usDwordOffset * 4; ulHardSkipBitOfst = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byBitOffset; ulHardSkipFieldSize = pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize; } /* Set the playout feature base address. */ ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Check if something is currently playing. */ if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { if ( pEchoChannel->fRinBufPlaying == TRUE ) { /* Check if we are stopping it or if it stopped by itself. */ fCheckStop = TRUE; } else { /* Not playing! */ if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL ) *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE; } } else /* if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */ { if ( pEchoChannel->fSoutBufPlaying == TRUE ) { /* Check if we are stopping it or if it stopped by itself. */ fCheckStop = TRUE; } else { /* Not playing! */ if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL ) *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE; } } if ( ( fCheckStop == TRUE ) || ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) ) { /* Read the read pointer. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; /* Optimize this access by only reading the word we are interested in. */ if ( ulReadPtrBitOfst < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulReadPtrBitOfst < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); /* Store the read pointer. */ ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; /* Playout has finished when the read pointer reaches the write pointer. */ if ( f_pBufferPlayoutStop->pfAlreadyStopped != NULL ) { if ( ulReadPtr != ulWritePtr ) *f_pBufferPlayoutStop->pfAlreadyStopped = FALSE; else /* if ( ulReadPtr == ulWritePtr ) */ *f_pBufferPlayoutStop->pfAlreadyStopped = TRUE; } } /* If the skip bits are located in the event itself, the playout is stopped by setting the */ /* skip pointer to the hardware chip write pointer. Read it directly from the NLP configuration. */ if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) { if ( ulReadPtr != ulWritePtr ) { /* Get the write pointer in the chip. */ ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulReadData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); /* Store the write pointer. */ ulWritePtr = ( ulReadData & ulMask ) >> ulWritePtrBitOfst; ulSkipPtr = ulWritePtr; } } /* Check if must clear repeat bit. */ if ( ( ( pEchoChannel->fRinBufPlayoutRepeatUsed == TRUE ) && ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) ) || ( ( pEchoChannel->fSoutBufPlayoutRepeatUsed == TRUE ) && ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) ) ) { if ( ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) || ( ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) && ( ulWritePtr != ulReadPtr ) ) ) { if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst; } else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst; } /* Set the playout event base address. */ if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE ) && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) ) { /* 127 or 31 events image. */ ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ( ( ulWritePtr - 1 ) & ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ))); } else { /* Old 31 events image. */ ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + (cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ( ( ulWritePtr - 1 ) & 0x1F)); } /* EVENT BASE + 4 */ /* Playout configuration. */ ulAddress += 4; ReadParams.ulReadAddress = ulAddress; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read-clear-write the new repeat bit. */ usReadData &= 0x7FFF; WriteParams.ulWriteAddress = ulAddress; WriteParams.usWriteData = usReadData; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Write the skip to the value of the write pointer to stop buffer playout. */ /*=======================================================================*/ /* First set the ignore skip clean bit if required. */ if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == FALSE ) || ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == FALSE ) ) { ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); /* Check if the skip need to be clean or not. */ if ( f_pBufferPlayoutStop->fStopCleanly == FALSE ) ulTempData |= 0x1 << ulIgnoreBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /*=======================================================================*/ /* Fetch and modify the write pointer. */ ulAddress = ulPlayoutBaseAddress + ulWritePtrBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); ulTempData |= ulWritePtr << ulWritePtrBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Fetch and modify the skip pointer. */ ulAddress = ulPlayoutBaseAddress + ulSkipPtrBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulSkipPtrFieldSize, ulSkipPtrBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); ulTempData |= ulSkipPtr << ulSkipPtrBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* If in the new buffer playout case, things are in a different order. */ if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) { if ( ( pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip == TRUE ) && ( pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip == TRUE ) ) { ulAddress = ulPlayoutBaseAddress + ulHardSkipBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulHardSkipFieldSize, ulHardSkipBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); /* Check if the skip need to be clean or not. */ if ( f_pBufferPlayoutStop->fStopCleanly == FALSE ) ulTempData |= 0x1 << ulHardSkipBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now is the appropriate time to skip! */ ulAddress = ulPlayoutBaseAddress + ulIgnoreBytesOfst; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulIgnoreFieldSize, ulIgnoreBitOfst, &ulMask ); ulTempData &= ( ~ulMask ); /* Set the skip bit. */ ulTempData |= 0x1 << ulIgnoreBitOfst; ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulAddress, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*=======================================================================*/ /*=======================================================================*/ /* The API must set the skip bit in all the events that are queued. */ if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) { if ( fCheckStop == TRUE ) { if ( ulReadPtr != ulWritePtr ) { if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst; } else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { ulEventBuffer = pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst; } for ( ulCurrentPtr = ulReadPtr; ulCurrentPtr != ulWritePtr; ) { /* Set the playout event base address. */ /* 127 or 31 events image. */ ulAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + ulEventBuffer + ( cOCT6100_PLAYOUT_EVENT_MEM_SIZE * ulCurrentPtr ); ulCurrentPtr++; ulCurrentPtr &= ( pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents - 1 ); /* EVENT BASE + 0 playout configuration. */ WriteParams.ulWriteAddress = ulAddress; /* Set skip bit + hard-skip bit. */ WriteParams.usWriteData = 0x8000; if ( f_pBufferPlayoutStop->fStopCleanly == FALSE ) WriteParams.usWriteData |= 0x4000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } /*=======================================================================*/ /* If stop immediatly, wait the stop before leaving the function. */ if ( f_pBufferPlayoutStop->fStopCleanly == FALSE ) { /* Remember that an "hard stop" was used for the next start. */ if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) pEchoChannel->fRinHardStop = TRUE; else /* if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT ) */ pEchoChannel->fSoutHardStop = TRUE; } /*=======================================================================*/ /* Update the channel entry to set the playing flag to FALSE. */ /* Select the port of interest. */ if ( f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Check if the global ports active stat must be decremented. */ if ( pEchoChannel->fRinBufPlaying == TRUE ) { /* Decrement the number of active buffer playout ports. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; } pEchoChannel->fRinBufPlaying = FALSE; /* Return user information. */ if ( f_pBufferPlayoutStop->pfNotifyOnPlayoutStop != NULL ) *f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = pEchoChannel->fRinBufPlayoutNotifyOnStop; /* Make sure no new event is recorded for this channel/port. */ pEchoChannel->fRinBufPlayoutNotifyOnStop = FALSE; if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) { pEchoChannel->ulRinBufSkipPtr = ulSkipPtr; pEchoChannel->ulRinBufWritePtr = ulWritePtr; } else /* if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) */ pEchoChannel->ulRinBufSkipPtr = pEchoChannel->ulRinBufWritePtr; /* The repeat flag can now be used. */ pEchoChannel->fRinBufPlayoutRepeatUsed = FALSE; /* For sure, all buffers have now been cleared on the Rin port. */ pEchoChannel->fRinBufAdded = FALSE; /* Clear optimization flag if possible. */ if ( ( pEchoChannel->fSoutBufPlaying == FALSE ) && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == FALSE ) ) { /* Buffer playout is no more active on this channel. */ pEchoChannel->fBufPlayoutActive = FALSE; } } else /* f_pBufferPlayoutStop->ulPlayoutPort == cOCT6100_CHANNEL_PORT_SOUT */ { /* Check if the global ports active stat must be decremented. */ if ( pEchoChannel->fSoutBufPlaying == TRUE ) { /* Decrement the number of active buffer playout ports. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; } pEchoChannel->fSoutBufPlaying = FALSE; /* Return user information. */ if ( f_pBufferPlayoutStop->pfNotifyOnPlayoutStop != NULL ) *f_pBufferPlayoutStop->pfNotifyOnPlayoutStop = pEchoChannel->fSoutBufPlayoutNotifyOnStop; /* Make sure no new event is recorded for this channel/port. */ pEchoChannel->fSoutBufPlayoutNotifyOnStop = FALSE; if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == TRUE ) { pEchoChannel->ulSoutBufSkipPtr = ulSkipPtr; pEchoChannel->ulSoutBufWritePtr = ulWritePtr; } else /* if ( pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents == FALSE ) */ pEchoChannel->ulSoutBufSkipPtr = pEchoChannel->ulSoutBufWritePtr; /* The repeat flag can now be used. */ pEchoChannel->fSoutBufPlayoutRepeatUsed = FALSE; /* For sure, all buffers have now been cleared on the Sout port. */ pEchoChannel->fSoutBufAdded = FALSE; /* Clear optimization flag if possible. */ if ( ( pEchoChannel->fRinBufPlaying == FALSE ) && ( pEchoChannel->fRinBufPlayoutNotifyOnStop == FALSE ) ) { /* Buffer playout is no more active on this channel. */ pEchoChannel->fBufPlayoutActive = FALSE; } } /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBufPlayoutListEntry Description: Reserves a free entry in the Buffer playout list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulBufferIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBufPlayoutListEntry UINT32 Oct6100ApiReserveBufPlayoutListEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulBufferIndex ) { PVOID pBufPlayoutAlloc; UINT32 ulResult; mOCT6100_GET_BUFFER_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBufPlayoutAlloc ) ulResult = OctapiLlmAllocAlloc( pBufPlayoutAlloc, f_pulBufferIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_BUFFER_PLAYOUT_ALL_BUFFERS_OPEN; else return cOCT6100_ERR_FATAL_40; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBufPlayoutListEntry Description: Release an entry from the Buffer playout list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulBufferIndex List entry to be freed. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBufPlayoutListEntry UINT32 Oct6100ApiReleaseBufPlayoutListEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBufferIndex ) { PVOID pBufPlayoutAlloc; UINT32 ulResult; mOCT6100_GET_BUFFER_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBufPlayoutAlloc ) ulResult = OctapiLlmAllocDealloc( pBufPlayoutAlloc, f_ulBufferIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_41; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c0000644000175000017500000014606611604644235030764 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_events.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to retrieve tone and playout events. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 81 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_events_inst.h" #include "oct6100api/oct6100_tone_detection_inst.h" #include "oct6100api/oct6100_playout_buf_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_events_pub.h" #include "oct6100api/oct6100_tone_detection_pub.h" #include "oct6100api/oct6100_playout_buf_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_events_priv.h" #include "oct6100_tone_detection_priv.h" #include "oct6100_playout_buf_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100EventGetTone Description: Retreives an array of tone events. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pEventGetTone Pointer to structure used to store the Tone events. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100EventGetToneDef UINT32 Oct6100EventGetToneDef( tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) { f_pEventGetTone->pToneEvent = NULL; f_pEventGetTone->ulMaxToneEvent = 1; f_pEventGetTone->ulNumValidToneEvent = cOCT6100_INVALID_VALUE; f_pEventGetTone->fMoreEvents = FALSE; f_pEventGetTone->fResetBufs = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100EventGetTone UINT32 Oct6100EventGetTone( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100EventGetToneSer( f_pApiInstance, f_pEventGetTone ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutGetEvent Description: Retrieves an array of playout stop events. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pBufPlayoutGetEvent Pointer to structure used to store the playout events. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutGetEventDef UINT32 Oct6100BufferPlayoutGetEventDef( tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) { f_pBufPlayoutGetEvent->pBufferPlayoutEvent = NULL; f_pBufPlayoutGetEvent->ulMaxEvent = 1; f_pBufPlayoutGetEvent->ulNumValidEvent = cOCT6100_INVALID_VALUE; f_pBufPlayoutGetEvent->fMoreEvents = FALSE; f_pBufPlayoutGetEvent->fResetBufs = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100BufferPlayoutGetEvent UINT32 Oct6100BufferPlayoutGetEvent( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100BufferPlayoutGetEventSer( f_pApiInstance, f_pBufPlayoutGetEvent ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetEventsSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of the tone events and playout events software buffers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetEventsSwSizes UINT32 Oct6100ApiGetEventsSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { { UINT32 ulTempVar; /* Memory needed by soft tone event buffers. */ /* Add 1 to the circular buffer such that all user requested events can fit in the circular queue. */ f_pInstSizes->ulSoftToneEventsBuffer = ( f_pOpenChip->ulSoftToneEventsBufSize + 1 ) * sizeof( tOCT6100_API_TONE_EVENT ); /* Round off the sizes of the soft buffers above. */ mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulSoftToneEventsBuffer, ulTempVar ) } { UINT32 ulTempVar; /* Memory needed by soft playout stop event buffers. */ if ( f_pOpenChip->ulSoftBufferPlayoutEventsBufSize != cOCT6100_INVALID_VALUE ) { f_pInstSizes->ulSoftBufPlayoutEventsBuffer = ( f_pOpenChip->ulSoftBufferPlayoutEventsBufSize + 1 ) * sizeof( tOCT6100_API_BUFFER_PLAYOUT_EVENT ); /* Round off the sizes of the soft buffers above. */ mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulSoftBufPlayoutEventsBuffer, ulTempVar ) } else /* if ( f_pInstSizes->ulSoftBufferPlayoutEventsBufSize == cOCT6100_INVALID_VALUE ) */ { f_pInstSizes->ulSoftBufPlayoutEventsBuffer = 0; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100EventGetToneSer Description: Retreives an array of tone event from the software event buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pEventGetTone Pointer to structure which will contain the retreived events. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100EventGetToneSer UINT32 Oct6100EventGetToneSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TONE_EVENT pSoftEvent; UINT32 ulSoftReadPnt; UINT32 ulSoftWritePnt; UINT32 ulSoftBufSize; UINT32 ulNumEventsReturned; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the parameters given by the user. */ if ( f_pEventGetTone->fResetBufs != TRUE && f_pEventGetTone->fResetBufs != FALSE ) return cOCT6100_ERR_EVENTS_GET_TONE_RESET_BUFS; /* Check max tones. */ if ( f_pEventGetTone->ulMaxToneEvent > pSharedInfo->ChipConfig.ulSoftToneEventsBufSize ) return cOCT6100_ERR_EVENTS_MAX_TONES; if ( f_pEventGetTone->fResetBufs == FALSE ) { /* Check if the events need to be fetched from the chip buffer. */ ulSoftReadPnt = pSharedInfo->SoftBufs.ulToneEventBufferReadPtr; ulSoftWritePnt = pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; if ( ulSoftReadPnt == ulSoftWritePnt ) { ulResult = Oct6100ApiTransferToneEvents( f_pApiInstance, f_pEventGetTone->fResetBufs ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If there are no events in the soft buffer then there are none in the chip */ /* either, so return the empty case. Else, return the events in the buffer. */ ulSoftReadPnt = pSharedInfo->SoftBufs.ulToneEventBufferReadPtr; ulSoftWritePnt = pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; ulSoftBufSize = pSharedInfo->SoftBufs.ulToneEventBufferSize; if ( ulSoftReadPnt != ulSoftWritePnt ) { ulNumEventsReturned = 0; while( (ulSoftReadPnt != ulSoftWritePnt) && ( ulNumEventsReturned != f_pEventGetTone->ulMaxToneEvent) ) { /* Get a pointer to the first event in the buffer. */ mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += ulSoftReadPnt; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulChannelHndl = pSoftEvent->ulChannelHandle; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulUserChanId = pSoftEvent->ulUserChanId; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulTimestamp = pSoftEvent->ulTimestamp; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulEventType = pSoftEvent->ulEventType; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulToneDetected = pSoftEvent->ulToneDetected; f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulExtToneDetectionPort = pSoftEvent->ulExtToneDetectionPort; /* Update the pointers of the soft buffer. */ ulSoftReadPnt++; if ( ulSoftReadPnt == ulSoftBufSize ) ulSoftReadPnt = 0; ulNumEventsReturned++; } pSharedInfo->SoftBufs.ulToneEventBufferReadPtr = ulSoftReadPnt; /* Detemine if there are more events pending in the soft buffer. */ if ( ulSoftReadPnt != ulSoftWritePnt ) f_pEventGetTone->fMoreEvents = TRUE; else /* ( ulSoftReadPnt == ulSoftWritePnt ) */ { f_pEventGetTone->fMoreEvents = FALSE; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fToneEventsPending = FALSE; } f_pEventGetTone->ulNumValidToneEvent = ulNumEventsReturned; } else { /* No valid tone.*/ f_pEventGetTone->ulNumValidToneEvent = 0; f_pEventGetTone->fMoreEvents = FALSE; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fToneEventsPending = FALSE; return cOCT6100_ERR_EVENTS_TONE_BUF_EMPTY; } } else /* ( f_pEventGetTone->fResetBufs == TRUE ) */ { /* Empty the hardware buffer. */ ulResult = Oct6100ApiTransferToneEvents( f_pApiInstance, f_pEventGetTone->fResetBufs ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* If the buffers are to be reset then update the pointers and full flag. */ pSharedInfo->SoftBufs.ulToneEventBufferReadPtr = 0; pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; f_pEventGetTone->fMoreEvents = FALSE; f_pEventGetTone->ulNumValidToneEvent = 0; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fToneEventsPending = FALSE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiTransferToneEvents Description: Transfers all tone events from the PGSP event out chip buffer to the soft buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulResetBuf Reset flag. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiTransferToneEvents UINT32 Oct6100ApiTransferToneEvents( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulResetBuf ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TONE_EVENT pSoftEvent; tPOCT6100_API_CHANNEL pEchoChannel; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; tOCT6100_READ_BURST_PARAMS BurstParams; UINT32 ulChipBufFill; UINT32 ulChipWritePtr = 0; UINT32 ulChipReadPtr = 0; UINT32 usChannelIndex; UINT32 ulBaseTimestamp; UINT32 ulToneCnt; UINT32 ulNumWordsToRead; UINT32 ulEventCode; UINT32 ulResult; UINT32 i, j; UINT16 usReadData; UINT16 ausReadData[ cOCT6100_NUM_WORDS_PER_TONE_EVENT ]; UINT32 ulExtToneDetectionPort; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* If the buffer is to be reset then clear the overflow flag. */ if ( f_ulResetBuf == TRUE ) { pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt = 0; } /* Set some parameters of read struct. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Get the current read pointer of the chip buffer. */ ReadParams.ulReadAddress = cOCT6100_TONE_EVENT_READ_PTR_REG; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulChipReadPtr = usReadData; /* Now get the current write pointer. */ ReadParams.ulReadAddress = cOCT6100_TONE_EVENT_WRITE_PTR_REG; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulChipWritePtr = usReadData; ulChipBufFill = (( ulChipWritePtr - ulChipReadPtr ) & ( cOCT6100_NUM_PGSP_EVENT_OUT - 1 )); /* Set some parameters of write structs. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Read in the tone event one at a time. */ for ( i = 0; i < ulChipBufFill; i++ ) { /* Skip the event processing if the buffer is to be reset. */ if ( f_ulResetBuf == TRUE ) { /* Update the control variables of the buffer. */ ulChipReadPtr++; if ( cOCT6100_NUM_PGSP_EVENT_OUT == ulChipReadPtr ) ulChipReadPtr = 0; } else { /* Read in the event only if there's enough room in the soft buffer, and */ /* the chip buffer is NOT to be reset. */ if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) { BurstParams.ulReadAddress = cOCT6100_PGSP_EVENT_OUT_BASE + ( ulChipReadPtr * cOCT6100_PGSP_TONE_EVENT_SIZE ); BurstParams.pusReadData = ausReadData; ulNumWordsToRead = cOCT6100_PGSP_TONE_EVENT_SIZE / 2; while ( ulNumWordsToRead > 0 ) { if ( ulNumWordsToRead > pSharedInfo->ChipConfig.usMaxRwAccesses ) { BurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; } else { BurstParams.ulReadLength = ulNumWordsToRead; } mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BurstParams.pusReadData += BurstParams.ulReadLength; BurstParams.ulReadAddress += BurstParams.ulReadLength * 2; ulNumWordsToRead -= BurstParams.ulReadLength; } /* Verify if the event is valid. */ if ( ( ausReadData[ 0 ] & cOCT6100_VALID_TONE_EVENT ) == 0x0 ) return cOCT6100_ERR_FATAL_2D; /* First extract the channel number of the tone event. */ usChannelIndex = ausReadData[ 1 ] & 0x3FF; /* Now the timestamp. */ ulBaseTimestamp = ausReadData[ 2 ] << 16; ulBaseTimestamp |= ausReadData[ 3 ]; /* This timestamp is 256 in adwance, must remove 256 frames. */ ulBaseTimestamp -= 256; /* Fetch the channel stucture to validate which event can be reported. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, usChannelIndex ); if ( pEchoChannel->fReserved != TRUE ) { /* Update the control variables of the buffer. */ ulChipReadPtr++; if ( ulChipReadPtr == cOCT6100_NUM_PGSP_EVENT_OUT ) ulChipReadPtr = 0; /* This channel has been closed since the generation of the event. */ continue; } /* Extract the extended tone detection port if available. */ if ( pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_SIN_PORT_MODE ) { ulExtToneDetectionPort = cOCT6100_CHANNEL_PORT_SIN; } else if ( pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_RIN_PORT_MODE ) { ulExtToneDetectionPort = cOCT6100_CHANNEL_PORT_RIN; /* Modify the channel index. */ usChannelIndex = pEchoChannel->usExtToneChanIndex; /* Change the channel entry to the original one for statistical purposes. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, usChannelIndex ); } else /* pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_DISABLED */ { ulExtToneDetectionPort = cOCT6100_INVALID_VALUE; } ulToneCnt = 0; /* Verify all the possible events that might have been detected. */ for ( j = 4; j < cOCT6100_NUM_WORDS_PER_TONE_EVENT; j++ ) { ulEventCode = ( ausReadData[ j ] >> 8 ) & 0x7; if ( ulEventCode != 0x0 ) { /* This tone generated an event, now check if event is masked for the channel. */ if ((( pEchoChannel->aulToneConf[ ulToneCnt / 32 ] >> ( 31 - ( ulToneCnt % 32 ))) & 0x1) == 1 ) { BOOL f2100Tone; /* Check if it is a 2100 Tone STOP and if the user wants receive those events*/ ulResult = Oct6100ApiIs2100Tone(f_pApiInstance, pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, &f2100Tone); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (f2100Tone == FALSE) || ( (f2100Tone == TRUE) && (ulEventCode != 2) ) || ( (f2100Tone == TRUE) && pSharedInfo->ChipConfig.fEnable2100StopEvent == TRUE ) ) { /* If enough space. */ if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) { /* The tone event is not masked, The API can create a soft tone event. */ mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; /* Decode the event type. */ switch( ulEventCode ) { case 1: pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; break; case 2: pSoftEvent->ulEventType = cOCT6100_TONE_STOP; break; case 3: /* This one is a little tricky. We first */ /* generate the "PRESENT" event and then generate the "STOP" event. */ pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; /* We want the timestamp not to be equal to the "STOP" event, so we subtract one to the detector's value. */ pSoftEvent->ulTimestamp = ( ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ) ) - 1; pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; /* If enough space for the "STOP" event. */ if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) { mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; pSoftEvent->ulEventType = cOCT6100_TONE_STOP; } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; /* We continue in the loop in order to empty the hardware buffer. */ continue; } break; case 4: pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; break; default: pSharedInfo->ErrorStats.ulToneDetectorErrorCnt++; /* do not process this packet*/ continue; } pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; pSoftEvent->ulTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; /* Set the interrupt manager such that the user knows that some tone events */ /* are pending in the software Q. */ pSharedInfo->IntrptManage.fToneEventsPending = TRUE; } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; /* We continue in the loop in order to empty the hardware buffer. */ } } } else { BOOL fSSTone; ulResult = Oct6100ApiIsSSTone( f_pApiInstance, pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, &fSSTone ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( fSSTone == TRUE ) { /* Check if this is a "PRESENT" or "STOP" event */ switch( ulEventCode ) { case 1: /* This is a signaling system present event. Keep this in the instance memory. */ pEchoChannel->ulLastSSToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; pEchoChannel->ulLastSSToneTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); break; case 2: /* This is the "STOP" event, invalidate the last value. The user does not want to know about this. */ pEchoChannel->ulLastSSToneDetected = (PTR_TYPE)cOCT6100_INVALID_VALUE; pEchoChannel->ulLastSSToneTimestamp = (PTR_TYPE)cOCT6100_INVALID_VALUE; break; default: break; } } } } ulToneCnt++; /* Check the other tone of this word. */ ulEventCode = ausReadData[ j ] & 0x7; if ( ulEventCode != 0x0 ) { if ((( pEchoChannel->aulToneConf[ ulToneCnt / 32 ] >> ( 31 - ( ulToneCnt % 32 ))) & 0x1) == 1 ) { BOOL f2100Tone; /* Check if it is a 2100 Tone STOP and if the user wants receive those events*/ ulResult = Oct6100ApiIs2100Tone(f_pApiInstance, pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, &f2100Tone); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (f2100Tone == FALSE) || ( (f2100Tone == TRUE) && (ulEventCode != 2) ) || ( (f2100Tone == TRUE) && pSharedInfo->ChipConfig.fEnable2100StopEvent == TRUE ) ) { /* If enough space. */ if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) { /* The tone event is not masked, The API can create a soft tone event. */ mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; /* Decode the event type. */ switch( ulEventCode ) { case 1: pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; break; case 2: pSoftEvent->ulEventType = cOCT6100_TONE_STOP; break; case 3: /* This one is a little tricky. We first */ /* generate the "PRESENT" event and then generate the "STOP" event. */ pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; /* We want the timestamp not to be equal to the "STOP" event, so we subtract one to the detector's value. */ pSoftEvent->ulTimestamp = ( ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ) ) - 1; pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; /* If enough space for the "STOP" event. */ if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) { mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; pSoftEvent->ulEventType = cOCT6100_TONE_STOP; } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; /* We continue in the loop in order to empty the hardware buffer. */ continue; } break; case 4: pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; break; default: pSharedInfo->ErrorStats.ulToneDetectorErrorCnt++; /* Do not process this packet. */ continue; } pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; pSoftEvent->ulTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; /* Set the interrupt manager such that the user knows that some tone events */ /* are pending in the software Q. */ pSharedInfo->IntrptManage.fToneEventsPending = TRUE; } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; /* We continue in the loop in order to empty the hardware buffer. */ } } } else { BOOL fSSTone; ulResult = Oct6100ApiIsSSTone( f_pApiInstance, pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, &fSSTone ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( fSSTone == TRUE ) { /* Check if this is a "PRESENT" event. */ switch ( ulEventCode ) { case 1: /* This is a signaling system present event. Keep this in the instance memory. */ pEchoChannel->ulLastSSToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; pEchoChannel->ulLastSSToneTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); break; case 2: /* This is the "STOP" event, invalidate the last value. The user does not want to know about this. */ pEchoChannel->ulLastSSToneDetected = (PTR_TYPE)cOCT6100_INVALID_VALUE; pEchoChannel->ulLastSSToneTimestamp = (PTR_TYPE)cOCT6100_INVALID_VALUE; break; default: break; } } } } ulToneCnt++; } } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; /* We continue in the loop in order to empty the hardware buffer. */ } /* Update the control variables of the buffer. */ ulChipReadPtr++; if ( ulChipReadPtr == cOCT6100_NUM_PGSP_EVENT_OUT ) ulChipReadPtr = 0; } } /* Write the value of the new Read pointer.*/ WriteParams.ulWriteAddress = cOCT6100_TONE_EVENT_READ_PTR_REG; WriteParams.usWriteData = (UINT16)( ulChipReadPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutGetEventSer Description: Retreives an array of buffer playout event from the software event buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pEventGetPlayoutStop Pointer to structure which will contain the retreived events. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutGetEventSer UINT32 Oct6100BufferPlayoutGetEventSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_EVENT pSoftEvent; UINT32 ulSoftReadPnt; UINT32 ulSoftWritePnt; UINT32 ulSoftBufSize; UINT32 ulNumEventsReturned; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the parameters past by the user. */ if ( f_pBufPlayoutGetEvent->fResetBufs != TRUE && f_pBufPlayoutGetEvent->fResetBufs != FALSE ) return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_RESET; /* Check if software buffer has been allocated and thus enabled. */ if ( pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize == 0 ) return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_DISABLED; /* Checking max playout events. */ if ( f_pBufPlayoutGetEvent->ulMaxEvent > pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize ) return cOCT6100_ERR_BUFFER_PLAYOUT_MAX_EVENT; if ( f_pBufPlayoutGetEvent->fResetBufs == FALSE ) { /* Check if events need to be fetched from the chip. */ ulSoftReadPnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr; ulSoftWritePnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; if ( ulSoftReadPnt == ulSoftWritePnt ) { ulResult = Oct6100BufferPlayoutTransferEvents( f_pApiInstance, f_pBufPlayoutGetEvent->fResetBufs ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If there are no events in the soft buffer then there are none in the chip */ /* either, so return the empty case. Else, return the events in the buffer. */ ulSoftReadPnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr; ulSoftWritePnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; ulSoftBufSize = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize; if ( ulSoftReadPnt != ulSoftWritePnt ) { ulNumEventsReturned = 0; while( (ulSoftReadPnt != ulSoftWritePnt) && ( ulNumEventsReturned != f_pBufPlayoutGetEvent->ulMaxEvent) ) { /* Get a pointer to the first event in the buffer. */ mOCT6100_GET_BUFFER_PLAYOUT_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += ulSoftReadPnt; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulChannelHndl = pSoftEvent->ulChannelHandle; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulUserChanId = pSoftEvent->ulUserChanId; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulChannelPort = pSoftEvent->ulChannelPort; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulUserEventId = pSoftEvent->ulUserEventId; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulEventType = pSoftEvent->ulEventType; f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulTimestamp = pSoftEvent->ulTimestamp; /* Update the pointers of the soft buffer. */ ulSoftReadPnt++; if ( ulSoftReadPnt == ulSoftBufSize ) ulSoftReadPnt = 0; ulNumEventsReturned++; } pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr = ulSoftReadPnt; /* Detemine if there are more events pending in the soft buffer. */ if ( ulSoftReadPnt != ulSoftWritePnt ) f_pBufPlayoutGetEvent->fMoreEvents = TRUE; else /* ( ulSoftReadPnt == ulSoftWritePnt ) */ { f_pBufPlayoutGetEvent->fMoreEvents = FALSE; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; } f_pBufPlayoutGetEvent->ulNumValidEvent = ulNumEventsReturned; } else /* if ( ulSoftReadPnt == ulSoftWritePnt ) */ { /* No valid buffer playout events. */ f_pBufPlayoutGetEvent->ulNumValidEvent = 0; f_pBufPlayoutGetEvent->fMoreEvents = FALSE; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_BUF_EMPTY; } } else /* ( f_pEventGetPlayoutStop->fResetBufs == TRUE ) */ { /* Check with the hardware first. */ ulResult = Oct6100BufferPlayoutTransferEvents( f_pApiInstance, f_pBufPlayoutGetEvent->fResetBufs ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* If the buffers are to be reset, then update the pointers and full flag. */ pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr = 0; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr = 0; f_pBufPlayoutGetEvent->fMoreEvents = FALSE; f_pBufPlayoutGetEvent->ulNumValidEvent = 0; /* Remember this state in the interrupt manager. */ pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutTransferEvents Description: Check all channels that are currently playing a buffer and generate an event if a buffer has stopped playing. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulResetBuf Reset flag. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutTransferEvents UINT32 Oct6100BufferPlayoutTransferEvents( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulResetBuf ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulChannelIndex; UINT32 ulResult; UINT32 ulLastBufPlayoutEventBufferOverflowCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* If the buffer is to be reset then clear the overflow flag. */ if ( f_ulResetBuf == TRUE ) { pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt = 0; /* We are done for now. */ /* No need to check for new events since the user requested to empty the soft buffer. */ return cOCT6100_ERR_OK; } /* Check if buffer playout has been activated on some ports. */ if ( pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts == 0 ) { /* Buffer playout has not been activated on any channel, */ /* let's not waste time here. */ return cOCT6100_ERR_OK; } /* Save the current overflow count. We want to know if an overflow occured to get out of the loop. */ ulLastBufPlayoutEventBufferOverflowCnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt; /* Search through the list of API channel entry for the ones that need playout event checking. */ for ( ulChannelIndex = 0; ulChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; ulChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, ulChannelIndex ); /* Check if buffer playout is active on this channel, using the optimization flag. */ /* This flag is redundant of other flags used for playout, but will make the above loop */ /* much faster. This is needed since this function is called very frequently on systems */ /* which use buffer playout stop events. */ if ( pEchoChannel->fBufPlayoutActive == TRUE ) { /* Read in the event only if there's enough room in the soft buffer. */ if ( ulLastBufPlayoutEventBufferOverflowCnt == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) { /* Check Rout buffer playout first. */ if ( ( pEchoChannel->fRinBufPlayoutNotifyOnStop == TRUE ) && ( pEchoChannel->fRinBufPlaying == TRUE ) ) { ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, ulChannelIndex, cOCT6100_CHANNEL_PORT_ROUT, TRUE, NULL ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( ulLastBufPlayoutEventBufferOverflowCnt != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) */ { /* Get out of the loop, no more events can be inserted in the soft buffer. */ break; } /* An overflow might have been detected in the lower level function. */ /* Check the overflow count once again to make sure there might be room for a next event. */ if ( ulLastBufPlayoutEventBufferOverflowCnt == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) { /* Check Sout buffer playout. */ if ( ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == TRUE ) && ( pEchoChannel->fSoutBufPlaying == TRUE ) ) { ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, ulChannelIndex, cOCT6100_CHANNEL_PORT_SOUT, TRUE, NULL ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( ulLastBufPlayoutEventBufferOverflowCnt != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) */ { /* Get out of the loop, no more events can be inserted in the soft buffer. */ break; } } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100BufferPlayoutCheckForSpecificEvent Description: Check a specific channel/port for playout buffer events. If asked to, save this event to the software event buffer. Return a flag specifying whether the event was detected or not. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulChannelIndex Index of the channel to be checked. f_ulChannelPort Port of the channel to be checked. f_fSaveToSoftBuffer Save event to software buffer. f_pfEventDetected Whether or not an event was detected. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100BufferPlayoutCheckForSpecificEvent UINT32 Oct6100BufferPlayoutCheckForSpecificEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulChannelPort, IN BOOL f_fSaveToSoftBuffer, OUT PBOOL f_pfEventDetected ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_EVENT pSoftEvent; tPOCT6100_API_CHANNEL pEchoChannel; tOCT6100_READ_PARAMS ReadParams; tOCT6100_GET_TIME GetTimeParms; UINT32 ulResult; UINT16 usReadData; UINT32 ulReadPtrBytesOfst; UINT32 ulReadPtrBitOfst; UINT32 ulReadPtrFieldSize; UINT32 ulWritePtrBytesOfst; UINT32 ulWritePtrBitOfst; UINT32 ulWritePtrFieldSize; UINT32 ulPlayoutBaseAddress; UINT32 ulTempData; UINT32 ulReadPtr; UINT32 ulMask; UINT32 ulWritePtr; UINT32 ulUserEventId; UINT32 ulEventType; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Compare the read and write pointers for matching. If they matched, playout stopped. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex ); /* Set the playout feature base address. */ ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Check on the Rout port. */ ulUserEventId = pEchoChannel->ulRinUserBufPlayoutEventId; ulEventType = pEchoChannel->byRinPlayoutStopEventType; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize; } else /* if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_SOUT ) */ { /* Check on the Sout port. */ ulUserEventId = pEchoChannel->ulSoutUserBufPlayoutEventId; ulEventType = pEchoChannel->bySoutPlayoutStopEventType; ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4; ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset; ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize; ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4; ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset; ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize; } /* Retrieve the current write pointer. */ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChannel, ulPlayoutBaseAddress + ulWritePtrBytesOfst, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); /* Store the write pointer.*/ ulWritePtr = ( ulTempData & ulMask ) >> ulWritePtrBitOfst; /* Read the read pointer.*/ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; /* Optimize this access by only reading the word we are interested in. */ if ( ulReadPtrBitOfst < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulReadPtrBitOfst < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); /* Store the read pointer. */ ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; /* Playout has finished when the read pointer reaches the write pointer. */ if ( ulReadPtr != ulWritePtr ) { /* Still playing -- do not generate an event. */ if ( f_pfEventDetected != NULL ) *f_pfEventDetected = FALSE; } else { /* Buffer stopped playing, generate an event here, if asked. */ if ( ( f_fSaveToSoftBuffer == TRUE ) && ( ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr ) && ( ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize || pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr != 0 ) ) { /* The API can create a soft buffer playout event. */ mOCT6100_GET_BUFFER_PLAYOUT_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_ulChannelIndex; pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; pSoftEvent->ulUserEventId = ulUserEventId; pSoftEvent->ulChannelPort = f_ulChannelPort; /* For now, only this type of event is available. */ pSoftEvent->ulEventType = ulEventType; /* Generate millisecond timestamp. */ GetTimeParms.pProcessContext = f_pApiInstance->pProcessContext; ulResult = Oct6100UserGetTime( &GetTimeParms ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pSoftEvent->ulTimestamp = ( GetTimeParms.aulWallTimeUs[ 0 ] / 1000 ); pSoftEvent->ulTimestamp += ( GetTimeParms.aulWallTimeUs[ 1 ] ) * ( 0xFFFFFFFF / 1000 ); /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize ) pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr = 0; /* Set the interrupt manager such that the user knows that some playout events */ /* are pending in the software Q. */ pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = TRUE; } else if ( f_fSaveToSoftBuffer == TRUE ) { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt++; } /* Update the channel entry to set the playing flag to FALSE. */ /* Select the port of interest. */ if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Decrement the number of active buffer playout ports. */ /* No need to check anything here, it's been done in the calling function. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; pEchoChannel->fRinBufPlaying = FALSE; pEchoChannel->fRinBufPlayoutNotifyOnStop = FALSE; /* Clear optimization flag if possible. */ if ( ( pEchoChannel->fSoutBufPlaying == FALSE ) && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == FALSE ) ) { /* Buffer playout is no more active on this channel. */ pEchoChannel->fBufPlayoutActive = FALSE; } } else /* f_ulChannelPort == cOCT6100_CHANNEL_PORT_SOUT */ { /* Decrement the number of active buffer playout ports. */ /* No need to check anything here, it's been done in the calling function. */ pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; pEchoChannel->fSoutBufPlaying = FALSE; pEchoChannel->fSoutBufPlayoutNotifyOnStop = FALSE; /* Clear optimization flag if possible. */ if ( ( pEchoChannel->fRinBufPlaying == FALSE ) && ( pEchoChannel->fRinBufPlayoutNotifyOnStop == FALSE ) ) { /* Buffer playout is no more active on this channel. */ pEchoChannel->fBufPlayoutActive = FALSE; } } /* Return that an event was detected. */ if ( f_pfEventDetected != NULL ) *f_pfEventDetected = TRUE; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_phasing_tsst.c0000644000175000017500000007647011525010337032157 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_phasing_tsst.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to open and close phasing TSSTs. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 46 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_phasing_tsst_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_phasing_tsst_pub.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_phasing_tsst_priv.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100PhasingTsstOpen Description: This function opens a phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST open structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100PhasingTsstOpenDef UINT32 Oct6100PhasingTsstOpenDef( tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ) { f_pPhasingTsstOpen->pulPhasingTsstHndl = NULL; f_pPhasingTsstOpen->ulTimeslot = cOCT6100_INVALID_TIMESLOT; f_pPhasingTsstOpen->ulStream = cOCT6100_INVALID_STREAM; f_pPhasingTsstOpen->ulPhasingLength = 88; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100PhasingTsstOpen UINT32 Oct6100PhasingTsstOpen( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100PhasingTsstOpenSer( f_pApiInstance, f_pPhasingTsstOpen ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100PhasingTsstClose Description: This function closes a phasing TSST ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstClose Pointer to phasing TSST close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100PhasingTsstCloseDef UINT32 Oct6100PhasingTsstCloseDef( tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ) { f_pPhasingTsstClose->ulPhasingTsstHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100PhasingTsstClose UINT32 Oct6100PhasingTsstClose( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100PhasingTsstCloseSer( f_pApiInstance, f_pPhasingTsstClose ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetPhasingTsstSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of Phasing TSSTs. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetPhasingTsstSwSizes UINT32 Oct6100ApiGetPhasingTsstSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Determine the amount of memory required for the API phasing TSST list. */ f_pInstSizes->ulPhasingTsstList = f_pOpenChip->ulMaxPhasingTssts * sizeof( tOCT6100_API_PHASING_TSST ); if ( f_pOpenChip->ulMaxPhasingTssts > 0 ) { /* Calculate memory needed for Phasing TSST API memory allocation */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxPhasingTssts, &f_pInstSizes->ulPhasingTsstAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_38; } else { f_pInstSizes->ulPhasingTsstAlloc = 0; } mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulPhasingTsstList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulPhasingTsstAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiPhasingTsstSwInit Description: Initializes all elements of the instance structure associated to phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiPhasingTsstSwInit UINT32 Oct6100ApiPhasingTsstSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_PHASING_TSST pPhasingTsstList; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulMaxPhasingTssts; PVOID pPhasingTsstAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize the phasing TSST API list. */ ulMaxPhasingTssts = pSharedInfo->ChipConfig.usMaxPhasingTssts; /* Set all entries in the phasing TSST list to unused. */ mOCT6100_GET_PHASING_TSST_LIST_PNT( pSharedInfo, pPhasingTsstList ) /* Clear the memory */ Oct6100UserMemSet( pPhasingTsstList, 0x00, sizeof(tOCT6100_API_PHASING_TSST) * ulMaxPhasingTssts ); /* Initialize the phasing TSST allocation software to "all free". */ if ( ulMaxPhasingTssts > 0 ) { mOCT6100_GET_PHASING_TSST_ALLOC_PNT( pSharedInfo, pPhasingTsstAlloc ) ulResult = OctapiLlmAllocInit( &pPhasingTsstAlloc, ulMaxPhasingTssts ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_39; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100PhasingTsstOpenSer Description: Opens a phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST open configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100PhasingTsstOpenSer UINT32 Oct6100PhasingTsstOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ) { UINT16 usPhasingIndex; UINT16 usTsstIndex; UINT32 ulResult; /* Check the user's configuration of the phasing TSST for errors. */ ulResult = Oct6100ApiCheckPhasingParams( f_pApiInstance, f_pPhasingTsstOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the phasing TSST. */ ulResult = Oct6100ApiReservePhasingResources( f_pApiInstance, f_pPhasingTsstOpen, &usPhasingIndex, &usTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write all necessary structures to activate the phasing TSST. */ ulResult = Oct6100ApiWritePhasingStructs( f_pApiInstance, f_pPhasingTsstOpen, usPhasingIndex, usTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new phasing TSST entry in the API list. */ ulResult = Oct6100ApiUpdatePhasingEntry( f_pApiInstance, f_pPhasingTsstOpen, usPhasingIndex, usTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckPhasingParams Description: Checks the user's phasing TSST open configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST open configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckPhasingParams UINT32 Oct6100ApiCheckPhasingParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen ) { UINT32 ulResult; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxPhasingTssts == 0 ) return cOCT6100_ERR_PHASING_TSST_DISABLED; if ( f_pPhasingTsstOpen->pulPhasingTsstHndl == NULL ) return cOCT6100_ERR_PHASING_TSST_INVALID_HANDLE; /* Check the phasing length. */ if ( f_pPhasingTsstOpen->ulPhasingLength > 240 || f_pPhasingTsstOpen->ulPhasingLength < 2 ) return cOCT6100_ERR_PHASING_TSST_PHASING_LENGTH; /* Check the input TDM streams, timeslots component for errors. */ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, cOCT6100_NUMBER_TSSTS_1, f_pPhasingTsstOpen->ulTimeslot, f_pPhasingTsstOpen->ulStream, cOCT6100_INPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_PHASING_TSST_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_PHASING_TSST_STREAM; } else { return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReservePhasingResources Description: Reserves all resources needed for the new phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST configuration structure. f_pusPhasingIndex Allocated entry in Phasing TSST API list. f_pusTsstIndex TSST memory index of the counter. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReservePhasingResources UINT32 Oct6100ApiReservePhasingResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, OUT PUINT16 f_pusPhasingIndex, OUT PUINT16 f_pusTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; UINT32 ulTempVar; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Reserve an entry in the phasing TSST list. */ ulResult = Oct6100ApiReservePhasingEntry( f_pApiInstance, f_pusPhasingIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* Reserve the input TSST entry. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pPhasingTsstOpen->ulTimeslot, f_pPhasingTsstOpen->ulStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_INPUT_TSST, f_pusTsstIndex, NULL ); if ( ulResult != cOCT6100_ERR_OK ) { /* Release the previously reserved entries. */ ulTempVar = Oct6100ApiReleasePhasingEntry( f_pApiInstance, *f_pusPhasingIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; return ulResult; } } else { return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWritePhasingStructs Description: Performs all the required structure writes to configure the new phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST configuration structure. f_usPhasingIndex Allocated entry in phasing TSST API list. f_usTsstIndex TSST memory index of the counter. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWritePhasingStructs UINT32 Oct6100ApiWritePhasingStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, IN UINT16 f_usPhasingIndex, IN UINT16 f_usTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulPhasingTsstChariotMemIndex; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*------------------------------------------------------------------------------*/ /* Configure the TSST control memory of the phasing TSST. */ /* Find the asociated entry in the chariot memory for the phasing TSST. */ ulPhasingTsstChariotMemIndex = cOCT6100_TSST_CONTROL_PHASING_TSST_BASE_ENTRY + f_usPhasingIndex; WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_TSST_CONTROL_MEM_INPUT_TSST; WriteParams.usWriteData |= ulPhasingTsstChariotMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Write the phasing length of the TSST in the ADPCM / MIXER memory. */ WriteParams.ulWriteAddress = cOCT6100_CONVERSION_CONTROL_PHASE_SIZE_BASE_ADD + ( f_usPhasingIndex * 2 ); WriteParams.usWriteData = (UINT16)( f_pPhasingTsstOpen->ulPhasingLength ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdatePhasingEntry Description: Updates the new phasing TSST in the API phasing TSST list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstOpen Pointer to phasing TSST open structure. f_usPhasingIndex Allocated entry in phasing TSST API list. f_usTsstIndex TSST memory index of the counter. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdatePhasingEntry UINT32 Oct6100ApiUpdatePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_OPEN f_pPhasingTsstOpen, IN UINT16 f_usPhasingIndex, IN UINT16 f_usTsstIndex ) { tPOCT6100_API_PHASING_TSST pPhasingTsstEntry; /*================================================================================*/ /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingTsstEntry, f_usPhasingIndex ) /* Copy the phasing TSST's configuration and allocated resources. */ pPhasingTsstEntry->usTimeslot = (UINT16)( f_pPhasingTsstOpen->ulTimeslot & 0xFFFF ); pPhasingTsstEntry->usStream = (UINT16)( f_pPhasingTsstOpen->ulStream & 0xFFFF ); pPhasingTsstEntry->usPhasingLength = (UINT16)( f_pPhasingTsstOpen->ulPhasingLength & 0xFFFF ); /* Store hardware related information. */ pPhasingTsstEntry->usPhasingTsstIndex = f_usTsstIndex; /* Form handle returned to user. */ *f_pPhasingTsstOpen->pulPhasingTsstHndl = cOCT6100_HNDL_TAG_PHASING_TSST | (pPhasingTsstEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usPhasingIndex; pPhasingTsstEntry->usDependencyCnt = 0; /* Nobody is using the phasing TSST.*/ /* Finally, mark the phasing TSST as open. */ pPhasingTsstEntry->fReserved = TRUE; /* Increment the number of phasing TSSTs opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberPhasingTssts++; /*================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100PhasingTsstCloseSer Description: Closes a phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstClose Pointer to phasing TSST close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100PhasingTsstCloseSer UINT32 Oct6100PhasingTsstCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose ) { UINT16 usPhasingIndex; UINT16 usTsstIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertPhasingParams( f_pApiInstance, f_pPhasingTsstClose, &usPhasingIndex, &usTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the phasing TSST. */ ulResult = Oct6100ApiInvalidatePhasingStructs( f_pApiInstance, usTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the phasing TSST. */ ulResult = Oct6100ApiReleasePhasingResources( f_pApiInstance, usPhasingIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pPhasingTsstClose->ulPhasingTsstHndl = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertPhasingParams Description: Validate the handle given by the user and verify the state of the phasing TSST about to be closed. Also returns all required information to deactivate the phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pPhasingTsstClose Pointer to phasing TSST close structure. f_pusPhasingIndex Index of the phasing TSST structure in the API list. f_pusTsstIndex Index of the entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertPhasingParams UINT32 Oct6100ApiAssertPhasingParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_PHASING_TSST_CLOSE f_pPhasingTsstClose, OUT PUINT16 f_pusPhasingIndex, OUT PUINT16 f_pusTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_PHASING_TSST pPhasingEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pPhasingTsstClose->ulPhasingTsstHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_PHASING_TSST ) return cOCT6100_ERR_PHASING_TSST_INVALID_HANDLE; *f_pusPhasingIndex = (UINT16)( f_pPhasingTsstClose->ulPhasingTsstHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusPhasingIndex >= pSharedInfo->ChipConfig.usMaxPhasingTssts ) return cOCT6100_ERR_PHASING_TSST_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the phasing TSST's list entry. */ mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pPhasingEntry, *f_pusPhasingIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pPhasingTsstClose->ulPhasingTsstHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pPhasingEntry->fReserved != TRUE ) return cOCT6100_ERR_PHASING_TSST_NOT_OPEN; if ( pPhasingEntry->usDependencyCnt != 0 ) return cOCT6100_ERR_PHASING_TSST_ACTIVE_DEPENDENCIES; if ( ulEntryOpenCnt != pPhasingEntry->byEntryOpenCnt ) return cOCT6100_ERR_PHASING_TSST_INVALID_HANDLE; /* Return info needed to close the phasing TSST and release all resources. */ *f_pusTsstIndex = pPhasingEntry->usPhasingTsstIndex; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidatePhasingStructs Description: Closes a phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usTsstIndex Index of the entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidatePhasingStructs UINT32 Oct6100ApiInvalidatePhasingStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*------------------------------------------------------------------------------*/ /* Deactivate the TSST control memory. */ /* Set the input TSST control entry to unused. */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleasePhasingResources Description: Release and clear the API entry associated to the phasing TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usPhasingIndex Index of the phasing TSST in the API list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleasePhasingResources UINT32 Oct6100ApiReleasePhasingResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usPhasingIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_PHASING_TSST pPhasingEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pPhasingEntry, f_usPhasingIndex ); /* Release the entry in the phasing TSST list. */ ulResult = Oct6100ApiReleasePhasingEntry( f_pApiInstance, f_usPhasingIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* Release the entry. */ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pPhasingEntry->usTimeslot, pPhasingEntry->usStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); /* Release the TSST entry */ if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL; } } else { return ulResult; } /*=============================================================*/ /* Update the phasing TSST's list entry. */ /* Mark the entry as closed. */ pPhasingEntry->fReserved = FALSE; pPhasingEntry->byEntryOpenCnt++; /* Decrement the number of phasing TSSTs opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberPhasingTssts--; /*=============================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReservePhasingEntry Description: Reserves a phasing TSST API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusPhasingIndex Resulting index reserved in the phasing TSST list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReservePhasingEntry UINT32 Oct6100ApiReservePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusPhasingIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pPhasingAlloc; UINT32 ulResult; UINT32 ulPhasingIndex; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_PHASING_TSST_ALLOC_PNT( pSharedInfo, pPhasingAlloc ) ulResult = OctapiLlmAllocAlloc( pPhasingAlloc, &ulPhasingIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_PHASING_TSST_ALL_ENTRIES_ARE_OPENED; else return cOCT6100_ERR_FATAL_3A; } *f_pusPhasingIndex = (UINT16)( ulPhasingIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleasePhasingEntry Description: Releases the specified phasing TSST API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usPhasingIndex Index reserved in the phasing TSST API list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleasePhasingEntry UINT32 Oct6100ApiReleasePhasingEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usPhasingIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pPhasingAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_PHASING_TSST_ALLOC_PNT( pSharedInfo, pPhasingAlloc ) ulResult = OctapiLlmAllocDealloc( pPhasingAlloc, f_usPhasingIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_3B; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_user.c0000644000175000017500000003710311431317470030421 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_user.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions provided by the user. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 28 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_errors.h" /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserGetTime Description: Returns the system time in us. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pTime Pointer to structure in which the time is returned. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserGetTime UINT32 Oct6100UserGetTime( IN OUT tPOCT6100_GET_TIME f_pTime ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserMemSet Description: Sets f_ulLength bytes pointed to by f_pAddress to f_ulPattern. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pAddress Address in host memory where data should be set. f_ulPattern Pattern to apply at the address. This value will never exceed 0xFF. f_ulLength Length in bytes to set. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserMemSet UINT32 Oct6100UserMemSet( IN PVOID f_pAddress, IN UINT32 f_ulPattern, IN UINT32 f_ulLength ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserMemCopy Description: Copy f_ulLength bytes from f_pSource to f_pDestination. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pDestination Host data destination address. f_pSource Host data source address. f_ulLength Length in bytes to copy. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserMemCopy UINT32 Oct6100UserMemCopy( IN PVOID f_pDestination, IN const void *f_pSource, IN UINT32 f_ulLength ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserCreateSerializeObject Description: Creates a serialization object. The serialization object is seized via the Oct6100UserSeizeSerializeObject function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pCreate Pointer to structure in which the serialization object's handle is returned. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserCreateSerializeObject UINT32 Oct6100UserCreateSerializeObject( IN OUT tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDestroySerializeObject Description: Destroys the indicated serialization object. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pDestroy Pointer to structure containing the handle of the serialization object. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDestroySerializeObject UINT32 Oct6100UserDestroySerializeObject( IN tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserSeizeSerializeObject Description: Seizes the indicated serialization object. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pSeize Pointer to structure containing the handle of the serialization object. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserSeizeSerializeObject UINT32 Oct6100UserSeizeSerializeObject( IN tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserReleaseSerializeObject Description: Releases the indicated serialization object. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pRelease Pointer to structure containing the handle of the serialization object. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserReleaseSerializeObject UINT32 Oct6100UserReleaseSerializeObject( IN tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteApi Description: Performs a write access to the chip. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pWriteParams Pointer to structure containing the Params to the write function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteApi UINT32 Oct6100UserDriverWriteApi( IN tPOCT6100_WRITE_PARAMS f_pWriteParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteOs Description: Performs a write access to the chip. This function is accessible only from the APIMI code entity (i.e. not from the API code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pWriteParams Pointer to structure containing the Params to the write function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteOs UINT32 Oct6100UserDriverWriteOs( IN tPOCT6100_WRITE_PARAMS f_pWriteParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteSmearApi Description: Performs a series of write accesses to the chip. The same data word is written to a series of addresses. The writes begin at the start address, and the address is incremented by the indicated amount for each subsequent write. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pSmearParams Pointer to structure containing the parameters to the write smear function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteSmearApi UINT32 Oct6100UserDriverWriteSmearApi( IN tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteSmearOs Description: Performs a series of write accesses to the chip. The same data word is written to a series of addresses. The writes begin at the start address, and the address is incremented by the indicated amount for each subsequent write. This function is accessible only from the APIMI code entity (i.e. not from the API code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pSmearParams Pointer to structure containing the parameters to the write smear function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteSmearOs UINT32 Oct6100UserDriverWriteSmearOs( IN tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteBurstApi Description: Performs a series of write accesses to the chip. An array of data words is written to a series of consecutive addresses. The writes begin at the start address with element 0 of the provided array as the data word. The address is incremented by two for each subsequent write. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pBurstParams Pointer to structure containing the parameters to the write burst function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteBurstApi UINT32 Oct6100UserDriverWriteBurstApi( IN tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverWriteBurstOs Description: Performs a series of write accesses to the chip. An array of data words is written to a series of consecutive addresses. The writes begin at the start address with element 0 of the provided array as the data word. The address is incremented by two for each subsequent write. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pBurstParams Pointer to structure containing the parameters to the write burst function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverWriteBurstOs UINT32 Oct6100UserDriverWriteBurstOs( IN tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverReadApi Description: Performs a read access to the chip. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pReadParams Pointer to structure containing the parameters to the read function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverReadApi UINT32 Oct6100UserDriverReadApi( IN OUT tPOCT6100_READ_PARAMS f_pReadParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverReadOs Description: Performs a read access to the chip. This function is accessible only from the APIMI code entity (i.e. not from the API code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pReadParams Pointer to structure containing the parameters to the read function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverReadOs UINT32 Oct6100UserDriverReadOs( IN OUT tPOCT6100_READ_PARAMS f_pReadParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverReadBurstApi Description: Performs a burst of read accesses to the chip. The first read is performed at the start address, and the address is incremented by two for each subsequent read. The data is retunred in an array provided by the user. This function is accessible only from the API code entity (i.e. not from the APIMI code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pBurstParams Pointer to structure containing the parameters to the read burst function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverReadBurstApi UINT32 Oct6100UserDriverReadBurstApi( IN OUT tPOCT6100_READ_BURST_PARAMS f_pBurstParams ) { return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100UserDriverReadBurstOs Description: Performs a burst of read accesses to the chip. The first read is performed at the start address, and the address is incremented by two for each subsequent read. The data is retunred in an array provided by the user. This function is accessible only from the APIMI code entity (i.e. not from the API code entity). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pBurstParams Pointer to structure containing the parameters to the read burst function. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100UserDriverReadBurstOs UINT32 Oct6100UserDriverReadBurstOs( IN OUT tPOCT6100_READ_BURST_PARAMS f_pBurstParams ) { return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_mixer.c0000644000175000017500000015774111431317470030602 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_mixer.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions used to manage the allocation of mixer blocks in memories. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 42 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_mixer_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_mixer_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_mixer_priv.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100MixerCopyEventCreate Description: This function creates a mixer copy event used to copy information from one channel port to another channel port. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventCreate Pointer to a mixer copy event structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100MixerCopyEventCreateDef UINT32 Oct6100MixerCopyEventCreateDef( tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ) { f_pCopyEventCreate->pulCopyEventHndl = NULL; f_pCopyEventCreate->ulSourceChanHndl = cOCT6100_INVALID_HANDLE; f_pCopyEventCreate->ulSourcePort = cOCT6100_INVALID_PORT; f_pCopyEventCreate->ulDestinationChanHndl = cOCT6100_INVALID_HANDLE; f_pCopyEventCreate->ulDestinationPort = cOCT6100_INVALID_PORT; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100MixerCopyEventCreate UINT32 Oct6100MixerCopyEventCreate( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100MixerCopyEventCreateSer( f_pApiInstance, f_pCopyEventCreate ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100MixerCopyEventDestroy Description: This function destroys a mixer copy event used to copy information from one channel port to another. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventDestroy Pointer to a destroy copy event structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100MixerCopyEventDestroyDef UINT32 Oct6100MixerCopyEventDestroyDef( tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ) { f_pCopyEventDestroy->ulCopyEventHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100MixerCopyEventDestroy UINT32 Oct6100MixerCopyEventDestroy( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100MixerCopyEventDestroySer( f_pApiInstance, f_pCopyEventDestroy ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetMixerSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of mixer events. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip User chip configuration. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetMixerSwSizes UINT32 Oct6100ApiGetMixerSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Calculate the API memory required for the resource entry lists. */ f_pInstSizes->ulMixerEventList = cOCT6100_MAX_MIXER_EVENTS * sizeof( tOCT6100_API_MIXER_EVENT ); /* Calculate memory needed for mixers entry allocation. */ ulResult = OctapiLlmAllocGetSize( cOCT6100_MAX_MIXER_EVENTS, &f_pInstSizes->ulMixerEventAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1D; mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulMixerEventList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulMixerEventAlloc, ulTempVar ) f_pInstSizes->ulCopyEventList = cOCT6100_MAX_MIXER_EVENTS * sizeof( tOCT6100_API_COPY_EVENT ); ulResult = OctapiLlmAllocGetSize( cOCT6100_MAX_MIXER_EVENTS, &f_pInstSizes->ulCopyEventAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1D; mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulCopyEventList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulCopyEventAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMixerSwInit Description: Initializes all elements of the instance structure associated to the mixer events. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This mixer is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMixerSwInit UINT32 Oct6100ApiMixerSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_MIXER_EVENT pMixerEventList; PVOID pMixerEventAlloc; PVOID pCopyEventAlloc; UINT32 ulTempVar; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /*===================================================================*/ /* Initialize the mixer event list. */ mOCT6100_GET_MIXER_EVENT_LIST_PNT( pSharedInfo, pMixerEventList ); /* Initialize the mixer event allocation software to "all free". */ Oct6100UserMemSet( pMixerEventList, 0x00, cOCT6100_MAX_MIXER_EVENTS * sizeof( tOCT6100_API_MIXER_EVENT )); mOCT6100_GET_MIXER_EVENT_ALLOC_PNT( pSharedInfo, pMixerEventAlloc ) ulResult = OctapiLlmAllocInit( &pMixerEventAlloc, cOCT6100_MAX_MIXER_EVENTS ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1F; /* Now reserve the first entry as the first node. */ ulResult = OctapiLlmAllocAlloc( pMixerEventAlloc, &ulTempVar ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_20; } /* Check that we obtain the first event. */ if ( ulTempVar != 0 ) return cOCT6100_ERR_FATAL_21; /* Now reserve the tail entry. */ ulResult = OctapiLlmAllocAlloc( pMixerEventAlloc, &ulTempVar ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_AA; } /* Check that we obtain the first event. */ if ( ulTempVar != 1 ) return cOCT6100_ERR_FATAL_AB; /* Program the head node. */ pMixerEventList[ cOCT6100_MIXER_HEAD_NODE ].fReserved = TRUE; pMixerEventList[ cOCT6100_MIXER_HEAD_NODE ].usNextEventPtr = cOCT6100_MIXER_TAIL_NODE; pMixerEventList[ cOCT6100_MIXER_HEAD_NODE ].usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; /* Program the tail node. */ pMixerEventList[ cOCT6100_MIXER_TAIL_NODE ].fReserved = TRUE; pMixerEventList[ cOCT6100_MIXER_TAIL_NODE ].usNextEventPtr = cOCT6100_INVALID_INDEX; pMixerEventList[ cOCT6100_MIXER_TAIL_NODE ].usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; /* Now reserve the entry used for channel recording if the feature is enabled. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) { UINT32 ulAllocIndex; /* Reserve an entry to copy the desire SOUT signal to the SIN signal of the recording channel. */ ulResult = OctapiLlmAllocAlloc( pMixerEventAlloc, &ulAllocIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_90; } pSharedInfo->MixerInfo.usRecordCopyEventIndex = (UINT16)( ulAllocIndex & 0xFFFF ); /* Reserve an entry to copy the saved SIN signal of the debugged channel into it's original location. */ ulResult = OctapiLlmAllocAlloc( pMixerEventAlloc, &ulAllocIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_90; } pSharedInfo->MixerInfo.usRecordSinEventIndex = (UINT16)( ulAllocIndex & 0xFFFF ); /* Configure the SIN event. */ pMixerEventList[ pSharedInfo->MixerInfo.usRecordSinEventIndex ].fReserved = TRUE; pMixerEventList[ pSharedInfo->MixerInfo.usRecordSinEventIndex ].usNextEventPtr = cOCT6100_MIXER_TAIL_NODE; pMixerEventList[ pSharedInfo->MixerInfo.usRecordSinEventIndex ].usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; /* Configure the SOUT copy event. */ pMixerEventList[ pSharedInfo->MixerInfo.usRecordCopyEventIndex ].fReserved = TRUE; pMixerEventList[ pSharedInfo->MixerInfo.usRecordCopyEventIndex ].usNextEventPtr = pSharedInfo->MixerInfo.usRecordSinEventIndex; pMixerEventList[ pSharedInfo->MixerInfo.usRecordCopyEventIndex ].usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; /* Program the head node. */ pMixerEventList[ cOCT6100_MIXER_HEAD_NODE ].usNextEventPtr = pSharedInfo->MixerInfo.usRecordCopyEventIndex; } /* Initialize the copy event list. */ mOCT6100_GET_COPY_EVENT_ALLOC_PNT( pSharedInfo, pCopyEventAlloc ) ulResult = OctapiLlmAllocInit( &pCopyEventAlloc, cOCT6100_MAX_MIXER_EVENTS ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_B4; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMixerEventAdd Description: This function adds a mixer event event to the list of events based on the event type passed to the function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEventIndex Index of the event within the API's mixer event list. f_usEventType Type of mixer event. f_usDestinationChanIndex Index of the destination channel within the API's channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMixerEventAdd UINT32 Oct6100ApiMixerEventAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex, IN UINT16 f_usEventType, IN UINT16 f_usDestinationChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_MIXER_EVENT pCurrentEventEntry; tPOCT6100_API_MIXER_EVENT pTempEventEntry; tPOCT6100_API_CHANNEL pDestinationEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT16 usTempEventIndex; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get a pointer to the event entry. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCurrentEventEntry, f_usEventIndex ); /* Get a pointer to the destination channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pDestinationEntry, f_usDestinationChanIndex ); /* Now proceed according to the event type. */ switch ( f_usEventType ) { case cOCT6100_EVENT_TYPE_SOUT_COPY: /* Now insert the Sin copy event */ if ( pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { /* The only node in the list before the point where the node needs to */ /* be inserted is the head node. */ usTempEventIndex = cOCT6100_MIXER_HEAD_NODE; /* This node will be the first one in the Sout copy section. */ pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr = f_usEventIndex; pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = f_usEventIndex; } else /* pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr != cOCT6100_INVALID_INDEX */ { usTempEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = f_usEventIndex; } break; case cOCT6100_EVENT_TYPE_SIN_COPY: /* Now insert the Sin copy event. */ if ( pSharedInfo->MixerInfo.usFirstSinCopyEventPtr == cOCT6100_INVALID_INDEX ) { /* This is the first Sin copy event. We must find the event that comes before */ /* the event we want to add. First let's check for a bridge event. */ if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == cOCT6100_INVALID_INDEX ) { /* No event in the bridge section, now let's check in the Sout copy section. */ if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { /* The only node in the list then is the head node. */ usTempEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { usTempEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } else { usTempEventIndex = pSharedInfo->MixerInfo.usLastBridgeEventPtr; } /* This node will be the first one in the Sin copy section. */ pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = f_usEventIndex; pSharedInfo->MixerInfo.usLastSinCopyEventPtr = f_usEventIndex; } else /* pSharedInfo->MixerInfo.usFirstSinCopyEventPtr != cOCT6100_INVALID_INDEX */ { usTempEventIndex = pSharedInfo->MixerInfo.usLastSinCopyEventPtr; pSharedInfo->MixerInfo.usLastSinCopyEventPtr = f_usEventIndex; } break; default: return cOCT6100_ERR_FATAL_AF; } mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, usTempEventIndex ); /*=======================================================================*/ /* Program the Copy event. */ /* Set the Copy event first. */ pCurrentEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_COPY; pCurrentEventEntry->usNextEventPtr = pTempEventEntry->usNextEventPtr; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = pCurrentEventEntry->usNextEventPtr; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Modify the previous node. */ /* Set the last Sub-store entry. */ pTempEventEntry->usNextEventPtr = f_usEventIndex; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = f_usEventIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Save the destination channel index, needed when removing the event from the mixer. */ pCurrentEventEntry->usDestinationChanIndex = f_usDestinationChanIndex; /* Mark the entry as reserved. */ pCurrentEventEntry->fReserved = TRUE; /* Increment the event count on that particular destination channel */ pDestinationEntry->usMixerEventCnt++; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMixerEventRemove Description: This function removes a mixer event event from the list of events based on the event type passed to the function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEventIndex Index of event within the API's mixer event list. f_usEventType Type of mixer event. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMixerEventRemove UINT32 Oct6100ApiMixerEventRemove( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex, IN UINT16 f_usEventType ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_MIXER_EVENT pCurrentEventEntry; tPOCT6100_API_MIXER_EVENT pTempEventEntry; tPOCT6100_API_CHANNEL pDestinationEntry; tOCT6100_WRITE_BURST_PARAMS BurstWriteParams; tOCT6100_WRITE_PARAMS WriteParams; BOOL fFirstSinCopyEvent = FALSE; UINT32 ulResult; UINT16 usTempEventIndex; UINT32 ulLoopCount = 0; UINT16 ausWriteData[ 4 ] = { 0 }; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; BurstWriteParams.pProcessContext = f_pApiInstance->pProcessContext; BurstWriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; BurstWriteParams.pusWriteData = ausWriteData; BurstWriteParams.ulWriteLength = 4; /* Get a pointer to the event entry. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCurrentEventEntry, f_usEventIndex ); /* Get the pointer to the channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pDestinationEntry, pCurrentEventEntry->usDestinationChanIndex ); /* Now proceed according to the event type. */ switch ( f_usEventType ) { case cOCT6100_EVENT_TYPE_SOUT_COPY: if ( f_usEventIndex == pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr ) { usTempEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { /* Now insert the Sin copy event. */ usTempEventIndex = pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr; } /* Find the copy entry before the entry to remove. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, usTempEventIndex ); while( pTempEventEntry->usNextEventPtr != f_usEventIndex ) { usTempEventIndex = pTempEventEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_B2; } /*=======================================================================*/ /* Update the global mixer pointers. */ if ( f_usEventIndex == pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr ) { if ( f_usEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr ) { /* This event was the only of the list.*/ pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = cOCT6100_INVALID_INDEX; } else { pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr = pCurrentEventEntry->usNextEventPtr; } } else if ( f_usEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr ) { pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = usTempEventIndex; } /*=======================================================================*/ break; case cOCT6100_EVENT_TYPE_SIN_COPY: if ( f_usEventIndex == pSharedInfo->MixerInfo.usFirstSinCopyEventPtr ) { fFirstSinCopyEvent = TRUE; if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr != cOCT6100_INVALID_INDEX ) { usTempEventIndex = pSharedInfo->MixerInfo.usLastBridgeEventPtr; } else if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr != cOCT6100_INVALID_INDEX ) { usTempEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } else { usTempEventIndex = cOCT6100_MIXER_HEAD_NODE; } } else { /* Now insert the Sin copy event. */ usTempEventIndex = pSharedInfo->MixerInfo.usFirstSinCopyEventPtr; } /* Find the copy entry before the entry to remove. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, usTempEventIndex ); /* If we are not the first event of the Sin copy list. */ if ( fFirstSinCopyEvent == FALSE ) { while( pTempEventEntry->usNextEventPtr != f_usEventIndex ) { usTempEventIndex = pTempEventEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_B1; } } /*=======================================================================*/ /* Update the global mixer pointers. */ if ( f_usEventIndex == pSharedInfo->MixerInfo.usFirstSinCopyEventPtr ) { if ( f_usEventIndex == pSharedInfo->MixerInfo.usLastSinCopyEventPtr ) { /* This event was the only of the list. */ pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastSinCopyEventPtr = cOCT6100_INVALID_INDEX; } else { pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = pCurrentEventEntry->usNextEventPtr; } } else if ( f_usEventIndex == pSharedInfo->MixerInfo.usLastSinCopyEventPtr ) { pSharedInfo->MixerInfo.usLastSinCopyEventPtr = usTempEventIndex; } /*=======================================================================*/ break; default: return cOCT6100_ERR_FATAL_B0; } /*=======================================================================*/ /* Modify the previous event. */ pTempEventEntry->usNextEventPtr = pCurrentEventEntry->usNextEventPtr; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = pTempEventEntry->usNextEventPtr; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Clear the current event. */ BurstWriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_WRITE_BURST_API( BurstWriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Decrement the mixer event count active on that channel. */ pDestinationEntry->usMixerEventCnt--; /*=======================================================================*/ /*=======================================================================*/ /* This index of this channel is not valid anymore! */ pCurrentEventEntry->usDestinationChanIndex = cOCT6100_INVALID_INDEX; /* Mark this entry as free. */ pCurrentEventEntry->fReserved = FALSE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100MixerCopyEventCreateSer ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventCreate Pointer to a create copy event structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100MixerCopyEventCreateSer UINT32 Oct6100MixerCopyEventCreateSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate ) { UINT16 usCopyEventIndex = 0; UINT16 usMixerEventIndex = 0; UINT16 usSourceChanIndex; UINT16 usDestinationChanIndex; UINT32 ulResult; /* Check the user's configuration of the copy event for errors. */ ulResult = Oct6100ApiCheckCopyEventCreateParams( f_pApiInstance, f_pCopyEventCreate, &usSourceChanIndex, &usDestinationChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the copy event. */ ulResult = Oct6100ApiReserveCopyEventCreateResources( f_pApiInstance, &usCopyEventIndex, &usMixerEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write all necessary structures to activate the echo cancellation channel. */ ulResult = Oct6100ApiWriteCopyEventCreateStructs( f_pApiInstance, f_pCopyEventCreate, usMixerEventIndex, usSourceChanIndex, usDestinationChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new echo cancellation channels's entry in the ECHO channel list. */ ulResult = Oct6100ApiUpdateCopyEventCreateEntry( f_pApiInstance, f_pCopyEventCreate, usCopyEventIndex, usMixerEventIndex, usSourceChanIndex, usDestinationChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckCopyEventCreateParams Description: Checks the user's parameter passed to the create copy event function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventCreate Pointer to a create copy event structure. f_pusSourceChanIndex Pointer to the index of the input channel. f_pusDestinationChanIndex Pointer to the index of the output channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckCopyEventCreateParams UINT32 Oct6100ApiCheckCopyEventCreateParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, OUT PUINT16 f_pusSourceChanIndex, OUT PUINT16 f_pusDestinationChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pSourceEntry; tPOCT6100_API_CHANNEL pDestinationEntry; UINT32 ulEntryOpenCnt; /* Obtain shared resources pointer. */ pSharedInfo = f_pApiInstance->pSharedInfo; if ( f_pCopyEventCreate->pulCopyEventHndl == NULL ) return cOCT6100_ERR_MIXER_COPY_EVENT_HANDLE; if ( f_pCopyEventCreate->ulSourceChanHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_MIXER_SOURCE_CHAN_HANDLE; if ( f_pCopyEventCreate->ulDestinationChanHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_MIXER_DESTINATION_CHAN_HANDLE; if ( f_pCopyEventCreate->ulSourcePort != cOCT6100_CHANNEL_PORT_RIN && f_pCopyEventCreate->ulSourcePort != cOCT6100_CHANNEL_PORT_SIN ) return cOCT6100_ERR_MIXER_SOURCE_PORT; if ( f_pCopyEventCreate->ulDestinationPort != cOCT6100_CHANNEL_PORT_RIN && f_pCopyEventCreate->ulDestinationPort != cOCT6100_CHANNEL_PORT_SIN ) return cOCT6100_ERR_MIXER_DESTINATION_PORT; /*=======================================================================*/ /* Verify the first channel handle. */ if ( (f_pCopyEventCreate->ulSourceChanHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_MIXER_SOURCE_CHAN_HANDLE; *f_pusSourceChanIndex = (UINT16)( f_pCopyEventCreate->ulSourceChanHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusSourceChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_MIXER_SOURCE_CHAN_HANDLE; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSourceEntry, *f_pusSourceChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pCopyEventCreate->ulSourceChanHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pSourceEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pSourceEntry->byEntryOpenCnt ) return cOCT6100_ERR_MIXER_SOURCE_CHAN_HANDLE; if ( pSourceEntry->CodecConfig.byDecoderPort == f_pCopyEventCreate->ulSourcePort ) return cOCT6100_ERR_MIXER_SOURCE_ADPCM_RESOURCES_ACTIVATED; /*=======================================================================*/ /*=======================================================================*/ /* Verify the second channel handle. */ if ( (f_pCopyEventCreate->ulDestinationChanHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_MIXER_DESTINATION_CHAN_HANDLE; *f_pusDestinationChanIndex = (UINT16)( f_pCopyEventCreate->ulDestinationChanHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusDestinationChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_MIXER_DESTINATION_CHAN_HANDLE; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pDestinationEntry, *f_pusDestinationChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pCopyEventCreate->ulDestinationChanHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pDestinationEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pDestinationEntry->byEntryOpenCnt ) return cOCT6100_ERR_MIXER_DESTINATION_CHAN_HANDLE; if ( pDestinationEntry->CodecConfig.byDecoderPort == f_pCopyEventCreate->ulDestinationPort ) return cOCT6100_ERR_MIXER_DEST_ADPCM_RESOURCES_ACTIVATED; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveCopyEventCreateResources ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusCopyEntryIndex Pointer to the index of the copy entry within the API's list. f_pusCopyEventIndex Pointer to the index of the mixer copy event. . \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveCopyEventCreateResources UINT32 Oct6100ApiReserveCopyEventCreateResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusCopyEntryIndex, IN OUT PUINT16 f_pusCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /*===============================================================================*/ /* Verify and reserve the resources that might already be allocated. */ ulResult = Oct6100ApiReserveCopyEventEntry( f_pApiInstance, f_pusCopyEntryIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* Reserve the source copy event for the first channel. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { /* Reserve the Sin copy event for the first channel. */ ulTempVar = Oct6100ApiReleaseCopyEventEntry ( f_pApiInstance, *f_pusCopyEntryIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteCopyEventCreateStructs Description: Performs all the required structure writes to configure the new copy event ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventCreate Pointer to a create copy event structure. f_usMixerEventIndex Index of the copy event within the mixer memory. f_usSourceChanIndex Index of the source channel within the API's channel list. f_usDestinationChanIndex Index of the destination channel within the API's channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteCopyEventCreateStructs UINT32 Oct6100ApiWriteCopyEventCreateStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, IN UINT16 f_usMixerEventIndex, IN UINT16 f_usSourceChanIndex, IN UINT16 f_usDestinationChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pSourceEntry; tPOCT6100_API_CHANNEL pDestinationEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*==============================================================================*/ /* Get a pointer to the two channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSourceEntry, f_usSourceChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pDestinationEntry, f_usDestinationChanIndex ); /*==============================================================================*/ /* Configure the TSST control memory and add the Sin copy event if necessary. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usMixerEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; if ( f_pCopyEventCreate->ulSourcePort == cOCT6100_CHANNEL_PORT_RIN ) { WriteParams.usWriteData |= pSourceEntry->usRinRoutTsiMemIndex; WriteParams.usWriteData |= pSourceEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } else /* f_pCopyEventCreate->ulSourcePort == cOCT6100_CHANNEL_PORT_SIN */ { if ( pSourceEntry->usExtraSinTsiMemIndex != cOCT6100_INVALID_INDEX ) { WriteParams.usWriteData |= pSourceEntry->usExtraSinTsiMemIndex; } else { WriteParams.usWriteData |= pSourceEntry->usSinSoutTsiMemIndex; } WriteParams.usWriteData |= pSourceEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; if ( f_pCopyEventCreate->ulDestinationPort == cOCT6100_CHANNEL_PORT_RIN ) { WriteParams.usWriteData = (UINT16)( pDestinationEntry->usRinRoutTsiMemIndex ); } else /* f_pCopyEventCreate->ulDestinationPort == cOCT6100_CHANNEL_PORT_SIN */ { WriteParams.usWriteData = (UINT16)( pDestinationEntry->usSinSoutTsiMemIndex ); } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Now insert the event into the event list. */ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usMixerEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usDestinationChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Increment the copy event count on this channel. */ pDestinationEntry->usCopyEventCnt++; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateCopyEventCreateEntry ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventCreate Pointer to a create copy event structure. f_usCopyEventIndex Index of the copy event within the API's event list. f_usMixerEventIndex Index of the copy event within the mixer memory. f_usSourceChanIndex Index of the source channel within the API's channel list. f_usDestinationChanIndex Index of the destination channel within the API's channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateCopyEventCreateEntry UINT32 Oct6100ApiUpdateCopyEventCreateEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_COPY_EVENT_CREATE f_pCopyEventCreate, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex, IN UINT16 f_usSourceChanIndex, IN UINT16 f_usDestinationChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_COPY_EVENT pCopyEventEntry; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_COPY_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, f_usCopyEventIndex ); /*=======================================================================*/ /* Copy the channel's configuration and allocated resources. */ /* Save the channel info in the copy event. */ pCopyEventEntry->usSourceChanIndex = f_usSourceChanIndex; pCopyEventEntry->bySourcePort = (UINT8)( f_pCopyEventCreate->ulSourcePort & 0xFF ); pCopyEventEntry->usDestinationChanIndex = f_usDestinationChanIndex; pCopyEventEntry->byDestinationPort = (UINT8)( f_pCopyEventCreate->ulDestinationPort & 0xFF ); pCopyEventEntry->usMixerEventIndex = f_usMixerEventIndex; /*=======================================================================*/ /* Form handle returned to user. */ *f_pCopyEventCreate->pulCopyEventHndl = cOCT6100_HNDL_TAG_COPY_EVENT | (pCopyEventEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usCopyEventIndex; /* Finally, mark the event as used. */ pCopyEventEntry->fReserved = TRUE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100MixerCopyEventDestroySer ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventDestroy Pointer to a destroy copy event structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100MixerCopyEventDestroySer UINT32 Oct6100MixerCopyEventDestroySer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy ) { UINT16 usCopyEventIndex; UINT16 usMixerEventIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertCopyEventDestroyParams( f_pApiInstance, f_pCopyEventDestroy, &usCopyEventIndex, &usMixerEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiInvalidateCopyEventStructs( f_pApiInstance, usCopyEventIndex, usMixerEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiReleaseCopyEventResources( f_pApiInstance, usCopyEventIndex, usMixerEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle. */ f_pCopyEventDestroy->ulCopyEventHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertCopyEventDestroyParams Description: ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCopyEventDestroy Pointer to a destroy copy event structure. f_pusCopyEventIndex Pointer to the index of the copy event in the API. f_pusMixerEventIndex Pointer to the index of the copy event in the mixer memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertCopyEventDestroyParams UINT32 Oct6100ApiAssertCopyEventDestroyParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_COPY_EVENT_DESTROY f_pCopyEventDestroy, IN OUT PUINT16 f_pusCopyEventIndex, IN OUT PUINT16 f_pusMixerEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_COPY_EVENT pCopyEventEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pCopyEventDestroy->ulCopyEventHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_COPY_EVENT ) return cOCT6100_ERR_MIXER_COPY_EVENT_HANDLE; *f_pusCopyEventIndex = (UINT16)( f_pCopyEventDestroy->ulCopyEventHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusCopyEventIndex >= cOCT6100_MAX_MIXER_EVENTS ) return cOCT6100_ERR_MIXER_COPY_EVENT_HANDLE; /*=======================================================================*/ mOCT6100_GET_COPY_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, *f_pusCopyEventIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pCopyEventDestroy->ulCopyEventHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pCopyEventEntry->fReserved != TRUE ) return cOCT6100_ERR_MIXER_EVENT_NOT_OPEN; if ( ulEntryOpenCnt != pCopyEventEntry->byEntryOpenCnt ) return cOCT6100_ERR_MIXER_COPY_EVENT_HANDLE; /*=======================================================================*/ /* Return the index of the associated event. */ *f_pusMixerEventIndex = pCopyEventEntry->usMixerEventIndex; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateCopyEventStructs Description: Destroy the link between the two channels. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usCopyEventIndex Index of the copy event in the API. f_usMixerEventIndex Index of the copy event in the mixer memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateCopyEventStructs UINT32 Oct6100ApiInvalidateCopyEventStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*=======================================================================*/ /* Clear the Copy event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usMixerEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Remove the event from the list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, f_usMixerEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseCopyEventResources ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usCopyEventIndex Index of the copy event in the API. f_usMixerEventIndex Index of the copy event in the mixer memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseCopyEventResources UINT32 Oct6100ApiReleaseCopyEventResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usCopyEventIndex, IN UINT16 f_usMixerEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pDestinationEntry; tPOCT6100_API_COPY_EVENT pCopyEventEntry; tPOCT6100_API_MIXER_EVENT pTempEventEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_COPY_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, f_usCopyEventIndex ); ulResult = Oct6100ApiReleaseCopyEventEntry( f_pApiInstance, f_usCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_AC; /* Relese the SIN copy event. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usMixerEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_B3; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, f_usMixerEventIndex ); /* Invalidate the entry. */ pTempEventEntry->fReserved = FALSE; pTempEventEntry->usEventType = cOCT6100_INVALID_INDEX; pTempEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pDestinationEntry, pCopyEventEntry->usDestinationChanIndex ); /* Decrement the copy event count on this channel. */ pDestinationEntry->usCopyEventCnt--; /*=======================================================================*/ /* Mark the event entry as unused. */ pCopyEventEntry->fReserved = FALSE; pCopyEventEntry->byEntryOpenCnt++; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveMixerEventEntry Description: Reserves a free entry in the mixer event list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusEventIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveMixerEventEntry UINT32 Oct6100ApiReserveMixerEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEventIndex ) { PVOID pMixerEventAlloc; UINT32 ulResult; UINT32 ulEventIndex; mOCT6100_GET_MIXER_EVENT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pMixerEventAlloc ) ulResult = OctapiLlmAllocAlloc( pMixerEventAlloc, &ulEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_MIXER_ALL_MIXER_EVENT_ENTRY_OPENED; else return cOCT6100_ERR_FATAL_2B; } *f_pusEventIndex = (UINT16)( ulEventIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseMixerEventEntry Description: Release an entry from the mixer event list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEventIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseMixerEventEntry UINT32 Oct6100ApiReleaseMixerEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex ) { PVOID pMixerEventAlloc; UINT32 ulResult; mOCT6100_GET_MIXER_EVENT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pMixerEventAlloc ) ulResult = OctapiLlmAllocDealloc( pMixerEventAlloc, f_usEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_2C; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetFreeMixerEventCnt Description: Retrieve the number of events left in the list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulFreeEventCnt How many events left. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetFreeMixerEventCnt UINT32 Oct6100ApiGetFreeMixerEventCnt( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulFreeEventCnt ) { PVOID pMixerEventAlloc; UINT32 ulResult; UINT32 ulAllocatedEvents; UINT32 ulAvailableEvents; mOCT6100_GET_MIXER_EVENT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pMixerEventAlloc ) ulResult = OctapiLlmAllocInfo( pMixerEventAlloc, &ulAllocatedEvents, &ulAvailableEvents ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E8; /* Return number of free events. */ *f_pulFreeEventCnt = ulAvailableEvents; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveCopyEventEntry Description: Reserves a free entry in the copy event list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusEventIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveCopyEventEntry UINT32 Oct6100ApiReserveCopyEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEventIndex ) { PVOID pCopyEventAlloc; UINT32 ulResult; UINT32 ulEventIndex; mOCT6100_GET_COPY_EVENT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pCopyEventAlloc ) ulResult = OctapiLlmAllocAlloc( pCopyEventAlloc, &ulEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_MIXER_ALL_COPY_EVENT_ENTRY_OPENED; else return cOCT6100_ERR_FATAL_AD; } *f_pusEventIndex = (UINT16)( ulEventIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseCopyEventEntry Description: Release an entry from the copy event list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEventIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseCopyEventEntry UINT32 Oct6100ApiReleaseCopyEventEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEventIndex ) { PVOID pCopyEventAlloc; UINT32 ulResult; mOCT6100_GET_COPY_EVENT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pCopyEventAlloc ) ulResult = OctapiLlmAllocDealloc( pCopyEventAlloc, f_usEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_AE; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tsi_cnct.c0000644000175000017500000010427011431317470031251 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsi_cnct.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to open and close TSI connections This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 38 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_tsi_cnct_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_tsi_cnct_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_tsi_cnct_priv.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100TsiCnctOpen Description: This function opens a TSI connection between two TDM timeslots. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to TSI connection open structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100TsiCnctOpenDef UINT32 Oct6100TsiCnctOpenDef( tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ) { f_pTsiCnctOpen->pulTsiCnctHndl = NULL; f_pTsiCnctOpen->ulInputTimeslot = cOCT6100_INVALID_TIMESLOT; f_pTsiCnctOpen->ulInputStream = cOCT6100_INVALID_STREAM; f_pTsiCnctOpen->ulOutputTimeslot = cOCT6100_INVALID_TIMESLOT; f_pTsiCnctOpen->ulOutputStream = cOCT6100_INVALID_STREAM; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100TsiCnctOpen UINT32 Oct6100TsiCnctOpen( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100TsiCnctOpenSer( f_pApiInstance, f_pTsiCnctOpen ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100TsiCnctClose Description: This function closes a TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctClose Pointer to TSI connection close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100TsiCnctCloseDef UINT32 Oct6100TsiCnctCloseDef( tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ) { f_pTsiCnctClose->ulTsiCnctHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100TsiCnctClose UINT32 Oct6100TsiCnctClose( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100TsiCnctCloseSer( f_pApiInstance, f_pTsiCnctClose ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetTsiCnctSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management the TSI memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetTsiCnctSwSizes UINT32 Oct6100ApiGetTsiCnctSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Determine the amount of memory required for the API TSI connection list. */ f_pInstSizes->ulTsiCnctList = f_pOpenChip->ulMaxTsiCncts * sizeof( tOCT6100_API_TSI_CNCT ); if ( f_pOpenChip->ulMaxTsiCncts > 0 ) { /* Calculate memory needed for TSI memory allocation. */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxTsiCncts, &f_pInstSizes->ulTsiCnctAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_48; } else { f_pInstSizes->ulTsiCnctAlloc = 0; } mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsiCnctList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsiCnctAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiTsiCnctSwInit Description: Initializes all elements of the instance structure associated to the TSI memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiTsiCnctSwInit UINT32 Oct6100ApiTsiCnctSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_TSI_CNCT pChannelsTsiList; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulMaxTsiChannels; PVOID pTsiChannelsAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize the TSI connections API list. */ ulMaxTsiChannels = pSharedInfo->ChipConfig.usMaxTsiCncts; mOCT6100_GET_TSI_CNCT_LIST_PNT( pSharedInfo, pChannelsTsiList ) /* Clear the memory. */ Oct6100UserMemSet( pChannelsTsiList, 0x00, sizeof(tOCT6100_API_TSI_CNCT) * ulMaxTsiChannels ); /* Set all entries in the TSI connections list to unused. */ if ( ulMaxTsiChannels > 0 ) { mOCT6100_GET_TSI_CNCT_ALLOC_PNT( pSharedInfo, pTsiChannelsAlloc ) ulResult = OctapiLlmAllocInit( &pTsiChannelsAlloc, ulMaxTsiChannels ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_49; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100TsiCnctOpenSer Description: Opens a TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to a tOCT6100_TSI_CNCT_OPEN structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100TsiCnctOpenSer UINT32 Oct6100TsiCnctOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ) { UINT16 usTsiChanIndex; UINT16 usTsiMemIndex; UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; UINT32 ulResult; /* Check the user's configuration of the TSI connection open structure for errors. */ ulResult = Oct6100ApiCheckTsiParams( f_pApiInstance, f_pTsiCnctOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the TSI connection. */ ulResult = Oct6100ApiReserveTsiResources( f_pApiInstance, f_pTsiCnctOpen, &usTsiChanIndex, &usTsiMemIndex, &usInputTsstIndex, &usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write all necessary structures to activate the TSI connection. */ ulResult = Oct6100ApiWriteTsiStructs( f_pApiInstance, f_pTsiCnctOpen, usTsiMemIndex, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the TSI connection entry in the API list. */ ulResult = Oct6100ApiUpdateTsiEntry( f_pApiInstance, f_pTsiCnctOpen, usTsiChanIndex, usTsiMemIndex, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckTsiParams Description: Checks the user's TSI connection open configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to TSI connection open configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckTsiParams UINT32 Oct6100ApiCheckTsiParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen ) { UINT32 ulResult; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxTsiCncts == 0 ) return cOCT6100_ERR_TSI_CNCT_DISABLED; if ( f_pTsiCnctOpen->pulTsiCnctHndl == NULL ) return cOCT6100_ERR_TSI_CNCT_INVALID_HANDLE; /* Check the input TDM streams, timeslots component for errors. */ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, cOCT6100_NUMBER_TSSTS_1, f_pTsiCnctOpen->ulInputTimeslot, f_pTsiCnctOpen->ulInputStream, cOCT6100_INPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_TSI_CNCT_INPUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_TSI_CNCT_INPUT_STREAM; } else { return ulResult; } } /* Check the output TDM streams, timeslots component for errors. */ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, cOCT6100_NUMBER_TSSTS_1, f_pTsiCnctOpen->ulOutputTimeslot, f_pTsiCnctOpen->ulOutputStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_TSI_CNCT_OUTPUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_TSI_CNCT_OUTPUT_STREAM; } else { return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveTsiResources Description: Reserves all resources needed for the new TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to tsi channel configuration structure. f_pusTsiChanIndex Allocated entry in TSI channel list. f_pusTsiMemIndex Allocated entry in the TSI control memory. f_pusInputTsstIndex TSST memory index of the input samples. f_pusOutputTsstIndex TSST memory index of the output samples. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveTsiResources UINT32 Oct6100ApiReserveTsiResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; UINT32 ulTempVar; BOOL fTsiChanEntry = FALSE; BOOL fTsiMemEntry = FALSE; BOOL fInputTsst = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Reserve an entry in the TSI connection list. */ ulResult = Oct6100ApiReserveTsiCnctEntry( f_pApiInstance, f_pusTsiChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fTsiChanEntry = TRUE; /* Find a TSI memory entry. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, f_pusTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fTsiMemEntry = TRUE; /* Reserve the input TSST entry. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pTsiCnctOpen->ulInputTimeslot, f_pTsiCnctOpen->ulInputStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_INPUT_TSST, f_pusInputTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fInputTsst = TRUE; /* Reserve the output TSST entry. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pTsiCnctOpen->ulOutputTimeslot, f_pTsiCnctOpen->ulOutputStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, f_pusOutputTsstIndex, NULL ); } } else { /* Return an error other then a fatal. */ ulResult = cOCT6100_ERR_TSI_CNCT_NO_MORE_TSI_AVAILABLE; } } if ( ulResult != cOCT6100_ERR_OK ) { if( fTsiChanEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiCnctEntry( f_pApiInstance, *f_pusTsiChanIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fTsiMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, *f_pusTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fInputTsst == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, f_pTsiCnctOpen->ulInputTimeslot, f_pTsiCnctOpen->ulInputStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteTsiStructs Description: Performs all the required structure writes to configure the new TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to tsi connection open structure. f_usTsiMemIndex Allocated entry in the TSI control memory. f_usInputTsstIndex TSST memory index of the input samples. f_usOutputTsstIndex TSST memory index of the output samples. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteTsiStructs UINT32 Oct6100ApiWriteTsiStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*==================================================================================*/ /* Configure the TSST control memory.*/ /* Set the input TSST control entry.*/ ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usInputTsstIndex, f_usTsiMemIndex, cOCT6100_PCM_U_LAW ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the output TSST control entry. */ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usOutputTsstIndex, cOCT6100_ADPCM_IN_LOW_BITS, 1, f_usTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateTsiEntry Description: Updates the new TSI connection in the TSI connection list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctOpen Pointer to TSI connection open configuration structure. f_usTsiMemIndex Allocated entry in TSI chariot memory. f_usTsiChanIndex Allocated entry in the TSI channel list. f_usInputTsstIndex TSST control memory index of the input TSST. f_usOutputTsstIndex TSST control memory index of the output TSST. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateTsiEntry UINT32 Oct6100ApiUpdateTsiEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_OPEN f_pTsiCnctOpen, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_API_TSI_CNCT pTsiCnctEntry; /*================================================================================*/ /* Obtain a pointer to the new TSI connection's list entry. */ mOCT6100_GET_TSI_CNCT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsiCnctEntry, f_usTsiChanIndex ) /* Copy the TSI's configuration and allocated resources. */ pTsiCnctEntry->usInputTimeslot = (UINT16)( f_pTsiCnctOpen->ulInputTimeslot & 0xFFFF ); pTsiCnctEntry->usInputStream = (UINT16)( f_pTsiCnctOpen->ulInputStream & 0xFFFF ); pTsiCnctEntry->usOutputTimeslot = (UINT16)( f_pTsiCnctOpen->ulOutputTimeslot & 0xFFFF ); pTsiCnctEntry->usOutputStream = (UINT16)( f_pTsiCnctOpen->ulOutputStream & 0xFFFF ); /* Store hardware related information. */ pTsiCnctEntry->usTsiMemIndex = f_usTsiMemIndex; pTsiCnctEntry->usInputTsstIndex = f_usInputTsstIndex; pTsiCnctEntry->usOutputTsstIndex = f_usOutputTsstIndex; /* Form handle returned to user. */ *f_pTsiCnctOpen->pulTsiCnctHndl = cOCT6100_HNDL_TAG_TSI_CNCT | (pTsiCnctEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usTsiChanIndex; /* Finally, mark the connection as opened. */ pTsiCnctEntry->fReserved = TRUE; /* Increment the number of TSI connection opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberTsiCncts++; /*================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100TsiCnctCloseSer Description: Closes a TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctClose Pointer to TSI connection close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100TsiCnctCloseSer UINT32 Oct6100TsiCnctCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose ) { UINT16 usTsiChanIndex; UINT16 usTsiMemIndex; UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertTsiParams( f_pApiInstance, f_pTsiCnctClose, &usTsiChanIndex, &usTsiMemIndex, &usInputTsstIndex, &usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the TSI channel. */ ulResult = Oct6100ApiInvalidateTsiStructs( f_pApiInstance, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the TSI connection. */ ulResult = Oct6100ApiReleaseTsiResources( f_pApiInstance, usTsiChanIndex, usTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle. */ f_pTsiCnctClose->ulTsiCnctHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertTsiParams Description: Validate the handle given by the user and verify the state of the TSI connection about to be closed. Also returns all required information to deactivate the connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTsiCnctClose Pointer to TSI connection close structure. f_pusTsiChanIndex Index of the TSI connection structure in the API list. f_pusTsiMemIndex Index of the TSI entry within the TSI chariot memory f_pusInputTsstIndex Index of the input entry in the TSST control memory. f_pusOutputTsstIndex Index of the output entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertTsiParams UINT32 Oct6100ApiAssertTsiParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TSI_CNCT_CLOSE f_pTsiCnctClose, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TSI_CNCT pTsiEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pTsiCnctClose->ulTsiCnctHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_TSI_CNCT ) return cOCT6100_ERR_TSI_CNCT_INVALID_HANDLE; *f_pusTsiChanIndex = (UINT16)( f_pTsiCnctClose->ulTsiCnctHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusTsiChanIndex >= pSharedInfo->ChipConfig.usMaxTsiCncts ) return cOCT6100_ERR_TSI_CNCT_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_TSI_CNCT_ENTRY_PNT( pSharedInfo, pTsiEntry, *f_pusTsiChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pTsiCnctClose->ulTsiCnctHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pTsiEntry->fReserved != TRUE ) return cOCT6100_ERR_TSI_CNCT_NOT_OPEN; if ( ulEntryOpenCnt != pTsiEntry->byEntryOpenCnt ) return cOCT6100_ERR_TSI_CNCT_INVALID_HANDLE; /* Return info needed to close the channel and release all resources. */ *f_pusInputTsstIndex = pTsiEntry->usInputTsstIndex; *f_pusOutputTsstIndex = pTsiEntry->usOutputTsstIndex; *f_pusTsiMemIndex = pTsiEntry->usTsiMemIndex; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateTsiStructs Description: This function closes a TSI connection. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usInputTsstIndex Index of the input entry in the TSST control memory. f_usOutputTsstIndex Index of the output entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateTsiStructs UINT32 Oct6100ApiInvalidateTsiStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*==================================================================================*/ /* Deactivate the TSST control memory. */ /* Set the input TSST control entry to unused. */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usInputTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the output TSST control entry to unused. */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usOutputTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseTsiResources Description: Release and clear the API entry associated to the TSI channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usTsiChanIndex Index of the TSI connection in the API list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseTsiResources UINT32 Oct6100ApiReleaseTsiResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usTsiMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TSI_CNCT pTsiEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSI_CNCT_ENTRY_PNT( pSharedInfo, pTsiEntry, f_usTsiChanIndex ); /* Release the entry in the TSI connection list. */ ulResult = Oct6100ApiReleaseTsiCnctEntry( f_pApiInstance, f_usTsiChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, f_usTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* Release the input entry. */ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTsiEntry->usInputTimeslot, pTsiEntry->usInputStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { /* Release the output TSST entry. */ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTsiEntry->usOutputTimeslot, pTsiEntry->usOutputStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); } } } /* Check if an error occured while releasing the reserved resources. */ if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult >= cOCT6100_ERR_FATAL ) return ulResult; else return cOCT6100_ERR_FATAL_4A; } /*=============================================================*/ /* Update the TSI connection's list entry. */ /* Mark the connection as closed. */ pTsiEntry->fReserved = FALSE; pTsiEntry->byEntryOpenCnt++; /* Decrement the number of TSI connection opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberTsiCncts--; /*=============================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveTsiCnctEntry Description: Reserves one of the TSI connection API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusTsiChanIndex Resulting index reserved in the TSI channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveTsiCnctEntry UINT32 Oct6100ApiReserveTsiCnctEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusTsiChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsiChanAlloc; UINT32 ulResult; UINT32 ulTsiIndex; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSI_CNCT_ALLOC_PNT( pSharedInfo, pTsiChanAlloc ) ulResult = OctapiLlmAllocAlloc( pTsiChanAlloc, &ulTsiIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_TSI_CNCT_ALL_CHANNELS_ARE_OPENED; else return cOCT6100_ERR_FATAL_4B; } *f_pusTsiChanIndex = (UINT16)( ulTsiIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseTsiCnctEntry Description: Releases the specified TSI connection API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usTsiChanIndex Index reserved in the TSI channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseTsiCnctEntry UINT32 Oct6100ApiReleaseTsiCnctEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsiChanAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSI_CNCT_ALLOC_PNT( pSharedInfo, pTsiChanAlloc ) ulResult = OctapiLlmAllocDealloc( pTsiChanAlloc, f_usTsiChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_4C; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_debug.c0000644000175000017500000015042611431317470030535 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_debug.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to debug the OCT6100. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 65 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_debug_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_debug_priv.h" #include "oct6100_version.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100DebugSelectChannel Description: This function sets the current debug channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pSelectDebugChan Pointer to select debug channel structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100DebugSelectChannelDef UINT32 Oct6100DebugSelectChannelDef( tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan ) { f_pSelectDebugChan->ulChannelHndl = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100DebugSelectChannel UINT32 Oct6100DebugSelectChannel( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100DebugSelectChannelSer( f_pApiInstance, f_pSelectDebugChan, TRUE ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100DebugGetData Description: This function retrieves the last recorded debug data. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pGetData Pointer to debug get data structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100DebugGetDataDef UINT32 Oct6100DebugGetDataDef( tPOCT6100_DEBUG_GET_DATA f_pGetData ) { f_pGetData->ulGetDataMode = cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE; f_pGetData->ulGetDataContent = cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE; f_pGetData->ulRemainingNumBytes = cOCT6100_INVALID_VALUE; f_pGetData->ulTotalNumBytes = cOCT6100_INVALID_VALUE; f_pGetData->ulMaxBytes = cOCT6100_INVALID_VALUE; f_pGetData->ulValidNumBytes = cOCT6100_INVALID_VALUE; f_pGetData->pbyData = NULL; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100DebugGetData UINT32 Oct6100DebugGetData( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_DEBUG_GET_DATA f_pGetData ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100DebugGetDataSer( f_pApiInstance, f_pGetData ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100DebugSelectChannelSer Description: This function sets the debug channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pSelectDebugChan Pointer to a tOCT6100_DEBUG_SELECT_CHANNEL structure. f_fCheckChannelRecording Check if channel recording is enabled or not. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100DebugSelectChannelSer UINT32 Oct6100DebugSelectChannelSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_DEBUG_SELECT_CHANNEL f_pSelectDebugChan, IN BOOL f_fCheckChannelRecording ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry = NULL; tPOCT6100_API_CHANNEL pTempChanEntry; tOCT6100_CHANNEL_OPEN TempChanOpen; tOCT6100_WRITE_BURST_PARAMS BurstParams; UINT16 usChanIndex = 0; UINT32 ulEntryOpenCnt; UINT16 ausWriteData[ 2 ]; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pusWriteData = ausWriteData; /* First release the resources reserved for the channel that was previously debugged. */ if ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex != cOCT6100_INVALID_INDEX && pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) { /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempChanEntry, pSharedInfo->DebugInfo.usCurrentDebugChanIndex ) /* Release the extra TSI memory entry and reprogram the TSST control memory if required. */ if ( pTempChanEntry->usExtraSinTsiDependencyCnt >= 1 ) { /*=======================================================================*/ /* Clear memcpy operations. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); BurstParams.ulWriteLength = 2; ausWriteData[ 0 ] = cOCT6100_MIXER_CONTROL_MEM_NO_OP; ausWriteData[ 1 ] = 0x0; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordSinEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* If we are the last dependency using the extra Sin TSI, release it */ if ( pTempChanEntry->usExtraSinTsiDependencyCnt == 1 ) { ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pTempChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Do not forget to reprogram the TSST control memory. */ if ( pTempChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pTempChanEntry->usSinTsstIndex, pTempChanEntry->usSinSoutTsiMemIndex, pTempChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } pTempChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; /* XXX: What about the silence TSI usSinSilenceEventIndex ?? */ } pTempChanEntry->usExtraSinTsiDependencyCnt--; } } /* Set the new parameters. */ if ( f_pSelectDebugChan->ulChannelHndl != cOCT6100_INVALID_HANDLE ) { /* Check the provided handle. */ if ( (f_pSelectDebugChan->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_DEBUG_CHANNEL_INVALID_HANDLE; usChanIndex = (UINT16)( f_pSelectDebugChan->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( usChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_DEBUG_CHANNEL_INVALID_HANDLE; if ( f_fCheckChannelRecording == TRUE ) { if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE ) return cOCT6100_ERR_DEBUG_CHANNEL_RECORDING_DISABLED; } /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, usChanIndex ); /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pSelectDebugChan->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* First program the mixer entry if the user wants to record. */ /* Check if the API needs to reserve an extra TSI memory to load the SIN signal. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) { /* Reserve the extra Sin TSI memory if it was not already reserved. */ if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reprogram the TSST control memory accordingly. */ if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usSinTsstIndex, pChanEntry->usExtraSinTsiMemIndex, pChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* XXX: What about the silence TSI usSinSilenceEventIndex ?? */ } /*=======================================================================*/ /* Program the Sout Copy event. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); BurstParams.ulWriteLength = 2; ausWriteData[ 0 ] = cOCT6100_MIXER_CONTROL_MEM_COPY; ausWriteData[ 0 ] |= pChanEntry->usSinSoutTsiMemIndex; ausWriteData[ 0 ] |= pChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; ausWriteData[ 1 ] = (UINT16)( pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex ); mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the Sin copy event. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordSinEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); BurstParams.ulWriteLength = 2; ausWriteData[ 0 ] = cOCT6100_MIXER_CONTROL_MEM_COPY; ausWriteData[ 0 ] |= pChanEntry->usExtraSinTsiMemIndex; ausWriteData[ 0 ] |= pChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; ausWriteData[ 1 ] = pChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ pChanEntry->usExtraSinTsiDependencyCnt++; } } else { /* Set the index to invalid to deactivate the recording. */ usChanIndex = cOCT6100_INVALID_INDEX; } /* Set law of newly selected hot channel. */ if ( ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) && ( f_pSelectDebugChan->ulChannelHndl != cOCT6100_INVALID_HANDLE ) && ( pChanEntry != NULL ) ) { /* Set the PCM law of the debug channel. */ /* Let's program the channel memory. */ Oct6100ChannelOpenDef( &TempChanOpen ); TempChanOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_HT_RESET; /* Activate the channel. */ TempChanOpen.VqeConfig.fEnableNlp = FALSE; TempChanOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL; TempChanOpen.VqeConfig.fSinDcOffsetRemoval = FALSE; TempChanOpen.VqeConfig.fRinDcOffsetRemoval = FALSE; TempChanOpen.VqeConfig.lDefaultErlDb = 0; /* Use the law of the channel being recorded. */ TempChanOpen.TdmConfig.ulRinPcmLaw = pChanEntry->TdmConfig.byRinPcmLaw; TempChanOpen.TdmConfig.ulSinPcmLaw = pChanEntry->TdmConfig.bySinPcmLaw; TempChanOpen.TdmConfig.ulRoutPcmLaw = pChanEntry->TdmConfig.byRoutPcmLaw; TempChanOpen.TdmConfig.ulSoutPcmLaw = pChanEntry->TdmConfig.bySoutPcmLaw; ulResult = Oct6100ApiWriteDebugChanMemory( f_pApiInstance, &TempChanOpen.TdmConfig, &TempChanOpen.VqeConfig, &TempChanOpen, pSharedInfo->DebugInfo.usRecordChanIndex, pSharedInfo->DebugInfo.usRecordMemIndex, pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex, pSharedInfo->DebugInfo.usRecordSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } ausWriteData[ 0 ] = 0x0; ausWriteData[ 1 ] = (UINT16)(( usChanIndex >> 0) & 0xFFFF); /* Write the channel number into the Matrix hot channel field.*/ BurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress; BurstParams.pusWriteData = ausWriteData; BurstParams.ulWriteLength = 2; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pSharedInfo->DebugInfo.usCurrentDebugChanIndex = usChanIndex; /* Cancel data dump request, if there was one. */ pSharedInfo->DebugInfo.fDebugDataBeingDumped = FALSE; pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = cOCT6100_INVALID_VALUE; /* Call from remote client. */ if ( f_fCheckChannelRecording == FALSE ) { /* If the user has not activated recording, let the remote client know. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE ) return cOCT6100_ERR_DEBUG_RC_CHANNEL_RECORDING_DISABLED; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100DebugGetDataSer Description: This function retrieves the latest recorded debug data. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pGetData Pointer to a tOCT6100_DEBUG_GET_DATA structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100DebugGetDataSer UINT32 Oct6100DebugGetDataSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_DEBUG_GET_DATA f_pGetData ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry = NULL; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_BURST_PARAMS ReadBurstParams; tOCT6100_WRITE_BURST_PARAMS WriteBurstParams; UINT16 ausWriteData[ 2 ]; UINT16 usReadData; UINT16 usDebugEventReadPtr; UINT16 usTempNumEvents; UINT32 ulResult; UINT32 ulToneEventIndex; UINT32 ulReadPointer; UINT32 ulUserBufWriteIndex = 0; UINT32 ulTimestamp; UINT32 ulDebugEventIndex = 0; UINT32 ulStreamIndex; UINT32 ulPcmSampleIndex; UINT32 ulNumAfEvents; UINT32 ulNumReads = 0; UINT32 ulTempIndex; UINT32 ulCopyIndex; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulStreamIndexMin; UINT32 ulStreamIndexMax; UINT32 ulTempData; UINT32 ulMask; BOOL fResetRemainingDataFlag = FALSE; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; ReadBurstParams.pProcessContext = f_pApiInstance->pProcessContext; ReadBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; WriteBurstParams.pProcessContext = f_pApiInstance->pProcessContext; WriteBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Check all user parameters. */ /* Check if channel recording is enabled. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE ) return cOCT6100_ERR_DEBUG_CHANNEL_RECORDING_DISABLED; /* Check if a current debugging channel has been selected. */ /* If not, the user has not yet called Oct6100DebugSelectChannel. */ if ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_DEBUG_RECORD_NO_CHAN_SELECTED; /* Check that the user supplied a valid max bytes value. */ if ( f_pGetData->ulMaxBytes == cOCT6100_INVALID_VALUE ) return cOCT6100_ERR_DEBUG_GET_DATA_MAX_BYTES; /* Data buffer must be aligned on 1024 bytes. */ if ( ( f_pGetData->ulMaxBytes % 1024 ) != 0 ) return cOCT6100_ERR_DEBUG_GET_DATA_MAX_BYTES; /* Check that the user provided the required memory to transfer the information. */ if ( f_pGetData->pbyData == NULL ) return cOCT6100_ERR_DEBUG_GET_DATA_PTR_INVALID; /* Check dump type. */ if ( ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE ) && ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE ) && ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_16S ) && ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) return cOCT6100_ERR_DEBUG_GET_DATA_MODE; /* Check dump content. */ if ( ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) && ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM ) && ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM ) && ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) ) return cOCT6100_ERR_DEBUG_GET_DATA_CONTENT; /* Check if can accomodate the 120 seconds dump. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { if ( pSharedInfo->DebugInfo.ulDebugEventSize != 0x100 ) return cOCT6100_ERR_NOT_SUPPORTED_DEBUG_DATA_MODE_120S; } mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, pSharedInfo->DebugInfo.usCurrentDebugChanIndex ) /* Lets go dump the requested data. */ usDebugEventReadPtr = 0; /* Check if this is the first time this function is called since the hot channel was set. */ if ( pSharedInfo->DebugInfo.fDebugDataBeingDumped == FALSE ) { /* Check that the channel is not in POWER_DOWN. When the channel is in POWER_DOWN, */ /* the debug events are not recorded correctly in external memory. */ if ( pChanEntry->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN ) return cOCT6100_ERR_DEBUG_CHANNEL_IN_POWER_DOWN; pSharedInfo->DebugInfo.fDebugDataBeingDumped = TRUE; /* Flag the hot channel that it must stop recording. The data is being transfered. */ /* This also tells the remote client not to do anything right now. */ ReadBurstParams.ulReadAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress; ReadBurstParams.ulReadLength = 2; ReadBurstParams.pusReadData = pSharedInfo->DebugInfo.ausHotChannelData; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteBurstParams.pusWriteData = ausWriteData; WriteBurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress; WriteBurstParams.ulWriteLength = 2; WriteBurstParams.pusWriteData[ 0 ] = 0xFFFF; WriteBurstParams.pusWriteData[ 1 ] = 0xFFFF; mOCT6100_DRIVER_WRITE_BURST_API( WriteBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get the maximum number of events this firmware supports from the TLVs. */ pSharedInfo->DebugInfo.usMatrixCBMask = (UINT16)( pSharedInfo->DebugInfo.ulDebugEventSize & 0xFFFF ); pSharedInfo->DebugInfo.usMatrixCBMask -= 1; /* Find out the chip log write pointer. */ /* Now get the current write pointer for matrix events. */ ReadParams.pusReadData = &pSharedInfo->DebugInfo.usChipDebugEventWritePtr; ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixWpBaseAddress + 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ReadParams.pusReadData = &usReadData; /* This write pointer might have wrapped, but we don't know for sure. */ /* To be confident, the chip frame timestamp is read. */ ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixTimestampBaseAddress; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulTimestamp = usReadData << 16; ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulTimestamp |= usReadData; ulTimestamp >>= 12; /* TDM time for 1 event (512 ms) */ /* There is a probability here (once very 6.2 days) that the timestamp is close */ /* to 0, because it has wrapped. But still, we need a way to workaround the highly */ /* occuring case of the chip just being opened. This will fix this problem. */ if ( ulTimestamp < (UINT32)( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) ) { if ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr >= 2 ) { /* Must trash the first 2 events. The chip is not yet ready. */ pSharedInfo->DebugInfo.usNumEvents = (UINT16)( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - 2 ); } else { pSharedInfo->DebugInfo.usNumEvents = 0x0; } } else { pSharedInfo->DebugInfo.usNumEvents = (UINT16)( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ); /* Account for event being created right now while the chip is running. */ /* The event at the write pointer will be discarded. */ if ( pSharedInfo->DebugInfo.usNumEvents > 0 ) pSharedInfo->DebugInfo.usNumEvents--; } /* If the user only requested the last 16 seconds, cap the number of events. */ if ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S || f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE ) { /* x events to get the last 16 seconds. */ if ( pSharedInfo->DebugInfo.usNumEvents > ( 16000 / ( pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize / 8 ) ) ) pSharedInfo->DebugInfo.usNumEvents = (UINT16)( ( 16000 / ( pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize / 8 ) ) & 0xFFFF ); } /* Make sure that all the events are pertaining to the current hot channel. */ /* Calculate the event read pointer. */ ulReadPointer = ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) & pSharedInfo->DebugInfo.usMatrixCBMask ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize; ulReadPointer %= ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ); /* Travel through the events and throw away the bad events. */ usTempNumEvents = pSharedInfo->DebugInfo.usNumEvents; pSharedInfo->DebugInfo.usNumEvents = 0; for ( ulDebugEventIndex = 0; ulDebugEventIndex < usTempNumEvents; ulDebugEventIndex ++ ) { /* The HOT channel index for the event is stored at offset 0xF2 (word offset) */ ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ulReadPointer; ReadParams.ulReadAddress += 0xF2 * sizeof(UINT16); ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the current debug index is the same as the one found in the event. */ if ( usReadData != pSharedInfo->DebugInfo.usCurrentDebugChanIndex ) pSharedInfo->DebugInfo.usNumEvents = 0; /* As soon as we hit another channel, we reset the number of valid events. */ else pSharedInfo->DebugInfo.usNumEvents++; /* Increment read pointer to get next event. */ ulReadPointer = ( ulReadPointer + pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ) % ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ); } /* In heavy mode, the AF log pointer is retrieved. */ if ( ( pSharedInfo->DebugInfo.usNumEvents >= 2 ) && ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) ) { /* The latest AF log write pointer is at the latest matrix event. */ ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr & pSharedInfo->DebugInfo.usMatrixCBMask ) * 1024 ); /* To get the AF log write pointer, which is at offset pSharedInfo->ImageInfo.ulAfWritePtrByteOffset. */ ReadParams.ulReadAddress += pSharedInfo->DebugInfo.ulAfWritePtrByteOffset; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pSharedInfo->DebugInfo.usAfLogWritePtr = usReadData; /* The AF event read pointer is the AF write pointer +4096 */ /* This will make sure we do not get mixed up and fetch events that have */ /* just been written, but we think are old. */ /* To get the exact AF log pointer, the API would have to wait 512 milliseconds to make */ /* sure logging had stopped. This is not required since missing a few last events is not */ /* important at this point (the user knows that valid data has already been recorded). */ pSharedInfo->DebugInfo.usLastAfLogReadPtr = (UINT16)( ( pSharedInfo->DebugInfo.usAfLogWritePtr + 4096 ) & 0xFFFF ); /* Note that if the chip has just been booted, some of the AF events might not be initialized. */ } else { pSharedInfo->DebugInfo.usLastAfLogReadPtr = 0; pSharedInfo->DebugInfo.usAfLogWritePtr = 0; } /* To be aligned correctly for the bursts. */ while ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) != 0 ) pSharedInfo->DebugInfo.usLastAfLogReadPtr++; /* Remember the data mode for later checks. Also, the user cannot change this "mode". */ pSharedInfo->DebugInfo.ulCurrentGetDataMode = f_pGetData->ulGetDataMode; } else { /* Check that the user did not change the current data mode. */ if ( pSharedInfo->DebugInfo.ulCurrentGetDataMode != f_pGetData->ulGetDataMode ) return cOCT6100_ERR_DEBUG_GET_DATA_MODE_CANNOT_CHANGE; } /* Check if this is the first pass here. */ if ( pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes == cOCT6100_INVALID_VALUE ) { /* Calculate how many bytes of data will be returned with respect to the selected data content. */ /* Check what content type the user requested. */ if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) { /* Remember first AF Event Read Pointer. */ f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr >> 8 ) & 0xFF ); /* Remember the AF Event Write Pointer. */ f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usAfLogWritePtr ) & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usAfLogWritePtr >> 8 ) & 0xFF ); /* Remember law and hot channel */ f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.bySinPcmLaw | ( ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex >> 2 ) & 0xFE ) ); f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.bySoutPcmLaw ); /* Insert light or heavy mode in array. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE ) ) { f_pGetData->pbyData[ ulUserBufWriteIndex - 1 ] |= 0x80; } f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.byRinPcmLaw | ( ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex & 0x1F ) << 3 ) ); /* Remember usNumEvents */ f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usNumEvents ) & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usNumEvents >> 8 ) & 0xFF ); } /* Last indexes set to '0'! */ pSharedInfo->DebugInfo.usLastDebugEventIndex = 0; pSharedInfo->DebugInfo.ulLastPcmSampleIndex = 0; /* No tone event has been retrieved. */ pSharedInfo->DebugInfo.usLastToneEventIndex = 0; /* The version strings have not yet been copied. */ pSharedInfo->DebugInfo.fImageVersionCopied = FALSE; pSharedInfo->DebugInfo.fApiVersionCopied = FALSE; /* Estimate the total size of the buffer that will be returned. */ f_pGetData->ulTotalNumBytes = ulUserBufWriteIndex; /* If the full content is requested, add all the debug data. */ if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) { /* Add the matrix events. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { /* Heavy mode! Grab everything! */ f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize; } else { /* Lite mode! Only the most important stuff. */ f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize; } /* Add the PCM samples. */ f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize * 3; /* If requested, add the AF log events. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { f_pGetData->ulTotalNumBytes += (UINT32)( ( pSharedInfo->DebugInfo.usAfLogWritePtr - pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFFFF ) * 16; } /* Add the tone events strings. */ f_pGetData->ulTotalNumBytes += cOCT6100_TLV_MAX_TONE_NAME_SIZE * pSharedInfo->ImageInfo.byNumToneDetectors; /* Add the image version string. */ f_pGetData->ulTotalNumBytes += 512; /* Add the API version string. */ f_pGetData->ulTotalNumBytes += sizeof( cOCT6100_API_VERSION ); } else /* if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */ { /* Add one PCM stream. */ f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize; } /* Save this in the instance for further calls. */ pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = f_pGetData->ulTotalNumBytes; /* Calculate remaining bytes. All the bytes for now! */ f_pGetData->ulRemainingNumBytes = f_pGetData->ulTotalNumBytes; /* Save this in the instance for the next calls. */ pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes = f_pGetData->ulRemainingNumBytes; } else { f_pGetData->ulTotalNumBytes = pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes; } /* Calculate the event read pointer. */ ulReadPointer = ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) & pSharedInfo->DebugInfo.usMatrixCBMask ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize; ulReadPointer += pSharedInfo->DebugInfo.ulDebugChanStatsByteSize * pSharedInfo->DebugInfo.usLastDebugEventIndex; ulReadPointer %= ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ); if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) { /* Copy the debug events in the user buffer. */ for( ulDebugEventIndex = pSharedInfo->DebugInfo.usLastDebugEventIndex; ulDebugEventIndex < pSharedInfo->DebugInfo.usNumEvents; ulDebugEventIndex ++ ) { ReadBurstParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ulReadPointer; /* Check if we are in light or heavy mode. The burst size is not the same. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ) ulNumReads = pSharedInfo->DebugInfo.ulDebugChanStatsByteSize / 2; else break; } else { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize ) ulNumReads = pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize / 2; else break; } ulTempIndex = 0; while ( ulNumReads != 0 ) { if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses ) ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else ReadBurstParams.ulReadLength = ulNumReads; /* Set pointer where to write data. */ ReadBurstParams.pusReadData = pSharedInfo->MiscVars.ausSuperArray; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Copy data byte per byte to avoid endianess problems. */ for ( ulCopyIndex = 0; ulCopyIndex < ReadBurstParams.ulReadLength; ulCopyIndex ++ ) { f_pGetData->pbyData[ ulUserBufWriteIndex + ulTempIndex + ( 2 * ulCopyIndex ) ] = (UINT8)( ReadBurstParams.pusReadData[ ulCopyIndex ] & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex + ulTempIndex + ( 2 * ulCopyIndex ) + 1 ] = (UINT8)( ( ReadBurstParams.pusReadData[ ulCopyIndex ] >> 8 ) & 0xFF ); } /* Update indexes, temp variables, addresses. */ ulNumReads -= ReadBurstParams.ulReadLength; ulTempIndex += ReadBurstParams.ulReadLength * 2; ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2; } /* Store register 0x202 in the event structure. */ f_pGetData->pbyData[ ulUserBufWriteIndex + 255 ] = (UINT8)( pSharedInfo->IntrptManage.usRegister202h & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex + 256 ] = (UINT8)( ( pSharedInfo->IntrptManage.usRegister202h >> 8 ) & 0xFF ); /* Increment index. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { ulUserBufWriteIndex += pSharedInfo->DebugInfo.ulDebugChanStatsByteSize; } else { ulUserBufWriteIndex += pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize; } /* Increment read pointer to get next event. */ ulReadPointer = ( ulReadPointer + pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ) % ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ); /* Save in the instance that one of the events was dumped. */ pSharedInfo->DebugInfo.usLastDebugEventIndex ++; } } /* Check if all debug events have been transfered. */ if ( ( ulDebugEventIndex == pSharedInfo->DebugInfo.usNumEvents ) || ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) ) { /* Fetch all streams per event. */ for ( ulPcmSampleIndex = pSharedInfo->DebugInfo.ulLastPcmSampleIndex; ulPcmSampleIndex < ( (UINT32)pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ); ulPcmSampleIndex ++ ) { /* Check if enough room for this sample. */ if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 1 ) break; } else /* if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */ { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 3 ) break; } /* Check if must retrieve data from external memory. */ if ( ( ulPcmSampleIndex % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE * 2 ) ) == 0x0 ) { ulReadPointer = ( ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) & ( pSharedInfo->DebugInfo.usMatrixCBMask * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) ); ulReadPointer += ( ulPcmSampleIndex / pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize; ulReadPointer &= ( pSharedInfo->DebugInfo.usMatrixCBMask * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ); ulReadPointer += ulPcmSampleIndex % pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize; /* Retrieve more data from external memory. */ switch ( f_pGetData->ulGetDataContent ) { case cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM: ulStreamIndexMin = 0; ulStreamIndexMax = 1; break; case cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM: ulStreamIndexMin = 1; ulStreamIndexMax = 2; break; case cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM: ulStreamIndexMin = 2; ulStreamIndexMax = 3; break; case cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE: default: ulStreamIndexMin = 0; ulStreamIndexMax = 3; break; } for ( ulStreamIndex = ulStreamIndexMin; ulStreamIndex < ulStreamIndexMax; ulStreamIndex ++ ) { ReadBurstParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase; /* To get right channel information. */ ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usRecordMemIndex + 2 ) * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->DebugInfo.ulAfEventCbByteSize; /* To get correct stream. */ ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize * ulStreamIndex ); /* PCM sample pointer in that stream. */ ReadBurstParams.ulReadAddress += ulReadPointer; /* As much as we can for the burst. */ ulTempIndex = 0; ulNumReads = cOCT6100_INTERNAL_SUPER_ARRAY_SIZE; while ( ulNumReads != 0 ) { if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses ) ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else ReadBurstParams.ulReadLength = ulNumReads; /* Set pointer where to write data. */ if ( ulStreamIndex == 0 ) ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray[ ulTempIndex ]; else if ( ulStreamIndex == 1 ) ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray1[ ulTempIndex ]; else /* if ( ulStreamIndex == 2 ) */ ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray2[ ulTempIndex ]; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update indexes, temp variables, addresses. */ ulNumReads -= ReadBurstParams.ulReadLength; ulTempIndex += ReadBurstParams.ulReadLength; ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2; } } } /* We now have the stream data for all streams for 1 event. */ /* Return what we can to the user. */ if ( ( ulPcmSampleIndex % 2 ) == 0 ) { if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF ); if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray1[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF ); if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray2[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF ); } else /* if ( ulPcmSampleIndex % 2 == 1 ) */ { if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF ); if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray1[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF ); if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) || ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) ) f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray2[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF ); } pSharedInfo->DebugInfo.ulLastPcmSampleIndex++; } /* Check if we are done dumping the PCM samples! */ if ( pSharedInfo->DebugInfo.ulLastPcmSampleIndex == ( (UINT32)pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) ) { if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) { /* Go for the AF events. The AF events are only copied in heavy mode. */ if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S ) || ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) { while ( pSharedInfo->DebugInfo.usLastAfLogReadPtr != pSharedInfo->DebugInfo.usAfLogWritePtr ) { /* Check if enough room for an event. */ if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 16 ) break; /* Check if must fill our buffer. */ if ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) == 0x0 ) { ulNumAfEvents = ( pSharedInfo->DebugInfo.usAfLogWritePtr - pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFFFF; /* Check for the size of the available buffer. */ if ( ulNumAfEvents > ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) ulNumAfEvents = ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ); /* Start at channel main base address. */ ReadBurstParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase; /* To get right channel information. */ ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usRecordMemIndex + 2 ) * pSharedInfo->MemoryMap.ulChanMainMemSize ); /* To get the right AF log. */ ReadBurstParams.ulReadAddress += ( pSharedInfo->DebugInfo.usLastAfLogReadPtr * 16 ); ulTempIndex = 0; ulNumReads = ulNumAfEvents * 8; while ( ulNumReads != 0 ) { if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses ) ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else ReadBurstParams.ulReadLength = ulNumReads; /* Set pointer where to write data. */ ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray[ ulTempIndex ]; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update indexes, temp variables, addresses. */ ulNumReads -= ReadBurstParams.ulReadLength; ulTempIndex += ReadBurstParams.ulReadLength; ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2; } } /* Copy data byte per byte to avoid endianess problems. */ for ( ulCopyIndex = 0; ulCopyIndex < 8; ulCopyIndex ++ ) { f_pGetData->pbyData[ ulUserBufWriteIndex + ( 2 * ulCopyIndex ) ] = (UINT8)( pSharedInfo->MiscVars.ausSuperArray[ ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) * 8 ) + ulCopyIndex ] & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex + ( 2 * ulCopyIndex ) + 1 ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) * 8 ) + ulCopyIndex ] >> 8 ) & 0xFF ); } ulUserBufWriteIndex += 16; /* Increment AF log read ptr. */ pSharedInfo->DebugInfo.usLastAfLogReadPtr = (UINT16)(( pSharedInfo->DebugInfo.usLastAfLogReadPtr + 1 ) & 0xFFFF ); } } /* Check if we are done with the AF events. */ if ( pSharedInfo->DebugInfo.usLastAfLogReadPtr == pSharedInfo->DebugInfo.usAfLogWritePtr ) { /* Insert the tone event information. */ for ( ulToneEventIndex = pSharedInfo->DebugInfo.usLastToneEventIndex; ulToneEventIndex < pSharedInfo->ImageInfo.byNumToneDetectors; ulToneEventIndex++ ) { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < cOCT6100_TLV_MAX_TONE_NAME_SIZE ) break; Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], pSharedInfo->ImageInfo.aToneInfo[ ulToneEventIndex ].aszToneName, cOCT6100_TLV_MAX_TONE_NAME_SIZE ); ulUserBufWriteIndex += cOCT6100_TLV_MAX_TONE_NAME_SIZE; pSharedInfo->DebugInfo.usLastToneEventIndex++; } /* If all the tone information has been copied. */ if ( ulToneEventIndex == pSharedInfo->ImageInfo.byNumToneDetectors ) { /* Copy the image version. */ if ( pSharedInfo->DebugInfo.fImageVersionCopied == FALSE ) { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= 512 ) { Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], pSharedInfo->ImageInfo.szVersionNumber, 512 ); /* Get PLL jitter count from external memory. */ if ( pSharedInfo->DebugInfo.fPouchCounter == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Create the mask to retrieve the appropriate value. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Mask data. */ ulTempData &= ulMask; /* Move to right position. */ ulTempData = ulTempData >> ulFeatureBitOffset; f_pGetData->pbyData[ ulUserBufWriteIndex + 510 ] = (UINT8)( ( ulTempData >> 8 ) & 0xFF ); f_pGetData->pbyData[ ulUserBufWriteIndex + 511 ] = (UINT8)( ( ulTempData >> 0 ) & 0xFF ); } /* Add "ISR is not called" bit. */ if ( pSharedInfo->IntrptManage.fIsrCalled == FALSE ) { f_pGetData->pbyData[ ulUserBufWriteIndex + 510 ] |= 0x80; } ulUserBufWriteIndex += 512; /* The version has been copied. */ pSharedInfo->DebugInfo.fImageVersionCopied = TRUE; } } /* If the image version has been copied, proceed with the API version. */ if ( pSharedInfo->DebugInfo.fImageVersionCopied == TRUE ) { if ( pSharedInfo->DebugInfo.fApiVersionCopied == FALSE ) { if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= sizeof(cOCT6100_API_VERSION) ) { Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], cOCT6100_API_VERSION, sizeof(cOCT6100_API_VERSION) ); ulUserBufWriteIndex += sizeof(cOCT6100_API_VERSION); /* The API version has been copied. */ pSharedInfo->DebugInfo.fApiVersionCopied = TRUE; } } } } /* Check if we are done! */ if ( pSharedInfo->DebugInfo.fApiVersionCopied == TRUE ) { /* Done dumping. */ /* Reset data being dumpped flag. */ pSharedInfo->DebugInfo.fDebugDataBeingDumped = FALSE; /* Reset data recording in the chip. */ WriteBurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress; WriteBurstParams.ulWriteLength = 2; WriteBurstParams.pusWriteData = pSharedInfo->DebugInfo.ausHotChannelData; mOCT6100_DRIVER_WRITE_BURST_API( WriteBurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; fResetRemainingDataFlag = TRUE; } } } else /* if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */ { fResetRemainingDataFlag = TRUE; } } } /* Return number of valid bytes in buffer to user. */ f_pGetData->ulValidNumBytes = ulUserBufWriteIndex; /* Update remaining bytes. */ pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes -= ulUserBufWriteIndex; /* Return remaining bytes. */ f_pGetData->ulRemainingNumBytes = pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes; /* Return total number of bytes. */ f_pGetData->ulTotalNumBytes = pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes; /* Check if we are done dump the requested content. */ if ( fResetRemainingDataFlag == TRUE ) pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.c0000644000175000017500000070734211603154003031410 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_open.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions used to power-up the chip according to the user's configuration. Also, the API instance is initialized to reflect the desired configuration. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 347 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #if defined(__FreeBSD__) #include #include #else #ifndef __KERNEL__ #include #define kmalloc(size, type) malloc(size) #define kfree(ptr) free(ptr) #define GFP_ATOMIC 0 /*Dummy */ #else #include #include #endif #endif #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_bt0.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_tsi_cnct_inst.h" #include "oct6100api/oct6100_events_inst.h" #include "oct6100api/oct6100_conf_bridge_inst.h" #include "oct6100api/oct6100_playout_buf_inst.h" #include "oct6100api/oct6100_mixer_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_adpcm_chan_inst.h" #include "oct6100api/oct6100_phasing_tsst_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_chip_stats_pub.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_tsi_cnct_pub.h" #include "oct6100api/oct6100_events_pub.h" #include "oct6100api/oct6100_conf_bridge_pub.h" #include "oct6100api/oct6100_playout_buf_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_adpcm_chan_pub.h" #include "oct6100api/oct6100_phasing_tsst_pub.h" #include "oct6100api/oct6100_remote_debug_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_mixer_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_debug_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_interrupts_priv.h" #include "oct6100_chip_stats_priv.h" #include "octrpc/rpc_protocol.h" #include "oct6100_remote_debug_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_tsi_cnct_priv.h" #include "oct6100_mixer_priv.h" #include "oct6100_events_priv.h" #include "oct6100_conf_bridge_priv.h" #include "oct6100_playout_buf_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_adpcm_chan_priv.h" #include "oct6100_phasing_tsst_priv.h" #include "oct6100_tlv_priv.h" #include "oct6100_debug_priv.h" #include "oct6100_version.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100GetInstanceSizeDef Description: Retrieves the size of the required API instance structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pGetSize Structure containing API instance size. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100GetInstanceSizeDef UINT32 Oct6100GetInstanceSizeDef( tPOCT6100_GET_INSTANCE_SIZE f_pGetSize ) { return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100GetInstanceSize UINT32 Oct6100GetInstanceSize( tPOCT6100_CHIP_OPEN f_pChipOpen, tPOCT6100_GET_INSTANCE_SIZE f_pGetSize ) { tOCT6100_API_INSTANCE_SIZES InstanceSizes; UINT32 ulResult; /* Check user configuration for errors and conflicts. */ ulResult = Oct6100ApiCheckChipConfiguration( f_pChipOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Calculate the instance size required for user's configuration. */ ulResult = Oct6100ApiCalculateInstanceSizes( f_pChipOpen, &InstanceSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Return required size to user. */ f_pGetSize->ulApiInstanceSize = InstanceSizes.ulApiInstTotal; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipOpenDef Description: Inserts default chip configuration parameters into the structure pointed to by f_pChipOpen. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pChipOpen Structure containing user chip configuration. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipOpenDef UINT32 Oct6100ChipOpenDef( tPOCT6100_CHIP_OPEN f_pChipOpen ) { UINT32 i; f_pChipOpen->ulUserChipId = 0; f_pChipOpen->fMultiProcessSystem = FALSE; f_pChipOpen->pProcessContext = NULL; f_pChipOpen->ulMaxRwAccesses = 8; f_pChipOpen->pbyImageFile = NULL; f_pChipOpen->ulImageSize = 0; f_pChipOpen->ulMemClkFreq = 133000000; /* 133 Mhz */ f_pChipOpen->ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ; /* 33.33 Mhz */ f_pChipOpen->fEnableMemClkOut = TRUE; f_pChipOpen->ulMemoryType = cOCT6100_MEM_TYPE_DDR; f_pChipOpen->ulNumMemoryChips = 1; f_pChipOpen->ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_64MB; /* Set the tail displacement to zero. */ f_pChipOpen->ulTailDisplacement = 0; /* Disable acoustic echo by default. */ f_pChipOpen->fEnableAcousticEcho = FALSE; /* Resource allocation parameters. */ f_pChipOpen->ulMaxChannels = 256; f_pChipOpen->ulMaxTsiCncts = 0; f_pChipOpen->ulMaxBiDirChannels = 0; f_pChipOpen->ulMaxConfBridges = 0; f_pChipOpen->ulMaxFlexibleConfParticipants = 0; f_pChipOpen->ulMaxPlayoutBuffers = 0; f_pChipOpen->ulMaxPhasingTssts = 0; f_pChipOpen->ulMaxAdpcmChannels = 0; f_pChipOpen->ulMaxTdmStreams = 32; f_pChipOpen->fUseSynchTimestamp = FALSE; for ( i = 0; i < 4; i++ ) { f_pChipOpen->aulTimestampTimeslots[ i ] = cOCT6100_INVALID_TIMESLOT; f_pChipOpen->aulTimestampStreams[ i ] = cOCT6100_INVALID_STREAM; } f_pChipOpen->fEnableFastH100Mode = FALSE; /* Configure the soft tone event buffer. */ f_pChipOpen->ulSoftToneEventsBufSize = 128; f_pChipOpen->fEnableExtToneDetection = FALSE; f_pChipOpen->fEnable2100StopEvent = FALSE; /* Configure the soft playout event buffer. */ f_pChipOpen->ulSoftBufferPlayoutEventsBufSize = cOCT6100_INVALID_VALUE; /* Interrupt configuration. */ f_pChipOpen->ulInterruptPolarity = cOCT6100_ACTIVE_LOW_POLARITY; f_pChipOpen->InterruptConfig.ulErrorMemoryConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulFatalGeneralConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulFatalMemoryConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulFatalMemoryConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulErrorH100Config = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pChipOpen->InterruptConfig.ulErrorMemoryTimeout = 100; f_pChipOpen->InterruptConfig.ulFatalMemoryTimeout = 100; f_pChipOpen->InterruptConfig.ulErrorH100Timeout = 100; f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsTimeout = 100; f_pChipOpen->ulMaxRemoteDebugSessions = 0; f_pChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_3_QUARTERS; for ( i = 0; i < cOCT6100_TDM_STREAM_MAX_GROUPS; i++ ) f_pChipOpen->aulTdmStreamFreqs[ i ] = cOCT6100_TDM_STREAM_FREQ_8MHZ; f_pChipOpen->fEnableChannelRecording = FALSE; f_pChipOpen->fEnableProductionBist = FALSE; f_pChipOpen->ulProductionBistMode = cOCT6100_PRODUCTION_BIST_STANDARD; f_pChipOpen->ulNumProductionBistLoops = 1; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipOpen Description: Configures the chip according to the user specified configuration f_pChipOpen. This function will perform all I/O accesses necessary and initialize the API instance to reflect the configuration. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipOpen Structure containing user chip configuration. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipOpen UINT32 Oct6100ChipOpen( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHIP_OPEN f_pChipOpen ) { tOCT6100_API_INSTANCE_SIZES *InstanceSizes; UINT32 ulStructSize; UINT32 ulResult; UINT32 ulTempVar; /* Check user chip configuration parameters for errors. */ ulResult = Oct6100ApiCheckChipConfiguration( f_pChipOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the host system is multi-process or not and adjust instance accordingly. */ if ( f_pChipOpen->fMultiProcessSystem != TRUE ) { /* Set pointer to tOCT6100_SHARED_INFO structure within instance. */ ulStructSize = sizeof( tOCT6100_INSTANCE_API ); mOCT6100_ROUND_MEMORY_SIZE( ulStructSize, ulTempVar ) f_pApiInstance->pSharedInfo = ( tPOCT6100_SHARED_INFO )(( PUINT8 )f_pApiInstance + ulStructSize); /* Save the process context specified by the user. */ f_pApiInstance->pProcessContext = f_pChipOpen->pProcessContext; /* Create serialization object handles. */ ulResult = Oct6100ApiCreateSerializeObjects( f_pApiInstance, f_pChipOpen->ulUserChipId ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Copy the configuration structure. */ ulResult = Oct6100ApiCopyChipConfiguration( f_pApiInstance, f_pChipOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Perform various calculations based on user chip configuration. */ ulResult = Oct6100ApiInitializeMiscellaneousVariables( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; InstanceSizes = kmalloc(sizeof(tOCT6100_API_INSTANCE_SIZES), GFP_ATOMIC); if (!InstanceSizes) return cOCT6100_ERR_FATAL_0; /* Calculate the amount of memory needed for the API instance structure. */ ulResult = Oct6100ApiCalculateInstanceSizes( f_pChipOpen, InstanceSizes ); if ( ulResult != cOCT6100_ERR_OK ) { kfree(InstanceSizes); return ulResult; } /* Allocate the memory for the API instance structure internal pointers. */ ulResult = Oct6100ApiAllocateInstanceMemory( f_pApiInstance, InstanceSizes ); kfree(InstanceSizes); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the allocated instance structure memory. */ ulResult = Oct6100ApiInitializeInstanceMemory( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the tone information structure. */ ulResult = Oct6100ApiInitToneInfo( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Test the CPU registers. */ ulResult = Oct6100ApiCpuRegisterBist( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Boot the FC2 PLL. */ ulResult = Oct6100ApiBootFc2Pll( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Program the FC1 PLL. */ ulResult = Oct6100ApiProgramFc1Pll( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Decode the key and bist internal memories. */ ulResult = Oct6100ApiDecodeKeyAndBist( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Boot the FC1 PLL. */ ulResult = Oct6100ApiBootFc1Pll( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Boot the SDRAM. */ ulResult = Oct6100ApiBootSdram( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Bist the external memory. */ ulResult = Oct6100ApiExternalMemoryBist( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the external memory. */ ulResult = Oct6100ApiExternalMemoryInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Load the image into the chip. */ ulResult = Oct6100ApiLoadImage( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the clock distribution registers. */ ulResult = Oct6100ApiEnableClocks( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Program the NLP processor. */ ulResult = Oct6100ApiProgramNLP( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_OPEN_EGO_TIMEOUT ) ulResult = Oct6100ApiProgramNLP( f_pApiInstance ); } if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( f_pChipOpen->fEnableProductionBist == FALSE ) { /* Read all TLV fields present in external memory. */ ulResult = Oct6100ApiProcessTlvRegion( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the H.100 interface. */ ulResult = Oct6100ApiSetH100Register( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Write miscellaneous registers. */ ulResult = Oct6100ApiWriteMiscellaneousRegisters( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Proceed with the rest only if the production BIST has not been requested. */ if ( f_pChipOpen->fEnableProductionBist == FALSE ) { /* Initialize the errors counters. */ ulResult = Oct6100ApiChipStatsSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get revision number of chip. */ ulResult = Oct6100ApiGetChipRevisionNum( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the channels. */ ulResult = Oct6100ApiInitChannels( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the mixer memory. */ ulResult = Oct6100ApiInitMixer( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize the mixer memory. */ ulResult = Oct6100ApiInitRecordResources( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Initialize free external memory for buffer playout. */ ulResult = Oct6100ApiBufferPlayoutMemorySwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*Clear all interrupts that could have occured during startup*/ ulResult = Oct6100ApiClearInterrupts( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the interrupt registers. */ ulResult = Oct6100ApiIsrHwInit( f_pApiInstance, &f_pChipOpen->InterruptConfig ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipCloseDef Description: Puts the chip into soft reset. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipClose Pointer to a tOCT6100_CHIP_CLOSE structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipCloseDef UINT32 Oct6100ChipCloseDef( tPOCT6100_CHIP_CLOSE f_pChipClose ) { f_pChipClose->ulDummyVariable = 0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChipClose UINT32 Oct6100ChipClose( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHIP_CLOSE f_pChipClose ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; WriteParams.ulWriteAddress = 0x100; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Destroy the allocated ressources used for serialization. */ ulResult = Oct6100ApiDestroySerializeObjects( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100CreateLocalInstance Description: Creates a local instance for a process in a multi-process host system. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pCreateLocal Structure used to create process' local instance. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100CreateLocalInstanceDef UINT32 Oct6100CreateLocalInstanceDef( tPOCT6100_CREATE_LOCAL_INSTANCE f_pCreateLocal ) { f_pCreateLocal->pApiInstShared = NULL; f_pCreateLocal->pApiInstLocal = NULL; f_pCreateLocal->pProcessContext = NULL; f_pCreateLocal->ulUserChipId = 0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100CreateLocalInstance UINT32 Oct6100CreateLocalInstance( tPOCT6100_CREATE_LOCAL_INSTANCE f_pCreateLocal ) { tPOCT6100_INSTANCE_API pApiInstLocal; UINT32 ulApiInstSize; UINT32 ulTempVar; UINT32 ulResult; /* Check user's structure for errors. */ if ( f_pCreateLocal->pApiInstShared == NULL ) return cOCT6100_ERR_MULTIPROC_API_INST_SHARED; if ( f_pCreateLocal->pApiInstLocal == NULL ) return cOCT6100_ERR_MULTIPROC_API_INST_LOCAL; /* Get local pointer to local instance. */ pApiInstLocal = f_pCreateLocal->pApiInstLocal; /* Assign pointers to local structure. */ ulApiInstSize = sizeof( tOCT6100_INSTANCE_API ); mOCT6100_ROUND_MEMORY_SIZE( ulApiInstSize, ulTempVar ) pApiInstLocal->pSharedInfo = ( tPOCT6100_SHARED_INFO )(( PUINT8 )f_pCreateLocal->pApiInstShared + ulApiInstSize); pApiInstLocal->pProcessContext = f_pCreateLocal->pProcessContext; /* Create serialization object handles needed. */ ulResult = Oct6100ApiCreateSerializeObjects( pApiInstLocal, f_pCreateLocal->ulUserChipId ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100DestroyLocalInstance Description: Release local instance for a process in a multi-process host system. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pDestroyLocal Structure used to destroy the process' local instance. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100DestroyLocalInstanceDef UINT32 Oct6100DestroyLocalInstanceDef( tPOCT6100_DESTROY_LOCAL_INSTANCE f_pDestroyLocal ) { f_pDestroyLocal->ulDummy = 0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100DestroyLocalInstance UINT32 Oct6100DestroyLocalInstance( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_DESTROY_LOCAL_INSTANCE f_pDestroyLocal ) { UINT32 ulResult; /* Destroy the allocated ressources used for serialization. */ ulResult = Oct6100ApiDestroySerializeObjects( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100GetHwRevision Description: Gets the hardware revision number of the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pGetHwRev Pointer to user structure in which to return revision number. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100GetHwRevisionDef UINT32 Oct6100GetHwRevisionDef( tPOCT6100_GET_HW_REVISION f_pGetHwRev ) { f_pGetHwRev->ulUserChipId = cOCT6100_INVALID_CHIP_ID; f_pGetHwRev->pProcessContext = NULL; f_pGetHwRev->ulRevisionNum = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100GetHwRevision UINT32 Oct6100GetHwRevision( tPOCT6100_GET_HW_REVISION f_pGetHwRev ) { tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usReadData; /* Read the hardware revision register. */ ReadParams.pProcessContext = f_pGetHwRev->pProcessContext; ReadParams.ulUserChipId = f_pGetHwRev->ulUserChipId; ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = 0x17E; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pGetHwRev->ulRevisionNum = ( usReadData >> 8 ) & 0xFF; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100FreeResources Description: This function closes all opened channels and frees all specified global resources used by the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pFreeResources Pointer to user structure in which to choose what to free. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100FreeResourcesDef UINT32 Oct6100FreeResourcesDef( tPOCT6100_FREE_RESOURCES f_pFreeResources ) { f_pFreeResources->fFreeTsiConnections = FALSE; f_pFreeResources->fFreeConferenceBridges = FALSE; f_pFreeResources->fFreePlayoutBuffers = FALSE; f_pFreeResources->fFreePhasingTssts = FALSE; f_pFreeResources->fFreeAdpcmChannels = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100FreeResources UINT32 Oct6100FreeResources( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_FREE_RESOURCES f_pFreeResources ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100FreeResourcesSer( f_pApiInstance, f_pFreeResources ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ProductionBist Description: This function retrieves the current BIST status of the firmware. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pProductionBist Pointer to user structure where the bist information will be returned. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ProductionBistDef UINT32 Oct6100ProductionBistDef( tPOCT6100_PRODUCTION_BIST f_pProductionBist ) { f_pProductionBist->ulCurrentAddress = cOCT6100_INVALID_VALUE; f_pProductionBist->ulCurrentLoop = cOCT6100_INVALID_VALUE; f_pProductionBist->ulFailedAddress = cOCT6100_INVALID_VALUE; f_pProductionBist->ulReadValue = cOCT6100_INVALID_VALUE; f_pProductionBist->ulExpectedValue = cOCT6100_INVALID_VALUE; f_pProductionBist->ulBistStatus = cOCT6100_BIST_IN_PROGRESS; f_pProductionBist->ulCurrentTest = cOCT6100_INVALID_VALUE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ProductionBist UINT32 Oct6100ProductionBist( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_PRODUCTION_BIST f_pProductionBist ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ProductionBistSer( f_pApiInstance, f_pProductionBist ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetVersion Description: Retrieves the API version. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiGetVersion Pointer to structure that will receive version information. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetVersionDef UINT32 Oct6100ApiGetVersionDef( tPOCT6100_API_GET_VERSION f_pApiGetVersion ) { UINT32 i; /* Initialize the string. */ for ( i = 0; i < cOCT6100_API_VERSION_STRING_LENGTH; i++ ) f_pApiGetVersion->achApiVersion[ i ] = 0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ApiGetVersion UINT32 Oct6100ApiGetVersion( tPOCT6100_API_GET_VERSION f_pApiGetVersion ) { /* Copy API version information to user. */ Oct6100UserMemCopy( f_pApiGetVersion->achApiVersion, cOCT6100_API_VERSION, sizeof(cOCT6100_API_VERSION) ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetCapacityPins Description: Retrieves the Capcity Pins value. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pGetCapacityPins Pointer to the parameters structure needed by GetCapacityPins(). \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetCapacityPinsDef UINT32 Oct6100ApiGetCapacityPinsDef( tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins) { f_pGetCapacityPins->pProcessContext = NULL; f_pGetCapacityPins->ulUserChipId = 0; f_pGetCapacityPins->ulMemoryType = cOCT6100_MEM_TYPE_DDR; f_pGetCapacityPins->ulCapacityValue = cOCT6100_INVALID_VALUE; f_pGetCapacityPins->fEnableMemClkOut = TRUE; f_pGetCapacityPins->ulMemClkFreq = 133000000; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ApiGetCapacityPins UINT32 Oct6100ApiGetCapacityPins( tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ) { UINT32 ulResult; tOCT6100_INSTANCE_API ApiInstance; Oct6100UserMemSet(&ApiInstance,0,sizeof(tOCT6100_INSTANCE_API)); /*Check parameters*/ if ( f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_133_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_125_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_117_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_108_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_100_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_92_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_83_MHZ && f_pGetCapacityPins->ulMemClkFreq != cOCT6100_MCLK_FREQ_75_MHZ ) return cOCT6100_ERR_OPEN_MEM_CLK_FREQ; if ( f_pGetCapacityPins->fEnableMemClkOut != TRUE && f_pGetCapacityPins->fEnableMemClkOut != FALSE ) return cOCT6100_ERR_OPEN_ENABLE_MEM_CLK_OUT; if ( f_pGetCapacityPins->ulMemoryType != cOCT6100_MEM_TYPE_SDR && f_pGetCapacityPins->ulMemoryType != cOCT6100_MEM_TYPE_DDR && f_pGetCapacityPins->ulMemoryType != cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) return cOCT6100_ERR_OPEN_MEMORY_TYPE; ApiInstance.pProcessContext = f_pGetCapacityPins->pProcessContext; ulResult = Oct6100ApiReadCapacity(&ApiInstance, f_pGetCapacityPins); return ulResult; } #endif /*************************** PRIVATE FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReadCapacity Description: Read the capacity pins using modified functions from the openchip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pChipOpen Pointer to chip configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_OCT6100ApiReadCapacity UINT32 Oct6100ApiReadCapacity( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins) { UINT32 ulResult; tOCT6100_READ_PARAMS ReadParams; UINT16 usReadData; /*Read capacity Pins*/ ReadParams.pProcessContext = f_pGetCapacityPins->pProcessContext; ReadParams.ulUserChipId = f_pGetCapacityPins->ulUserChipId; ReadParams.pusReadData = &usReadData; /*Check the Reset register*/ ReadParams.ulReadAddress = 0x100; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ((usReadData & 0xFFFF) != 0x0000) return cOCT6100_ERR_CAP_PINS_INVALID_CHIP_STATE; /* Test the CPU registers. */ ulResult = Oct6100ApiCpuRegisterBistReadCap( f_pApiInstance, f_pGetCapacityPins ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Boot the FC2 PLL. */ ulResult = Oct6100ApiBootFc2PllReadCap( f_pApiInstance,f_pGetCapacityPins ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Program the FC1 PLL. */ ulResult = Oct6100ApiProgramFc1PllReadCap( f_pApiInstance,f_pGetCapacityPins ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR) || (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { ReadParams.ulReadAddress = 0x168; } else ReadParams.ulReadAddress = 0x166; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; switch (usReadData & 0xF) { case 0x9: f_pGetCapacityPins->ulCapacityValue = 16; break; case 0x8: f_pGetCapacityPins->ulCapacityValue = 32; break; case 0xE: f_pGetCapacityPins->ulCapacityValue = 64; break; case 0x0: f_pGetCapacityPins->ulCapacityValue = 128; break; case 0x2: f_pGetCapacityPins->ulCapacityValue = 256; break; case 0x5: f_pGetCapacityPins->ulCapacityValue = 512; break; case 0x6: f_pGetCapacityPins->ulCapacityValue = 672; break; default: f_pGetCapacityPins->ulCapacityValue = (usReadData & 0xF); return cOCT6100_ERR_CAP_PINS_INVALID_CAPACITY_VALUE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChipConfiguration Description: Checks the user chip configuration structure for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pChipOpen Pointer to chip configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChipConfiguration UINT32 Oct6100ApiCheckChipConfiguration( IN tPOCT6100_CHIP_OPEN f_pChipOpen ) { UINT32 ulTempVar; UINT32 i; /*-----------------------------------------------------------------------------*/ /* Check general parameters. */ if ( f_pChipOpen->fMultiProcessSystem != TRUE && f_pChipOpen->fMultiProcessSystem != FALSE ) return cOCT6100_ERR_OPEN_MULTI_PROCESS_SYSTEM; if ( f_pChipOpen->ulMaxRwAccesses < 1 || f_pChipOpen->ulMaxRwAccesses > 1024) return cOCT6100_ERR_OPEN_MAX_RW_ACCESSES; /* Check the clocks. */ if ( f_pChipOpen->ulUpclkFreq != cOCT6100_UPCLK_FREQ_33_33_MHZ ) return cOCT6100_ERR_OPEN_UP_CLK_FREQ; if ( f_pChipOpen->ulMemClkFreq != cOCT6100_MCLK_FREQ_133_MHZ ) return cOCT6100_ERR_OPEN_MEM_CLK_FREQ; if ( f_pChipOpen->fEnableMemClkOut != TRUE && f_pChipOpen->fEnableMemClkOut != FALSE ) return cOCT6100_ERR_OPEN_ENABLE_MEM_CLK_OUT; /* Check the image file. */ if ( f_pChipOpen->ulImageSize < cOCT6100_MIN_IMAGE_SIZE || f_pChipOpen->ulImageSize > cOCT6100_MAX_IMAGE_SIZE ) return cOCT6100_ERR_OPEN_IMAGE_SIZE; if ( f_pChipOpen->pbyImageFile == NULL ) return cOCT6100_ERR_OPEN_IMAGE_FILE; ulTempVar = Oct6100ApiCheckImageFileHeader(f_pChipOpen); if (ulTempVar != cOCT6100_ERR_OK) return ulTempVar; /* Check the acoustic echo activation flag. */ if ( f_pChipOpen->fEnableAcousticEcho != TRUE && f_pChipOpen->fEnableAcousticEcho != FALSE ) return cOCT6100_ERR_OPEN_ENABLE_ACOUSTIC_ECHO; /* Check the tail displacement parameter. */ if ( f_pChipOpen->ulTailDisplacement > cOCT6100_MAX_TAIL_DISPLACEMENT ) return cOCT6100_ERR_OPEN_TAIL_DISPLACEMENT; /*-----------------------------------------------------------------------------*/ /* Check TDM bus configuration parameters. */ for ( i = 0; i < 8; i++ ) { if ( f_pChipOpen->aulTdmStreamFreqs[ i ] != cOCT6100_TDM_STREAM_FREQ_2MHZ && f_pChipOpen->aulTdmStreamFreqs[ i ] != cOCT6100_TDM_STREAM_FREQ_4MHZ && f_pChipOpen->aulTdmStreamFreqs[ i ] != cOCT6100_TDM_STREAM_FREQ_8MHZ) return cOCT6100_ERR_OPEN_TDM_STREAM_FREQS; } if ( f_pChipOpen->ulTdmSampling != cOCT6100_TDM_SAMPLE_AT_3_QUARTERS && f_pChipOpen->ulTdmSampling != cOCT6100_TDM_SAMPLE_AT_RISING_EDGE && f_pChipOpen->ulTdmSampling != cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE ) return cOCT6100_ERR_OPEN_TDM_SAMPLING; if ( f_pChipOpen->fEnableFastH100Mode != TRUE && f_pChipOpen->fEnableFastH100Mode != FALSE ) return cOCT6100_ERR_OPEN_FAST_H100_MODE; /*-----------------------------------------------------------------------------*/ /* Check external memory configuration parameters. */ if ( f_pChipOpen->ulMemoryType != cOCT6100_MEM_TYPE_SDR && f_pChipOpen->ulMemoryType != cOCT6100_MEM_TYPE_DDR && f_pChipOpen->ulMemoryType != cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) return cOCT6100_ERR_OPEN_MEMORY_TYPE; if ( f_pChipOpen->ulMemoryChipSize != cOCT6100_MEMORY_CHIP_SIZE_8MB && f_pChipOpen->ulMemoryChipSize != cOCT6100_MEMORY_CHIP_SIZE_16MB && f_pChipOpen->ulMemoryChipSize != cOCT6100_MEMORY_CHIP_SIZE_32MB && f_pChipOpen->ulMemoryChipSize != cOCT6100_MEMORY_CHIP_SIZE_64MB && f_pChipOpen->ulMemoryChipSize != cOCT6100_MEMORY_CHIP_SIZE_128MB ) return cOCT6100_ERR_OPEN_MEMORY_CHIP_SIZE; if ( f_pChipOpen->ulMemoryChipSize == cOCT6100_MEMORY_CHIP_SIZE_8MB && f_pChipOpen->ulMemoryType == cOCT6100_MEM_TYPE_DDR ) return cOCT6100_ERR_OPEN_MEMORY_CHIP_SIZE; if ( f_pChipOpen->ulNumMemoryChips < 1 || f_pChipOpen->ulNumMemoryChips > cOCT6100_MAX_NUM_MEMORY_CHIP ) return cOCT6100_ERR_OPEN_MEMORY_CHIPS_NUMBER; /* Check the total memory size. */ ulTempVar = f_pChipOpen->ulMemoryChipSize * f_pChipOpen->ulNumMemoryChips; if ( ulTempVar < cOCT6100_MEMORY_CHIP_SIZE_16MB || ulTempVar > cOCT6100_MEMORY_CHIP_SIZE_128MB ) return cOCT6100_ERR_OPEN_TOTAL_MEMORY_SIZE; if ( f_pChipOpen->ulMaxTdmStreams != 4 && f_pChipOpen->ulMaxTdmStreams != 8 && f_pChipOpen->ulMaxTdmStreams != 16 && f_pChipOpen->ulMaxTdmStreams != 32 ) return cOCT6100_ERR_OPEN_MAX_TDM_STREAM; if ( f_pChipOpen->ulMaxTdmStreams > 8 && f_pChipOpen->ulMemClkFreq == cOCT6100_MCLK_FREQ_75_MHZ ) return cOCT6100_ERR_OPEN_MAX_TDM_STREAM; if ( f_pChipOpen->fUseSynchTimestamp != TRUE && f_pChipOpen->fUseSynchTimestamp != FALSE ) return cOCT6100_ERR_OPEN_USE_SYNCH_TIMESTAMP; if ( f_pChipOpen->fUseSynchTimestamp == TRUE ) { return cOCT6100_ERR_NOT_SUPPORTED_OPEN_USE_SYNCH_TIMESTAMP; } /*-----------------------------------------------------------------------------*/ /* Check soft buffer for tone events size. */ if (f_pChipOpen->ulSoftToneEventsBufSize < 64 || f_pChipOpen->ulSoftToneEventsBufSize > cOCT6100_ABSOLUTE_MAX_NUM_PGSP_EVENT_OUT ) return cOCT6100_ERR_OPEN_SOFT_TONE_EVENT_SIZE; if ( f_pChipOpen->fEnableExtToneDetection != TRUE && f_pChipOpen->fEnableExtToneDetection != FALSE ) return cOCT6100_ERR_OPEN_ENABLE_EXT_TONE_DETECTION; if ( f_pChipOpen->fEnable2100StopEvent != TRUE && f_pChipOpen->fEnable2100StopEvent != FALSE) return cOCT6100_ERR_OPEN_ENABLE_2100_STOP_EVENT; /* Check soft buffer for playout events size. */ if ( ( f_pChipOpen->ulSoftBufferPlayoutEventsBufSize != cOCT6100_INVALID_VALUE ) && ( f_pChipOpen->ulSoftBufferPlayoutEventsBufSize < cOCT6100_MIN_BUFFER_PLAYOUT_EVENT || f_pChipOpen->ulSoftBufferPlayoutEventsBufSize > cOCT6100_MAX_BUFFER_PLAYOUT_EVENT ) ) return cOCT6100_ERR_OPEN_SOFT_PLAYOUT_STOP_EVENT_SIZE; /*-----------------------------------------------------------------------------*/ /* Check interrupt configuration parameters. */ if ( f_pChipOpen->ulInterruptPolarity != cOCT6100_ACTIVE_LOW_POLARITY && f_pChipOpen->ulInterruptPolarity != cOCT6100_ACTIVE_HIGH_POLARITY ) return cOCT6100_ERR_OPEN_INTERRUPT_POLARITY; if ( f_pChipOpen->InterruptConfig.ulFatalGeneralConfig != cOCT6100_INTERRUPT_NO_TIMEOUT && f_pChipOpen->InterruptConfig.ulFatalGeneralConfig != cOCT6100_INTERRUPT_DISABLE ) return cOCT6100_ERR_OPEN_FATAL_GENERAL_CONFIG; if ( f_pChipOpen->InterruptConfig.ulFatalMemoryConfig != cOCT6100_INTERRUPT_NO_TIMEOUT && f_pChipOpen->InterruptConfig.ulFatalMemoryConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pChipOpen->InterruptConfig.ulFatalMemoryConfig != cOCT6100_INTERRUPT_DISABLE ) return cOCT6100_ERR_OPEN_FATAL_MEMORY_CONFIG; if ( f_pChipOpen->InterruptConfig.ulErrorMemoryConfig != cOCT6100_INTERRUPT_NO_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorMemoryConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorMemoryConfig != cOCT6100_INTERRUPT_DISABLE ) return cOCT6100_ERR_OPEN_ERROR_MEMORY_CONFIG; if ( f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_NO_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_DISABLE ) return cOCT6100_ERR_OPEN_ERROR_OVERFLOW_TONE_EVENTS_CONFIG; if ( f_pChipOpen->InterruptConfig.ulErrorH100Config != cOCT6100_INTERRUPT_NO_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorH100Config != cOCT6100_INTERRUPT_TIMEOUT && f_pChipOpen->InterruptConfig.ulErrorH100Config != cOCT6100_INTERRUPT_DISABLE ) return cOCT6100_ERR_OPEN_ERROR_H100_CONFIG; /* Check the timeout value. */ if ( f_pChipOpen->InterruptConfig.ulFatalMemoryTimeout < 10 || f_pChipOpen->InterruptConfig.ulFatalMemoryTimeout > 10000 ) return cOCT6100_ERR_OPEN_FATAL_MEMORY_TIMEOUT; if ( f_pChipOpen->InterruptConfig.ulErrorMemoryTimeout < 10 || f_pChipOpen->InterruptConfig.ulErrorMemoryTimeout > 10000 ) return cOCT6100_ERR_OPEN_ERROR_MEMORY_TIMEOUT; if ( f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsTimeout < 10 || f_pChipOpen->InterruptConfig.ulErrorOverflowToneEventsTimeout > 10000 ) return cOCT6100_ERR_OPEN_ERROR_OVERFLOW_TONE_EVENTS_TIMEOUT; if ( f_pChipOpen->InterruptConfig.ulErrorH100Timeout < 10 || f_pChipOpen->InterruptConfig.ulErrorH100Timeout > 10000 ) return cOCT6100_ERR_OPEN_ERROR_H100_TIMEOUT; /*-----------------------------------------------------------------------------*/ /* Check maximum resources. */ switch ( f_pChipOpen->ulMemClkFreq ) { case 133000000: ulTempVar = 672; break; case 125000000: ulTempVar = 624; break; case 117000000: ulTempVar = 576; break; case 108000000: ulTempVar = 528; break; case 100000000: ulTempVar = 480; break; case 92000000: ulTempVar = 432; break; case 83000000: ulTempVar = 384; break; case 75000000: ulTempVar = 336; break; default: return cOCT6100_ERR_FATAL_DA; } if ( f_pChipOpen->ulMaxChannels > ulTempVar ) return cOCT6100_ERR_OPEN_MAX_ECHO_CHANNELS; if ( f_pChipOpen->ulMaxTsiCncts > cOCT6100_MAX_TSI_CNCTS ) return cOCT6100_ERR_OPEN_MAX_TSI_CNCTS; if ( f_pChipOpen->ulMaxBiDirChannels > 255 ) return cOCT6100_ERR_OPEN_MAX_BIDIR_CHANNELS; if ( f_pChipOpen->ulMaxBiDirChannels > (f_pChipOpen->ulMaxChannels / 2) ) return cOCT6100_ERR_OPEN_MAX_BIDIR_CHANNELS; if ( f_pChipOpen->ulMaxConfBridges > cOCT6100_MAX_CONF_BRIDGE ) return cOCT6100_ERR_OPEN_MAX_CONF_BRIDGES; if ( f_pChipOpen->ulMaxFlexibleConfParticipants > cOCT6100_MAX_FLEX_CONF_PARTICIPANTS ) return cOCT6100_ERR_OPEN_MAX_FLEXIBLE_CONF_PARTICIPANTS; if ( f_pChipOpen->ulMaxPlayoutBuffers > cOCT6100_MAX_PLAYOUT_BUFFERS ) return cOCT6100_ERR_OPEN_MAX_PLAYOUT_BUFFERS; if ( f_pChipOpen->ulMaxPhasingTssts > cOCT6100_MAX_PHASING_TSST ) return cOCT6100_ERR_OPEN_MAX_PHASING_TSSTS; if ( f_pChipOpen->ulMaxAdpcmChannels > cOCT6100_MAX_ADPCM_CHANNELS ) return cOCT6100_ERR_OPEN_MAX_ADPCM_CHANNELS; if ( f_pChipOpen->ulMaxRemoteDebugSessions > 256 ) return cOCT6100_ERR_OPEN_MAX_REMOTE_DEBUG_SESSIONS; /* Check the channel recording flag. */ if ( f_pChipOpen->fEnableChannelRecording != TRUE && f_pChipOpen->fEnableChannelRecording != FALSE ) return cOCT6100_ERR_OPEN_DEBUG_CHANNEL_RECORDING; /* Check the enable production BIST flag. */ if ( ( f_pChipOpen->fEnableProductionBist != TRUE ) && ( f_pChipOpen->fEnableProductionBist != FALSE ) ) return cOCT6100_ERR_OPEN_ENABLE_PRODUCTION_BIST; /* Check number of loops for the production BIST. */ if ( f_pChipOpen->fEnableProductionBist == TRUE ) { if ( f_pChipOpen->ulNumProductionBistLoops == 0 ) return cOCT6100_ERR_OPEN_NUM_PRODUCTION_BIST_LOOPS; if ( (f_pChipOpen->ulProductionBistMode != cOCT6100_PRODUCTION_BIST_STANDARD) && (f_pChipOpen->ulProductionBistMode != cOCT6100_PRODUCTION_BIST_SHORT) ) return cOCT6100_ERR_OPEN_PRODUCTION_BIST_MODE; } /* If the production BIST has been requested, make sure all */ /* other resources are disabled. */ if ( f_pChipOpen->fEnableProductionBist == TRUE ) { /* All must be disabled. */ f_pChipOpen->ulMaxChannels = 0; f_pChipOpen->ulMaxTsiCncts = 0; f_pChipOpen->fEnableChannelRecording = FALSE; f_pChipOpen->ulMaxBiDirChannels = 0; f_pChipOpen->ulMaxConfBridges = 0; f_pChipOpen->ulMaxPlayoutBuffers = 0; f_pChipOpen->ulSoftBufferPlayoutEventsBufSize = cOCT6100_INVALID_VALUE; f_pChipOpen->ulMaxPhasingTssts = 0; f_pChipOpen->ulMaxAdpcmChannels = 0; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCopyChipConfiguration Description: Copies the chip configuration from the user supplied config structure to the instance structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipOpen Pointer to chip configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCopyChipConfiguration UINT32 Oct6100ApiCopyChipConfiguration( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHIP_OPEN f_pChipOpen ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; pSharedInfo->ChipConfig.ulUserChipId = f_pChipOpen->ulUserChipId; pSharedInfo->ChipConfig.fMultiProcessSystem = (UINT8)( f_pChipOpen->fMultiProcessSystem & 0xFF ); pSharedInfo->ChipConfig.usMaxRwAccesses = (UINT16)( f_pChipOpen->ulMaxRwAccesses & 0xFFFF ); pSharedInfo->ChipConfig.pbyImageFile = f_pChipOpen->pbyImageFile; pSharedInfo->ChipConfig.ulImageSize = f_pChipOpen->ulImageSize; pSharedInfo->ChipConfig.ulMemClkFreq = f_pChipOpen->ulMemClkFreq; pSharedInfo->ChipConfig.ulUpclkFreq = f_pChipOpen->ulUpclkFreq; pSharedInfo->ChipConfig.byMemoryType = (UINT8)( f_pChipOpen->ulMemoryType & 0xFF ); pSharedInfo->ChipConfig.byNumMemoryChips = (UINT8)( f_pChipOpen->ulNumMemoryChips & 0xFF ); pSharedInfo->ChipConfig.ulMemoryChipSize = f_pChipOpen->ulMemoryChipSize; pSharedInfo->ChipConfig.usTailDisplacement = (UINT16)( f_pChipOpen->ulTailDisplacement & 0xFFFF ); pSharedInfo->ChipConfig.fEnableAcousticEcho = (UINT8)( f_pChipOpen->fEnableAcousticEcho & 0xFF ); /* Resource allocation parameters. */ if ( f_pChipOpen->fEnableChannelRecording == TRUE && f_pChipOpen->ulMaxChannels == 672 ) pSharedInfo->ChipConfig.usMaxChannels = (UINT16)( ( f_pChipOpen->ulMaxChannels - 1 ) & 0xFFFF ); else pSharedInfo->ChipConfig.usMaxChannels = (UINT16)( f_pChipOpen->ulMaxChannels & 0xFFFF ); pSharedInfo->ChipConfig.usMaxTsiCncts = (UINT16)( f_pChipOpen->ulMaxTsiCncts & 0xFFFF ); pSharedInfo->ChipConfig.usMaxBiDirChannels = (UINT16)( f_pChipOpen->ulMaxBiDirChannels & 0xFFFF ); pSharedInfo->ChipConfig.usMaxConfBridges = (UINT16)( f_pChipOpen->ulMaxConfBridges & 0xFFFF ); pSharedInfo->ChipConfig.usMaxFlexibleConfParticipants = (UINT16)( f_pChipOpen->ulMaxFlexibleConfParticipants & 0xFFFF ); pSharedInfo->ChipConfig.usMaxPlayoutBuffers = (UINT16)( f_pChipOpen->ulMaxPlayoutBuffers & 0xFFFF ); pSharedInfo->ChipConfig.usMaxPhasingTssts = (UINT16)( f_pChipOpen->ulMaxPhasingTssts & 0xFFFF ); pSharedInfo->ChipConfig.usMaxAdpcmChannels = (UINT16)( f_pChipOpen->ulMaxAdpcmChannels & 0xFFFF ); pSharedInfo->ChipConfig.byMaxTdmStreams = (UINT8)( f_pChipOpen->ulMaxTdmStreams & 0xFF ); pSharedInfo->ChipConfig.fUseSynchTimestamp = (UINT8)( f_pChipOpen->fUseSynchTimestamp & 0xFF ); for ( i = 0; i < 4; i++ ) { pSharedInfo->ChipConfig.ausTimestampTimeslots[ i ] = (UINT16)( f_pChipOpen->aulTimestampTimeslots[ i ] & 0xFFFF ); pSharedInfo->ChipConfig.ausTimestampStreams[ i ] = (UINT16)( f_pChipOpen->aulTimestampStreams[ i ] & 0xFFFF ); } pSharedInfo->ChipConfig.byInterruptPolarity = (UINT8)( f_pChipOpen->ulInterruptPolarity & 0xFF ); pSharedInfo->ChipConfig.byTdmSampling = (UINT8)( f_pChipOpen->ulTdmSampling & 0xFF ); pSharedInfo->ChipConfig.fEnableFastH100Mode = (UINT8)( f_pChipOpen->fEnableFastH100Mode & 0xFF ); for ( i = 0; i < cOCT6100_TDM_STREAM_MAX_GROUPS; i++ ) { if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->ChipConfig.aulTdmStreamFreqs[ i ] = cOCT6100_TDM_STREAM_FREQ_16MHZ; else pSharedInfo->ChipConfig.aulTdmStreamFreqs[ i ] = f_pChipOpen->aulTdmStreamFreqs[ i ]; } pSharedInfo->ChipConfig.fEnableFastH100Mode = (UINT8)( f_pChipOpen->fEnableFastH100Mode & 0xFF ); pSharedInfo->ChipConfig.fEnableMemClkOut = (UINT8)( f_pChipOpen->fEnableMemClkOut & 0xFF ); /* Add 1 to the circular buffer such that all user requested events can fit in the circular queue. */ pSharedInfo->ChipConfig.ulSoftToneEventsBufSize = f_pChipOpen->ulSoftToneEventsBufSize + 1; pSharedInfo->ChipConfig.fEnableExtToneDetection = (UINT8)( f_pChipOpen->fEnableExtToneDetection & 0xFF ); pSharedInfo->ChipConfig.fEnable2100StopEvent = (UINT8)( f_pChipOpen->fEnable2100StopEvent & 0xFF ); if ( f_pChipOpen->ulSoftBufferPlayoutEventsBufSize != cOCT6100_INVALID_VALUE ) pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize = f_pChipOpen->ulSoftBufferPlayoutEventsBufSize + 1; else pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize = 0; pSharedInfo->ChipConfig.usMaxRemoteDebugSessions = (UINT16)( f_pChipOpen->ulMaxRemoteDebugSessions & 0xFFFF ); pSharedInfo->ChipConfig.fEnableChannelRecording = (UINT8)( f_pChipOpen->fEnableChannelRecording & 0xFF ); pSharedInfo->ChipConfig.fEnableProductionBist = (UINT8)( f_pChipOpen->fEnableProductionBist & 0xFF ); pSharedInfo->ChipConfig.ulProductionBistMode = f_pChipOpen->ulProductionBistMode; pSharedInfo->ChipConfig.ulNumProductionBistLoops = f_pChipOpen->ulNumProductionBistLoops; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitializeMiscellaneousVariables Description: Function where all the various parameters from the API instance are set to their defaults value. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitializeMiscellaneousVariables UINT32 Oct6100ApiInitializeMiscellaneousVariables( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 i; /* Obtain pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Calculate the total memory available. */ pSharedInfo->MiscVars.ulTotalMemSize = pSharedInfo->ChipConfig.ulMemoryChipSize * pSharedInfo->ChipConfig.byNumMemoryChips; /* Software buffers initialization. */ /* Tones */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; pSharedInfo->SoftBufs.ulToneEventBufferReadPtr = 0; pSharedInfo->SoftBufs.ulToneEventBufferSize = pSharedInfo->ChipConfig.ulSoftToneEventsBufSize; pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt = 0; /* Playout */ pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr = 0; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr = 0; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize = pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt = 0; /* Set the number of conference bridges opened to zero. */ pSharedInfo->MiscVars.usNumBridgesOpened = 0; pSharedInfo->MiscVars.usFirstBridge = cOCT6100_INVALID_INDEX; /* Set the H.100 slave mode. */ pSharedInfo->MiscVars.ulH100SlaveMode = cOCT6100_H100_TRACKA; /* Save the Mclk value.*/ pSharedInfo->MiscVars.ulMclkFreq = pSharedInfo->ChipConfig.ulMemClkFreq; /* Init the NLP params. */ pSharedInfo->MiscVars.usCodepoint = 0; pSharedInfo->MiscVars.usCpuLsuWritePtr = 0; /* Pouch counter not present until TLVs are read. */ pSharedInfo->DebugInfo.fPouchCounter = FALSE; pSharedInfo->DebugInfo.fIsIsrCalledField = FALSE; /* Initialize the image info parameters */ pSharedInfo->ImageInfo.fAdaptiveNoiseReduction = FALSE; pSharedInfo->ImageInfo.fSoutNoiseBleaching = FALSE; pSharedInfo->ImageInfo.fComfortNoise = FALSE; pSharedInfo->ImageInfo.fBufferPlayout = TRUE; pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip = FALSE; pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip = FALSE; pSharedInfo->ImageInfo.fNlpControl = FALSE; pSharedInfo->ImageInfo.fRinAutoLevelControl = FALSE; pSharedInfo->ImageInfo.fSoutAutoLevelControl = FALSE; pSharedInfo->ImageInfo.fRinHighLevelCompensation = FALSE; pSharedInfo->ImageInfo.fSoutHighLevelCompensation = FALSE; pSharedInfo->ImageInfo.fAlcHlcStatus = FALSE; pSharedInfo->ImageInfo.fRinDcOffsetRemoval = FALSE; pSharedInfo->ImageInfo.fSilenceSuppression = FALSE; pSharedInfo->ImageInfo.fSinDcOffsetRemoval = FALSE; pSharedInfo->ImageInfo.fToneDisabler = FALSE; pSharedInfo->ImageInfo.fAdpcm = FALSE; pSharedInfo->ImageInfo.fTailDisplacement = FALSE; pSharedInfo->ImageInfo.fConferencing = FALSE; pSharedInfo->ImageInfo.fConferencingNoiseReduction = FALSE; pSharedInfo->ImageInfo.fDominantSpeakerEnabled = FALSE; pSharedInfo->ImageInfo.fAecEnabled = FALSE; pSharedInfo->ImageInfo.fAcousticEcho = FALSE; pSharedInfo->ImageInfo.fToneRemoval = FALSE; pSharedInfo->ImageInfo.fDefaultErl = FALSE; pSharedInfo->ImageInfo.fMaxEchoPoint = FALSE; pSharedInfo->ImageInfo.fNonLinearityBehaviorA = FALSE; pSharedInfo->ImageInfo.fNonLinearityBehaviorB = FALSE; pSharedInfo->ImageInfo.fPerChannelTailDisplacement = FALSE; pSharedInfo->ImageInfo.fPerChannelTailLength = FALSE; pSharedInfo->ImageInfo.fAfTailDisplacement = FALSE; pSharedInfo->ImageInfo.fMusicProtection = FALSE; pSharedInfo->ImageInfo.fAftControl = FALSE; pSharedInfo->ImageInfo.fSinVoiceDetectedStat = FALSE; pSharedInfo->ImageInfo.fRinAppliedGainStat = FALSE; pSharedInfo->ImageInfo.fSoutAppliedGainStat = FALSE; pSharedInfo->ImageInfo.fListenerEnhancement = FALSE; pSharedInfo->ImageInfo.fRoutNoiseReduction = FALSE; pSharedInfo->ImageInfo.fRoutNoiseReductionLevel = FALSE; pSharedInfo->ImageInfo.fAnrSnrEnhancement = FALSE; pSharedInfo->ImageInfo.fAnrVoiceNoiseSegregation = FALSE; pSharedInfo->ImageInfo.fRinMute = FALSE; pSharedInfo->ImageInfo.fSinMute = FALSE; pSharedInfo->ImageInfo.fToneDisablerVqeActivationDelay = FALSE; pSharedInfo->ImageInfo.fAecTailLength = FALSE; pSharedInfo->ImageInfo.fMusicProtectionConfiguration= FALSE; pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents = FALSE; pSharedInfo->ImageInfo.fRinEnergyStat = FALSE; pSharedInfo->ImageInfo.fSoutEnergyStat = FALSE; pSharedInfo->ImageInfo.fDoubleTalkBehavior = FALSE; pSharedInfo->ImageInfo.fDoubleTalkBehaviorFieldOfst = FALSE; pSharedInfo->ImageInfo.fIdleCodeDetection = TRUE; pSharedInfo->ImageInfo.fIdleCodeDetectionConfiguration = FALSE; pSharedInfo->ImageInfo.fSinLevel = TRUE; pSharedInfo->ImageInfo.usMaxNumberOfChannels = 0; pSharedInfo->ImageInfo.ulToneProfileNumber = cOCT6100_INVALID_VALUE; pSharedInfo->ImageInfo.ulBuildId = cOCT6100_INVALID_VALUE; pSharedInfo->ImageInfo.byImageType = cOCT6100_IMAGE_TYPE_WIRELINE; pSharedInfo->ImageInfo.usMaxTailDisplacement = 0; pSharedInfo->ImageInfo.usMaxTailLength = cOCT6100_TAIL_LENGTH_128MS; pSharedInfo->DebugInfo.ulDebugEventSize = 0x100; pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents = 32; pSharedInfo->DebugInfo.ulMatrixBaseAddress = cOCT6100_MATRIX_DWORD_BASE; pSharedInfo->DebugInfo.ulDebugChanStatsByteSize = cOCT6100_DEBUG_CHAN_STATS_EVENT_BYTE_SIZE; pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize = cOCT6100_DEBUG_CHAN_STATS_LITE_EVENT_BYTE_SIZE; pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress= cOCT6100_MATRIX_CHAN_SELECT_DWORD_ADD; pSharedInfo->DebugInfo.ulMatrixTimestampBaseAddress = cOCT6100_MATRIX_TIMESTAMP_DWORD_ADD; pSharedInfo->DebugInfo.ulMatrixWpBaseAddress = cOCT6100_MATRIX_WRITE_PTR_DWORD_ADD; pSharedInfo->DebugInfo.ulAfWritePtrByteOffset = 206; pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize = 4096; pSharedInfo->DebugInfo.ulAfEventCbByteSize = 0x100000; /* Set all tones to invalid. */ pSharedInfo->ImageInfo.byNumToneDetectors = 0; for ( i = 0; i < cOCT6100_MAX_TONE_EVENT; i++ ) { pSharedInfo->ImageInfo.aToneInfo[ i ].ulToneID = cOCT6100_INVALID_VALUE; pSharedInfo->ImageInfo.aToneInfo[ i ].ulDetectionPort = cOCT6100_INVALID_PORT; Oct6100UserMemSet( pSharedInfo->ImageInfo.aToneInfo[ i ].aszToneName, 0x00, cOCT6100_TLV_MAX_TONE_NAME_SIZE ); } /* Initialize the channel recording info. */ pSharedInfo->DebugInfo.usRecordChanIndex = pSharedInfo->ChipConfig.usMaxChannels; pSharedInfo->DebugInfo.usRecordMemIndex = cOCT6100_INVALID_INDEX; pSharedInfo->DebugInfo.usCurrentDebugChanIndex = cOCT6100_INVALID_INDEX; /* Initialize the mixer information. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastBridgeEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastSinCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usRecordCopyEventIndex = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usRecordSinEventIndex = cOCT6100_INVALID_INDEX; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCalculateInstanceSizes Description: Calculates the amount of memory needed for the instance structure memory block based on the user's configuration. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pChipOpen Pointer to user chip configuration structure. f_pInstSizes Pointer to structure containing the size of memory needed by all pointers internal to the API instance. The memory is needed to keep track of the present state of all the chip's resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCalculateInstanceSizes UINT32 Oct6100ApiCalculateInstanceSizes( IN OUT tPOCT6100_CHIP_OPEN f_pChipOpen, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulApiInstProcessSpecific; UINT32 ulTempVar; UINT32 ulResult; /* Start with all instance sizes set to 0. */ Oct6100UserMemSet( f_pInstSizes, 0x00, sizeof( tOCT6100_API_INSTANCE_SIZES ) ); /* All memory sizes are rounded up to the next multiple of 64 bytes. */ /*-----------------------------------------------------------------------------*/ /* Obtain size of static members of API instance. */ f_pInstSizes->ulApiInstStatic = sizeof( tOCT6100_SHARED_INFO ); mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulApiInstStatic, ulTempVar ) /* Calculate memory needed by pointers internal to the API instance. */ /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for the EC channels. */ ulResult = Oct6100ApiGetChannelsEchoSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Memory needed by the TSI structures. */ ulResult = Oct6100ApiGetTsiCnctSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for the conference bridges. */ ulResult = Oct6100ApiGetConfBridgeSwSizes( f_pChipOpen, f_pInstSizes ); /* Calculate memory needed for list and allocation software serialization. */ if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Memory needed by the buffer playout structures. */ ulResult = Oct6100ApiGetPlayoutBufferSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Memory needed by soft Rx Event buffers. */ ulResult = Oct6100ApiGetEventsSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for phasing tssts. */ ulResult = Oct6100ApiGetPhasingTsstSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for the ADPCM channels. */ ulResult = Oct6100ApiGetAdpcmChanSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for the management of TSSTs. */ ulResult = Oct6100ApiGetTsstSwSizes( f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate memory needed for the management of the mixer. */ ulResult = Oct6100ApiGetMixerSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Determine amount of memory needed for memory allocation softwares. These pieces of software will be responsible for the allocation of the chip's external memory and API memory. */ ulResult = Oct6100ApiGetMemorySwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Memory needed for remote debugging sessions. */ ulResult = Oct6100ApiGetRemoteDebugSwSizes( f_pChipOpen, f_pInstSizes ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Calculate total memory needed by pointers internal to API instance. The total contains both the process specific portion of the instance (tOCT6100_INSTANCE_API) and the shared portion (tOCT6100_SHARED_INFO). The process specific portion will be used only in the case where the host system is a single-process one. */ ulApiInstProcessSpecific = sizeof( tOCT6100_INSTANCE_API ); mOCT6100_ROUND_MEMORY_SIZE( ulApiInstProcessSpecific, ulTempVar ) f_pInstSizes->ulApiInstTotal = f_pInstSizes->ulChannelList + f_pInstSizes->ulChannelAlloc + f_pInstSizes->ulTsiCnctList + f_pInstSizes->ulTsiCnctAlloc + f_pInstSizes->ulSoftToneEventsBuffer + f_pInstSizes->ulSoftBufPlayoutEventsBuffer + f_pInstSizes->ulBiDirChannelList + f_pInstSizes->ulBiDirChannelAlloc + f_pInstSizes->ulConfBridgeList + f_pInstSizes->ulConfBridgeAlloc + f_pInstSizes->ulFlexConfParticipantsList + f_pInstSizes->ulFlexConfParticipantsAlloc + f_pInstSizes->ulPlayoutBufList + f_pInstSizes->ulPlayoutBufAlloc + f_pInstSizes->ulPlayoutBufMemoryNodeList + f_pInstSizes->ulCopyEventList + f_pInstSizes->ulCopyEventAlloc + f_pInstSizes->ulMixerEventList + f_pInstSizes->ulMixerEventAlloc + f_pInstSizes->ulPhasingTsstList + f_pInstSizes->ulPhasingTsstAlloc + f_pInstSizes->ulAdpcmChannelList + f_pInstSizes->ulAdpcmChannelAlloc + f_pInstSizes->ulConversionMemoryAlloc + f_pInstSizes->ulTsiMemoryAlloc + f_pInstSizes->ulRemoteDebugList + f_pInstSizes->ulRemoteDebugTree + f_pInstSizes->ulRemoteDebugPktCache + f_pInstSizes->ulRemoteDebugDataBuf + f_pInstSizes->ulTsstEntryList + f_pInstSizes->ulTsstEntryAlloc + f_pInstSizes->ulTsstAlloc + f_pInstSizes->ulApiInstStatic + ulApiInstProcessSpecific; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAllocateInstanceMemory Description: Allocates the API instance memory to the various members of the structure f_pApiInstance according to the sizes contained in f_pInstSizes. No initialization of this memory is performed. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pInstSizes Pointer to structure containing the size of memory needed by all pointers internal to the API instance. The memory is needed to keep track of the present state of all the chip's resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAllocateInstanceMemory UINT32 Oct6100ApiAllocateInstanceMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulOffset; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get address of first UINT32 of memory in API instance structure following */ /* the static members of the API instance structure. */ ulOffset = f_pInstSizes->ulApiInstStatic; /*===================================================================*/ /* Allocate memory for the echo channels.*/ pSharedInfo->ulChannelListOfst = ulOffset; ulOffset += f_pInstSizes->ulChannelList; pSharedInfo->ulChannelAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulChannelAlloc; /*===================================================================*/ /* Allocate memory for the TSI connections */ pSharedInfo->ulTsiCnctListOfst = ulOffset; ulOffset += f_pInstSizes->ulTsiCnctList; pSharedInfo->ulTsiCnctAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulTsiCnctAlloc; pSharedInfo->ulMixerEventListOfst = ulOffset; ulOffset += f_pInstSizes->ulMixerEventList; pSharedInfo->ulMixerEventAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulMixerEventAlloc; pSharedInfo->ulBiDirChannelListOfst = ulOffset; ulOffset += f_pInstSizes->ulBiDirChannelList; pSharedInfo->ulBiDirChannelAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulBiDirChannelAlloc; pSharedInfo->ulCopyEventListOfst = ulOffset; ulOffset += f_pInstSizes->ulCopyEventList; pSharedInfo->ulCopyEventAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulCopyEventAlloc; /*===================================================================*/ /* Allocate memory for the conference bridges */ pSharedInfo->ulConfBridgeListOfst = ulOffset; ulOffset += f_pInstSizes->ulConfBridgeList; pSharedInfo->ulConfBridgeAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulConfBridgeAlloc; /*===================================================================*/ /* Allocate memory for the flexible conferencing participants. */ pSharedInfo->ulFlexConfParticipantListOfst = ulOffset; ulOffset += f_pInstSizes->ulFlexConfParticipantsList; pSharedInfo->ulFlexConfParticipantAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulFlexConfParticipantsAlloc; /*===================================================================*/ /* Allocate memory for the play-out buffers */ pSharedInfo->ulPlayoutBufListOfst = ulOffset; ulOffset += f_pInstSizes->ulPlayoutBufList; pSharedInfo->ulPlayoutBufAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulPlayoutBufAlloc; pSharedInfo->ulPlayoutBufMemoryNodeListOfst = ulOffset; ulOffset += f_pInstSizes->ulPlayoutBufMemoryNodeList; /*===================================================================*/ /* Allocate memory for the phasing TSSTs */ pSharedInfo->ulPhasingTsstListOfst = ulOffset; ulOffset += f_pInstSizes->ulPhasingTsstList; pSharedInfo->ulPhasingTsstAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulPhasingTsstAlloc; /*===================================================================*/ /* Allocate memory for the ADPCM channel */ pSharedInfo->ulAdpcmChanAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulAdpcmChannelAlloc; pSharedInfo->ulAdpcmChanListOfst = ulOffset; ulOffset += f_pInstSizes->ulAdpcmChannelList; /*===================================================================*/ /* Allocate memory for the conversion memory */ pSharedInfo->ulConversionMemoryAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulConversionMemoryAlloc; /*===================================================================*/ /* Allocate memory for the TSI chariot memory */ pSharedInfo->ulTsiMemoryAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulTsiMemoryAlloc; /*===================================================================*/ /* Allocate memory for the TSST management */ pSharedInfo->ulTsstAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulTsstAlloc; pSharedInfo->ulTsstListOfst = ulOffset; ulOffset += f_pInstSizes->ulTsstEntryList; pSharedInfo->ulTsstListAllocOfst = ulOffset; ulOffset += f_pInstSizes->ulTsstEntryAlloc; /*===================================================================*/ pSharedInfo->SoftBufs.ulToneEventBufferMemOfst = ulOffset; ulOffset += f_pInstSizes->ulSoftToneEventsBuffer; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferMemOfst = ulOffset; ulOffset += f_pInstSizes->ulSoftBufPlayoutEventsBuffer; /*===================================================================*/ pSharedInfo->RemoteDebugInfo.ulSessionListOfst = ulOffset; ulOffset += f_pInstSizes->ulRemoteDebugList; pSharedInfo->RemoteDebugInfo.ulSessionTreeOfst = ulOffset; ulOffset += f_pInstSizes->ulRemoteDebugTree; pSharedInfo->RemoteDebugInfo.ulDataBufOfst = ulOffset; ulOffset += f_pInstSizes->ulRemoteDebugDataBuf; pSharedInfo->RemoteDebugInfo.ulPktCacheOfst = ulOffset; ulOffset += f_pInstSizes->ulRemoteDebugPktCache; /*===================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitializeInstanceMemory Description: Initializes the various members of the structure f_pApiInstance to reflect the current state of the chip and its resources. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitializeInstanceMemory UINT32 Oct6100ApiInitializeInstanceMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { UINT32 ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize API EC channels. */ ulResult = Oct6100ApiChannelsEchoSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the API TSI connection structures. */ ulResult = Oct6100ApiTsiCnctSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the API conference bridges. */ ulResult = Oct6100ApiConfBridgeSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the API buffer playout structures. */ ulResult = Oct6100ApiPlayoutBufferSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the API phasing tssts. */ ulResult = Oct6100ApiPhasingTsstSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the API ADPCM channels. */ ulResult = Oct6100ApiAdpcmChanSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the external memory management structures. */ ulResult = Oct6100ApiMemorySwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize TSST management stuctures. */ ulResult = Oct6100ApiTsstSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the mixer management stuctures. */ ulResult = Oct6100ApiMixerSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Initialize the remote debugging session management variables. */ ulResult = Oct6100ApiRemoteDebuggingSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*-----------------------------------------------------------------------------*/ /* Configure the interrupt registers. */ ulResult = Oct6100ApiIsrSwInit( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetChipRevisionNum Description: Reads the chip's revision number register. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetChipRevisionNum UINT32 Oct6100ApiGetChipRevisionNum( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usReadData; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get the chip revision number. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.ulReadAddress = cOCT6100_CHIP_ID_REVISION_REG; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save the info in the API miscellaneous structure. */ pSharedInfo->MiscVars.usChipId = (UINT16)( usReadData & 0xFF ); pSharedInfo->MiscVars.usChipRevision = (UINT16)( usReadData >> 8 ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckImageFileHeader Description: This function check if the image loaded is valid ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckImageFileHeader UINT32 Oct6100ApiCheckImageFileHeader( IN tPOCT6100_CHIP_OPEN f_pChipOpen ) { PUINT8 pszImageInfoStart = NULL; UINT32 ulStrLen; ulStrLen = Oct6100ApiStrLen( (PUINT8)cOCT6100_IMAGE_START_STRING ); pszImageInfoStart = (PUINT8) Oct6100ApiStrStr(f_pChipOpen->pbyImageFile,(PUINT8)cOCT6100_IMAGE_START_STRING, f_pChipOpen->pbyImageFile + ulStrLen); if (pszImageInfoStart == NULL) return cOCT6100_ERR_OPEN_IMAGE_FILE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiDecodeKeyAndBist Description: This function decodes the key and runs the automatic BIST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiDecodeKeyAndBist UINT32 Oct6100ApiDecodeKeyAndBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT16 ausBistData[ 3 ]; UINT16 usReadData; UINT32 ulResult; BOOL fBitEqual; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a local pointer to the chip config structure */ /* contained in the instance structure. */ pChipConfig = &pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pChipConfig->ulUserChipId; /* Set the process context and user chip ID parameters once and for all. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pChipConfig->ulUserChipId; /* Write key in CPU internal memory. */ for(i=0; i<8; i++) { WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = 0x0000; if (( i % 2 ) == 0) { WriteParams.usWriteData |= ((UINT16)pChipConfig->pbyImageFile[0x100 + ((i/2)*4) + 2]) << 8; WriteParams.usWriteData |= ((UINT16)pChipConfig->pbyImageFile[0x100 + ((i/2)*4) + 3]) << 0; } else { WriteParams.usWriteData |= ((UINT16)pChipConfig->pbyImageFile[0x100 + ((i/2)*4) + 0]) << 8; WriteParams.usWriteData |= ((UINT16)pChipConfig->pbyImageFile[0x100 + ((i/2)*4) + 1]) << 0; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x152; WriteParams.usWriteData = (UINT16)( 0x8000 | i ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Write one in CPU internal memory. */ for(i=0; i<8; i++) { WriteParams.ulWriteAddress = 0x150; if (i == 0) { WriteParams.usWriteData = 0x0001; } else { WriteParams.usWriteData = 0x0000; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x152; WriteParams.usWriteData = (UINT16)( 0x8000 | ( i + 8 )); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Clear memory access registers: */ WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x152; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Run BISTs and key decode. */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0081; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for the key decode PC to clear. */ ulResult = Oct6100ApiWaitForPcRegisterBit( f_pApiInstance, 0x160, 0, 0, 100000, &fBitEqual ); if ( TRUE != fBitEqual ) return cOCT6100_ERR_FATAL_13; /* Read the key valid bit to make sure everything is ok. */ ReadParams.ulReadAddress = 0x160; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Either the firmware image was not loaded correctly (from pointer given by user) */ /* or the channel capacity pins of the chip do not match what the firmware is expecting. */ if ( ( usReadData & 0x4 ) == 0 ) return cOCT6100_ERR_OPEN_INVALID_FIRMWARE_OR_CAPACITY_PINS; /* Read the result of the internal memory bist. */ ReadParams.ulReadAddress = 0x110; ReadParams.pusReadData = &ausBistData[ 0 ]; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ReadParams.ulReadAddress = 0x114; ReadParams.pusReadData = &ausBistData[ 1 ]; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ReadParams.ulReadAddress = 0x118; ReadParams.pusReadData = &ausBistData[ 2 ]; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if an error was reported. */ if (ausBistData[0] != 0x0000 || ausBistData[1] != 0x0000 || ausBistData[2] != 0x0000) return cOCT6100_ERR_OPEN_INTERNAL_MEMORY_BIST; /* Put key decoder in powerdown. */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x008A; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBootFc2PllReadCap Description: Configures the chip's FC2 PLL. Special version for GetcapacityPins. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ UINT32 Oct6100ApiBootFc2PllReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 aulWaitTime[ 2 ]; UINT32 ulResult; UINT32 ulFc2PllDivisor = 0; UINT32 ulMtDivisor = 0; UINT32 ulFcDivisor = 0; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pGetCapacityPins->pProcessContext; WriteParams.ulUserChipId = f_pGetCapacityPins->ulUserChipId; /* First put the chip and main registers in soft-reset. */ WriteParams.ulWriteAddress = 0x100; WriteParams.usWriteData = 0x0; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulFc2PllDivisor = 0x1050; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; /* Setup delay chains. */ if ( (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR) || (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { /* SDRAM */ WriteParams.ulWriteAddress = 0x1B0; WriteParams.usWriteData = 0x1003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B2; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B4; WriteParams.usWriteData = 0x4030; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B6; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* if ( cOCT6100_MEM_TYPE_DDR == pChipConfig->byMemoryType ) */ { /* DDR */ WriteParams.ulWriteAddress = 0x1B0; WriteParams.usWriteData = 0x201F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B2; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B4; WriteParams.usWriteData = 0x1000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B6; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* udqs */ WriteParams.ulWriteAddress = 0x1B8; WriteParams.usWriteData = 0x1003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1BA; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* ldqs */ WriteParams.ulWriteAddress = 0x1BC; WriteParams.usWriteData = 0x1000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1BE; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x12C; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x12E; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select fc2pll for fast_clk and mtsclk sources. Select mem_clk_i for afclk. */ WriteParams.ulWriteAddress = 0x140; WriteParams.usWriteData = (UINT16)ulMtDivisor; if ( f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) WriteParams.usWriteData |= 0x0001; else WriteParams.usWriteData |= 0x0004; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x144; WriteParams.usWriteData = (UINT16)ulFcDivisor; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x13E; WriteParams.usWriteData = 0x0001; /* Remove reset from above divisors */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select upclk directly as ref source for fc2pll. */ WriteParams.ulWriteAddress = 0x134; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Setup fc2pll. */ WriteParams.ulWriteAddress = 0x132; WriteParams.usWriteData = (UINT16)ulFc2PllDivisor; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.usWriteData |= 0x02; /* Raise fb divisor reset. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.usWriteData |= 0x80; /* Raise IDDTN signal.*/ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for fc2pll to stabilize. */ aulWaitTime[ 0 ] = 2000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Drive mem_clk_o out on proper interface. */ if ( TRUE == f_pGetCapacityPins->fEnableMemClkOut ) { if ( (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR) || (f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { WriteParams.ulWriteAddress = 0x128; WriteParams.usWriteData = 0x0301; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_DDR || f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) { WriteParams.ulWriteAddress = 0x12A; WriteParams.usWriteData = 0x000F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBootFc2Pll Description: Configures the chip's FC2 PLL. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBootFc2Pll UINT32 Oct6100ApiBootFc2Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; UINT32 aulWaitTime[ 2 ]; UINT32 ulResult; UINT32 ulFc2PllDivisor = 0; UINT32 ulMtDivisor = 0; UINT32 ulFcDivisor = 0; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain local pointer to chip configuration structure. */ pChipConfig = &pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pChipConfig->ulUserChipId; /* First put the chip and main registers in soft-reset. */ WriteParams.ulWriteAddress = 0x100; WriteParams.usWriteData = 0x0; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select register configuration based on the memory frequency. */ switch ( f_pApiInstance->pSharedInfo->ChipConfig.ulMemClkFreq ) { case 133000000: ulFc2PllDivisor = 0x1050; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 672; pSharedInfo->MiscVars.usMaxH100Speed = 124; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x050B; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x0516; break; case 125000000: ulFc2PllDivisor = 0x0F50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 624; pSharedInfo->MiscVars.usMaxH100Speed = 116; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x04CA; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x04D4; break; case 117000000: ulFc2PllDivisor = 0x0E50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 576; pSharedInfo->MiscVars.usMaxH100Speed = 108; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x0489; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x0492; break; case 108000000: ulFc2PllDivisor = 0x0D50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 528; pSharedInfo->MiscVars.usMaxH100Speed = 99; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x0408; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x0410; break; case 100000000: ulFc2PllDivisor = 0x0C50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 480; pSharedInfo->MiscVars.usMaxH100Speed = 91; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x03C8; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x03D0; break; case 92000000: ulFc2PllDivisor = 0x0B50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 432; pSharedInfo->MiscVars.usMaxH100Speed = 83; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x0387; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x038E; break; case 83000000: ulFc2PllDivisor = 0x0A50; ulMtDivisor = 0x4300; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 384; pSharedInfo->MiscVars.usMaxH100Speed = 74; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x0346; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x034C; break; case 75000000: ulFc2PllDivisor = 0x0950; ulMtDivisor = 0x4200; ulFcDivisor = 0x4043; pSharedInfo->MiscVars.usMaxNumberOfChannels = 336; pSharedInfo->MiscVars.usMaxH100Speed = 64; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) pSharedInfo->MiscVars.usTdmClkBoundary = 0x0306; else pSharedInfo->MiscVars.usTdmClkBoundary = 0x030C; break; default: return cOCT6100_ERR_FATAL_DB; } /* Verify that the max channel is not too big based on the chip frequency. */ if ( pSharedInfo->ChipConfig.usMaxChannels > pSharedInfo->MiscVars.usMaxNumberOfChannels ) return cOCT6100_ERR_OPEN_MAX_ECHO_CHANNELS; /* Setup delay chains. */ if ( (pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_SDR) || (pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { /* SDRAM */ WriteParams.ulWriteAddress = 0x1B0; WriteParams.usWriteData = 0x1003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B2; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B4; WriteParams.usWriteData = 0x4030; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B6; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* if ( cOCT6100_MEM_TYPE_DDR == pChipConfig->byMemoryType ) */ { /* DDR */ WriteParams.ulWriteAddress = 0x1B0; WriteParams.usWriteData = 0x201F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B2; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B4; WriteParams.usWriteData = 0x1000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1B6; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* udqs */ WriteParams.ulWriteAddress = 0x1B8; WriteParams.usWriteData = 0x1003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1BA; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* ldqs */ WriteParams.ulWriteAddress = 0x1BC; WriteParams.usWriteData = 0x1000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x1BE; WriteParams.usWriteData = 0x0021; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x12C; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x12E; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select fc2pll for fast_clk and mtsclk sources. Select mem_clk_i for afclk. */ WriteParams.ulWriteAddress = 0x140; WriteParams.usWriteData = (UINT16)ulMtDivisor; if ( f_pApiInstance->pSharedInfo->ChipConfig.byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) WriteParams.usWriteData |= 0x0001; else WriteParams.usWriteData |= 0x0004; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x144; WriteParams.usWriteData = (UINT16)ulFcDivisor; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x13E; WriteParams.usWriteData = 0x0001; /* Remove reset from above divisors */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select upclk directly as ref source for fc2pll. */ WriteParams.ulWriteAddress = 0x134; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Setup fc2pll. */ WriteParams.ulWriteAddress = 0x132; WriteParams.usWriteData = (UINT16)ulFc2PllDivisor; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.usWriteData |= 0x02; /* Raise fb divisor reset. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.usWriteData |= 0x80; /* Raise IDDTN signal.*/ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for fc2pll to stabilize. */ aulWaitTime[ 0 ] = 2000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Drive mem_clk_o out on proper interface. */ if ( TRUE == pChipConfig->fEnableMemClkOut ) { if ( (pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_SDR) || (pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { WriteParams.ulWriteAddress = 0x128; WriteParams.usWriteData = 0x0301; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_DDR || pChipConfig->byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) { WriteParams.ulWriteAddress = 0x12A; WriteParams.usWriteData = 0x000F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiProgramFc1PllReadCap Description: Configures the chip's FC1 PLL. Special version for getCapacityPins. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ UINT32 Oct6100ApiProgramFc1PllReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 aulWaitTime[ 2 ]; UINT32 ulResult; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pGetCapacityPins->ulUserChipId; /* Programm P/Z bits. */ WriteParams.ulWriteAddress = 0x130; if ( f_pGetCapacityPins->ulMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) WriteParams.usWriteData = 0x0041; else WriteParams.usWriteData = 0x0040; WriteParams.usWriteData |= ( f_pGetCapacityPins->ulMemoryType << 8 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Raise FB divisor. */ WriteParams.usWriteData |= 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Raise IDDTN. */ WriteParams.usWriteData |= 0x0080; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for fc1pll to stabilize. */ aulWaitTime[ 0 ] = 2000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable all the clock domains to do reset procedure. */ WriteParams.ulWriteAddress = 0x186; WriteParams.usWriteData = 0x015F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; aulWaitTime[ 0 ] = 15000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiProgramFc1Pll Description: Configures the chip's FC1 PLL. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiProgramFc1Pll UINT32 Oct6100ApiProgramFc1Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; UINT32 aulWaitTime[ 2 ]; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain local pointer to chip configuration structure. */ pChipConfig = &pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pChipConfig->ulUserChipId; /* Programm P/Z bits. */ WriteParams.ulWriteAddress = 0x130; if ( f_pApiInstance->pSharedInfo->ChipConfig.byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS ) WriteParams.usWriteData = 0x0041; else WriteParams.usWriteData = 0x0040; WriteParams.usWriteData |= ( pChipConfig->byMemoryType << 8 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Raise FB divisor. */ WriteParams.usWriteData |= 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Raise IDDTN. */ WriteParams.usWriteData |= 0x0080; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for fc1pll to stabilize. */ aulWaitTime[ 0 ] = 2000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable all the clock domains to do reset procedure. */ WriteParams.ulWriteAddress = 0x186; WriteParams.usWriteData = 0x015F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; aulWaitTime[ 0 ] = 15000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBootFc1Pll Description: Boot the chip's FC1 PLL. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBootFc1Pll UINT32 Oct6100ApiBootFc1Pll( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; UINT32 aulWaitTime[ 2 ]; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain local pointer to chip configuration structure. */ pChipConfig = &pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pChipConfig->ulUserChipId; /* Force bist_clk also (it too is used on resetable flops). */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0188; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Force all cpu clocks on chariot controllers. */ WriteParams.ulWriteAddress = 0x182; WriteParams.usWriteData = 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x184; WriteParams.usWriteData = 0x0202; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; aulWaitTime[ 0 ] = 1000; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Remove the reset on the entire chip and disable CPU access caching. */ WriteParams.ulWriteAddress = 0x100; WriteParams.usWriteData = 0x2003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Remove the bist_clk. It is no longer needed.*/ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0088; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Disable all clks to prepare for bist clock switchover. */ WriteParams.ulWriteAddress = 0x182; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x186; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x184; WriteParams.usWriteData = 0x0101; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Deassert bist_active */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0008; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Change CPU interface to normal mode (from boot mode). */ WriteParams.ulWriteAddress = 0x154; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Give a couple of BIST clock cycles to turn off the BIST permanently. */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0108; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Turn BIST clock off for the last time. */ WriteParams.ulWriteAddress = 0x160; WriteParams.usWriteData = 0x0008; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reset procedure done! */ /* Enable mclk for cpu interface and external memory controller. */ WriteParams.ulWriteAddress = 0x186; WriteParams.usWriteData = 0x0100; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiLoadImage Description: This function writes the firmware image in the external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiLoadImage UINT32 Oct6100ApiLoadImage( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_BURST_PARAMS BurstParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 ulTempPtr; UINT32 ulNumWrites; PUINT16 pusSuperArray; unsigned char const *pbyImageFile; UINT32 ulByteCount = 0; UINT16 usReadData; UINT32 ulAddressOfst; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Breakdown image into subcomponents. */ ulTempPtr = cOCT6100_IMAGE_FILE_BASE + cOCT6100_IMAGE_AF_CST_OFFSET; for(i=0;iImageRegion[ i ].ulPart1Size = pSharedInfo->ChipConfig.pbyImageFile[ 0x110 + ( i * 4 ) + 0 ]; pSharedInfo->ImageRegion[ i ].ulPart2Size = pSharedInfo->ChipConfig.pbyImageFile[ 0x110 + ( i * 4 ) + 1 ]; pSharedInfo->ImageRegion[ i ].ulClockInfo = pSharedInfo->ChipConfig.pbyImageFile[ 0x110 + ( i * 4 ) + 2 ]; pSharedInfo->ImageRegion[ i ].ulReserved = pSharedInfo->ChipConfig.pbyImageFile[ 0x110 + ( i * 4 ) + 3 ]; if (i == 0) /* AF constant. */ { pSharedInfo->ImageRegion[ i ].ulPart1BaseAddress = ulTempPtr & 0x07FFFFFF; pSharedInfo->ImageRegion[ i ].ulPart2BaseAddress = 0; ulTempPtr += ( pSharedInfo->ImageRegion[ i ].ulPart1Size * 612 ); } else if (i == 1) /* NLP image */ { pSharedInfo->ImageRegion[ i ].ulPart1BaseAddress = ulTempPtr & 0x07FFFFFF; pSharedInfo->ImageRegion[ i ].ulPart2BaseAddress = 0; ulTempPtr += ( pSharedInfo->ImageRegion[ i ].ulPart1Size * 2056 ); } else /* Others */ { pSharedInfo->ImageRegion[ i ].ulPart1BaseAddress = ulTempPtr & 0x07FFFFFF; ulTempPtr += ( pSharedInfo->ImageRegion[ i ].ulPart1Size * 2064 ); pSharedInfo->ImageRegion[ i ].ulPart2BaseAddress = ulTempPtr & 0x07FFFFFF; ulTempPtr += ( pSharedInfo->ImageRegion[ i ].ulPart2Size * 2448 ); } } /* Write the image in external memory. */ ulNumWrites = pSharedInfo->ChipConfig.ulImageSize / 2; BurstParams.ulWriteAddress = cOCT6100_IMAGE_FILE_BASE; BurstParams.pusWriteData = pSharedInfo->MiscVars.ausSuperArray; pusSuperArray = pSharedInfo->MiscVars.ausSuperArray; pbyImageFile = pSharedInfo->ChipConfig.pbyImageFile; while ( ulNumWrites != 0 ) { if ( ulNumWrites >= pSharedInfo->ChipConfig.usMaxRwAccesses ) BurstParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else BurstParams.ulWriteLength = ulNumWrites; for ( i = 0; i < BurstParams.ulWriteLength; i++ ) { pusSuperArray[ i ] = ( UINT16 )(( pbyImageFile [ ulByteCount++ ]) << 8); pusSuperArray[ i ] |= ( UINT16 )pbyImageFile [ ulByteCount++ ]; } mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BurstParams.ulWriteAddress += 2 * BurstParams.ulWriteLength; ulNumWrites -= BurstParams.ulWriteLength; } /* Perform a serie of reads to make sure the image was correclty written into memory. */ ulAddressOfst = ( pSharedInfo->ChipConfig.ulImageSize / 2 ) & 0xFFFFFFFE; while ( ulAddressOfst != 0 ) { ReadParams.ulReadAddress = cOCT6100_IMAGE_FILE_BASE + ulAddressOfst; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (usReadData >> 8) != pbyImageFile[ ulAddressOfst ] ) return cOCT6100_ERR_OPEN_IMAGE_WRITE_FAILED; ulAddressOfst = (ulAddressOfst / 2) & 0xFFFFFFFE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCpuRegisterBistReadCap Description: Tests the operation of the CPU registers. Special Version for GetCapacityPins ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ UINT32 Oct6100ApiCpuRegisterBistReadCap( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_GET_CAPACITY_PINS f_pGetCapacityPins ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 i; UINT16 usReadData; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pGetCapacityPins->ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pGetCapacityPins->ulUserChipId; /* Assign read data pointer that will be used throughout the function. */ ReadParams.pusReadData = &usReadData; /* Start with a walking bit test. */ for ( i = 0; i < 16; i ++ ) { /* Write at address 0x150.*/ WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = (UINT16)( 0x1 << i ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write at address 0x180.*/ WriteParams.ulWriteAddress = 0x180; WriteParams.usWriteData = (UINT16)( 0x1 << ( 15 - i ) ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now read back the two registers to make sure the acceses were successfull. */ ReadParams.ulReadAddress = 0x150; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != ( 0x1 << i ) ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; ReadParams.ulReadAddress = 0x180; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != ( 0x1 << ( 15 - i ) ) ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; } /* Write at address 0x150. */ WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = 0xCAFE; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write at address 0x180. */ WriteParams.ulWriteAddress = 0x180; WriteParams.usWriteData = 0xDECA; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now read back the two registers to make sure the acceses were successfull. */ ReadParams.ulReadAddress = 0x150; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != 0xCAFE ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; ReadParams.ulReadAddress = 0x180; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != 0xDECA ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; return cOCT6100_ERR_OK; } /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCpuRegisterBist Description: Tests the operation of the CPU registers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCpuRegisterBist UINT32 Oct6100ApiCpuRegisterBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 i; UINT16 usReadData; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Assign read data pointer that will be used throughout the function. */ ReadParams.pusReadData = &usReadData; /* Start with a walking bit test. */ for ( i = 0; i < 16; i ++ ) { /* Write at address 0x150.*/ WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = (UINT16)( 0x1 << i ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write at address 0x180.*/ WriteParams.ulWriteAddress = 0x180; WriteParams.usWriteData = (UINT16)( 0x1 << ( 15 - i ) ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now read back the two registers to make sure the acceses were successfull. */ ReadParams.ulReadAddress = 0x150; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != ( 0x1 << i ) ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; ReadParams.ulReadAddress = 0x180; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != ( 0x1 << ( 15 - i ) ) ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; } /* Write at address 0x150. */ WriteParams.ulWriteAddress = 0x150; WriteParams.usWriteData = 0xCAFE; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write at address 0x180. */ WriteParams.ulWriteAddress = 0x180; WriteParams.usWriteData = 0xDECA; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now read back the two registers to make sure the acceses were successfull. */ ReadParams.ulReadAddress = 0x150; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != 0xCAFE ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; ReadParams.ulReadAddress = 0x180; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != 0xDECA ) return cOCT6100_ERR_OPEN_CPU_REG_BIST_ERROR; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBootSdram Description: Configure and test the SDRAM. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBootSdram UINT32 Oct6100ApiBootSdram( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usReadData; UINT16 usWriteData23E; UINT16 usWriteData230; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get local pointer to the chip configuration structure.*/ pChipConfig = &f_pApiInstance->pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; usWriteData23E = 0x0000; usWriteData230 = 0x0000; if ( (pSharedInfo->ChipConfig.byMemoryType == cOCT6100_MEM_TYPE_SDR) || (pSharedInfo->ChipConfig.byMemoryType == cOCT6100_MEM_TYPE_SDR_PLL_BYPASS) ) { /* SDRAM: */ switch( pChipConfig->ulMemoryChipSize ) { case cOCT6100_MEMORY_CHIP_SIZE_8MB: usWriteData230 |= ( cOCT6100_16MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_16MB: usWriteData230 |= ( cOCT6100_32MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_32MB: usWriteData230 |= ( cOCT6100_64MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_64MB: usWriteData230 |= ( cOCT6100_128MB_MEMORY_BANKS << 2 ); break; default: return cOCT6100_ERR_FATAL_16; } usWriteData230 |= 0x0002; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Precharge all banks. */ usWriteData230 &= 0x000C; usWriteData230 |= 0x0010; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Program the mode register. */ usWriteData23E = 0x0030; WriteParams.usWriteData = usWriteData23E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 &= 0x000C; usWriteData230 |= 0x0000; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Do CBR refresh (twice) */ usWriteData230 &= 0x000C; usWriteData230 |= 0x0040; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { /* DDR: */ switch( pChipConfig->ulMemoryChipSize ) { case cOCT6100_MEMORY_CHIP_SIZE_16MB: usWriteData230 |= ( cOCT6100_16MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_32MB: usWriteData230 |= ( cOCT6100_32MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_64MB: usWriteData230 |= ( cOCT6100_64MB_MEMORY_BANKS << 2 ); break; case cOCT6100_MEMORY_CHIP_SIZE_128MB: usWriteData230 |= ( cOCT6100_128MB_MEMORY_BANKS << 2 ); break; default: return cOCT6100_ERR_FATAL_17; } WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Precharge all banks. */ usWriteData230 &= 0x000C; usWriteData230 |= 0x0010; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Program DDR mode register. */ usWriteData23E = 0x4000; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 &= 0x000C; usWriteData230 |= 0x0000; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Program SDR mode register. */ usWriteData23E = 0x0161; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 &= 0x000C; usWriteData230 |= 0x0000; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Precharge all banks. */ usWriteData23E = 0xFFFF; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 &= 0x000C; usWriteData230 |= 0x0010; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Do CBR refresh (twice) */ usWriteData230 &= 0x000C; usWriteData230 |= 0x0040; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle.*/ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Program SDR mode register. */ usWriteData23E = 0x0061; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 &= 0x000C; usWriteData230 |= 0x0000; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usWriteData230 |= 0x0002; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x23E; WriteParams.usWriteData = usWriteData23E; for ( i = 0; i < 5; i++ ) { /* Wait cycle. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the refresh frequency. */ WriteParams.ulWriteAddress = 0x242; WriteParams.usWriteData = 0x0400; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x244; WriteParams.usWriteData = 0x0200; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x248; WriteParams.usWriteData = 0x800; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x246; WriteParams.usWriteData = 0x0012; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable the SDRAM and refreshes. */ usWriteData230 &= 0x000C; usWriteData230 |= 0x0001; WriteParams.ulWriteAddress = 0x230; WriteParams.usWriteData = usWriteData230; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x246; WriteParams.usWriteData = 0x0013; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiEnableClocks Description: This function will disable clock masking for all the modules of the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiEnableClocks UINT32 Oct6100ApiEnableClocks( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Initialize the process context and user chip ID once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Enable tdmie / adpcm mclk clocks. */ WriteParams.ulWriteAddress = 0x186; WriteParams.usWriteData = 0x015F; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the DQS register for the DDR memory */ WriteParams.ulWriteAddress = 0x180; WriteParams.usWriteData = 0xFF00; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable pgsp chariot clocks */ WriteParams.ulWriteAddress = 0x182; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable af/mt chariot clocks */ WriteParams.ulWriteAddress = 0x184; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiProgramNLP Description: This function will write image values to configure the NLP. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiProgramNLP UINT32 Oct6100ApiProgramNLP( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; UINT32 ulResult; UINT16 usReadData; UINT16 usReadHighData; BOOL fBitEqual; UINT32 ulEgoEntry[4]; UINT32 ulTempAddress; UINT32 ulAfCpuUp = FALSE; UINT32 i; UINT32 ulLoopCounter = 0; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get local pointer to the chip configuration structure.*/ pChipConfig = &f_pApiInstance->pSharedInfo->ChipConfig; /* Initialize the process context and user chip ID once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Initialize the process context and user chip ID once and for all. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; if ( pSharedInfo->ChipConfig.fEnableProductionBist == TRUE ) { UINT32 ulReadData; UINT32 ulBitPattern; UINT32 j, k; /* Since the pouch section (256 bytes) will not be tested by the firmware, */ /* the API has to make sure this section is working correctly. */ for ( k = 0; k < 2; k ++ ) { if ( k == 0 ) ulBitPattern = 0x1; else ulBitPattern = 0xFFFFFFFE; for ( j = 0; j < 32; j ++ ) { /* Write the DWORDs. */ for ( i = 0; i < 64; i ++ ) { ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + i * 4, ulBitPattern << j ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Read the DWORDs. */ for ( i = 0; i < 64; i ++ ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + i * 4, &ulReadData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the value matches. */ if ( ( ulBitPattern << j ) != ulReadData ) return cOCT6100_ERR_OPEN_PRODUCTION_BIST_POUCH_ERROR; } } } } /* Write the image info in the chip. */ WriteParams.ulWriteAddress = cOCT6100_PART1_END_STATICS_BASE; WriteParams.usWriteData = (UINT16)( ( pSharedInfo->ImageRegion[ 0 ].ulPart1BaseAddress >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( pSharedInfo->ImageRegion[ 0 ].ulPart1BaseAddress & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; for( i = 0; i < 8; i++ ) { if ( pSharedInfo->ImageRegion[ i + 2 ].ulPart1Size != 0 ) { WriteParams.ulWriteAddress = cOCT6100_PART1_END_STATICS_BASE + 0x4 + ( i * 0xC ); WriteParams.usWriteData = (UINT16)(( pSharedInfo->ImageRegion[ i + 2 ].ulPart1BaseAddress >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( pSharedInfo->ImageRegion[ i + 2 ].ulPart1BaseAddress & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pSharedInfo->ImageRegion[ i + 2 ].ulPart2Size != 0 ) { WriteParams.ulWriteAddress = cOCT6100_PART1_END_STATICS_BASE + 0x4 + ( i * 0xC ) + 4; WriteParams.usWriteData = (UINT16)(( pSharedInfo->ImageRegion[ i + 2 ].ulPart2BaseAddress >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( pSharedInfo->ImageRegion[ i + 2 ].ulPart2BaseAddress & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } WriteParams.ulWriteAddress = cOCT6100_PART1_END_STATICS_BASE + 0x4 + ( i * 0xC ) + 8; WriteParams.usWriteData = 0x0000; WriteParams.usWriteData |= ( pSharedInfo->ImageRegion[ i + 2 ].ulPart1Size << 8 ); WriteParams.usWriteData |= pSharedInfo->ImageRegion[ i + 2 ].ulPart2Size; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = 0x0000; WriteParams.usWriteData |= ( pSharedInfo->ImageRegion[ i + 2 ].ulClockInfo << 8 ); WriteParams.usWriteData |= pSharedInfo->ImageRegion[ i + 2 ].ulReserved; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Put NLP in config mode. */ WriteParams.ulWriteAddress = 0x2C2; WriteParams.usWriteData = 0x160E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x692; WriteParams.usWriteData = 0x010A; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Upload the up to 8 NLP pages + 1 AF page (for timing reasons). */ for ( i = 0; i < pSharedInfo->ImageRegion[ 1 ].ulPart1Size; i++ ) { ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 1 ].ulPart1BaseAddress + 1028 * ( i * 2 ), 0x1280, 1024, &(ulEgoEntry[0])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 1 ].ulPart1BaseAddress + 1028 * (( i * 2 ) + 1 ), 0x1680, 1024, &(ulEgoEntry[2])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiRunEgo( f_pApiInstance, FALSE, 2, ulEgoEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Shift mt chariot memories. This process will complete by the time */ /* the next LSU transfer is done. */ WriteParams.ulWriteAddress = 0x692; WriteParams.usWriteData = 0x010B; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiWaitForPcRegisterBit( f_pApiInstance, 0x692, 0, 0, 100000, &fBitEqual ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( TRUE != fBitEqual ) return cOCT6100_ERR_FATAL_1A; } /* 1 AF page (for timing reasons). */ ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 2 ].ulPart1BaseAddress + (516 * 0), 0x1280, 512, &(ulEgoEntry[0])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 2 ].ulPart1BaseAddress + (516 * 1), 0x1480, 512, &(ulEgoEntry[2])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiRunEgo( f_pApiInstance, FALSE, 2, ulEgoEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 2 ].ulPart1BaseAddress + (516 * 2), 0x1680, 512, &(ulEgoEntry[0])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiCreateEgoEntry( cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + pSharedInfo->ImageRegion[ 2 ].ulPart1BaseAddress + (516 * 3), 0x1880, 512, &(ulEgoEntry[2])); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiRunEgo( f_pApiInstance, FALSE, 2, ulEgoEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write constant memory init context position in channel "672" for pgsp. */ WriteParams.ulWriteAddress = 0x71A; WriteParams.usWriteData = 0x8000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set fixed PGSP event_in base address to 800 on a 2k boundary */ WriteParams.ulWriteAddress = 0x716; WriteParams.usWriteData = 0x800 >> 11; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set fixed PGSP event_out to 0x2C0000h on a 16k boundary */ WriteParams.ulWriteAddress = 0x71C; WriteParams.usWriteData = 0x2C0000 >> 14; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Give chariot control of the chip. */ WriteParams.ulWriteAddress = 0x712; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + 0x2C0000 + 0xC; ulTempAddress = 0x300000 + 0x0800; WriteParams.usWriteData = (UINT16)( ( ulTempAddress >> 16 ) & 0x07FF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + 0x2C0000 + 0xE; WriteParams.usWriteData = (UINT16)( ( ulTempAddress >> 0 ) & 0xFF00 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the init PGSP event in place. */ WriteParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + 0x800; WriteParams.usWriteData = 0x0200; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + 0x802; WriteParams.usWriteData = 0x02A0; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Also write the register 710, which tells PGSP how many tones are supported. */ WriteParams.ulWriteAddress = 0x710; WriteParams.usWriteData = 0x0000; WriteParams.usWriteData |= pChipConfig->pbyImageFile[ 0x7FA ] << 8; WriteParams.usWriteData |= pChipConfig->pbyImageFile[ 0x7FB ] << 0; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Start both processors in the NLP. */ WriteParams.ulWriteAddress = 0x373FE; WriteParams.usWriteData = 0x00FF; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x37BFE; WriteParams.usWriteData = 0x00FE; /* Tell processor 1 to just go to sleep. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x37FC6; WriteParams.usWriteData = 0x8004; /* First PC.*/ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x37FD0; WriteParams.usWriteData = 0x0002; /* Take out of reset. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x37FD2; WriteParams.usWriteData = 0x0002; /* Take out of reset. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Start processor in the AF. */ for ( i = 0; i < 16; i ++ ) { WriteParams.ulWriteAddress = cOCT6100_POUCH_BASE + ( i * 2 ); if ( i == 9 ) { if ( pSharedInfo->ChipConfig.fEnableProductionBist == TRUE ) { if (pSharedInfo->ChipConfig.ulProductionBistMode == cOCT6100_PRODUCTION_BIST_SHORT) WriteParams.usWriteData = cOCT6100_PRODUCTION_SHORT_BOOT_TYPE; else WriteParams.usWriteData = cOCT6100_PRODUCTION_BOOT_TYPE; } else { WriteParams.usWriteData = cOCT6100_AF_BOOT_TYPE; } } else WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if the production BIST mode was requested. */ if ( pSharedInfo->ChipConfig.fEnableProductionBist == TRUE ) { UINT32 ulTotalElements = 3; UINT32 ulCrcKey; UINT32 aulMessage[ 4 ]; UINT32 ulWriteAddress = 0x20 + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; /* Magic key. */ aulMessage[ 0 ] = 0xCAFECAFE; /* Memory size. */ aulMessage[ 1 ] = pSharedInfo->MiscVars.ulTotalMemSize; /* Loop count. */ aulMessage[ 2 ] = pSharedInfo->ChipConfig.ulNumProductionBistLoops; /* CRC initialized. */ aulMessage[ 3 ] = 0; ulResult = Oct6100ApiProductionCrc( f_pApiInstance, aulMessage, ulTotalElements, &ulCrcKey ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; aulMessage[ 3 ] = ulCrcKey; /* Write the message to the external memory. */ for ( i = 0; i < ulTotalElements + 1; i ++ ) { ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulWriteAddress + i * 4, aulMessage[ i ] ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } WriteParams.ulWriteAddress = 0xFFFC6; WriteParams.usWriteData = 0x1284; /* First PC.*/ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0xFFFD0; WriteParams.usWriteData = 0x0002; /* Take out of reset. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; while ( ulAfCpuUp == FALSE ) { if ( ulAfCpuUp == FALSE ) { ReadParams.ulReadAddress = cOCT6100_POUCH_BASE; ReadParams.pusReadData = &usReadHighData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ReadParams.ulReadAddress += 2; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( pSharedInfo->ChipConfig.fEnableProductionBist == TRUE ) { /* Should read 0x0007 when bisting. */ if ( (( usReadHighData & 0xFFFF ) == cOCT6100_PRODUCTION_BOOT_TYPE) || (( usReadHighData & 0xFFFF ) == cOCT6100_PRODUCTION_SHORT_BOOT_TYPE) ) { /* Verify if the bist has started successfully. */ if ( ( usReadData & 0xFFFF ) == 0x0002 ) return cOCT6100_ERR_OPEN_PRODUCTION_BIST_CONF_FAILED; else if ( ( usReadData & 0xFFFF ) != 0xEEEE ) return cOCT6100_ERR_OPEN_PRODUCTION_BOOT_FAILED; ulAfCpuUp = TRUE; } } else /* if ( pSharedInfo->ChipConfig.fEnableProductionBist == FALSE ) */ { if ( ( usReadHighData & 0xFFFF ) == cOCT6100_AF_BOOT_TYPE ) { /* Verify if the bist succeeded. */ if ( ( usReadData & 0xFFFF ) != 0x0000 ) return cOCT6100_ERR_OPEN_FUNCTIONAL_BIST_FAILED; ulAfCpuUp = TRUE; } } } ulLoopCounter++; if ( ulLoopCounter == cOCT6100_MAX_LOOP_CPU_TIMEOUT ) return cOCT6100_ERR_OPEN_AF_CPU_TIMEOUT; } /* Return NLP in operationnal mode. */ WriteParams.ulWriteAddress = 0x2C2; WriteParams.usWriteData = 0x060E; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x692; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiSetH100Register Description: This function will configure the H.100 registers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiSetH100Register UINT32 Oct6100ApiSetH100Register( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; UINT32 i; UINT32 ulOffset; BOOL fAllStreamAt2Mhz = TRUE; const UINT16 ausAdpcmResetContext[32] = { 0x1100, 0x0220, 0x0000, 0x0000, 0x0000, 0x0020, 0x0000, 0x0000, 0x0008, 0x0000, 0x0000, 0x0100, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x0000, 0x0010, 0x0000, 0x0000, 0x0000}; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get local pointer to the chip configuration structure. */ pChipConfig = &f_pApiInstance->pSharedInfo->ChipConfig; /* Initialize the process context and user chip ID once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Set the Global OE bit. */ WriteParams.ulWriteAddress = 0x300; WriteParams.usWriteData = 0x0004; /* Set the number of streams. */ switch( pChipConfig->byMaxTdmStreams ) { case 32: WriteParams.usWriteData |= ( 0 << 3 ); break; case 16: WriteParams.usWriteData |= ( 1 << 3 ); break; case 8: WriteParams.usWriteData |= ( 2 << 3 ); break; case 4: WriteParams.usWriteData |= ( 3 << 3 ); break; default: break; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the stream frequency. */ WriteParams.ulWriteAddress = 0x330; WriteParams.usWriteData = 0x0000; for ( i = 0; i < (UINT32)(pChipConfig->byMaxTdmStreams / 4); i++) { ulOffset = i*2; switch( pChipConfig->aulTdmStreamFreqs[ i ] ) { case cOCT6100_TDM_STREAM_FREQ_2MHZ: WriteParams.usWriteData |= ( 0x0 << ulOffset ); break; case cOCT6100_TDM_STREAM_FREQ_4MHZ: WriteParams.usWriteData |= ( 0x1 << ulOffset ); fAllStreamAt2Mhz = FALSE; break; case cOCT6100_TDM_STREAM_FREQ_8MHZ: WriteParams.usWriteData |= ( 0x2 << ulOffset ); fAllStreamAt2Mhz = FALSE; break; default: break; } } /* Set the stream to 16 MHz if the fast H.100 mode is selected. */ if ( pChipConfig->fEnableFastH100Mode == TRUE ) { fAllStreamAt2Mhz = FALSE; WriteParams.usWriteData = 0xFFFF; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) { /* Make the chip track both clock A and B to perform fast H.100 mode. */ WriteParams.ulWriteAddress = 0x322; WriteParams.usWriteData = 0x0004; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Enable the fast H.100 mode. */ WriteParams.ulWriteAddress = 0x332; WriteParams.usWriteData = 0x0003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } WriteParams.ulWriteAddress = 0x376; WriteParams.usWriteData = (UINT16)( pSharedInfo->MiscVars.usTdmClkBoundary ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Select delay for early clock (90 and 110). */ WriteParams.ulWriteAddress = 0x378; if ( pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) WriteParams.usWriteData = 0x000A; else { /* Set the TDM sampling. */ if ( pSharedInfo->ChipConfig.byTdmSampling == cOCT6100_TDM_SAMPLE_AT_RISING_EDGE ) { WriteParams.usWriteData = 0x0AF0; } else if ( pSharedInfo->ChipConfig.byTdmSampling == cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE ) { WriteParams.usWriteData = 0x0A0F; } else /* pSharedInfo->ChipConfig.ulTdmSampling == cOCT6100_TDM_SAMPLE_AT_3_QUARTERS */ { WriteParams.usWriteData = 0x0A08; } } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Protect chip by preventing too rapid timeslot arrival (mclk == 133 MHz). */ WriteParams.ulWriteAddress = 0x37A; WriteParams.usWriteData = (UINT16)pSharedInfo->MiscVars.usMaxH100Speed; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Allow H.100 TS to progress. */ WriteParams.ulWriteAddress = 0x382; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set by-pass mode. */ WriteParams.ulWriteAddress = 0x50E; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* TDMIE bits. */ WriteParams.ulWriteAddress = 0x500; WriteParams.usWriteData = 0x0003; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write normal ADPCM reset values in ADPCM context 1344. */ for(i=0;i<32;i++) { WriteParams.ulWriteAddress = 0x140000 + ( 0x40 * 1344 ) + ( i * 2 ); WriteParams.usWriteData = ausAdpcmResetContext[i]; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Make sure delay flops are configured correctly if all streams are at 2 MHz. */ if ( fAllStreamAt2Mhz == TRUE ) { /* Setup H.100 sampling to lowest value. */ WriteParams.ulWriteAddress = 0x144; WriteParams.usWriteData = 0x4041; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x378; WriteParams.usWriteData = 0x0A00; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteMiscellaneousRegisters Description: This function will write to various registers to activate the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteMiscellaneousRegisters UINT32 Oct6100ApiWriteMiscellaneousRegisters( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Initialize the process context and user chip ID once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Free the interrupt pin of the chip (i.e. remove minimum time requirement between interrupts). */ WriteParams.ulWriteAddress = 0x214; WriteParams.usWriteData = 0x0000; if ( f_pApiInstance->pSharedInfo->ChipConfig.byInterruptPolarity == cOCT6100_ACTIVE_HIGH_POLARITY ) WriteParams.usWriteData |= 0x4000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write MT chariot interval */ WriteParams.ulWriteAddress = 0x2C2; if ( f_pApiInstance->pSharedInfo->ImageInfo.usMaxNumberOfChannels > 640 ) WriteParams.usWriteData = 0x05EA; else if ( f_pApiInstance->pSharedInfo->ImageInfo.usMaxNumberOfChannels > 513 ) WriteParams.usWriteData = 0x0672; else /* if ( f_pApiInstance->pSharedInfo->ImageInfo.usMaxNumberOfChannels <= 513 ) */ WriteParams.usWriteData = 0x0750; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write set second part5 time. */ WriteParams.ulWriteAddress = 0x2C4; WriteParams.usWriteData = 0x04A0; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write CPU bucket timer to guarantee 200 cycles between each CPU access. */ WriteParams.ulWriteAddress = 0x234; WriteParams.usWriteData = 0x0804; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x236; WriteParams.usWriteData = 0x0100; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCreateSerializeObjects Description: Creates a handle to each serialization object used by the API. Note that in a multi-process system the user's process context structure pointer is needed by this function. Thus, the pointer must be valid. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulUserChipId User chip ID for this serialization object. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCreateSerializeObjects UINT32 Oct6100ApiCreateSerializeObjects( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulUserChipId ) { tOCT6100_CREATE_SERIALIZE_OBJECT CreateSerObj; UINT32 ulResult; CHAR szSerObjName[ 64 ] = "Oct6100ApiXXXXXXXXApiSerObj"; /* Set some parameters of the create structure once and for all. */ CreateSerObj.pProcessContext = f_pApiInstance->pProcessContext; CreateSerObj.pszSerialObjName = szSerObjName; /*----------------------------------------------------------------------*/ /* Set the chip ID in the semaphore name. */ szSerObjName[ 10 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 28 ) & 0xFF ); szSerObjName[ 11 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 24 ) & 0xFF ); szSerObjName[ 12 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 20 ) & 0xFF ); szSerObjName[ 13 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 16 ) & 0xFF ); szSerObjName[ 14 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 12 ) & 0xFF ); szSerObjName[ 15 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 8 ) & 0xFF ); szSerObjName[ 16 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 4 ) & 0xFF ); szSerObjName[ 17 ] = (CHAR) Oct6100ApiHexToAscii( (f_ulUserChipId >> 0 ) & 0xFF ); ulResult = Oct6100UserCreateSerializeObject( &CreateSerObj ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pApiInstance->ulApiSerObj = CreateSerObj.ulSerialObjHndl; /*----------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiDestroySerializeObjects Description: Destroy handles to each serialization object used by the API. Note that in a multi-process system the user's process context structure pointer is needed by this function. Thus, the pointer must be valid. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiDestroySerializeObjects UINT32 Oct6100ApiDestroySerializeObjects( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_DESTROY_SERIALIZE_OBJECT DestroySerObj; UINT32 ulResult; /* Set some parameters of the create structure once and for all. */ DestroySerObj.pProcessContext = f_pApiInstance->pProcessContext; DestroySerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulResult = Oct6100UserDestroySerializeObject( &DestroySerObj ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRunEgo Description: Private function used to communicate with the internal processors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_fStoreFlag Type of access performed. (Load or Store) f_ulNumEntry Number of access. f_aulEntry Array of access to perform. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRunEgo UINT32 Oct6100ApiRunEgo( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN BOOL f_fStoreFlag, IN UINT32 f_ulNumEntry, OUT PUINT32 f_aulEntry ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 aulCpuLsuCmd[ 2 ]; UINT16 usReadData; UINT32 i; BOOL fConditionFlag = TRUE; UINT32 ulLoopCounter = 0; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get local pointer to the chip configuration structure. */ pChipConfig = &f_pApiInstance->pSharedInfo->ChipConfig; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* No more than 2 entries may be requested. */ if ( f_ulNumEntry > 2 ) return cOCT6100_ERR_FATAL_1B; /* Write the requested entries at address reserved for CPU. */ for( i = 0; i < f_ulNumEntry; i++ ) { WriteParams.ulWriteAddress = cOCT6100_PART1_API_SCRATCH_PAD + ( 0x8 * i ); WriteParams.usWriteData = (UINT16)(( f_aulEntry[ i * 2 ] >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( f_aulEntry[ i * 2 ] & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)(( f_aulEntry[ (i * 2) + 1] >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( f_aulEntry[ (i * 2) + 1] & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Preincrement code point. */ pSharedInfo->MiscVars.usCodepoint++; /* Create DWORD 0 of command. */ aulCpuLsuCmd[0] = 0x00000000; if ( f_fStoreFlag == FALSE ) aulCpuLsuCmd[0] |= 0xC0000000; /* EGO load. */ else aulCpuLsuCmd[0] |= 0xE0000000; /* EGO store. */ aulCpuLsuCmd[0] |= (f_ulNumEntry - 1) << 19; aulCpuLsuCmd[0] |= cOCT6100_PART1_API_SCRATCH_PAD; /* Create DWORD 1 of command. */ aulCpuLsuCmd[1] = 0x00000000; aulCpuLsuCmd[1] |= ( ( cOCT6100_PART1_API_SCRATCH_PAD + 0x10 ) & 0xFFFF ) << 16; aulCpuLsuCmd[1] |= pSharedInfo->MiscVars.usCodepoint; /* Write the EGO command in the LSU CB. */ WriteParams.ulWriteAddress = cOCT6100_PART1_CPU_LSU_CB_BASE + ((pSharedInfo->MiscVars.usCpuLsuWritePtr & 0x7) * 0x8 ); WriteParams.usWriteData = (UINT16)(( aulCpuLsuCmd[ 0 ] >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( aulCpuLsuCmd[ 0 ] & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)(( aulCpuLsuCmd[ 1 ] >> 16 ) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( aulCpuLsuCmd[ 1 ] & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Post increment the write pointer. */ pSharedInfo->MiscVars.usCpuLsuWritePtr++; /* Indicate new write pointer position to HW. */ WriteParams.ulWriteAddress = cOCT6100_PART1_EGO_REG + 0x5A; WriteParams.usWriteData = (UINT16)( pSharedInfo->MiscVars.usCpuLsuWritePtr & 0x7 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Wait for codepoint to be updated before returning. */ while( fConditionFlag ) { ReadParams.ulReadAddress = cOCT6100_PART1_API_SCRATCH_PAD + 0x12; usReadData = (UINT16)( pSharedInfo->MiscVars.usCodepoint ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData == pSharedInfo->MiscVars.usCodepoint ) fConditionFlag = FALSE; ulLoopCounter++; if ( ulLoopCounter == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_OPEN_EGO_TIMEOUT; } /* CRC error bit must be zero. */ ReadParams.ulReadAddress = 0x202; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( ( usReadData & 0x0400 ) != 0 ) return cOCT6100_ERR_OPEN_CORRUPTED_IMAGE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCreateEgoEntry Description: Private function used to create an access structure to be sent to the internal processors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_ulExternalAddress External memory address for the access. f_ulInternalAddress Which process should receive the command. f_ulNumBytes Number of bytes associated to the access. f_aulEntry Array of access to perform. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCreateEgoEntry UINT32 Oct6100ApiCreateEgoEntry( IN UINT32 f_ulExternalAddress, IN UINT32 f_ulInternalAddress, IN UINT32 f_ulNumBytes, OUT UINT32 f_aulEntry[ 2 ] ) { f_aulEntry[0] = 0x80000000; f_aulEntry[0] |= f_ulExternalAddress & 0x07FFFFFC; f_aulEntry[1] = 0x0011C000; f_aulEntry[1] |= (f_ulNumBytes / 8) << 23; f_aulEntry[1] |= (f_ulInternalAddress >> 2) & 0x3FFF; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitChannels Description: This function will initialize all the channels to power down. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitChannels UINT32 Oct6100ApiInitChannels( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 i; UINT32 ulResult; tOCT6100_WRITE_BURST_PARAMS BurstParams; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT16 usReadData; UINT32 ulTempData; UINT32 ulBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; UINT16 ausWriteData[ 4 ]; UINT16 usLoopCount = 0; UINT16 usWriteData = 0; UINT16 usMclkRead; UINT16 usLastMclkRead; UINT16 usMclkDiff; UINT32 ulNumberOfCycleToWait; UINT32 ulTimeoutCounter; pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pusWriteData = ausWriteData; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Verify that the image has enough memory to work correctly. */ if ( ( pSharedInfo->MiscVars.ulTotalMemSize + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) < pSharedInfo->MemoryMap.ulFreeMemBaseAddress ) return cOCT6100_ERR_OPEN_INSUFFICIENT_EXTERNAL_MEMORY; /* Verify that the tail length is supported by the device.*/ if ( pSharedInfo->ChipConfig.usTailDisplacement > pSharedInfo->ImageInfo.usMaxTailDisplacement ) return cOCT6100_ERR_NOT_SUPPORTED_OPEN_TAIL_DISPLACEMENT_VALUE; /* Verify that acoustic echo is supported by the device. */ if ( pSharedInfo->ChipConfig.fEnableAcousticEcho == TRUE && pSharedInfo->ImageInfo.fAcousticEcho == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_OPEN_ACOUSTIC_ECHO; /* Verify that the image supports all the requested channels. */ if ( pSharedInfo->ChipConfig.usMaxChannels > pSharedInfo->ImageInfo.usMaxNumberOfChannels ) return cOCT6100_ERR_NOT_SUPPORTED_OPEN_MAX_ECHO_CHANNELS_VALUE; /* Max number of channels the image supports + 1 for channel recording, if requested */ if ( ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) && ( pSharedInfo->ImageInfo.usMaxNumberOfChannels < cOCT6100_MAX_ECHO_CHANNELS ) && ( pSharedInfo->ChipConfig.usMaxChannels == pSharedInfo->ImageInfo.usMaxNumberOfChannels ) ) return cOCT6100_ERR_NOT_SUPPORTED_OPEN_MAX_ECHO_CHANNELS_VALUE; /* Initialize the memory for all required channels. */ for( i = 0; i < f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels; i++ ) { /*==============================================================================*/ /* Configure the Global Static Configuration memory of the channel. */ ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( i * cOCT6100_CHANNEL_ROOT_SIZE ) + cOCT6100_CHANNEL_ROOT_GLOBAL_CONF_OFFSET; /* Set the PGSP context base address. */ ulTempData = pSharedInfo->MemoryMap.ulChanMainMemBase + ( i * pSharedInfo->MemoryMap.ulChanMainMemSize ) + cOCT6100_CH_MAIN_PGSP_CONTEXT_OFFSET; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_PGSP_CONTEXT_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the PGSP init context base address. */ ulTempData = ( cOCT6100_IMAGE_FILE_BASE + 0x200 ) & 0x07FFFFFF; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_PGSP_INIT_CONTEXT_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the RIN circular buffer base address. */ ulTempData = pSharedInfo->MemoryMap.ulChanMainMemBase + ( i * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainRinCBMemOfst; /* Set the circular buffer size. */ ulTempData &= 0xFFFFFF00; if (( pSharedInfo->MemoryMap.ulChanMainRinCBMemSize & 0xFFFF00FF ) != 0 ) return cOCT6100_ERR_CHANNEL_INVALID_RIN_CB_SIZE; ulTempData |= pSharedInfo->MemoryMap.ulChanMainRinCBMemSize >> 8; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_RIN_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the SIN circular buffer base address. */ ulTempData = pSharedInfo->MemoryMap.ulChanMainMemBase + ( i * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainSinCBMemOfst; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_SIN_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the SOUT circular buffer base address. */ ulTempData = pSharedInfo->MemoryMap.ulChanMainMemBase + ( i * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainSoutCBMemOfst;; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_SOUT_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ } /* Put all channel in powerdown mode "3". */ for( i = 0; i < f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels; i++ ) { WriteParams.ulWriteAddress = 0x014000 + (i*4) + 0; WriteParams.usWriteData = 0x85FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x014000 + (i*4) + 2; WriteParams.usWriteData = 0xC5FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Set the maximum number of channels. */ WriteParams.ulWriteAddress = 0x690; if ( pSharedInfo->ImageInfo.usMaxNumberOfChannels < 384 ) WriteParams.usWriteData = 384; else WriteParams.usWriteData = (UINT16)pSharedInfo->ImageInfo.usMaxNumberOfChannels; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set power-dowm TSI chariot memory to silence. */ for( i = 0; i < 6; i++ ) { WriteParams.ulWriteAddress = 0x20000 + ( i * 0x1000 ) + ( 1534 * 2 ); WriteParams.usWriteData = 0x3EFF; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x20000 + ( i * 0x1000 ) + ( 1535 * 2 ); WriteParams.usWriteData = 0x3EFF; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Remove chariot hold. */ WriteParams.ulWriteAddress = 0x500; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; for( usLoopCount = 0; usLoopCount < 4096; usLoopCount++ ) { if ( (usLoopCount % 16) < 8 ) { usWriteData = (UINT16)((usLoopCount / 16) << 7); usWriteData |= (UINT16)((usLoopCount % 8)); } else { usWriteData = (UINT16)((usLoopCount / 16) << 7); usWriteData |= (UINT16)((usLoopCount % 8)); usWriteData |= 0x78; } /* Set timeslot pointer. */ WriteParams.ulWriteAddress = 0x50E; WriteParams.usWriteData = 0x0003; WriteParams.usWriteData |= usWriteData << 2; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now read the mclk counter. */ ReadParams.ulReadAddress = 0x30A; ReadParams.pusReadData = &usLastMclkRead; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reset loop timeout counter. */ ulTimeoutCounter = 0x0; do { ReadParams.pusReadData = &usMclkRead; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( ( usLoopCount % 16 ) != 15 ) { ulNumberOfCycleToWait = 133; } else { ulNumberOfCycleToWait = 20000; } /* Evaluate the difference. */ usMclkDiff = (UINT16)(( usMclkRead - usLastMclkRead ) & 0xFFFF); /* Check for loop timeout. Bad mclk? */ ulTimeoutCounter++; if ( ulTimeoutCounter == cOCT6100_MAX_LOOP_CPU_TIMEOUT ) return cOCT6100_ERR_FATAL_EA; } while( usMclkDiff <= ulNumberOfCycleToWait ); } /* Back to normal mode. */ WriteParams.ulWriteAddress = 0x50E; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check for CRC errors. */ ReadParams.pusReadData = &usReadData; ReadParams.ulReadAddress = 0x202; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (usReadData & 0x400) != 0x0000 ) return cOCT6100_ERR_OPEN_CRC_ERROR; /* Clear the error rol raised by manually moving the clocks. */ WriteParams.ulWriteAddress = 0x502; WriteParams.usWriteData = 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*======================================================================*/ /* Write the tail displacement value in external memory. */ ulFeatureBytesOffset = pSharedInfo->MemoryMap.PouchTailDisplOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PouchTailDisplOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PouchTailDisplOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set the tail displacement. */ ulTempData |= (pSharedInfo->ChipConfig.usTailDisplacement << ulFeatureBitOffset ); /* Write the DWORD where the field is located. */ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*======================================================================*/ /*======================================================================*/ /* Clear the pouch counter, if present. */ if ( pSharedInfo->DebugInfo.fPouchCounter == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Clear counter! */ ulTempData &= (~ulMask); /* Write the DWORD where the field is located.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* The ISR has not yet been called. Set the appropriate bit in external memory. */ if ( pSharedInfo->DebugInfo.fIsIsrCalledField == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Read previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Toggle the bit to '1'. */ ulTempData |= 1 << ulFeatureBitOffset; /* Write the DWORD where the field is located.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitToneInfo Description: This function will parse the software image and retrieve the information about the tones that it supports. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitToneInfo UINT32 Oct6100ApiInitToneInfo( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { UINT32 ulResult; unsigned char const *pszToneInfoStart = NULL; unsigned char const *pszToneInfoEnd = NULL; unsigned char const *pszCurrentInfo; unsigned char const *pszNextInfo; UINT32 ulToneEventNumber; UINT32 ulTempValue; UINT32 ulNumCharForValue; UINT32 ulUniqueToneId; UINT32 ulToneNameSize; UINT32 ulOffset = 0; UINT32 i; /* Init the tone detector parameter. */ f_pApiInstance->pSharedInfo->ImageInfo.byNumToneDetectors = 0; /* Find the start and the end of the tone info section. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize > 4096 ) { /* For performance reasons, and since the tone detector information */ /* is always located at the end of the image file, try to start from the end */ /* of the buffer. */ ulOffset = f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize - 2048; pszToneInfoStart = Oct6100ApiStrStr( f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + ulOffset, (PUINT8)cOCT6100_TONE_INFO_START_STRING, f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize ); /* Check if the information was found. */ if ( pszToneInfoStart == NULL ) { /* Try again, but giving a larger string to search. */ ulOffset = f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize - 4096; pszToneInfoStart = Oct6100ApiStrStr( f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + ulOffset, (PUINT8)cOCT6100_TONE_INFO_START_STRING, f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize ); } } if ( pszToneInfoStart == NULL ) { /* Travel through the whole file buffer. */ pszToneInfoStart = Oct6100ApiStrStr( f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile, (PUINT8)cOCT6100_TONE_INFO_START_STRING, f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize ); } /* We have to return immediatly if no tones are found. */ if ( pszToneInfoStart == NULL ) return cOCT6100_ERR_OK; /* The end of the tone detector information is after the beginning of the tone information. */ pszToneInfoEnd = Oct6100ApiStrStr( pszToneInfoStart, (PUINT8)cOCT6100_TONE_INFO_STOP_STRING, f_pApiInstance->pSharedInfo->ChipConfig.pbyImageFile + f_pApiInstance->pSharedInfo->ChipConfig.ulImageSize ); if ( pszToneInfoEnd == NULL ) return cOCT6100_ERR_OPEN_TONE_INFO_STOP_TAG_NOT_FOUND; /* Find and process all tone events within the region. */ pszCurrentInfo = Oct6100ApiStrStr( pszToneInfoStart, (PUINT8)cOCT6100_TONE_INFO_EVENT_STRING, pszToneInfoEnd ); while ( pszCurrentInfo != NULL ) { /* Skip the string. */ pszCurrentInfo += ( Oct6100ApiStrLen( (PUINT8)cOCT6100_TONE_INFO_EVENT_STRING ) ); /* Extract the number of char used to represent the tone event number ( 1 or 2 ). */ pszNextInfo = Oct6100ApiStrStr( pszCurrentInfo, (PUINT8)",", pszToneInfoEnd ); ulNumCharForValue = (UINT32)( pszNextInfo - pszCurrentInfo ); /* Retreive the event number */ ulToneEventNumber = 0; for ( i = ulNumCharForValue; i > 0; i-- ) { ulResult = Oct6100ApiAsciiToHex( *pszCurrentInfo, &ulTempValue ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulToneEventNumber |= ( ulTempValue << (( i - 1) * 4 ) ); pszCurrentInfo++; } if ( ulToneEventNumber >= cOCT6100_MAX_TONE_EVENT ) return cOCT6100_ERR_OPEN_INVALID_TONE_EVENT; /* Skip the comma and the 0x. */ pszCurrentInfo += 3; /*======================================================================*/ /* Retreive the unique tone id. */ ulUniqueToneId = 0; for ( i = 0; i < 8; i++ ) { ulResult = Oct6100ApiAsciiToHex( *pszCurrentInfo, &ulTempValue ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulOffset = 28 - ( i * 4 ); ulUniqueToneId |= ( ulTempValue << ulOffset ); pszCurrentInfo++; } /*======================================================================*/ /* Skip the comma. */ pszCurrentInfo++; /* Find out where the next event info starts */ pszNextInfo = Oct6100ApiStrStr( pszCurrentInfo,(PUINT8) cOCT6100_TONE_INFO_EVENT_STRING, pszToneInfoEnd ); if ( pszNextInfo == NULL ) pszNextInfo = pszToneInfoEnd; /* Extract the name size. */ ulToneNameSize = (UINT32)( pszNextInfo - pszCurrentInfo - 2 ); /* - 2 for 0x0D and 0x0A.*/ if ( ulToneNameSize > cOCT6100_TLV_MAX_TONE_NAME_SIZE ) return cOCT6100_ERR_OPEN_INVALID_TONE_NAME; /* Copy the tone name into the image info structure. */ ulResult = Oct6100UserMemCopy( f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].aszToneName, pszCurrentInfo, ulToneNameSize ); /* Update the tone info into the image info structure. */ f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulToneID = ulUniqueToneId; /* Find out the port on which this tone detector is associated. */ switch( (ulUniqueToneId >> 28) & 0xF ) { case 1: f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulDetectionPort = cOCT6100_CHANNEL_PORT_ROUT; break; case 2: f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulDetectionPort = cOCT6100_CHANNEL_PORT_SIN; break; case 4: f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulDetectionPort = cOCT6100_CHANNEL_PORT_SOUT; break; case 5: f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulDetectionPort = cOCT6100_CHANNEL_PORT_ROUT_SOUT; break; default: f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulDetectionPort = cOCT6100_INVALID_PORT; break; } /* Find out where the next event info starts */ pszNextInfo = Oct6100ApiStrStr( pszCurrentInfo,(PUINT8) cOCT6100_TONE_INFO_EVENT_STRING, pszToneInfoEnd ); /* Update the current info pointer. */ pszCurrentInfo = pszNextInfo; f_pApiInstance->pSharedInfo->ImageInfo.byNumToneDetectors++; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiExternalMemoryBist Description: Tests the functionality of the external memories. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiExternalMemoryBist UINT32 Oct6100ApiExternalMemoryBist( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulMemSize = 0; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Test the external memory. */ switch ( pSharedInfo->ChipConfig.ulMemoryChipSize ) { case cOCT6100_MEMORY_CHIP_SIZE_8MB: ulMemSize = cOCT6100_SIZE_8M; break; case cOCT6100_MEMORY_CHIP_SIZE_16MB: ulMemSize = cOCT6100_SIZE_16M; break; case cOCT6100_MEMORY_CHIP_SIZE_32MB: ulMemSize = cOCT6100_SIZE_32M; break; case cOCT6100_MEMORY_CHIP_SIZE_64MB: ulMemSize = cOCT6100_SIZE_64M; break; case cOCT6100_MEMORY_CHIP_SIZE_128MB: ulMemSize = cOCT6100_SIZE_128M; break; default: return cOCT6100_ERR_FATAL_D9; } ulMemSize *= pSharedInfo->ChipConfig.byNumMemoryChips; ulResult = Oct6100ApiRandomMemoryWrite( f_pApiInstance, cOCT6100_EXTERNAL_MEM_BASE_ADDRESS, ulMemSize, 16, 1000, cOCT6100_ERR_OPEN_EXTERNAL_MEM_BIST_FAILED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Make sure the user I/O functions are working as required. */ ulResult = Oct6100ApiUserIoTest( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGenerateNumber Description: Generate a number using an index. Passing the same index generates the same number. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulIndex Index used to generate the random number. f_ulDataMask Data mask to apply to generated number. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGenerateNumber UINT16 Oct6100ApiGenerateNumber( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulIndex, IN UINT32 f_ulDataMask ) { UINT16 usGeneratedNumber; usGeneratedNumber = (UINT16)( ( ( ~( f_ulIndex - 1 ) ) & 0xFF00 ) | ( ( f_ulIndex + 1 ) & 0xFF ) ); return (UINT16)( usGeneratedNumber & f_ulDataMask ); } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRandomMemoryWrite Description: Writes to f_ulNumAccesses random locations in the indicated memory and read back to test the operation of that memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulMemBase Base address of the memory access. f_ulMemSize Size of the memory to be tested. f_ulNumDataBits Number of data bits. f_ulNumAccesses Number of random access to be perform. f_ulErrorCode Error code to be returned if the bist fails. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRandomMemoryWrite UINT32 Oct6100ApiRandomMemoryWrite( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulMemBase, IN UINT32 f_ulMemSize, IN UINT32 f_ulNumDataBits, IN UINT32 f_ulNumAccesses, IN UINT32 f_ulErrorCode ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulDataMask; UINT32 ulResult, i, j; UINT32 ulBistAddress; UINT16 usReadData; UINT32 aulBistAddress[20]={0x00000000, 0x00000002, 0x00000004, 0x007FFFFE, 0x00900000, 0x00900006, 0x00900008, 0x009FFFFE, 0x01000000, 0x0100000A, 0x0200000C, 0x01FFFFFE, 0x03000000, 0x03000002, 0x04000004, 0x03FFFFFE, 0x04000000, 0x05000006, 0x06000008, 0x07FFFFFE}; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Determine mask for number of data bits. */ ulDataMask = (1 << f_ulNumDataBits) - 1; /* Write specific data to specific address */ WriteParams.ulWriteAddress = f_ulMemBase | 0x00001000; WriteParams.usWriteData = 0xCAFE; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; for(j=0; j<20; j++) { /* Change address to test lower and higher part of the 32 bit bus */ ulBistAddress = aulBistAddress[j]; ulBistAddress &= f_ulMemSize - 2; ulBistAddress |= f_ulMemBase; /* Bist 16 data pins of this address */ for ( i = 0; i < 16; i ++) { WriteParams.ulWriteAddress = ulBistAddress; WriteParams.usWriteData = (UINT16)(0x1 << i); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read back the specific data to flush the data bus.*/ ReadParams.ulReadAddress = f_ulMemBase | 0x00001000; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != 0xCAFE ) return f_ulErrorCode; /* Read back the data written.*/ ReadParams.ulReadAddress = WriteParams.ulWriteAddress; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != (UINT16)(0x1 << i) ) return f_ulErrorCode; } } /* Perform the first write at address 0 + mem base */ j = 0; WriteParams.ulWriteAddress = f_ulMemBase; WriteParams.usWriteData = Oct6100ApiGenerateNumber( f_pApiInstance, j, ulDataMask ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Try each address line of the memory. */ for ( i = 2, j = 1; i < f_ulMemSize; i <<= 1, j++ ) { WriteParams.ulWriteAddress = ( f_ulMemBase + i ); WriteParams.usWriteData = Oct6100ApiGenerateNumber( f_pApiInstance, j, ulDataMask ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } for ( i = 0; i < j; i++ ) { if ( i > 0 ) ReadParams.ulReadAddress = ( f_ulMemBase + ( 0x1 << i ) ); else ReadParams.ulReadAddress = f_ulMemBase; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData != Oct6100ApiGenerateNumber( f_pApiInstance, i, ulDataMask ) ) return f_ulErrorCode; } /* Write to random addresses of the memory. */ for ( i = 0; i < f_ulNumAccesses; i++ ) { ulBistAddress = (UINT16)Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ) << 16; ulBistAddress |= (UINT16)Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ); ulBistAddress &= f_ulMemSize - 2; ulBistAddress |= f_ulMemBase; WriteParams.ulWriteAddress = ulBistAddress; WriteParams.usWriteData = Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } for ( i = 0; i < f_ulNumAccesses; i++ ) { ulBistAddress = (UINT16)Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ) << 16; ulBistAddress |= (UINT16)Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ); ulBistAddress &= f_ulMemSize - 2; ulBistAddress |= f_ulMemBase; ReadParams.ulReadAddress = ulBistAddress; ReadParams.pusReadData = &usReadData; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( ( usReadData & ulDataMask ) != ( Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ) & ulDataMask ) ) return f_ulErrorCode; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUserIoTest Description: This function will verify the correct functionality of the following user functions: - Oct6100UserDriverWriteBurstApi - Oct6100UserDriverWriteSmearApi - Oct6100UserDriverReadBurstApi The Oct6100UserDriverWriteApi and Oct6100UserDriverReadApi functions do not need to be tested here as this has be done in the external memory bisting function above. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUserIoTest UINT32 Oct6100ApiUserIoTest( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_BURST_PARAMS WriteBurstParams; tOCT6100_WRITE_SMEAR_PARAMS WriteSmearParams; tOCT6100_READ_PARAMS ReadParams; tOCT6100_READ_BURST_PARAMS ReadBurstParams; UINT32 ulResult, i; UINT16 usReadData; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ WriteBurstParams.pProcessContext = f_pApiInstance->pProcessContext; WriteBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Test what the user has specified is the maximum that can be used for a burst. */ WriteBurstParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses; WriteBurstParams.pusWriteData = pSharedInfo->MiscVars.ausSuperArray; WriteSmearParams.pProcessContext = f_pApiInstance->pProcessContext; WriteSmearParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Test what the user has specified is the maximum that can be used for a smear. */ WriteSmearParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; ReadBurstParams.pProcessContext = f_pApiInstance->pProcessContext; ReadBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Test what the user has specified is the maximum that can be used for a burst. */ ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; ReadBurstParams.pusReadData = pSharedInfo->MiscVars.ausSuperArray; /*======================================================================*/ /* Write burst check. */ WriteBurstParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; /* Set the random data to be written. */ for ( i = 0; i < WriteBurstParams.ulWriteLength; i++ ) { WriteBurstParams.pusWriteData[ i ] = Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ); } mOCT6100_DRIVER_WRITE_BURST_API( WriteBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read back pattern using simple read function and make sure we are reading what's expected. */ ReadParams.ulReadAddress = WriteBurstParams.ulWriteAddress; for ( i = 0; i < WriteBurstParams.ulWriteLength; i++ ) { mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the data matches. */ if ( usReadData != WriteBurstParams.pusWriteData[ i ] ) { /* The values do not match. Something seems to be wrong with the WriteBurst user function. */ return cOCT6100_ERR_OPEN_USER_WRITE_BURST_FAILED; } /* Next address to check. */ ReadParams.ulReadAddress += 2; } /*======================================================================*/ /*======================================================================*/ /* Write smear check. */ WriteSmearParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS + ( WriteBurstParams.ulWriteLength * 2 ); /* Set the random data to be written. */ WriteSmearParams.usWriteData = Oct6100ApiGenerateNumber( f_pApiInstance, Oct6100ApiRand( 0xFFFF ), 0xFFFF ); mOCT6100_DRIVER_WRITE_SMEAR_API( WriteSmearParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read back pattern using simple read function and make sure we are reading what's expected. */ ReadParams.ulReadAddress = WriteSmearParams.ulWriteAddress; for ( i = 0; i < WriteSmearParams.ulWriteLength; i++ ) { mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the data matches. */ if ( usReadData != WriteSmearParams.usWriteData ) { /* The values do not match. Something seems to be wrong with the WriteSmear user function. */ return cOCT6100_ERR_OPEN_USER_WRITE_SMEAR_FAILED; } /* Next address to check. */ ReadParams.ulReadAddress += 2; } /*======================================================================*/ /*======================================================================*/ /* Read burst check. */ /* First check with what the WriteBurst function wrote. */ ReadBurstParams.ulReadAddress = WriteBurstParams.ulWriteAddress; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; for ( i = 0; i < ReadBurstParams.ulReadLength; i++ ) { /* Check if the data matches. */ if ( ReadBurstParams.pusReadData[ i ] != Oct6100ApiGenerateNumber( f_pApiInstance, i, 0xFFFF ) ) { /* The values do not match. Something seems to be wrong with the ReadBurst user function. */ return cOCT6100_ERR_OPEN_USER_READ_BURST_FAILED; } } /* Then check with what the WriteSmear function wrote. */ ReadBurstParams.ulReadAddress = WriteSmearParams.ulWriteAddress; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; for ( i = 0; i < ReadBurstParams.ulReadLength; i++ ) { /* Check if the data matches. */ if ( ReadBurstParams.pusReadData[ i ] != WriteSmearParams.usWriteData ) { /* The values do not match. Something seems to be wrong with the ReadBurst user function. */ return cOCT6100_ERR_OPEN_USER_READ_BURST_FAILED; } } /*======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiExternalMemoryInit Description: Initialize the external memory before uploading the image. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiExternalMemoryInit UINT32 Oct6100ApiExternalMemoryInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_SMEAR_PARAMS SmearParams; UINT32 ulTotalWordToWrite; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; SmearParams.pProcessContext = f_pApiInstance->pProcessContext; SmearParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Clear the first part of the memory. */ ulTotalWordToWrite = 0x400; SmearParams.ulWriteAddress = cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; while ( ulTotalWordToWrite != 0 ) { if ( ulTotalWordToWrite >= pSharedInfo->ChipConfig.usMaxRwAccesses ) SmearParams.ulWriteLength = pSharedInfo->ChipConfig.usMaxRwAccesses; else SmearParams.ulWriteLength = ulTotalWordToWrite; SmearParams.usWriteData = 0x0; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the number of words to write. */ ulTotalWordToWrite -= SmearParams.ulWriteLength; /* Update the address. */ SmearParams.ulWriteAddress += ( SmearParams.ulWriteLength * 2 ); } /* Clear the TLV flag.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_TLV_BASE, 0x0 ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitMixer Description: This function will initialize the mixer memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitMixer UINT32 Oct6100ApiInitMixer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_BURST_PARAMS BurstParams; UINT16 ausWriteData[ 4 ]; UINT32 ulResult; pSharedInfo = f_pApiInstance->pSharedInfo; BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pusWriteData = ausWriteData; /*======================================================================*/ /* Initialize the mixer memory if required. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) { /* Modify the mixer pointer by adding the record event into the link list. */ pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = pSharedInfo->MixerInfo.usRecordSinEventIndex; pSharedInfo->MixerInfo.usLastSinCopyEventPtr = pSharedInfo->MixerInfo.usRecordSinEventIndex; pSharedInfo->MixerInfo.usFirstSoutCopyEventPtr = pSharedInfo->MixerInfo.usRecordCopyEventIndex; pSharedInfo->MixerInfo.usLastSoutCopyEventPtr = pSharedInfo->MixerInfo.usRecordCopyEventIndex; /* Program the Sin copy event. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordSinEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); BurstParams.ulWriteLength = 4; ausWriteData[ 0 ] = 0x0000; ausWriteData[ 1 ] = 0x0000; ausWriteData[ 2 ] = (UINT16)(cOCT6100_MIXER_TAIL_NODE & 0x7FF); /* Head node.*/ ausWriteData[ 3 ] = 0x0000; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Program the Sout copy event. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); BurstParams.ulWriteLength = 4; ausWriteData[ 0 ] = 0x0000; ausWriteData[ 1 ] = 0x0000; ausWriteData[ 2 ] = (UINT16)(pSharedInfo->MixerInfo.usRecordSinEventIndex & 0x7FF); ausWriteData[ 3 ] = 0x0000; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the head node. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE; BurstParams.ulWriteLength = 4; ausWriteData[ 0 ] = 0x0000; ausWriteData[ 1 ] = 0x0000; ausWriteData[ 2 ] = (UINT16)(pSharedInfo->MixerInfo.usRecordCopyEventIndex & 0x7FF); ausWriteData[ 3 ] = 0x0000; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Init the mixer pointer */ pSharedInfo->MixerInfo.usFirstSinCopyEventPtr = pSharedInfo->MixerInfo.usRecordSinEventIndex; } else { /* Configure the head node. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE; BurstParams.ulWriteLength = 4; ausWriteData[ 0 ] = 0x0000; ausWriteData[ 1 ] = 0x0000; ausWriteData[ 2 ] = (UINT16)(cOCT6100_MIXER_TAIL_NODE & 0x7FF); /* Head node. */ ausWriteData[ 3 ] = 0x0000; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Configure the tail node. */ BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + 0x10; BurstParams.ulWriteLength = 4; ausWriteData[ 0 ] = 0x0000; ausWriteData[ 1 ] = 0x0000; ausWriteData[ 2 ] = (UINT16)(cOCT6100_MIXER_HEAD_NODE & 0x7FF); /* Head node. */ ausWriteData[ 3 ] = 0x0000; mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInitRecordResources Description: This function will initialize the resources required to perform recording on a debug channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInitRecordResources UINT32 Oct6100ApiInitRecordResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; pSharedInfo = f_pApiInstance->pSharedInfo; /* Check if recording is enabled. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE ) return cOCT6100_ERR_OK; if ( pSharedInfo->DebugInfo.usRecordMemIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_NOT_SUPPORTED_OPEN_DEBUG_RECORD; /* Check the provided recording memory index within the SSPX. */ if ( pSharedInfo->DebugInfo.usRecordMemIndex != ( pSharedInfo->ImageInfo.usMaxNumberOfChannels - 1 ) ) return cOCT6100_ERR_OPEN_DEBUG_MEM_INDEX; /* Reserve the TSI entries for the channel. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pSharedInfo->DebugInfo.usRecordSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Open the debug channel. */ ulResult = Oct6100ApiDebugChannelOpen( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100FreeResourcesSer Description: This function closes all opened channels and frees all specified global resources used by the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pFreeResources Pointer to user structure in which to choose what to free. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100FreeResourcesSer UINT32 Oct6100FreeResourcesSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_FREE_RESOURCES f_pFreeResources ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; UINT32 i; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Close all bidirectional channels. */ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxBiDirChannels; i ++ ) { tPOCT6100_API_BIDIR_CHANNEL pBiDirChanEntry; mOCT6100_GET_BIDIR_CHANNEL_ENTRY_PNT( pSharedInfo, pBiDirChanEntry, i ); if ( pBiDirChanEntry->fReserved == TRUE ) { tOCT6100_CHANNEL_DESTROY_BIDIR DestroyBidir; Oct6100ChannelDestroyBiDirDef( &DestroyBidir ); DestroyBidir.ulBiDirChannelHndl = cOCT6100_HNDL_TAG_BIDIR_CHANNEL | (pBiDirChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; ulResult = Oct6100ChannelDestroyBiDirSer( f_pApiInstance, &DestroyBidir ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Close all bridge participants. */ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i ++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, i ); if ( pChanEntry->fReserved == TRUE && pChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) { /* This channel is on a bridge. */ tOCT6100_CONF_BRIDGE_CHAN_REMOVE BridgeChanRemove; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; Oct6100ConfBridgeChanRemoveDef( &BridgeChanRemove ); /* Obtain a pointer to the conference bridge's list entry. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pChanEntry->usBridgeIndex ); BridgeChanRemove.fRemoveAll = TRUE; BridgeChanRemove.ulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pBridgeEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pChanEntry->usBridgeIndex; ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &BridgeChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Close all opened channels. This will bring the broadcast TSSTs with it. */ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i ++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, i ); if ( pChanEntry->fReserved == TRUE ) { tOCT6100_CHANNEL_CLOSE ChannelClose; /* Generate handle. */ ChannelClose.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | (pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; /* Call serialized close channel function. */ ulResult = Oct6100ChannelCloseSer( f_pApiInstance, &ChannelClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Close all TSI connections. */ if ( f_pFreeResources->fFreeTsiConnections == TRUE ) { tPOCT6100_API_TSI_CNCT pTsiCnct; tOCT6100_TSI_CNCT_CLOSE TsiCnctClose; Oct6100TsiCnctCloseDef( &TsiCnctClose ); for ( i = 0; i < pSharedInfo->ChipConfig.usMaxTsiCncts; i ++ ) { /* Obtain a pointer to the TSI connection list entry. */ mOCT6100_GET_TSI_CNCT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsiCnct, i ); if ( pTsiCnct->fReserved == TRUE ) { TsiCnctClose.ulTsiCnctHndl = cOCT6100_HNDL_TAG_TSI_CNCT | (pTsiCnct->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; ulResult = Oct6100TsiCnctCloseSer( f_pApiInstance, &TsiCnctClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Close all conference bridges. */ if ( f_pFreeResources->fFreeConferenceBridges == TRUE ) { tPOCT6100_API_CONF_BRIDGE pConfBridge; tOCT6100_CONF_BRIDGE_CLOSE ConfBridgeClose; Oct6100ConfBridgeCloseDef( &ConfBridgeClose ); for ( i = 0; i < pSharedInfo->ChipConfig.usMaxConfBridges; i ++ ) { /* Obtain a pointer to the conference bridge's list entry. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pConfBridge, i ); if ( pConfBridge->fReserved == TRUE ) { ConfBridgeClose.ulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pConfBridge->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; ulResult = Oct6100ConfBridgeCloseSer( f_pApiInstance, &ConfBridgeClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Free all playout buffers loaded in external memory. */ if ( f_pFreeResources->fFreePlayoutBuffers == TRUE ) { tPOCT6100_API_BUFFER pBuffer; tOCT6100_BUFFER_UNLOAD BufferUnload; Oct6100BufferPlayoutUnloadDef( &BufferUnload ); for ( i = 0; i < pSharedInfo->ChipConfig.usMaxPlayoutBuffers; i ++ ) { /* Obtain a pointer to the buffer list entry. */ mOCT6100_GET_BUFFER_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBuffer, i ); if ( pBuffer->fReserved == TRUE ) { BufferUnload.ulBufferIndex = i; ulResult = Oct6100BufferUnloadSer( f_pApiInstance, &BufferUnload, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Close all phasing TSSTs. */ if ( f_pFreeResources->fFreePhasingTssts == TRUE ) { tPOCT6100_API_PHASING_TSST pPhasingTsst; tOCT6100_PHASING_TSST_CLOSE PhasingTsstClose; Oct6100PhasingTsstCloseDef( &PhasingTsstClose ); for ( i = 0; i < pSharedInfo->ChipConfig.usMaxPhasingTssts; i ++ ) { mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pPhasingTsst, i ); if ( pPhasingTsst->fReserved == TRUE ) { PhasingTsstClose.ulPhasingTsstHndl = cOCT6100_HNDL_TAG_PHASING_TSST | (pPhasingTsst->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; ulResult = Oct6100PhasingTsstCloseSer( f_pApiInstance, &PhasingTsstClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Close all ADPCM channels. */ if ( f_pFreeResources->fFreeAdpcmChannels == TRUE ) { tPOCT6100_API_ADPCM_CHAN pAdpcmChannel; tOCT6100_ADPCM_CHAN_CLOSE AdpcmChanClose; Oct6100AdpcmChanCloseDef( &AdpcmChanClose ); for ( i = 0; i < pSharedInfo->ChipConfig.usMaxAdpcmChannels; i ++ ) { mOCT6100_GET_ADPCM_CHAN_ENTRY_PNT( pSharedInfo, pAdpcmChannel, i ); if ( pAdpcmChannel->fReserved == TRUE ) { AdpcmChanClose.ulChanHndl = cOCT6100_HNDL_TAG_ADPCM_CHANNEL | (pAdpcmChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | i; ulResult = Oct6100AdpcmChanCloseSer( f_pApiInstance, &AdpcmChanClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ProductionBistSer Description: This function returns the instantaneous production BIST status. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pProductionBist Pointer to user structure in which BIST status will be returned. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ProductionBistSer UINT32 Oct6100ProductionBistSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_PRODUCTION_BIST f_pProductionBist ) { UINT32 ulCalculatedCrc = cOCT6100_INVALID_VALUE; UINT32 ulResult; UINT32 ulLoopCnt = 0x0; UINT32 i = 1; UINT32 ulTotalElements = 4; UINT32 ulReadAddress = cOCT6100_POUCH_BASE; UINT32 aulMessage[ 5 ]; /* Check if the production bist has been activated. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableProductionBist == FALSE ) return cOCT6100_ERR_PRODUCTION_BIST_DISABLED; f_pProductionBist->ulCurrentAddress = cOCT6100_INVALID_VALUE; f_pProductionBist->ulCurrentLoop = cOCT6100_INVALID_VALUE; f_pProductionBist->ulCurrentTest = cOCT6100_INVALID_VALUE; f_pProductionBist->ulFailedAddress = cOCT6100_INVALID_VALUE; f_pProductionBist->ulReadValue = cOCT6100_INVALID_VALUE; f_pProductionBist->ulExpectedValue = cOCT6100_INVALID_VALUE; f_pProductionBist->ulBistStatus = cOCT6100_BIST_IN_PROGRESS; /* The API knows that the firmware might be writing a status event. */ /* The firmware does write a status event every 200ms (approximately). */ /* So the status is read a couple of times to make sure an event was not read while */ /* it was written. */ while ( ulLoopCnt != 2 ) { /* Read the BIST status in the external memory. */ for ( i = 0; i < ulTotalElements + 1; i ++ ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, ulReadAddress + i * 4, &aulMessage[ i ] ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Calculate the CRC of this message. */ ulResult = Oct6100ApiProductionCrc( f_pApiInstance, aulMessage, ulTotalElements, &ulCalculatedCrc ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* If the CRCs do match, break off the while. We have a valid status event. */ if ( aulMessage[ i - 1 ] == ulCalculatedCrc ) break; ulLoopCnt++; } /* Check if the CRC matches */ if ( aulMessage[ i - 1 ] != ulCalculatedCrc ) { /* Well, the exchange memory at the base of the external memory is corrupted. */ /* Something very basic is not working correctly with this chip! */ f_pProductionBist->ulBistStatus = cOCT6100_BIST_STATUS_CRC_FAILED; } else { /* Check for problems. */ switch ( aulMessage[ 0 ] & 0xFFFF ) { case ( 0x2 ): /* The initial configuration failed. */ f_pProductionBist->ulBistStatus = cOCT6100_BIST_CONFIGURATION_FAILED; break; case ( 0x1 ): /* A memory location failed. Return useful information to the user. */ f_pProductionBist->ulBistStatus = cOCT6100_BIST_MEMORY_FAILED; f_pProductionBist->ulFailedAddress = ( aulMessage[ 1 ] & ( ~0x80000000 ) ) + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; f_pProductionBist->ulReadValue = aulMessage[ 2 ]; f_pProductionBist->ulExpectedValue = aulMessage[ 3 ]; break; case ( 0xFFFF ): /* Bist is completed! */ f_pProductionBist->ulBistStatus = cOCT6100_BIST_SUCCESS; break; default: /* Bist is in progress. All seems to be working fine up to now. */ /* Return progress status. */ f_pProductionBist->ulCurrentAddress = ( aulMessage[ 1 ] & ( ~0x80000000 ) ) + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; f_pProductionBist->ulCurrentTest = aulMessage[ 2 ]; f_pProductionBist->ulCurrentLoop = aulMessage[ 3 ]; break; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiProductionCrc Description: This function calculates the crc for a production BIST message. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulMessage Message to be exchanged with the firmware. The CRC will be calculated on this. f_ulMessageLength Length of the message to be exchanged. This value does not include the CRC value at the end f_pulCrcResult Resulting calculated CRC value. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiProductionCrc UINT32 Oct6100ApiProductionCrc( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulMessage, IN UINT32 f_ulMessageLength, OUT PUINT32 f_pulCrcResult ) { UINT32 ulWidth = 32; UINT32 ulKey, i, j; UINT32 ulRemainder = 0; /* CRC the message. */ ulRemainder = f_pulMessage[ f_ulMessageLength - 1 ]; for ( j = f_ulMessageLength - 1; j != 0xFFFFFFFF ; j-- ) { for ( i = 0; i < ulWidth; i++ ) { if ( ( ( ulRemainder >> 0x1F ) & 0x1 ) == 0x1 ) { /* Division is by something meaningful */ ulKey = 0x8765DCBA; } else { /* Remainder is less than our divisor */ ulKey = 0; } ulRemainder = ulRemainder ^ ulKey; ulRemainder = ulRemainder << 1; if ( j != 0 ) { ulRemainder = ulRemainder | ( ( f_pulMessage[ j - 1 ] ) >> ( 0x1F - i ) ); } } } *f_pulCrcResult = ulRemainder; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiClearInterrupts Description: Called only by the Oct6100OpenChip function, this function writes to all register ROLs to clear them. This is necessary because some ROLs are set during the startup. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- IN f_pApiInst Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiClearInterrupts UINT32 Oct6100ApiClearInterrupts( IN tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; WriteParams.ulWriteAddress = 0x102; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_102H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x202; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_202H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x302; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_302H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x502; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_502H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x702; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_702H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_remote_debug.c0000644000175000017500000016566511431317470032123 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_remote_debug.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the routines used for remote debugging. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 35 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_bt0.h" #include "apilib/octapi_largmath.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_debug_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_remote_debug_pub.h" #include "octrpc/rpc_protocol.h" #include "octrpc/oct6100_rpc_protocol.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_chip_open_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_debug_priv.h" #include "oct6100_remote_debug_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100RemoteDebug Description: This function interprets the remote debugging packets received by the user’s software. Commands contained in the packet are executed by the API. In addition, a response packet is constructed and returned by the function. It is the responsibility of the user’s software to transmit the response packet back to the source of the debugging packet. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pRemoteDebug Pointer to a remote debug structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100RemoteDebugDef UINT32 Oct6100RemoteDebugDef( tPOCT6100_REMOTE_DEBUG f_pRemoteDebug ) { f_pRemoteDebug->pulReceivedPktPayload = NULL; f_pRemoteDebug->ulReceivedPktLength = 0; f_pRemoteDebug->pulResponsePktPayload = NULL; f_pRemoteDebug->ulMaxResponsePktLength = 0; f_pRemoteDebug->ulResponsePktLength = 0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100RemoteDebug UINT32 Oct6100RemoteDebug( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_REMOTE_DEBUG f_pRemoteDebug ) { tPOCTRPC_OGRDTP_HEADER pOgrdtpHeader; tPOCTRPC_INTERFACE_HEADER pInterfaceHeader; tPOCTRPC_COMMAND_HEADER pRspCmndHeader; PUINT32 pulRcvPktPayload; PUINT32 pulRspPktPayload; UINT32 ulPktLengthDword; UINT32 ulSessionIndex; UINT32 ulChecksum; UINT32 ulResult; /* Check for errors. */ if ( f_pRemoteDebug->pulReceivedPktPayload == NULL ) return cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_PAYLOAD; if ( f_pRemoteDebug->pulResponsePktPayload == NULL ) return cOCT6100_ERR_REMOTEDEBUG_RESPONSE_PKT_PAYLOAD; if ( f_pRemoteDebug->ulReceivedPktLength < cOCTRPC_MIN_PACKET_BYTE_LENGTH ) return cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_LENGTH; if ( f_pRemoteDebug->ulReceivedPktLength > cOCTRPC_MAX_PACKET_BYTE_LENGTH ) return cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_LENGTH; if ( f_pRemoteDebug->ulMaxResponsePktLength < f_pRemoteDebug->ulReceivedPktLength ) return cOCT6100_ERR_REMOTEDEBUG_RESPONSE_PKT_LENGTH; if ( (f_pRemoteDebug->ulReceivedPktLength % 4) != 0 ) return cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_LENGTH; if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxRemoteDebugSessions == 0 ) return cOCT6100_ERR_REMOTEDEBUG_DISABLED; /* Set response length as received length. */ f_pRemoteDebug->ulResponsePktLength = f_pRemoteDebug->ulReceivedPktLength; /* Typecast the packet payload to local pointers. */ pOgrdtpHeader = ( tPOCTRPC_OGRDTP_HEADER )f_pRemoteDebug->pulReceivedPktPayload; pInterfaceHeader = ( tPOCTRPC_INTERFACE_HEADER )(f_pRemoteDebug->pulReceivedPktPayload + (sizeof( tOCTRPC_OGRDTP_HEADER ) / 4)); /* Get local pointer to received and response packet payloads. */ pulRcvPktPayload = f_pRemoteDebug->pulReceivedPktPayload; pulRspPktPayload = f_pRemoteDebug->pulResponsePktPayload; /* Get the length of the packet in UINT32s. */ ulPktLengthDword = f_pRemoteDebug->ulReceivedPktLength / 4; /* Check the endian detection field to determine if the payload must be */ /* swapped to account for different endian formats. */ ulResult = Oct6100ApiCheckEndianDetectField( pOgrdtpHeader, ulPktLengthDword ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check the packet's length. */ if ( pOgrdtpHeader->ulPktByteSize != f_pRemoteDebug->ulReceivedPktLength ) return cOCT6100_ERR_REMOTEDEBUG_RECEIVED_PKT_LENGTH; /* Perform the sum of each word in the packet and compare to checksum. */ Oct6100ApiCalculateChecksum( pulRcvPktPayload, ulPktLengthDword, &ulChecksum ); if ( ulChecksum != pOgrdtpHeader->ulChecksum ) return cOCT6100_ERR_REMOTEDEBUG_CHECKSUM; /* Check if the packet's session number has a corresponding entry in the API table. If not then close an entry which has timed out, and allocate the entry to the new session number. */ ulResult = Oct6100ApiCheckSessionNum( f_pApiInstance, pOgrdtpHeader, &ulSessionIndex ); if ( ulResult == cOCT6100_ERR_REMOTEDEBUG_ALL_SESSIONS_OPEN ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, cOCT6100_INVALID_VALUE, cOCTRPC_RDBGERR_ALL_SESSIONS_OPEN, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } else if ( ulResult == cOCT6100_ERR_REMOTEDEBUG_TRANSACTION_ANSWERED ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, TRUE, FALSE, FALSE, FALSE, ulSessionIndex, cOCT6100_INVALID_VALUE, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } else if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Check if an echo packet. If so then there's no need to check the rest of the packet. Simply copy the packet back to the output buffer, enter the protocol number supported by this API compilation, and recalculate the checksum. If the packet is not an echo packet and the protocol version does not correspond to this compiled version then return the supported protocol version. */ if ( pOgrdtpHeader->ulRpcProtocolNum == cOCTRPC_ECHO_PROTOCOL ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, TRUE, FALSE, FALSE, ulSessionIndex, cOCT6100_INVALID_VALUE, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } else if ( pOgrdtpHeader->ulRpcProtocolNum != cOCTRPC_PROTOCOL_V1_1 ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, TRUE, FALSE, FALSE, ulSessionIndex, cOCTRPC_RDBGERR_PROTOCOL_NUMBER, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } else if ( f_pRemoteDebug->ulReceivedPktLength <= cOCTRPC_FIRST_COMMAND_BYTE_OFFSET ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, ulSessionIndex, cOCTRPC_RDBGERR_NO_COMMAND_HEADER, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } /* Check the packet's RPC interface type and version. If either does not match then return the packet with the supported interface type and version of this compilation. */ if ( pInterfaceHeader->ulInterfaceVersion != cOCTRPC_INTERFACE_VERSION ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, FALSE, TRUE, TRUE, ulSessionIndex, cOCTRPC_RDBGERR_INTERFACE_VERSION, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } if ( pInterfaceHeader->ulInterfaceType != cOCTRPC_OCT6100_INTERFACE ) { Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, FALSE, TRUE, TRUE, ulSessionIndex, cOCTRPC_RDBGERR_INTERFACE_TYPE, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } /* Check each command header to make sure the indicated command and length agree. If there is an error in the packet's commands then the response packet will be constructed by the function. */ ulResult = Oct6100ApiCheckPktCommands( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulSessionIndex, ulPktLengthDword, ulChecksum ); if ( ulResult == cOCT6100_ERR_REMOTE_DEBUG_PARSING_ERROR ) return cOCT6100_ERR_OK; /* The packet's fields are valid. Each command must now be extracted and executed. */ Oct6100ApiExecutePktCommands( f_pApiInstance, pulRcvPktPayload, ulPktLengthDword ); pRspCmndHeader = ( tPOCTRPC_COMMAND_HEADER )(( PUINT32 )pulRspPktPayload + ((sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) / 4)); /* Verify if the new method of using the protocol is the selected case. */ /* All commands have been executed. Calculate the packet's new checksum and copy the packet to user provided buffer for response packet. */ Oct6100ApiCalculateChecksum( pulRcvPktPayload, ulPktLengthDword, &ulChecksum ); /* Send response packet. */ Oct6100ApiFormResponsePkt( f_pApiInstance, pulRcvPktPayload, pulRspPktPayload, ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, ulSessionIndex, cOCTRPC_RDBGERR_OK, cOCT6100_INVALID_VALUE, ulChecksum ); return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetRemoteDebugSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of remote debugging. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pChipOpen Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetRemoteDebugSwSizes UINT32 Oct6100ApiGetRemoteDebugSwSizes( IN tPOCT6100_CHIP_OPEN f_pChipOpen, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Memory needed for remote debugging sessions. */ if ( f_pChipOpen->ulMaxRemoteDebugSessions > 0 ) { f_pInstSizes->ulRemoteDebugList = f_pChipOpen->ulMaxRemoteDebugSessions * sizeof( tOCT6100_API_REMOTE_DEBUG_SESSION ); ulResult = octapi_bt0_get_size( f_pChipOpen->ulMaxRemoteDebugSessions, 4, 4, &f_pInstSizes->ulRemoteDebugTree ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_41; f_pInstSizes->ulRemoteDebugPktCache = cOCTRPC_MAX_PACKET_BYTE_LENGTH * f_pChipOpen->ulMaxRemoteDebugSessions; f_pInstSizes->ulRemoteDebugDataBuf = cOCTRPC_MAX_PACKET_BYTE_LENGTH * 4; } else { f_pInstSizes->ulRemoteDebugList = 0; f_pInstSizes->ulRemoteDebugTree = 0; f_pInstSizes->ulRemoteDebugPktCache = 0; f_pInstSizes->ulRemoteDebugDataBuf = 0; } /* Round off the size. */ mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulRemoteDebugList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulRemoteDebugTree, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulRemoteDebugPktCache, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulRemoteDebugDataBuf, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRemoteDebuggingSwInit Description: Initializes all portions of the API instance associated to remote debugging. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRemoteDebuggingSwInit UINT32 Oct6100ApiRemoteDebuggingSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pSessionTree; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; pSharedInfo->RemoteDebugInfo.ulNumSessionsOpen = 0; pSharedInfo->RemoteDebugInfo.ulMaxSessionsOpen = pSharedInfo->ChipConfig.usMaxRemoteDebugSessions; pSharedInfo->RemoteDebugInfo.ulSessionListHead = cOCT6100_INVALID_VALUE; pSharedInfo->RemoteDebugInfo.ulSessionListTail = cOCT6100_INVALID_VALUE; if ( pSharedInfo->ChipConfig.usMaxRemoteDebugSessions > 0 ) { mOCT6100_GET_REMOTE_DEBUG_TREE_PNT( pSharedInfo, pSessionTree ) ulResult = octapi_bt0_init( ( ( PVOID* )&pSessionTree ), pSharedInfo->ChipConfig.usMaxRemoteDebugSessions, 4, 4 ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_42; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckEndianDetectField Description: Checks the endian field of a packet and performs a swap of the packet data if deemed necessary. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulPktLengthDword Length of the packet in dwords. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckEndianDetectField UINT32 Oct6100ApiCheckEndianDetectField( IN OUT tPOCTRPC_OGRDTP_HEADER f_pOgrdtpHeader, IN UINT32 f_ulPktLengthDword ) { PUINT32 pulPktPayload; UINT32 ulBytePositionW = cOCT6100_INVALID_VALUE; UINT32 ulBytePositionX = cOCT6100_INVALID_VALUE; UINT32 ulBytePositionY = cOCT6100_INVALID_VALUE; UINT32 ulBytePositionZ = cOCT6100_INVALID_VALUE; UINT32 ulTempVar; UINT32 i; /* Bytes in dword are labeled as Z Y X W. */ /* Only swap if necessary. */ if ( f_pOgrdtpHeader->ulEndianDetect != cOCTRPC_ENDIAN_DETECT ) { /* Find the position of each byte. */ for ( i = 0; i < 4; i++ ) { ulTempVar = (f_pOgrdtpHeader->ulEndianDetect >> (8 * i)) & 0xFF; switch ( ulTempVar ) { case cOCTRPC_ENDIAN_DETECT_BYTE_W: ulBytePositionW = i * 8; break; case cOCTRPC_ENDIAN_DETECT_BYTE_X: ulBytePositionX = i * 8; break; case cOCTRPC_ENDIAN_DETECT_BYTE_Y: ulBytePositionY = i * 8; break; case cOCTRPC_ENDIAN_DETECT_BYTE_Z: ulBytePositionZ = i * 8; break; default: return cOCT6100_ERR_REMOTEDEBUG_INVALID_PACKET; } } /* Make sure all bytes of the endian detect field were found. */ if ( ulBytePositionW == cOCT6100_INVALID_VALUE || ulBytePositionX == cOCT6100_INVALID_VALUE || ulBytePositionY == cOCT6100_INVALID_VALUE || ulBytePositionZ == cOCT6100_INVALID_VALUE ) return cOCT6100_ERR_REMOTEDEBUG_INVALID_PACKET; /* Swap the bytes of each dword of the packet. */ pulPktPayload = ( PUINT32 )f_pOgrdtpHeader; for ( i = 0; i < f_ulPktLengthDword; i++ ) { ulTempVar = pulPktPayload[ i ]; pulPktPayload[ i ] = ((ulTempVar >> ulBytePositionZ) & 0xFF) << 24; pulPktPayload[ i ] |= ((ulTempVar >> ulBytePositionY) & 0xFF) << 16; pulPktPayload[ i ] |= ((ulTempVar >> ulBytePositionX) & 0xFF) << 8; pulPktPayload[ i ] |= ((ulTempVar >> ulBytePositionW) & 0xFF) << 0; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCalculateChecksum Description: Calculates the checksum of the given packet payload. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pulPktPayload Pointer to the payload of the packet. f_ulPktLengthDword Length of the packet in dwords. f_pulChecksum Pointer to the checksum of the packet. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCalculateChecksum VOID Oct6100ApiCalculateChecksum( IN PUINT32 f_pulPktPayload, IN UINT32 f_ulPktLengthDword, OUT PUINT32 f_pulChecksum ) { tPOCTRPC_OGRDTP_HEADER pOgrdtpHeader; UINT32 i; for ( i = 0, *f_pulChecksum = 0; i < f_ulPktLengthDword; i++ ) { *f_pulChecksum += (f_pulPktPayload[ i ] >> 16) & 0xFFFF; *f_pulChecksum += (f_pulPktPayload[ i ] >> 0) & 0xFFFF; } pOgrdtpHeader = ( tPOCTRPC_OGRDTP_HEADER )f_pulPktPayload; *f_pulChecksum -= (pOgrdtpHeader->ulChecksum >> 16) & 0xFFFF; *f_pulChecksum -= (pOgrdtpHeader->ulChecksum >> 0) & 0xFFFF; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiFormResponsePkt Description: Modifies the values of the indicated receive packet, update the checksum field, and copy the receive packet to the response packet. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulRcvPktPayload Pointer to the payload of the received packet. f_pulRspPktPayload Pointer to the payload of the response packet. f_ulPktLengthDword Length of the packet in dwords. f_fRetryPktResponse Flag indicating if the received packet was a retry packet. f_fReplaceProtocolNum Flag indicating if the protocol number must be replaced. f_fReplaceInterfaceType Flag indicating if the interface type must be replaced. f_fReplaceInterfaceVersion Flag indicating if the interface version must be replaced. f_ulSessionIndex Index of the remote debug session within the API' session list. f_ulParsingErrorValue Parsing error value. f_ulPayloadDwordIndex Index in the packet where the payload starts. f_ulChecksum Checksum of the packet. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiFormResponsePkt VOID Oct6100ApiFormResponsePkt( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, OUT PUINT32 f_pulRspPktPayload, IN UINT32 f_ulPktLengthDword, IN BOOL f_fRetryPktResponse, IN BOOL f_fReplaceProtocolNum, IN BOOL f_fReplaceInterfaceType, IN BOOL f_fReplaceInterfaceVersion, IN UINT32 f_ulSessionIndex, IN UINT32 f_ulParsingErrorValue, IN UINT32 f_ulPayloadDwordIndex, IN UINT32 f_ulChecksum ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCTRPC_OGRDTP_HEADER pOgrdtpHeader; tPOCTRPC_INTERFACE_HEADER pInterfaceHeader; PUINT32 pulPktCache; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Typecast pointer to OGRDTP packet header. */ pOgrdtpHeader = ( tPOCTRPC_OGRDTP_HEADER )f_pulRcvPktPayload; /* Check if a response to a retry packet. */ if ( f_fRetryPktResponse == TRUE ) { mOCT6100_GET_REMOTE_DEBUG_SESSION_PKT_CACHE_PNT( pSharedInfo, pulPktCache, f_ulSessionIndex ) Oct6100UserMemCopy( f_pulRspPktPayload, pulPktCache, f_ulPktLengthDword * 4 ); return; } /* Replace all packet header fields which must be changed. */ if ( f_ulParsingErrorValue != cOCT6100_INVALID_VALUE ) { f_ulChecksum -= (pOgrdtpHeader->ulParsingError >> 16) & 0xFFFF; f_ulChecksum -= (pOgrdtpHeader->ulParsingError >> 0) & 0xFFFF; pOgrdtpHeader->ulParsingError = f_ulParsingErrorValue; f_ulChecksum += (pOgrdtpHeader->ulParsingError >> 16) & 0xFFFF; f_ulChecksum += (pOgrdtpHeader->ulParsingError >> 0) & 0xFFFF; } if ( f_fReplaceProtocolNum == TRUE ) { f_ulChecksum -= (pOgrdtpHeader->ulRpcProtocolNum >> 16) & 0xFFFF; f_ulChecksum -= (pOgrdtpHeader->ulRpcProtocolNum >> 0) & 0xFFFF; pOgrdtpHeader->ulRpcProtocolNum = cOCTRPC_PROTOCOL_V1_1; f_ulChecksum += (pOgrdtpHeader->ulRpcProtocolNum >> 16) & 0xFFFF; f_ulChecksum += (pOgrdtpHeader->ulRpcProtocolNum >> 0) & 0xFFFF; } if ( f_fReplaceInterfaceType == TRUE ) { pInterfaceHeader = ( tPOCTRPC_INTERFACE_HEADER )(f_pulRcvPktPayload + (sizeof( tOCTRPC_OGRDTP_HEADER ) / 4)); f_ulChecksum -= (pInterfaceHeader->ulInterfaceType >> 16) & 0xFFFF; f_ulChecksum -= (pInterfaceHeader->ulInterfaceType >> 0) & 0xFFFF; pInterfaceHeader->ulInterfaceType = cOCTRPC_OCT6100_INTERFACE; f_ulChecksum += (pInterfaceHeader->ulInterfaceType >> 16) & 0xFFFF; f_ulChecksum += (pInterfaceHeader->ulInterfaceType >> 0) & 0xFFFF; } if ( f_fReplaceInterfaceVersion == TRUE ) { pInterfaceHeader = ( tPOCTRPC_INTERFACE_HEADER )(f_pulRcvPktPayload + (sizeof( tOCTRPC_OGRDTP_HEADER ) / 4)); f_ulChecksum -= (pInterfaceHeader->ulInterfaceVersion >> 16) & 0xFFFF; f_ulChecksum -= (pInterfaceHeader->ulInterfaceVersion >> 0) & 0xFFFF; pInterfaceHeader->ulInterfaceVersion = cOCTRPC_INTERFACE_VERSION; f_ulChecksum += (pInterfaceHeader->ulInterfaceVersion >> 16) & 0xFFFF; f_ulChecksum += (pInterfaceHeader->ulInterfaceVersion >> 0) & 0xFFFF; } if ( f_ulPayloadDwordIndex != cOCT6100_INVALID_VALUE ) { f_pulRcvPktPayload += f_ulPayloadDwordIndex; f_ulChecksum -= (*f_pulRcvPktPayload >> 16) & 0xFFFF; f_ulChecksum -= (*f_pulRcvPktPayload >> 0) & 0xFFFF; *f_pulRcvPktPayload = cOCTRPC_UNKNOWN_COMMAND_NUM; f_ulChecksum += (*f_pulRcvPktPayload >> 16) & 0xFFFF; f_ulChecksum += (*f_pulRcvPktPayload >> 0) & 0xFFFF; f_pulRcvPktPayload -= f_ulPayloadDwordIndex; } /* Replace checksum. */ pOgrdtpHeader->ulChecksum = f_ulChecksum; /* Copy the modified receive packet payload to the response packet. */ Oct6100UserMemCopy( f_pulRspPktPayload, f_pulRcvPktPayload, f_ulPktLengthDword * 4 ); /* Copy the response packet to the session's packet cache. */ if ( f_ulSessionIndex != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_SESSION_PKT_CACHE_PNT( pSharedInfo, pulPktCache, f_ulSessionIndex ) Oct6100UserMemCopy( pulPktCache, f_pulRspPktPayload, f_ulPktLengthDword * 4 ); } } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckPktCommands Description: Checks the commands contained in the packet for errors in size. Also checks for unknown commands. If an error is encountered then the function will construct the response packet. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulRcvPktPayload Pointer to the payload of the received packet. f_pulRspPktPayload Pointer to the payload of the response packet. f_ulPktLengthDword Length of the packet in dwords. f_ulSessionIndex Index of the remote debug session within the API' session list. f_ulChecksum Checksum of the packet. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckPktCommands UINT32 Oct6100ApiCheckPktCommands( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, IN OUT PUINT32 f_pulRspPktPayload, IN UINT32 f_ulSessionIndex, IN UINT32 f_ulPktLengthDword, IN UINT32 f_ulChecksum ) { tPOCTRPC_COMMAND_HEADER pCmndHeader; UINT32 ulNumDwordsLeft; UINT32 ulNumDwordsNeeded = 0; UINT32 ulRpcCmndSizeDword; BOOL fCmndIdentified; BOOL fCmndHeaderPresent; pCmndHeader = ( tPOCTRPC_COMMAND_HEADER )(f_pulRcvPktPayload + ((sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) / 4)); ulNumDwordsLeft = f_ulPktLengthDword - ((sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) / 4); ulRpcCmndSizeDword = sizeof( tOCTRPC_COMMAND_HEADER ) / 4; fCmndIdentified = TRUE; while ( ulNumDwordsLeft != 0 ) { if ( ulNumDwordsLeft < ulRpcCmndSizeDword ) { fCmndHeaderPresent = FALSE; } else { fCmndHeaderPresent = TRUE; switch ( pCmndHeader->ulRpcCommandNum ) { case cOCT6100_RPC_READ_WORD: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_READ_WORD ) / 4; } break; case cOCT6100_RPC_READ_BURST: { tPOCT6100_RPC_READ_BURST pBurstHeader; ulNumDwordsNeeded = (sizeof( tOCT6100_RPC_READ_BURST ) - sizeof( UINT32 )) / 4; pBurstHeader = ( tPOCT6100_RPC_READ_BURST )(( PUINT32 )pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); ulNumDwordsNeeded += (pBurstHeader->ulBurstLength + 1) / 2; } break; case cOCT6100_RPC_WRITE_WORD: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_WRITE_WORD ) / 4; } break; case cOCT6100_RPC_WRITE_SMEAR: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_WRITE_SMEAR ) / 4; } break; case cOCT6100_RPC_WRITE_INC: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_WRITE_INC ) / 4; } break; case cOCT6100_RPC_READ_ARRAY: { tPOCT6100_RPC_READ_ARRAY pArrayHeader; ulNumDwordsNeeded = (sizeof( tOCT6100_RPC_READ_ARRAY ) - sizeof( UINT32 )) / 4; pArrayHeader = ( tPOCT6100_RPC_READ_ARRAY )(( PUINT32 )pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); ulNumDwordsNeeded += pArrayHeader->ulArrayLength; ulNumDwordsNeeded += (pArrayHeader->ulArrayLength + 1) / 2; } break; case cOCT6100_RPC_WRITE_BURST: { tPOCT6100_RPC_WRITE_BURST pBurstHeader; ulNumDwordsNeeded = (sizeof( tOCT6100_RPC_WRITE_BURST ) - sizeof( UINT32 )) / 4; pBurstHeader = ( tPOCT6100_RPC_WRITE_BURST )(( PUINT32 )pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); ulNumDwordsNeeded += (pBurstHeader->ulBurstLength + 1) / 2; } break; case cOCT6100_RPC_SET_HOT_CHANNEL: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_SET_HOT_CHANNEL ) / 4; } break; case cOCT6100_RPC_GET_DEBUG_CHAN_INDEX: { ulNumDwordsNeeded = sizeof( tOCT6100_RPC_GET_DEBUG_CHAN_INDEX ) / 4; } break; case cOCT6100_RPC_API_DISCONNECT: { /* There is no parameter to the disconnect command. */ ulNumDwordsNeeded = 0; } break; default: fCmndIdentified = FALSE; } ulNumDwordsNeeded += sizeof( tOCTRPC_COMMAND_HEADER ) / 4; } if ( fCmndHeaderPresent != TRUE ) { Oct6100ApiFormResponsePkt( f_pApiInstance, f_pulRcvPktPayload, f_pulRspPktPayload, f_ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, f_ulSessionIndex, cOCTRPC_RDBGERR_INVALID_PACKET_LENGTH, cOCT6100_INVALID_VALUE, f_ulChecksum ); return cOCT6100_ERR_REMOTE_DEBUG_PARSING_ERROR; } if ( fCmndIdentified != TRUE ) { Oct6100ApiFormResponsePkt( f_pApiInstance, f_pulRcvPktPayload, f_pulRspPktPayload, f_ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, f_ulSessionIndex, cOCTRPC_RDBGERR_INVALID_COMMAND_NUMBER, f_ulPktLengthDword - ulNumDwordsLeft, f_ulChecksum ); return cOCT6100_ERR_REMOTE_DEBUG_PARSING_ERROR; } if ( ulNumDwordsNeeded != (pCmndHeader->ulCommandByteSize / 4) || ulNumDwordsNeeded > ulNumDwordsLeft ) { Oct6100ApiFormResponsePkt( f_pApiInstance, f_pulRcvPktPayload, f_pulRspPktPayload, f_ulPktLengthDword, FALSE, FALSE, FALSE, FALSE, f_ulSessionIndex, cOCTRPC_RDBGERR_INVALID_COMMAND_LENGTH, cOCT6100_INVALID_VALUE, f_ulChecksum ); return cOCT6100_ERR_REMOTE_DEBUG_PARSING_ERROR; } pCmndHeader = ( tPOCTRPC_COMMAND_HEADER )(( PUINT32 )pCmndHeader + ulNumDwordsNeeded); ulNumDwordsLeft -= ulNumDwordsNeeded; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiExecutePktCommands Description: Executes the commands contained in the received packet. The received packet payload buffer is modified but NOT copied to the response packet buffer. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulRcvPktPayload Pointer to the payload of the received packet. f_ulPktLengthDword Length of the packet in dwords. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiExecutePktCommands VOID Oct6100ApiExecutePktCommands( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN PUINT32 f_pulRcvPktPayload, IN UINT32 f_ulPktLengthDword ) { tPOCTRPC_COMMAND_HEADER pReqCmndHeader; tPOCTRPC_OGRDTP_HEADER pReqPktHeader; UINT32 ulNumDwordsLeft; UINT32 ulRpcCmndSizeDword; pReqPktHeader = ( tPOCTRPC_OGRDTP_HEADER )(f_pulRcvPktPayload); pReqCmndHeader = ( tPOCTRPC_COMMAND_HEADER )(( PUINT32 )f_pulRcvPktPayload + ((sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) / 4)); ulNumDwordsLeft = f_ulPktLengthDword - ((sizeof( tOCTRPC_OGRDTP_HEADER ) + sizeof( tOCTRPC_INTERFACE_HEADER )) / 4); ulRpcCmndSizeDword = sizeof( tOCTRPC_COMMAND_HEADER ) / 4; while ( ulNumDwordsLeft != 0 ) { /* Switch on command number. */ switch ( pReqCmndHeader->ulRpcCommandNum ) { case cOCT6100_RPC_READ_WORD: Oct6100ApiRpcReadWord( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_READ_BURST: Oct6100ApiRpcReadBurst( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_READ_ARRAY: Oct6100ApiRpcReadArray( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_WRITE_WORD: Oct6100ApiRpcWriteWord( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_WRITE_SMEAR: Oct6100ApiRpcWriteSmear( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_WRITE_BURST: Oct6100ApiRpcWriteBurst( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_SET_HOT_CHANNEL: Oct6100ApiRpcSetHotChannel( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_GET_DEBUG_CHAN_INDEX: Oct6100ApiRpcGetDebugChanIndex( f_pApiInstance, pReqCmndHeader ); break; case cOCT6100_RPC_API_DISCONNECT: Oct6100ApiRpcDisconnect( f_pApiInstance, pReqCmndHeader, pReqPktHeader->ulDebugSessionNum ); break; default: pReqCmndHeader->ulFunctionResult = cOCT6100_ERR_REMOTEDEBUG_INVALID_RPC_COMMAND_NUM; break; } /* Insert the result of the operation in the command header. */ if ( pReqCmndHeader->ulFunctionResult != cOCT6100_ERR_OK ) break; /* Decrement the number of DWORDs left in the packet. */ ulNumDwordsLeft -= pReqCmndHeader->ulCommandByteSize / 4; /* Point to the next command in the packet. */ pReqCmndHeader = ( tPOCTRPC_COMMAND_HEADER )(( PUINT32 )pReqCmndHeader + (pReqCmndHeader->ulCommandByteSize / 4)); } } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckSessionNum Description: Checks if there is a session list entry open for the session number received. If not, a free one is reserved if one is available. If none are free, one which has timed-out is released. If none are timed out then an error is returned. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pOgrdtpHeader Pointer to the header of the packet. f_pulSessionIndex Pointer to the remote debugging session within the API's session list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckSessionNum UINT32 Oct6100ApiCheckSessionNum( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCTRPC_OGRDTP_HEADER f_pOgrdtpHeader, OUT PUINT32 f_pulSessionIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_REMOTE_DEBUG_INFO pRemoteDebugInfo; tPOCT6100_API_REMOTE_DEBUG_SESSION pSessionEntry; tPOCT6100_API_REMOTE_DEBUG_SESSION pSessionLink; tOCT6100_GET_TIME GetTime; PVOID pSessionTree; PUINT32 pulTreeData; UINT32 ulNewSessionIndex; UINT32 aulTimeDiff[ 2 ]; UINT32 ulResult; UINT16 usNegative; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context of GetTime. */ GetTime.pProcessContext = f_pApiInstance->pProcessContext; /* Get the current system time. */ ulResult = Oct6100UserGetTime( &GetTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get a local pointer to the remote debugging info. */ pRemoteDebugInfo = &pSharedInfo->RemoteDebugInfo; /* Check if the session number has an associated session list entry. */ mOCT6100_GET_REMOTE_DEBUG_TREE_PNT( pSharedInfo, pSessionTree ) ulResult = octapi_bt0_query_node( pSessionTree, ( ( PVOID )(&f_pOgrdtpHeader->ulDebugSessionNum) ), ( ( PVOID* )&pulTreeData ) ); if ( ulResult == cOCT6100_ERR_OK ) { /* Return session index. */ *f_pulSessionIndex = *pulTreeData; /* A session list entry is associated, so update the entries last packet time, transaction number and packet retry number, and position in the linked list. */ mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, *pulTreeData, pSessionEntry ) pSessionEntry->aulLastPktTime[ 0 ] = GetTime.aulWallTimeUs[ 0 ]; pSessionEntry->aulLastPktTime[ 1 ] = GetTime.aulWallTimeUs[ 1 ]; pSessionEntry->ulPktRetryNum = f_pOgrdtpHeader->ulPktRetryNum; /* Remove the node from its current place in the linked-list and add it to the end. */ if ( pRemoteDebugInfo->ulSessionListTail != *pulTreeData ) { /* Obtain local pointer to the session list entry to be moved. */ mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, *pulTreeData, pSessionEntry ) /* Update link of previous session in list. */ if ( pSessionEntry->ulBackwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulBackwardLink, pSessionLink ) pSessionLink->ulForwardLink = pSessionEntry->ulForwardLink; } else { pRemoteDebugInfo->ulSessionListHead = pSessionEntry->ulForwardLink; } /* Update link of next session in list. */ if ( pSessionEntry->ulForwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulForwardLink, pSessionLink ) pSessionLink->ulBackwardLink = pSessionEntry->ulBackwardLink; } else { pRemoteDebugInfo->ulSessionListTail = pSessionEntry->ulBackwardLink; } /* Place session at the end of the list. */ pSessionEntry->ulBackwardLink = pRemoteDebugInfo->ulSessionListTail; pSessionEntry->ulForwardLink = cOCT6100_INVALID_VALUE; pRemoteDebugInfo->ulSessionListTail = *pulTreeData; if ( pRemoteDebugInfo->ulSessionListHead == cOCT6100_INVALID_VALUE ) { pRemoteDebugInfo->ulSessionListHead = *pulTreeData; } else { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulBackwardLink, pSessionLink ) pSessionLink->ulForwardLink = *pulTreeData; } } /* Check if packet should be interpreted based on transaction number. */ if ( f_pOgrdtpHeader->ulPktRetryNum != 0 && pSessionEntry->ulTransactionNum == f_pOgrdtpHeader->ulTransactionNum && pSessionEntry->ulPktByteSize == f_pOgrdtpHeader->ulPktByteSize ) return cOCT6100_ERR_REMOTEDEBUG_TRANSACTION_ANSWERED; /* Update transaction number since packet will be interpreted. */ pSessionEntry->ulTransactionNum = f_pOgrdtpHeader->ulTransactionNum; pSessionEntry->ulPktByteSize = f_pOgrdtpHeader->ulPktByteSize; return cOCT6100_ERR_OK; } else if ( ulResult == OCTAPI_BT0_KEY_NOT_IN_TREE ) { /* If there is a free entry in the session list then seize it. Else, try to find an entry which has timed out. If there are none then return an error. */ if ( pRemoteDebugInfo->ulNumSessionsOpen < pRemoteDebugInfo->ulMaxSessionsOpen ) { ulNewSessionIndex = pRemoteDebugInfo->ulNumSessionsOpen; } else /* ( pRemoteDebugInfo->ulNumSessionsOpen == pRemoteDebugInfo->ulMaxSessionsOpen ) */ { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pRemoteDebugInfo->ulSessionListHead, pSessionEntry ) ulResult = octapi_lm_subtract( GetTime.aulWallTimeUs, 1, pSessionEntry->aulLastPktTime, 1, aulTimeDiff, 1, &usNegative ); if ( ulResult != cOCT6100_ERR_OK || usNegative != FALSE ) return cOCT6100_ERR_FATAL_43; /* If there are no session list entries available then return the packet with a parsing error. */ if ( aulTimeDiff[ 1 ] == 0 && aulTimeDiff[ 0 ] < (cOCTRPC_SESSION_TIMEOUT * 1000000) ) return cOCT6100_ERR_REMOTEDEBUG_ALL_SESSIONS_OPEN; ulNewSessionIndex = pRemoteDebugInfo->ulSessionListHead; /* Remove old session index. */ ulResult = octapi_bt0_remove_node( pSessionTree, ( ( PVOID )&pSessionEntry->ulSessionNum ) ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_44; if ( pSessionEntry->ulBackwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulBackwardLink, pSessionLink ) pSessionLink->ulForwardLink = pSessionEntry->ulForwardLink; } else { pRemoteDebugInfo->ulSessionListHead = pSessionEntry->ulForwardLink; } if ( pSessionEntry->ulForwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulForwardLink, pSessionLink ) pSessionLink->ulBackwardLink = pSessionEntry->ulBackwardLink; } else { pRemoteDebugInfo->ulSessionListTail = pSessionEntry->ulBackwardLink; } /* Decrement number of open sessions. */ pRemoteDebugInfo->ulNumSessionsOpen--; } /* Add new session. */ ulResult = octapi_bt0_add_node( pSessionTree, ( ( PVOID )&f_pOgrdtpHeader->ulDebugSessionNum ), ( ( PVOID* )&pulTreeData ) ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_45; *pulTreeData = ulNewSessionIndex; mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, ulNewSessionIndex, pSessionEntry ) pSessionEntry->aulLastPktTime[ 0 ] = GetTime.aulWallTimeUs[ 0 ]; pSessionEntry->aulLastPktTime[ 1 ] = GetTime.aulWallTimeUs[ 1 ]; pSessionEntry->ulSessionNum = f_pOgrdtpHeader->ulDebugSessionNum; pSessionEntry->ulTransactionNum = f_pOgrdtpHeader->ulTransactionNum; pSessionEntry->ulPktRetryNum = f_pOgrdtpHeader->ulPktRetryNum; pSessionEntry->ulBackwardLink = pRemoteDebugInfo->ulSessionListTail; pSessionEntry->ulForwardLink = cOCT6100_INVALID_VALUE; pRemoteDebugInfo->ulSessionListTail = ulNewSessionIndex; if ( pRemoteDebugInfo->ulSessionListHead == cOCT6100_INVALID_VALUE ) pRemoteDebugInfo->ulSessionListHead = ulNewSessionIndex; if ( pSessionEntry->ulBackwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulBackwardLink, pSessionLink ) pSessionLink->ulForwardLink = ulNewSessionIndex; } *f_pulSessionIndex = ulNewSessionIndex; /* Increment number of open sessions. */ pRemoteDebugInfo->ulNumSessionsOpen++; return cOCT6100_ERR_OK; } else { return cOCT6100_ERR_FATAL_46; } } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcReadWord Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_READ_WORD command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcReadWord VOID Oct6100ApiRpcReadWord( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_READ_WORD pReadCommand; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usReadData; /* Get pointer to command arguments. */ pReadCommand = ( tPOCT6100_RPC_READ_WORD )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set some read structure parameters. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Copy parameters from packet payload to local read structure. */ ReadParams.ulReadAddress = pReadCommand->ulAddress; /* Supply memory for read data. */ ReadParams.pusReadData = &usReadData; /* Perform read access. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) usReadData &= 0xFFFF; /* Return read data and result. */ pReadCommand->ulReadData = (usReadData << 16) | usReadData; f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcReadBurst Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_READ_BURST command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcReadBurst VOID Oct6100ApiRpcReadBurst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_READ_BURST pBurstCommand; tOCT6100_READ_BURST_PARAMS BurstParams; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar; UINT32 i; PUINT16 pusReadData; UINT32 ulNumWordsToRead; /* Get local pointer to remote debugging read data buffer. */ mOCT6100_GET_REMOTE_DEBUG_DATA_BUF_PNT( f_pApiInstance->pSharedInfo, pusReadData ) /* Get pointer to command arguments. */ pBurstCommand = ( tPOCT6100_RPC_READ_BURST )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set some read structure parameters. */ BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Copy parameters from packet payload to local read structure. */ BurstParams.ulReadAddress = pBurstCommand->ulAddress; /* Supply memory for read data. */ BurstParams.pusReadData = pusReadData; ulNumWordsToRead = pBurstCommand->ulBurstLength; while( ulNumWordsToRead > 0) { if ( ulNumWordsToRead <= f_pApiInstance->pSharedInfo->ChipConfig.usMaxRwAccesses ) BurstParams.ulReadLength = ulNumWordsToRead; else BurstParams.ulReadLength = f_pApiInstance->pSharedInfo->ChipConfig.usMaxRwAccesses; /* Perform read access. */ mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) { f_pCmndHeader->ulFunctionResult = ulResult; return; } BurstParams.ulReadAddress += BurstParams.ulReadLength * 2; BurstParams.pusReadData += BurstParams.ulReadLength; /* Update the number of dword to read. */ ulNumWordsToRead -= BurstParams.ulReadLength; } /* Return read data. */ ulTempVar = (pBurstCommand->ulBurstLength + 1) / 2; for ( i = 0; i < ulTempVar; i++ ) { pBurstCommand->aulReadData[ i ] = (*pusReadData & 0xFFFF) << 16; pusReadData++; pBurstCommand->aulReadData[ i ] |= (*pusReadData & 0xFFFF) << 0; pusReadData++; } /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcReadArray Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_READ_ARRAY command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcReadArray VOID Oct6100ApiRpcReadArray( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_READ_ARRAY pArrayCommand; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 i; PUINT32 pulAddressArray; PUINT32 pulDataArray; UINT16 usReadData; /* Get pointer to command arguments. */ pArrayCommand = ( tPOCT6100_RPC_READ_ARRAY )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set some read structure parameters. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Supply memory for read data. */ ReadParams.pusReadData = &usReadData; /* Get pointers to array of addresses and data. */ pulAddressArray = pArrayCommand->aulArrayData; pulDataArray = pArrayCommand->aulArrayData + pArrayCommand->ulArrayLength; for ( i = 0; i < pArrayCommand->ulArrayLength; i++ ) { /* Copy parameters from packet payload to local read structure. */ ReadParams.ulReadAddress = pulAddressArray[ i ]; /* Perform read access. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) break; /* Return read data. */ if ( (i % 2) == 0 ) pulDataArray[ i / 2 ] = (usReadData & 0xFFFF) << 16; else /* ( (i % 2) == 1 ) */ pulDataArray[ i / 2 ] |= (usReadData & 0xFFFF) << 0; } /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcWriteWord Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_WRITE_WORD command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcWriteWord VOID Oct6100ApiRpcWriteWord( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_WRITE_WORD pWriteCommand; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Get pointer to command arguments. */ pWriteCommand = ( tPOCT6100_RPC_WRITE_WORD )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set some read structure parameters. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Copy parameters from packet payload to local read structure. */ WriteParams.ulWriteAddress = pWriteCommand->ulAddress; WriteParams.usWriteData = (UINT16)pWriteCommand->ulWriteData; /* Perform write access. */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcWriteSmear Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_WRITE_SMEAR command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcWriteSmear VOID Oct6100ApiRpcWriteSmear( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_WRITE_SMEAR pSmearCommand; tOCT6100_WRITE_SMEAR_PARAMS SmearParams; UINT32 ulResult; /* Get pointer to command arguments. */ pSmearCommand = ( tPOCT6100_RPC_WRITE_SMEAR )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set the smear structure parameters. */ SmearParams.pProcessContext = f_pApiInstance->pProcessContext; SmearParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Copy parameters from packet payload to local read structure. */ SmearParams.ulWriteAddress = pSmearCommand->ulAddress; SmearParams.usWriteData = (UINT16)pSmearCommand->ulWriteData; SmearParams.ulWriteLength = pSmearCommand->ulSmearLength; /* Perform write access. */ mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ) /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcWriteBurst Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_WRITE_BURST command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcWriteBurst VOID Oct6100ApiRpcWriteBurst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_WRITE_BURST pBurstCommand; tOCT6100_WRITE_BURST_PARAMS BurstParams; UINT32 ulResult; UINT32 ulTempVar; UINT32 i, j; PUINT16 pusWriteData; /* Get local pointer to remote debugging write data buffer. */ mOCT6100_GET_REMOTE_DEBUG_DATA_BUF_PNT( f_pApiInstance->pSharedInfo, pusWriteData ) /* Get pointer to command arguments. */ pBurstCommand = ( tPOCT6100_RPC_WRITE_BURST )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); ulTempVar = (pBurstCommand->ulBurstLength + 1) / 2; for ( i = 0, j = 0; i < ulTempVar; i++ ) { pusWriteData[ j++ ] = (UINT16)((pBurstCommand->aulWriteData[ i ] >> 16) & 0xFFFF); pusWriteData[ j++ ] = (UINT16)((pBurstCommand->aulWriteData[ i ] >> 0) & 0xFFFF); } /* Set some structure parameters. */ BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Copy parameters from packet payload to local read structure. */ BurstParams.ulWriteAddress = pBurstCommand->ulAddress; BurstParams.ulWriteLength = pBurstCommand->ulBurstLength; BurstParams.pusWriteData = pusWriteData; /* Perform write access. */ mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult ) /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcSetHotChannel Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_SET_HOT_CHANNEL command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcSetHotChannel VOID Oct6100ApiRpcSetHotChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_SET_HOT_CHANNEL pHotChanCommand; tOCT6100_DEBUG_SELECT_CHANNEL DebugSelectChannel; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; pHotChanCommand = ( tPOCT6100_RPC_SET_HOT_CHANNEL )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Verify if the hot channel index is valid. */ if ( pHotChanCommand->ulHotChannel >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) { f_pCmndHeader->ulFunctionResult = cOCT6100_ERR_REMOTEDEBUG_INVALID_HOT_CHAN_INDEX; return; } mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, pHotChanCommand->ulHotChannel ); DebugSelectChannel.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | (pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pHotChanCommand->ulHotChannel; /* The PCM law parameter is now obsolete. */ /* The instance knows the law of the channel being recorded! */ /* Call the function. */ ulResult = Oct6100DebugSelectChannelSer( f_pApiInstance, &DebugSelectChannel, FALSE ); /* Return result. */ f_pCmndHeader->ulFunctionResult = ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcGetDebugChanIndex Description: Checks the provided portion of an OCTRPC packet and interprets it as an cOCT6100_RPC_GET_DEBUG_CHAN_INDEX command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcGetDebugChanIndex VOID Oct6100ApiRpcGetDebugChanIndex( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader ) { tPOCT6100_RPC_GET_DEBUG_CHAN_INDEX pDebugChanCommand; pDebugChanCommand = ( tPOCT6100_RPC_GET_DEBUG_CHAN_INDEX )(( PUINT32 )f_pCmndHeader + (sizeof( tOCTRPC_COMMAND_HEADER ) / 4)); /* Set the debug channel index of the structure. */ pDebugChanCommand->ulDebugChanIndex = f_pApiInstance->pSharedInfo->DebugInfo.usRecordMemIndex; /* Return result. */ f_pCmndHeader->ulFunctionResult = cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRpcDisconnect Description: Destroy the current session. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCmndHeader Pointer to RPC command structure. f_ulSessionNumber Session number of the current remote debugging session. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRpcDisconnect VOID Oct6100ApiRpcDisconnect( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCTRPC_COMMAND_HEADER f_pCmndHeader, IN UINT32 f_ulSessionNumber ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_REMOTE_DEBUG_INFO pRemoteDebugInfo; tPOCT6100_API_REMOTE_DEBUG_SESSION pSessionEntry; tPOCT6100_API_REMOTE_DEBUG_SESSION pSessionTempEntry; PVOID pSessionTree; UINT32 ulResult; PUINT32 pulTreeData; UINT32 ulSessionIndex; f_pCmndHeader->ulFunctionResult = cOCT6100_ERR_OK; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get a local pointer to the remote debugging info. */ pRemoteDebugInfo = &pSharedInfo->RemoteDebugInfo; /* Check if the session number has an associated session list entry. */ mOCT6100_GET_REMOTE_DEBUG_TREE_PNT( pSharedInfo, pSessionTree ) ulResult = octapi_bt0_query_node( pSessionTree, ( ( PVOID )(&f_ulSessionNumber) ), ( ( PVOID* )&pulTreeData ) ); if ( ulResult != cOCT6100_ERR_OK ) f_pCmndHeader->ulFunctionResult = cOCT6100_ERR_REMOTEDEBUG_INAVLID_SESSION_NUMBER; /* Return session index. */ ulSessionIndex= *pulTreeData; mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, ulSessionIndex, pSessionEntry ); /* Clear the entry of the session. */ pSessionEntry->aulLastPktTime[ 0 ] = 0; pSessionEntry->aulLastPktTime[ 1 ] = 0; pSessionEntry->ulSessionNum = cOCT6100_INVALID_VALUE; pSessionEntry->ulTransactionNum = cOCT6100_INVALID_VALUE; pSessionEntry->ulPktRetryNum = cOCT6100_INVALID_VALUE; /* Update the other entry before removing the node. */ pSessionEntry->ulBackwardLink = pRemoteDebugInfo->ulSessionListTail; pSessionEntry->ulForwardLink = cOCT6100_INVALID_VALUE; if ( pSessionEntry->ulBackwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulBackwardLink, pSessionTempEntry ); pSessionTempEntry->ulForwardLink = pSessionEntry->ulForwardLink; } else /* pSessionEntry->ulBackwardLink == cOCT6100_INVALID_VALUE */ { pRemoteDebugInfo->ulSessionListHead = pSessionEntry->ulForwardLink; } if ( pSessionEntry->ulForwardLink != cOCT6100_INVALID_VALUE ) { mOCT6100_GET_REMOTE_DEBUG_LIST_ENTRY_PNT( pSharedInfo, pSessionEntry->ulForwardLink, pSessionTempEntry ); pSessionTempEntry->ulBackwardLink = pSessionEntry->ulBackwardLink; } else /* pSessionEntry->ulForwardLink == cOCT6100_INVALID_VALUE */ { pRemoteDebugInfo->ulSessionListTail = pSessionEntry->ulBackwardLink; } /* Invalidate the pointer. */ pSessionEntry->ulBackwardLink = cOCT6100_INVALID_VALUE; pSessionEntry->ulForwardLink = cOCT6100_INVALID_VALUE; /* Remove the session. */ ulResult = octapi_bt0_remove_node( pSessionTree, ( ( PVOID )&f_ulSessionNumber ) ); if ( ulResult != cOCT6100_ERR_OK ) f_pCmndHeader->ulFunctionResult = cOCT6100_ERR_FATAL_47; /* Increment number of open sessions. */ pRemoteDebugInfo->ulNumSessionsOpen--; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tsst.c0000644000175000017500000004356711431317470030453 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tsst.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions used to manage the allocation of TSST control structures in internal memory. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 39 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_tsst_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_tsst_priv.h" /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetTsstSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of TSSTs. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetTsstSwSizes UINT32 Oct6100ApiGetTsstSwSizes( OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Determine amount of TSST needed for TSST allocation table. */ f_pInstSizes->ulTsstAlloc = 4096 / 8; /* Calculate the API memory required for the TSST entry list. */ f_pInstSizes->ulTsstEntryList = cOCT6100_MAX_TSSTS * sizeof( tOCT6100_API_TSST_ENTRY ); /* Calculate memory needed for TSST entry allocation. */ ulResult = OctapiLlmAllocGetSize( cOCT6100_MAX_TSSTS, &f_pInstSizes->ulTsstEntryAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_4D; mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsstAlloc, ulTempVar ); mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsstEntryList, ulTempVar ); mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsstEntryAlloc, ulTempVar ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiTsstSwInit Description: Initializes all elements of the instance structure associated to the TSST control entries. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This tsst is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiTsstSwInit UINT32 Oct6100ApiTsstSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TSST_ENTRY pTsstList; PUINT32 pulTsstAlloc; PVOID pTsstListAlloc; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize the TSST allocation table to "all free". */ mOCT6100_GET_TSST_ALLOC_PNT( pSharedInfo, pulTsstAlloc ); Oct6100UserMemSet( pulTsstAlloc, 0x00, 512 ); /* Initialize all the TSST list entries. */ mOCT6100_GET_TSST_LIST_PNT( pSharedInfo, pTsstList ); Oct6100UserMemSet( pTsstList, 0xFF, cOCT6100_MAX_TSSTS * sizeof(tOCT6100_API_TSST_ENTRY) ); /* Initialize the allocation list to manage the TSST entries.*/ mOCT6100_GET_TSST_LIST_ALLOC_PNT( pSharedInfo, pTsstListAlloc ) ulResult = OctapiLlmAllocInit( &pTsstListAlloc, cOCT6100_MAX_TSSTS ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_4E; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiValidateTsst Description: Validates a timeslot, stream combination. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This tsst is used to keep the present state of the chip and all its resources. f_ulTimeslot Timeslot component of the TDM TSST. f_ulStream Stream component of the TDM TSST. f_ulNumTssts Number of TSST required. f_ulDirection Direction of the TSST (Input or Output). \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiValidateTsst UINT32 Oct6100ApiValidateTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulNumTssts, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulDirection ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_CONFIG pChipConfig; PUINT32 pulTsstAlloc; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSST_ALLOC_PNT( f_pApiInstance->pSharedInfo, pulTsstAlloc ); /* Obtain local pointer to chip configuration. */ pChipConfig = &pSharedInfo->ChipConfig; /* Check the TDM streams, timeslots component for errors. */ if ( f_ulTimeslot == cOCT6100_UNASSIGNED && f_ulStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_TSST_TIMESLOT; if ( f_ulTimeslot != cOCT6100_UNASSIGNED && f_ulStream == cOCT6100_UNASSIGNED ) return cOCT6100_ERR_TSST_STREAM; if ( f_ulStream >= pChipConfig->byMaxTdmStreams ) return cOCT6100_ERR_TSST_STREAM; /* Check timeslot value based on the frequenccy of the selected stream. */ switch ( pChipConfig->aulTdmStreamFreqs[ f_ulStream / 4 ] ) { case cOCT6100_TDM_STREAM_FREQ_2MHZ: if ( f_ulTimeslot >= 32 ) return cOCT6100_ERR_TSST_TIMESLOT; break; case cOCT6100_TDM_STREAM_FREQ_4MHZ: if ( f_ulTimeslot >= 64 ) return cOCT6100_ERR_TSST_TIMESLOT; break; case cOCT6100_TDM_STREAM_FREQ_8MHZ: if ( f_ulTimeslot >= 128 ) return cOCT6100_ERR_TSST_TIMESLOT; break; case cOCT6100_TDM_STREAM_FREQ_16MHZ: if ( f_ulTimeslot >= 256 ) return cOCT6100_ERR_TSST_TIMESLOT; /* Check the stream value based on the direction. */ if ( f_ulDirection == cOCT6100_INPUT_TSST && f_ulStream >= 16 ) { return cOCT6100_ERR_TSST_STREAM; } else if( f_ulDirection == cOCT6100_OUTPUT_TSST && f_ulStream < 16 ) { return cOCT6100_ERR_TSST_STREAM; } break; default: return cOCT6100_ERR_FATAL_DC; } /* Stream must be odd if two TSSTs are required. */ if ( f_ulNumTssts == 2 && ( ( f_ulStream & 0x1) != 0x1 ) ) return cOCT6100_ERR_TSST_STREAM; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveTsst Description: Reserves a TSST, only one TSI entry can access a TSST at any one time. If the pointer f_pulTsstListIndex is set to NULL, no TSST list entry will be reserved. The index in TSST control memory returned is based on the frequency of the streams where the TSST is located and on the direction of the TSST ( input or output ). ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This tsst is used to keep the present state of the chip and all its resources. f_ulTimeslot Timeslot component of the TDM TSST. f_ulNumTssts Number of TSSTs required. f_ulStream Stream component of the TDM TSST. f_ulDirection Whether the TSST in and input TSST or output TSST. f_pusTsstMemIndex Index of the resulting TSST in the TSST control memory. f_pusTsstListIndex Index in the TSST list of the current entry. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveTsst UINT32 Oct6100ApiReserveTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulNumTsst, IN UINT32 f_ulDirection, OUT PUINT16 f_pusTsstMemIndex, OUT PUINT16 f_pusTsstListIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsstListAlloc; PUINT32 pulTsstAlloc; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulStream; UINT32 ulTimeslot; /* Get local pointer to shared portion of API instance structure. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSST_ALLOC_PNT( f_pApiInstance->pSharedInfo, pulTsstAlloc ); /*==================================================================================*/ /* Now make the proper conversion to obtain the TSST value. */ /* Save the timeslot and stream value received. */ ulStream = f_ulStream; ulTimeslot = f_ulTimeslot; /* Set the TSST index associated to this stream, timeslot combination. */ switch ( f_pApiInstance->pSharedInfo->ChipConfig.aulTdmStreamFreqs[ f_ulStream / 4 ] ) { case cOCT6100_TDM_STREAM_FREQ_16MHZ: if ( f_ulDirection == cOCT6100_INPUT_TSST ) { ulStream = f_ulStream + ( f_ulTimeslot % 2 ) * 16; ulTimeslot = f_ulTimeslot / 2; } else /* f_ulDirection == cOCT6100_OUTPUT_TSST */ { ulStream = ( f_ulStream - 16 ) + ( f_ulTimeslot % 2 ) * 16; if ( f_ulStream < 28 && ((f_ulTimeslot % 2) == 1) ) { ulTimeslot = ((f_ulTimeslot / 2) + 4) % 128; } else { ulTimeslot = f_ulTimeslot / 2 ; } } *f_pusTsstMemIndex = (UINT16)( ulTimeslot * 32 + ulStream ); break; case cOCT6100_TDM_STREAM_FREQ_8MHZ: *f_pusTsstMemIndex = (UINT16)( ulTimeslot * 32 + ulStream ); break; case cOCT6100_TDM_STREAM_FREQ_4MHZ: *f_pusTsstMemIndex = (UINT16)( ulTimeslot * 32 * 2 ); if ( f_ulDirection == cOCT6100_OUTPUT_TSST ) { *f_pusTsstMemIndex = (UINT16)( *f_pusTsstMemIndex + ulStream ); } else /* if ( f_ulDirection == cOCT6100_INPUT_TSST ) */ { *f_pusTsstMemIndex = (UINT16)( ( 1 * 32 + ulStream ) + *f_pusTsstMemIndex ); } break; case cOCT6100_TDM_STREAM_FREQ_2MHZ: *f_pusTsstMemIndex = (UINT16)( ulTimeslot * 32 * 4 ); if ( f_ulDirection == cOCT6100_OUTPUT_TSST ) { *f_pusTsstMemIndex = (UINT16)( ulStream + *f_pusTsstMemIndex ); } else /* if ( f_ulDirection == cOCT6100_INPUT_TSST ) */ { *f_pusTsstMemIndex = (UINT16)( ( 3 * 32 + ulStream ) + *f_pusTsstMemIndex ); } break; default: ulResult = cOCT6100_ERR_FATAL_8B; } /*======================================================================*/ /*======================================================================*/ /* First reserve the TSST. */ /* Get local pointer to TSST's entry in allocation table. */ switch ( pSharedInfo->ChipConfig.aulTdmStreamFreqs[ ulStream / 4 ] ) { case cOCT6100_TDM_STREAM_FREQ_2MHZ: ulTimeslot *= 4; break; case cOCT6100_TDM_STREAM_FREQ_4MHZ: ulTimeslot *= 2; break; case cOCT6100_TDM_STREAM_FREQ_8MHZ: ulTimeslot *= 1; break; case cOCT6100_TDM_STREAM_FREQ_16MHZ: ulTimeslot *= 1; break; default: return cOCT6100_ERR_FATAL_DD; } /* Check if entry is already reserved. */ if ( ((pulTsstAlloc[ ulTimeslot ] >> ulStream) & 0x1) == 0x1 ) return cOCT6100_ERR_TSST_TSST_RESERVED; /* Check and reserve the associated TSST if required. */ if ( f_ulNumTsst == 2 ) { /* Check if entry is already reserved. */ if ( ((pulTsstAlloc[ ulTimeslot ] >> (ulStream - 1) ) & 0x1) == 0x1 ) return cOCT6100_ERR_TSST_ASSOCIATED_TSST_RESERVED; /* The entry is free, it won't anymore. */ pulTsstAlloc[ ulTimeslot ] |= (0x1 << (ulStream - 1)); } /* The entry is free, it won't anymore.*/ pulTsstAlloc[ ulTimeslot ] |= (0x1 << ulStream); /*======================================================================*/ /*======================================================================*/ /* Now reserve a TSST entry if requested. */ if ( f_pusTsstListIndex != NULL && ulResult == cOCT6100_ERR_OK ) { UINT32 ulTsstListIndex; /* Reserve a TSST entry in the API TSST list. */ mOCT6100_GET_TSST_LIST_ALLOC_PNT( f_pApiInstance->pSharedInfo, pTsstListAlloc ); ulResult = OctapiLlmAllocAlloc( pTsstListAlloc, &ulTsstListIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) ulResult = cOCT6100_ERR_TSST_ALL_TSSTS_ARE_OPENED; else ulResult = cOCT6100_ERR_FATAL_52; } *f_pusTsstListIndex = (UINT16)( ulTsstListIndex & 0xFFFF ); } /*======================================================================*/ /*======================================================================*/ /* Check the result of the TSST list reservation. */ if ( ulResult != cOCT6100_ERR_OK ) { /* Release the previously reserved TSST. */ if ( f_ulNumTsst == 2 ) { /* Clear the entry. */ pulTsstAlloc[ ulTimeslot ] &= ~(0x1 << (ulStream - 1) ); } /* Clear the entry. */ pulTsstAlloc[ ulTimeslot ] &= ~(0x1 << ulStream); } /*======================================================================*/ return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseTsst Description: Releases a TSST. If f_usTsstListIndex is set to cOCT6100_INVALID_INDEX, the API will assume that no TSST list entry was reserved for this TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This tsst is used to keep the present state of the chip and all its resources. f_ulNumTssts Number of TSSTs to be released. f_ulStream Stream component of the TDM TSST. f_ulTimeslot Timeslot component of the TDM TSST. f_ulDirection Whether the TSST is an input TSST or output TSST. f_usTsstListIndex Index in the TSST list of the current entry. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseTsst UINT32 Oct6100ApiReleaseTsst( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTimeslot, IN UINT32 f_ulStream, IN UINT32 f_ulNumTsst, IN UINT32 f_ulDirection, IN UINT16 f_usTsstListIndex) { tPOCT6100_SHARED_INFO pSharedInfo; PUINT32 pulTsstAlloc; PVOID pTsstListAlloc; UINT32 ulResult; UINT32 ulStream; UINT32 ulTimeslot; /* Get local pointer to shared portion of API instance structure. */ pSharedInfo = f_pApiInstance->pSharedInfo; if ( f_usTsstListIndex != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ALLOC_PNT( pSharedInfo, pTsstListAlloc ) ulResult = OctapiLlmAllocDealloc( pTsstListAlloc, f_usTsstListIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_53; } } mOCT6100_GET_TSST_ALLOC_PNT( f_pApiInstance->pSharedInfo, pulTsstAlloc ); /*==================================================================================*/ /* Now make the proper conversion to obtain the TSST value. */ /* Save the timeslot and stream value received. */ ulStream = f_ulStream; ulTimeslot = f_ulTimeslot; /* Set the TSST index associated to this stream, timeslot combination. */ if ( pSharedInfo->ChipConfig.aulTdmStreamFreqs[ f_ulStream / 4 ] == cOCT6100_TDM_STREAM_FREQ_16MHZ ) { if ( f_ulDirection == cOCT6100_INPUT_TSST ) { ulStream = f_ulStream + ( f_ulTimeslot % 2 ) * 16; ulTimeslot = f_ulTimeslot / 2; } else /* f_ulDirection == cOCT6100_OUTPUT_TSST */ { ulStream = ( f_ulStream - 16 ) + ( f_ulTimeslot % 2 ) * 16; if ( f_ulStream < 28 && ((f_ulTimeslot % 2) == 1) ) { ulTimeslot = ((f_ulTimeslot / 2) + 4) % 128; } else { ulTimeslot = f_ulTimeslot / 2 ; } } } /* Get local pointer to TSST's entry in allocation table. */ switch ( pSharedInfo->ChipConfig.aulTdmStreamFreqs[ ulStream / 4 ] ) { case cOCT6100_TDM_STREAM_FREQ_2MHZ: ulTimeslot *= 4; break; case cOCT6100_TDM_STREAM_FREQ_4MHZ: ulTimeslot *= 2; break; case cOCT6100_TDM_STREAM_FREQ_8MHZ: ulTimeslot *= 1; break; case cOCT6100_TDM_STREAM_FREQ_16MHZ: ulTimeslot *= 1; break; default: return cOCT6100_ERR_FATAL_DE; } /* Check if entry is actualy reserved. */ if ( ((pulTsstAlloc[ ulTimeslot ] >> ulStream) & 0x1) != 0x1 ) return cOCT6100_ERR_FATAL_55; /*==================================================================================*/ /* Clear the entry. */ pulTsstAlloc[ ulTimeslot ] &= ~(0x1 << ulStream); /* Check and release the associated TSST if required. */ if ( f_ulNumTsst == 2 ) { /* Check if entry is actualy reserved. */ if ( ((pulTsstAlloc[ ulTimeslot ] >> ( ulStream - 1)) & 0x1) != 0x1 ) return cOCT6100_ERR_FATAL_54; /* Clear the entry. */ pulTsstAlloc[ ulTimeslot ] &= ~(0x1 << (ulStream - 1)); } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_memory.c0000644000175000017500000006652611431317470030766 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_memory.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions used to manage the allocation of memory blocks in external memory. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 42 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_playout_buf_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_memory_priv.h" /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetMemorySwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of the memories. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetMemorySwSizes UINT32 Oct6100ApiGetMemorySwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; UINT32 ulNumTsiChariots; /*=========================================================================*/ /* Internal memory */ /* Evaluate the number of available TSI memory after reserving the ones used by channels. */ ulNumTsiChariots = cOCT6100_TOTAL_TSI_CONTROL_MEM_ENTRY - f_pOpenChip->ulMaxPhasingTssts - cOCT6100_TSI_MEM_FOR_TIMESTAMP; if ( f_pOpenChip->fEnableExtToneDetection == TRUE ) ulNumTsiChariots--; /* Calculate memory needed for TSI memory allocation. */ ulResult = OctapiLlmAllocGetSize( ulNumTsiChariots, &f_pInstSizes->ulTsiMemoryAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_94; /* Calculate memory needed for conversion memory allocation. */ ulResult = OctapiLlmAllocGetSize( cOCT6100_MAX_CONVERSION_MEMORY_BLOCKS, &f_pInstSizes->ulConversionMemoryAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_B5; mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulTsiMemoryAlloc, ulTempVar ); mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulConversionMemoryAlloc, ulTempVar ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMemorySwInit Description: Initializes all elements of the instance structure associated to memories. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMemorySwInit UINT32 Oct6100ApiMemorySwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsiMemAlloc; PVOID pAllocPnt; UINT32 ulResult; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /*=========================================================================*/ /* Internal memory */ /* Initialize the TSI memory allocation structure. */ pSharedInfo->MemoryMap.ulNumTsiEntries = cOCT6100_TOTAL_TSI_CONTROL_MEM_ENTRY - pSharedInfo->ChipConfig.usMaxPhasingTssts - cOCT6100_TSI_MEM_FOR_TIMESTAMP; if ( pSharedInfo->ChipConfig.fEnableExtToneDetection == TRUE ) pSharedInfo->MemoryMap.ulNumTsiEntries--; mOCT6100_GET_TSI_MEMORY_ALLOC_PNT( pSharedInfo, pTsiMemAlloc ); ulResult = OctapiLlmAllocInit( &pTsiMemAlloc, pSharedInfo->MemoryMap.ulNumTsiEntries ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_95; /* Initialize the conversion memory allocation structure. */ mOCT6100_GET_CONVERSION_MEMORY_ALLOC_PNT( pSharedInfo, pAllocPnt ); ulResult = OctapiLlmAllocInit( &pAllocPnt, cOCT6100_MAX_CONVERSION_MEMORY_BLOCKS ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_B6; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBufferPlayoutMemorySwInit Description: Initialize the buffer playout memory allocation working structures. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBufferPlayoutMemorySwInit UINT32 Oct6100ApiBufferPlayoutMemorySwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pNode; UINT32 i; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Only if buffer playout will be used. */ if ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers > 0 ) { mOCT6100_GET_BUFFER_MEMORY_NODE_LIST_PNT( pSharedInfo, pNode ); /* First node contains all free memory at beginning. This node is not used, but represents the memory. */ pNode->ulSize = ( pSharedInfo->MiscVars.ulTotalMemSize + cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) - pSharedInfo->MemoryMap.ulFreeMemBaseAddress; pNode->ulNext = 0; pNode->ulPrevious = 0; pNode->fAllocated = FALSE; pNode->ulStartAddress = pSharedInfo->MemoryMap.ulFreeMemBaseAddress; pNode++; /* Now create the first node of the free list, i.e. nodes that can be used later for modeling the memory. */ pNode->ulSize = 0; /* Next free. */ pNode->ulNext = 2; /* Last. */ pNode->ulPrevious = ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers * 2 ) - 1; pNode->fAllocated = FALSE; pNode->ulStartAddress = 0; pNode++; /* Link all the unused nodes. */ for( i = 2; i < (UINT32)( ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers * 2 ) - 1 ); i ++ ) { pNode->ulNext = i + 1; pNode->ulPrevious = i - 1; pNode->ulStartAddress = 0; pNode->ulSize = 0; pNode->fAllocated = FALSE; pNode++; } /* Last node of the unused list. */ pNode->fAllocated = FALSE; pNode->ulPrevious = ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers * 2 ) - 2; /* Free list head. */ pNode->ulNext = 1; pNode->ulSize = 0; pNode->ulStartAddress = 0; /* Set roving pointer to first node ( which can be used! ) */ pSharedInfo->PlayoutInfo.ulRovingNode = 0; /* First unused node. */ pSharedInfo->PlayoutInfo.ulFirstUnusedNode = 1; /* Last unused node. */ pSharedInfo->PlayoutInfo.ulLastUnusedNode = ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers * 2 ) - 1; /* Number of unused nodes. */ pSharedInfo->PlayoutInfo.ulUnusedNodeCnt = ( pSharedInfo->ChipConfig.usMaxPlayoutBuffers * 2 ) - 1; } else { pSharedInfo->PlayoutInfo.ulUnusedNodeCnt = 0; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBufferPlayoutMemoryNode Description: Get a free node from the unused buffer playout node list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pulNewNode The index of the node. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBufferPlayoutMemoryNode UINT32 Oct6100ApiReserveBufferPlayoutMemoryNode( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT32 f_pulNewNode ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pNode; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check if a free block is left. */ if ( pSharedInfo->PlayoutInfo.ulUnusedNodeCnt == 0 ) { /* This should not happen according to the allocated list from the beginning. */ return cOCT6100_ERR_FATAL_CC; } /* The new node is the first in the unused list. */ *f_pulNewNode = pSharedInfo->PlayoutInfo.ulFirstUnusedNode; /* Unlink this new node from the unused list. */ mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNode, *f_pulNewNode ); pSharedInfo->PlayoutInfo.ulFirstUnusedNode = pNode->ulNext; pNode->ulPrevious = pSharedInfo->PlayoutInfo.ulLastUnusedNode; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNode, pSharedInfo->PlayoutInfo.ulLastUnusedNode ); pNode->ulNext = pSharedInfo->PlayoutInfo.ulFirstUnusedNode; /* Update unused node count. */ pSharedInfo->PlayoutInfo.ulUnusedNodeCnt--; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBufferPlayoutMemoryNode Description: Release a node that is not used anymore. Insert this node into the unused list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulOldNode The index of the node. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBufferPlayoutMemoryNode UINT32 Oct6100ApiReleaseBufferPlayoutMemoryNode( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulOldNode ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pNode; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get the last unused node. Insert this old node at the end of the unused list. */ mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNode, pSharedInfo->PlayoutInfo.ulLastUnusedNode ); /* Last node points to old node. */ pNode->ulNext = f_ulOldNode; /* Update old node. */ mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNode, f_ulOldNode ); pNode->ulPrevious = pSharedInfo->PlayoutInfo.ulLastUnusedNode; pNode->ulNext = pSharedInfo->PlayoutInfo.ulFirstUnusedNode; pSharedInfo->PlayoutInfo.ulLastUnusedNode = f_ulOldNode; /* Keep unused node count. */ pSharedInfo->PlayoutInfo.ulUnusedNodeCnt++; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBufferPlayoutMemory Description: Try to allocate requested size. Returns an error if malloc point could not be found. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulSize Needed size. f_pulMallocAddress Alloc point. This memory can now be used. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBufferPlayoutMemory UINT32 Oct6100ApiReserveBufferPlayoutMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulSize, OUT PUINT32 f_pulMallocAddress ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pCurrentNode; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pTempNode; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pNewNode; UINT32 ulCurrentBufferPlayoutMallocNode; UINT32 ulNewNode; BOOL fFoundMemory = FALSE; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Requested size must be divisible by 64. */ if ( f_ulSize % 64 ) { f_ulSize = f_ulSize + ( 64 - ( f_ulSize % 64 ) ); } /* Start with roving pointer. */ ulCurrentBufferPlayoutMallocNode = pSharedInfo->PlayoutInfo.ulRovingNode; *f_pulMallocAddress = 0; /* Return an error if size requested is zero. */ if ( f_ulSize == 0 ) { return cOCT6100_ERR_BUFFER_PLAYOUT_MALLOC_ZERO; } do { mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pCurrentNode, ulCurrentBufferPlayoutMallocNode ); /* Look for a free node big enough to fulfill user requested size. */ if ( ( pCurrentNode->fAllocated == FALSE ) && ( pCurrentNode->ulSize >= f_ulSize ) ) { /* Use this node! */ pCurrentNode->fAllocated = TRUE; if ( pCurrentNode->ulNext != 0 ) { mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, pCurrentNode->ulNext ); if( ( pTempNode->fAllocated == TRUE ) && ( pCurrentNode->ulSize > f_ulSize ) ) { /* Fragmentation NOW! */ /* Allocate new node that will contain free size. */ ulResult = Oct6100ApiReserveBufferPlayoutMemoryNode( f_pApiInstance, &ulNewNode ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNewNode, ulNewNode ); /* Can use this free node. */ pNewNode->ulSize = pCurrentNode->ulSize - f_ulSize; pNewNode->ulStartAddress = pCurrentNode->ulStartAddress + f_ulSize; /* Link new node into the list. */ pNewNode->ulNext = pCurrentNode->ulNext; pNewNode->ulPrevious = ulCurrentBufferPlayoutMallocNode; pNewNode->fAllocated = FALSE; pTempNode->ulPrevious = ulNewNode; pCurrentNode->ulNext = ulNewNode; } } else if ( pCurrentNode->ulSize > f_ulSize ) { /* Must allocate a new free node for the rest of the space. */ ulResult = Oct6100ApiReserveBufferPlayoutMemoryNode( f_pApiInstance, &ulNewNode ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pNewNode, ulNewNode ); pNewNode->ulNext = pCurrentNode->ulNext; pCurrentNode->ulNext = ulNewNode; pNewNode->ulPrevious = ulCurrentBufferPlayoutMallocNode; pNewNode->fAllocated = FALSE; pNewNode->ulSize = pCurrentNode->ulSize - f_ulSize; pNewNode->ulStartAddress = pCurrentNode->ulStartAddress + f_ulSize; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, 0 ); /* Check for the head node that would have to be updated. */ if ( ( ulCurrentBufferPlayoutMallocNode == 0 ) && ( pTempNode->ulPrevious == 0 ) ) pTempNode->ulPrevious = ulNewNode; } else { /* Perfect fit. */ } pCurrentNode->ulSize = f_ulSize; /* Update roving pointer. */ pSharedInfo->PlayoutInfo.ulRovingNode = ulCurrentBufferPlayoutMallocNode; *f_pulMallocAddress = pCurrentNode->ulStartAddress; fFoundMemory = TRUE; break; } /* Next block! */ ulCurrentBufferPlayoutMallocNode = pCurrentNode->ulNext; } while ( pSharedInfo->PlayoutInfo.ulRovingNode != ulCurrentBufferPlayoutMallocNode ); if ( fFoundMemory == FALSE ) { return cOCT6100_ERR_BUFFER_PLAYOUT_NO_MEMORY; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBufferPlayoutMemory Description: Free what was allocated at address. Free is somewhat slower then Malloc. O(n), must travel through the list looking for the malloc point. Return an error if alloc point was not found. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulMallocAddress Alloc point. The memory at address will be freed. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBufferPlayoutMemory UINT32 Oct6100ApiReleaseBufferPlayoutMemory( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulMallocAddress ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pCurrentNode; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pTempNode; tPOCT6100_API_BUFFER_PLAYOUT_MALLOC_NODE pOldNode; UINT32 ulResult = cOCT6100_ERR_BUFFER_PLAYOUT_MALLOC_POINT_NOT_FOUND; UINT32 ulNodeToMerge; UINT32 ulNodeToRemove; UINT32 ulCurrentBufferPlayoutMallocNode; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Start from the beginning and find the alloc node. */ ulCurrentBufferPlayoutMallocNode = 0; do { mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pCurrentNode, ulCurrentBufferPlayoutMallocNode ); if ( ( pCurrentNode->ulStartAddress == f_ulMallocAddress ) && ( pCurrentNode->fAllocated == TRUE ) ) { /* We found the block! */ pCurrentNode->fAllocated = FALSE; /* Check if the next node can be merged. */ if ( pCurrentNode->ulNext != 0 ) { mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, pCurrentNode->ulNext ); if ( pTempNode->fAllocated == FALSE ) { /* Can merge this block to us. */ pCurrentNode->ulSize += pTempNode->ulSize; pTempNode->ulSize = 0; /* Unlink unused node. */ ulNodeToRemove = pCurrentNode->ulNext; pCurrentNode->ulNext = pTempNode->ulNext; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, pCurrentNode->ulNext ); pTempNode->ulPrevious = ulCurrentBufferPlayoutMallocNode; ulResult = Oct6100ApiReleaseBufferPlayoutMemoryNode( f_pApiInstance, ulNodeToRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move roving pointer if have to. */ if ( pSharedInfo->PlayoutInfo.ulRovingNode == ulNodeToRemove ) pSharedInfo->PlayoutInfo.ulRovingNode = ulCurrentBufferPlayoutMallocNode; } } /* Check if previous node can merge. */ if ( ulCurrentBufferPlayoutMallocNode != 0 ) { mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, pCurrentNode->ulPrevious ); if ( pTempNode->fAllocated == FALSE ) { ulNodeToMerge = pCurrentNode->ulPrevious; /* Can merge us to this node. */ pTempNode->ulSize += pCurrentNode->ulSize; pCurrentNode->ulSize = 0; /* Unlink unused node. */ ulNodeToRemove = ulCurrentBufferPlayoutMallocNode; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pOldNode, ulNodeToRemove ); pTempNode->ulNext = pOldNode->ulNext; mOCT6100_GET_BUFFER_MEMORY_NODE_ENTRY_PNT( pSharedInfo, pTempNode, pTempNode->ulNext ); pTempNode->ulPrevious = ulNodeToMerge; pOldNode->fAllocated = FALSE; pOldNode->ulSize = 0; pOldNode->ulStartAddress = 0; /* Move roving pointer if have to. */ if ( pSharedInfo->PlayoutInfo.ulRovingNode == ulNodeToRemove ) pSharedInfo->PlayoutInfo.ulRovingNode = ulNodeToMerge; /* Release this unused node. */ ulResult = Oct6100ApiReleaseBufferPlayoutMemoryNode( f_pApiInstance, ulNodeToRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* All's good! */ ulResult = 0; break; } /* Next node. */ ulCurrentBufferPlayoutMallocNode = pCurrentNode->ulNext; } while( ulCurrentBufferPlayoutMallocNode != 0 ); return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveTsiMemEntry Description: Reserves a TSI chariot memory entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusTsiMemIndex Resulting index reserved in the TSI chariot memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveTsiMemEntry UINT32 Oct6100ApiReserveTsiMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusTsiMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsiMemAlloc; UINT32 ulResult; UINT32 ulIndex; UINT32 ulNumTsiB4Timestamp; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_TSI_MEMORY_ALLOC_PNT( pSharedInfo, pTsiMemAlloc ) ulResult = OctapiLlmAllocAlloc( pTsiMemAlloc, &ulIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_MEMORY_ALL_TSI_MEM_ENTRY_RESERVED; else return cOCT6100_ERR_FATAL_92; } if ( ulIndex >= cOCT6100_NUM_TSI_B4_PHASING ) { /* Evaluate the number of TSI memory before the timestamp TSI. */ ulNumTsiB4Timestamp = cOCT6100_NUM_TSI_B4_PHASING + cOCT6100_MAX_TSI_B4_TIMESTAMP - pSharedInfo->ChipConfig.usMaxPhasingTssts; if ( ulIndex >= ulNumTsiB4Timestamp ) { /* + 4 for the timestamp TSI entries.*/ *f_pusTsiMemIndex = (UINT16)( pSharedInfo->ChipConfig.usMaxPhasingTssts + ulIndex + cOCT6100_TSI_MEM_FOR_TIMESTAMP ); } else /* ulIndex < ulNumTsiB4Timestamp */ { *f_pusTsiMemIndex = (UINT16)( pSharedInfo->ChipConfig.usMaxPhasingTssts + ulIndex ); } } else /* ulIndex < ulNumTsiB4Timestamp */ { *f_pusTsiMemIndex = (UINT16)( ulIndex ); } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseTsiMemEntry Description: Releases a TSI chariot memory entry specified. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usTsiMemIndex Index reserved in the TSI chariot memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseTsiMemEntry UINT32 Oct6100ApiReleaseTsiMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pTsiMemAlloc; UINT32 ulResult; UINT32 ulIndex; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check if the entry programmed is greater then the timestamp entries. */ if ( f_usTsiMemIndex > cOCT6100_TSST_CONTROL_TIMESTAMP_BASE_ENTRY ) ulIndex = f_usTsiMemIndex - cOCT6100_TSI_MEM_FOR_TIMESTAMP; else ulIndex = f_usTsiMemIndex; /* Check if the entry programmed is greater then the phasing TSST entries. */ if ( ulIndex > cOCT6100_TSST_CONTROL_PHASING_TSST_BASE_ENTRY ) ulIndex -= pSharedInfo->ChipConfig.usMaxPhasingTssts; mOCT6100_GET_TSI_MEMORY_ALLOC_PNT( pSharedInfo, pTsiMemAlloc ) ulResult = OctapiLlmAllocDealloc( pTsiMemAlloc, ulIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_93; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveConversionMemEntry Description: Reserves one of the conversion memory entry ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusConversionMemIndex Resulting index reserved in the conversion memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveConversionMemEntry UINT32 Oct6100ApiReserveConversionMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusConversionMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pConversionMemAlloc; UINT32 ulConversionMemIndex; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CONVERSION_MEMORY_ALLOC_PNT( pSharedInfo, pConversionMemAlloc ) ulResult = OctapiLlmAllocAlloc( pConversionMemAlloc, &ulConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_MEMORY_ALL_CONVERSION_MEM_ENTRY_RESERVED; else return cOCT6100_ERR_FATAL_B8; } *f_pusConversionMemIndex = (UINT16)( ulConversionMemIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseConversionMemEntry Description: Releases the conversion chariot memory entry specified. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usConversionMemIndex Index reserved in the conversion chariot memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseConversionMemEntry UINT32 Oct6100ApiReleaseConversionMemEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usConversionMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pConversionMemAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CONVERSION_MEMORY_ALLOC_PNT( pSharedInfo, pConversionMemAlloc ) ulResult = OctapiLlmAllocDealloc( pConversionMemAlloc, f_usConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_B7; } return cOCT6100_ERR_OK; } #endif ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tone_detection.cdahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tone_detection0000644000175000017500000011354711431317470032234 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tone_detection.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to enable and disable tone detection on an echo channel. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 51 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_tone_detection_inst.h" #include "oct6100api/oct6100_events_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_tone_detection_pub.h" #include "oct6100api/oct6100_events_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_tone_detection_priv.h" #include "oct6100_events_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ToneDetectionEnable Description: This function enables the generation of event for a selected tone on the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectEnable Pointer to tone detection enable structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ToneDetectionEnableDef UINT32 Oct6100ToneDetectionEnableDef( tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable ) { f_pToneDetectEnable->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pToneDetectEnable->ulToneNumber = cOCT6100_INVALID_TONE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ToneDetectionEnable UINT32 Oct6100ToneDetectionEnable( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ToneDetectionEnableSer( f_pApiInstance, f_pToneDetectEnable ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ToneDetectionDisable Description: This function disables the detection of a tone for a specific channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectDisable Pointer to tone detection disable structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ToneDetectionDisableDef UINT32 Oct6100ToneDetectionDisableDef( tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable ) { f_pToneDetectDisable->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pToneDetectDisable->ulToneNumber = cOCT6100_INVALID_VALUE; f_pToneDetectDisable->fDisableAll = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ToneDetectionDisable UINT32 Oct6100ToneDetectionDisable( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ToneDetectionDisableSer( f_pApiInstance, f_pToneDetectDisable ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ToneDetectionEnableSer Description: Activate the detection of a tone on the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectEnable Pointer to tone detect enable structure. This structure contains, among other things, the tone ID to enable and the channel handle where detection should be enabled. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ToneDetectionEnableSer UINT32 Oct6100ToneDetectionEnableSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable ) { UINT32 ulChanIndex; UINT32 ulExtToneChanIndex; UINT32 ulToneEventNumber = 0; UINT32 ulResult; /* Check the user's configuration of the tone detection for errors. */ ulResult = Oct6100ApiCheckToneEnableParams( f_pApiInstance, f_pToneDetectEnable, &ulChanIndex, &ulToneEventNumber, &ulExtToneChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write to all resources needed to enable tone detection. */ ulResult = Oct6100ApiWriteToneDetectEvent( f_pApiInstance, ulChanIndex, ulToneEventNumber, ulExtToneChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the channel entry to indicate that a new tone has been activated. */ ulResult = Oct6100ApiUpdateChanToneDetectEntry( f_pApiInstance, ulChanIndex, ulToneEventNumber, ulExtToneChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckToneEnableParams Description: Check the validity of the channel and tone requested. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectEnable Pointer to tone detection enable structure. f_pulChannelIndex Pointer to the channel index. f_pulToneEventNumber Pointer to the Index of the tone associated to the requested tone. f_pulExtToneChanIndex Pointer to the index of the extended channel index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckToneEnableParams UINT32 Oct6100ApiCheckToneEnableParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_ENABLE f_pToneDetectEnable, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulToneEventNumber, OUT PUINT32 f_pulExtToneChanIndex ) { tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulEntryOpenCnt; UINT32 i; /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pToneDetectEnable->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; *f_pulChannelIndex = f_pToneDetectEnable->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK; if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pToneDetectEnable->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChannel->fReserved != TRUE ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; /* Set the extended tone detection info if it is activated on the channel. */ *f_pulExtToneChanIndex = pEchoChannel->usExtToneChanIndex; /*=====================================================================*/ /* Check the tone information. */ /* Find out if the tone is present in the build. */ for ( i = 0; i < cOCT6100_MAX_TONE_EVENT; i++ ) { if ( f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ i ].ulToneID == f_pToneDetectEnable->ulToneNumber ) { *f_pulToneEventNumber = i; break; } } /* Check if tone is present. */ if ( i == cOCT6100_MAX_TONE_EVENT ) return cOCT6100_ERR_NOT_SUPPORTED_TONE_NOT_PRESENT_IN_FIRMWARE; /* Check if the requested tone is actually detected. */ if ((( pEchoChannel->aulToneConf[ *f_pulToneEventNumber / 32 ] >> ( 31 - ( *f_pulToneEventNumber % 32 ))) & 0x1) == 1 ) return cOCT6100_ERR_TONE_DETECTION_TONE_ACTIVATED; /*=====================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteToneDetectEvent Description: Write the tone detection event in the channel main structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulChannelIndex Index of the channel within the API's channel list. f_ulToneEventNumber Event number of the tone to be activated. f_ulExtToneChanIndex Index of the extended tone detection channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteToneDetectEvent UINT32 Oct6100ApiWriteToneDetectEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usReadData; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*=======================================================================*/ /* Read the current event config about to be modified. */ ReadParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ReadParams.ulReadAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; ReadParams.ulReadAddress += (f_ulToneEventNumber / 16) * 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Set the tone event in the channel main memory for the requested direction. */ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = usReadData; WriteParams.usWriteData |= ( 0x1 << ( 15 - ( f_ulToneEventNumber % 16 ))); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Also program the extended channel if one is present. */ if ( f_ulExtToneChanIndex != cOCT6100_INVALID_INDEX ) { /* Read the current event config about to be modified. */ ReadParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_ulExtToneChanIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ReadParams.ulReadAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; ReadParams.ulReadAddress += (f_ulToneEventNumber / 16) * 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the tone event in the channel main memory for the requested direction. */ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = usReadData; WriteParams.usWriteData |= ( 0x1 << ( 15 - ( f_ulToneEventNumber % 16 ))); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateChanToneDetectEntry Description: Update the echo channel entry to store the info about the tone being configured to generate detection events. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulChannelIndex Index of the channel within the API's channel list. f_ulToneEventNumber Enabled tone event number. f_ulExtToneChanIndex Index of the extended tone detection channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateChanToneDetectEntry UINT32 Oct6100ApiUpdateChanToneDetectEntry ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex ) { tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulToneEntry; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Update the channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_ulChannelIndex ); /* Set the corresponding bit in the channel array. */ ulToneEntry = pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ]; /* Modify the entry. */ ulToneEntry |= ( 0x1 << ( 31 - ( f_ulToneEventNumber % 32 ))); /* Copy back the new value. */ pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ] = ulToneEntry; /* Configure also the extended channel if necessary. */ if ( f_ulExtToneChanIndex != cOCT6100_INVALID_INDEX ) { /* Update the channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_ulExtToneChanIndex ); /* Set the corresponding bit in the channel array. */ ulToneEntry = pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ]; /* Modify the entry. */ ulToneEntry |= ( 0x1 << ( 31 - ( f_ulToneEventNumber % 32 ))); /* Copy back the new value. */ pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ] = ulToneEntry; } /* Check for the SS tone events that could have been generated before. */ if ( f_ulExtToneChanIndex == cOCT6100_INVALID_INDEX ) { BOOL fSSTone; UINT32 ulResult; ulResult = Oct6100ApiIsSSTone( f_pApiInstance, pSharedInfo->ImageInfo.aToneInfo[ f_ulToneEventNumber ].ulToneID, &fSSTone ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Is this a signaling system tone? */ if ( fSSTone == TRUE ) { /* Check if must generate an event for the last detected SS tone. */ if ( ( pEchoChanEntry->ulLastSSToneDetected != cOCT6100_INVALID_INDEX ) && ( pEchoChanEntry->ulLastSSToneDetected == pSharedInfo->ImageInfo.aToneInfo[ f_ulToneEventNumber ].ulToneID ) ) { /* Must write an event for this. */ tPOCT6100_API_TONE_EVENT pSoftEvent; /* If enough space. */ if ( ( ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr ) && ( ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0 ) ) { /* Form the event for this captured tone. */ mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_ulChannelIndex; pSoftEvent->ulUserChanId = pEchoChanEntry->ulUserChanId; pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ f_ulToneEventNumber ].ulToneID; pSoftEvent->ulTimestamp = pEchoChanEntry->ulLastSSToneTimestamp; pSoftEvent->ulExtToneDetectionPort = cOCT6100_INVALID_VALUE; pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; /* Update the control variables of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; /* Set the interrupt manager such that the user knows that some tone events */ /* are pending in the software Q. */ pSharedInfo->IntrptManage.fToneEventsPending = TRUE; } else { /* Set the overflow flag of the buffer. */ pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; } } } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ToneDetectionDisableSer Description: Disable the generation of events for a selected tone on the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectDisable Pointer to tOCT6100_TONE_DETECTION_DISABLE structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ToneDetectionDisableSer UINT32 Oct6100ToneDetectionDisableSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable ) { UINT32 ulChanIndex; UINT32 ulExtToneChanIndex; UINT32 ulToneEventNumber = 0; UINT32 ulResult; BOOL fDisableAll; /* Check the user's configuration of the tone detection disable structure for errors. */ ulResult = Oct6100ApiAssertToneDetectionParams( f_pApiInstance, f_pToneDetectDisable, &ulChanIndex, &ulToneEventNumber, &ulExtToneChanIndex, &fDisableAll ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear the event to detect the specified tone. */ ulResult = Oct6100ApiClearToneDetectionEvent( f_pApiInstance, ulChanIndex, ulToneEventNumber, ulExtToneChanIndex, fDisableAll ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the channel structure to indicate that the tone is no longer detected. */ ulResult = Oct6100ApiReleaseToneDetectionEvent( f_pApiInstance, ulChanIndex, ulToneEventNumber, ulExtToneChanIndex, fDisableAll ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertToneDetectionParams Description: Check the validity of the tone detection disable command. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pToneDetectDisable Pointer to tone detection disable structure. f_pulChannelIndex Pointer to the channel index f_pulToneEventNumber Pointer to the tone event number. f_pulExtToneChanIndex Pointer to the extended channel index. f_pfDisableAll Pointer to the flag specifying whether all tones should be disabled. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertToneDetectionParams UINT32 Oct6100ApiAssertToneDetectionParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_TONE_DETECTION_DISABLE f_pToneDetectDisable, OUT PUINT32 f_pulChannelIndex, OUT PUINT32 f_pulToneEventNumber, OUT PUINT32 f_pulExtToneChanIndex, OUT PBOOL f_pfDisableAll ) { tPOCT6100_API_CHANNEL pEchoChannel; UINT32 ulEntryOpenCnt; UINT32 i; /*=====================================================================*/ /* Check the echo channel handle. */ if ( (f_pToneDetectDisable->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; *f_pulChannelIndex = f_pToneDetectDisable->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK; if ( *f_pulChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, *f_pulChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pToneDetectDisable->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChannel->fReserved != TRUE ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChannel->byEntryOpenCnt ) return cOCT6100_ERR_TONE_DETECTION_CHANNEL_HANDLE_INVALID; /* Return the extended channel index. */ *f_pulExtToneChanIndex = pEchoChannel->usExtToneChanIndex; /* Check the disable all flag. */ if ( f_pToneDetectDisable->fDisableAll != TRUE && f_pToneDetectDisable->fDisableAll != FALSE ) return cOCT6100_ERR_TONE_DETECTION_DISABLE_ALL; /*=====================================================================*/ /* Check the tone information. */ /* Find out if the tone is present in the build. */ if ( f_pToneDetectDisable->fDisableAll == FALSE ) { for ( i = 0; i < cOCT6100_MAX_TONE_EVENT; i++ ) { if ( f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ i ].ulToneID == f_pToneDetectDisable->ulToneNumber ) { *f_pulToneEventNumber = i; break; } } /* Check if tone is present. */ if ( i == cOCT6100_MAX_TONE_EVENT ) return cOCT6100_ERR_NOT_SUPPORTED_TONE_NOT_PRESENT_IN_FIRMWARE; /* Check if the requested tone is actually detected. */ if ((( pEchoChannel->aulToneConf[ *f_pulToneEventNumber / 32 ] >> ( 31 - ( *f_pulToneEventNumber % 32 ))) & 0x1) == 0 ) return cOCT6100_ERR_TONE_DETECTION_TONE_NOT_ACTIVATED; } /*=====================================================================*/ /* Return the disable all flag as requested. */ *f_pfDisableAll = f_pToneDetectDisable->fDisableAll; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiClearToneDetectionEvent Description: Clear the buffer playout event in the channel main structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulChannelIndex Index of the channel within the API's channel list. f_ulToneEventNumber Tone event number to be deactivated. f_ulExtToneChanIndex Index of the extended tone detection channel. f_fDisableAll Clear all activated tones. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiClearToneDetectionEvent UINT32 Oct6100ApiClearToneDetectionEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex, IN BOOL f_fDisableAll ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_SMEAR_PARAMS SmearParams; UINT32 ulResult; UINT32 ulToneEventBaseAddress; UINT16 usReadData; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; SmearParams.pProcessContext = f_pApiInstance->pProcessContext; SmearParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*=======================================================================*/ /* Read the current event config about to be modified. */ ulToneEventBaseAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_ulChannelIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ulToneEventBaseAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; /* Check if must disable all tone events or not. */ if ( f_fDisableAll == FALSE ) { ReadParams.ulReadAddress = ulToneEventBaseAddress; ReadParams.ulReadAddress += (f_ulToneEventNumber / 16) * 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear the event in the channel main memory.*/ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = usReadData; WriteParams.usWriteData &= (~( 0x1 << ( 15 - ( f_ulToneEventNumber % 16 )))); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* if ( f_fDisableAll == TRUE ) */ { /* Clear all events in the channel main memory. */ SmearParams.ulWriteLength = 4; SmearParams.usWriteData = 0x0000; SmearParams.ulWriteAddress = ulToneEventBaseAddress; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /* Also program the extended channel if one is present. */ if ( f_ulExtToneChanIndex != cOCT6100_INVALID_INDEX ) { ulToneEventBaseAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_ulExtToneChanIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ulToneEventBaseAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; /* Check if must disable all tone events or not. */ if ( f_fDisableAll == FALSE ) { /* Read the current event config about to be modified. */ ReadParams.ulReadAddress = ulToneEventBaseAddress; ReadParams.ulReadAddress += (f_ulToneEventNumber / 16) * 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear the event in the channel main memory.*/ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = usReadData; WriteParams.usWriteData &= (~( 0x1 << ( 15 - ( f_ulToneEventNumber % 16 )))); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* if ( f_fDisableAll == TRUE ) */ { /* Clear all events in the channel main memory.*/ SmearParams.ulWriteLength = 4; SmearParams.usWriteData = 0x0000; SmearParams.ulWriteAddress = ulToneEventBaseAddress; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseToneDetectionEvent Description: Clear the entry made for this tone in the channel tone enable array. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulChannelIndex Index of the channel within the API's channel list. f_ulToneEventNumber Tone event number to be deactivated. f_ulExtToneChanIndex Index of the extended tone detection channel. f_fDisableAll Release all activated tones. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseToneDetectionEvent UINT32 Oct6100ApiReleaseToneDetectionEvent ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulChannelIndex, IN UINT32 f_ulToneEventNumber, IN UINT32 f_ulExtToneChanIndex, IN BOOL f_fDisableAll ) { tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulToneEntry; UINT32 ulResult; UINT32 ulToneEventNumber; BOOL fSSTone; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Update the channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_ulChannelIndex ); /* Check if must release all tone events. */ if ( f_fDisableAll == FALSE ) { /* Set the corresponding bit in the channel array. */ ulToneEntry = pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ]; /* Modify the entry. */ ulToneEntry &= (~( 0x1 << ( 31 - ( f_ulToneEventNumber % 32 )))); /* Copy back the new value. */ pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ] = ulToneEntry; } else /* if ( f_fDisableAll == TRUE ) */ { /* Clear all events. */ Oct6100UserMemSet( pEchoChanEntry->aulToneConf, 0x00, sizeof( pEchoChanEntry->aulToneConf ) ); } /* Configure also the extended channel if necessary. */ if ( f_ulExtToneChanIndex != cOCT6100_INVALID_INDEX ) { /* Update the channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_ulExtToneChanIndex ); /* Check if must release all tone events. */ if ( f_fDisableAll == FALSE ) { /* Set the corresponding bit in the channel array. */ ulToneEntry = pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ]; /* Modify the entry. */ ulToneEntry &= (~( 0x1 << ( 31 - ( f_ulToneEventNumber % 32 )))); /* Copy back the new value. */ pEchoChanEntry->aulToneConf[ f_ulToneEventNumber / 32 ] = ulToneEntry; } else /* if ( f_fDisableAll == TRUE ) */ { /* Clear all events. */ Oct6100UserMemSet( pEchoChanEntry->aulToneConf, 0x00, sizeof( pEchoChanEntry->aulToneConf ) ); } } /* Re-enable the SS7 tones */ for ( ulToneEventNumber = 0; ulToneEventNumber < cOCT6100_MAX_TONE_EVENT; ulToneEventNumber++ ) { /* Check if the current tone is a SS tone. */ ulResult = Oct6100ApiIsSSTone( f_pApiInstance, f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulToneID, &fSSTone ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( fSSTone == TRUE ) { /* Write to all resources needed to activate tone detection on this SS tone. */ ulResult = Oct6100ApiWriteToneDetectEvent( f_pApiInstance, f_ulChannelIndex, ulToneEventNumber, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiIsSSTone Description: Check if specified tone number is a special signaling system tone. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulToneEventNumber Tone event number to be checked against. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiIsSSTone UINT32 Oct6100ApiIsSSTone( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulToneEventNumber, OUT PBOOL f_fSSTone ) { *f_fSSTone = FALSE; switch( f_ulToneEventNumber ) { case cOCT6100_TONE_SIN_SYSTEM7_2000 : case cOCT6100_TONE_SIN_SYSTEM7_1780 : case cOCT6100_TONE_ROUT_G168_2100GB_ON : case cOCT6100_TONE_ROUT_G168_2100GB_WSPR : case cOCT6100_TONE_ROUT_G168_1100GB_ON : case cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_A : case cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_B : case cOCT6100_TONE_ROUT_G168_2100GB_WSPR_WIDE : case cOCT6100_TONE_SOUT_G168_2100GB_ON : case cOCT6100_TONE_SOUT_G168_2100GB_WSPR : case cOCT6100_TONE_SOUT_G168_1100GB_ON : case cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_A : case cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_B : case cOCT6100_TONE_SOUT_G168_2100GB_WSPR_WIDE : case cOCT6100_TONE_SIN_SYSTEM5_2400 : case cOCT6100_TONE_SIN_SYSTEM5_2600 : case cOCT6100_TONE_SIN_SYSTEM5_2400_2600 : *f_fSSTone = TRUE; break; default: break; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiIsSSTone Description: Check if specified tone number is a 2100 special signaling system tone. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulToneEventNumber Tone event number to be checked against. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiIs2100Tone UINT32 Oct6100ApiIs2100Tone( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulToneEventNumber, OUT PBOOL f_fIs2100Tone ) { *f_fIs2100Tone = FALSE; switch( f_ulToneEventNumber ) { case cOCT6100_TONE_ROUT_G168_2100GB_ON : case cOCT6100_TONE_ROUT_G168_2100GB_WSPR : case cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_A : case cOCT6100_TONE_ROUT_G168_2100GB_ON_WIDE_B : case cOCT6100_TONE_ROUT_G168_2100GB_WSPR_WIDE : case cOCT6100_TONE_SOUT_G168_2100GB_ON : case cOCT6100_TONE_SOUT_G168_2100GB_WSPR : case cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_A : case cOCT6100_TONE_SOUT_G168_2100GB_ON_WIDE_B : case cOCT6100_TONE_SOUT_G168_2100GB_WSPR_WIDE : *f_fIs2100Tone = TRUE; break; default: break; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_chip_stats.c0000644000175000017500000004273611525010337031610 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_chip_stats.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to retreive the OCT6100 chip stats. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 89 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_chip_stats_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_chip_stats_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_chip_stats_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipGetStats Description: Retreives the chip statistics and configuration. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipStats Pointer to a tOCT6100_CHIP_STATS structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipGetStatsDef UINT32 Oct6100ChipGetStatsDef( tPOCT6100_CHIP_STATS f_pChipStats ) { f_pChipStats->fResetChipStats = FALSE; f_pChipStats->ulNumberChannels = cOCT6100_INVALID_STAT; f_pChipStats->ulNumberTsiCncts = cOCT6100_INVALID_STAT; f_pChipStats->ulNumberConfBridges = cOCT6100_INVALID_STAT; f_pChipStats->ulNumberPlayoutBuffers = cOCT6100_INVALID_STAT; f_pChipStats->ulPlayoutFreeMemSize = cOCT6100_INVALID_STAT; f_pChipStats->ulNumberPhasingTssts = cOCT6100_INVALID_STAT; f_pChipStats->ulNumberAdpcmChannels = cOCT6100_INVALID_STAT; f_pChipStats->ulH100OutOfSynchCount = cOCT6100_INVALID_STAT; f_pChipStats->ulH100ClockABadCount = cOCT6100_INVALID_STAT; f_pChipStats->ulH100FrameABadCount = cOCT6100_INVALID_STAT; f_pChipStats->ulH100ClockBBadCount = cOCT6100_INVALID_STAT; f_pChipStats->ulInternalReadTimeoutCount = cOCT6100_INVALID_STAT; f_pChipStats->ulSdramRefreshTooLateCount = cOCT6100_INVALID_STAT; f_pChipStats->ulPllJitterErrorCount = cOCT6100_INVALID_STAT; f_pChipStats->ulOverflowToneEventsCount = cOCT6100_INVALID_STAT; f_pChipStats->ulSoftOverflowToneEventsCount = cOCT6100_INVALID_STAT; f_pChipStats->ulSoftOverflowBufferPlayoutEventsCount = cOCT6100_INVALID_STAT; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChipGetStats UINT32 Oct6100ChipGetStats( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHIP_STATS f_pChipStats ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChipGetStatsSer( f_pApiInstance, f_pChipStats ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipGetImageInfo Description: Retrieves the chip image information indicating the supported features and tones. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipImageInfo Pointer to a tPOCT6100_CHIP_IMAGE_INFO structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipGetImageInfoDef UINT32 Oct6100ChipGetImageInfoDef( tPOCT6100_CHIP_IMAGE_INFO f_pChipImageInfo ) { UINT32 i; Oct6100UserMemSet( f_pChipImageInfo->szVersionNumber, 0x0, cOCT6100_VERSION_NUMBER_MAX_SIZE ); f_pChipImageInfo->fBufferPlayout = FALSE; f_pChipImageInfo->fAdaptiveNoiseReduction = FALSE; f_pChipImageInfo->fSoutNoiseBleaching = FALSE; f_pChipImageInfo->fConferencingNoiseReduction = FALSE; f_pChipImageInfo->fAutoLevelControl = FALSE; f_pChipImageInfo->fHighLevelCompensation = FALSE; f_pChipImageInfo->fSilenceSuppression = FALSE; f_pChipImageInfo->fAdpcm = FALSE; f_pChipImageInfo->fConferencing = FALSE; f_pChipImageInfo->fDominantSpeaker = FALSE; f_pChipImageInfo->ulMaxChannels = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulNumTonesAvailable = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulToneProfileNumber = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulMaxTailDisplacement = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulBuildId = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulMaxTailLength = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulDebugEventSize = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulMaxPlayoutEvents = cOCT6100_INVALID_VALUE; f_pChipImageInfo->ulImageType = cOCT6100_INVALID_VALUE; f_pChipImageInfo->fAcousticEcho = FALSE; f_pChipImageInfo->fAecTailLength = FALSE; f_pChipImageInfo->fToneRemoval = FALSE; f_pChipImageInfo->fDefaultErl = FALSE; f_pChipImageInfo->fNonLinearityBehaviorA = FALSE; f_pChipImageInfo->fNonLinearityBehaviorB = FALSE; f_pChipImageInfo->fPerChannelTailDisplacement = FALSE; f_pChipImageInfo->fPerChannelTailLength = FALSE; f_pChipImageInfo->fListenerEnhancement = FALSE; f_pChipImageInfo->fRoutNoiseReduction = FALSE; f_pChipImageInfo->fRoutNoiseReductionLevel = FALSE; f_pChipImageInfo->fAnrSnrEnhancement = FALSE; f_pChipImageInfo->fAnrVoiceNoiseSegregation = FALSE; f_pChipImageInfo->fToneDisablerVqeActivationDelay = FALSE; f_pChipImageInfo->fMusicProtection = FALSE; f_pChipImageInfo->fDoubleTalkBehavior = FALSE; f_pChipImageInfo->fIdleCodeDetection = TRUE; f_pChipImageInfo->fSinLevel = TRUE; for ( i = 0; i < cOCT6100_MAX_TONE_EVENT; i++ ) { Oct6100UserMemSet( f_pChipImageInfo->aToneInfo[ i ].aszToneName, 0x00, cOCT6100_TLV_MAX_TONE_NAME_SIZE ); f_pChipImageInfo->aToneInfo[ i ].ulDetectionPort = cOCT6100_INVALID_PORT; f_pChipImageInfo->aToneInfo[ i ].ulToneID = cOCT6100_INVALID_VALUE; } return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChipGetImageInfo UINT32 Oct6100ChipGetImageInfo( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHIP_IMAGE_INFO f_pChipImageInfo ) { tPOCT6100_API_IMAGE_INFO pImageInfo; UINT32 i; /* Get local pointer(s). */ pImageInfo = &f_pApiInstance->pSharedInfo->ImageInfo; Oct6100UserMemCopy( f_pChipImageInfo->szVersionNumber, pImageInfo->szVersionNumber, cOCT6100_VERSION_NUMBER_MAX_SIZE ); /* Copy the customer info. */ f_pChipImageInfo->ulBuildId = pImageInfo->ulBuildId; /* Copy the features list. */ f_pChipImageInfo->fBufferPlayout = pImageInfo->fBufferPlayout; f_pChipImageInfo->fAdaptiveNoiseReduction = pImageInfo->fAdaptiveNoiseReduction; f_pChipImageInfo->fSoutNoiseBleaching = pImageInfo->fSoutNoiseBleaching; f_pChipImageInfo->fSilenceSuppression = pImageInfo->fSilenceSuppression; f_pChipImageInfo->fAdpcm = pImageInfo->fAdpcm; f_pChipImageInfo->fConferencing = pImageInfo->fConferencing; f_pChipImageInfo->fDominantSpeaker = pImageInfo->fDominantSpeakerEnabled; f_pChipImageInfo->fConferencingNoiseReduction = pImageInfo->fConferencingNoiseReduction; f_pChipImageInfo->fAcousticEcho = pImageInfo->fAcousticEcho; f_pChipImageInfo->fAecTailLength = pImageInfo->fAecTailLength; f_pChipImageInfo->fDefaultErl = pImageInfo->fDefaultErl; f_pChipImageInfo->fToneRemoval = pImageInfo->fToneRemoval; f_pChipImageInfo->fNonLinearityBehaviorA = pImageInfo->fNonLinearityBehaviorA; f_pChipImageInfo->fNonLinearityBehaviorB = pImageInfo->fNonLinearityBehaviorB; f_pChipImageInfo->fPerChannelTailDisplacement = pImageInfo->fPerChannelTailDisplacement; f_pChipImageInfo->fListenerEnhancement = pImageInfo->fListenerEnhancement; f_pChipImageInfo->fRoutNoiseReduction = pImageInfo->fRoutNoiseReduction; f_pChipImageInfo->fRoutNoiseReductionLevel = pImageInfo->fRoutNoiseReductionLevel; f_pChipImageInfo->fAnrSnrEnhancement = pImageInfo->fAnrSnrEnhancement; f_pChipImageInfo->fAnrVoiceNoiseSegregation = pImageInfo->fAnrVoiceNoiseSegregation; f_pChipImageInfo->fMusicProtection = pImageInfo->fMusicProtection; f_pChipImageInfo->fIdleCodeDetection = pImageInfo->fIdleCodeDetection; f_pChipImageInfo->fSinLevel = pImageInfo->fSinLevel; f_pChipImageInfo->fDoubleTalkBehavior = pImageInfo->fDoubleTalkBehavior; f_pChipImageInfo->fHighLevelCompensation = pImageInfo->fRinHighLevelCompensation; if ( ( pImageInfo->fRinAutoLevelControl == TRUE ) && ( pImageInfo->fSoutAutoLevelControl == TRUE ) ) f_pChipImageInfo->fAutoLevelControl = TRUE; else f_pChipImageInfo->fAutoLevelControl = FALSE; f_pChipImageInfo->ulMaxChannels = pImageInfo->usMaxNumberOfChannels; f_pChipImageInfo->ulNumTonesAvailable = pImageInfo->byNumToneDetectors; f_pChipImageInfo->ulToneProfileNumber = pImageInfo->ulToneProfileNumber; f_pChipImageInfo->ulMaxTailDisplacement = pImageInfo->usMaxTailDisplacement; f_pChipImageInfo->ulMaxTailLength = pImageInfo->usMaxTailLength; f_pChipImageInfo->fPerChannelTailLength = pImageInfo->fPerChannelTailLength; f_pChipImageInfo->ulDebugEventSize = f_pApiInstance->pSharedInfo->DebugInfo.ulDebugEventSize; f_pChipImageInfo->fToneDisablerVqeActivationDelay = pImageInfo->fToneDisablerVqeActivationDelay; f_pChipImageInfo->ulMaxPlayoutEvents = pImageInfo->byMaxNumberPlayoutEvents - 1; /* 127 or 31 */ f_pChipImageInfo->ulImageType = pImageInfo->byImageType; for ( i = 0; i < cOCT6100_MAX_TONE_EVENT; i++ ) { Oct6100UserMemCopy( f_pChipImageInfo->aToneInfo[ i ].aszToneName, pImageInfo->aToneInfo[ i ].aszToneName, cOCT6100_TLV_MAX_TONE_NAME_SIZE ); f_pChipImageInfo->aToneInfo[ i ].ulDetectionPort = pImageInfo->aToneInfo[ i ].ulDetectionPort; f_pChipImageInfo->aToneInfo[ i ].ulToneID = pImageInfo->aToneInfo[ i ].ulToneID; } return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiChipStatsSwInit Description: Initializes portions of API instance associated to chip stats. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiChipStatsSwInit UINT32 Oct6100ApiChipStatsSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; /* Get local pointer to shared portion of API instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize chip stats. */ pSharedInfo->ErrorStats.fFatalChipError = FALSE; pSharedInfo->ErrorStats.ulH100ClkABadCnt = 0; pSharedInfo->ErrorStats.ulH100ClkBBadCnt = 0; pSharedInfo->ErrorStats.ulH100FrameABadCnt = 0; pSharedInfo->ErrorStats.ulH100OutOfSyncCnt = 0; pSharedInfo->ErrorStats.ulInternalReadTimeoutCnt = 0; pSharedInfo->ErrorStats.ulSdramRefreshTooLateCnt = 0; pSharedInfo->ErrorStats.ulPllJitterErrorCnt = 0; pSharedInfo->ErrorStats.ulOverflowToneEventsCnt = 0; pSharedInfo->ErrorStats.ulToneDetectorErrorCnt = 0; /* Init the chip stats. */ pSharedInfo->ChipStats.usNumberChannels = 0; pSharedInfo->ChipStats.usNumberBiDirChannels = 0; pSharedInfo->ChipStats.usNumberTsiCncts = 0; pSharedInfo->ChipStats.usNumberConfBridges = 0; pSharedInfo->ChipStats.usNumberPlayoutBuffers = 0; pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts = 0; pSharedInfo->ChipStats.ulPlayoutMemUsed = 0; pSharedInfo->ChipStats.usNumEcChanUsingMixer = 0; pSharedInfo->ChipStats.usNumberPhasingTssts = 0; pSharedInfo->ChipStats.usNumberAdpcmChans = 0; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChipGetStatsSer Description: Serialized function retreiving the chip statistics. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChipStats Pointer to master mode configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChipGetStatsSer UINT32 Oct6100ChipGetStatsSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_CHIP_STATS f_pChipStats ) { tPOCT6100_SHARED_INFO pSharedInfo; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; f_pChipStats->ulNumberChannels = pSharedInfo->ChipStats.usNumberChannels; f_pChipStats->ulNumberTsiCncts = pSharedInfo->ChipStats.usNumberTsiCncts; f_pChipStats->ulNumberConfBridges = pSharedInfo->ChipStats.usNumberConfBridges; f_pChipStats->ulNumberPlayoutBuffers = pSharedInfo->ChipStats.usNumberPlayoutBuffers; f_pChipStats->ulPlayoutFreeMemSize = ( f_pApiInstance->pSharedInfo->MiscVars.ulTotalMemSize - ( f_pApiInstance->pSharedInfo->MemoryMap.ulFreeMemBaseAddress - cOCT6100_EXTERNAL_MEM_BASE_ADDRESS ) ) - ( pSharedInfo->ChipStats.ulPlayoutMemUsed ); f_pChipStats->ulNumberPhasingTssts = pSharedInfo->ChipStats.usNumberPhasingTssts; f_pChipStats->ulNumberAdpcmChannels = pSharedInfo->ChipStats.usNumberAdpcmChans; /* Check the input parameters. */ if ( f_pChipStats->fResetChipStats != TRUE && f_pChipStats->fResetChipStats != FALSE ) return cOCT6100_ERR_CHIP_STATS_RESET; if ( f_pChipStats->fResetChipStats == TRUE ) { pSharedInfo->ErrorStats.ulH100OutOfSyncCnt = 0; pSharedInfo->ErrorStats.ulH100ClkABadCnt = 0; pSharedInfo->ErrorStats.ulH100FrameABadCnt = 0; pSharedInfo->ErrorStats.ulH100ClkBBadCnt = 0; pSharedInfo->ErrorStats.ulInternalReadTimeoutCnt = 0; pSharedInfo->ErrorStats.ulPllJitterErrorCnt = 0; pSharedInfo->ErrorStats.ulSdramRefreshTooLateCnt = 0; pSharedInfo->ErrorStats.ulOverflowToneEventsCnt = 0; pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt = 0; pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt = 0; } f_pChipStats->ulH100OutOfSynchCount = pSharedInfo->ErrorStats.ulH100OutOfSyncCnt; f_pChipStats->ulH100ClockABadCount = pSharedInfo->ErrorStats.ulH100ClkABadCnt; f_pChipStats->ulH100FrameABadCount = pSharedInfo->ErrorStats.ulH100FrameABadCnt; f_pChipStats->ulH100ClockBBadCount = pSharedInfo->ErrorStats.ulH100ClkBBadCnt; f_pChipStats->ulInternalReadTimeoutCount = pSharedInfo->ErrorStats.ulInternalReadTimeoutCnt; f_pChipStats->ulPllJitterErrorCount = pSharedInfo->ErrorStats.ulPllJitterErrorCnt; f_pChipStats->ulSdramRefreshTooLateCount = pSharedInfo->ErrorStats.ulSdramRefreshTooLateCnt; f_pChipStats->ulOverflowToneEventsCount = pSharedInfo->ErrorStats.ulOverflowToneEventsCnt; f_pChipStats->ulSoftOverflowToneEventsCount = pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt; f_pChipStats->ulSoftOverflowBufferPlayoutEventsCount = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_interrupts.c0000644000175000017500000021633311525010337031662 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_interrupts.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the API's interrupt service routine and all of its sub-functions. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 81 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_events_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_events_priv.h" #include "oct6100_interrupts_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100InterruptConfigure Description: Configure the operation of all possible interrupt sources. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntrptConfig Pointer to interrupt configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100InterruptConfigureDef UINT32 Oct6100InterruptConfigureDef( tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig ) { f_pIntrptConfig->ulFatalGeneralConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pIntrptConfig->ulFatalMemoryConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pIntrptConfig->ulErrorMemoryConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pIntrptConfig->ulErrorOverflowToneEventsConfig = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pIntrptConfig->ulErrorH100Config = cOCT6100_INTERRUPT_NO_TIMEOUT; f_pIntrptConfig->ulFatalMemoryTimeout = 100; f_pIntrptConfig->ulErrorMemoryTimeout = 100; f_pIntrptConfig->ulErrorOverflowToneEventsTimeout = 100; f_pIntrptConfig->ulErrorH100Timeout = 100; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100InterruptConfigure UINT32 Oct6100InterruptConfigure( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulResult; UINT32 ulFncRes; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Create serialization object for ISR. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulResult = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Call serialized sub-function. */ ulFncRes = Oct6100InterruptConfigureSer( f_pApiInstance, f_pIntrptConfig, TRUE ); /* Release serialization object. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulResult = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if an error occured in sub-function. */ if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100InterruptServiceRoutine Description: The API's interrupt service routine. This function clears all register ROLs which have generated an interrupt and report the events in the user supplied structure. Also, the tone event and/or playout event buffer will be emptied if valid events are present. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntFlags Pointer to structure containing event flags returned to user. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100InterruptServiceRoutineDef UINT32 Oct6100InterruptServiceRoutineDef( tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ) { f_pIntFlags->fFatalGeneral = FALSE; f_pIntFlags->ulFatalGeneralFlags = 0x0; f_pIntFlags->fFatalReadTimeout = FALSE; f_pIntFlags->fErrorRefreshTooLate = FALSE; f_pIntFlags->fErrorPllJitter = FALSE; f_pIntFlags->fErrorOverflowToneEvents = FALSE; f_pIntFlags->fErrorH100OutOfSync = FALSE; f_pIntFlags->fErrorH100ClkA = FALSE; f_pIntFlags->fErrorH100ClkB = FALSE; f_pIntFlags->fErrorH100FrameA = FALSE; f_pIntFlags->fToneEventsPending = FALSE; f_pIntFlags->fBufferPlayoutEventsPending = FALSE; f_pIntFlags->fApiSynch = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100InterruptServiceRoutine UINT32 Oct6100InterruptServiceRoutine( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulResult; UINT32 ulFncRes; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize the serialization object for the ISR. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulResult = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulResult == cOCT6100_ERR_OK ) { /* Call the serialized sub-function. */ ulFncRes = Oct6100InterruptServiceRoutineSer( f_pApiInstance, f_pIntFlags ); } else { return ulResult; } /* Release the serialization object. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulResult = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check for an error in the sub-function. */ if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiIsrSwInit Description: Initializes portions of API instance associated to the API's interrupt service routine. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiIsrSwInit UINT32 Oct6100ApiIsrSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the state of each interrupt group to disabled. The state will */ /* be updated to the true configuration once the configure interrupts function is called. */ pSharedInfo->IntrptManage.byFatalGeneralState = cOCT6100_INTRPT_DISABLED; pSharedInfo->IntrptManage.byFatalMemoryState = cOCT6100_INTRPT_DISABLED; pSharedInfo->IntrptManage.byErrorMemoryState = cOCT6100_INTRPT_DISABLED; pSharedInfo->IntrptManage.byErrorH100State = cOCT6100_INTRPT_DISABLED; pSharedInfo->IntrptManage.byErrorOverflowToneEventsState = cOCT6100_INTRPT_DISABLED; /* Indicate that the mclk interrupt is not active at the moment. */ pSharedInfo->IntrptManage.fMclkIntrptActive = FALSE; /* Indicate that no buffer playout events are pending for the moment. */ pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; /* Indicate that no tone events are pending for the moment. */ pSharedInfo->IntrptManage.fToneEventsPending = FALSE; /* The ISR has never been called. */ pSharedInfo->IntrptManage.fIsrCalled = FALSE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiIsrHwInit Description: Initializes the chip's interrupt registers. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntrptConfig Pointer to structure defining how the interrupts should be configured. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiIsrHwInit UINT32 Oct6100ApiIsrHwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*==================================================================================*/ /* Enable all the interrupts */ WriteParams.ulWriteAddress = 0x104; WriteParams.usWriteData = 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x204; WriteParams.usWriteData = 0x1C05; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0xFFFF; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x504; WriteParams.usWriteData = 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x704; WriteParams.usWriteData = 0x0007; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /* Calculate the number of mclk cycles in 1 ms. */ f_pApiInstance->pSharedInfo->IntrptManage.ulNumMclkCyclesIn1Ms = f_pApiInstance->pSharedInfo->MiscVars.ulMclkFreq / 1000; /* Configure the interrupt registers as requested by the user. */ ulResult = Oct6100InterruptConfigureSer( f_pApiInstance, f_pIntrptConfig, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100InterruptConfigureSer Description: Configure the operation of interrupt groups. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntrptConfig Pointer to interrupt configuration structure. f_fCheckParams Check parameter enable flag. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100InterruptConfigureSer UINT32 Oct6100InterruptConfigureSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_CONFIGURE f_pIntrptConfig, IN BOOL f_fCheckParams ) { tPOCT6100_API_INTRPT_CONFIG pIntrptConfig; tPOCT6100_API_INTRPT_MANAGE pIntrptManage; UINT32 ulResult; /* Check for errors. */ if ( f_fCheckParams == TRUE ) { if ( f_pIntrptConfig->ulFatalGeneralConfig != cOCT6100_INTERRUPT_DISABLE && f_pIntrptConfig->ulFatalGeneralConfig != cOCT6100_INTERRUPT_NO_TIMEOUT ) return cOCT6100_ERR_INTRPTS_FATAL_GENERAL_CONFIG; if ( f_pIntrptConfig->ulFatalMemoryConfig != cOCT6100_INTERRUPT_DISABLE && f_pIntrptConfig->ulFatalMemoryConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pIntrptConfig->ulFatalMemoryConfig != cOCT6100_INTERRUPT_NO_TIMEOUT ) return cOCT6100_ERR_INTRPTS_FATAL_MEMORY_CONFIG; if ( f_pIntrptConfig->ulErrorMemoryConfig != cOCT6100_INTERRUPT_DISABLE && f_pIntrptConfig->ulErrorMemoryConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pIntrptConfig->ulErrorMemoryConfig != cOCT6100_INTERRUPT_NO_TIMEOUT ) return cOCT6100_ERR_INTRPTS_DATA_ERR_MEMORY_CONFIG; if ( f_pIntrptConfig->ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_DISABLE && f_pIntrptConfig->ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_TIMEOUT && f_pIntrptConfig->ulErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_NO_TIMEOUT ) return cOCT6100_ERR_INTRPTS_OVERFLOW_TONE_EVENTS_CONFIG; if ( f_pIntrptConfig->ulErrorH100Config != cOCT6100_INTERRUPT_DISABLE && f_pIntrptConfig->ulErrorH100Config != cOCT6100_INTERRUPT_TIMEOUT && f_pIntrptConfig->ulErrorH100Config != cOCT6100_INTERRUPT_NO_TIMEOUT ) return cOCT6100_ERR_INTRPTS_H100_ERROR_CONFIG; if ( f_pIntrptConfig->ulFatalMemoryTimeout < 10 || f_pIntrptConfig->ulFatalMemoryTimeout > 10000 ) return cOCT6100_ERR_INTRPTS_FATAL_MEMORY_TIMEOUT; if ( f_pIntrptConfig->ulErrorMemoryTimeout < 10 || f_pIntrptConfig->ulErrorMemoryTimeout > 10000 ) return cOCT6100_ERR_INTRPTS_DATA_ERR_MEMORY_TIMEOUT; if ( f_pIntrptConfig->ulErrorOverflowToneEventsTimeout < 10 || f_pIntrptConfig->ulErrorOverflowToneEventsTimeout > 10000 ) return cOCT6100_ERR_INTRPTS_OVERFLOW_TONE_EVENTS_TIMEOUT; if ( f_pIntrptConfig->ulErrorH100Timeout < 10 || f_pIntrptConfig->ulErrorH100Timeout > 10000 ) return cOCT6100_ERR_INTRPTS_H100_ERROR_TIMEOUT; } /* Copy the configuration to the API instance. */ pIntrptConfig = &f_pApiInstance->pSharedInfo->IntrptConfig; pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; pIntrptConfig->byFatalGeneralConfig = (UINT8)( f_pIntrptConfig->ulFatalGeneralConfig & 0xFF ); pIntrptConfig->byFatalMemoryConfig = (UINT8)( f_pIntrptConfig->ulFatalMemoryConfig & 0xFF ); pIntrptConfig->byErrorMemoryConfig = (UINT8)( f_pIntrptConfig->ulErrorMemoryConfig & 0xFF ); pIntrptConfig->byErrorOverflowToneEventsConfig = (UINT8)( f_pIntrptConfig->ulErrorOverflowToneEventsConfig & 0xFF ); pIntrptConfig->byErrorH100Config = (UINT8)( f_pIntrptConfig->ulErrorH100Config & 0xFF ); f_pIntrptConfig->ulFatalMemoryTimeout = ((f_pIntrptConfig->ulFatalMemoryTimeout + 9) / 10) * 10; pIntrptConfig->ulFatalMemoryTimeoutMclk = f_pIntrptConfig->ulFatalMemoryTimeout * pIntrptManage->ulNumMclkCyclesIn1Ms; f_pIntrptConfig->ulErrorMemoryTimeout = ((f_pIntrptConfig->ulErrorMemoryTimeout + 9) / 10) * 10; pIntrptConfig->ulErrorMemoryTimeoutMclk = f_pIntrptConfig->ulErrorMemoryTimeout * pIntrptManage->ulNumMclkCyclesIn1Ms; f_pIntrptConfig->ulErrorOverflowToneEventsTimeout = ((f_pIntrptConfig->ulErrorOverflowToneEventsTimeout + 9) / 10) * 10; pIntrptConfig->ulErrorOverflowToneEventsTimeoutMclk = f_pIntrptConfig->ulErrorOverflowToneEventsTimeout * pIntrptManage->ulNumMclkCyclesIn1Ms; f_pIntrptConfig->ulErrorH100Timeout = ((f_pIntrptConfig->ulErrorH100Timeout + 9) / 10) * 10; pIntrptConfig->ulErrorH100TimeoutMclk = f_pIntrptConfig->ulErrorH100Timeout * pIntrptManage->ulNumMclkCyclesIn1Ms; /*Clear all interrupts that were already enabled*/ ulResult = Oct6100ApiClearEnabledInterrupts( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Before writing the new configuration to the chip's registers, make sure that any */ /* interrupts which are either disabled or have no timeout period are not on the */ /* disabled interrupt list. */ /*==================================================================================*/ if ( pIntrptConfig->byFatalGeneralConfig == cOCT6100_INTERRUPT_DISABLE ) pIntrptManage->byFatalGeneralState = cOCT6100_INTRPT_DISABLED; else /* pIntrptConfig->byFatalGeneralConfig == cOCT6100_INTERRUPT_NO_TIMEOUT */ pIntrptManage->byFatalGeneralState = cOCT6100_INTRPT_ACTIVE; /*==================================================================================*/ if ( pIntrptConfig->byFatalMemoryConfig == cOCT6100_INTERRUPT_DISABLE ) pIntrptManage->byFatalMemoryState = cOCT6100_INTRPT_DISABLED; else if ( pIntrptConfig->byFatalMemoryConfig == cOCT6100_INTERRUPT_NO_TIMEOUT ) pIntrptManage->byFatalMemoryState = cOCT6100_INTRPT_ACTIVE; else /* ( pIntrptConfig->byFatalMemoryConfig == cOCT6100_INTERRUPT_TIMEOUT ) */ { if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_DISABLED ) pIntrptManage->byFatalMemoryState = cOCT6100_INTRPT_ACTIVE; } /*==================================================================================*/ if ( pIntrptConfig->byErrorMemoryConfig == cOCT6100_INTERRUPT_DISABLE ) pIntrptManage->byErrorMemoryState = cOCT6100_INTRPT_DISABLED; else if ( pIntrptConfig->byErrorMemoryConfig == cOCT6100_INTERRUPT_NO_TIMEOUT ) pIntrptManage->byErrorMemoryState = cOCT6100_INTRPT_ACTIVE; else /* (pIntrptConfig->byErrorMemoryConfig == cOCT6100_INTERRUPT_TIMEOUT ) */ { if ( pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_DISABLED ) pIntrptManage->byErrorMemoryState = cOCT6100_INTRPT_ACTIVE; } /*==================================================================================*/ if ( pIntrptConfig->byErrorOverflowToneEventsConfig == cOCT6100_INTERRUPT_DISABLE ) pIntrptManage->byErrorOverflowToneEventsState = cOCT6100_INTRPT_DISABLED; else if ( pIntrptConfig->byErrorOverflowToneEventsConfig == cOCT6100_INTERRUPT_NO_TIMEOUT ) pIntrptManage->byErrorOverflowToneEventsState = cOCT6100_INTRPT_ACTIVE; else /* (pIntrptConfig->byErrorOverflowToneEventsConfig == cOCT6100_INTERRUPT_TIMEOUT ) */ { if ( pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_DISABLED ) pIntrptManage->byErrorOverflowToneEventsState = cOCT6100_INTRPT_ACTIVE; } /*==================================================================================*/ if ( pIntrptConfig->byErrorH100Config == cOCT6100_INTERRUPT_DISABLE ) pIntrptManage->byErrorH100State = cOCT6100_INTRPT_DISABLED; else if ( pIntrptConfig->byErrorH100Config == cOCT6100_INTERRUPT_NO_TIMEOUT ) pIntrptManage->byErrorH100State = cOCT6100_INTRPT_ACTIVE; else /* (pIntrptConfig->byErrorH100Config == cOCT6100_INTERRUPT_TIMEOUT ) */ { if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_DISABLED ) pIntrptManage->byErrorH100State = cOCT6100_INTRPT_ACTIVE; } /* Write to the interrupt registers to update the state of each interrupt group. */ ulResult = Oct6100ApiWriteIeRegs( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiClearEnabledInterrupts Description: Disabled interruption are not reported but still available. This function will clear the interrupts that were disabled and wish to enable now. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntrptConfig Pointer to interrupt configuration structure. f_pIntrptManage Pointer to interrupt manager structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiClearEnabledInterrupts UINT32 Oct6100ApiClearEnabledInterrupts( IN tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tPOCT6100_API_INTRPT_CONFIG pIntrptConfig; tPOCT6100_API_INTRPT_MANAGE pIntrptManage; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set the process context and user chip ID parameters once and for all. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Copy the configuration to the API instance. */ pIntrptConfig = &f_pApiInstance->pSharedInfo->IntrptConfig; pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; if ( pIntrptConfig->byFatalGeneralConfig != cOCT6100_INTERRUPT_DISABLE && pIntrptManage->byFatalGeneralState != cOCT6100_INTRPT_DISABLED ) { WriteParams.ulWriteAddress = 0x102; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_102H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x202; WriteParams.usWriteData = 0x1800; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x502; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_502H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pIntrptConfig->byErrorMemoryConfig != cOCT6100_INTERRUPT_DISABLE && pIntrptManage->byErrorMemoryState != cOCT6100_INTRPT_DISABLED ) { WriteParams.ulWriteAddress = 0x202; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_202H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pIntrptConfig->byErrorH100Config != cOCT6100_INTERRUPT_DISABLE && pIntrptManage->byErrorH100State != cOCT6100_INTRPT_DISABLED ) { WriteParams.ulWriteAddress = 0x302; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_302H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pIntrptConfig->byErrorOverflowToneEventsConfig != cOCT6100_INTERRUPT_DISABLE && pIntrptManage->byErrorOverflowToneEventsState != cOCT6100_INTRPT_DISABLED ) { WriteParams.ulWriteAddress = 0x702; WriteParams.usWriteData = cOCT6100_INTRPT_MASK_REG_702H; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100InterruptServiceRoutineSer Description: Serialized sub-function of API's interrupt service routine. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntFlags Pointer to structure containing event flags returned to user. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100InterruptServiceRoutineSer UINT32 Oct6100InterruptServiceRoutineSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulRegister210h; UINT32 ulResult; UINT16 usReadData; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Must update the statistics. Set parameters in read and write structs. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Set all the flags to default values to make sure the variables are initialized. */ f_pIntFlags->fFatalGeneral = FALSE; f_pIntFlags->ulFatalGeneralFlags = 0x0; f_pIntFlags->fFatalReadTimeout = FALSE; f_pIntFlags->fErrorRefreshTooLate = FALSE; f_pIntFlags->fErrorPllJitter = FALSE; f_pIntFlags->fErrorH100OutOfSync = FALSE; f_pIntFlags->fErrorH100ClkA = FALSE; f_pIntFlags->fErrorH100ClkB = FALSE; f_pIntFlags->fErrorH100FrameA = FALSE; f_pIntFlags->fApiSynch = FALSE; f_pIntFlags->fErrorOverflowToneEvents = FALSE; /* Start by reading registers 210h to determine if any modules have flagged an interrupt. */ ReadParams.ulReadAddress = 0x210; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulRegister210h = usReadData; /* Update the extended mclk counter. */ ulResult = Oct6100ApiReadChipMclkTime( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* If the mclk interrupt is active then check which interrupt timeout periods have expired. */ ReadParams.ulReadAddress = 0x302; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( (usReadData & 0x1) != 0 && pSharedInfo->IntrptManage.fMclkIntrptActive == TRUE ) { /* Update timeout periods. */ ulResult = Oct6100ApiUpdateIntrptTimeouts( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pIntFlags->fApiSynch = TRUE; /* Read registers 210h and 212h again to determine if any modules have flagged an interrupt. */ ReadParams.ulReadAddress = 0x210; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulRegister210h = usReadData; } /* Read the interrupt registers to determine what interrupt conditions have occured. */ ulResult = Oct6100ApiReadIntrptRegs( f_pApiInstance, f_pIntFlags, ulRegister210h ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Empty the tone buffer if any events are pending. */ ulResult = Oct6100ApiTransferToneEvents( f_pApiInstance, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the tone events pending flag. */ f_pIntFlags->fToneEventsPending = pSharedInfo->IntrptManage.fToneEventsPending; /* Check for buffer playout events and insert in the software queue -- if activated. */ if ( pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize != 0 ) { ulResult = Oct6100BufferPlayoutTransferEvents( f_pApiInstance, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the buffer playout events pending flag. */ f_pIntFlags->fBufferPlayoutEventsPending = pSharedInfo->IntrptManage.fBufferPlayoutEventsPending; } else { f_pIntFlags->fBufferPlayoutEventsPending = FALSE; } /* Update the states of each interrupt group. */ ulResult = Oct6100ApiUpdateIntrptStates( f_pApiInstance, f_pIntFlags ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check the state of the NLP timestamp if required.*/ ulResult = Oct6100ApiCheckProcessorState( f_pApiInstance, f_pIntFlags ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write to the necessary IE registers. */ ulResult = Oct6100ApiWriteIntrptRegs( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Schedule the next mclk interrupt, if one is needed. */ ulResult = Oct6100ApiScheduleNextMclkIntrptSer( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Free the interrupt pin of the chip (i.e. remove minimum time requirement between interrupts). */ WriteParams.ulWriteAddress = 0x214; WriteParams.usWriteData = 0x0000; if ( pSharedInfo->ChipConfig.byInterruptPolarity == cOCT6100_ACTIVE_HIGH_POLARITY ) WriteParams.usWriteData |= 0x4000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Indicate that the interrupt ROLs have been treated. */ WriteParams.ulWriteAddress = 0x212; WriteParams.usWriteData = 0x8000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReadIntrptRegs Description: Reads the interrupt registers of all modules currently indicating an interrupt condition. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntFlags Pointer to an interrupt flag structure. f_ulRegister210h Value of register 0x210. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReadIntrptRegs UINT32 Oct6100ApiReadIntrptRegs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags, IN UINT32 f_ulRegister210h ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHIP_ERROR_STATS pErrorStats; tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT16 usReadData; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulTempData; UINT32 ulCounterValue; UINT32 ulMask; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; pErrorStats = &pSharedInfo->ErrorStats; pIntrptManage = &pSharedInfo->IntrptManage; /* Set some parameters of read struct. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* CPU registers. */ if ( (f_ulRegister210h & 0x00001) != 0 ) { /*=======================================================================*/ /* Read registers of this module. */ ReadParams.ulReadAddress = 0x102; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check which interrupt(s) were set. */ if ( (usReadData & 0x0001) != 0 ) { f_pIntFlags->fFatalReadTimeout = TRUE; pErrorStats->ulInternalReadTimeoutCnt++; } pIntrptManage->usRegister102h = usReadData; /*=======================================================================*/ } else { pIntrptManage->usRegister102h = 0x0; } /* MAIN registers. */ if ( (f_ulRegister210h & 0x00002) != 0 ) { /*=======================================================================*/ /* Read registers of this module. */ ReadParams.ulReadAddress = 0x202; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save current value in instance. */ pIntrptManage->usRegister202h = usReadData; /* Check which interrupts were set. */ if ( (usReadData & 0x0001) != 0 ) { f_pIntFlags->fErrorRefreshTooLate = TRUE; pErrorStats->ulSdramRefreshTooLateCnt++; } if ( (usReadData & 0x0800) != 0 ) { f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_1; f_pIntFlags->fFatalGeneral = TRUE; pErrorStats->fFatalChipError = TRUE; } if ( (usReadData & 0x1000) != 0 ) { f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_2; f_pIntFlags->fFatalGeneral = TRUE; pErrorStats->fFatalChipError = TRUE; } if ( (usReadData & 0x0400) != 0 ) { f_pIntFlags->fErrorPllJitter = TRUE; pErrorStats->ulPllJitterErrorCnt++; /* Update the PLL jitter error count here. */ if ( pSharedInfo->DebugInfo.fPouchCounter == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Read previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Update counter. */ ulCounterValue = ulTempData & ulMask; ulCounterValue = ulCounterValue >> ulFeatureBitOffset; ulCounterValue ++; /* Handle wrap around case. */ ulCounterValue &= ( 1 << ulFeatureFieldLength ) - 1; /* Clear old counter value. */ ulTempData &= (~ulMask); ulTempData |= ulCounterValue << ulFeatureBitOffset; /* Write the DWORD where the field is located.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*=======================================================================*/ } else { pIntrptManage->usRegister202h = 0x0; } /* H.100 registers. */ if ( (f_ulRegister210h & 0x00004) != 0 ) { /*=======================================================================*/ /* Read registers of this module. */ ReadParams.ulReadAddress = 0x302; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check which interrupts were set. */ if ( (usReadData & 0x0100) != 0 ) { f_pIntFlags->fErrorH100OutOfSync = TRUE; pErrorStats->ulH100OutOfSyncCnt++; } if ( (usReadData & 0x1000) != 0 ) { f_pIntFlags->fErrorH100FrameA = TRUE; pErrorStats->ulH100FrameABadCnt++; } if ( (usReadData & 0x4000) != 0 ) { f_pIntFlags->fErrorH100ClkA = TRUE; pErrorStats->ulH100ClkABadCnt++; } if ( (usReadData & 0x8000) != 0 ) { if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) { f_pIntFlags->fErrorH100ClkB = TRUE; pErrorStats->ulH100ClkBBadCnt++; } } pIntrptManage->usRegister302h = usReadData; /*=======================================================================*/ } else { pIntrptManage->usRegister302h = 0x0; } /* TDMIE registers. */ if ( (f_ulRegister210h & 0x00010) != 0 ) { /*=======================================================================*/ /* Read register. */ ReadParams.ulReadAddress = 0x502; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check which interrupts were set. */ if ( (usReadData & 0x0002) != 0 ) { f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_3; f_pIntFlags->fFatalGeneral = TRUE; pErrorStats->fFatalChipError = TRUE; } pIntrptManage->usRegister502h = usReadData; /*=======================================================================*/ } else { pIntrptManage->usRegister502h = 0x0; } /* PGSP registers. */ if ( (f_ulRegister210h & 0x00080) != 0 ) { /*=======================================================================*/ /* Read register. */ ReadParams.ulReadAddress = 0x702; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check which interrupts were set. */ if ( (usReadData & 0x0002) != 0 ) { f_pIntFlags->fErrorOverflowToneEvents = TRUE; pErrorStats->ulOverflowToneEventsCnt++; } pIntrptManage->usRegister702h = usReadData; /*=======================================================================*/ } else { pIntrptManage->usRegister702h = 0x0; } /* If this is the first time the ISR is called, clear the ISR is not called bit */ /* in external memory to signal the remote client that we are called. */ if ( pSharedInfo->IntrptManage.fIsrCalled == FALSE ) { /* Remember that we are being called. */ pSharedInfo->IntrptManage.fIsrCalled = TRUE; if ( pSharedInfo->DebugInfo.fIsIsrCalledField == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.IsIsrCalledFieldOfst.byFieldSize; ulResult = Oct6100ApiReadDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, &ulTempData ); /* Read previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Clear the field. */ ulTempData &= (~ulMask); /* Write the DWORD where the field is located.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, cOCT6100_POUCH_BASE + ulFeatureBytesOffset, ulTempData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateIntrptStates Description: Updates the state of all interrupt register groups. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntFlags Interrupt flags. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateIntrptStates UINT32 Oct6100ApiUpdateIntrptStates( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ) { tPOCT6100_API_INTRPT_CONFIG pIntrptConfig; tPOCT6100_API_INTRPT_MANAGE pIntrptManage; pIntrptConfig = &f_pApiInstance->pSharedInfo->IntrptConfig; pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; /*-----------------------------------------------------------------------*/ if ( ( f_pIntFlags->fFatalReadTimeout == TRUE) && pIntrptConfig->byFatalMemoryConfig == cOCT6100_INTERRUPT_TIMEOUT && pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) { pIntrptManage->byFatalMemoryState = cOCT6100_INTRPT_WILL_TIMEOUT; pIntrptManage->ulFatalMemoryDisableMclkHigh = pIntrptManage->ulRegMclkTimeHigh; pIntrptManage->ulFatalMemoryDisableMclkLow = pIntrptManage->ulRegMclkTimeLow; } /*-----------------------------------------------------------------------*/ if ( (f_pIntFlags->fErrorRefreshTooLate == TRUE || f_pIntFlags->fErrorPllJitter == TRUE ) && pIntrptConfig->byErrorMemoryConfig == cOCT6100_INTERRUPT_TIMEOUT && pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_ACTIVE ) { pIntrptManage->byErrorMemoryState = cOCT6100_INTRPT_WILL_TIMEOUT; pIntrptManage->ulErrorMemoryDisableMclkHigh = pIntrptManage->ulRegMclkTimeHigh; pIntrptManage->ulErrorMemoryDisableMclkLow = pIntrptManage->ulRegMclkTimeLow; } /*-----------------------------------------------------------------------*/ if ( (f_pIntFlags->fErrorOverflowToneEvents == TRUE) && pIntrptConfig->byErrorOverflowToneEventsConfig == cOCT6100_INTERRUPT_TIMEOUT && pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_ACTIVE ) { pIntrptManage->byErrorOverflowToneEventsState = cOCT6100_INTRPT_WILL_TIMEOUT; pIntrptManage->ulErrorOverflowToneEventsDisableMclkHigh = pIntrptManage->ulRegMclkTimeHigh; pIntrptManage->ulErrorOverflowToneEventsDisableMclkLow = pIntrptManage->ulRegMclkTimeLow; } /*-----------------------------------------------------------------------*/ if ( (f_pIntFlags->fErrorH100OutOfSync == TRUE || f_pIntFlags->fErrorH100ClkA == TRUE || f_pIntFlags->fErrorH100ClkB == TRUE || f_pIntFlags->fErrorH100FrameA == TRUE ) && pIntrptConfig->byErrorH100Config == cOCT6100_INTERRUPT_TIMEOUT && pIntrptManage->byErrorH100State == cOCT6100_INTRPT_ACTIVE ) { pIntrptManage->byErrorH100State = cOCT6100_INTRPT_WILL_TIMEOUT; pIntrptManage->ulErrorH100DisableMclkHigh = pIntrptManage->ulRegMclkTimeHigh; pIntrptManage->ulErrorH100DisableMclkLow = pIntrptManage->ulRegMclkTimeLow; } /*-----------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteIntrptRegs Description: Writes to interrupt registers to clear interrupt condition, and writes to an interrupt's IE register if interrupt is to time out. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteIntrptRegs UINT32 Oct6100ApiWriteIntrptRegs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Get some local pointers. */ pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*===========================================================================*/ if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_WILL_TIMEOUT ) { WriteParams.ulWriteAddress = 0x104; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( (pIntrptManage->usRegister102h & cOCT6100_INTRPT_MASK_REG_102H) != 0 ) { WriteParams.ulWriteAddress = 0x102; WriteParams.usWriteData = pIntrptManage->usRegister102h; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*===========================================================================*/ /*===========================================================================*/ if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_WILL_TIMEOUT || pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_WILL_TIMEOUT ) { WriteParams.ulWriteAddress = 0x204; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x1800; if ( pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0401; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( (pIntrptManage->usRegister202h & cOCT6100_INTRPT_MASK_REG_202H) != 0 ) { WriteParams.ulWriteAddress = 0x202; WriteParams.usWriteData = pIntrptManage->usRegister202h; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*===========================================================================*/ /*===========================================================================*/ if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_WILL_TIMEOUT ) { WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->fMclkIntrptActive == TRUE ) WriteParams.usWriteData |= 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( (pIntrptManage->usRegister302h & cOCT6100_INTRPT_MASK_REG_302H) != 0 ) { WriteParams.ulWriteAddress = 0x302; WriteParams.usWriteData = pIntrptManage->usRegister302h; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*===========================================================================*/ /*===========================================================================*/ if ( (pIntrptManage->usRegister502h & cOCT6100_INTRPT_MASK_REG_502H) != 0 ) { WriteParams.ulWriteAddress = 0x502; WriteParams.usWriteData = pIntrptManage->usRegister502h; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*===========================================================================*/ /*===========================================================================*/ if ( pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_WILL_TIMEOUT ) { WriteParams.ulWriteAddress = 0x704; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( (pIntrptManage->usRegister702h & cOCT6100_INTRPT_MASK_REG_702H) != 0 ) { WriteParams.ulWriteAddress = 0x702; WriteParams.usWriteData = pIntrptManage->usRegister702h; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*===========================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteIeRegs Description: Writes the IE field of each interrupt register. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteIeRegs UINT32 Oct6100ApiWriteIeRegs( tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; /* Get some local pointers. */ pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Set some parameters of read struct. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*==================================================================================*/ WriteParams.ulWriteAddress = 0x104; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /*==================================================================================*/ WriteParams.ulWriteAddress = 0x204; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x1800; if ( pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0401; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /*==================================================================================*/ WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->fMclkIntrptActive == TRUE ) WriteParams.usWriteData |= 0x0001; if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_ACTIVE ) { if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) WriteParams.usWriteData |= 0xD100; else WriteParams.usWriteData |= 0x5100; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /*==================================================================================*/ WriteParams.ulWriteAddress = 0x504; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalGeneralState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /*==================================================================================*/ WriteParams.ulWriteAddress = 0x704; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ /*==================================================================================*/ /* Enable the GLOBAL IEs for the interrupt pin. */ WriteParams.ulWriteAddress = 0x218; WriteParams.usWriteData = 0x00D7; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReadChipMclkTime Description: Reads the chip's mclk cycle count to construct a chip time. The time is used to manage interrupts. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReadChipMclkTime UINT32 Oct6100ApiReadChipMclkTime( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; UINT32 ulCheckData; UINT32 ulResult; UINT32 i; UINT16 usReadData; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; pIntrptManage = &pSharedInfo->IntrptManage; /* Assign memory for read data. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Perform reads. */ for ( i = 0; i < 100; i++ ) { ReadParams.ulReadAddress = 0x306; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pIntrptManage->ulRegMclkTimeHigh = usReadData & 0xFF; ulCheckData = usReadData; ReadParams.ulReadAddress = 0x308; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pIntrptManage->ulRegMclkTimeLow = (usReadData & 0xFFFF) << 16; ReadParams.ulReadAddress = 0x306; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( ulCheckData == usReadData ) break; } if ( i == 100 ) return cOCT6100_ERR_FATAL_2F; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateIntrptTimeouts Description: Checks which interrupt groups have finished their timeout period. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateIntrptTimeouts UINT32 Oct6100ApiUpdateIntrptTimeouts( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulRegMclkTimePlus5MsHigh; UINT32 ulRegMclkTimePlus5MsLow; UINT32 ulResult; BOOL fFatalMemoryChange = FALSE; BOOL fDataErrMemoryChange = FALSE; BOOL fErrorOverflowToneEventsChange = FALSE; BOOL fH100ErrorChange = FALSE; /* Get local pointer to interrupt management structure. */ pIntrptManage = &f_pApiInstance->pSharedInfo->IntrptManage; /* Calculate mclk time + 5 ms. */ ulRegMclkTimePlus5MsLow = pIntrptManage->ulRegMclkTimeLow + (5 * pIntrptManage->ulNumMclkCyclesIn1Ms); if ( ulRegMclkTimePlus5MsLow < pIntrptManage->ulRegMclkTimeLow ) ulRegMclkTimePlus5MsHigh = pIntrptManage->ulRegMclkTimeHigh + 1; else /* ( ulRegMclkTimePlus5MsLow >= pIntrptManage->ulRegMclkTimeLow ) */ ulRegMclkTimePlus5MsHigh = pIntrptManage->ulRegMclkTimeHigh; /* Check which interrupts are timed out and need to be reenabled now. */ if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_IN_TIMEOUT ) { mOCT6100_CHECK_INTRPT_TIMEOUT( ulRegMclkTimePlus5MsHigh, ulRegMclkTimePlus5MsLow, pIntrptManage->ulFatalMemoryDisableMclkHigh, pIntrptManage->ulFatalMemoryDisableMclkLow, pIntrptManage->ulFatalMemoryEnableMclkHigh, pIntrptManage->ulFatalMemoryEnableMclkLow, pIntrptManage->byFatalMemoryState, fFatalMemoryChange ) } if ( pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_IN_TIMEOUT ) { mOCT6100_CHECK_INTRPT_TIMEOUT( ulRegMclkTimePlus5MsHigh, ulRegMclkTimePlus5MsLow, pIntrptManage->ulErrorMemoryDisableMclkHigh, pIntrptManage->ulErrorMemoryDisableMclkLow, pIntrptManage->ulErrorMemoryEnableMclkHigh, pIntrptManage->ulErrorMemoryEnableMclkLow, pIntrptManage->byErrorMemoryState, fDataErrMemoryChange ) } if ( pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_IN_TIMEOUT ) { mOCT6100_CHECK_INTRPT_TIMEOUT( ulRegMclkTimePlus5MsHigh, ulRegMclkTimePlus5MsLow, pIntrptManage->ulErrorOverflowToneEventsDisableMclkHigh, pIntrptManage->ulErrorOverflowToneEventsDisableMclkLow, pIntrptManage->ulErrorOverflowToneEventsEnableMclkHigh, pIntrptManage->ulErrorOverflowToneEventsEnableMclkLow, pIntrptManage->byErrorOverflowToneEventsState, fErrorOverflowToneEventsChange ) } if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_IN_TIMEOUT ) { mOCT6100_CHECK_INTRPT_TIMEOUT( ulRegMclkTimePlus5MsHigh, ulRegMclkTimePlus5MsLow, pIntrptManage->ulErrorH100DisableMclkHigh, pIntrptManage->ulErrorH100DisableMclkLow, pIntrptManage->ulErrorH100EnableMclkHigh, pIntrptManage->ulErrorH100EnableMclkLow, pIntrptManage->byErrorH100State, fH100ErrorChange ) } /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Write to the IE registers which have changed. */ /*==================================================================================*/ if ( fFatalMemoryChange == TRUE ) { WriteParams.ulWriteAddress = 0x104; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0001; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==================================================================================*/ /*==================================================================================*/ if ( fFatalMemoryChange == TRUE || fDataErrMemoryChange == TRUE ) { WriteParams.ulWriteAddress = 0x204; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byFatalMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x1800; if ( pIntrptManage->byErrorMemoryState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0401; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==================================================================================*/ /*==================================================================================*/ if ( pIntrptManage->fMclkIntrptActive == TRUE || fH100ErrorChange == TRUE ) { WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->fMclkIntrptActive == TRUE ) WriteParams.usWriteData |= 0x0001; if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_ACTIVE ) { if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) WriteParams.usWriteData |= 0xD100; else WriteParams.usWriteData |= 0x5100; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==================================================================================*/ /*==================================================================================*/ if ( fErrorOverflowToneEventsChange == TRUE ) { WriteParams.ulWriteAddress = 0x704; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byErrorOverflowToneEventsState == cOCT6100_INTRPT_ACTIVE ) WriteParams.usWriteData |= 0x0002; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiScheduleNextMclkIntrptSer Description: Serialized sub-function of Oct6100ApiScheduleNextMclkIntrpt. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiScheduleNextMclkIntrptSer UINT32 Oct6100ApiScheduleNextMclkIntrptSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_INTRPT_CONFIG pIntrptConfig; tPOCT6100_API_INTRPT_MANAGE pIntrptManage; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulTimeDiff; UINT32 ulRegMclkTimeHigh; UINT32 ulRegMclkTimeLow; UINT32 ulResult; BOOL fConditionFlag = TRUE; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain temporary pointers to reduce indirection, thus speeding up processing. */ pIntrptConfig = &pSharedInfo->IntrptConfig; pIntrptManage = &pSharedInfo->IntrptManage; ulRegMclkTimeHigh = pIntrptManage->ulRegMclkTimeHigh; ulRegMclkTimeLow = pIntrptManage->ulRegMclkTimeLow; /* First, check if any interrupts have just been disabled. If there are any, */ /* determine the time at which they should be reenabled. */ pIntrptManage->ulNextMclkIntrptTimeHigh = cOCT6100_INVALID_VALUE; pIntrptManage->ulNextMclkIntrptTimeLow = cOCT6100_INVALID_VALUE; while ( fConditionFlag ) { /* Indicate that no mclk interrupt is needed, yet. */ ulTimeDiff = cOCT6100_INVALID_VALUE; /* Check each interrupt category to see if an mclk interrupt is needed to */ /* reenable an interrupt at a later time. */ if ( pIntrptManage->byFatalMemoryState != cOCT6100_INTRPT_ACTIVE && pIntrptManage->byFatalMemoryState != cOCT6100_INTRPT_DISABLED ) { mOCT6100_GET_INTRPT_ENABLE_TIME( ulRegMclkTimeHigh, ulRegMclkTimeLow, pIntrptManage->byFatalMemoryState, pIntrptManage->ulFatalMemoryEnableMclkHigh, pIntrptManage->ulFatalMemoryEnableMclkLow, pIntrptConfig->ulFatalMemoryTimeoutMclk, ulTimeDiff ) } if ( pIntrptManage->byErrorMemoryState != cOCT6100_INTRPT_ACTIVE && pIntrptManage->byErrorMemoryState != cOCT6100_INTRPT_DISABLED ) { mOCT6100_GET_INTRPT_ENABLE_TIME( ulRegMclkTimeHigh, ulRegMclkTimeLow, pIntrptManage->byErrorMemoryState, pIntrptManage->ulErrorMemoryEnableMclkHigh, pIntrptManage->ulErrorMemoryEnableMclkLow, pIntrptConfig->ulErrorMemoryTimeoutMclk, ulTimeDiff ) } if ( pIntrptManage->byErrorOverflowToneEventsState != cOCT6100_INTRPT_ACTIVE && pIntrptManage->byErrorOverflowToneEventsState != cOCT6100_INTRPT_DISABLED ) { mOCT6100_GET_INTRPT_ENABLE_TIME( ulRegMclkTimeHigh, ulRegMclkTimeLow, pIntrptManage->byErrorOverflowToneEventsState, pIntrptManage->ulErrorOverflowToneEventsEnableMclkHigh, pIntrptManage->ulErrorOverflowToneEventsEnableMclkLow, pIntrptConfig->ulErrorOverflowToneEventsTimeoutMclk, ulTimeDiff ) } if ( pIntrptManage->byErrorH100State != cOCT6100_INTRPT_ACTIVE && pIntrptManage->byErrorH100State != cOCT6100_INTRPT_DISABLED ) { mOCT6100_GET_INTRPT_ENABLE_TIME( ulRegMclkTimeHigh, ulRegMclkTimeLow, pIntrptManage->byErrorH100State, pIntrptManage->ulErrorH100EnableMclkHigh, pIntrptManage->ulErrorH100EnableMclkLow, pIntrptConfig->ulErrorH100TimeoutMclk, ulTimeDiff ) } /* Set some parameters of write struct. */ WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /* Schedule next mclk interrupt, if any is needed. */ if ( ulTimeDiff != cOCT6100_INVALID_VALUE ) { UINT32 ulMclkTimeTest; UINT32 ulAlarmTimeTest; UINT32 ulTimeDiffTest; BOOL fAlarmTimePassed; /* Indicate that an mclk interrupt is scheduled.*/ pIntrptManage->fMclkIntrptActive = TRUE; pIntrptManage->ulNextMclkIntrptTimeLow = ulRegMclkTimeLow + ulTimeDiff; if ( pIntrptManage->ulNextMclkIntrptTimeLow < ulRegMclkTimeLow ) pIntrptManage->ulNextMclkIntrptTimeHigh = ulRegMclkTimeHigh + 1; else /* ( pIntrptManage->ulNextMclkIntrptTimeLow >= ulRegMclkTimeLow ) */ pIntrptManage->ulNextMclkIntrptTimeHigh = ulRegMclkTimeHigh; WriteParams.ulWriteAddress = 0x30C; WriteParams.usWriteData = (UINT16)( (pIntrptManage->ulNextMclkIntrptTimeLow >> 24) & 0xFF ); WriteParams.usWriteData |= (UINT16)( (pIntrptManage->ulNextMclkIntrptTimeHigh & 0xFF) << 8 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x30E; WriteParams.usWriteData = (UINT16)( (pIntrptManage->ulNextMclkIntrptTimeLow >> 8) & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0; if ( pIntrptManage->fMclkIntrptActive == TRUE ) WriteParams.usWriteData = 0x0001; if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_ACTIVE ) { if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) WriteParams.usWriteData |= 0xD100; else WriteParams.usWriteData |= 0x5100; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Disable the ROL if previously set. */ WriteParams.ulWriteAddress = 0x302; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if already passed the next interrupt time. */ ulResult = Oct6100ApiReadChipMclkTime( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulMclkTimeTest = (pIntrptManage->ulRegMclkTimeLow >> 16) & 0xFFFF; ulAlarmTimeTest = (pIntrptManage->ulNextMclkIntrptTimeLow >> 16) & 0xFFFF; /* Update the local Mlck timer values.*/ ulRegMclkTimeHigh = pIntrptManage->ulRegMclkTimeHigh; ulRegMclkTimeLow = pIntrptManage->ulRegMclkTimeLow; fAlarmTimePassed = FALSE; if ( ulMclkTimeTest > ulAlarmTimeTest ) { ulTimeDiffTest = ulMclkTimeTest - ulAlarmTimeTest; if ( ulTimeDiffTest <= 0x8000 ) fAlarmTimePassed = TRUE; } else /* ( ulMclkTimeTest <= ulAlarmTimeTest ) */ { ulTimeDiffTest = ulAlarmTimeTest - ulMclkTimeTest; if ( ulTimeDiffTest > 0x8000 ) fAlarmTimePassed = TRUE; } if ( fAlarmTimePassed == TRUE ) { /* Passed the interrupt time. Schedule next interrupt (if needed). */ ulResult = Oct6100ApiUpdateIntrptTimeouts( f_pApiInstance ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; continue; } else { fConditionFlag = FALSE; } } else { /* Indicate that no mclk interrupt is scheduled. */ pIntrptManage->fMclkIntrptActive = FALSE; /* Insure that the mclk interrupt is not enabled. */ WriteParams.ulWriteAddress = 0x304; WriteParams.usWriteData = 0x0000; if ( pIntrptManage->byErrorH100State == cOCT6100_INTRPT_ACTIVE ) { if ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableFastH100Mode == TRUE ) WriteParams.usWriteData |= 0xD100; else WriteParams.usWriteData |= 0x5100; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; fConditionFlag = FALSE; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckProcessorState Description: This function verifies if the NLP and AF processors are operating correctly. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pIntFlags Pointer to a tOCT6100_INTERRUPT_FLAGS structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckProcessorState UINT32 Oct6100ApiCheckProcessorState( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_INTERRUPT_FLAGS f_pIntFlags ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; tOCT6100_READ_BURST_PARAMS ReadBurstParams; UINT32 ulNlpTimestamp; UINT32 ulAfTimestamp; UINT32 ulTimestampDiff; UINT32 ulResult; UINT32 i; UINT16 usReadData; UINT16 ausReadData[ 2 ]; UINT32 aulWaitTime[ 2 ]; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Set some parameters of write struct. */ ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Set some parameters of write struct. */ ReadBurstParams.pProcessContext = f_pApiInstance->pProcessContext; ReadBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadBurstParams.pusReadData = ausReadData; /*-----------------------------------------------------------------------*/ /* Check if chip is in reset. */ /* Read the main control register. */ ReadParams.ulReadAddress = 0x100; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData == 0x0000 ) { /* Chip was resetted. */ f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_4; f_pIntFlags->fFatalGeneral = TRUE; pSharedInfo->ErrorStats.fFatalChipError = TRUE; } /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Reading the AF timestamp.*/ for ( i = 0; i < cOCT6100_MAX_LOOP; i++ ) { /* Read the timestamp.*/ ReadBurstParams.ulReadAddress = 0x082E0008; ReadBurstParams.ulReadLength = 2; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read the high part again to make sure it didn't wrap. */ ReadParams.ulReadAddress = 0x082E0008; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the low part wrapped. */ if ( ausReadData[ 0 ] == usReadData ) break; } if ( i == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_INTRPTS_AF_TIMESTAMP_READ_TIMEOUT; /* Save the AF timestamp. */ ulAfTimestamp = (ausReadData[ 0 ] << 16) | ausReadData[ 1 ]; /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Reading the NLP timestamp. */ for ( i = 0; i < cOCT6100_MAX_LOOP; i++ ) { /* Read the timestamp. */ ReadBurstParams.ulReadAddress = 0x08000008; ReadBurstParams.ulReadLength = 2; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read the high part again to make sure it didn't wrap. */ ReadParams.ulReadAddress = 0x08000008; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the low part wrapped. */ if ( ausReadData[ 0 ] == usReadData ) break; } if ( i == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_INTRPTS_NLP_TIMESTAMP_READ_TIMEOUT; /* Save the NLP timestamp. */ ulNlpTimestamp = (ausReadData[ 0 ] << 16) | ausReadData[ 1 ]; /*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Check the validity of the timestamp. */ if ( ulAfTimestamp > ulNlpTimestamp ) { /* The NLP timestamp wrapped. */ ulTimestampDiff = 0xFFFFFFFF - ulAfTimestamp + 1; ulTimestampDiff += ulNlpTimestamp; } else ulTimestampDiff = ulNlpTimestamp - ulAfTimestamp; if ( ulTimestampDiff > 0x2000 ) { f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_5; f_pIntFlags->fFatalGeneral = TRUE; pSharedInfo->ErrorStats.fFatalChipError = TRUE; } /*Check if AF and NLP are both stuck*/ if ( f_pIntFlags->fErrorH100ClkA == FALSE && f_pIntFlags->fErrorH100ClkB == FALSE && f_pIntFlags->fErrorH100FrameA == FALSE && f_pIntFlags->fErrorH100OutOfSync == FALSE ) { if ( ulAfTimestamp == 0 && ulNlpTimestamp == 0 ) { /*Give some time to the counters*/ aulWaitTime[ 0 ] = 250; aulWaitTime[ 1 ] = 0; ulResult = Oct6100ApiWaitForTime( f_pApiInstance, aulWaitTime ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*Let's read again the AF timestamp to be sure. Maybe they were at 0 at the same time*/ ReadBurstParams.ulReadAddress = 0x082E0008; ReadBurstParams.ulReadLength = 2; mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulAfTimestamp = (ausReadData[ 0 ] << 16) | ausReadData[ 1 ]; if ( ulAfTimestamp == 0 ) { /*TDM Clocks are ok but NLP and AF timestamps are both at 0*/ f_pIntFlags->ulFatalGeneralFlags |= cOCT6100_FATAL_GENERAL_ERROR_TYPE_9; f_pIntFlags->fFatalGeneral = TRUE; pSharedInfo->ErrorStats.fFatalChipError = TRUE; } } } /*-----------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_tlv.c0000644000175000017500000021344111525010337030245 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_tlv.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains the functions used to read information allowing the API to know where all the features supported by this API version are located in the chip's external memory. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 113 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_tlv_priv.h" /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiProcessTlvRegion Description: This function will read and interpret the TLV memory of the chip to obtain memory offsets and features available of the image loaded into the chip. The API will read this region until it finds a TLV type of 0 with a length of 0. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiProcessTlvRegion UINT32 Oct6100ApiProcessTlvRegion( tPOCT6100_INSTANCE_API f_pApiInstance ) { tOCT6100_READ_PARAMS ReadParams; UINT16 usReadData; UINT32 ulResult; UINT32 ulTlvTypeField; UINT32 ulTlvLengthField; UINT32 ulTlvWritingTimeoutCount = 0; UINT32 ulConditionFlag = TRUE; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Set the address of the first TLV type. */ ReadParams.ulReadAddress = cOCT6100_TLV_BASE; ReadParams.ulReadAddress += 2; /* Wait for the TLV configuration to be configured in memory. */ while ( ulConditionFlag ) { /* Read the TLV write done flag. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( usReadData & 0x1 ) break; ulTlvWritingTimeoutCount++; if ( ulTlvWritingTimeoutCount == 0x100000 ) return cOCT6100_ERR_TLV_TIMEOUT; } /*======================================================================*/ /* Read the first 16 bits of the TLV type. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvTypeField = usReadData << 16; /* Read the last word of the TLV type. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvTypeField |= usReadData; /*======================================================================*/ /*======================================================================*/ /* Now, read the TLV field length. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvLengthField = usReadData << 16; /* Read the last word of the TLV length. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvLengthField |= usReadData; /* Modify the address to point at the TLV value field. */ ReadParams.ulReadAddress += 2; /*======================================================================*/ /* Read the TLV value until the end of TLV region is reached. */ while( !((ulTlvTypeField == 0) && (ulTlvLengthField == 0)) ) { ulResult = Oct6100ApiInterpretTlvEntry( f_pApiInstance, ulTlvTypeField, ulTlvLengthField, ReadParams.ulReadAddress ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the address to after the TLV value. */ ReadParams.ulReadAddress += ulTlvLengthField; /*======================================================================*/ /* Read the first 16 bits of the TLV type. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvTypeField = usReadData << 16; /* Read the last word of the TLV type. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvTypeField |= usReadData; /*======================================================================*/ /*======================================================================*/ /* Now, read the TLV field length. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvLengthField = usReadData << 16; /* Read the last word of the TLV length. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulTlvLengthField |= usReadData; ReadParams.ulReadAddress += 2; /*======================================================================*/ } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInterpretTlvEntry Description: This function will interpret a TLV entry from the chip. All known TLV types by the API are exhaustively listed here. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulTlvFieldType Type of the TLV field to interpret. f_ulTlvFieldLength Byte length of the TLV field. f_ulTlvValueAddress Address where the data of the TLV block starts. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInterpretTlvEntry UINT32 Oct6100ApiInterpretTlvEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulTlvFieldType, IN UINT32 f_ulTlvFieldLength, IN UINT32 f_ulTlvValueAddress ) { tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult = cOCT6100_ERR_OK; UINT16 usReadData; UINT32 i; UINT32 ulTempValue = 0; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Find out how to interpret the TLV value according to the TLV type. */ switch( f_ulTlvFieldType ) { case cOCT6100_TLV_TYPE_VERSION_NUMBER: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_VERSION_NUMBER, cOCT6100_TLV_MAX_LENGTH_VERSION_NUMBER ); if ( ulResult == cOCT6100_ERR_OK ) { ReadParams.ulReadAddress = f_ulTlvValueAddress; for( i = 0; i < (f_ulTlvFieldLength/2); i++ ) { /* Perform the actual read. */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pApiInstance->pSharedInfo->ImageInfo.szVersionNumber[ (i * 2) ] = (UINT8)((usReadData >> 8) & 0xFF); f_pApiInstance->pSharedInfo->ImageInfo.szVersionNumber[ (i * 2) + 1 ] = (UINT8)((usReadData >> 0) & 0xFF); /* Modify the address. */ ReadParams.ulReadAddress += 2; } } break; case cOCT6100_TLV_TYPE_CUSTOMER_PROJECT_ID: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CUSTOMER_PROJECT_ID, cOCT6100_TLV_MAX_LENGTH_CUSTOMER_PROJECT_ID ); if ( ulResult == cOCT6100_ERR_OK ) { /* Perform the actual read. */ ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->ImageInfo.ulBuildId ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH0_MAIN_BASE_ADDRESS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH0_MAIN_BASE_ADDRESS, cOCT6100_TLV_MAX_LENGTH_CH0_MAIN_BASE_ADDRESS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase &= 0x0FFFFFFF; /* Modify the base address to incorporate the external memory offset. */ f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase += cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; } break; case cOCT6100_TLV_TYPE_CH_MAIN_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_SIZE, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_IO_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_IO_OFFSET, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_IO_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_ZCB_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_ZCB_OFFSET, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_ZCB_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainRinCBMemOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_ZCB_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_ZCB_SIZE, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_ZCB_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainRinCBMemSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_XCB_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_XCB_OFFSET, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_XCB_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSinCBMemOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_XCB_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_XCB_SIZE, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_XCB_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSinCBMemSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_YCB_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_YCB_OFFSET, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_YCB_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSoutCBMemOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_MAIN_YCB_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_MAIN_YCB_SIZE, cOCT6100_TLV_MAX_LENGTH_CH_MAIN_YCB_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSoutCBMemSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_FREE_MEM_BASE_ADDRESS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_FREE_MEM_BASE_ADDRESS, cOCT6100_TLV_MAX_LENGTH_FREE_MEM_BASE_ADDRESS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulFreeMemBaseAddress ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; f_pApiInstance->pSharedInfo->MemoryMap.ulFreeMemBaseAddress &= 0x0FFFFFFF; } break; case cOCT6100_TLV_TYPE_CHAN_MAIN_IO_STATS_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CHAN_MAIN_IO_STATS_OFFSET, cOCT6100_TLV_MAX_LENGTH_CHAN_MAIN_IO_STATS_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoStatsOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CHAN_MAIN_IO_STATS_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CHAN_MAIN_IO_STATS_OFFSET, cOCT6100_TLV_MAX_LENGTH_CHAN_MAIN_IO_STATS_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoStatsSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_CH_ROOT_CONF_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CH_ROOT_CONF_OFFSET, cOCT6100_TLV_MAX_LENGTH_CH_ROOT_CONF_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanRootConfOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_POA_CH_MAIN_ZPO_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_ZPO_OFFSET, cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_ZPO_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemOfst ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_POA_CH_MAIN_ZPO_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_ZPO_SIZE, cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_ZPO_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainRinPlayoutMemSize ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; case cOCT6100_TLV_TYPE_POA_CH_MAIN_YPO_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_YPO_OFFSET, cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_YPO_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemOfst ); } break; case cOCT6100_TLV_TYPE_POA_CH_MAIN_YPO_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_CH_MAIN_YPO_SIZE, cOCT6100_TLV_MAX_LENGTH_POA_CH_MAIN_YPO_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainSoutPlayoutMemSize ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_ZWP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZWP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZWP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_ZIS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZIS, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZIS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutRinIgnoreSkipCleanOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_ZSP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_ZSP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_ZSP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutRinSkipPtrOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_YWP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YWP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YWP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_YIS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YIS, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YIS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutSoutIgnoreSkipCleanOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RW_YSP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RW_YSP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RW_YSP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutSoutSkipPtrOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RO_ZRP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RO_ZRP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RO_ZRP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst ); } break; case cOCT6100_TLV_TYPE_POA_BOFF_RO_YRP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POA_BOFF_RO_YRP, cOCT6100_TLV_MAX_LENGTH_POA_BOFF_RO_YRP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst ); } break; case cOCT6100_TLV_TYPE_CNR_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CNR_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_CNR_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ConferencingNoiseReductionOfst ); } break; case cOCT6100_TLV_TYPE_ANR_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ANR_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_ANR_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AdaptiveNoiseReductionOfst ); } break; case cOCT6100_TLV_TYPE_HZ_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_HZ_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_HZ_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinDcOffsetRemovalOfst ); } /* Set flag indicating that the feature is present.*/ f_pApiInstance->pSharedInfo->ImageInfo.fRinDcOffsetRemoval = TRUE; break; case cOCT6100_TLV_TYPE_HX_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_HX_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_HX_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SinDcOffsetRemovalOfst ); } /* Set flag indicating that the feature is present.*/ f_pApiInstance->pSharedInfo->ImageInfo.fSinDcOffsetRemoval = TRUE; break; case cOCT6100_TLV_TYPE_LCA_Z_CONF_BOFF_RW_GAIN: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_LCA_Z_CONF_BOFF_RW_GAIN, cOCT6100_TLV_MAX_LENGTH_LCA_Z_CONF_BOFF_RW_GAIN ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinLevelControlOfst ); } break; case cOCT6100_TLV_TYPE_LCA_Y_CONF_BOFF_RW_GAIN: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_LCA_Y_CONF_BOFF_RW_GAIN, cOCT6100_TLV_MAX_LENGTH_LCA_Y_CONF_BOFF_RW_GAIN ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SoutLevelControlOfst ); } break; case cOCT6100_TLV_TYPE_CNA_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CNA_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_CNA_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ComfortNoiseModeOfst ); } /* Set flag indicating that the feature is present.*/ f_pApiInstance->pSharedInfo->ImageInfo.fComfortNoise = TRUE; break; case cOCT6100_TLV_TYPE_NOA_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_NOA_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_NOA_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.NlpControlFieldOfst ); } /* Set flag indicating that the feature is present.*/ f_pApiInstance->pSharedInfo->ImageInfo.fNlpControl = TRUE; break; case cOCT6100_TLV_TYPE_VFA_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_VFA_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_VFA_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.VadControlFieldOfst ); } /* Set flag indicating that the feature is present.*/ f_pApiInstance->pSharedInfo->ImageInfo.fSilenceSuppression = TRUE; break; case cOCT6100_TLV_TYPE_TLA_MAIN_IO_BOFF_RW_TAIL_DISP: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TLA_MAIN_IO_BOFF_RW_TAIL_DISP, cOCT6100_TLV_MAX_LENGTH_TLA_MAIN_IO_BOFF_RW_TAIL_DISP ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PouchTailDisplOfst ); } break; case cOCT6100_TLV_TYPE_BOOTA_POUCH_BOFF_RW_BOOT_INST: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_INST, cOCT6100_TLV_MAX_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_INST ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PouchBootInstructionOfst ); } break; case cOCT6100_TLV_TYPE_BOOTA_POUCH_BOFF_RW_BOOT_RESULT: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_RESULT, cOCT6100_TLV_MAX_LENGTH_BOOTA_POUCH_BOFF_RW_BOOT_RESULT ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PouchBootResultOfst ); } break; case cOCT6100_TLV_TYPE_TDM_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TDM_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_TDM_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ToneDisablerControlOfst ); } f_pApiInstance->pSharedInfo->ImageInfo.fToneDisabler = TRUE; break; case cOCT6100_TLV_TYPE_DIS_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DIS_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_DIS_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.TailDisplEnableOfst ); } f_pApiInstance->pSharedInfo->ImageInfo.fTailDisplacement = TRUE; break; case cOCT6100_TLV_TYPE_NT_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_NT_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_NT_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.NlpTrivialFieldOfst ); } break; case cOCT6100_TLV_TYPE_DEBUG_CHAN_INDEX_VALUE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_INDEX_VALUE, cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_INDEX_VALUE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); } f_pApiInstance->pSharedInfo->DebugInfo.usRecordMemIndex = (UINT16)( ulTempValue & 0xFFFF ); break; case cOCT6100_TLV_TYPE_ADPCM_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ADPCM_ENABLE, cOCT6100_TLV_MAX_LENGTH_ADPCM_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); } if ( ulTempValue == 0 ) f_pApiInstance->pSharedInfo->ImageInfo.fAdpcm = FALSE; else f_pApiInstance->pSharedInfo->ImageInfo.fAdpcm = TRUE; break; case cOCT6100_TLV_TYPE_CONFERENCING_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CONFERENCING_ENABLE, cOCT6100_TLV_MAX_LENGTH_CONFERENCING_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); } if ( ulTempValue == 0 ) f_pApiInstance->pSharedInfo->ImageInfo.fConferencing = FALSE; else f_pApiInstance->pSharedInfo->ImageInfo.fConferencing = TRUE; break; case cOCT6100_TLV_TYPE_TONE_DETECTOR_PROFILE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TONE_DETECTOR_PROFILE, cOCT6100_TLV_MIN_LENGTH_TONE_DETECTOR_PROFILE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->ImageInfo.ulToneProfileNumber ); } break; case cOCT6100_TLV_TYPE_MAX_TAIL_DISPLACEMENT: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MAX_TAIL_DISPLACEMENT, cOCT6100_TLV_MAX_LENGTH_MAX_TAIL_DISPLACEMENT ); if ( ulResult == cOCT6100_ERR_OK ) { UINT32 ulTailDispTempValue; ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTailDispTempValue ); ulTailDispTempValue += 1; /* Convert the value into milliseconds.*/ ulTailDispTempValue *= 16; /* value was given in multiple of 16 ms. */ if ( ulTailDispTempValue >= 128 ) f_pApiInstance->pSharedInfo->ImageInfo.usMaxTailDisplacement = (UINT16)( ulTailDispTempValue - 128 ); else f_pApiInstance->pSharedInfo->ImageInfo.usMaxTailDisplacement = 0; } break; case cOCT6100_TLV_TYPE_AEC_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AEC_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_AEC_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AecFieldOfst ); } /* Set the flag. */ f_pApiInstance->pSharedInfo->ImageInfo.fAecEnabled = TRUE; /* Acoustic echo cancellation available! */ f_pApiInstance->pSharedInfo->ImageInfo.fAcousticEcho = TRUE; break; case cOCT6100_TLV_TYPE_PCM_LEAK_CONF_BOFF_RW: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_PCM_LEAK_CONF_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_PCM_LEAK_CONF_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PcmLeakFieldOfst ); } f_pApiInstance->pSharedInfo->ImageInfo.fNonLinearityBehaviorA = TRUE; break; case cOCT6100_TLV_TYPE_DEFAULT_ERL_CONF_BOFF_RW: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DEFAULT_ERL_CONF_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_DEFAULT_ERL_CONF_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.DefaultErlFieldOfst ); } /* Set the flag. */ f_pApiInstance->pSharedInfo->ImageInfo.fDefaultErl = TRUE; break; case cOCT6100_TLV_TYPE_TONE_REM_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TONE_REM_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_TONE_REM_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ToneRemovalFieldOfst ); } /* Set the flag. */ f_pApiInstance->pSharedInfo->ImageInfo.fToneRemoval = TRUE; break; case cOCT6100_TLV_TYPE_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT, cOCT6100_TLV_MAX_LENGTH_TLA_MAIN_IO_BOFF_RW_MAX_ECHO_POINT ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ChanMainIoMaxEchoPointOfst ); } /* Set the flag. */ f_pApiInstance->pSharedInfo->ImageInfo.fMaxEchoPoint = TRUE; break; case cOCT6100_TLV_TYPE_NLP_CONV_CAP_CONF_BOFF_RW: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_NLP_CONV_CAP_CONF_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_NLP_CONV_CAP_CONF_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.NlpConvCapFieldOfst ); } /* Set the flag. */ f_pApiInstance->pSharedInfo->ImageInfo.fNonLinearityBehaviorB = TRUE; break; case cOCT6100_TLV_TYPE_MATRIX_EVENT_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MATRIX_EVENT_SIZE, cOCT6100_TLV_MAX_LENGTH_MATRIX_EVENT_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulDebugEventSize ); } break; case cOCT6100_TLV_TYPE_CNR_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CNR_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_CNR_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fConferencingNoiseReduction = (UINT8)( ulTempValue & 0xFF ); if ( f_pApiInstance->pSharedInfo->ImageInfo.fConferencingNoiseReduction == TRUE ) { /* Set flag indicating that the dominant speaker feature is present. */ f_pApiInstance->pSharedInfo->ImageInfo.fDominantSpeakerEnabled = TRUE; } } break; case cOCT6100_TLV_TYPE_MAX_TAIL_LENGTH_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MAX_TAIL_LENGTH_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_MAX_TAIL_LENGTH_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.usMaxTailLength = (UINT16)( ulTempValue & 0xFFFF ); } break; case cOCT6100_TLV_TYPE_MAX_NUMBER_OF_CHANNELS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MAX_NUMBER_OF_CHANNELS, cOCT6100_TLV_MAX_LENGTH_MAX_NUMBER_OF_CHANNELS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.usMaxNumberOfChannels = (UINT16)( ulTempValue & 0xFFFF ); } break; case cOCT6100_TLV_TYPE_PLAYOUT_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_PLAYOUT_ENABLE, cOCT6100_TLV_MAX_LENGTH_PLAYOUT_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { /* Set flag indicating that the feature is present. */ ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fBufferPlayout = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_DOMINANT_SPEAKER_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DOMINANT_SPEAKER_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_DOMINANT_SPEAKER_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst ); } break; case cOCT6100_TLV_TYPE_TAIL_DISP_CONF_BOFF_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TAIL_DISP_CONF_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_TAIL_DISP_CONF_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PerChanTailDisplacementFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fPerChannelTailDisplacement = TRUE; } break; case cOCT6100_TLV_TYPE_ANR_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ANR_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_ANR_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fAdaptiveNoiseReduction = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_MUSIC_PROTECTION_RW_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MUSIC_PROTECTION_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_MUSIC_PROTECTION_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fMusicProtection = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_AEC_DEFAULT_ERL_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AEC_DEFAULT_ERL_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_AEC_DEFAULT_ERL_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AecDefaultErlFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAecDefaultErl = TRUE; } break; case cOCT6100_TLV_TYPE_Z_ALC_TARGET_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Z_ALC_TARGET_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_Z_ALC_TARGET_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinAutoLevelControlTargetOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinAutoLevelControl = TRUE; } break; case cOCT6100_TLV_TYPE_Y_ALC_TARGET_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Y_ALC_TARGET_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_Y_ALC_TARGET_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SoutAutoLevelControlTargetOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSoutAutoLevelControl = TRUE; } break; case cOCT6100_TLV_TYPE_Z_HLC_TARGET_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Z_HLC_TARGET_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_Z_HLC_TARGET_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinHighLevelCompensationThresholdOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinHighLevelCompensation = TRUE; } break; case cOCT6100_TLV_TYPE_Y_HLC_TARGET_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Y_HLC_TARGET_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_Y_HLC_TARGET_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SoutHighLevelCompensationThresholdOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSoutHighLevelCompensation = TRUE; } break; case cOCT6100_TLV_TYPE_ALC_HLC_STATUS_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ALC_HLC_STATUS_BOFF_RW_ENABLE, cOCT6100_TLV_MAX_LENGTH_ALC_HLC_STATUS_BOFF_RW_ENABLE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AlcHlcStatusOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAlcHlcStatus = TRUE; } break; case cOCT6100_TLV_TYPE_Z_PLAYOUT_HARD_SKIP_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Z_PLAYOUT_HARD_SKIP_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_Z_PLAYOUT_HARD_SKIP_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutRinHardSkipOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinBufferPlayoutHardSkip = TRUE; } break; case cOCT6100_TLV_TYPE_Y_PLAYOUT_HARD_SKIP_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_Y_PLAYOUT_HARD_SKIP_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_Y_PLAYOUT_HARD_SKIP_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PlayoutSoutHardSkipOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSoutBufferPlayoutHardSkip = TRUE; } break; case cOCT6100_TLV_TYPE_AFT_FIELD_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AFT_FIELD_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_AFT_FIELD_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AftControlOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAftControl = TRUE; } break; case cOCT6100_TLV_TYPE_VOICE_DETECTED_STAT_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_VOICE_DETECTED_STAT_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_VOICE_DETECTED_STAT_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SinVoiceDetectedStatOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSinVoiceDetectedStat = TRUE; } break; case cOCT6100_TLV_TYPE_GAIN_APPLIED_RIN_STAT_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_GAIN_APPLIED_RIN_STAT_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_GAIN_APPLIED_RIN_STAT_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinAppliedGainStatOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinAppliedGainStat = TRUE; } break; case cOCT6100_TLV_TYPE_GAIN_APPLIED_SOUT_STAT_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_GAIN_APPLIED_SOUT_STAT_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_GAIN_APPLIED_SOUT_STAT_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SoutAppliedGainStatOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSoutAppliedGainStat = TRUE; } break; case cOCT6100_TLV_TYPE_MAX_ADAPT_ALE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MAX_ADAPT_ALE_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_MAX_ADAPT_ALE_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AdaptiveAleOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fListenerEnhancement = TRUE; } break; case cOCT6100_TLV_TYPE_RIN_ANR_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_RIN_ANR_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_RIN_ANR_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinAnrOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRoutNoiseReduction = TRUE; } break; case cOCT6100_TLV_TYPE_RIN_ANR_VALUE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_RIN_ANR_VALUE_RW, cOCT6100_TLV_MAX_LENGTH_RIN_ANR_VALUE_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinAnrValOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRoutNoiseReductionLevel = TRUE; } break; case cOCT6100_TLV_TYPE_RIN_MUTE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_RIN_MUTE_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_RIN_MUTE_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinMuteOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinMute = TRUE; } break; case cOCT6100_TLV_TYPE_SIN_MUTE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_SIN_MUTE_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_SIN_MUTE_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SinMuteOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSinMute = TRUE; } break; case cOCT6100_TLV_TYPE_NUMBER_PLAYOUT_EVENTS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_NUMBER_PLAYOUT_EVENTS, cOCT6100_TLV_MAX_LENGTH_NUMBER_PLAYOUT_EVENTS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.byMaxNumberPlayoutEvents = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_ANR_SNR_IMPROVEMENT_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ANR_SNR_IMPROVEMENT_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_ANR_SNR_IMPROVEMENT_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AnrSnrEnhancementOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAnrSnrEnhancement = TRUE; } break; case cOCT6100_TLV_TYPE_ANR_AGRESSIVITY_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ANR_AGRESSIVITY_BOFF_RW, cOCT6100_TLV_MAX_LENGTH_ANR_AGRESSIVITY_BOFF_RW ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AnrVoiceNoiseSegregationOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAnrVoiceNoiseSegregation = TRUE; } break; case cOCT6100_TLV_TYPE_CHAN_TAIL_LENGTH_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CHAN_TAIL_LENGTH_BOFF, cOCT6100_TLV_MAX_LENGTH_CHAN_TAIL_LENGTH_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PerChanTailLengthFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fPerChannelTailLength = TRUE; } break; case cOCT6100_TLV_TYPE_CHAN_VQE_TONE_DISABLING_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_CHAN_VQE_TONE_DIS_BOFF, cOCT6100_TLV_MAX_LENGTH_CHAN_VQE_TONE_DIS_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.ToneDisablerVqeActivationDelayOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fToneDisablerVqeActivationDelay = TRUE; } break; case cOCT6100_TLV_TYPE_AF_TAIL_DISP_VALUE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AF_TAIL_DISP_VALUE_BOFF, cOCT6100_TLV_MAX_LENGTH_AF_TAIL_DISP_VALUE_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AfTailDisplacementFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAfTailDisplacement = TRUE; } break; case cOCT6100_TLV_TYPE_POUCH_COUNTER_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_POUCH_COUNTER_BOFF, cOCT6100_TLV_MAX_LENGTH_POUCH_COUNTER_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.PouchCounterFieldOfst ); f_pApiInstance->pSharedInfo->DebugInfo.fPouchCounter = TRUE; } break; case cOCT6100_TLV_TYPE_AEC_TAIL_LENGTH_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AEC_TAIL_BOFF, cOCT6100_TLV_MAX_LENGTH_AEC_TAIL_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.AecTailLengthFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fAecTailLength = TRUE; } break; case cOCT6100_TLV_TYPE_MATRIX_DWORD_BASE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MATRIX_DWORD_BASE, cOCT6100_TLV_MAX_LENGTH_MATRIX_DWORD_BASE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulMatrixBaseAddress ); /* Mask the upper bits set by the firmware. */ f_pApiInstance->pSharedInfo->DebugInfo.ulMatrixBaseAddress &= 0x0FFFFFFF; /* Modify the base address to incorporate the external memory offset. */ f_pApiInstance->pSharedInfo->DebugInfo.ulMatrixBaseAddress += cOCT6100_EXTERNAL_MEM_BASE_ADDRESS; } break; case cOCT6100_TLV_TYPE_DEBUG_CHAN_STATS_BYTE_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_STATS_BYTE_SIZE, cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_STATS_BYTE_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ); } break; case cOCT6100_TLV_TYPE_DEBUG_CHAN_LITE_STATS_BYTE_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DEBUG_CHAN_LITE_STATS_BYTE_SIZE, cOCT6100_TLV_MAX_LENGTH_DEBUG_CHAN_LITE_STATS_BYTE_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize ); } break; case cOCT6100_TLV_TYPE_HOT_CHANNEL_SELECT_DWORD_BASE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_HOT_CHANNEL_SELECT_DWORD_BASE, cOCT6100_TLV_MAX_LENGTH_HOT_CHANNEL_SELECT_DWORD_BASE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress ); } break; case cOCT6100_TLV_TYPE_MATRIX_TIMESTAMP_DWORD_BASE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_TIMESTAMP_DWORD_BASE, cOCT6100_TLV_MAX_LENGTH_TIMESTAMP_DWORD_BASE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulMatrixTimestampBaseAddress ); } break; case cOCT6100_TLV_TYPE_MATRIX_WP_DWORD_BASE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MATRIX_WP_DWORD_BASE, cOCT6100_TLV_MAX_LENGTH_MATRIX_WP_DWORD_BASE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulMatrixWpBaseAddress ); } break; case cOCT6100_TLV_TYPE_AF_WRITE_PTR_BYTE_OFFSET: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AF_WRITE_PTR_BYTE_OFFSET, cOCT6100_TLV_MAX_LENGTH_AF_WRITE_PTR_BYTE_OFFSET ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulAfWritePtrByteOffset ); } break; case cOCT6100_TLV_TYPE_RECORDED_PCM_EVENT_BYTE_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_RECORDED_PCM_EVENT_BYTE_SIZE, cOCT6100_TLV_MAX_LENGTH_RECORDED_PCM_EVENT_BYTE_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ); } break; case cOCT6100_TLV_TYPE_IS_ISR_CALLED_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_IS_ISR_CALLED_BOFF, cOCT6100_TLV_MAX_LENGTH_IS_ISR_CALLED_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.IsIsrCalledFieldOfst ); f_pApiInstance->pSharedInfo->DebugInfo.fIsIsrCalledField = TRUE; } break; case cOCT6100_TLV_TYPE_MUSIC_PROTECTION_ENABLE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MUSIC_PROTECTION_ENABLE_BOFF, cOCT6100_TLV_MAX_LENGTH_MUSIC_PROTECTION_ENABLE_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.MusicProtectionFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fMusicProtectionConfiguration = TRUE; } break; case cOCT6100_TLV_TYPE_IDLE_CODE_DETECTION_ENABLE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_IDLE_CODE_DETECTION, cOCT6100_TLV_MAX_LENGTH_IDLE_CODE_DETECTION ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fIdleCodeDetection = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_IDLE_CODE_DETECTION_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_IDLE_CODE_DETECTION_BOFF, cOCT6100_TLV_MAX_LENGTH_IDLE_CODE_DETECTION_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.IdleCodeDetectionFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fIdleCodeDetectionConfiguration = TRUE; } break; case cOCT6100_TLV_TYPE_IMAGE_TYPE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_IMAGE_TYPE, cOCT6100_TLV_MAX_LENGTH_IMAGE_TYPE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); /* Check if read image type value is what's expected. */ if ( ( ulTempValue != cOCT6100_IMAGE_TYPE_WIRELINE ) && ( ulTempValue != cOCT6100_IMAGE_TYPE_COMBINED ) ) return cOCT6100_ERR_FATAL_E9; f_pApiInstance->pSharedInfo->ImageInfo.byImageType = (UINT8)( ulTempValue & 0xFF ); } break; case cOCT6100_TLV_TYPE_MAX_WIRELINE_CHANNELS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_MAX_WIRELINE_CHANNELS, cOCT6100_TLV_MAX_LENGTH_MAX_WIRELINE_CHANNELS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); } break; case cOCT6100_TLV_TYPE_AF_EVENT_CB_SIZE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_AF_EVENT_CB_BYTE_SIZE, cOCT6100_TLV_MAX_LENGTH_AF_EVENT_CB_BYTE_SIZE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->DebugInfo.ulAfEventCbByteSize ); } break; case cOCT6100_TLV_TYPE_BUFFER_PLAYOUT_SKIP_IN_EVENTS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_BUFFER_PLAYOUT_SKIP_IN_EVENTS, cOCT6100_TLV_MAX_LENGTH_BUFFER_PLAYOUT_SKIP_IN_EVENTS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); f_pApiInstance->pSharedInfo->ImageInfo.fBufferPlayoutSkipInEvents = TRUE; } break; case cOCT6100_TLV_TYPE_ZZ_ENERGY_CHAN_STATS_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_ZZ_ENERGY_CHAN_STATS_BOFF, cOCT6100_TLV_MAX_LENGTH_ZZ_ENERGY_CHAN_STATS_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.RinEnergyStatFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fRinEnergyStat = TRUE; } break; case cOCT6100_TLV_TYPE_YY_ENERGY_CHAN_STATS_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_YY_ENERGY_CHAN_STATS_BOFF, cOCT6100_TLV_MAX_LENGTH_YY_ENERGY_CHAN_STATS_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.SoutEnergyStatFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fSoutEnergyStat = TRUE; } break; case cOCT6100_TLV_TYPE_DOUBLE_TALK_BEH_MODE: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DOUBLE_TALK_BEH_MODE, cOCT6100_TLV_MAX_LENGTH_DOUBLE_TALK_BEH_MODE ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); if ( ulTempValue != 0 ) f_pApiInstance->pSharedInfo->ImageInfo.fDoubleTalkBehavior = TRUE; else f_pApiInstance->pSharedInfo->ImageInfo.fDoubleTalkBehavior = FALSE; } break; case cOCT6100_TLV_TYPE_DOUBLE_TALK_BEH_MODE_BOFF: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DOUBLE_TALK_BEH_MODE_BOFF, cOCT6100_TLV_MAX_LENGTH_DOUBLE_TALK_BEH_MODE_BOFF ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiTlvReadBitOffsetStruct( f_pApiInstance, f_ulTlvValueAddress, &f_pApiInstance->pSharedInfo->MemoryMap.DoubleTalkBehaviorFieldOfst ); f_pApiInstance->pSharedInfo->ImageInfo.fDoubleTalkBehaviorFieldOfst = TRUE; } break; case cOCT6100_TLV_TYPE_SOUT_NOISE_BLEACHING: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_SOUT_NOISE_BLEACHING, cOCT6100_TLV_MAX_LENGTH_SOUT_NOISE_BLEACHING ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); if ( ulTempValue != 0 ) f_pApiInstance->pSharedInfo->ImageInfo.fSoutNoiseBleaching = TRUE; else f_pApiInstance->pSharedInfo->ImageInfo.fSoutNoiseBleaching = FALSE; } break; case cOCT6100_TLV_TYPE_NLP_STATISTICS: ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_NLP_STATISTICS, cOCT6100_TLV_MAX_LENGTH_NLP_STATISTICS ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulTlvValueAddress, &ulTempValue ); if ( ulTempValue != 0 ) f_pApiInstance->pSharedInfo->ImageInfo.fSinLevel = TRUE; else f_pApiInstance->pSharedInfo->ImageInfo.fSinLevel = FALSE; } break; default: /* Unknown TLV type field... check default length and nothing else. */ ulResult = Oct6100ApiTlvCheckLengthField( f_ulTlvFieldLength, cOCT6100_TLV_MIN_LENGTH_DEFAULT, cOCT6100_TLV_MAX_LENGTH_DEFAULT ); break; } return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiTlvCheckLengthField Description: This function validates the TLV length field. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_ulTlvFieldLength Length field read from the TLV. f_ulMinLengthValue Minimum value supported for the TLV. f_ulMaxLengthValue Maximum value supported for the TLV. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiTlvCheckLengthField UINT32 Oct6100ApiTlvCheckLengthField( IN UINT32 f_ulTlvFieldLength, IN UINT32 f_ulMinLengthValue, IN UINT32 f_ulMaxLengthValue ) { /* Check if the value is too small. */ if ( f_ulTlvFieldLength < f_ulMinLengthValue ) return ( cOCT6100_ERR_FATAL_59 ); /* Check if the value is too big. */ if ( f_ulTlvFieldLength > f_ulMaxLengthValue ) return ( cOCT6100_ERR_FATAL_5A ); /* Check if the value is dword aligned. */ if ( ( f_ulTlvFieldLength % 4 ) != 0 ) return ( cOCT6100_ERR_OPEN_INVALID_TLV_LENGTH ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiTlvReadBitOffsetStruct Description: This function extracts a bit offset structure from the TLV. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulAddress Address where the read the TLV information. f_pBitOffsetStruct Pointer to a bit offset stucture. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiTlvReadBitOffsetStruct UINT32 Oct6100ApiTlvReadBitOffsetStruct( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulAddress, OUT tPOCT6100_TLV_OFFSET f_pBitOffsetStruct ) { tOCT6100_READ_PARAMS ReadParams; UINT16 usReadData; UINT32 ulResult; UINT32 ulOffsetValue; UINT32 ulSizeValue; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /*======================================================================*/ /* Read the first 16 bits of the TLV field. */ ReadParams.ulReadAddress = f_ulAddress; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulOffsetValue = usReadData << 16; /* Read the last word of the TLV type. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulOffsetValue |= usReadData; /*======================================================================*/ /*======================================================================*/ /* Read the first 16 bits of the TLV field. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulSizeValue = usReadData << 16; /* Read the last word of the TLV type. */ ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save data. */ ulSizeValue |= usReadData; /*======================================================================*/ /* Set the structure fields. */ f_pBitOffsetStruct->usDwordOffset = (UINT16)(ulOffsetValue / 32); f_pBitOffsetStruct->byBitOffset = (UINT8) (32 - (ulOffsetValue % 32) - ulSizeValue); f_pBitOffsetStruct->byFieldSize = (UINT8) (ulSizeValue); return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_conf_bridge.c0000644000175000017500000110130511525010337031675 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_conf_bridge.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains all functions related to a conference bridge. Procedures needed to open/close a bridge, add/remove a participant to a conference bridge, mute/unmute a participant, etc.. are all present in this source file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 146 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_mixer_inst.h" #include "oct6100api/oct6100_conf_bridge_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_mixer_pub.h" #include "oct6100api/oct6100_conf_bridge_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_mixer_priv.h" #include "oct6100_conf_bridge_priv.h" /**************************** PUBLIC FUNCTIONS *****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeOpen Description: This function opens a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeOpen Pointer to conference bridge open structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeOpenDef UINT32 Oct6100ConfBridgeOpenDef( tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ) { f_pConfBridgeOpen->pulConfBridgeHndl = NULL; f_pConfBridgeOpen->fFlexibleConferencing = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeOpen UINT32 Oct6100ConfBridgeOpen( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeOpenSer( f_pApiInstance, f_pConfBridgeOpen ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeClose Description: This function closes a conference bridge. A conference bridge can only be closed if no participants are present on the bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeClose Pointer to conference bridge close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeCloseDef UINT32 Oct6100ConfBridgeCloseDef( tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ) { f_pConfBridgeClose->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeClose UINT32 Oct6100ConfBridgeClose( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeCloseSer( f_pApiInstance, f_pConfBridgeClose ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanAdd Description: This function adds an echo channel (participant) to a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeAdd Pointer to conference bridge channel addition structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanAddDef UINT32 Oct6100ConfBridgeChanAddDef( tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ) { f_pConfBridgeAdd->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeAdd->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeAdd->ulInputPort = cOCT6100_CHANNEL_PORT_SOUT; f_pConfBridgeAdd->ulListenerMaskIndex = cOCT6100_INVALID_VALUE; f_pConfBridgeAdd->ulListenerMask = 0; f_pConfBridgeAdd->fMute = FALSE; f_pConfBridgeAdd->ulTappedChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeChanAdd UINT32 Oct6100ConfBridgeChanAdd( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeChanAddSer( f_pApiInstance, f_pConfBridgeAdd ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanRemove Description: This function removes an echo channel (participant) from a conference bridge. All participants can be removed from the bridge if a special flag (fRemoveAll) is set to TRUE. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeRemove Pointer to conference bridge channel removal structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanRemoveDef UINT32 Oct6100ConfBridgeChanRemoveDef( tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ) { f_pConfBridgeRemove->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeRemove->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeRemove->fRemoveAll = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeChanRemove UINT32 Oct6100ConfBridgeChanRemove( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, f_pConfBridgeRemove ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanMute Description: This function mutes a participant present on a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMute Pointer to conference bridge channel mute structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanMuteDef UINT32 Oct6100ConfBridgeChanMuteDef( tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ) { f_pConfBridgeMute->ulChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeChanMute UINT32 Oct6100ConfBridgeChanMute( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeChanMuteSer( f_pApiInstance, f_pConfBridgeMute ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanUnMute Description: This function unmutes a channel on a bridge. The other member of the conference will start to hear this participant again. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeUnMute Pointer to conference bridge channel unmute structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanUnMuteDef UINT32 Oct6100ConfBridgeChanUnMuteDef( tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ) { f_pConfBridgeUnMute->ulChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeChanUnMute UINT32 Oct6100ConfBridgeChanUnMute( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeChanUnMuteSer( f_pApiInstance, f_pConfBridgeUnMute ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeDominantSpeakerSet Description: This function sets a participant present on a conference bridge as the dominant speaker. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeDominant Pointer to conference bridge dominant speaker structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeDominantSpeakerSetDef UINT32 Oct6100ConfBridgeDominantSpeakerSetDef( tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ) { f_pConfBridgeDominantSpeaker->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeDominantSpeaker->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeDominantSpeakerSet UINT32 Oct6100ConfBridgeDominantSpeakerSet( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeDominantSpeakerSetSer( f_pApiInstance, f_pConfBridgeDominantSpeaker ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeMaskChange Description: This function changes the mask of a flexible bridge participant. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMaskChange Pointer to conference bridge change of mask structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeMaskChangeDef UINT32 Oct6100ConfBridgeMaskChangeDef( tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ) { f_pConfBridgeMaskChange->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeMaskChange->ulNewListenerMask = 0x0; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeMaskChange UINT32 Oct6100ConfBridgeMaskChange( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeMaskChangeSer( f_pApiInstance, f_pConfBridgeMaskChange ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeGetStats Description: This function returns the stats for a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeStats Pointer to conference bridge channel stats structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeGetStatsDef UINT32 Oct6100ConfBridgeGetStatsDef( tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ) { f_pConfBridgeStats->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; f_pConfBridgeStats->ulNumChannels = cOCT6100_INVALID_STAT; f_pConfBridgeStats->ulNumTappedChannels = cOCT6100_INVALID_STAT; f_pConfBridgeStats->fFlexibleConferencing = cOCT6100_INVALID_STAT; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ConfBridgeGetStats UINT32 Oct6100ConfBridgeGetStats( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure. */ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ConfBridgeGetStatsSer( f_pApiInstance, f_pConfBridgeStats ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetConfBridgeSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of conference bridges. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetConfBridgeSwSizes UINT32 Oct6100ApiGetConfBridgeSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Calculate memory needed for conference bridge list. */ if ( f_pOpenChip->ulMaxConfBridges == 0 && f_pOpenChip->fEnableChannelRecording == TRUE ) f_pOpenChip->ulMaxConfBridges = 1; f_pInstSizes->ulConfBridgeList = f_pOpenChip->ulMaxConfBridges * sizeof( tOCT6100_API_CONF_BRIDGE ); /* Calculate memory needed for conference bridge allocation software. */ if ( f_pOpenChip->ulMaxConfBridges > 0 ) { /* Get size of bridge allocation memory */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxConfBridges, &f_pInstSizes->ulConfBridgeAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1C; /* Check if the user wants to build flexible conference bridges. */ if ( f_pOpenChip->ulMaxFlexibleConfParticipants > 0 ) { /* Allocate the lowest quantity according to what the user requested. */ if ( f_pOpenChip->ulMaxFlexibleConfParticipants < ( f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ) ) f_pInstSizes->ulFlexConfParticipantsList = f_pOpenChip->ulMaxFlexibleConfParticipants * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT ); else { f_pOpenChip->ulMaxFlexibleConfParticipants = f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; f_pInstSizes->ulFlexConfParticipantsList = f_pOpenChip->ulMaxConfBridges * cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT ); } /* Get size of flexible conferencing participants allocation memory */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxFlexibleConfParticipants, &f_pInstSizes->ulFlexConfParticipantsAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1C; } else { f_pInstSizes->ulFlexConfParticipantsList = 0; f_pInstSizes->ulFlexConfParticipantsAlloc = 0; } } else { f_pInstSizes->ulMixerEventList = 0; f_pInstSizes->ulMixerEventAlloc = 0; f_pInstSizes->ulConfBridgeAlloc = 0; /* Make sure flexible conferencing is not used. */ f_pInstSizes->ulFlexConfParticipantsList = 0; f_pInstSizes->ulFlexConfParticipantsAlloc = 0; } /* Calculate memory needed for list and allocation software serialization. */ mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulConfBridgeList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulConfBridgeAlloc, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulFlexConfParticipantsList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulFlexConfParticipantsAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiConfBridgeSwInit Description: Initializes all elements of the instance structure associated to conference bridges. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiConfBridgeSwInit UINT32 Oct6100ApiConfBridgeSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CONF_BRIDGE pConfBridgeList; tPOCT6100_API_FLEX_CONF_PARTICIPANT pFlexConfParticipantList; PVOID pFlexConfPartipantsAlloc; UINT32 ulMaxFlexConfParicipants; PVOID pConfBridgeAlloc; UINT32 ulMaxConfBridges; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get the maximum number of conference bridges. */ ulMaxConfBridges = pSharedInfo->ChipConfig.usMaxConfBridges; /*===================================================================*/ /* Set all entries in the conference bridge list to unused. */ mOCT6100_GET_CONF_BRIDGE_LIST_PNT( pSharedInfo, pConfBridgeList ); /* Initialize the conference bridge allocation software to "all free". */ if ( ulMaxConfBridges > 0 ) { /* Clear the bridge memory */ Oct6100UserMemSet( pConfBridgeList, 0x00, ulMaxConfBridges * sizeof( tOCT6100_API_CONF_BRIDGE )); mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( pSharedInfo, pConfBridgeAlloc ) ulResult = OctapiLlmAllocInit( &pConfBridgeAlloc, ulMaxConfBridges ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1E; } /*===================================================================*/ /*===================================================================*/ /* Set all entries in the flexible conferencing participant list to unused. */ /* Get the maximum number of flexible conferencing participants. */ ulMaxFlexConfParicipants = pSharedInfo->ChipConfig.usMaxFlexibleConfParticipants; mOCT6100_GET_FLEX_CONF_PARTICIPANT_LIST_PNT( pSharedInfo, pFlexConfParticipantList ); /* Initialize the flexible conferencing allocation software. */ if ( ulMaxFlexConfParicipants > 0 ) { UINT32 i, ulEventIndex; /* Clear the participants memory */ Oct6100UserMemSet( pFlexConfParticipantList, 0x00, ulMaxFlexConfParicipants * sizeof( tOCT6100_API_FLEX_CONF_PARTICIPANT )); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( pSharedInfo, pFlexConfPartipantsAlloc ) ulResult = OctapiLlmAllocInit( &pFlexConfPartipantsAlloc, ulMaxFlexConfParicipants ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1E; /* Initialize the conferencing indexes. */ for ( i = 0; i < ulMaxFlexConfParicipants; i ++ ) { for ( ulEventIndex = 0; ulEventIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulEventIndex ++ ) pFlexConfParticipantList[ i ].ausLoadOrAccumulateEventIndex[ ulEventIndex ] = cOCT6100_INVALID_INDEX; } } /*===================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeOpenSer Description: Open a conference bridge. Note that no chip resources are allocated until a channel is added to the bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeOpen Pointer to conference bridge configuration structure. The handle identifying the conference bridge in all future function calls is returned in this structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeOpenSer UINT32 Oct6100ConfBridgeOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ) { UINT16 usBridgeIndex; UINT32 ulResult; /* Check the user's configuration of the conference bridge for errors. */ ulResult = Oct6100ApiCheckBridgeParams( f_pApiInstance, f_pConfBridgeOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the conference bridge. */ ulResult = Oct6100ApiReserveBridgeResources( f_pApiInstance, &usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new conference bridge's entry in the conference bridge list. */ ulResult = Oct6100ApiUpdateBridgeEntry( f_pApiInstance, f_pConfBridgeOpen, usBridgeIndex); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeParams Description: Checks the user's conference bridge open configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeOpen Pointer to conference bridge configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeParams UINT32 Oct6100ApiCheckBridgeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen ) { /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeOpen->pulConfBridgeHndl == NULL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; if ( f_pApiInstance->pSharedInfo->ImageInfo.fConferencing == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CONF_BRIDGE; if ( f_pConfBridgeOpen->fFlexibleConferencing != FALSE && f_pConfBridgeOpen->fFlexibleConferencing != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBridgeResources Description: Reserves all resources needed for the new conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusBridgeIndex Allocated entry in the API conference bridge list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBridgeResources UINT32 Oct6100ApiReserveBridgeResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusBridgeIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Reserve an entry in the conference bridge list. */ ulResult = Oct6100ApiReserveBridgeEntry( f_pApiInstance, f_pusBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBridgeEntry Description: Updates the new conference bridge's entry in the conference bridge list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeOpen Pointer to conference bridge configuration structure. f_usBridgeIndex Allocated entry in API conference bridge list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBridgeEntry UINT32 Oct6100ApiUpdateBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_OPEN f_pConfBridgeOpen, IN UINT16 f_usBridgeIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CONF_BRIDGE pTempBridgeEntry; /*================================================================================*/ /* Obtain a pointer to the new conference bridge's list entry. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ) /* No clients are currently connected to the bridge. */ pBridgeEntry->usNumClients = 0; /* Nobody is tapped for now. */ pBridgeEntry->usNumTappedClients = 0; pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX; /* Now update the bridge pointer. */ if ( f_pApiInstance->pSharedInfo->MiscVars.usNumBridgesOpened == 0 ) { pBridgeEntry->usNextBridgePtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usPrevBridgePtr = cOCT6100_INVALID_INDEX; /* Set the global first bridge to this bridge. */ f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge = f_usBridgeIndex; } else /* Insert this bridge at the head of the bridge list.*/ { if ( f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_FATAL_22; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge ) if ( pTempBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_FATAL_23; /* Modify the old first entry. */ pTempBridgeEntry->usPrevBridgePtr = f_usBridgeIndex; /* Modify current pointer. */ pBridgeEntry->usPrevBridgePtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usNextBridgePtr = f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge; /* Set the new first bridge of the list. */ f_pApiInstance->pSharedInfo->MiscVars.usFirstBridge = f_usBridgeIndex; } /* Form handle returned to user. */ *f_pConfBridgeOpen->pulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pBridgeEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usBridgeIndex; /* Remember whether or not we are a flexible conference bridge. */ pBridgeEntry->fFlexibleConferencing = (UINT8)( f_pConfBridgeOpen->fFlexibleConferencing & 0xFF ); /* Finally, mark the conference bridge as opened. */ pBridgeEntry->fReserved = TRUE; /* Increment the number of conference bridge opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberConfBridges++; f_pApiInstance->pSharedInfo->MiscVars.usNumBridgesOpened++; /*================================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeCloseSer Description: Closes a conference bridge. Note that no client must be present on the bridge for the bridge to be closed. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeClose Pointer to conference bridge close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeCloseSer UINT32 Oct6100ConfBridgeCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose ) { UINT16 usBridgeIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertBridgeParams( f_pApiInstance, f_pConfBridgeClose, &usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the conference bridge. */ ulResult = Oct6100ApiReleaseBridgeResources( f_pApiInstance, usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle. */ f_pConfBridgeClose->ulConfBridgeHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertBridgeParams Description: Checks the user's conference bridge close configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeClose Pointer to conference bridge close structure. f_pusBridgeIndex Pointer to API instance conference bridge index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertBridgeParams UINT32 Oct6100ApiAssertBridgeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CLOSE f_pConfBridgeClose, OUT PUINT16 f_pusBridgeIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; UINT32 ulEntryOpenCnt; /* Check the provided handle. */ if ( (f_pConfBridgeClose->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusBridgeIndex = (UINT16)( f_pConfBridgeClose->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeClose->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( pBridgeEntry->usNumClients != 0 ) return cOCT6100_ERR_CONF_BRIDGE_ACTIVE_DEPENDENCIES; if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBridgeResources Description: Release all resources reserved for the conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Allocated external memory block for the conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBridgeResources UINT32 Oct6100ApiReleaseBridgeResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CONF_BRIDGE pTempBridgeEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Release the entry from the conference bridge list. */ ulResult = Oct6100ApiReleaseBridgeEntry( f_pApiInstance, f_usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_24; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ); /* Remove the bridge entry from the bridge list. */ if ( pSharedInfo->MiscVars.usNumBridgesOpened == 1 ) { /* This bridge was the only one opened. */ pSharedInfo->MiscVars.usFirstBridge = cOCT6100_INVALID_INDEX; } else if ( pSharedInfo->MiscVars.usNumBridgesOpened > 1 ) { /* There are more then one bridge open, must update the list. */ if ( pBridgeEntry->usPrevBridgePtr != cOCT6100_INVALID_INDEX ) { /* There is a valid entry before this bridge, let's update this entry. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, pBridgeEntry->usPrevBridgePtr ); pTempBridgeEntry->usNextBridgePtr = pBridgeEntry->usNextBridgePtr; } if ( pBridgeEntry->usNextBridgePtr != cOCT6100_INVALID_INDEX ) { /* There is a valid entry after this bridge, let's update this entry. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempBridgeEntry, pBridgeEntry->usNextBridgePtr ); pTempBridgeEntry->usPrevBridgePtr = pBridgeEntry->usPrevBridgePtr; } if ( pSharedInfo->MiscVars.usFirstBridge == f_usBridgeIndex ) { /* This entry was the first of the list, make the next one be the first now. */ pSharedInfo->MiscVars.usFirstBridge = pBridgeEntry->usNextBridgePtr; } } else { /* Variable has become out of sync. */ return cOCT6100_ERR_FATAL_25; } /*=============================================================*/ /* Update the conference bridge's list entry. */ /* Mark the bridge as closed. */ pBridgeEntry->fFlexibleConferencing = FALSE; pBridgeEntry->fReserved = FALSE; pBridgeEntry->byEntryOpenCnt++; /* Decrement the number of conference bridges opened. */ pSharedInfo->MiscVars.usNumBridgesOpened--; pSharedInfo->ChipStats.usNumberConfBridges--; /*=============================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanAddSer Description: Adds an echo channel (participant) to a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeAdd Pointer to conference bridge channel add structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanAddSer UINT32 Oct6100ConfBridgeChanAddSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd ) { UINT16 usBridgeIndex; UINT16 usChanIndex; UINT16 usLoadEventIndex; UINT16 usSubStoreEventIndex; UINT16 usCopyEventIndex; UINT32 ulInputPort; UINT8 fFlexibleConfBridge; UINT32 ulListenerMaskIndex; UINT32 ulListenerMask; UINT16 usTapChanIndex; UINT16 usTapBridgeIndex; UINT8 fMute; UINT8 fTap; UINT32 ulResult; /* Check the validity of the channel and conference bridge given. */ ulResult = Oct6100ApiCheckBridgeAddParams( f_pApiInstance, f_pConfBridgeAdd, &usBridgeIndex, &usChanIndex, &fMute, &ulInputPort, &fFlexibleConfBridge, &ulListenerMaskIndex, &ulListenerMask, &fTap, &usTapChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the conference bridge. */ ulResult = Oct6100ApiReserveBridgeAddResources( f_pApiInstance, usBridgeIndex, usChanIndex, ulInputPort, fFlexibleConfBridge, ulListenerMaskIndex, ulListenerMask, fTap, &usLoadEventIndex, &usSubStoreEventIndex, &usCopyEventIndex, &usTapBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the conference bridge. */ ulResult = Oct6100ApiBridgeEventAdd( f_pApiInstance, usBridgeIndex, usChanIndex, fFlexibleConfBridge, usLoadEventIndex, usSubStoreEventIndex, usCopyEventIndex, ulInputPort, fMute, ulListenerMaskIndex, ulListenerMask, fTap, usTapBridgeIndex, usTapChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeAddParams Description: Check the validity of the channel and conference bridge given. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeAdd Pointer to conference bridge channenl add structure. f_pusBridgeIndex Extracted bridge index where this channel should be added. f_pusChannelIndex Extracted channel index related to the channel handle to be added to the bridge. f_pfMute Whether to mute this channel in the bridge or not. f_pulInputPort Input port where the channel signal should be copied from. f_pfFlexibleConfBridge If this is a flexible conference bridge. f_pulListenerMaskIndex Index of the listener in this flexible conference bridge. f_pulListenerMask Mask of listeners in this flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeAddParams UINT32 Oct6100ApiCheckBridgeAddParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_ADD f_pConfBridgeAdd, OUT PUINT16 f_pusBridgeIndex, OUT PUINT16 f_pusChannelIndex, OUT PUINT8 f_pfMute, OUT PUINT32 f_pulInputPort, OUT PUINT8 f_pfFlexibleConfBridge, OUT PUINT32 f_pulListenerMaskIndex, OUT PUINT32 f_pulListenerMask, OUT PUINT8 f_pfTap, OUT PUINT16 f_pusTapChannelIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulEntryOpenCnt; UINT8 byTapChannelLaw; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 1 && f_pApiInstance->pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeAdd->ulConfBridgeHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; if ( f_pConfBridgeAdd->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE; if( f_pConfBridgeAdd->ulInputPort != cOCT6100_CHANNEL_PORT_SOUT && f_pConfBridgeAdd->ulInputPort != cOCT6100_CHANNEL_PORT_RIN ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_INPUT_PORT; if ( f_pConfBridgeAdd->fMute != TRUE && f_pConfBridgeAdd->fMute != FALSE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_MUTE; /*=====================================================================*/ /* Check the conference bridge handle. */ if ( (f_pConfBridgeAdd->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusBridgeIndex = (UINT16)( f_pConfBridgeAdd->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeAdd->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* When we a flexible conference bridge, more things need to be checked. */ if ( pBridgeEntry->fFlexibleConferencing == TRUE ) { /* Check if flexible conferencing has been activated. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxFlexibleConfParticipants == 0 ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_DISABLED; /* Check the number of clients on the bridge. */ if ( pBridgeEntry->usNumClients >= cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_PARTICIPANT_CNT; /* Check if the listener index in a flexible bridge is valid. */ if ( f_pConfBridgeAdd->ulListenerMaskIndex == cOCT6100_INVALID_VALUE || f_pConfBridgeAdd->ulListenerMaskIndex >= cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_MASK_INDEX; } if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE ) { if ( pBridgeEntry->fFlexibleConferencing == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_TAP_NOT_SUPPORTED; } /*=====================================================================*/ /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pConfBridgeAdd->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeAdd->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeAdd->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; if ( pEchoChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ALREADY_ON_BRIDGE; if ( pEchoChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_BIDIR; /* Law conversion is not allowed on a conference bridge. */ if ( ( pEchoChanEntry->TdmConfig.usRinTimeslot != cOCT6100_UNASSIGNED ) && ( pEchoChanEntry->TdmConfig.usRoutTimeslot != cOCT6100_UNASSIGNED ) ) { if ( pEchoChanEntry->TdmConfig.byRinPcmLaw != pEchoChanEntry->TdmConfig.byRoutPcmLaw ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_LAW_CONVERSION; } if ( ( pEchoChanEntry->TdmConfig.usSinTimeslot != cOCT6100_UNASSIGNED ) && ( pEchoChanEntry->TdmConfig.usSoutTimeslot != cOCT6100_UNASSIGNED ) ) { if ( pEchoChanEntry->TdmConfig.bySinPcmLaw != pEchoChanEntry->TdmConfig.bySoutPcmLaw ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_LAW_CONVERSION; } if ( pEchoChanEntry->fRinRoutCodecActive == TRUE || pEchoChanEntry->fSinSoutCodecActive == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_CODEC_ACTIVE; if ( pEchoChanEntry->fEnableExtToneDetection == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_EXT_TONE_ENABLED; if ( pEchoChanEntry->usCopyEventCnt != 0x0 ) return cOCT6100_ERR_CONF_BRIDGE_COPY_EVENTS; /* If the bridge is flexible, few more things need to be checked. */ if ( pBridgeEntry->fFlexibleConferencing == TRUE ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT16 usChannelIndex; UINT32 ulResult = cOCT6100_ERR_OK; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check if the listener index has been used by another channel in the specified bridge. */ for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != ( *f_pusChannelIndex ) ) && ( pEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pEchoChanEntry->usBridgeIndex == ( *f_pusBridgeIndex ) ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Check if this participant has the same listener index. */ if ( f_pConfBridgeAdd->ulListenerMaskIndex == pCurrentParticipant->ulListenerMaskIndex ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_LISTENER_INDEX_USED; } } } } if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE ) { /* For internal logic, make sure the mute flag is set to false. */ f_pConfBridgeAdd->fMute = FALSE; /* Force input port to Sout for logic below. */ f_pConfBridgeAdd->ulInputPort = cOCT6100_CHANNEL_PORT_SOUT; /* Keep law to check for conversion. */ /* Check if the same law. */ byTapChannelLaw = pEchoChanEntry->TdmConfig.bySoutPcmLaw; /* Check the tap handle. */ if ( (f_pConfBridgeAdd->ulTappedChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE; *f_pusTapChannelIndex = (UINT16)( f_pConfBridgeAdd->ulTappedChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusTapChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusTapChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeAdd->ulTappedChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_TAP_HANDLE; if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_BRIDGE; if ( pEchoChanEntry->usBridgeIndex != *f_pusBridgeIndex ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_NOT_ON_SAME_BRIDGE; /* We can only tap a channel added on the Sout port. */ if ( pEchoChanEntry->usSinCopyEventIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_TAP_SOUT_ONLY; /* Check if already tapped. */ if ( pEchoChanEntry->fBeingTapped == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_ALREADY_TAPPED; } /*=====================================================================*/ /* Return the tap flag. */ if ( f_pConfBridgeAdd->ulTappedChannelHndl != cOCT6100_INVALID_HANDLE ) { *f_pfTap = TRUE; } else { *f_pfTap = FALSE; } /* Return the mute config specified. */ *f_pfMute = (UINT8)( f_pConfBridgeAdd->fMute & 0xFF ); /* Return the input port specified. */ *f_pulInputPort = f_pConfBridgeAdd->ulInputPort; /* Return whether we are in the flexible conference bridge case. */ *f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing; /* Return the listener mask index as specified. */ *f_pulListenerMaskIndex = f_pConfBridgeAdd->ulListenerMaskIndex; /* Return the listener mask as specified. */ *f_pulListenerMask = f_pConfBridgeAdd->ulListenerMask; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBridgeAddResources Description: Reserves all resources needed for the addition of a channel to the conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Bridge index of the bridge where this channel is added. f_usChanIndex Channel index of the channel to be added to the bridge. f_ulInputPort Input port where to copy samples from. f_fFlexibleConfBridge If this is a flexible conference bridge. f_ulListenerMaskIndex Index of the listener in this flexible conference bridge. f_ulListenerMask Mask of listeners in this flexible conference bridge. f_pusLoadEventIndex Load event index within the API's list of mixer event. f_pusSubStoreEventIndex Sub-Store event index within the API's list of mixer event. f_pusCopyEventIndex Copy event index within the API's list of mixer event. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBridgeAddResources UINT32 Oct6100ApiReserveBridgeAddResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulInputPort, IN UINT8 f_fFlexibleConfBridge, IN UINT32 f_ulListenerMaskIndex, IN UINT32 f_ulListenerMask, IN UINT8 f_fTap, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT16 f_pusCopyEventIndex, OUT PUINT16 f_pusTapBridgeIndex ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pTempEchoChanEntry; UINT32 ulResult; UINT32 ulTempVar; UINT16 usChannelIndex; BOOL fLoadEventReserved = FALSE; BOOL fStoreEventReserved = FALSE; BOOL fCopyEventReserved = FALSE; BOOL fExtraSinTsiReserved = FALSE; BOOL fExtraRinTsiReserved = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) /* Resources must be reserved according to the type of bridge we are adding to. */ if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pNewParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant; /*========================================================================*/ /* If we are in the flexible conferencing case, things are a little */ /* different. We create a mixer for every participant instead of the */ /* usual same mixer for everyone. For example, if we have 3 participants */ /* of type client - agent - coach, we build the mixers as follows: */ /* */ /* Client: - Load Agent */ /* - Store */ /* */ /* Agent: - Load Client */ /* - Accumulate Coach */ /* - Store */ /* */ /* Coach: - Load Client */ /* - Accumulate Agent */ /* - Store */ /* */ /*========================================================================*/ /* First reserve a flexible conferencing participant entry. */ ulResult = Oct6100ApiReserveFlexConfParticipantEntry( f_pApiInstance, &pChanEntry->usFlexConfParticipantIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pNewParticipant, pChanEntry->usFlexConfParticipantIndex ); /* Reserve an entry for the store event in the mixer memory. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusSubStoreEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* If using the SOUT port, we must copy this entry */ if( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { /* Reserve an entry for the copy event in the Mixer memory. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusCopyEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fCopyEventReserved = TRUE; /* Reserve a SIN copy entry if none were reserved before.*/ if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX ) { /* Reserve an entry for the extra tsi chariot memory. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pChanEntry->usExtraSinTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) fExtraSinTsiReserved = TRUE; } } } else /* if( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { /* Reserve a RIN copy entry if none were reserved before.*/ if ( pChanEntry->usExtraRinTsiMemIndex == cOCT6100_INVALID_INDEX ) { /* Reserve an entry for the extra tsi chariot memory. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pChanEntry->usExtraRinTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) fExtraRinTsiReserved = TRUE; } } /* Must travel all clients of this conference and reserve a load or accumulate event for */ /* all participants which can hear us. */ /* Search through the list of API channel entry for the ones on to this bridge.*/ for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can hear this participant. */ if ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 ) { /* Must reserve a load or accumulate entry mixer event here! */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { /* Most probably, the hardware is out of mixer events. */ break; } } /* Check if this participant can hear us. */ if ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 ) { /* Must reserve a load or accumulate entry mixer event here! */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { /* Most probably, the hardware is out of mixer events. */ break; } } } } } /* If an error is returned, make sure everything is cleaned up properly. */ if ( ulResult != cOCT6100_ERR_OK ) { /* Release the flexible conferencing participant entry. */ ulTempVar = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pChanEntry->usFlexConfParticipantIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX; /* Release the substore event in the mixer memory. */ ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusSubStoreEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; if ( fCopyEventReserved == TRUE ) { /* Release the copy event in the mixer memory. */ ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusCopyEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fExtraSinTsiReserved == TRUE ) { /* Release the extra Sin TSI in TSI memory. */ ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraSinTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } if ( fExtraRinTsiReserved == TRUE ) { /* Release the extra Rin TSI in TSI memory. */ ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraRinTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX; } /* Search through the list of API channel entry for the ones on to this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can hear this participant. */ if ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 ) { /* If the load or event entry in the mixer memory was reserved. */ if ( pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX ) { /* Must release the load or accumulate entry mixer event. */ ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } /* Check this participant can hear us. */ if ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 ) { /* If the load or event entry in the mixer memory was reserved. */ if ( pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX ) { /* Must release the load or accumulate entry mixer event. */ ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } } } } return ulResult; } } else /* if ( ulResult != cOCT6100_ERR_OK ) */ { ulTempVar = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pChanEntry->usFlexConfParticipantIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX; /* Return the error code to the user. The mixer event allocation failed. */ return ulResult; } /*=======================================================================*/ } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { /*=======================================================================*/ /* Normal conferencing. */ /* Reserve an entry for the load event in the mixer memory. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusLoadEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fLoadEventReserved = TRUE; /* Reserve an entry for the substract and store event in the mixer memory. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusSubStoreEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fStoreEventReserved = TRUE; /* If using the SOUT port, we must copy this entry */ if( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { /* Reserve an entry for the copy event in the mixer memory. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, f_pusCopyEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fCopyEventReserved = TRUE; /* Reserve a SIN copy entry if none were reserved before. */ if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX ) { /* Reserve an entry for the extra tsi chariot memory. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pChanEntry->usExtraSinTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) fExtraSinTsiReserved = TRUE; } } } } } if ( ( ulResult == cOCT6100_ERR_OK ) && ( f_fTap == TRUE ) ) { /* Reserve a "tap" bridge. */ tOCT6100_CONF_BRIDGE_OPEN ConfBridgeOpen; UINT32 ulTapBridgeHndl = 0; Oct6100ConfBridgeOpenDef( &ConfBridgeOpen ); ConfBridgeOpen.pulConfBridgeHndl = &ulTapBridgeHndl; ulResult = Oct6100ConfBridgeOpenSer( f_pApiInstance, &ConfBridgeOpen ); *f_pusTapBridgeIndex = (UINT16)( ulTapBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); } if ( ulResult != cOCT6100_ERR_OK ) { if ( fLoadEventReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusLoadEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fStoreEventReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusSubStoreEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fCopyEventReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusCopyEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fExtraSinTsiReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtraSinTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } return ulResult; } /*=======================================================================*/ } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeEventAdd Description: Add the event into the global event list of the chip and update the bridge and channel structures. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Index of the current bridge in the API list. f_usChanIndex Index of the current channel in the API list. f_fFlexibleConfBridge If this is a flexible conference bridge. f_usLoadEventIndex Allocated entry for the Load event of the channel. f_usSubStoreEventIndex Allocated entry for the substract and store event of the channel. f_usCopyEventIndex Allocated entry for the copy event of the channel. f_ulInputPort Input port where to copy samples from. f_fMute Mute flag indicating if the channel is added in a mute state. f_ulListenerMaskIndex Index of the listener in this flexible conference bridge. f_ulListenerMask Mask of listeners in this flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeEventAdd UINT32 Oct6100ApiBridgeEventAdd( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT32 f_ulInputPort, IN UINT8 f_fMute, IN UINT32 f_ulListenerMaskIndex, IN UINT32 f_ulListenerMask, IN UINT8 f_fTap, IN UINT16 f_usTapBridgeIndex, IN UINT16 f_usTapChanIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pSubStoreEventEntry; tPOCT6100_API_MIXER_EVENT pTempEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_API_CHANNEL pTapEchoChanEntry = NULL; tPOCT6100_API_CHANNEL pTempEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT16 usChannelIndex; UINT16 usLastSubStoreEventIndex; UINT16 usLastLoadEventIndex; BOOL fAddSinCopy = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get the bridge and channel entries of interest. */ if ( f_fTap == FALSE ) { mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usBridgeIndex ); } else { mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usTapBridgeIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTapEchoChanEntry, f_usTapChanIndex ); } mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pNewParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pCurrentParticipant; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pNewParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Search through the list of API channel entry for the ones onto this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pCurrentParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can hear this participant. */ if ( ( pTempEchoChanEntry->fMute == FALSE ) && ( ( f_ulListenerMask & ( 0x1 << pCurrentParticipant->ulListenerMaskIndex ) ) == 0x0 ) ) { /* First create/update the current channel's mixer. */ ulResult = Oct6100ApiBridgeAddParticipantToChannel( f_pApiInstance, f_usBridgeIndex, usChannelIndex, f_usChanIndex, pNewParticipant->ausLoadOrAccumulateEventIndex[ pCurrentParticipant->ulListenerMaskIndex ], f_usSubStoreEventIndex, f_usCopyEventIndex, pCurrentParticipant->ulInputPort, f_ulInputPort ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if this participant can hear us. */ if ( ( f_fMute == FALSE ) && ( ( pCurrentParticipant->ulListenerMask & ( 0x1 << f_ulListenerMaskIndex ) ) == 0x0 ) ) { /* Then create/update this channel's mixer. */ ulResult = Oct6100ApiBridgeAddParticipantToChannel( f_pApiInstance, f_usBridgeIndex, f_usChanIndex, usChannelIndex, pCurrentParticipant->ausLoadOrAccumulateEventIndex[ f_ulListenerMaskIndex ], pTempEchoChanEntry->usSubStoreEventIndex, pTempEchoChanEntry->usSinCopyEventIndex, f_ulInputPort, pCurrentParticipant->ulInputPort ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the Rin silence event can be cleared now that the */ /* channel has been added to a conference. */ if ( ( pCurrentParticipant->fFlexibleMixerCreated == TRUE ) && ( pTempEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pTempEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } } } } } /* Check if the mixer for the destination channel has been created. */ if ( pNewParticipant->fFlexibleMixerCreated == FALSE ) { /* Save store event index that might be used for next channel added. */ pEchoChanEntry->usSubStoreEventIndex = f_usSubStoreEventIndex; } else { /* Check if the Rin silence event can be cleared now that the */ /* channel has been added to a conference. */ if ( pEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } } pNewParticipant->ulListenerMaskIndex = f_ulListenerMaskIndex; pNewParticipant->ulListenerMask = f_ulListenerMask; /* Remember this channel's input port. */ pNewParticipant->ulInputPort = f_ulInputPort; /*=======================================================================*/ } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { /* Configure the SIN copy mixer entry and memory - if using the SOUT port. */ if ( ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( f_fTap == FALSE ) ) { if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pEchoChanEntry->usSinTsstIndex, pEchoChanEntry->usExtraSinTsiMemIndex, pEchoChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the extra sin TSI. */ if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usExtraSinTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex ); /*=======================================================================*/ /* Program the Load event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); if ( ( f_fMute == FALSE ) || ( f_fTap == TRUE ) ) { if ( pBridgeEntry->usLoadIndex != cOCT6100_INVALID_INDEX ) { WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; /* Set the event type. */ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; if ( f_fTap == TRUE ) return cOCT6100_ERR_FATAL_D1; } else /* pBridgeEntry->usLoadIndex == cOCT6100_INVALID_INDEX */ { WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Modify the bridge entry to show store the new load index.*/ pBridgeEntry->usLoadIndex = f_usLoadEventIndex; /* Set the event type.*/ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; } /* Select the TSI memory index according to the source port. */ if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { if ( f_fTap == FALSE ) { WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex; } else { tPOCT6100_API_CONF_BRIDGE pTempBridgeEntry; UINT16 usTempWriteData; UINT32 ulTempWriteAddress; /* Save temp write data before trying to clear the Rin TSST. */ usTempWriteData = WriteParams.usWriteData; ulTempWriteAddress = WriteParams.ulWriteAddress; /* Clear the Rin TSST if used. */ if ( pTapEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pTapEchoChanEntry->usRinTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Reassign write data that might have been cleared by write above. */ WriteParams.usWriteData = usTempWriteData; WriteParams.ulWriteAddress = ulTempWriteAddress; WriteParams.usWriteData |= pTapEchoChanEntry->usRinRoutTsiMemIndex; /* Remember that this channel is being tapped by us. */ pTapEchoChanEntry->fBeingTapped = TRUE; pTapEchoChanEntry->usTapChanIndex = f_usChanIndex; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pTempBridgeEntry, f_usBridgeIndex ); pTempBridgeEntry->usNumTappedClients++; } } else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex; } } else /* f_fMute == TRUE */ { /* Do not load the sample if the channel is muted. */ if ( pBridgeEntry->usNumClients == 0 ) { /* If the participant to be added is muted, and it would cause the conference to */ /* be completely muted, load the silence TSI. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD; WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */ /* We know for sure that the load of the bridge will be the silence one. */ pBridgeEntry->usSilenceLoadEventPtr = f_usLoadEventIndex; } else { /* Do nothing! */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; } /* Set the event type. */ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the Substract and store event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); if ( ( f_fMute == FALSE ) && ( f_fTap == FALSE ) ) { WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE; /* Select the TSI memory index and PCM law according to the source port. */ if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex; } else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex; } /* Set the event type. */ pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE; } else /* f_fMute == TRUE */ { /* Do not substore the sample if the channel is muted. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE; /* Select the PCM law according to the source port. */ if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } else /* if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } /* Set the event type. */ pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the Copy event - if using the SOUT port */ if ( ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( f_fTap == FALSE ) ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= pEchoChanEntry->usExtraSinTsiMemIndex; WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set add copy event flag. */ fAddSinCopy = TRUE; /* For sure. */ pEchoChanEntry->fCopyEventCreated = TRUE; } else if ( f_fTap == TRUE ) { /* Accumulate the tapped channel's voice instead of building a copy event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; WriteParams.usWriteData |= pTapEchoChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Link to next operation. */ WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = f_usSubStoreEventIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software model. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, f_usCopyEventIndex ); pTempEntry->usSourceChanIndex = f_usTapChanIndex; pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; pTempEntry->usNextEventPtr = f_usSubStoreEventIndex; pTempEntry->usDestinationChanIndex = cOCT6100_INVALID_INDEX; pTempEntry->fReserved = TRUE; } /*=======================================================================*/ /*=======================================================================*/ /* Now insert the event into the list.*/ if ( pBridgeEntry->usNumClients == 0 ) { /* This is the first entry for this bridge. Insert the two events at the head of the list just after the last sub-store event.*/ if ( f_fTap == FALSE ) { ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usLastSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND ) { if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } else { return cOCT6100_ERR_FATAL_26; } } } else { if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } /* An Entry was found, now, modify it's value.*/ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex ); /* Set the Sub-Store event first.*/ pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE; pSubStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr; /*=======================================================================*/ /* Program the Sub-Store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pSubStoreEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Set the load/accumulate event now.*/ if ( f_fTap == FALSE ) { pLoadEventEntry->usNextEventPtr = f_usSubStoreEventIndex; } else { /* This is a little tricky, we use the copy event index for accumulating the tapped channel's voice. */ pLoadEventEntry->usNextEventPtr = f_usCopyEventIndex; } /*=======================================================================*/ /* Program the load/accumulate event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Now modify the previous last Sub Store event from another bridge. */ pTempEntry->usNextEventPtr = f_usLoadEventIndex; /*=======================================================================*/ /* Modify the last node of the other bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Set the event pointer info in the bridge stucture. */ pBridgeEntry->usFirstLoadEventPtr = f_usLoadEventIndex; pBridgeEntry->usFirstSubStoreEventPtr = f_usSubStoreEventIndex; pBridgeEntry->usLastSubStoreEventPtr = f_usSubStoreEventIndex; /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == cOCT6100_INVALID_INDEX ) { /* This bridge is the first to generate mixer event. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadEventIndex; pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usSubStoreEventIndex; } else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex ) { /* The two entries were added at the end of the bridge section, */ /* change only the last pointer. */ pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usSubStoreEventIndex; } else if ( usLastSubStoreEventIndex == cOCT6100_MIXER_HEAD_NODE || usLastSubStoreEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr ) { /* The two entries were added at the start of the bridge section, */ /* change only the first pointer. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadEventIndex; } } else /* pBridgeEntry->usNumClients != 0 */ { /* For sanity. */ if ( f_fTap == TRUE ) return cOCT6100_ERR_FATAL_D2; /*=======================================================================*/ /* Program the Load event. */ /* Now find the last load entry of this bridge. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, pBridgeEntry->usFirstSubStoreEventPtr, 0, &usLastLoadEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Add the load/accumulate event to the list. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastLoadEventIndex ); /* Set the load event now. */ pLoadEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Modify the previous last load event. */ /* Now modify the previous last load event. */ pTempEntry->usNextEventPtr = f_usLoadEventIndex; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the Sub-Store event. */ usLastSubStoreEventIndex = pBridgeEntry->usLastSubStoreEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex ); /* Set the Sub-Store event first. */ pSubStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pSubStoreEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Modify the previous last sub store event of the bridge. */ /* Now modify the last Load event of the bridge. */ pTempEntry->usNextEventPtr = f_usSubStoreEventIndex; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Update the bridge pointers. */ pBridgeEntry->usLastSubStoreEventPtr = f_usSubStoreEventIndex; /* Check if modification to the global mixer pointer are required. */ if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex ) { /* We have a new last bridge pointer. */ pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usSubStoreEventIndex; } } if ( f_fTap == TRUE ) { if ( pEchoChanEntry->usRinTsstIndex == cOCT6100_INVALID_INDEX ) { /* Remove the mute on the Rin port. */ UINT32 ulTempData; UINT32 ulMask; UINT32 ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usChanIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Configure the level control. */ UINT32 ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinLevelControlOfst.usDwordOffset * 4; UINT32 ulFeatureBitOffset = pSharedInfo->MemoryMap.RinLevelControlOfst.byBitOffset; UINT32 ulFeatureFieldLength = pSharedInfo->MemoryMap.RinLevelControlOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set the DC filter to pass through.*/ ulTempData |= ( cOCT6100_PASS_THROUGH_LEVEL_CONTROL << ulFeatureBitOffset ); /* First read the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the event entries as reserved. */ pLoadEventEntry->fReserved = TRUE; pSubStoreEventEntry->fReserved = TRUE; /* Store the event indexes into the channel structure. */ pEchoChanEntry->usLoadEventIndex = f_usLoadEventIndex; pEchoChanEntry->usSubStoreEventIndex = f_usSubStoreEventIndex; /* Check if must insert the Sin copy event in the list. */ if ( fAddSinCopy == TRUE ) { /* Now insert the Sin copy event into the list. */ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usChanIndex ); } /* Check if the Rin silence event can be cleared now that the */ /* channel has been added to a conference. */ if ( ( f_fTap == FALSE ) && ( pEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } } /* Configure the RIN copy mixer entry and memory - if using the RIN port. */ if ( ( f_fFlexibleConfBridge == TRUE ) && ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) ) { if ( pEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pEchoChanEntry->usRinTsstIndex, pEchoChanEntry->usExtraRinTsiMemIndex, pEchoChanEntry->TdmConfig.byRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } if ( pBridgeEntry->fDominantSpeakerSet == TRUE ) { /* Dominant speaker is another channel. Set accordingly for this new conference channel. */ ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, pBridgeEntry->usDominantSpeakerChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { /* No dominant speaker set on this bridge yet. */ ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Update the bridge entry. */ pBridgeEntry->usNumClients++; /* Store the bridge index into the channel structure. */ pEchoChanEntry->usBridgeIndex = f_usBridgeIndex; /* Store the copy event index into the channel structure. */ if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { pEchoChanEntry->usSinCopyEventIndex = f_usCopyEventIndex; } else { pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; } /* Remember if the channel is muted in the conference. */ pEchoChanEntry->fMute = f_fMute; /* Remember if the channel is a tap in a conference. */ pEchoChanEntry->fTap = f_fTap; /* We start by not being tapped. */ pEchoChanEntry->fBeingTapped = FALSE; pEchoChanEntry->usTapChanIndex = cOCT6100_INVALID_INDEX; /* Remember the tap bridge index if necessary. */ if ( pEchoChanEntry->fTap == TRUE ) { pEchoChanEntry->usTapBridgeIndex = f_usTapBridgeIndex; } else { pEchoChanEntry->usTapBridgeIndex = cOCT6100_INVALID_INDEX; } /* Indicate that the extra SIN TSI is currently in used by the conference bridge. */ if ( f_ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { pEchoChanEntry->usExtraSinTsiDependencyCnt++; } /* Indicate that the extra RIN TSI is currently in used by the conference bridge. */ if ( ( f_fFlexibleConfBridge == TRUE ) && ( f_ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) ) { pEchoChanEntry->usExtraRinTsiDependencyCnt++; } /* Update the chip stats structure. */ pSharedInfo->ChipStats.usNumEcChanUsingMixer++; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeAddParticipantToChannel Description: Used for the flexible conference bridges. Insert a participant onto a channel that is on a conference. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Bridge index where this channel is located. f_usSourceChannelIndex Source channel to copy voice from. f_usDestinationChannelIndex Destination channel to store resulting voice to. f_usLoadOrAccumulateEventIndex Load or Accumulate allocated event index. f_usStoreEventIndex Store allocated event index. f_usCopyEventIndex Copy allocated event index. f_ulSourceInputPort Source input port of the conference for this channel. f_ulDestinationInputPort Destination input port of the conference for this channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeAddParticipantToChannel UINT32 Oct6100ApiBridgeAddParticipantToChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usSourceChannelIndex, IN UINT16 f_usDestinationChannelIndex, IN UINT16 f_usLoadOrAccumulateEventIndex, IN UINT16 f_usStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT32 f_ulSourceInputPort, IN UINT32 f_ulDestinationInputPort ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pStoreEventEntry; tPOCT6100_API_MIXER_EVENT pTempEntry; tPOCT6100_API_CHANNEL pSourceChanEntry; tPOCT6100_API_CHANNEL pDestinationChanEntry; tPOCT6100_API_FLEX_CONF_PARTICIPANT pSourceParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pDestinationParticipant; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT16 usLastSubStoreEventIndex; UINT16 usLastLoadEventIndex; BOOL fInsertCopy = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceChanEntry, f_usSourceChannelIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceParticipant, pSourceChanEntry->usFlexConfParticipantIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationChanEntry, f_usDestinationChannelIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationParticipant, pDestinationChanEntry->usFlexConfParticipantIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadOrAccumulateEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pStoreEventEntry, f_usStoreEventIndex ); /* Check if we are creating the first event for this channel. */ if ( pDestinationParticipant->fFlexibleMixerCreated == FALSE ) { /*=======================================================================*/ /* Before creating the participant's flexible mixer, make sure the extra Sin */ /* mixer event is programmed correctly for sending the voice stream to the right place. */ /* Configure the SIN copy mixer entry and memory - if using the SOUT port. */ if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { if ( pDestinationChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pDestinationChanEntry->usSinTsstIndex, pDestinationChanEntry->usExtraSinTsiMemIndex, pDestinationChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the extra sin TSI. */ if ( pDestinationChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pDestinationChanEntry->usExtraSinTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*=======================================================================*/ /*=======================================================================*/ /* Program the load event. This is the first event for this new destination channel. */ /* First set the TSI buffer where the resulting stream should be written to. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); /* For sure, we are loading. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Select the TSI memory index according to the source port. */ if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { WriteParams.usWriteData |= pSourceChanEntry->usSinSoutTsiMemIndex; } else /* if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pSourceChanEntry->usExtraRinTsiMemIndex; } /* Set the event type. */ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Set the source channel index. */ pLoadEventEntry->usSourceChanIndex = f_usSourceChannelIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE; /* Select the TSI memory index and PCM law according to the source port. */ if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pDestinationChanEntry->usSinSoutTsiMemIndex; } else /* if ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pDestinationChanEntry->usRinRoutTsiMemIndex; } /* Set the event type. */ pStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE; /* Set the destination channel index. */ pStoreEventEntry->usDestinationChanIndex = f_usDestinationChannelIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pDestinationChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Program the Copy event - if using the SOUT port */ if ( ( f_ulDestinationInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pDestinationChanEntry->fCopyEventCreated == FALSE ) ) { /* The copy event has not been created, create it once for the life of the participant on the bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= pDestinationChanEntry->usExtraSinTsiMemIndex; WriteParams.usWriteData |= pDestinationChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pDestinationChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pDestinationChanEntry->fCopyEventCreated = TRUE; /* Set insert copy flag. */ fInsertCopy = TRUE; } /*=======================================================================*/ /*=======================================================================*/ /*=======================================================================*/ /* Now, insert the events into the current list. */ /*=======================================================================*/ /*=======================================================================*/ /* This is the first entry for this channel. Insert the two events at the head */ /* of the list just after the last Sub-Store or Store event. */ ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, f_usLoadOrAccumulateEventIndex, &usLastSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND ) { if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { usLastSubStoreEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { usLastSubStoreEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } else { return cOCT6100_ERR_FATAL_26; } } /* An entry was found, now, modify it's value. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastSubStoreEventIndex ); /*=======================================================================*/ /*=======================================================================*/ /* Link the store event first. */ pStoreEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr; /* Link the store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pStoreEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Link the load event now.*/ pLoadEventEntry->usNextEventPtr = f_usStoreEventIndex; /* Link the load event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Now modify the previous last Sub-Store or Store event from another bridge, */ /* such that it links to us. */ pTempEntry->usNextEventPtr = f_usLoadOrAccumulateEventIndex; /* Modify the last node of the other bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Set the event pointer info in the bridge stucture. */ if ( pBridgeEntry->usFirstLoadEventPtr == cOCT6100_INVALID_INDEX ) { /* We only do this once in case of the flexible conference bridges. */ pBridgeEntry->usFirstLoadEventPtr = f_usLoadOrAccumulateEventIndex; pBridgeEntry->usFirstSubStoreEventPtr = f_usStoreEventIndex; } pBridgeEntry->usLastSubStoreEventPtr = f_usStoreEventIndex; /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == cOCT6100_INVALID_INDEX ) { /* This bridge is the first to generate mixer event. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadOrAccumulateEventIndex; pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usStoreEventIndex; } else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == usLastSubStoreEventIndex ) { /* The two entries were added at the end of the bridge section, */ /* change only the last pointer. */ pSharedInfo->MixerInfo.usLastBridgeEventPtr = f_usStoreEventIndex; } else if ( usLastSubStoreEventIndex == cOCT6100_MIXER_HEAD_NODE || usLastSubStoreEventIndex == pSharedInfo->MixerInfo.usLastSoutCopyEventPtr ) { /* The two entries were added at the start of the bridge section, */ /* change only the first pointer.*/ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = f_usLoadOrAccumulateEventIndex; } /*=======================================================================*/ /*=======================================================================*/ /* Insert the copy event if needed in the mixer's list. */ if ( fInsertCopy == TRUE ) { /* Now insert the Sin copy event into the list. */ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usDestinationChannelIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /*=======================================================================*/ /* Update the status of the instance structures. */ pDestinationParticipant->fFlexibleMixerCreated = TRUE; /* Set the event entries as reserved. */ pLoadEventEntry->fReserved = TRUE; pStoreEventEntry->fReserved = TRUE; /* Store the event indexes into the channel structure. */ pDestinationChanEntry->usLoadEventIndex = f_usLoadOrAccumulateEventIndex; pDestinationChanEntry->usSubStoreEventIndex = f_usStoreEventIndex; /*=======================================================================*/ } else /* if ( pDestinationChanEntry->fFlexibleMixerCreated == TRUE ) */ { /*=======================================================================*/ /* Program the Accumulate event. */ /* First set the TSI buffer where the resulting stream should be written to. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); /* For sure, we are accumulating. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; /* Select the TSI memory index according to the source port. */ if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { WriteParams.usWriteData |= pSourceChanEntry->usSinSoutTsiMemIndex; } else /* if ( f_ulSourceInputPort == cOCT6100_CHANNEL_PORT_RIN ) */ { WriteParams.usWriteData |= pSourceChanEntry->usExtraRinTsiMemIndex; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /*=======================================================================*/ /* Now, insert the Accumulate event into the current list. */ /*=======================================================================*/ /*=======================================================================*/ /* Use the Load entry of this channel. */ usLastLoadEventIndex = pDestinationChanEntry->usLoadEventIndex; /* Add the Accumulate event to the list. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usLastLoadEventIndex ); /* Set the accumulate event now. */ pLoadEventEntry->usNextEventPtr = pTempEntry->usNextEventPtr; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadOrAccumulateEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pLoadEventEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Modify the previous Load event. */ /* Now modify the previous Load event. */ pTempEntry->usNextEventPtr = f_usLoadOrAccumulateEventIndex; WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Update the status of the instance structures. */ /* Set the Accumulate event entry as reserved. */ pLoadEventEntry->fReserved = TRUE; /* Set the Event type. */ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; /* Set the source channel index. */ pLoadEventEntry->usSourceChanIndex = f_usSourceChannelIndex; /*=======================================================================*/ } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanRemoveSer Description: Removes an echo channel from a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeRemove Pointer to conference bridge channel remove structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanRemoveSer UINT32 Oct6100ConfBridgeChanRemoveSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove ) { UINT16 usBridgeIndex; UINT16 usChanIndex = 0; UINT16 usLoadEventIndex; UINT16 usSubStoreEventIndex; UINT16 usCopyEventIndex; UINT32 ulResult; UINT8 fFlexibleConfBridge; UINT8 fTap; /* Check the validity of the channel and conference bridge given. */ ulResult = Oct6100ApiCheckChanRemoveParams( f_pApiInstance, f_pConfBridgeRemove, &usBridgeIndex, &usChanIndex, &fFlexibleConfBridge, &fTap, &usLoadEventIndex, &usSubStoreEventIndex, &usCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources reserved for the conference bridge. */ ulResult = Oct6100ApiReleaseChanEventResources( f_pApiInstance, f_pConfBridgeRemove, usBridgeIndex, usChanIndex, fFlexibleConfBridge, usLoadEventIndex, usSubStoreEventIndex, usCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear the memory entry for this channel within the bridge. */ ulResult = Oct6100ApiBridgeEventRemove( f_pApiInstance, f_pConfBridgeRemove, usBridgeIndex, usChanIndex, fFlexibleConfBridge, usLoadEventIndex, usSubStoreEventIndex, usCopyEventIndex, fTap ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChanRemoveParams Description: Check the validity of the channel and conference bridge given. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeRemove Pointer to conference bridge channenl add structure. f_pusBridgeIndex Pointer to the bridge index. f_pfFlexibleConfBridge If this is a flexible conference bridge f_pusChannelIndex Pointer to the channel index to be added to the bridge. f_pusLoadEventIndex Pointer to the load mixer event. f_pusSubStoreEventIndex Pointer to the sub-store mixer event. f_pusCopyEventIndex Pointer to the copy mixer event. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChanRemoveParams UINT32 Oct6100ApiCheckChanRemoveParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, OUT PUINT16 f_pusBridgeIndex, OUT PUINT16 f_pusChannelIndex, OUT PUINT8 f_pfFlexibleConfBridge, OUT PUINT8 f_pfTap, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT16 f_pusCopyEventIndex ) { UINT32 ulEntryOpenCnt; tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; /* Verify if the remove all flag is valid. */ if ( f_pConfBridgeRemove->fRemoveAll != TRUE && f_pConfBridgeRemove->fRemoveAll != FALSE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_REMOVE_ALL; /* Check the channel handle only if the remove all flag is set to FALSE. */ if ( f_pConfBridgeRemove->fRemoveAll == FALSE ) { /*=====================================================================*/ /* Check the channel handle. */ if ( (f_pConfBridgeRemove->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeRemove->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeRemove->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; if ( pEchoChanEntry->fBeingTapped == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_DEPENDENCY; /*=====================================================================*/ *f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex; *f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex; *f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex; *f_pusCopyEventIndex = pEchoChanEntry->usSinCopyEventIndex; /* Check if the channel is really part of the bridge. */ if ( *f_pusBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Return whether this is a flexible bridge or not. */ *f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing; /* Return whether this is a tap or not. */ *f_pfTap = pEchoChanEntry->fTap; } else /* f_pConfBridgeRemove->fRemoveAll == TRUE */ { /* Check the provided handle. */ if ( (f_pConfBridgeRemove->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusBridgeIndex = (UINT16)( f_pConfBridgeRemove->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeRemove->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* This information is not currently available. */ *f_pusLoadEventIndex = cOCT6100_INVALID_INDEX; *f_pusSubStoreEventIndex = cOCT6100_INVALID_INDEX; *f_pusCopyEventIndex = cOCT6100_INVALID_INDEX; /* Return whether this is a flexible bridge or not. */ *f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing; *f_pfTap = FALSE; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseChanEventResources Description: Release all resources reserved to the channel part of the conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeRemove Pointer to conference bridge channel add structure. f_usBridgeIndex Index of the bridge structure within the API's bridge list. f_usChanIndex Index of the channel structure within the API's channel list f_fFlexibleConfBridge If this is a flexible conference bridge. f_usLoadEventIndex Index of the load mixer event. f_usSubStoreEventIndex Index of the sub-store mixer event. f_usCopyEventIndex Index of the copy mixer event. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseChanEventResources UINT32 Oct6100ApiReleaseChanEventResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulResult; UINT32 i; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; if ( f_pConfBridgeRemove->fRemoveAll == FALSE ) { tPOCT6100_API_CHANNEL pTempEchoChanEntry; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Release an entry for the store event in the mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the Sin copy event in the mixer memory. */ /* This value can be invalid if the Rin port was used - no need to release. */ if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Sout port was used - no need to release. */ if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraRinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* Must travel all clients of this conference and release the load or accumulate events for */ /* all participants which can hear us and vice versa. */ /* Search through the list of API channel entry for the ones on to this bridge. */ for ( i = 0; ( i < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ); i++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, i ); /* Channel reserved? */ if ( ( i != f_usChanIndex ) && pTempEchoChanEntry->fReserved == TRUE ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can hear this participant. */ if ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) { /* Must release the allocated mixer event. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } /* Check if this participant can hear us. */ if ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 ) { /* Must release the allocated mixer event. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } } } } else /* f_pConfBridgeRemove->fRemoveAll == TRUE */ { UINT32 ulListenerMaskIndex; ulResult = cOCT6100_ERR_OK; /* Search through the list of API channel entry for the ones on to this bridge.*/ for ( i = 0; ( i < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ); i++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i ); /* Channel reserved? */ if ( pEchoChanEntry->fReserved == TRUE ) { /* On current bridge? */ if ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Release an entry for the Store event in the Mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the Sin copy event in the Mixer memory. */ /* This value can be invalid if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Sout port was used - no need to release. */ if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraRinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* Check if something can be freed. */ for ( ulListenerMaskIndex = 0; ulListenerMaskIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulListenerMaskIndex ++ ) { if ( pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX ) { /* Must release the allocated mixer event. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } pParticipant->ausLoadOrAccumulateEventIndex[ ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } } } } if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { if ( f_pConfBridgeRemove->fRemoveAll == FALSE ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); /* Release the entry for the load event in the mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usLoadEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the substract and store event in the mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the Sin copy event in the Mixer memory. */ /* This value can be invalid if the Rin port was used - no need to release. */ if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_usCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry. */ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } } else /* f_pConfBridgeRemove->fRemoveAll == TRUE */ { /* Search through the list of API channel entry for the ones on to the specified bridge.*/ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i ); if ( pEchoChanEntry->fReserved == TRUE ) { if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) ) { /* Release the entry for the load event in the mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usLoadEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the substract and store event in the Mixer memory. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSubStoreEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /* Release an entry for the Sin copy event in the Mixer memory. */ /* This value can be invalid if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } /* This value can be 0 if the Rin port was used - no need to release. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the extra TSI entry.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pEchoChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } } } } } } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeEventRemove Description: Remove the event from the global event list of the chip and update the bridge and channel structures. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeRemove Pointer to a conference bridge channel remove structure. f_usBridgeIndex Index of the current bridge in the API list. f_usChanIndex Index of the current channel in the API list. f_fFlexibleConfBridge If this is a flexible conference bridge. f_usLoadEventIndex Allocated entry for the Load event of the channel. f_usSubStoreEventIndex Allocated entry for the substract and store event of the channel. f_usCopyEventIndex Allocated entry for the copy event of the channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeEventRemove UINT32 Oct6100ApiBridgeEventRemove ( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_REMOVE f_pConfBridgeRemove, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT8 f_fFlexibleConfBridge, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT16 f_usCopyEventIndex, IN UINT8 f_fTap ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pSubStoreEventEntry; tPOCT6100_API_MIXER_EVENT pCopyEventEntry = NULL; tPOCT6100_API_MIXER_EVENT pTempEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_API_CHANNEL pTempEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT16 usPreviousEventIndex; UINT16 usTempEventIndex; UINT32 ulLoopCount = 0; UINT16 usReadData; UINT16 usChannelIndex; UINT32 i; BOOL fRemoveSinCopy = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, f_usBridgeIndex ); /* If no client on the bridge, and the remove all option is specified, return here. */ if ( ( pBridgeEntry->usNumClients == 0 ) && ( f_pConfBridgeRemove->fRemoveAll == TRUE ) ) return cOCT6100_ERR_OK; /* Make sure the dominant speaker feature is disabled first. */ if ( pBridgeEntry->fDominantSpeakerSet == TRUE ) { /* If all channels are to be removed or if the dominant speaker is the current channel to be removed. */ if ( ( f_pConfBridgeRemove->fRemoveAll == TRUE ) || ( ( f_pConfBridgeRemove->fRemoveAll == FALSE ) && ( pBridgeEntry->usDominantSpeakerChanIndex == f_usChanIndex ) ) ) { /* Disable on all channels part of this conference. */ /* Search through the list of API channel entry for the ones on to this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( pTempEchoChanEntry->fReserved == TRUE ) { if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, usChannelIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Save this in the conference bridge structure. */ pBridgeEntry->fDominantSpeakerSet = FALSE; pBridgeEntry->usDominantSpeakerChanIndex = cOCT6100_INVALID_INDEX; } else { /* Only disable this current channel. */ ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; UINT16 ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ]; UINT32 ulMutePortChannelIndex; for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX; if ( f_pConfBridgeRemove->fRemoveAll == FALSE ) { /* The channel index is valid. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Search through the list of API channel entry for the ones on to this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can hear this participant. */ if ( ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pParticipant->fFlexibleMixerCreated == TRUE ) && ( pTempEchoChanEntry->fMute == FALSE ) ) { /* First update the current channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, f_usBridgeIndex, usChannelIndex, f_usChanIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if this participant can hear us. */ if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pTempParticipant->fFlexibleMixerCreated == TRUE ) && ( pEchoChanEntry->fMute == FALSE ) ) { /* Then update this channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, f_usBridgeIndex, f_usChanIndex, usChannelIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Remember to mute the port on this channel. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usChannelIndex ) { break; } else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) { ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usChannelIndex; break; } } } } } } /* Check if must manually clear the Sin copy event. */ if ( ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( pEchoChanEntry->fCopyEventCreated == TRUE ) ) { /* Transform event into no-operation. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now remove the copy event from the event list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pEchoChanEntry->fCopyEventCreated = FALSE; } /* Release an entry for the participant. */ ulResult = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pEchoChanEntry->usFlexConfParticipantIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /*=======================================================================*/ /* Update the event and channel API structure */ pEchoChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; /* Indicate that the extra SIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraSinTsiDependencyCnt--; pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } else { /* Decrement the dependency count, but do not clear the mem index. */ pEchoChanEntry->usExtraSinTsiDependencyCnt--; } /* Indicate that the extra RIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraRinTsiDependencyCnt--; pEchoChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX; } /* Update the chip stats structure. */ pSharedInfo->ChipStats.usNumEcChanUsingMixer--; pBridgeEntry->usNumClients--; /* For sure we have to mute the ports of this channel to be removed. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pEchoChanEntry->usRinTsstIndex, pEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); if ( pTempParticipant->fFlexibleMixerCreated == FALSE ) { /* Check if the Rin port must be muted on this channel. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, ausMutePortChannelIndexes[ ulMutePortChannelIndex ], pTempEchoChanEntry->usRinTsstIndex, pTempEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */ { /* No more channels to check for muting. */ break; } } } else /* if ( f_pConfBridgeRemove->fRemoveAll == TRUE ) */ { UINT16 usMainChannelIndex; for ( usMainChannelIndex = 0 ; usMainChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ; usMainChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usMainChannelIndex ); /* If this channel is on the bridge we are closing all the channels. */ if ( ( pEchoChanEntry->fReserved == TRUE ) && ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) ) { /* Remember to mute the port on this channel. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usMainChannelIndex ) { break; } else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) { ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usMainChannelIndex; break; } } mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Search through the list of API channel entry for the ones on to this bridge. */ for ( usChannelIndex = (UINT16)( usMainChannelIndex + 1 ); usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( pTempEchoChanEntry->fReserved == TRUE ) { if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Everyone that we can hear must be removed. */ if ( ( ( pParticipant->ulListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pParticipant->fFlexibleMixerCreated == TRUE ) && ( pTempEchoChanEntry->fMute == FALSE ) ) { /* First update the current channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, f_usBridgeIndex, usChannelIndex, usMainChannelIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if this participant can hear us. */ if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pTempParticipant->fFlexibleMixerCreated == TRUE ) && ( pEchoChanEntry->fMute == FALSE ) ) { /* Then update this channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, f_usBridgeIndex, usMainChannelIndex, usChannelIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } /* Check if must manually clear the Sin copy event. */ if ( ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( pEchoChanEntry->fCopyEventCreated == TRUE ) ) { /* Transform event into no-operation. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now remove the copy event from the event list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pEchoChanEntry->fCopyEventCreated = FALSE; } /* Release an entry for the participant. */ ulResult = Oct6100ApiReleaseFlexConfParticipantEntry( f_pApiInstance, pEchoChanEntry->usFlexConfParticipantIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return ulResult; } /*=======================================================================*/ /* Update the event and channel API structure */ pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; /* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraSinTsiDependencyCnt--; pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } else { /* Decrement the dependency count, but do not clear the mem index. */ pEchoChanEntry->usExtraSinTsiDependencyCnt--; } /* Indicate that the Extra RIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraRinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraRinTsiDependencyCnt--; pEchoChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX; } /* Update the chip stats structure. */ pSharedInfo->ChipStats.usNumEcChanUsingMixer--; } } /* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); if ( pTempParticipant->fFlexibleMixerCreated == FALSE ) { /* Check if the Rin port must be muted on this channel. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, ausMutePortChannelIndexes[ ulMutePortChannelIndex ], pTempEchoChanEntry->usRinTsstIndex, pTempEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */ { /* No more channels to check for muting. */ break; } /* Clear the flexible conf bridge participant index. */ pTempEchoChanEntry->usFlexConfParticipantIndex = cOCT6100_INVALID_INDEX; } /* No more clients on bridge. */ pBridgeEntry->usNumClients = 0; } } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { if ( f_pConfBridgeRemove->fRemoveAll == FALSE ) { /* The channel index is valid. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); if ( f_fTap == TRUE ) { mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pBridgeEntry, pEchoChanEntry->usTapBridgeIndex ); } /* Get a pointer to the event entry. */ if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX ) mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, f_usCopyEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex ); /*=======================================================================*/ /* Check if have to modify the silence load event. */ if ( pBridgeEntry->usNumClients != 1 ) { if ( pBridgeEntry->usSilenceLoadEventPtr != cOCT6100_INVALID_INDEX ) { if ( pBridgeEntry->usSilenceLoadEventPtr == f_usLoadEventIndex ) { /* Make sure the next event becomes the silence event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pLoadEventEntry->usNextEventPtr * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD; WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software model to remember the silence load. */ pBridgeEntry->usSilenceLoadEventPtr = pLoadEventEntry->usNextEventPtr; } else { /* Somebody else is the silence event, no need to worry. */ } } } /*=======================================================================*/ /*=======================================================================*/ /* Clear the Load event. */ /* First verify if the event to be removed was a load event. */ if ( f_usLoadEventIndex == pBridgeEntry->usLoadIndex ) { /* Change the next entry if one is present to a load event to keep the bridge alive. */ if ( pBridgeEntry->usNumClients == 1 ) { /* There is no other entry on the bridge, no need to search for an Accumulate event. */ pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX; /* Clear the silence event, for sure it's invalid. */ pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX; } else { /* Search for an accumulate event to tranform into a Load event. */ usTempEventIndex = pLoadEventEntry->usNextEventPtr; ulLoopCount = 0; /* Find the copy entry before the entry to remove. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE ) { if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE ) { /* Change this entry into a load event. */ ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set this entry as the load index. */ pBridgeEntry->usLoadIndex = usTempEventIndex; /* Update the software model. */ pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Stop searching. */ break; } /* Go to the next entry into the list. */ usTempEventIndex = pTempEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_9B; } } } WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Clear the substract and store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Clear the Copy event - if needed. */ if ( f_usCopyEventIndex != cOCT6100_INVALID_INDEX ) { /* Transform event into no-operation. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( f_fTap == FALSE ) { /* Set remove Sin copy event flag to remove the event from the mixer's list. */ fRemoveSinCopy = TRUE; /* Clear the copy event created flag. */ pEchoChanEntry->fCopyEventCreated = FALSE; } } /*=======================================================================*/ /*=======================================================================*/ /* Now remove the event from the event list. */ /* Look for the entry that is pointing at the first entry of our bridge. */ if ( f_fTap == FALSE ) { ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex ); } else { ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, pEchoChanEntry->usTapBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex ); } if ( ulResult != cOCT6100_ERR_OK ) { /* If the entry was not found, we now check for the Sout copy event section/list. */ if ( ulResult == cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND ) { if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { /* No Sout copy, it has to be the head node. */ usPreviousEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { /* Use the last Sout copy event. */ usPreviousEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } else { return cOCT6100_ERR_FATAL_27; } } if ( pBridgeEntry->usNumClients == 1 ) { /* An entry was found, now, modify it's value. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex ); /* Now modify the previous last Sub Store event from another bridge. */ pTempEntry->usNextEventPtr = pSubStoreEventEntry->usNextEventPtr; /*=======================================================================*/ /* Modify the last node of the previous bridge to point to the next bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Set the event pointer info in the bridge stucture. */ pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX; /*=======================================================================*/ /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex && pSharedInfo->MixerInfo.usLastBridgeEventPtr == f_usSubStoreEventIndex ) { /* There is no more bridge entry in the mixer link list. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastBridgeEventPtr = cOCT6100_INVALID_INDEX; } else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex ) { pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pSubStoreEventEntry->usNextEventPtr; } else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == f_usSubStoreEventIndex ) { pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex; } /*=======================================================================*/ if ( f_fTap == TRUE ) { /* The channel being tapped is not tapped anymore. */ /* There is no direct way of finding the tap, so loop through all channels and find the */ /* tapped channel index. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( pTempEchoChanEntry->usTapChanIndex == f_usChanIndex ) { tPOCT6100_API_CONF_BRIDGE pTempBridgeEntry; pTempEchoChanEntry->fBeingTapped = FALSE; pTempEchoChanEntry->usTapChanIndex = cOCT6100_INVALID_INDEX; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( pSharedInfo, pTempBridgeEntry, f_usBridgeIndex ); pTempBridgeEntry->usNumTappedClients--; /* Re-assign Rin TSST for tapped channel. */ if ( pTempEchoChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pTempEchoChanEntry->usRinTsstIndex, pTempEchoChanEntry->usRinRoutTsiMemIndex, pTempEchoChanEntry->TdmConfig.byRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } break; } } /* Check if our model is broken. */ if ( usChannelIndex == pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_FATAL_D3; } } else /* pBridgeEntry->usNumClients > 1 */ { if ( pBridgeEntry->usFirstLoadEventPtr != f_usLoadEventIndex ) { /* Now find the load entry of this bridge pointing at this load event */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, f_usLoadEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Remove the load event to the list. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex ); /* Now modify the previous last Sub Store event from another bridge. */ pTempEntry->usNextEventPtr = pLoadEventEntry->usNextEventPtr; /*=======================================================================*/ /* Modify the previous node. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Now find the last load entry of this bridge ( the one pointing at the first sub-store event ). */ if ( pBridgeEntry->usFirstSubStoreEventPtr == f_usSubStoreEventIndex ) { /* Must start with the first load to get the entry before the first sub store. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstLoadEventPtr, f_usSubStoreEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { /* Must start with the first load to get the entry before the first sub store. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pBridgeEntry->usFirstSubStoreEventPtr, f_usSubStoreEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex ); /* Now modify the last load event of the bridge. */ pTempEntry->usNextEventPtr = pSubStoreEventEntry->usNextEventPtr; /*=======================================================================*/ /* Modify the last node of the other bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = (UINT16)( pTempEntry->usNextEventPtr ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Update the bridge pointers. */ if ( pBridgeEntry->usFirstLoadEventPtr == f_usLoadEventIndex ) pBridgeEntry->usFirstLoadEventPtr = pLoadEventEntry->usNextEventPtr; if ( pBridgeEntry->usFirstSubStoreEventPtr == f_usSubStoreEventIndex ) pBridgeEntry->usFirstSubStoreEventPtr = pSubStoreEventEntry->usNextEventPtr; if ( pBridgeEntry->usLastSubStoreEventPtr == f_usSubStoreEventIndex ) pBridgeEntry->usLastSubStoreEventPtr = usPreviousEventIndex; /*=======================================================================*/ /*=======================================================================*/ /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == f_usLoadEventIndex ) { pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pLoadEventEntry->usNextEventPtr; } if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == f_usSubStoreEventIndex ) { pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex; } /*=======================================================================*/ } /* Check if must remove the Sin copy event from the event list. */ if ( fRemoveSinCopy == TRUE ) { /* Now remove the copy event from the event list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, f_usCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Get the channel. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); /* Reprogram the TSST entry correctly if the Extra SIN TSI entry was released. */ if ( ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) && ( f_fTap == FALSE ) ) { if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pEchoChanEntry->usSinTsstIndex, pEchoChanEntry->usSinSoutTsiMemIndex, pEchoChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the original sin TSI. */ if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the event entries as free. */ pLoadEventEntry->fReserved = FALSE; pLoadEventEntry->usEventType = cOCT6100_INVALID_INDEX; pLoadEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; pSubStoreEventEntry->fReserved = FALSE; pSubStoreEventEntry->usEventType = cOCT6100_INVALID_INDEX; pSubStoreEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; if ( pCopyEventEntry != NULL ) { pCopyEventEntry->fReserved = FALSE; pCopyEventEntry->usEventType = cOCT6100_INVALID_INDEX; pCopyEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; } pBridgeEntry->usNumClients--; /*=======================================================================*/ /* Update the event and channel API structure */ pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; /* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraSinTsiDependencyCnt--; pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } else { /* Decrement the dependency count, but do not clear the mem index. */ pEchoChanEntry->usExtraSinTsiDependencyCnt--; } /* Update the chip stats structure. */ pSharedInfo->ChipStats.usNumEcChanUsingMixer--; if ( f_fTap == TRUE ) { /* Can now close the bridge. */ tOCT6100_CONF_BRIDGE_CLOSE BridgeClose; Oct6100ConfBridgeCloseDef( &BridgeClose ); BridgeClose.ulConfBridgeHndl = cOCT6100_HNDL_TAG_CONF_BRIDGE | (pBridgeEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pEchoChanEntry->usTapBridgeIndex; ulResult = Oct6100ConfBridgeCloseSer( f_pApiInstance, &BridgeClose ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pEchoChanEntry->usTapBridgeIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->fTap = FALSE; } /* Check if the Rin port must be muted. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pEchoChanEntry->usRinTsstIndex, pEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ } else /* f_ulBridgeChanRemove->fRemoveAll == TRUE ) */ { UINT16 usNextEventPtr; /* Save the next event pointer before invalidating everything. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, pBridgeEntry->usLastSubStoreEventPtr ); usNextEventPtr = pSubStoreEventEntry->usNextEventPtr; /* Search through the list of API channel entry for the ones on to the specified bridge. */ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i ); if ( pEchoChanEntry->fReserved == TRUE ) { if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) ) { /* Check if we are being tapped. If so, remove the channel that taps us from the conference. */ /* The removal of the channel will make sure the Rin TSST is re-assigned. */ if ( pEchoChanEntry->fBeingTapped == TRUE ) { tOCT6100_CONF_BRIDGE_CHAN_REMOVE ChanRemove; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, pEchoChanEntry->usTapChanIndex ); ulResult = Oct6100ConfBridgeChanRemoveDef( &ChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ChanRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | (pTempEchoChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pEchoChanEntry->usTapChanIndex; ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &ChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /* Clear the Load event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Clear the Substract and store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Clear the SIN copy event.*/ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { /* Transform event into no-operation. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get a pointer to the event entry. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, pEchoChanEntry->usSinCopyEventIndex ); /* Update the next event pointer if required. */ if ( usNextEventPtr == pEchoChanEntry->usSinCopyEventIndex ) usNextEventPtr = pCopyEventEntry->usNextEventPtr; /* Now remove the copy event from the event list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear the copy event created flag. */ pEchoChanEntry->fCopyEventCreated = FALSE; } /*=======================================================================*/ /*=======================================================================*/ /* Update the event and channel API structure */ /* Reprogram the TSST entry correctly if the Extra SIN TSI entry was released.*/ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { if ( pEchoChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pEchoChanEntry->usSinTsstIndex, pEchoChanEntry->usSinSoutTsiMemIndex, pEchoChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the original Sin TSI. */ if ( pEchoChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, pEchoChanEntry->usLoadEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, pEchoChanEntry->usSubStoreEventIndex ); /* Set the event entries as free. */ pLoadEventEntry->fReserved = FALSE; pLoadEventEntry->usEventType = cOCT6100_INVALID_EVENT; pLoadEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; pSubStoreEventEntry->fReserved = FALSE; pSubStoreEventEntry->usEventType = cOCT6100_INVALID_EVENT; pSubStoreEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; if ( pCopyEventEntry != NULL ) { pCopyEventEntry->fReserved = FALSE; pCopyEventEntry->usEventType = cOCT6100_INVALID_EVENT; pCopyEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; } /* Indicate that the Extra SIN TSI is not needed anymore by the mixer. */ if ( pEchoChanEntry->usExtraSinTsiDependencyCnt == 1 ) { pEchoChanEntry->usExtraSinTsiDependencyCnt--; pEchoChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; } else { /* Decrement the dependency count, but do not clear the mem index. */ pEchoChanEntry->usExtraSinTsiDependencyCnt--; } /* Invalidate the channel entry. */ pEchoChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX; pEchoChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; /* Update the chip stats structure. */ pSharedInfo->ChipStats.usNumEcChanUsingMixer--; /*=======================================================================*/ } } } ulResult = Oct6100ApiGetPrevLastSubStoreEvent( f_pApiInstance, f_usBridgeIndex, pBridgeEntry->usFirstLoadEventPtr, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND == ulResult ) { if ( pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { usPreviousEventIndex = cOCT6100_MIXER_HEAD_NODE; } else { usPreviousEventIndex = pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } } else { return cOCT6100_ERR_FATAL_28; } } /* An Entry was found, now, modify it's value. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex ); /* Now modify the previous last Sub Store event from another bridge.*/ /* It will now point at the next bridge, or copy events. */ pTempEntry->usNextEventPtr = usNextEventPtr; /*=======================================================================*/ /* Modify the last node of the other bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = pTempEntry->usNextEventPtr; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == pBridgeEntry->usFirstLoadEventPtr && pSharedInfo->MixerInfo.usLastBridgeEventPtr == pBridgeEntry->usLastSubStoreEventPtr ) { /* This bridge was the only one with event in the list. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastBridgeEventPtr = cOCT6100_INVALID_INDEX; } else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == pBridgeEntry->usFirstLoadEventPtr ) { /* This bridge was the first bridge. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = usNextEventPtr; } else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == pBridgeEntry->usLastSubStoreEventPtr ) { /* This bridge was the last bridge.*/ pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex; } /*=======================================================================*/ /* Set the event pointer info in the bridge stucture. */ pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usLastSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX; pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX; /* Set the number of clients to 0. */ pBridgeEntry->usNumClients = 0; /* Search through the list of API channel entry for the ones on to the specified bridge. */ for ( i = 0; i < pSharedInfo->ChipConfig.usMaxChannels; i++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, i ); if ( pEchoChanEntry->fReserved == TRUE ) { if ( ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) && ( pEchoChanEntry->fTap == FALSE ) ) { pEchoChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; /* Check if the Rin port must be muted. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, (UINT16)( i & 0xFFFF ), pEchoChanEntry->usRinTsstIndex, pEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeRemoveParticipantFromChannel Description: This will remove a flexible conference participant from a channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Bridge index where this channel is located. f_usSourceChannelIndex Source channel to copy voice from. f_usDestinationChannelIndex Destination channel to store resulting voice to. f_fRemovePermanently Whether to remove permanently this participant. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeRemoveParticipantFromChannel UINT32 Oct6100ApiBridgeRemoveParticipantFromChannel( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usSourceChannelIndex, IN UINT16 f_usDestinationChannelIndex, IN UINT8 f_fRemovePermanently ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pStoreEventEntry; tPOCT6100_API_MIXER_EVENT pCopyEventEntry; tPOCT6100_API_MIXER_EVENT pTempEntry; tPOCT6100_API_MIXER_EVENT pLoadTempEntry; tPOCT6100_API_MIXER_EVENT pLastEventEntry; tPOCT6100_API_MIXER_EVENT pLastLoadOrAccumulateEventEntry; tPOCT6100_API_CHANNEL pSourceChanEntry; tPOCT6100_API_CHANNEL pDestinationChanEntry; tPOCT6100_API_FLEX_CONF_PARTICIPANT pSourceParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pDestinationParticipant; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 ulLoopCount; UINT16 usLastLoadEventIndex; UINT16 usLoadOrAccumulateEventIndex; UINT16 usTempEventIndex; UINT16 usPreviousEventIndex; UINT16 usLastEventIndex; UINT16 usReadData; BOOL fLastEvent = FALSE; BOOL fSoutCopyEvent = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceChanEntry, f_usSourceChannelIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pSourceParticipant, pSourceChanEntry->usFlexConfParticipantIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationChanEntry, f_usDestinationChannelIndex ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pDestinationParticipant, pDestinationChanEntry->usFlexConfParticipantIndex ); /* Check if the mixer has been created on this channel. */ if ( pDestinationParticipant->fFlexibleMixerCreated == TRUE ) { /*=======================================================================*/ /* Clear the Load or Accumulate event.*/ usTempEventIndex = pDestinationChanEntry->usLoadEventIndex; ulLoopCount = 0; /* Find the Load or Accumulate event entry. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, usTempEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pStoreEventEntry, pDestinationChanEntry->usSubStoreEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); pLastEventEntry = pLoadEventEntry; pLastLoadOrAccumulateEventEntry = pLoadEventEntry; usLastLoadEventIndex = usTempEventIndex; usLastEventIndex = usTempEventIndex; while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE ) { /* If this is the entry we are looking for. */ if ( pTempEntry->usSourceChanIndex == f_usSourceChannelIndex ) { /* Check if this is a Load or Accumulate event. */ if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD ) { /* This is the first entry. Check if next entry is an accumulate. */ pLoadTempEntry = pTempEntry; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, pTempEntry->usNextEventPtr ); if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE ) { /* Change this entry into a Load event. */ ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pLoadTempEntry->usNextEventPtr * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the channel information with this new load event. */ pDestinationChanEntry->usLoadEventIndex = pLoadTempEntry->usNextEventPtr; /* Update the software model. */ pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Get the previous event. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex ); usLastEventIndex = usPreviousEventIndex; /* Stop searching. */ break; } else if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE ) { /* Get back the event to remove. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); /* This is the only event on this channel so we can clear everything up. */ fLastEvent = TRUE; /* Get the previous event. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex ); usLastEventIndex = usPreviousEventIndex; /* Stop searching. */ break; } else { /* Software model is broken. */ return cOCT6100_ERR_FATAL_C5; } } else if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE ) { /* Simply remove the entry. */ /* Get the previous event. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usTempEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLastEventEntry, usPreviousEventIndex ); usLastEventIndex = usPreviousEventIndex; /* Stop searching. */ break; } else { /* Software model is broken. */ return cOCT6100_ERR_FATAL_C6; } } pLastLoadOrAccumulateEventEntry = pTempEntry; usLastLoadEventIndex = usTempEventIndex; /* Go to the next entry into the list. */ usTempEventIndex = pTempEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_C8; } /* Check if we found what we were looking for. */ if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE || pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_SUB_STORE ) { /* Software model is broken. */ return cOCT6100_ERR_FATAL_C7; } /*=======================================================================*/ /*=======================================================================*/ /* Clear the Store event - if needed. */ if ( fLastEvent == TRUE ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /*=======================================================================*/ /* Clear the Load or Accumulate event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Save this event index. It's the Load or Accumulate we want to remove from the list later. */ usLoadOrAccumulateEventIndex = usTempEventIndex; /*=======================================================================*/ /*=======================================================================*/ /* Clear the Copy event - if needed. */ if ( ( fLastEvent == TRUE ) && ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( f_fRemovePermanently == TRUE ) ) { /* Transform event into no-operation. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* The event remove from the list will be done below. */ /* Clear the copy event created flag. */ pDestinationChanEntry->fCopyEventCreated = FALSE; } /*=======================================================================*/ /*=======================================================================*/ /*=======================================================================*/ /* Remove the events from the mixer event list.*/ /*=======================================================================*/ /*=======================================================================*/ /*=======================================================================*/ /* Remove the Load or Accumulate event from the event list. */ if ( fLastEvent == FALSE ) { /*=======================================================================*/ /* Remove the Accumulate event from the event list. */ /* We saved the Load or Accumulate event above. We also saved the previous event. Use those. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, usLoadOrAccumulateEventIndex ); /* Now modify the previous last event. */ pLastEventEntry->usNextEventPtr = pLoadEventEntry->usNextEventPtr; /* Modify the previous node. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usLastEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = pLastEventEntry->usNextEventPtr; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if this is the first load event on the bridge. */ if ( pBridgeEntry->usFirstLoadEventPtr == usLoadOrAccumulateEventIndex ) { pBridgeEntry->usFirstLoadEventPtr = pLoadEventEntry->usNextEventPtr; } /* Check if this was the first load of all bridges. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex ) { pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pLoadEventEntry->usNextEventPtr; } /*=======================================================================*/ } else /* if ( fLastEvent == TRUE ) */ { /*=======================================================================*/ /* Remove the Load event from the event list. */ /* Look for the entry that is pointing at the first entry of our mixer. */ ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, cOCT6100_MIXER_HEAD_NODE, usLoadOrAccumulateEventIndex, 0, &usPreviousEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* An Entry was found, now, modify it's value. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousEventIndex ); /* Check if this is a Sout copy event. */ if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_COPY ) { /* No more previous bridges. */ fSoutCopyEvent = TRUE; } /* Now modify the previous last Store or Sub-Store or Head-Node event from another bridge/channel. */ pTempEntry->usNextEventPtr = pStoreEventEntry->usNextEventPtr; /*=======================================================================*/ /*=======================================================================*/ /* Modify the last node of the previous bridge/channel to point to the next bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 4; WriteParams.usWriteData = pTempEntry->usNextEventPtr; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Set the event pointer info in the bridge stucture. */ if ( pBridgeEntry->usFirstLoadEventPtr == pDestinationChanEntry->usLoadEventIndex ) { UINT16 usChannelIndex; tPOCT6100_API_CHANNEL pTempEchoChanEntry; pBridgeEntry->usFirstSubStoreEventPtr = cOCT6100_INVALID_INDEX; pBridgeEntry->usFirstLoadEventPtr = cOCT6100_INVALID_INDEX; /* Find the next channel in this conference that could give us valid values. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( ( usChannelIndex != f_usDestinationChannelIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); if ( pTempParticipant->fFlexibleMixerCreated == TRUE ) { pBridgeEntry->usFirstSubStoreEventPtr = pTempEchoChanEntry->usSubStoreEventIndex; pBridgeEntry->usFirstLoadEventPtr = pTempEchoChanEntry->usLoadEventIndex; break; } } } } } /* Reprogram the TSST entry correctly if the extra SIN TSI entry was released. */ if ( ( pDestinationChanEntry->usExtraSinTsiDependencyCnt == 1 ) && ( f_fRemovePermanently == TRUE ) ) { if ( pDestinationChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pDestinationChanEntry->usSinTsstIndex, pDestinationChanEntry->usSinSoutTsiMemIndex, pDestinationChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the original sin TSI. */ if ( pDestinationChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pDestinationChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pDestinationChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Reprogram the TSST entry correctly if the extra RIN TSI entry was released. */ if ( ( pDestinationChanEntry->usExtraRinTsiDependencyCnt == 1 ) && ( f_fRemovePermanently == TRUE ) ) { if ( pDestinationChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pDestinationChanEntry->usRinTsstIndex, pDestinationChanEntry->usRinRoutTsiMemIndex, pDestinationChanEntry->TdmConfig.byRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*=======================================================================*/ /* Update the global mixer pointers. */ if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex && pSharedInfo->MixerInfo.usLastBridgeEventPtr == pDestinationChanEntry->usSubStoreEventIndex ) { /* There is no more bridge entry in the mixer link list. */ pSharedInfo->MixerInfo.usFirstBridgeEventPtr = cOCT6100_INVALID_INDEX; pSharedInfo->MixerInfo.usLastBridgeEventPtr = cOCT6100_INVALID_INDEX; } else if ( pSharedInfo->MixerInfo.usFirstBridgeEventPtr == usLoadOrAccumulateEventIndex ) { pSharedInfo->MixerInfo.usFirstBridgeEventPtr = pStoreEventEntry->usNextEventPtr; } else if ( pSharedInfo->MixerInfo.usLastBridgeEventPtr == pDestinationChanEntry->usSubStoreEventIndex ) { pSharedInfo->MixerInfo.usLastBridgeEventPtr = usPreviousEventIndex; } /*=======================================================================*/ /*=======================================================================*/ /* Check if must remove the Sin copy event from the list. */ if ( ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) && ( f_fRemovePermanently == TRUE ) ) { /* Now remove the copy event from the event list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pDestinationChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /*=======================================================================*/ if ( f_fRemovePermanently == TRUE ) { /* Set the event entries as free. */ pLoadEventEntry->fReserved = FALSE; pLoadEventEntry->usEventType = cOCT6100_INVALID_EVENT; pLoadEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; pStoreEventEntry->fReserved = FALSE; pStoreEventEntry->usEventType = cOCT6100_INVALID_EVENT; pStoreEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; if ( pDestinationChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pCopyEventEntry, pDestinationChanEntry->usSinCopyEventIndex ); pCopyEventEntry->fReserved = FALSE; pCopyEventEntry->usEventType = cOCT6100_INVALID_EVENT; pCopyEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; } } /* Flexible mixer for this channel not created anymore. */ pDestinationParticipant->fFlexibleMixerCreated = FALSE; /*=======================================================================*/ } /*=======================================================================*/ } else /* if ( pDestinationChanEntry->fFlexibleMixerCreated == FALSE ) */ { /* This point should never be reached. */ return cOCT6100_ERR_FATAL_C9; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanMuteSer Description: Mute an echo channel present on a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMute Pointer to conference bridge mute structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanMuteSer UINT32 Oct6100ConfBridgeChanMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute ) { UINT16 usChanIndex; UINT16 usLoadEventIndex; UINT16 usSubStoreEventIndex; UINT32 ulResult; UINT8 fFlexibleConferencing; /* Check the validity of the channel and conference bridge given. */ ulResult = Oct6100ApiCheckBridgeMuteParams( f_pApiInstance, f_pConfBridgeMute, &usChanIndex, &usLoadEventIndex, &usSubStoreEventIndex, &fFlexibleConferencing ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Modify all resources needed by the conference bridge. */ ulResult = Oct6100ApiUpdateBridgeMuteResources( f_pApiInstance, usChanIndex, usLoadEventIndex, usSubStoreEventIndex, fFlexibleConferencing ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeMuteParams Description: Check the validity of the channel and conference bridge given. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMute Pointer to conference bridge channel mute structure. f_pusChannelIndex Pointer to a channel index. f_pusLoadEventIndex Pointer to a load mixer event index. f_pusSubStoreEventIndex Pointer to a sub-store mixer event index. f_pfFlexibleConfBridge If this is a flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeMuteParams UINT32 Oct6100ApiCheckBridgeMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_MUTE f_pConfBridgeMute, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT8 f_pfFlexibleConfBridge ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeMute->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE; /*=====================================================================*/ /* Check the channel handle.*/ if ( (f_pConfBridgeMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* Check if the channel is bound to a conference bridge. */ if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; /* Check if channel is already muted. */ if ( pEchoChanEntry->fMute == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_ALREADY_MUTED; /* Check if this is a tap channel, which is always mute. */ if ( pEchoChanEntry->fTap == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_ALWAYS_MUTE; /*=====================================================================*/ /*=====================================================================*/ /* Check the conference bridge handle. */ if ( pEchoChanEntry->usBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pEchoChanEntry->usBridgeIndex ) /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( pBridgeEntry->fFlexibleConferencing == FALSE ) { /* Check the event entries.*/ if ( pEchoChanEntry->usLoadEventIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; if ( pEchoChanEntry->usSubStoreEventIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; } /*=====================================================================*/ /* Return the config of the channel and all other important information. */ *f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex; *f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex; *f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBridgeMuteResources Description: Modify the conference bridge entry for this channel in order to mute the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Index of the channel to be muted. f_usLoadEventIndex Allocated entry for the Load event of the channel. f_usSubStoreEventIndex Allocated entry for the substract and store event of the channel. f_fFlexibleConfBridge If this is a flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBridgeMuteResources UINT32 Oct6100ApiUpdateBridgeMuteResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT8 f_fFlexibleConfBridge ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pSubStoreEventEntry; tPOCT6100_API_MIXER_EVENT pTempEntry; UINT32 ulResult; UINT16 usTempEventIndex; UINT32 ulLoopCount; UINT16 usReadData; BOOL fCreateSilenceLoad = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pEchoChanEntry->usBridgeIndex ) if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_CHANNEL pTempEchoChanEntry; UINT16 usChannelIndex; tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; UINT16 ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ]; UINT32 ulMutePortChannelIndex; for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Search through the list of API channel entry for the ones on to this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { if ( pTempEchoChanEntry->usBridgeIndex == pEchoChanEntry->usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if this participant can hear us. */ if ( ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pTempParticipant->fFlexibleMixerCreated == TRUE ) ) { /* Then update this channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, pEchoChanEntry->usBridgeIndex, f_usChanIndex, usChannelIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( pTempParticipant->fFlexibleMixerCreated == FALSE ) { /* Remember to mute the port on this channel. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == usChannelIndex ) { break; } else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) { ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = usChannelIndex; break; } } } } } } } /* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); if ( pTempParticipant->fFlexibleMixerCreated == FALSE ) { /* Check if the Rin port must be muted on this channel. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, ausMutePortChannelIndexes[ ulMutePortChannelIndex ], pTempEchoChanEntry->usRinTsstIndex, pTempEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_MIXER_ALL_MIXER_EVENT_ENTRY_OPENED ) { UINT32 ulTempResult; /* Cleanup resources, unmute channel... */ ulTempResult = Oct6100ApiUpdateBridgeUnMuteResources( f_pApiInstance, f_usChanIndex, f_usLoadEventIndex, f_usSubStoreEventIndex, TRUE ); if ( ulTempResult != cOCT6100_ERR_OK ) return ulTempResult; else return ulResult; } else { return ulResult; } } } } else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */ { /* No more channels to check for muting. */ break; } } } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex ); /*=======================================================================*/ /* Program the Load event. */ /* Create silence load if this is the first event of the bridge. */ if ( f_usLoadEventIndex == pBridgeEntry->usFirstLoadEventPtr ) fCreateSilenceLoad = TRUE; /* First check if this event was a load or an accumulate event, if it's a load */ /* we need to find a new load. */ if ( f_usLoadEventIndex == pBridgeEntry->usLoadIndex ) { /* Change the next entry if one is present to a load event to keep the bridge alive. */ if ( pBridgeEntry->usNumClients == 1 ) { /* There is no other entry on the bridge, no need to search for an Accumulate event. */ pBridgeEntry->usLoadIndex = cOCT6100_INVALID_INDEX; } else { /* Search for an accumulate event to tranform into a Load event. */ usTempEventIndex = pLoadEventEntry->usNextEventPtr; ulLoopCount = 0; /* Find the copy entry before the entry to remove. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE ) { if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE ) { /* Change this entry into a load event. */ ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usTempEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_LOAD); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set this entry as the load index. */ pBridgeEntry->usLoadIndex = usTempEventIndex; /* Update the software model. */ pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; /* Stop searching. */ break; } /* Go to the next entry into the list. */ usTempEventIndex = pTempEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_9B; } } } WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); /* Do not load the sample if the channel is muted. */ if ( fCreateSilenceLoad == TRUE ) { if ( pBridgeEntry->usSilenceLoadEventPtr == cOCT6100_INVALID_INDEX ) { /* Instead of No-oping, load the silence TSI, to make sure the other conferences before us are not heard. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_LOAD; WriteParams.usWriteData |= 1534; /* TSI index 1534 reserved for silence */ /* Remember the silence load event. */ pBridgeEntry->usSilenceLoadEventPtr = f_usLoadEventIndex; } else { /* Do nothing. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; } } else { /* Do nothing. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software model. */ pLoadEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_NO_OP; /*=======================================================================*/ /*=======================================================================*/ /* Program the Substract and store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); /* Do not load the sample if the channel is muted. */ WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_STORE; /* If we have an extra Sin copy event, we know we are using the Sout port as a source. */ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { /* Sout input. */ WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } else /* if ( pEchoChanEntry->usSinCopyEventIndex == cOCT6100_INVALID_INDEX ) */ { /* Rin input. */ WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software model. */ pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_STORE; /*=======================================================================*/ } /* Update the channel entry API structure */ pEchoChanEntry->fMute = TRUE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeChanUnMuteSer Description: UnMute an echo channel present on a conference bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeUnMute Pointer to conference bridge channel unmute structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeChanUnMuteSer UINT32 Oct6100ConfBridgeChanUnMuteSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute ) { UINT16 usChanIndex; UINT16 usLoadEventIndex; UINT16 usSubStoreEventIndex; UINT8 fFlexibleConfBridge; UINT32 ulResult; /* Check the validity of the channel and conference bridge given. */ ulResult = Oct6100ApiCheckBridgeUnMuteParams( f_pApiInstance, f_pConfBridgeUnMute, &usChanIndex, &usLoadEventIndex, &usSubStoreEventIndex, &fFlexibleConfBridge ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Modify all resources needed by the conference bridge. */ ulResult = Oct6100ApiUpdateBridgeUnMuteResources( f_pApiInstance, usChanIndex, usLoadEventIndex, usSubStoreEventIndex, fFlexibleConfBridge ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeUnMuteParams Description: Check the validity of the channel and conference bridge given. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeUnMute Pointer to conference bridge channel unmute structure. f_pusChannelIndex Pointer to the channel index fo the channel to be unmuted. f_pusLoadEventIndex Pointer to the load index of the channel. f_pusSubStoreEventIndex Pointer to the sub-store event of the channel. f_pfFlexibleConfBridge If this is a flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeUnMuteParams UINT32 Oct6100ApiCheckBridgeUnMuteParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_CHAN_UNMUTE f_pConfBridgeUnMute, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusLoadEventIndex, OUT PUINT16 f_pusSubStoreEventIndex, OUT PUINT8 f_pfFlexibleConfBridge ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeUnMute->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_ADD_INVALID_HANDLE; /*=====================================================================*/ /* Check the channel handle.*/ if ( (f_pConfBridgeUnMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeUnMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeUnMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* Check if the channel is bound to a conference bridge.*/ if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; /* Check if channel is already muted.*/ if ( pEchoChanEntry->fMute == FALSE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_NOT_MUTED; /*=====================================================================*/ /*=====================================================================*/ /* Check the conference bridge handle. */ if ( pEchoChanEntry->usBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pEchoChanEntry->usBridgeIndex ) /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; /* Check the event entries.*/ if ( pBridgeEntry->fFlexibleConferencing == FALSE ) { if ( pEchoChanEntry->usLoadEventIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; /* Check the event entries.*/ if ( pEchoChanEntry->usSubStoreEventIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_MUTE_INVALID_HANDLE; } /*=====================================================================*/ /* Return the config of the channel and all other important information.*/ *f_pusSubStoreEventIndex = pEchoChanEntry->usSubStoreEventIndex; *f_pusLoadEventIndex = pEchoChanEntry->usLoadEventIndex; *f_pfFlexibleConfBridge = pBridgeEntry->fFlexibleConferencing; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBridgeUnMuteResources Description: Modify the conference bridge entry for this channel in order to un-mute the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Index of the channel to be unmuted. f_usLoadEventIndex Allocated entry for the Load event of the channel. f_usSubStoreEventIndex Allocated entry for the substract and store event of the channel. f_fFlexibleConfBridge If this is a flexible conference bridge. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBridgeUnMuteResources UINT32 Oct6100ApiUpdateBridgeUnMuteResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usLoadEventIndex, IN UINT16 f_usSubStoreEventIndex, IN UINT8 f_fFlexibleConfBridge ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pLoadEventEntry; tPOCT6100_API_MIXER_EVENT pSubStoreEventEntry; tPOCT6100_API_MIXER_EVENT pTempEntry; UINT32 ulResult; UINT16 usTempEventIndex; UINT32 ulLoopCount; UINT16 usReadData; UINT16 usLoadEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; UINT16 usPreviousLoadIndex = cOCT6100_INVALID_INDEX; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, f_usChanIndex ); mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, pEchoChanEntry->usBridgeIndex ) if ( f_fFlexibleConfBridge == TRUE ) { tPOCT6100_API_CHANNEL pTempEchoChanEntry; UINT16 usChannelIndex; tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pEchoChanEntry->usFlexConfParticipantIndex ); /* Before doing anything, check if the copy events must be created. */ if ( ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) && ( pEchoChanEntry->fCopyEventCreated == FALSE ) ) { /* The copy event has not been created, create it once for the life of the participant on the bridge. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pEchoChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= pEchoChanEntry->usExtraSinTsiMemIndex; WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now insert the Sin copy event into the list. */ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, pEchoChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; pEchoChanEntry->fCopyEventCreated = TRUE; } /* Search through the list of API channel entry for the ones onto this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == pEchoChanEntry->usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if this participant can hear us. */ if ( ( pTempParticipant->ulListenerMask & ( 0x1 << pParticipant->ulListenerMaskIndex ) ) == 0x0 ) { /* Then create/update this channel's mixer. */ ulResult = Oct6100ApiBridgeAddParticipantToChannel( f_pApiInstance, pEchoChanEntry->usBridgeIndex, f_usChanIndex, usChannelIndex, pTempParticipant->ausLoadOrAccumulateEventIndex[ pParticipant->ulListenerMaskIndex ], pTempEchoChanEntry->usSubStoreEventIndex, pTempEchoChanEntry->usSinCopyEventIndex, pParticipant->ulInputPort, pTempParticipant->ulInputPort ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the Rin silence event can be cleared now that the */ /* channel has unmuted. */ if ( ( pTempParticipant->fFlexibleMixerCreated == TRUE ) && ( pTempEchoChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list. */ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pTempEchoChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pTempEchoChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } } } } } } else /* if ( f_fFlexibleConfBridge == FALSE ) */ { mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pLoadEventEntry, f_usLoadEventIndex ); mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pSubStoreEventEntry, f_usSubStoreEventIndex ); /*=======================================================================*/ /* Program the Load event. */ /* Before reactivating this event, check what type of event this event must be. */ if ( f_usLoadEventIndex == pBridgeEntry->usFirstLoadEventPtr || pBridgeEntry->usLoadIndex == cOCT6100_INVALID_INDEX ) { /* This event must become a Load event. */ usLoadEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; pBridgeEntry->usLoadIndex = f_usLoadEventIndex; } usTempEventIndex = pBridgeEntry->usFirstLoadEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); ulLoopCount = 0; while( pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_SUB_STORE && pTempEntry->usEventType != cOCT6100_MIXER_CONTROL_MEM_STORE ) { if ( pTempEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD ) { usPreviousLoadIndex = usTempEventIndex; } /* Check if the previous load event is before or after the event about to be unmuted. */ if ( pTempEntry->usNextEventPtr == f_usLoadEventIndex ) { if ( usPreviousLoadIndex == cOCT6100_INVALID_INDEX ) { /* We did not find a load event before our node, this mean this one */ /* is about to become the new load event. */ usLoadEventType = cOCT6100_MIXER_CONTROL_MEM_LOAD; } } /* Go to the next entry into the list. */ usTempEventIndex = pTempEntry->usNextEventPtr; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usTempEventIndex ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_9B; } /* Now program the current event node. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usLoadEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = usLoadEventType; /* If we have an extra Sin copy event, we know we are using the Sout port as a source. */ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { /* Sout source */ WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex; } else { /* Rin source */ WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software event to reflect the hardware. */ pLoadEventEntry->usEventType = usLoadEventType; /* Check if we need to change another node. */ if ( usLoadEventType == cOCT6100_MIXER_CONTROL_MEM_LOAD ) { if ( usPreviousLoadIndex != cOCT6100_INVALID_INDEX ) { /* Now program the old load event. */ ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( usPreviousLoadIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ReadParams.ulReadAddress; WriteParams.usWriteData = (UINT16)(( usReadData & 0x1FFF ) | cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software event to reflect the hardware. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEntry, usPreviousLoadIndex ); pTempEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_ACCUMULATE; } } /*=======================================================================*/ /*=======================================================================*/ /* Program the Substract and store event. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSubStoreEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE; /* If we have an extra Sin copy event, we know we are using the Sout port as a source. */ if ( pEchoChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX ) { /* Sout port source */ WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pEchoChanEntry->usSinSoutTsiMemIndex; } else { /* Rin port source */ WriteParams.usWriteData |= pEchoChanEntry->TdmConfig.byRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; WriteParams.usWriteData |= pEchoChanEntry->usRinRoutTsiMemIndex; } mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pEchoChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the software event to reflect the hardware. */ pSubStoreEventEntry->usEventType = cOCT6100_MIXER_CONTROL_MEM_SUB_STORE; /*=======================================================================*/ /*=======================================================================*/ /* Check if have to remove silence load event. */ if ( pBridgeEntry->usSilenceLoadEventPtr != cOCT6100_INVALID_INDEX ) { if ( pBridgeEntry->usSilenceLoadEventPtr == f_usLoadEventIndex ) { /* Clear the silence load event ptr. */ pBridgeEntry->usSilenceLoadEventPtr = cOCT6100_INVALID_INDEX; } } } /* Update the channel entry API structure */ pEchoChanEntry->fMute = FALSE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeDominantSpeakerSetSer Description: This function sets the dominant speaker of a bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeDominant Pointer to conference bridge dominant speaker structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeDominantSpeakerSetSer UINT32 Oct6100ConfBridgeDominantSpeakerSetSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker ) { UINT16 usChanIndex; UINT16 usBridgeIndex; UINT32 ulResult; /* Check the validity of the channel handle given. */ ulResult = Oct6100ApiCheckBridgeDominantSpeakerParams( f_pApiInstance, f_pConfBridgeDominantSpeaker, &usChanIndex, &usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Modify all resources needed by the conference bridge. */ ulResult = Oct6100ApiUpdateBridgeDominantSpeakerResources( f_pApiInstance, usChanIndex, usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeDominantSpeakerParams Description: Check the validity of the channel given for setting the dominant speaker. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeDominant Pointer to conference bridge channel dominant speaker structure. f_pusChannelIndex Pointer to a channel index. f_pusChannelIndex Pointer to a bridge index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeDominantSpeakerParams UINT32 Oct6100ApiCheckBridgeDominantSpeakerParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET f_pConfBridgeDominantSpeaker, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusBridgeIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulEntryOpenCnt; BOOL fCheckEntryOpenCnt = FALSE; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeDominantSpeaker->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /*=====================================================================*/ /* Check the channel handle. */ if ( f_pConfBridgeDominantSpeaker->ulChannelHndl != cOCT6100_CONF_NO_DOMINANT_SPEAKER_HNDL ) { if ( (f_pConfBridgeDominantSpeaker->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeDominantSpeaker->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeDominantSpeaker->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* Check if the channel is bound to a conference bridge. */ if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE; /* Check if the NLP is enabled on this channel. */ if ( pEchoChanEntry->VqeConfig.fEnableNlp == FALSE ) return cOCT6100_ERR_CONF_BRIDGE_NLP_MUST_BE_ENABLED; /* Check if conferencing noise reduction is enabled on this channel. */ if ( pEchoChanEntry->VqeConfig.fSoutConferencingNoiseReduction == FALSE ) return cOCT6100_ERR_CONF_BRIDGE_CNR_MUST_BE_ENABLED; /* Check if this is a tap channel. If it is, it will never be the dominant speaker! */ if ( pEchoChanEntry->fTap == TRUE ) return cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_ALWAYS_MUTE; /* Set the bridge index. */ *f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex; } else { /* Set this such that there is no dominant speaker on this conference bridge. */ *f_pusChannelIndex = cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED; /* Check the conference bridge handle. */ if ( (f_pConfBridgeDominantSpeaker->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* Set the bridge index. */ *f_pusBridgeIndex = (UINT16)( f_pConfBridgeDominantSpeaker->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeDominantSpeaker->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; fCheckEntryOpenCnt = TRUE; } /*=====================================================================*/ /*=====================================================================*/ if ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( fCheckEntryOpenCnt == TRUE ) { if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; } /*=====================================================================*/ /* Check if dominant speaker is supported in this firmware version. */ if ( f_pApiInstance->pSharedInfo->ImageInfo.fDominantSpeakerEnabled == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_DOMINANT_SPEAKER; /*=====================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBridgeDominantSpeakerResources Description: Modify the conference bridge such that the new dominant speaker is the one specified by the index. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Index of the channel to be set as the dominant speaker. f_usBridgeIndex Index of the bridge where this channel is on. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBridgeDominantSpeakerResources UINT32 Oct6100ApiUpdateBridgeDominantSpeakerResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usBridgeIndex ) { tPOCT6100_API_CHANNEL pEchoChanEntry; tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_SHARED_INFO pSharedInfo; UINT16 usChannelIndex; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get the bridge entry for this channel. */ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ) /* Set the dominant speaker index for all channels in this conference. */ /* Search through the list of API channel entry for the ones on to this bridge.*/ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChanEntry, usChannelIndex ); if ( pEchoChanEntry->fReserved == TRUE ) { if ( pEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { /* If we are unsetting the dominant speaker, of if it is not our channel index. */ if ( ( f_usChanIndex == cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ) || ( f_usChanIndex != usChannelIndex ) ) { ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, usChannelIndex, f_usChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } /* Make sure this channel is disabled. */ if ( f_usChanIndex != cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ) { ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_usChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Save this in the conference bridge structure. */ /* This will be needed later when removing the channel. */ pBridgeEntry->fDominantSpeakerSet = TRUE; pBridgeEntry->usDominantSpeakerChanIndex = f_usChanIndex; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeMaskChangeSer Description: This function changes the mask of flexible bridge participant. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMaskChange Pointer to conference bridge participant mask change structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeMaskChangeSer UINT32 Oct6100ConfBridgeMaskChangeSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange ) { UINT16 usChanIndex; UINT16 usBridgeIndex; UINT32 ulResult; UINT32 ulNewParticipantMask; /* Check the validity of the channel handle given. */ ulResult = Oct6100ApiCheckBridgeMaskChangeParams( f_pApiInstance, f_pConfBridgeMaskChange, &usChanIndex, &usBridgeIndex, &ulNewParticipantMask ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update all resources needed by the new mask. */ ulResult = Oct6100ApiUpdateMaskModifyResources( f_pApiInstance, usBridgeIndex, usChanIndex, ulNewParticipantMask ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Commit the changes to the chip's internal memories. */ ulResult = Oct6100ApiBridgeUpdateMask( f_pApiInstance, usBridgeIndex, usChanIndex, ulNewParticipantMask ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckBridgeMaskChangeParams Description: Check the validity of the channel given for setting the mask. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeMaskChange Pointer to conference bridge channel mask change structure. f_pusChannelIndex Pointer to a channel index. f_pusBridgeIndex Pointer to a bridge index. f_pulNewParticipantMask New mask to apply for this participant. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckBridgeMaskChangeParams UINT32 Oct6100ApiCheckBridgeMaskChangeParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CONF_BRIDGE_MASK_CHANGE f_pConfBridgeMaskChange, OUT PUINT16 f_pusChannelIndex, OUT PUINT16 f_pusBridgeIndex, OUT PUINT32 f_pulNewParticipantMask ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_CHANNEL pEchoChanEntry; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; if ( f_pConfBridgeMaskChange->ulChannelHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /*=====================================================================*/ /* Check the channel handle.*/ if ( (f_pConfBridgeMaskChange->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; *f_pusChannelIndex = (UINT16)( f_pConfBridgeMaskChange->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChannelIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, *f_pusChannelIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeMaskChange->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pEchoChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pEchoChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /* Check if the channel is bound to a conference bridge. */ if ( pEchoChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CONF_BRIDGE_CHAN_NOT_ON_BRIDGE; /* Set the bridge index. */ *f_pusBridgeIndex = pEchoChanEntry->usBridgeIndex; /*=====================================================================*/ /*=====================================================================*/ if ( ( *f_pusBridgeIndex == cOCT6100_INVALID_INDEX ) || ( *f_pusBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, *f_pusBridgeIndex ) /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; /* Check if this is bridge is a flexible conference bridge. */ if ( pBridgeEntry->fFlexibleConferencing == FALSE ) return cOCT6100_ERR_CONF_BRIDGE_SIMPLE_BRIDGE; /*=====================================================================*/ /* Return new mask to apply. */ *f_pulNewParticipantMask = f_pConfBridgeMaskChange->ulNewListenerMask; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateMaskModifyResources Description: Modify/reserve all resources needed for the modification of the participant's mask. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Bridge index of the bridge where this channel is residing. f_usChanIndex Channel index of the channel to be modified. f_ulNewListenerMask New mask to apply to the selected participant. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateMaskModifyResources UINT32 Oct6100ApiUpdateMaskModifyResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulNewListenerMask ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_CHANNEL pTempEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar; UINT32 ulOldListenerMask; UINT16 usChannelIndex; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pChanEntry->usFlexConfParticipantIndex ); /* Must travel all clients of this conference and reserve a load or accumulate event for */ /* all participants which could not hear us but now can. While at it, check for events that */ /* could be released, for example a participant that we cannot hear anymore. */ ulOldListenerMask = pParticipant->ulListenerMask; /* Search through the list of API channel entry for the ones on to this bridge.*/ for ( usChannelIndex = 0; ( usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels ) && ( ulResult == cOCT6100_ERR_OK ) ; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can now hear this participant, but could not before. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) ) { /* Must reserve a load or accumulate entry mixer event here! */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { /* Most probably, the hardware is out of mixer events. */ break; } } /* Check if we can now NOT hear this participant, but could before. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) ) { /* Must release the load or accumulate entry mixer event. */ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ); if ( ulResult != cOCT6100_ERR_OK ) { break; } } } } } /* If an error is returned, make sure everything is cleaned up properly. */ if ( ulResult != cOCT6100_ERR_OK ) { /* Search through the list of API channel entry for the ones on to this bridge.*/ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can now hear this participant, but could not before. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) ) { /* If the load or event entry in the mixer memory was reserved. */ if ( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] != cOCT6100_INVALID_INDEX ) { /* Must release the load or accumulate entry mixer event. */ ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } /* Check if we can now NOT hear this participant, but could before. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) ) { /* If the load or event entry in the mixer memory was reserved. */ if ( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] == cOCT6100_INVALID_INDEX ) { /* Must release the load or accumulate entry mixer event. */ ulTempVar = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &( pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] ) ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } } } } } return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeUpdateMask Description: Update the participant's mask. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex Bridge index of the bridge where this channel is residing. f_usChanIndex Channel index of the channel to be modified. f_ulNewListenerMask New mask to apply to the selected participant. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeUpdateMask UINT32 Oct6100ApiBridgeUpdateMask( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usChanIndex, IN UINT32 f_ulNewListenerMask ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_CHANNEL pTempEchoChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_FLEX_CONF_PARTICIPANT pParticipant; tPOCT6100_API_FLEX_CONF_PARTICIPANT pTempParticipant; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulOldListenerMask; UINT16 usChannelIndex; UINT16 ausMutePortChannelIndexes[ cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE ]; UINT32 ulMutePortChannelIndex; for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = cOCT6100_INVALID_INDEX; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pParticipant, pChanEntry->usFlexConfParticipantIndex ); ulOldListenerMask = pParticipant->ulListenerMask; /* Search through the list of API channel entry for the ones onto this bridge. */ for ( usChannelIndex = 0; usChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; usChannelIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, usChannelIndex ); /* Channel reserved? */ if ( ( usChannelIndex != f_usChanIndex ) && ( pTempEchoChanEntry->fReserved == TRUE ) ) { /* On current bridge? */ if ( pTempEchoChanEntry->usBridgeIndex == f_usBridgeIndex ) { mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); /* Check if we can now hear this participant, but could not before. */ if ( ( pTempEchoChanEntry->fMute == FALSE ) && ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) ) { /* First create/update the current channel's mixer. */ ulResult = Oct6100ApiBridgeAddParticipantToChannel( f_pApiInstance, f_usBridgeIndex, usChannelIndex, f_usChanIndex, pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ], pChanEntry->usSubStoreEventIndex, pChanEntry->usSinCopyEventIndex, pTempParticipant->ulInputPort, pParticipant->ulInputPort ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( pParticipant->fFlexibleMixerCreated == TRUE ) { /* Check if the Rin silence event can be cleared now that the */ /* channel has been added to a conference. */ if ( pChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } } } /* Check if we can now NOT hear this participant, but could before. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) && ( pParticipant->fFlexibleMixerCreated == TRUE ) && ( pTempEchoChanEntry->fMute == FALSE ) ) { /* First update the current channel's mixer. */ ulResult = Oct6100ApiBridgeRemoveParticipantFromChannel( f_pApiInstance, f_usBridgeIndex, usChannelIndex, f_usChanIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( pParticipant->fFlexibleMixerCreated == FALSE ) { /* Remember to mute the port on this channel. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == f_usChanIndex ) { break; } else if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) { ausMutePortChannelIndexes[ ulMutePortChannelIndex ] = f_usChanIndex; break; } } } } /* Clear the load or accumulate event index for this participant. */ if ( ( ( f_ulNewListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) != 0x0 ) && ( ( ulOldListenerMask & ( 0x1 << pTempParticipant->ulListenerMaskIndex ) ) == 0x0 ) ) { pParticipant->ausLoadOrAccumulateEventIndex[ pTempParticipant->ulListenerMaskIndex ] = cOCT6100_INVALID_INDEX; } } } /* Travel through the channels that were heard by the participant removed and check if their Rin port must be muted. */ for( ulMutePortChannelIndex = 0; ulMutePortChannelIndex < cOCT6100_MAX_FLEX_CONF_PARTICIPANTS_PER_BRIDGE; ulMutePortChannelIndex ++ ) { if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempEchoChanEntry, ausMutePortChannelIndexes[ ulMutePortChannelIndex ] ); mOCT6100_GET_FLEX_CONF_PARTICIPANT_ENTRY_PNT( pSharedInfo, pTempParticipant, pTempEchoChanEntry->usFlexConfParticipantIndex ); if ( pTempParticipant->fFlexibleMixerCreated == FALSE ) { /* Check if the Rin port must be muted on this channel. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, ausMutePortChannelIndexes[ ulMutePortChannelIndex ], pTempEchoChanEntry->usRinTsstIndex, pTempEchoChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else /* if ( ausMutePortChannelIndexes[ ulMutePortChannelIndex ] == cOCT6100_INVALID_INDEX ) */ { /* No more channels to check for muting. */ break; } } } /* Configure the SIN copy mixer entry and memory - if using the SOUT port. */ if ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_SOUT ) { if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usSinTsstIndex, pChanEntry->usExtraSinTsiMemIndex, pChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* If the silence TSI is loaded on this port, update with the extra sin TSI. */ if ( pChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pChanEntry->usExtraSinTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure the RIN copy mixer entry and memory - if using the RIN port. */ if ( pParticipant->ulInputPort == cOCT6100_CHANNEL_PORT_RIN ) { if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usRinTsstIndex, pChanEntry->usExtraRinTsiMemIndex, pChanEntry->TdmConfig.byRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Save the new mask permanently in the API instance. */ pParticipant->ulListenerMask = f_ulNewListenerMask; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ConfBridgeGetStatsSer Description: This function returns the statistics from the specified bridge. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pConfBridgeStats Pointer to conference bridge stats structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ConfBridgeGetStatsSer UINT32 Oct6100ConfBridgeGetStatsSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CONF_BRIDGE_STATS f_pConfBridgeStats ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; UINT16 usConfBridgeIndex; UINT32 ulEntryOpenCnt; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges == 0 ) return cOCT6100_ERR_CONF_BRIDGE_DISABLED; /*=====================================================================*/ /* Check the conference bridge handle. */ /* Check the provided handle. */ if ( (f_pConfBridgeStats->ulConfBridgeHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CONF_BRIDGE ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; usConfBridgeIndex = (UINT16)( f_pConfBridgeStats->ulConfBridgeHndl & cOCT6100_HNDL_INDEX_MASK ); if ( usConfBridgeIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxConfBridges ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, usConfBridgeIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pConfBridgeStats->ulConfBridgeHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pBridgeEntry->fReserved != TRUE ) return cOCT6100_ERR_CONF_BRIDGE_NOT_OPEN; if ( ulEntryOpenCnt != pBridgeEntry->byEntryOpenCnt ) return cOCT6100_ERR_CONF_BRIDGE_INVALID_HANDLE; /*=====================================================================*/ /* Return the stats.*/ f_pConfBridgeStats->ulNumChannels = pBridgeEntry->usNumClients; f_pConfBridgeStats->ulNumTappedChannels = pBridgeEntry->usNumTappedClients; f_pConfBridgeStats->fFlexibleConferencing = pBridgeEntry->fFlexibleConferencing; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBridgeEntry Description: Reserves a free entry in the Bridge list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusBridgeIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBridgeEntry UINT32 Oct6100ApiReserveBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusBridgeIndex ) { PVOID pBridgeAlloc; UINT32 ulResult; UINT32 ulBridgeIndex; mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBridgeAlloc ) ulResult = OctapiLlmAllocAlloc( pBridgeAlloc, &ulBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_CONF_BRIDGE_ALL_BUFFERS_OPEN; else return cOCT6100_ERR_FATAL_29; } *f_pusBridgeIndex = (UINT16)( ulBridgeIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBridgeEntry Description: Release an entry from the bridge list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBridgeIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBridgeEntry UINT32 Oct6100ApiReleaseBridgeEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex ) { PVOID pBridgeAlloc; UINT32 ulResult; mOCT6100_GET_CONF_BRIDGE_ALLOC_PNT( f_pApiInstance->pSharedInfo, pBridgeAlloc ) ulResult = OctapiLlmAllocDealloc( pBridgeAlloc, f_usBridgeIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_2A; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetPrevLastSubStoreEvent Description: This function will search for the first valid LastSubStoreEvent in a bridge located before the current bridge in the bridge link list. If the function does not find an event before reaching the end of the mixers list, then the event head node will be used as the last Store or SubStore event. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusBridgeEntry Bridge entry. f_usBridgeFirstLoadEventPtr Load index to check against. First valid sub store index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetPrevLastSubStoreEvent UINT32 Oct6100ApiGetPrevLastSubStoreEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBridgeIndex, IN UINT16 f_usBridgeFirstLoadEventPtr, OUT PUINT16 f_pusLastSubStoreEventIndex ) { tPOCT6100_API_CONF_BRIDGE pBridgeEntry; tPOCT6100_API_MIXER_EVENT pTempMixerEntry; UINT16 usNextEventPtr; UINT16 usHeadEventPtr; UINT16 usLastSubStoreEventPtr; UINT32 ulLoopCount = 0; UINT16 usCurrentPtr; UINT32 ulResult = cOCT6100_ERR_OK; /* Get current entry to obtain the link to the previous entry.*/ mOCT6100_GET_CONF_BRIDGE_ENTRY_PNT( f_pApiInstance->pSharedInfo, pBridgeEntry, f_usBridgeIndex ); /* Since we have flexible bridges, we have to */ /* run down the list and check for the appropriate event. */ /* Travel down the list for the last Store or Sub/Store event before the bridge. */ if ( f_pApiInstance->pSharedInfo->MixerInfo.usLastSoutCopyEventPtr == cOCT6100_INVALID_INDEX ) { /* The only node in the list then is the head node.*/ usHeadEventPtr = cOCT6100_MIXER_HEAD_NODE; } else { usHeadEventPtr = f_pApiInstance->pSharedInfo->MixerInfo.usLastSoutCopyEventPtr; } mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempMixerEntry, usHeadEventPtr ); usLastSubStoreEventPtr = usHeadEventPtr; usNextEventPtr = pTempMixerEntry->usNextEventPtr; usCurrentPtr = usHeadEventPtr; while( usCurrentPtr != f_usBridgeFirstLoadEventPtr ) { if ( ( pTempMixerEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_STORE ) || ( pTempMixerEntry->usEventType == cOCT6100_MIXER_CONTROL_MEM_SUB_STORE ) ) { usLastSubStoreEventPtr = usNextEventPtr; } /* Next pointer. */ usCurrentPtr = usNextEventPtr; usNextEventPtr = pTempMixerEntry->usNextEventPtr; /* Check if next event pointer is valid. */ if ( ( ( f_usBridgeFirstLoadEventPtr != usCurrentPtr ) && ( pTempMixerEntry->usNextEventPtr == cOCT6100_INVALID_INDEX ) ) || ( pTempMixerEntry->usNextEventPtr == cOCT6100_MIXER_HEAD_NODE ) ) return cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND; if ( usNextEventPtr != cOCT6100_INVALID_INDEX ) mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTempMixerEntry, usNextEventPtr ); ulLoopCount++; if ( ulLoopCount == cOCT6100_MAX_LOOP ) return cOCT6100_ERR_FATAL_CA; } /* Return the result to the user. */ *f_pusLastSubStoreEventIndex = usLastSubStoreEventPtr; return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetPreviousEvent Description: This is a recursive function, it requires an entry event index and will run down the list until it finds the node just before the one required. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEntryIndex Event entry index. f_pusBridgeEntry Bridge entry. f_pusPreviousIndex Previous index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetPreviousEvent UINT32 Oct6100ApiGetPreviousEvent( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEntryIndex, IN UINT16 f_usSearchedIndex, IN UINT16 f_usLoopCnt, OUT PUINT16 f_pusPreviousIndex ) { tPOCT6100_API_MIXER_EVENT pCurrentEntry; UINT32 ulResult; /* Get current entry to obtain the link to the previous entry. */ mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( f_pApiInstance->pSharedInfo, pCurrentEntry, f_usEntryIndex ); /* Avoid stack overflows. */ if ( f_usLoopCnt == cOCT6100_MAX_MIXER_EVENTS ) return cOCT6100_ERR_FATAL_E3; if ( pCurrentEntry->usNextEventPtr == cOCT6100_INVALID_INDEX ) { /* Event not found. */ ulResult = cOCT6100_ERR_CONF_MIXER_EVENT_NOT_FOUND; } else if ( pCurrentEntry->usNextEventPtr == f_usSearchedIndex ) { /* We found our node. */ *f_pusPreviousIndex = f_usEntryIndex; ulResult = cOCT6100_ERR_OK; } else { /* Keep searching.*/ f_usLoopCnt++; ulResult = Oct6100ApiGetPreviousEvent( f_pApiInstance, pCurrentEntry->usNextEventPtr, f_usSearchedIndex, f_usLoopCnt, f_pusPreviousIndex ); } return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiBridgeSetDominantSpeaker Description: This function will set the index of the dominant speaker for the channel index specified. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChannelIndex Index of the channel where the API must set the current dominant speaker for the conference. f_usDominantSpeakerIndex Index of the channel which is the dominant speaker in the conference. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiBridgeSetDominantSpeaker UINT32 Oct6100ApiBridgeSetDominantSpeaker( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChannelIndex, IN UINT16 f_usDominantSpeakerIndex ) { UINT32 ulBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulResult; UINT32 ulTempData; UINT32 ulMask; tPOCT6100_API_CHANNEL pEchoChanEntry; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChanEntry, f_usChannelIndex ); ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanRootConfOfst; ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.byBitOffset; ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.DominantSpeakerFieldOfst.byFieldSize; /* Retrieve the current configuration. */ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pEchoChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= ( ( f_usDominantSpeakerIndex ) << ulFeatureBitOffset ); /* Save the new dominant speaker. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pEchoChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveFlexConfParticipantEntry Description: Reserves a free entry in the participant list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusParticipantIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveFlexConfParticipantEntry UINT32 Oct6100ApiReserveFlexConfParticipantEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusParticipantIndex ) { PVOID pParticipantAlloc; UINT32 ulResult; UINT32 ulParticipantIndex; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pParticipantAlloc ) ulResult = OctapiLlmAllocAlloc( pParticipantAlloc, &ulParticipantIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_CONF_BRIDGE_FLEX_CONF_ALL_BUFFERS_OPEN; else return cOCT6100_ERR_FATAL_29; } *f_pusParticipantIndex = (UINT16)( ulParticipantIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseFlexConfParticipantEntry Description: Release an entry from the flexible conferencing participant list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usParticipantIndex List entry reserved. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseFlexConfParticipantEntry UINT32 Oct6100ApiReleaseFlexConfParticipantEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usParticipantIndex ) { PVOID pParticipantAlloc; UINT32 ulResult; mOCT6100_GET_FLEX_CONF_PARTICIPANT_ALLOC_PNT( f_pApiInstance->pSharedInfo, pParticipantAlloc ) ulResult = OctapiLlmAllocDealloc( pParticipantAlloc, f_usParticipantIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_2A; return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_channel.c0000644000175000017500000200561511604644235031064 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_channel.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to open, modify and close echo cancellation channels. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 492 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #if defined(__FreeBSD__) #include #include #else #ifndef __KERNEL__ #include #include #define kmalloc(size, type) malloc(size) #define kfree(ptr) free(ptr) #define GFP_ATOMIC 0 /* Dummy */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #else #include #include #endif #endif #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_mixer_inst.h" #include "oct6100api/oct6100_tsi_cnct_inst.h" #include "oct6100api/oct6100_conf_bridge_inst.h" #include "oct6100api/oct6100_tone_detection_inst.h" #include "oct6100api/oct6100_phasing_tsst_inst.h" #include "oct6100api/oct6100_tsst_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_tsi_cnct_pub.h" #include "oct6100api/oct6100_playout_buf_pub.h" #include "oct6100api/oct6100_phasing_tsst_pub.h" #include "oct6100api/oct6100_mixer_pub.h" #include "oct6100api/oct6100_conf_bridge_pub.h" #include "oct6100api/oct6100_tone_detection_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_debug_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_mixer_priv.h" #include "oct6100_phasing_tsst_priv.h" #include "oct6100_tsi_cnct_priv.h" #include "oct6100_playout_buf_priv.h" #include "oct6100_conf_bridge_priv.h" #include "oct6100_tone_detection_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_debug_priv.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelOpen Description: This function opens a echo cancellation channel. An echo cancellation channel is constituted of two voice stream (RIN/ROUT and SIN/SOUT), and an echo cancelling core. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to echo channel open structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelOpenDef UINT32 Oct6100ChannelOpenDef( IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ) { f_pChannelOpen->pulChannelHndl = NULL; f_pChannelOpen->ulUserChanId = cOCT6100_INVALID_VALUE; f_pChannelOpen->ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_POWER_DOWN; f_pChannelOpen->fEnableToneDisabler = FALSE; f_pChannelOpen->fEnableExtToneDetection = FALSE; /* VQE configuration.*/ f_pChannelOpen->VqeConfig.fSinDcOffsetRemoval = TRUE; f_pChannelOpen->VqeConfig.fRinDcOffsetRemoval = TRUE; f_pChannelOpen->VqeConfig.fRinLevelControl = FALSE; f_pChannelOpen->VqeConfig.lRinLevelControlGainDb = 0; f_pChannelOpen->VqeConfig.fSoutLevelControl = FALSE; f_pChannelOpen->VqeConfig.lSoutLevelControlGainDb = 0; f_pChannelOpen->VqeConfig.fRinAutomaticLevelControl = FALSE; f_pChannelOpen->VqeConfig.lRinAutomaticLevelControlTargetDb = -20; f_pChannelOpen->VqeConfig.fSoutAutomaticLevelControl = FALSE; f_pChannelOpen->VqeConfig.lSoutAutomaticLevelControlTargetDb = -20; f_pChannelOpen->VqeConfig.fRinHighLevelCompensation = FALSE; f_pChannelOpen->VqeConfig.lRinHighLevelCompensationThresholdDb = -10; f_pChannelOpen->VqeConfig.fSoutAdaptiveNoiseReduction = FALSE; f_pChannelOpen->VqeConfig.fSoutNoiseBleaching = FALSE; f_pChannelOpen->VqeConfig.fSoutConferencingNoiseReduction = FALSE; f_pChannelOpen->VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL; f_pChannelOpen->VqeConfig.fEnableNlp = TRUE; f_pChannelOpen->VqeConfig.fEnableTailDisplacement = FALSE; f_pChannelOpen->VqeConfig.ulTailDisplacement = cOCT6100_AUTO_SELECT_TAIL; f_pChannelOpen->VqeConfig.ulTailLength = cOCT6100_AUTO_SELECT_TAIL; f_pChannelOpen->VqeConfig.fDtmfToneRemoval = FALSE; f_pChannelOpen->VqeConfig.fAcousticEcho = FALSE; f_pChannelOpen->VqeConfig.lDefaultErlDb = -6; f_pChannelOpen->VqeConfig.ulAecTailLength = 128; f_pChannelOpen->VqeConfig.lAecDefaultErlDb = 0; f_pChannelOpen->VqeConfig.ulNonLinearityBehaviorA = 1; f_pChannelOpen->VqeConfig.ulNonLinearityBehaviorB = 0; f_pChannelOpen->VqeConfig.ulDoubleTalkBehavior = cOCT6100_DOUBLE_TALK_BEH_NORMAL; f_pChannelOpen->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = 0; f_pChannelOpen->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = 0; f_pChannelOpen->VqeConfig.fSoutNaturalListenerEnhancement = FALSE; f_pChannelOpen->VqeConfig.fRoutNoiseReduction = FALSE; f_pChannelOpen->VqeConfig.lRoutNoiseReductionLevelGainDb = -18; f_pChannelOpen->VqeConfig.lAnrSnrEnhancementDb = -18; f_pChannelOpen->VqeConfig.ulAnrVoiceNoiseSegregation = 6; f_pChannelOpen->VqeConfig.ulToneDisablerVqeActivationDelay = 300; f_pChannelOpen->VqeConfig.fEnableMusicProtection = FALSE; /* Older images have idle code detection hard-coded to enabled. */ f_pChannelOpen->VqeConfig.fIdleCodeDetection = TRUE; /* TDM configuration.*/ f_pChannelOpen->TdmConfig.ulRinNumTssts = 1; f_pChannelOpen->TdmConfig.ulSinNumTssts = 1; f_pChannelOpen->TdmConfig.ulRoutNumTssts = 1; f_pChannelOpen->TdmConfig.ulSoutNumTssts = 1; f_pChannelOpen->TdmConfig.ulRinTimeslot = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulRinStream = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulRinPcmLaw = cOCT6100_PCM_U_LAW; f_pChannelOpen->TdmConfig.ulSinTimeslot = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulSinStream = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulSinPcmLaw = cOCT6100_PCM_U_LAW; f_pChannelOpen->TdmConfig.ulRoutTimeslot = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulRoutStream = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulRoutPcmLaw = cOCT6100_PCM_U_LAW; f_pChannelOpen->TdmConfig.ulSoutTimeslot = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulSoutStream = cOCT6100_UNASSIGNED; f_pChannelOpen->TdmConfig.ulSoutPcmLaw = cOCT6100_PCM_U_LAW; /* CODEC configuration.*/ f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition = cOCT6100_ADPCM_IN_LOW_BITS; f_pChannelOpen->CodecConfig.ulEncoderPort = cOCT6100_CHANNEL_PORT_SOUT; f_pChannelOpen->CodecConfig.ulEncodingRate = cOCT6100_G711_64KBPS; f_pChannelOpen->CodecConfig.ulDecoderPort = cOCT6100_CHANNEL_PORT_RIN; f_pChannelOpen->CodecConfig.ulDecodingRate = cOCT6100_G711_64KBPS; f_pChannelOpen->CodecConfig.fEnableSilenceSuppression = FALSE; f_pChannelOpen->CodecConfig.ulPhasingTsstHndl = cOCT6100_INVALID_HANDLE; f_pChannelOpen->CodecConfig.ulPhase = 1; f_pChannelOpen->CodecConfig.ulPhasingType = cOCT6100_NO_PHASING; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelOpen UINT32 Oct6100ChannelOpen( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelOpenSer( f_pApiInstance, f_pChannelOpen ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelClose Description: This function closes an echo canceller channel ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelClose Pointer to channel close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelCloseDef UINT32 Oct6100ChannelCloseDef( IN OUT tPOCT6100_CHANNEL_CLOSE f_pChannelClose ) { f_pChannelClose->ulChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelClose UINT32 Oct6100ChannelClose( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CLOSE f_pChannelClose ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelCloseSer( f_pApiInstance, f_pChannelClose ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelModify Description: This function will modify the parameter of an echo channel. If the call to this channel allows the channel to go from power down to enable, the API will activate it. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to echo channel change structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelModifyDef UINT32 Oct6100ChannelModifyDef( IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify ) { f_pChannelModify->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelModify->ulUserChanId = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->ulEchoOperationMode = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->fEnableToneDisabler = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->fApplyToAllChannels = FALSE; f_pChannelModify->fDisableToneDetection = FALSE; f_pChannelModify->fStopBufferPlayout = FALSE; f_pChannelModify->fRemoveConfBridgeParticipant = FALSE; f_pChannelModify->fRemoveBroadcastTssts = FALSE; f_pChannelModify->fTdmConfigModified = FALSE; f_pChannelModify->fVqeConfigModified = FALSE; f_pChannelModify->fCodecConfigModified = FALSE; /* VQE config. */ f_pChannelModify->VqeConfig.fSinDcOffsetRemoval = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fRinDcOffsetRemoval = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fRinLevelControl = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lRinLevelControlGainDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutLevelControl = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lSoutLevelControlGainDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fRinAutomaticLevelControl = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lRinAutomaticLevelControlTargetDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutAutomaticLevelControl = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lSoutAutomaticLevelControlTargetDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fRinHighLevelCompensation = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lRinHighLevelCompensationThresholdDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutAdaptiveNoiseReduction = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutNoiseBleaching = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutConferencingNoiseReduction = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulComfortNoiseMode = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fEnableNlp = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fEnableTailDisplacement = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulTailDisplacement = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fDtmfToneRemoval = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fAcousticEcho = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lDefaultErlDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulAecTailLength = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lAecDefaultErlDb = (INT32)cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulNonLinearityBehaviorA = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulNonLinearityBehaviorB = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulDoubleTalkBehavior = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fSoutNaturalListenerEnhancement = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fRoutNoiseReduction = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lRoutNoiseReductionLevelGainDb = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.lAnrSnrEnhancementDb = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulAnrVoiceNoiseSegregation = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.ulToneDisablerVqeActivationDelay = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fEnableMusicProtection = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->VqeConfig.fIdleCodeDetection = cOCT6100_KEEP_PREVIOUS_SETTING; /* TDM config. */ f_pChannelModify->TdmConfig.ulRinNumTssts = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSinNumTssts = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRoutNumTssts = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSoutNumTssts = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRinTimeslot = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRinStream = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRinPcmLaw = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSinTimeslot = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSinStream = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSinPcmLaw = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRoutTimeslot = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRoutStream = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulRoutPcmLaw = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSoutTimeslot = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSoutStream = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->TdmConfig.ulSoutPcmLaw = cOCT6100_KEEP_PREVIOUS_SETTING; /* CODEC config. */ f_pChannelModify->CodecConfig.ulEncoderPort = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulEncodingRate = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulDecoderPort = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulDecodingRate = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.fEnableSilenceSuppression = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulPhasingTsstHndl = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulPhase = cOCT6100_KEEP_PREVIOUS_SETTING; f_pChannelModify->CodecConfig.ulPhasingType = cOCT6100_KEEP_PREVIOUS_SETTING; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelModify UINT32 Oct6100ChannelModify( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Check the apply to all channels flag first. */ if ( f_pChannelModify->fApplyToAllChannels != TRUE && f_pChannelModify->fApplyToAllChannels != FALSE ) return cOCT6100_ERR_CHANNEL_APPLY_TO_ALL_CHANNELS; /* Check if must apply modification to all channels. */ if ( f_pChannelModify->fApplyToAllChannels == TRUE ) { tPOCT6100_API_CHANNEL pChanEntry; UINT16 usChanIndex; /* Loop through all channels and look for the opened ones. */ for ( usChanIndex = 0; usChanIndex < f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels; usChanIndex++ ) { mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, usChanIndex ); /* Check if this one is opened. */ if ( pChanEntry->fReserved == TRUE ) { /* Channel is opened. Form handle and call actual modify function. */ f_pChannelModify->ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | usChanIndex; /* Call the serialized function. */ ulFncRes = Oct6100ChannelModifySer( f_pApiInstance, f_pChannelModify ); if ( ulFncRes != cOCT6100_ERR_OK ) break; } } } else /* if ( f_pChannelModify->fApplyToAllChannels == FALSE ) */ { /* Call the serialized function. */ ulFncRes = Oct6100ChannelModifySer( f_pApiInstance, f_pChannelModify ); } } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelCreateBiDir Description: This function creates a bidirectional channel using two standard echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelCreateBiDir Pointer to channel create BiDir structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelCreateBiDirDef UINT32 Oct6100ChannelCreateBiDirDef( IN OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ) { f_pChannelCreateBiDir->pulBiDirChannelHndl = NULL; f_pChannelCreateBiDir->ulFirstChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelCreateBiDir->ulSecondChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelCreateBiDir UINT32 Oct6100ChannelCreateBiDir( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelCreateBiDirSer( f_pApiInstance, f_pChannelCreateBiDir ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelDestroyBiDir Description: This function destroys a bidirectional channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelDestroyBiDir Pointer to channel destroy BiDir structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelDestroyBiDirDef UINT32 Oct6100ChannelDestroyBiDirDef( IN OUT tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ) { f_pChannelDestroyBiDir->ulBiDirChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelDestroyBiDir UINT32 Oct6100ChannelDestroyBiDir( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelDestroyBiDirSer( f_pApiInstance, f_pChannelDestroyBiDir ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelBroadcastTsstAdd Description: This function adds a TSST to one of the two output ports of a channel. This TSST can never be modified by a call to Oct6100ChannelModify. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelBroadcastTsstAdd Pointer to the an Add Broadcast TSST structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelBroadcastTsstAddDef UINT32 Oct6100ChannelBroadcastTsstAddDef( tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelBroadcastTsstAdd ) { f_pChannelBroadcastTsstAdd->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelBroadcastTsstAdd->ulPort = cOCT6100_INVALID_PORT; f_pChannelBroadcastTsstAdd->ulTimeslot = cOCT6100_INVALID_TIMESLOT; f_pChannelBroadcastTsstAdd->ulStream = cOCT6100_INVALID_STREAM; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelBroadcastTsstAdd UINT32 Oct6100ChannelBroadcastTsstAdd( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelBroadcastTsstAdd ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelBroadcastTsstAddSer( f_pApiInstance, f_pChannelBroadcastTsstAdd ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelBroadcastTsstRemove Description: This function removes a TSST from one of the two output ports of a channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelBroadcastTsstRemove Pointer to the a Remove Broadcast TSST structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelBroadcastTsstRemoveDef UINT32 Oct6100ChannelBroadcastTsstRemoveDef( tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelBroadcastTsstRemove ) { f_pChannelBroadcastTsstRemove->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelBroadcastTsstRemove->ulPort = cOCT6100_INVALID_PORT; f_pChannelBroadcastTsstRemove->ulTimeslot = cOCT6100_INVALID_TIMESLOT; f_pChannelBroadcastTsstRemove->ulStream = cOCT6100_INVALID_STREAM; f_pChannelBroadcastTsstRemove->fRemoveAll = FALSE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelBroadcastTsstRemove UINT32 Oct6100ChannelBroadcastTsstRemove( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelBroadcastTsstRemove ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelBroadcastTsstRemoveSer( f_pApiInstance, f_pChannelBroadcastTsstRemove ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelGetStats Description: This function retrieves all the config and stats related to the channel designated by ulChannelHndl. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelStats Pointer to a tOCT6100_CHANNEL_STATS structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelGetStatsDef UINT32 Oct6100ChannelGetStatsDef( IN OUT tPOCT6100_CHANNEL_STATS f_pChannelStats ) { f_pChannelStats->fResetStats = FALSE; f_pChannelStats->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelStats->ulUserChanId = cOCT6100_INVALID_STAT; f_pChannelStats->ulEchoOperationMode = cOCT6100_INVALID_STAT; f_pChannelStats->fEnableToneDisabler = FALSE; f_pChannelStats->ulMutePortsMask = cOCT6100_CHANNEL_MUTE_PORT_NONE; f_pChannelStats->fEnableExtToneDetection = FALSE; /* VQE configuration.*/ f_pChannelStats->VqeConfig.fEnableNlp = FALSE; f_pChannelStats->VqeConfig.fEnableTailDisplacement = FALSE; f_pChannelStats->VqeConfig.ulTailDisplacement = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulTailLength = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.fSinDcOffsetRemoval = FALSE; f_pChannelStats->VqeConfig.fRinDcOffsetRemoval = FALSE; f_pChannelStats->VqeConfig.fRinLevelControl = FALSE; f_pChannelStats->VqeConfig.fSoutLevelControl = FALSE; f_pChannelStats->VqeConfig.fRinAutomaticLevelControl = FALSE; f_pChannelStats->VqeConfig.fSoutAutomaticLevelControl = FALSE; f_pChannelStats->VqeConfig.fRinHighLevelCompensation = FALSE; f_pChannelStats->VqeConfig.fAcousticEcho = FALSE; f_pChannelStats->VqeConfig.fSoutAdaptiveNoiseReduction = FALSE; f_pChannelStats->VqeConfig.fDtmfToneRemoval = FALSE; f_pChannelStats->VqeConfig.fSoutNoiseBleaching = FALSE; f_pChannelStats->VqeConfig.fSoutConferencingNoiseReduction = FALSE; f_pChannelStats->VqeConfig.ulComfortNoiseMode = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulNonLinearityBehaviorA = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulNonLinearityBehaviorB = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulDoubleTalkBehavior = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.lRinLevelControlGainDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lSoutLevelControlGainDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lRinAutomaticLevelControlTargetDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lSoutAutomaticLevelControlTargetDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lRinHighLevelCompensationThresholdDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lDefaultErlDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lAecDefaultErlDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.ulAecTailLength = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.fSoutNaturalListenerEnhancement = FALSE; f_pChannelStats->VqeConfig.fRoutNoiseReduction = FALSE; f_pChannelStats->VqeConfig.lRoutNoiseReductionLevelGainDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.lAnrSnrEnhancementDb = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->VqeConfig.ulAnrVoiceNoiseSegregation = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.ulToneDisablerVqeActivationDelay = cOCT6100_INVALID_STAT; f_pChannelStats->VqeConfig.fEnableMusicProtection = FALSE; f_pChannelStats->VqeConfig.fIdleCodeDetection = FALSE; /* TDM configuration.*/ f_pChannelStats->TdmConfig.ulMaxBroadcastTssts = 0; f_pChannelStats->TdmConfig.fMoreRoutBroadcastTssts = FALSE; f_pChannelStats->TdmConfig.fMoreSoutBroadcastTssts = FALSE; f_pChannelStats->TdmConfig.ulNumRoutBroadcastTssts = 0; f_pChannelStats->TdmConfig.ulNumSoutBroadcastTssts = 0; f_pChannelStats->TdmConfig.ulRinNumTssts = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSinNumTssts = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRoutNumTssts = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSoutNumTssts = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRinTimeslot = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRinStream = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRinPcmLaw = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSinTimeslot = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSinStream = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSinPcmLaw = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRoutTimeslot = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRoutStream = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulRoutPcmLaw = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.pulRoutBroadcastTimeslot = NULL; f_pChannelStats->TdmConfig.pulRoutBroadcastStream = NULL; f_pChannelStats->TdmConfig.ulSoutTimeslot = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSoutStream = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.ulSoutPcmLaw = cOCT6100_INVALID_STAT; f_pChannelStats->TdmConfig.pulSoutBroadcastTimeslot = NULL; f_pChannelStats->TdmConfig.pulSoutBroadcastStream = NULL; /* CODEC configuration.*/ f_pChannelStats->CodecConfig.ulAdpcmNibblePosition = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulEncoderPort = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulEncodingRate = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulDecoderPort = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulDecodingRate = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.fEnableSilenceSuppression = FALSE; f_pChannelStats->CodecConfig.ulPhasingTsstHndl = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulPhase = cOCT6100_INVALID_STAT; f_pChannelStats->CodecConfig.ulPhasingType = cOCT6100_INVALID_STAT; f_pChannelStats->ulNumEchoPathChanges = cOCT6100_INVALID_STAT; f_pChannelStats->ulToneDisablerStatus = cOCT6100_INVALID_STAT; f_pChannelStats->fEchoCancellerConverged = FALSE; f_pChannelStats->fSinVoiceDetected = FALSE; f_pChannelStats->lCurrentERL = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lCurrentERLE = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->ulCurrentEchoDelay = cOCT6100_INVALID_STAT; f_pChannelStats->lMaxERL = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lMaxERLE = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->ulMaxEchoDelay = cOCT6100_INVALID_STAT; f_pChannelStats->lRinLevel = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lSinLevel = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lRinAppliedGain = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lSoutAppliedGain = cOCT6100_INVALID_SIGNED_STAT; f_pChannelStats->lComfortNoiseLevel = cOCT6100_INVALID_SIGNED_STAT; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelGetStats UINT32 Oct6100ChannelGetStats( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_STATS f_pChannelStats ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ApiChannelGetStatsSer( f_pApiInstance, f_pChannelStats ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelMute Description: This function mutes some or all of the ports designated by ulChannelHndl. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelMute Pointer to a tPOCT6100_CHANNEL_MUTE structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelMuteDef UINT32 Oct6100ChannelMuteDef( IN OUT tPOCT6100_CHANNEL_MUTE f_pChannelMute ) { f_pChannelMute->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelMute->ulPortMask = cOCT6100_CHANNEL_MUTE_PORT_NONE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelMute UINT32 Oct6100ChannelMute( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MUTE f_pChannelMute ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelMuteSer( f_pApiInstance, f_pChannelMute ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelUnMute Description: This function unmutes some or all of the ports designated by ulChannelHndl. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelUnMute Pointer to a tPOCT6100_CHANNEL_UNMUTE structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelUnMuteDef UINT32 Oct6100ChannelUnMuteDef( IN OUT tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ) { f_pChannelUnMute->ulChannelHndl = cOCT6100_INVALID_HANDLE; f_pChannelUnMute->ulPortMask = cOCT6100_CHANNEL_MUTE_PORT_NONE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ChannelUnMute UINT32 Oct6100ChannelUnMute( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100ChannelUnMuteSer( f_pApiInstance, f_pChannelUnMute ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetChannelsEchoSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of the ECHO memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetChannelsEchoSwSizes UINT32 Oct6100ApiGetChannelsEchoSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; UINT32 ulMaxChannels; ulMaxChannels = f_pOpenChip->ulMaxChannels; if ( f_pOpenChip->fEnableChannelRecording == TRUE && ulMaxChannels != 672 ) ulMaxChannels++; /* Determine the amount of memory required for the API echo channel list.*/ f_pInstSizes->ulChannelList = ulMaxChannels * sizeof( tOCT6100_API_CHANNEL ); /* Add one for the record channel.*/ f_pInstSizes->ulBiDirChannelList = f_pOpenChip->ulMaxBiDirChannels * sizeof( tOCT6100_API_BIDIR_CHANNEL ); if ( ulMaxChannels > 0 ) { /* Calculate memory needed for ECHO memory allocation */ ulResult = OctapiLlmAllocGetSize( ulMaxChannels, &f_pInstSizes->ulChannelAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_0; } else { f_pInstSizes->ulChannelAlloc = 0; } if ( f_pOpenChip->ulMaxBiDirChannels > 0 ) { /* Calculate memory needed for ECHO memory allocation */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxBiDirChannels, &f_pInstSizes->ulBiDirChannelAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_0; } else { f_pInstSizes->ulBiDirChannelAlloc = 0; } mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulChannelList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulChannelAlloc, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulBiDirChannelList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulBiDirChannelAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiChannelsEchoSwInit Description: Initializes all elements of the instance structure associated to the ECHO memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiChannelsEchoSwInit UINT32 Oct6100ApiChannelsEchoSwInit( IN tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_CHANNEL pChannelsEchoList; tPOCT6100_API_BIDIR_CHANNEL pBiDirChannelsList; tPOCT6100_SHARED_INFO pSharedInfo; UINT16 usMaxChannels; PVOID pEchoChanAlloc; PVOID pBiDirChanAlloc; UINT32 ulResult; /* Get local pointer to shared portion of the API instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize the ECHO channel API list.*/ usMaxChannels = pSharedInfo->ChipConfig.usMaxChannels; /* add a channel to initialize if the recording is activated. */ if ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) usMaxChannels++; /* Set all entries in the ADCPM channel list to unused. */ mOCT6100_GET_CHANNEL_LIST_PNT( pSharedInfo, pChannelsEchoList ); /* Initialize the API ECHO channels allocation software to "all free". */ if ( usMaxChannels > 0 ) { /* Clear the memory */ Oct6100UserMemSet( pChannelsEchoList, 0x00, sizeof(tOCT6100_API_CHANNEL) * usMaxChannels ); mOCT6100_GET_CHANNEL_ALLOC_PNT( pSharedInfo, pEchoChanAlloc ) ulResult = OctapiLlmAllocInit( &pEchoChanAlloc, usMaxChannels ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_1; } mOCT6100_GET_BIDIR_CHANNEL_LIST_PNT( pSharedInfo, pBiDirChannelsList ); if ( pSharedInfo->ChipConfig.usMaxBiDirChannels > 0 ) { /* Clear the memory */ Oct6100UserMemSet( pBiDirChannelsList, 0x00, sizeof(tOCT6100_API_BIDIR_CHANNEL) * pSharedInfo->ChipConfig.usMaxBiDirChannels ); mOCT6100_GET_BIDIR_CHANNEL_ALLOC_PNT( pSharedInfo, pBiDirChanAlloc ) ulResult = OctapiLlmAllocInit( &pBiDirChanAlloc, pSharedInfo->ChipConfig.usMaxBiDirChannels ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A9; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelOpenSer Description: Opens a echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to channel configuration structure. Then handle identifying the buffer in all future function calls is returned in this structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelOpenSer UINT32 Oct6100ChannelOpenSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_OPEN f_pChannelOpen ) { tOCT6100_API_ECHO_CHAN_INDEX *ChannelIndexConf; UINT32 ulResult; ChannelIndexConf = kmalloc(sizeof(*ChannelIndexConf), GFP_ATOMIC); if (!ChannelIndexConf) return cOCT6100_ERR_FATAL_0; /* Check the user's configuration of the echo cancellation channel for errors. */ ulResult = Oct6100ApiCheckChannelParams( f_pApiInstance, f_pChannelOpen, ChannelIndexConf ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Reserve all resources needed by the echo cancellation channel. */ ulResult = Oct6100ApiReserveChannelResources( f_pApiInstance, f_pChannelOpen, ChannelIndexConf ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Write all necessary structures to activate the echo cancellation channel. */ ulResult = Oct6100ApiWriteChannelStructs( f_pApiInstance, f_pChannelOpen, ChannelIndexConf ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Update the new echo cancellation channels's entry in the ECHO channel list. */ ulResult = Oct6100ApiUpdateChannelEntry( f_pApiInstance, f_pChannelOpen, ChannelIndexConf ); if ( ulResult != cOCT6100_ERR_OK ) goto out; kfree(ChannelIndexConf); return cOCT6100_ERR_OK; out: kfree(ChannelIndexConf); return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChannelParams Description: Checks the user's echo cancellation channel open configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to echo cancellation channel open configuration structure. f_pChanIndexConf Pointer to a structure used to store the multiple resources indexes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChannelParams UINT32 Oct6100ApiCheckChannelParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ) { tPOCT6100_CHANNEL_OPEN_TDM pTdmConfig; tPOCT6100_CHANNEL_OPEN_VQE pVqeConfig; tPOCT6100_CHANNEL_OPEN_CODEC pCodecConfig; UINT32 ulDecoderNumTssts; UINT32 ulResult; /* Dereference the configuration structure for clearer code and faster access.*/ pTdmConfig = &f_pChannelOpen->TdmConfig; pVqeConfig = &f_pChannelOpen->VqeConfig; pCodecConfig = &f_pChannelOpen->CodecConfig; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels == 0 ) return cOCT6100_ERR_CHANNEL_DISABLED; if ( f_pChannelOpen->pulChannelHndl == NULL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; if ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NORMAL && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_HT_FREEZE && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_HT_RESET && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_POWER_DOWN && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_EXTERNAL && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION && f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NO_ECHO ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE; /* Check the 2100Hz echo disabling configuration.*/ if ( f_pChannelOpen->fEnableToneDisabler != TRUE && f_pChannelOpen->fEnableToneDisabler != FALSE ) return cOCT6100_ERR_CHANNEL_TONE_DISABLER_ENABLE; /* Check the extended Tone Detection flag value.*/ if ( f_pChannelOpen->fEnableExtToneDetection != TRUE && f_pChannelOpen->fEnableExtToneDetection != FALSE ) return cOCT6100_ERR_CHANNEL_ENABLE_EXT_TONE_DETECTION; /* Check that extented tone detection is actually enabled by the user. */ if ( ( f_pChannelOpen->fEnableExtToneDetection == TRUE ) && ( f_pApiInstance->pSharedInfo->ChipConfig.fEnableExtToneDetection == FALSE ) ) return cOCT6100_ERR_CHANNEL_EXT_TONE_DETECTION_DISABLED; /*==============================================================================*/ /* Check the TDM configuration parameters.*/ ulResult = Oct6100ApiCheckTdmConfig( f_pApiInstance, pTdmConfig ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Now validate the VQE parameters */ ulResult = Oct6100ApiCheckVqeConfig( f_pApiInstance, pVqeConfig, f_pChannelOpen->fEnableToneDisabler ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Verify if the echo operation mode selected can be applied. */ if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) && ( pVqeConfig->fEnableNlp == FALSE ) ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_NLP_REQUIRED; if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) && ( pVqeConfig->fEnableNlp == FALSE ) ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_NLP_REQUIRED; /* Comfort noise must be activated for speech recognition mode to work. */ if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) && ( pVqeConfig->ulComfortNoiseMode == cOCT6100_COMFORT_NOISE_OFF ) ) return cOCT6100_ERR_CHANNEL_COMFORT_NOISE_REQUIRED; /*==============================================================================*/ /*==============================================================================*/ /* Finally, validate the CODEC configuration.*/ if ( pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) ulDecoderNumTssts = pTdmConfig->ulRinNumTssts; else /* pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ ulDecoderNumTssts = pTdmConfig->ulSinNumTssts; ulResult = Oct6100ApiCheckCodecConfig( f_pApiInstance, pCodecConfig, ulDecoderNumTssts, &f_pChanIndexConf->usPhasingTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* make sure that if silence suppression is activated, the NLP is enabled.*/ if ( pCodecConfig->fEnableSilenceSuppression == TRUE && pVqeConfig->fEnableNlp == FALSE ) return cOCT6100_ERR_CHANNEL_SIL_SUP_NLP_MUST_BE_ENABLED; /* Verify if law conversion is allowed. */ if ( pCodecConfig->ulEncoderPort == cOCT6100_NO_ENCODING || pCodecConfig->ulDecoderPort == cOCT6100_NO_DECODING ) { /* No law conversion can occurs if one ADPCM memory is not reserved.*/ if ( pTdmConfig->ulRinPcmLaw != pTdmConfig->ulRoutPcmLaw ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_LAW_TRANSLATION; if ( pTdmConfig->ulSinPcmLaw != pTdmConfig->ulSoutPcmLaw ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_LAW_TRANSLATION; } /* Verify if the config supports extended tone detection.*/ if ( f_pChannelOpen->fEnableExtToneDetection == TRUE ) { if ( pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) return cOCT6100_ERR_CHANNEL_EXT_TONE_DETECTION_DECODER_PORT; } /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveChannelResources Description: Reserves all resources needed for the new channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to echo cancellation channel configuration structure. f_pulChannelIndex Allocated entry in ECHO channel list. f_pChanIndexConf Pointer to a structure used to store the multiple resources indexes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveChannelResources UINT32 Oct6100ApiReserveChannelResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_CHANNEL_OPEN_TDM pTdmConfig; tPOCT6100_CHANNEL_OPEN_CODEC pCodecConfig; UINT32 ulResult; UINT32 ulTempVar; UINT32 ulFreeMixerEventCnt; BOOL fRinTsstEntry = FALSE; BOOL fSinTsstEntry = FALSE; BOOL fRoutTsstEntry = FALSE; BOOL fSoutTsstEntry = FALSE; BOOL fRinRoutTsiMemEntry = FALSE; BOOL fSinSoutTsiMemEntry = FALSE; BOOL fEchoChanEntry = FALSE; PUINT16 pusRinRoutConversionMemIndex = NULL; PUINT16 pusSinSoutConversionMemIndex = NULL; BOOL fRinRoutConversionMemEntry = FALSE; BOOL fSinSoutConversionMemEntry = FALSE; BOOL fExtToneChanEntry = FALSE; BOOL fExtToneTsiEntry = FALSE; BOOL fExtToneMixerEntry = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a local pointer to the configuration structures.*/ pTdmConfig = &f_pChannelOpen->TdmConfig; pCodecConfig = &f_pChannelOpen->CodecConfig; /*===============================================================================*/ /* Reserve Echo and TSI entries. */ ulResult = Oct6100ApiReserveEchoEntry( f_pApiInstance, &f_pChanIndexConf->usEchoChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fEchoChanEntry = TRUE; /* Set the echo, encoder and decoder memory indexes.*/ f_pChanIndexConf->usEchoMemIndex = f_pChanIndexConf->usEchoChanIndex; /* Reserve an entry for the RIN/ROUT tsi chariot memory. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &f_pChanIndexConf->usRinRoutTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fRinRoutTsiMemEntry = TRUE; /* Reserve an entry for the SIN/SOUT tsi chariot memory. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &f_pChanIndexConf->usSinSoutTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fSinSoutTsiMemEntry = TRUE; /* Reserve an ADPCM memory block for compression if required.*/ if ( pCodecConfig->ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { pusRinRoutConversionMemIndex = &f_pChanIndexConf->usRinRoutConversionMemIndex; } else if ( pCodecConfig->ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT ) { pusSinSoutConversionMemIndex = &f_pChanIndexConf->usSinSoutConversionMemIndex; } /* Reserve an ADPCM memory block for decompression if required.*/ if ( pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { pusRinRoutConversionMemIndex = &f_pChanIndexConf->usRinRoutConversionMemIndex; } else if ( pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN ) { pusSinSoutConversionMemIndex = &f_pChanIndexConf->usSinSoutConversionMemIndex; } /* Reserve the conversion memories. */ if ( pusRinRoutConversionMemIndex != NULL ) { /* Reserve a conversion memory for the Rin/Rout stream. */ ulResult = Oct6100ApiReserveConversionMemEntry( f_pApiInstance, pusRinRoutConversionMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fRinRoutConversionMemEntry = TRUE; } } else { /* No conversion memory reserved.*/ f_pChanIndexConf->usRinRoutConversionMemIndex = cOCT6100_INVALID_INDEX; } if ( ( pusSinSoutConversionMemIndex != NULL ) && ( ulResult == cOCT6100_ERR_OK ) ) { /* Reserve a conversion memory for the Sin/Sout stream. */ ulResult = Oct6100ApiReserveConversionMemEntry( f_pApiInstance, pusSinSoutConversionMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fSinSoutConversionMemEntry = TRUE; } } else { /* No conversion memory reserved.*/ f_pChanIndexConf->usSinSoutConversionMemIndex = cOCT6100_INVALID_INDEX; } /* Reserve any resources required if the extended Tone detection is enabled.*/ if ( f_pChannelOpen->fEnableExtToneDetection == TRUE ) { ulResult = Oct6100ApiReserveEchoEntry( f_pApiInstance, &f_pChanIndexConf->usExtToneChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fExtToneChanEntry = TRUE; /* Reserve an entry for the TSI chariot memory for the additionnal channel. */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &f_pChanIndexConf->usExtToneTsiIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fExtToneTsiEntry = TRUE; /* Reserve an entry for the TSI chariot memory for the additionnal channel. */ ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &f_pChanIndexConf->usExtToneMixerIndex ); if ( ulResult == cOCT6100_ERR_OK ) fExtToneMixerEntry = TRUE; } } } else { f_pChanIndexConf->usExtToneChanIndex = cOCT6100_INVALID_INDEX; f_pChanIndexConf->usExtToneMixerIndex = cOCT6100_INVALID_INDEX; f_pChanIndexConf->usExtToneTsiIndex = cOCT6100_INVALID_INDEX; } } else { /* Return an error other then a Fatal.*/ ulResult = cOCT6100_ERR_CHANNEL_OUT_OF_TSI_MEMORY; } } else { /* Return an error other then a Fatal.*/ ulResult = cOCT6100_ERR_CHANNEL_OUT_OF_TSI_MEMORY; } } /*===============================================================================*/ /*===============================================================================*/ /* Now reserve the TSST entries if required.*/ /* Reserve the Rin TSST entry */ if ( (ulResult == cOCT6100_ERR_OK ) && (pTdmConfig->ulRinTimeslot != cOCT6100_UNASSIGNED && pTdmConfig->ulRinStream != cOCT6100_UNASSIGNED) ) { ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pTdmConfig->ulRinTimeslot, pTdmConfig->ulRinStream, pTdmConfig->ulRinNumTssts, cOCT6100_INPUT_TSST, &f_pChanIndexConf->usRinTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) fRinTsstEntry = TRUE; } else { f_pChanIndexConf->usRinTsstIndex = cOCT6100_INVALID_INDEX; } if ( (ulResult == cOCT6100_ERR_OK ) && (pTdmConfig->ulSinTimeslot != cOCT6100_UNASSIGNED && pTdmConfig->ulSinStream != cOCT6100_UNASSIGNED) ) { /* Reserve the Sin TSST entry.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pTdmConfig->ulSinTimeslot, pTdmConfig->ulSinStream, pTdmConfig->ulSinNumTssts, cOCT6100_INPUT_TSST, &f_pChanIndexConf->usSinTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) fSinTsstEntry = TRUE; } else { f_pChanIndexConf->usSinTsstIndex = cOCT6100_INVALID_INDEX; } if ( (ulResult == cOCT6100_ERR_OK ) && (pTdmConfig->ulRoutTimeslot != cOCT6100_UNASSIGNED && pTdmConfig->ulRoutStream != cOCT6100_UNASSIGNED) ) { /* Reserve the Rout TSST entry.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pTdmConfig->ulRoutTimeslot, pTdmConfig->ulRoutStream, pTdmConfig->ulRoutNumTssts, cOCT6100_OUTPUT_TSST, &f_pChanIndexConf->usRoutTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) fRoutTsstEntry = TRUE; } else { f_pChanIndexConf->usRoutTsstIndex = cOCT6100_INVALID_INDEX; } if ( (ulResult == cOCT6100_ERR_OK ) && (pTdmConfig->ulSoutTimeslot != cOCT6100_UNASSIGNED && pTdmConfig->ulSoutStream != cOCT6100_UNASSIGNED) ) { /* Reserve the Sout TSST entry.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pTdmConfig->ulSoutTimeslot, pTdmConfig->ulSoutStream, pTdmConfig->ulSoutNumTssts, cOCT6100_OUTPUT_TSST, &f_pChanIndexConf->usSoutTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) fSoutTsstEntry = TRUE; } else { f_pChanIndexConf->usSoutTsstIndex = cOCT6100_INVALID_INDEX; } /*===============================================================================*/ /*===============================================================================*/ /* Check if there are a couple of mixer events available for us. */ if ( ulResult == cOCT6100_ERR_OK ) { UINT32 ulMixerEventCntNeeded = 0; /* Calculate how many mixer events are needed. */ if ( f_pChanIndexConf->usRinTsstIndex == cOCT6100_INVALID_INDEX ) ulMixerEventCntNeeded++; if ( f_pChanIndexConf->usSinTsstIndex == cOCT6100_INVALID_INDEX ) ulMixerEventCntNeeded++; /* If at least 1 mixer event is needed, check if those are available. */ if ( ulMixerEventCntNeeded != 0 ) { ulResult = Oct6100ApiGetFreeMixerEventCnt( f_pApiInstance, &ulFreeMixerEventCnt ); if ( ulResult == cOCT6100_ERR_OK ) { /* The API might need more mixer events if the ports have to be muted. */ /* Check if these are available. */ if ( ulFreeMixerEventCnt < ulMixerEventCntNeeded ) { ulResult = cOCT6100_ERR_CHANNEL_OUT_OF_MIXER_EVENTS; } } } } /*===============================================================================*/ /*===============================================================================*/ /* Release the resources if something went wrong */ if ( ulResult != cOCT6100_ERR_OK ) { /*===============================================================================*/ /* Release the previously reserved resources .*/ if( fRinTsstEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->ulRinTimeslot, pTdmConfig->ulRinStream, pTdmConfig->ulRinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fSinTsstEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->ulSinTimeslot, pTdmConfig->ulSinStream, pTdmConfig->ulSinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fRoutTsstEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->ulRoutTimeslot, pTdmConfig->ulRoutStream, pTdmConfig->ulRoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fSoutTsstEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->ulSoutTimeslot, pTdmConfig->ulSoutStream, pTdmConfig->ulSoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fRinRoutTsiMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, f_pChanIndexConf->usRinRoutTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fSinSoutTsiMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, f_pChanIndexConf->usSinSoutTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /*===============================================================================*/ /*===============================================================================*/ /* Release the previously reserved echo resources .*/ if( fEchoChanEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseEchoEntry( f_pApiInstance, f_pChanIndexConf->usEchoChanIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /*===============================================================================*/ /*===============================================================================*/ /* Release the previously reserved resources for the extended tone detection.*/ if( fExtToneChanEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseEchoEntry( f_pApiInstance, f_pChanIndexConf->usExtToneChanIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fExtToneTsiEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, f_pChanIndexConf->usExtToneTsiIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fExtToneMixerEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, f_pChanIndexConf->usExtToneMixerIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /*===============================================================================*/ /*===============================================================================*/ /* Release the conversion resources. */ if( fRinRoutConversionMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, f_pChanIndexConf->usRinRoutConversionMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fSinSoutConversionMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, f_pChanIndexConf->usSinSoutConversionMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /*===============================================================================*/ return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteChannelStructs Description: Performs all the required structure writes to configure the new echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to echo cancellation channel configuration structure. f_pChanIndexConf Pointer to a structure used to store the multiple resources indexes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteChannelStructs UINT32 Oct6100ApiWriteChannelStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_CHANNEL_OPEN_TDM pTdmConfig; tOCT6100_WRITE_PARAMS WriteParams; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; UINT32 ulDwordAddress; UINT32 ulDwordData; BOOL fConversionEnabled = FALSE; BOOL fProgramAdpcmMem; UINT32 ulCompType = 0; UINT32 ulPcmLaw; UINT16 usTempTsiMemIndex; UINT16 usConversionMemIndex; UINT32 ulToneEventNumber; BOOL fSSTone; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a local pointer to the TDM configuration structure.*/ pTdmConfig = &f_pChannelOpen->TdmConfig; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_pChanIndexConf->usEchoChanIndex ); /*==============================================================================*/ /* Configure the Input Tsst control memory.*/ /* Set the RIN Tsst control entry.*/ if ( f_pChanIndexConf->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_pChanIndexConf->usRinTsstIndex, f_pChanIndexConf->usRinRoutTsiMemIndex, pTdmConfig->ulRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Set the SIN Tsst control entry.*/ if ( f_pChanIndexConf->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_pChanIndexConf->usSinTsstIndex, f_pChanIndexConf->usSinSoutTsiMemIndex, pTdmConfig->ulSinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /*==============================================================================*/ /* Configure the ADPCM control memory for the Decoder.*/ /* Set the codec state flags.*/ f_pChanIndexConf->fRinRoutCodecActive = FALSE; f_pChanIndexConf->fSinSoutCodecActive = FALSE; if ( f_pChannelOpen->CodecConfig.ulDecoderPort != cOCT6100_NO_DECODING ) { fProgramAdpcmMem = TRUE; switch( f_pChannelOpen->CodecConfig.ulDecodingRate ) { case cOCT6100_G711_64KBPS: ulCompType = 0x8; if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { if ( pTdmConfig->ulRinPcmLaw == pTdmConfig->ulRoutPcmLaw ) fProgramAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( pTdmConfig->ulRinStream == cOCT6100_UNASSIGNED ) || ( pTdmConfig->ulRoutStream == cOCT6100_UNASSIGNED ) ) fProgramAdpcmMem = FALSE; } else /* f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ { if ( pTdmConfig->ulSinPcmLaw == pTdmConfig->ulSoutPcmLaw ) fProgramAdpcmMem = FALSE; if ( ( pTdmConfig->ulSinStream == cOCT6100_UNASSIGNED ) || ( pTdmConfig->ulSoutStream == cOCT6100_UNASSIGNED ) ) fProgramAdpcmMem = FALSE; } break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; fConversionEnabled = TRUE; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; fConversionEnabled = TRUE; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; fConversionEnabled = TRUE; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; fConversionEnabled = TRUE; break; case cOCT6100_G727_2C_ENCODED: ulCompType = 0x4; fConversionEnabled = TRUE; break; case cOCT6100_G727_3C_ENCODED: ulCompType = 0x5; fConversionEnabled = TRUE; break; case cOCT6100_G727_4C_ENCODED: ulCompType = 0x6; fConversionEnabled = TRUE; break; case cOCT6100_G726_ENCODED: ulCompType = 0x9; fConversionEnabled = TRUE; break; case cOCT6100_G711_G726_ENCODED: ulCompType = 0xA; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_2C_ENCODED: ulCompType = 0xC; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_3C_ENCODED: ulCompType = 0xD; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_4C_ENCODED: ulCompType = 0xE; fConversionEnabled = TRUE; break; default: return cOCT6100_ERR_FATAL_D4; } if ( fProgramAdpcmMem == TRUE ) { /* Set the chariot memory based on the selected port.*/ if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { usTempTsiMemIndex = f_pChanIndexConf->usRinRoutTsiMemIndex; ulPcmLaw = pTdmConfig->ulRoutPcmLaw; /* Set the law for later use */ /* Set the codec state flags.*/ f_pChanIndexConf->fRinRoutCodecActive = TRUE; /* Set the conversion memory index to use for decompression */ usConversionMemIndex = f_pChanIndexConf->usRinRoutConversionMemIndex; } else /* f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ { usTempTsiMemIndex = f_pChanIndexConf->usSinSoutTsiMemIndex; ulPcmLaw = pTdmConfig->ulSoutPcmLaw; /* Set the law for later use */ /* Set the codec state flags.*/ f_pChanIndexConf->fSinSoutCodecActive = TRUE; /* Set the conversion memory index to use for decompression */ usConversionMemIndex = f_pChanIndexConf->usSinSoutConversionMemIndex; } ulResult = Oct6100ApiWriteDecoderMemory( f_pApiInstance, usConversionMemIndex, ulCompType, usTempTsiMemIndex, ulPcmLaw, f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Configure the ADPCM control memory for the Encoder */ if ( f_pChannelOpen->CodecConfig.ulEncoderPort != cOCT6100_NO_ENCODING ) { fProgramAdpcmMem = TRUE; switch( f_pChannelOpen->CodecConfig.ulEncodingRate ) { case cOCT6100_G711_64KBPS: if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { if ( pTdmConfig->ulRoutPcmLaw == cOCT6100_PCM_U_LAW ) ulCompType = 0x4; else ulCompType = 0x5; /* Check for law conversion.*/ if ( pTdmConfig->ulRinPcmLaw == pTdmConfig->ulRoutPcmLaw ) fProgramAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( pTdmConfig->ulRinStream == cOCT6100_UNASSIGNED ) || ( pTdmConfig->ulRoutStream == cOCT6100_UNASSIGNED ) ) fProgramAdpcmMem = FALSE; } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { if ( pTdmConfig->ulSoutPcmLaw == cOCT6100_PCM_U_LAW ) ulCompType = 0x4; else ulCompType = 0x5; /* Check for law conversion.*/ if ( pTdmConfig->ulSinPcmLaw == pTdmConfig->ulSoutPcmLaw ) fProgramAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( pTdmConfig->ulSinStream == cOCT6100_UNASSIGNED ) || ( pTdmConfig->ulSoutStream == cOCT6100_UNASSIGNED ) ) fProgramAdpcmMem = FALSE; } break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; fConversionEnabled = TRUE; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; fConversionEnabled = TRUE; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; fConversionEnabled = TRUE; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_4_1: ulCompType = 0xD; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_3_2: ulCompType = 0xA; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_2_3: ulCompType = 0x6; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_4_0: ulCompType = 0xE; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_3_1: ulCompType = 0xB; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_2_2: ulCompType = 0x7; fConversionEnabled = TRUE; break; case cOCT6100_G727_24KBPS_3_0: ulCompType = 0xC; fConversionEnabled = TRUE; break; case cOCT6100_G727_24KBPS_2_1: ulCompType = 0x8; fConversionEnabled = TRUE; break; case cOCT6100_G727_16KBPS_2_0: ulCompType = 0x9; fConversionEnabled = TRUE; break; default: return cOCT6100_ERR_FATAL_D5; } /* Program the APDCM memory only if ADPCM is requried.*/ if ( fProgramAdpcmMem == TRUE || f_pChanIndexConf->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { /* Set the chariot memory based on the selected port.*/ if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { usTempTsiMemIndex = f_pChanIndexConf->usRinRoutTsiMemIndex; /* Set the codec state flags.*/ f_pChanIndexConf->fRinRoutCodecActive = TRUE; /* Set the conversion memory index to use for compression */ usConversionMemIndex = f_pChanIndexConf->usRinRoutConversionMemIndex; } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { usTempTsiMemIndex = f_pChanIndexConf->usSinSoutTsiMemIndex; /* Set the codec state flags.*/ f_pChanIndexConf->fSinSoutCodecActive = TRUE; /* Set the conversion memory index to use for compression */ usConversionMemIndex = f_pChanIndexConf->usSinSoutConversionMemIndex; } ulResult = Oct6100ApiWriteEncoderMemory( f_pApiInstance, usConversionMemIndex, ulCompType, usTempTsiMemIndex, f_pChannelOpen->CodecConfig.fEnableSilenceSuppression, f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition, f_pChanIndexConf->usPhasingTsstIndex, f_pChannelOpen->CodecConfig.ulPhasingType, f_pChannelOpen->CodecConfig.ulPhase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Clearing the tone events bit vector */ ulDwordAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_pChanIndexConf->usEchoChanIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ulDwordAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; ulDwordData = 0x00000000; ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulDwordAddress, ulDwordData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulDwordAddress += 4; ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulDwordAddress, ulDwordData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Write the VQE memory */ ulResult = Oct6100ApiWriteVqeMemory( f_pApiInstance, &f_pChannelOpen->VqeConfig, f_pChannelOpen, f_pChanIndexConf->usEchoChanIndex, f_pChanIndexConf->usEchoMemIndex, TRUE, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Write the echo memory */ ulResult = Oct6100ApiWriteEchoMemory( f_pApiInstance, pTdmConfig, f_pChannelOpen, f_pChanIndexConf->usEchoMemIndex, f_pChanIndexConf->usRinRoutTsiMemIndex, f_pChanIndexConf->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Mute channel if required, this is done on a port basis */ /* Initialize the silence indexes to invalid for now. */ pChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; pChanEntry->usSinSilenceEventIndex = cOCT6100_INVALID_INDEX; /* Set the TSI memory indexes. */ pChanEntry->usRinRoutTsiMemIndex = f_pChanIndexConf->usRinRoutTsiMemIndex; pChanEntry->usSinSoutTsiMemIndex = f_pChanIndexConf->usSinSoutTsiMemIndex; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_pChanIndexConf->usEchoChanIndex, f_pChanIndexConf->usRinTsstIndex, f_pChanIndexConf->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Set the dominant speaker to unassigned, if required. */ if ( f_pApiInstance->pSharedInfo->ImageInfo.fDominantSpeakerEnabled == TRUE ) { ulResult = Oct6100ApiBridgeSetDominantSpeaker( f_pApiInstance, f_pChanIndexConf->usEchoChanIndex, cOCT6100_CONF_DOMINANT_SPEAKER_UNASSIGNED ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /*==============================================================================*/ /* If necessary, configure the extended tone detection channel.*/ if ( f_pChannelOpen->fEnableExtToneDetection == TRUE ) { UINT32 ulTempSinLaw; UINT32 ulTempSoutLaw; UINT32 ulTempEchoOpMode; /* save the original law.*/ ulTempSinLaw = pTdmConfig->ulSinPcmLaw; ulTempSoutLaw = pTdmConfig->ulSoutPcmLaw; ulTempEchoOpMode = f_pChannelOpen->ulEchoOperationMode; /* Now, make sure the Sin and Sout law are the same as the Rin law.*/ pTdmConfig->ulSinPcmLaw = pTdmConfig->ulRinPcmLaw; pTdmConfig->ulSoutPcmLaw = pTdmConfig->ulRinPcmLaw; f_pChannelOpen->ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL; /* Write the Echo and VQE memory of the extended channel.*/ ulResult = Oct6100ApiWriteDebugChanMemory( f_pApiInstance, pTdmConfig, &f_pChannelOpen->VqeConfig, f_pChannelOpen, f_pChanIndexConf->usExtToneChanIndex, f_pChanIndexConf->usExtToneChanIndex, cOCT6100_API_EXT_TONE_EXTRA_TSI, f_pChanIndexConf->usExtToneTsiIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now, write the mixer event used to copy the RIN signal of the original channel into the SIN signal of the exteded channel. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_pChanIndexConf->usExtToneMixerIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= f_pChanIndexConf->usRinRoutTsiMemIndex; WriteParams.usWriteData |= pTdmConfig->ulRinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = f_pChanIndexConf->usExtToneTsiIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Now insert the Sin copy event into the list.*/ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_pChanIndexConf->usExtToneMixerIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_pChanIndexConf->usEchoChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*==============================================================================*/ /* Clearing the tone events bit vector */ ulDwordAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_pChanIndexConf->usExtToneChanIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ); ulDwordAddress += cOCT6100_CH_MAIN_TONE_EVENT_OFFSET; ulDwordData = 0x00000000; ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulDwordAddress, ulDwordData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulDwordAddress += 4; ulResult = Oct6100ApiWriteDword( f_pApiInstance, ulDwordAddress, ulDwordData ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Write back the original values in the channel open structure.*/ pTdmConfig->ulSinPcmLaw = ulTempSinLaw; pTdmConfig->ulSoutPcmLaw = ulTempSoutLaw; f_pChannelOpen->ulEchoOperationMode = ulTempEchoOpMode; } /*==============================================================================*/ /*==============================================================================*/ /* If necessary, configure the SS tone detection. */ for ( ulToneEventNumber = 0; ulToneEventNumber < cOCT6100_MAX_TONE_EVENT; ulToneEventNumber++ ) { /* Check if the current tone is a SS tone. */ ulResult = Oct6100ApiIsSSTone( f_pApiInstance, f_pApiInstance->pSharedInfo->ImageInfo.aToneInfo[ ulToneEventNumber ].ulToneID, &fSSTone ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( fSSTone == TRUE ) { /* Write to all resources needed to activate tone detection on this SS tone. */ ulResult = Oct6100ApiWriteToneDetectEvent( f_pApiInstance, f_pChanIndexConf->usEchoChanIndex, ulToneEventNumber, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Configure the Output Tsst control memory.*/ /* Set the ROUT Tsst control entry.*/ if ( f_pChanIndexConf->usRoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_pChanIndexConf->usRoutTsstIndex, f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition, pTdmConfig->ulRoutNumTssts, f_pChanIndexConf->usRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Set the SOUT Tsst control entry.*/ if ( f_pChanIndexConf->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_pChanIndexConf->usSoutTsstIndex, f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition, pTdmConfig->ulSoutNumTssts, f_pChanIndexConf->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateChannelEntry Description: Updates the new channel in the ECHO channel list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelOpen Pointer to echo cancellation channel configuration structure. f_pChanIndexConf Pointer to a structure used to store the multiple resources indexes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateChannelEntry UINT32 Oct6100ApiUpdateChannelEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, OUT tPOCT6100_API_ECHO_CHAN_INDEX f_pChanIndexConf ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_CHANNEL_OPEN_TDM pTdmConfig; tPOCT6100_CHANNEL_OPEN_VQE pVqeConfig; tPOCT6100_CHANNEL_OPEN_CODEC pCodecConfig; /* Obtain a pointer to the config structures of the tPOCT6100_CHANNEL_OPEN structure. */ pTdmConfig = &f_pChannelOpen->TdmConfig; pVqeConfig = &f_pChannelOpen->VqeConfig; pCodecConfig = &f_pChannelOpen->CodecConfig; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_pChanIndexConf->usEchoChanIndex ) /*=======================================================================*/ /* Copy the channel's configuration and allocated resources. */ pChanEntry->ulUserChanId = f_pChannelOpen->ulUserChanId; pChanEntry->byEchoOperationMode = (UINT8)( f_pChannelOpen->ulEchoOperationMode & 0xFF ); pChanEntry->fEnableToneDisabler = (UINT8)( f_pChannelOpen->fEnableToneDisabler & 0xFF ); pChanEntry->fEnableExtToneDetection = (UINT8)( f_pChannelOpen->fEnableExtToneDetection & 0xFF ); /* Save the VQE configuration.*/ pChanEntry->VqeConfig.byComfortNoiseMode = (UINT8)( pVqeConfig->ulComfortNoiseMode & 0xFF ); pChanEntry->VqeConfig.fEnableNlp = (UINT8)( pVqeConfig->fEnableNlp & 0xFF ); pChanEntry->VqeConfig.fEnableTailDisplacement = (UINT8)( pVqeConfig->fEnableTailDisplacement ); pChanEntry->VqeConfig.usTailDisplacement = (UINT16)( pVqeConfig->ulTailDisplacement & 0xFFFF ); pChanEntry->VqeConfig.usTailLength = (UINT16)( pVqeConfig->ulTailLength & 0xFFFF ); pChanEntry->VqeConfig.fSinDcOffsetRemoval = (UINT8)( pVqeConfig->fSinDcOffsetRemoval & 0xFF ); pChanEntry->VqeConfig.fRinDcOffsetRemoval = (UINT8)( pVqeConfig->fRinDcOffsetRemoval & 0xFF ); pChanEntry->VqeConfig.fRinLevelControl = (UINT8)( pVqeConfig->fRinLevelControl & 0xFF ); pChanEntry->VqeConfig.chRinLevelControlGainDb = (OCT_INT8)( pVqeConfig->lRinLevelControlGainDb & 0xFF ); pChanEntry->VqeConfig.fSoutLevelControl = (UINT8)( pVqeConfig->fSoutLevelControl & 0xFF ); pChanEntry->VqeConfig.chSoutLevelControlGainDb = (OCT_INT8)( pVqeConfig->lSoutLevelControlGainDb & 0xFF ); pChanEntry->VqeConfig.fRinAutomaticLevelControl = (UINT8)( pVqeConfig->fRinAutomaticLevelControl & 0xFF ); pChanEntry->VqeConfig.chRinAutomaticLevelControlTargetDb = (OCT_INT8)( pVqeConfig->lRinAutomaticLevelControlTargetDb & 0xFF ); pChanEntry->VqeConfig.fSoutAutomaticLevelControl = (UINT8)( pVqeConfig->fSoutAutomaticLevelControl & 0xFF ); pChanEntry->VqeConfig.chSoutAutomaticLevelControlTargetDb = (OCT_INT8)( pVqeConfig->lSoutAutomaticLevelControlTargetDb & 0xFF ); pChanEntry->VqeConfig.fRinHighLevelCompensation = (UINT8)( pVqeConfig->fRinHighLevelCompensation & 0xFF ); pChanEntry->VqeConfig.chRinHighLevelCompensationThresholdDb = (OCT_INT8)( pVqeConfig->lRinHighLevelCompensationThresholdDb & 0xFF ); pChanEntry->VqeConfig.fSoutAdaptiveNoiseReduction = (UINT8)( pVqeConfig->fSoutAdaptiveNoiseReduction & 0xFF ); pChanEntry->VqeConfig.fSoutNoiseBleaching = (UINT8)( pVqeConfig->fSoutNoiseBleaching & 0xFF ); pChanEntry->VqeConfig.fSoutConferencingNoiseReduction = (UINT8)( pVqeConfig->fSoutConferencingNoiseReduction & 0xFF ); pChanEntry->VqeConfig.fAcousticEcho = (UINT8)( pVqeConfig->fAcousticEcho & 0xFF ); pChanEntry->VqeConfig.fDtmfToneRemoval = (UINT8)( pVqeConfig->fDtmfToneRemoval & 0xFF ); pChanEntry->VqeConfig.chDefaultErlDb = (OCT_INT8)( pVqeConfig->lDefaultErlDb & 0xFF ); pChanEntry->VqeConfig.chAecDefaultErlDb = (OCT_INT8)( pVqeConfig->lAecDefaultErlDb & 0xFF ); pChanEntry->VqeConfig.usAecTailLength = (UINT16)( pVqeConfig->ulAecTailLength & 0xFFFF ); pChanEntry->VqeConfig.byNonLinearityBehaviorA = (UINT8)( pVqeConfig->ulNonLinearityBehaviorA & 0xFF ); pChanEntry->VqeConfig.byNonLinearityBehaviorB = (UINT8)( pVqeConfig->ulNonLinearityBehaviorB & 0xFF ); pChanEntry->VqeConfig.byDoubleTalkBehavior = (UINT8)( pVqeConfig->ulDoubleTalkBehavior & 0xFF ); pChanEntry->VqeConfig.chAnrSnrEnhancementDb = (OCT_INT8)( pVqeConfig->lAnrSnrEnhancementDb & 0xFF ); pChanEntry->VqeConfig.byAnrVoiceNoiseSegregation = (UINT8)( pVqeConfig->ulAnrVoiceNoiseSegregation & 0xFF ); pChanEntry->VqeConfig.usToneDisablerVqeActivationDelay = (UINT16)( pVqeConfig->ulToneDisablerVqeActivationDelay & 0xFFFF ); pChanEntry->VqeConfig.bySoutAutomaticListenerEnhancementGainDb = (UINT8)( pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb & 0xFF ); pChanEntry->VqeConfig.bySoutNaturalListenerEnhancementGainDb = (UINT8)( pVqeConfig->ulSoutNaturalListenerEnhancementGainDb & 0xFF ); pChanEntry->VqeConfig.fSoutNaturalListenerEnhancement = (UINT8)( pVqeConfig->fSoutNaturalListenerEnhancement & 0xFF ); pChanEntry->VqeConfig.fRoutNoiseReduction = (UINT8)( pVqeConfig->fRoutNoiseReduction & 0xFF ); pChanEntry->VqeConfig.chRoutNoiseReductionLevelGainDb = (OCT_INT8) (pVqeConfig->lRoutNoiseReductionLevelGainDb & 0xFF); pChanEntry->VqeConfig.fEnableMusicProtection = (UINT8)( pVqeConfig->fEnableMusicProtection & 0xFF ); pChanEntry->VqeConfig.fIdleCodeDetection = (UINT8)( pVqeConfig->fIdleCodeDetection & 0xFF ); /* Save the codec information.*/ pChanEntry->CodecConfig.byAdpcmNibblePosition = (UINT8)( pCodecConfig->ulAdpcmNibblePosition & 0xFF ); pChanEntry->CodecConfig.byDecoderPort = (UINT8)( pCodecConfig->ulDecoderPort & 0xFF ); pChanEntry->CodecConfig.byDecodingRate = (UINT8)( pCodecConfig->ulDecodingRate & 0xFF ); pChanEntry->CodecConfig.byEncoderPort = (UINT8)( pCodecConfig->ulEncoderPort & 0xFF ); pChanEntry->CodecConfig.byEncodingRate = (UINT8)( pCodecConfig->ulEncodingRate & 0xFF ); pChanEntry->CodecConfig.fEnableSilenceSuppression = (UINT8)( pCodecConfig->fEnableSilenceSuppression & 0xFF ); pChanEntry->CodecConfig.byPhase = (UINT8)( pCodecConfig->ulPhase & 0xFF ); pChanEntry->CodecConfig.byPhasingType = (UINT8)( pCodecConfig->ulPhasingType & 0xFF ); /* Save the RIN settings.*/ pChanEntry->TdmConfig.byRinPcmLaw = (UINT8)( pTdmConfig->ulRinPcmLaw & 0xFF ); pChanEntry->TdmConfig.usRinTimeslot = (UINT16)( pTdmConfig->ulRinTimeslot & 0xFFFF ); pChanEntry->TdmConfig.usRinStream = (UINT16)( pTdmConfig->ulRinStream & 0xFFFF ); /* Save the SIN settings.*/ pChanEntry->TdmConfig.bySinPcmLaw = (UINT8)( pTdmConfig->ulSinPcmLaw & 0xFF ); pChanEntry->TdmConfig.usSinTimeslot = (UINT16)( pTdmConfig->ulSinTimeslot & 0xFFFF ); pChanEntry->TdmConfig.usSinStream = (UINT16)( pTdmConfig->ulSinStream & 0xFFFF ); /* Save the ROUT settings.*/ pChanEntry->TdmConfig.byRoutPcmLaw = (UINT8)( pTdmConfig->ulRoutPcmLaw & 0xFF ); pChanEntry->TdmConfig.usRoutTimeslot = (UINT16)( pTdmConfig->ulRoutTimeslot & 0xFFFF ); pChanEntry->TdmConfig.usRoutStream = (UINT16)( pTdmConfig->ulRoutStream & 0xFFFF ); pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry = cOCT6100_INVALID_INDEX; pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry = 0; /* Save the SOUT settings.*/ pChanEntry->TdmConfig.bySoutPcmLaw = (UINT8)( pTdmConfig->ulSoutPcmLaw & 0xFF ); pChanEntry->TdmConfig.usSoutTimeslot = (UINT16)( pTdmConfig->ulSoutTimeslot & 0xFFFF ); pChanEntry->TdmConfig.usSoutStream = (UINT16)( pTdmConfig->ulSoutStream & 0xFFFF ); pChanEntry->TdmConfig.byRinNumTssts = (UINT8)( pTdmConfig->ulRinNumTssts & 0xFF ); pChanEntry->TdmConfig.bySinNumTssts = (UINT8)( pTdmConfig->ulSinNumTssts & 0xFF ); pChanEntry->TdmConfig.byRoutNumTssts = (UINT8)( pTdmConfig->ulRoutNumTssts & 0xFF ); pChanEntry->TdmConfig.bySoutNumTssts = (UINT8)( pTdmConfig->ulSoutNumTssts & 0xFF ); pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry = cOCT6100_INVALID_INDEX; pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry = 0; /* Save the extended Tone detection information.*/ pChanEntry->usExtToneChanIndex = f_pChanIndexConf->usExtToneChanIndex; pChanEntry->usExtToneMixerIndex = f_pChanIndexConf->usExtToneMixerIndex; pChanEntry->usExtToneTsiIndex = f_pChanIndexConf->usExtToneTsiIndex; if ( f_pChannelOpen->fEnableExtToneDetection == TRUE ) { tPOCT6100_API_CHANNEL pExtToneChanEntry; /* Set the mode of the original channel. He is the channel performing detection on the SIN port. The extended channel will perform detection on the RIN port.*/ pChanEntry->ulExtToneChanMode = cOCT6100_API_EXT_TONE_SIN_PORT_MODE; /* Now, program the associated channel.*/ /* Obtain a pointer to the extended tone detection channel entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pExtToneChanEntry, f_pChanIndexConf->usExtToneChanIndex ); pExtToneChanEntry->fReserved = TRUE; pExtToneChanEntry->ulExtToneChanMode = cOCT6100_API_EXT_TONE_RIN_PORT_MODE; /* Detect on RIN port.*/ pExtToneChanEntry->usExtToneChanIndex = f_pChanIndexConf->usEchoChanIndex; pExtToneChanEntry->aulToneConf[ 0 ] = 0; pExtToneChanEntry->aulToneConf[ 1 ] = 0; } else { /* No extended tone detection supported.*/ pChanEntry->ulExtToneChanMode = cOCT6100_API_EXT_TONE_DISABLED; } /*=======================================================================*/ /*=======================================================================*/ /* Store hardware related information.*/ pChanEntry->usRinRoutTsiMemIndex = f_pChanIndexConf->usRinRoutTsiMemIndex; pChanEntry->usSinSoutTsiMemIndex = f_pChanIndexConf->usSinSoutTsiMemIndex; pChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; pChanEntry->usExtraRinTsiMemIndex = cOCT6100_INVALID_INDEX; /* We are not being tapped for now. */ pChanEntry->fBeingTapped = FALSE; pChanEntry->usTapChanIndex = cOCT6100_INVALID_INDEX; pChanEntry->usTapBridgeIndex = cOCT6100_INVALID_INDEX; /* The copy event has not yet been created. */ pChanEntry->fCopyEventCreated = FALSE; pChanEntry->usRinRoutConversionMemIndex = f_pChanIndexConf->usRinRoutConversionMemIndex; pChanEntry->usSinSoutConversionMemIndex = f_pChanIndexConf->usSinSoutConversionMemIndex; pChanEntry->usPhasingTsstIndex = f_pChanIndexConf->usPhasingTsstIndex; pChanEntry->fSinSoutCodecActive = f_pChanIndexConf->fSinSoutCodecActive; pChanEntry->fRinRoutCodecActive = f_pChanIndexConf->fRinRoutCodecActive; pChanEntry->usEchoMemIndex = f_pChanIndexConf->usEchoMemIndex; pChanEntry->usRinTsstIndex = f_pChanIndexConf->usRinTsstIndex; pChanEntry->usSinTsstIndex = f_pChanIndexConf->usSinTsstIndex; pChanEntry->usRoutTsstIndex = f_pChanIndexConf->usRoutTsstIndex; pChanEntry->usSoutTsstIndex = f_pChanIndexConf->usSoutTsstIndex; pChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; pChanEntry->usSoutCopyEventIndex = cOCT6100_INVALID_INDEX; /* Nothing muted for now. */ pChanEntry->usMutedPorts = cOCT6100_CHANNEL_MUTE_PORT_NONE; /* Set all the GW feature initial value.*/ /* Bridge info */ pChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; pChanEntry->fMute = FALSE; pChanEntry->usLoadEventIndex = cOCT6100_INVALID_INDEX; pChanEntry->usSubStoreEventIndex = cOCT6100_INVALID_INDEX; /* Buffer playout info.*/ pChanEntry->fRinBufPlaying = FALSE; pChanEntry->fSoutBufPlaying = FALSE; /* Tone detection state. */ /* This array is configured as follow.*/ /* Index 0 contain event 0 to 31 (msb = event 31) and Index 1 contain index 32 - 55 */ pChanEntry->aulToneConf[ 0 ] = 0; pChanEntry->aulToneConf[ 1 ] = 0; pChanEntry->ulLastSSToneDetected = (PTR_TYPE)cOCT6100_INVALID_VALUE; pChanEntry->ulLastSSToneTimestamp = (PTR_TYPE)cOCT6100_INVALID_VALUE; /* Initialize the bidirectional flag.*/ pChanEntry->fBiDirChannel = FALSE; /*=======================================================================*/ /* Init some of the stats.*/ pChanEntry->sMaxERL = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->sMaxERLE = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->usMaxEchoDelay = cOCT6100_INVALID_STAT_W; pChanEntry->usNumEchoPathChangesOfst = 0; /*=======================================================================*/ /*=======================================================================*/ /* Update the dependency of the phasing TSST if one is associated to the chanel.*/ if ( f_pChanIndexConf->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { tPOCT6100_API_PHASING_TSST pPhasingEntry; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingEntry, f_pChanIndexConf->usPhasingTsstIndex ); pPhasingEntry->usDependencyCnt++; } /*=======================================================================*/ /*=======================================================================*/ /* Form handle returned to user. */ *f_pChannelOpen->pulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | (pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_pChanIndexConf->usEchoChanIndex; /* Finally, mark the channel as open. */ pChanEntry->fReserved = TRUE; pChanEntry->usExtraSinTsiDependencyCnt = 0; /* Increment the number of channel open.*/ f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels++; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelCloseSer Description: Closes a echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelClose Pointer to echo cancellation channel close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelCloseSer UINT32 Oct6100ChannelCloseSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CLOSE f_pChannelClose ) { UINT16 usChannelIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertChannelParams( f_pApiInstance, f_pChannelClose, &usChannelIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiInvalidateChannelStructs( f_pApiInstance, usChannelIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiReleaseChannelResources( f_pApiInstance, usChannelIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle.*/ f_pChannelClose->ulChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertChannelParams Description: Validate the handle given by the user and verify the state of the channel about to be closed. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelClose Pointer to echo cancellation channel close structure. f_pulFpgaChanIndex Pointer to the FPGA channel index associated to this channel. f_pusChanIndex Pointer to the index of the channel within the API instance. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertChannelParams UINT32 Oct6100ApiAssertChannelParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CLOSE f_pChannelClose, IN OUT PUINT16 f_pusChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pChannelClose->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelClose->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelClose->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; if ( pChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CHANNEL_PART_OF_BIDIR_CHANNEL; /*=======================================================================*/ /* Check if the channel is bound to a bridge. */ if ( pChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_ACTIVE_DEPENDENCIES; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateChannelStructs Description: Closes a echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulFpgaChanIndex Index of the channel within the SCN_PLC FPGA. f_usChanIndex Index of the channel within the API instance. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateChannelStructs UINT32 Oct6100ApiInvalidateChannelStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_CHANNEL_TDM pTdmConfig; tPOCT6100_API_TSST_ENTRY pTsstEntry; tOCT6100_BUFFER_PLAYOUT_STOP BufferPlayoutStop; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_WRITE_SMEAR_PARAMS SmearParams; UINT32 ulResult; UINT16 usCurrentEntry; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ); /* Obtain local pointer to the TDM configuration of the channel */ pTdmConfig = &pChanEntry->TdmConfig; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; SmearParams.pProcessContext = f_pApiInstance->pProcessContext; SmearParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* If this channel is currently debugged, automatically close the debug channel. */ if ( ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) && ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex == f_usChanIndex ) ) { tOCT6100_DEBUG_SELECT_CHANNEL SelectDebugChan; /* Ensure forward compatibility. */ Oct6100DebugSelectChannelDef( &SelectDebugChan ); /* Set the hot channel to an invalid handle to disable recording. */ SelectDebugChan.ulChannelHndl = cOCT6100_INVALID_HANDLE; /* Call the serialized fonction. */ ulResult = Oct6100DebugSelectChannelSer( f_pApiInstance, &SelectDebugChan, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Deactivate the TSST control memory if used. */ /* RIN port.*/ if ( pTdmConfig->usRinTimeslot != cOCT6100_UNASSIGNED ) { /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pChanEntry->usRinTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* SIN port.*/ if ( pTdmConfig->usSinTimeslot != cOCT6100_UNASSIGNED ) { /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pChanEntry->usSinTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*=======================================================================*/ /* ROUT port.*/ if ( pTdmConfig->usRoutTimeslot != cOCT6100_UNASSIGNED ) { /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pChanEntry->usRoutTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now the broadcast TSST.*/ usCurrentEntry = pTdmConfig->usRoutBrdcastTsstFirstEntry; while( usCurrentEntry != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( pSharedInfo, pTsstEntry, usCurrentEntry ); /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pTsstEntry->usTsstMemoryIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move to the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; } /*=======================================================================*/ /*=======================================================================*/ /* SOUT port.*/ if ( pTdmConfig->usSoutTimeslot != cOCT6100_UNASSIGNED ) { /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( pChanEntry->usSoutTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now the broadcast TSST.*/ usCurrentEntry = pTdmConfig->usSoutBrdcastTsstFirstEntry; while( usCurrentEntry != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( pSharedInfo, pTsstEntry, usCurrentEntry ); /* Deactivate the TSST entry.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pTsstEntry->usTsstMemoryIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move to the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; } /*=======================================================================*/ /*------------------------------------------------------------------------------*/ /* Deactivate the ECHO control memory entry.*/ /* Set the input Echo control entry to unused.*/ WriteParams.ulWriteAddress = cOCT6100_ECHO_CONTROL_MEM_BASE + ( pChanEntry->usEchoMemIndex * cOCT6100_ECHO_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x85FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = 0xC5FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Deactivate the conversion control memories if used. */ if ( pChanEntry->usRinRoutConversionMemIndex != cOCT6100_INVALID_INDEX ) { /* Rin/Rout stream conversion memory was used */ ulResult = Oct6100ApiClearConversionMemory( f_pApiInstance, pChanEntry->usRinRoutConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pChanEntry->usSinSoutConversionMemIndex != cOCT6100_INVALID_INDEX ) { /* Sin/Sout stream conversion memory was used */ ulResult = Oct6100ApiClearConversionMemory( f_pApiInstance, pChanEntry->usSinSoutConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Clear the silence copy events if they were created. */ /* Unmute the Rin port if it was muted. */ if ( pChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_DF; pChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } /* Unmute the Sin port if it was muted. */ if ( pChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usSinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usSinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E0; pChanEntry->usSinSilenceEventIndex = cOCT6100_INVALID_INDEX; } /*------------------------------------------------------------------------------*/ /* Synch all the buffer playout field.*/ if ( pSharedInfo->ImageInfo.fBufferPlayout == TRUE ) { Oct6100BufferPlayoutStopDef( &BufferPlayoutStop ); BufferPlayoutStop.ulChannelHndl = cOCT6100_INVALID_HANDLE; BufferPlayoutStop.fStopCleanly = FALSE; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, pChanEntry->usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_SOUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, pChanEntry->usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Free all resources reserved for extended tone detection.*/ if ( pChanEntry->fEnableExtToneDetection == TRUE ) { /*------------------------------------------------------------------------------*/ /* Deactivate the ECHO control memory entry of the extended channel.*/ /* Set the input Echo control entry to unused.*/ WriteParams.ulWriteAddress = cOCT6100_ECHO_CONTROL_MEM_BASE + ( pChanEntry->usExtToneChanIndex * cOCT6100_ECHO_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x85FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = 0xC5FF; /* TSI index 1535 reserved for power-down mode */ mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Remove the mixer event used to copy the RIN signal to the SIN port of the extended channel.*/ /* Clear the Copy event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usExtToneMixerIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usExtToneMixerIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ } /*------------------------------------------------------------------------------*/ /* Reset PGSP */ WriteParams.ulWriteAddress = cOCT6100_CHANNEL_ROOT_BASE + ( pChanEntry->usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; WriteParams.usWriteData = 0x0800; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Clear the mute with feature bit. */ if ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) { ulResult = Oct6100ApiMuteSinWithFeatures( f_pApiInstance, f_usChanIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Clear the VQE memory. */ SmearParams.ulWriteAddress = cOCT6100_CHANNEL_ROOT_BASE + ( pChanEntry->usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst + 0x20; SmearParams.usWriteData = 0x0000; SmearParams.ulWriteLength = 2; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Clear the NLP memory. */ SmearParams.ulWriteAddress = cOCT6100_CHANNEL_ROOT_BASE + ( pChanEntry->usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst + 0x28; SmearParams.usWriteData = 0x0000; SmearParams.ulWriteLength = 2; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /* Clear the AF information memory. */ SmearParams.ulWriteAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( pChanEntry->usEchoMemIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst; SmearParams.usWriteData = 0x0000; SmearParams.ulWriteLength = 12; mOCT6100_DRIVER_WRITE_SMEAR_API( SmearParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*Reset ALC status*/ WriteParams.ulWriteAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( pChanEntry->usEchoMemIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst + 0x3A; WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseChannelResources Description: Release and clear the API entry associated to the echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChannelIndex Index of the echo cancellation channel in the API list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseChannelResources UINT32 Oct6100ApiReleaseChannelResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChannelIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_CHANNEL_TDM pTdmConfig; tPOCT6100_API_TSST_ENTRY pTsstEntry; UINT32 ulResult; UINT16 usCurrentEntry; UINT32 ulTimeslot; UINT32 ulStream; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChannelIndex ); /* Obtain local pointer to the TDM configurationof the channel */ pTdmConfig = &pChanEntry->TdmConfig; /* Release the two TSI chariot memory entries.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_2; ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_3; /* Now release the ECHO channel and control memory entries.*/ ulResult = Oct6100ApiReleaseEchoEntry( f_pApiInstance, f_usChannelIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_4; /* Release the conversion resources.*/ if ( pChanEntry->usRinRoutConversionMemIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, pChanEntry->usRinRoutConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_B9; pChanEntry->usRinRoutConversionMemIndex = cOCT6100_INVALID_INDEX; } if ( pChanEntry->usSinSoutConversionMemIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, pChanEntry->usSinSoutConversionMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_BA; pChanEntry->usSinSoutConversionMemIndex = cOCT6100_INVALID_INDEX; } /*=========================================================================*/ /* Release the TSST control memory entries if any were reserved.*/ if ( pTdmConfig->usRinTimeslot != cOCT6100_UNASSIGNED) { ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->usRinTimeslot, pTdmConfig->usRinStream, pTdmConfig->byRinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_5; } if ( pTdmConfig->usSinTimeslot != cOCT6100_UNASSIGNED) { ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->usSinTimeslot, pTdmConfig->usSinStream, pTdmConfig->bySinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_6; } /*=======================================================================*/ /* Release all the TSSTs associated to the ROUT port of this channel. */ if ( pTdmConfig->usRoutTimeslot != cOCT6100_UNASSIGNED) { ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->usRoutTimeslot, pTdmConfig->usRoutStream, pTdmConfig->byRoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_7; } /* Now release the Broadcast TSSTs. */ usCurrentEntry = pTdmConfig->usRoutBrdcastTsstFirstEntry; while( usCurrentEntry != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( pSharedInfo, pTsstEntry, usCurrentEntry ); ulTimeslot = pTsstEntry->usTsstValue >> 5; ulStream = pTsstEntry->usTsstValue & 0x1F; ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, ulTimeslot, ulStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, usCurrentEntry ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_8; /* Move to the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; /* Invalidate the current entry.*/ pTsstEntry->usTsstMemoryIndex = 0xFFFF; pTsstEntry->usTsstValue = 0xFFFF; pTsstEntry->usNextEntry = cOCT6100_INVALID_INDEX; } /*=======================================================================*/ /*=======================================================================*/ /* Release all the TSSTs associated to the SOUT port of this channel. */ if ( pTdmConfig->usSoutTimeslot != cOCT6100_UNASSIGNED) { ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pTdmConfig->usSoutTimeslot, pTdmConfig->usSoutStream, pTdmConfig->bySoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_9; } /* Now release the Broadcast TSSTs. */ usCurrentEntry = pTdmConfig->usSoutBrdcastTsstFirstEntry; while( usCurrentEntry != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( pSharedInfo, pTsstEntry, usCurrentEntry ); ulTimeslot = pTsstEntry->usTsstValue >> 5; ulStream = pTsstEntry->usTsstValue & 0x1F; ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, ulTimeslot, ulStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, usCurrentEntry ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A; /* Move to the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; /* Invalidate the current entry.*/ pTsstEntry->usTsstMemoryIndex = 0xFFFF; pTsstEntry->usTsstValue = 0xFFFF; pTsstEntry->usNextEntry = cOCT6100_INVALID_INDEX; } /*=======================================================================*/ /*=======================================================================*/ /* Update the dependency of the phasing TSST if one is associated to the chanel.*/ if ( pChanEntry->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { tPOCT6100_API_PHASING_TSST pPhasingEntry; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingEntry, pChanEntry->usPhasingTsstIndex ); pPhasingEntry->usDependencyCnt--; } /*=======================================================================*/ /*=======================================================================*/ /* Release any resources reserved for the extended tone detection.*/ if ( pChanEntry->fEnableExtToneDetection == TRUE ) { tPOCT6100_API_CHANNEL pExtToneChanEntry; mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pExtToneChanEntry, pChanEntry->usExtToneChanIndex ); /* Release the ECHO channel and control memory entries.*/ ulResult = Oct6100ApiReleaseEchoEntry( f_pApiInstance, pChanEntry->usExtToneChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_C1; ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pChanEntry->usExtToneTsiIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_C2; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usExtToneMixerIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_C3; /* Now release the channel entry */ pExtToneChanEntry->ulExtToneChanMode = cOCT6100_API_EXT_TONE_DISABLED; pExtToneChanEntry->fReserved = FALSE; /* Set the current entry to disable, just in case.*/ pChanEntry->ulExtToneChanMode = cOCT6100_API_EXT_TONE_DISABLED; } /*=======================================================================*/ /*=======================================================================*/ /* Update the channel's list entry. */ /* Clear the NLP dword array. */ Oct6100UserMemSet( pChanEntry->aulNlpConfDword, 0, sizeof( pChanEntry->aulNlpConfDword ) ); /* Clear the echo operation mode. */ pChanEntry->byEchoOperationMode = cOCT6100_ECHO_OP_MODE_POWER_DOWN; /* Mark the channel as closed. */ pChanEntry->fReserved = FALSE; pChanEntry->byEntryOpenCnt++; /* Reset the port, the bridge and BidirInfo */ pChanEntry->usMutedPorts = cOCT6100_CHANNEL_MUTE_PORT_NONE; pChanEntry->fBiDirChannel = FALSE; pChanEntry->usBridgeIndex = cOCT6100_INVALID_INDEX; /* Decrement the number of channel open.*/ f_pApiInstance->pSharedInfo->ChipStats.usNumberChannels--; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelModifySer Description: Modify an echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to channel configuration structure. The handle identifying the buffer in all future function calls is returned in this structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelModifySer UINT32 Oct6100ChannelModifySer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify ) { UINT16 usChanIndex; UINT32 ulResult; UINT16 usNewRinTsstIndex; UINT16 usNewSinTsstIndex; UINT16 usNewRoutTsstIndex; UINT16 usNewSoutTsstIndex; UINT8 fSinSoutCodecActive = FALSE; UINT8 fRinRoutCodecActive = FALSE; UINT16 usNewPhasingTsstIndex; tOCT6100_CHANNEL_OPEN *pTempChanOpen; /* We don't want this 290 byte structure on the stack */ pTempChanOpen = kmalloc(sizeof(*pTempChanOpen), GFP_ATOMIC); if (!pTempChanOpen) return cOCT6100_ERR_FATAL_0; /* Check the user's configuration of the echo cancellation channel for errors. */ ulResult = Oct6100ApiCheckChannelModify( f_pApiInstance, f_pChannelModify, pTempChanOpen, &usNewPhasingTsstIndex, &usChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Reserve all resources needed by the echo cancellation channel. */ ulResult = Oct6100ApiModifyChannelResources( f_pApiInstance, f_pChannelModify, usChanIndex, &usNewRinTsstIndex, &usNewSinTsstIndex, &usNewRoutTsstIndex, &usNewSoutTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Write all necessary structures to activate the echo cancellation channel. */ ulResult = Oct6100ApiModifyChannelStructs( f_pApiInstance, f_pChannelModify, pTempChanOpen, usChanIndex, usNewPhasingTsstIndex, &fSinSoutCodecActive, &fRinRoutCodecActive, usNewRinTsstIndex, usNewSinTsstIndex, usNewRoutTsstIndex, usNewSoutTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) goto out; /* Update the new echo cancellation channels's entry in the ECHO channel list. */ ulResult = Oct6100ApiModifyChannelEntry( f_pApiInstance, f_pChannelModify, pTempChanOpen, usChanIndex, usNewPhasingTsstIndex, fSinSoutCodecActive, fRinRoutCodecActive, usNewRinTsstIndex, usNewSinTsstIndex, usNewRoutTsstIndex, usNewSoutTsstIndex ); out: kfree(pTempChanOpen); return ulResult; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChannelModify Description: Checks the user's echo cancellation channel modify structure for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to echo cancellation channel modify structure. f_pTempChanOpen Pointer to a channel open structure. f_pusNewPhasingTsstIndex Pointer to a new phasing TSST index within the API instance. f_pusChanIndex Pointer to the channel index within the API instance channel list \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChannelModify UINT32 Oct6100ApiCheckChannelModify( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN tPOCT6100_CHANNEL_OPEN f_pTempChanOpen, OUT PUINT16 f_pusNewPhasingTsstIndex, OUT PUINT16 f_pusChanIndex ) { tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; UINT32 ulEntryOpenCnt; UINT32 ulDecoderNumTssts; /* Check the provided handle. */ if ( (f_pChannelModify->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelModify->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelModify->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /*=======================================================================*/ /* Check the general modify parameters. */ if ( f_pChannelModify->ulEchoOperationMode != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NORMAL && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_HT_FREEZE && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_HT_RESET && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_POWER_DOWN && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_EXTERNAL && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION && f_pChannelModify->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NO_ECHO ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE; /* Check the 2100Hz echo disabling configuration.*/ if ( f_pChannelModify->fEnableToneDisabler != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->fEnableToneDisabler != TRUE && f_pChannelModify->fEnableToneDisabler != FALSE ) return cOCT6100_ERR_CHANNEL_TONE_DISABLER_ENABLE; /* Check the disable tone detection flag. */ if ( f_pChannelModify->fDisableToneDetection != TRUE && f_pChannelModify->fDisableToneDetection != FALSE ) return cOCT6100_ERR_CHANNEL_DISABLE_TONE_DETECTION; /* Check the stop buffer playout flag. */ if ( f_pChannelModify->fStopBufferPlayout != TRUE && f_pChannelModify->fStopBufferPlayout != FALSE ) return cOCT6100_ERR_CHANNEL_STOP_BUFFER_PLAYOUT; /* Check the remove conference bridge participant flag. */ if ( f_pChannelModify->fRemoveConfBridgeParticipant != TRUE && f_pChannelModify->fRemoveConfBridgeParticipant != FALSE ) return cOCT6100_ERR_CHANNEL_REMOVE_CONF_BRIDGE_PARTICIPANT; /* Check the remove broadcast timeslots flag. */ if ( f_pChannelModify->fRemoveBroadcastTssts != TRUE && f_pChannelModify->fRemoveBroadcastTssts != FALSE ) return cOCT6100_ERR_CHANNEL_REMOVE_BROADCAST_TSSTS; if ( f_pChannelModify->fCodecConfigModified != TRUE && f_pChannelModify->fCodecConfigModified != FALSE ) return cOCT6100_ERR_CHANNEL_MODIFY_CODEC_CONFIG; if ( f_pChannelModify->fVqeConfigModified != TRUE && f_pChannelModify->fVqeConfigModified != FALSE ) return cOCT6100_ERR_CHANNEL_MODIFY_VQE_CONFIG; if ( f_pChannelModify->fTdmConfigModified != TRUE && f_pChannelModify->fTdmConfigModified != FALSE ) return cOCT6100_ERR_CHANNEL_MODIFY_TDM_CONFIG; /*=======================================================================*/ /*=======================================================================*/ /* Verify if any law change was requested. If so reprogram all structures.*/ if (( f_pChannelModify->fTdmConfigModified == TRUE ) && ( f_pChannelModify->TdmConfig.ulRinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulSinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulRoutPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulSoutPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING )) { f_pChannelModify->fVqeConfigModified = TRUE; f_pChannelModify->fCodecConfigModified = TRUE; } /*=======================================================================*/ ulResult = Oct6100ApiUpdateOpenStruct( f_pApiInstance, f_pChannelModify, f_pTempChanOpen, pChanEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* All further check will now be performed using the TempOpenChan structure in order to reuse the checks written for the open channel structure.*/ /* Check the TDM config.*/ if ( f_pChannelModify->fTdmConfigModified == TRUE ) { tPOCT6100_CHANNEL_MODIFY_TDM pModifyTdm; tPOCT6100_CHANNEL_OPEN_TDM pOpenTdm; pModifyTdm = &f_pChannelModify->TdmConfig; pOpenTdm = &f_pTempChanOpen->TdmConfig; ulResult = Oct6100ApiCheckTdmConfig( f_pApiInstance, pOpenTdm ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if that Stream and Timeslot values are valid.*/ /* Check the RIN port.*/ if ( f_pChannelModify->TdmConfig.ulRinStream == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_RIN_TIMESLOT; if ( f_pChannelModify->TdmConfig.ulRinStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_RIN_STREAM; if ( pChanEntry->fBeingTapped == TRUE ) { /* Check that the Rin stream + timeslot are not being assigned. */ if ( f_pChannelModify->TdmConfig.ulRinStream != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_pChannelModify->TdmConfig.ulRinStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_RIN_STREAM; if ( f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_RIN_TIMESLOT; } } /* Check the SIN port.*/ if ( f_pChannelModify->TdmConfig.ulSinStream == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_SIN_TIMESLOT; if ( f_pChannelModify->TdmConfig.ulSinStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_SIN_STREAM; /* Check the ROUT port.*/ if ( f_pChannelModify->TdmConfig.ulRoutStream == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_ROUT_TIMESLOT; if ( f_pChannelModify->TdmConfig.ulRoutStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_ROUT_STREAM; /* Check the SOUT port.*/ if ( f_pChannelModify->TdmConfig.ulSoutStream == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT; if ( f_pChannelModify->TdmConfig.ulSoutStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) return cOCT6100_ERR_CHANNEL_SOUT_STREAM; /* Verify if the channel is currently part of a bidirectional channel, and if */ /* so perform the required checks. */ if ( pChanEntry->fBiDirChannel == TRUE ) { /* Check the ports that must remain unassigned.*/ if ( f_pTempChanOpen->TdmConfig.ulRinTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_RIN_TIMESLOT; if ( f_pTempChanOpen->TdmConfig.ulSoutTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT; /* Check that no PCM law change is requested.*/ if ( f_pTempChanOpen->TdmConfig.ulRinPcmLaw != f_pTempChanOpen->TdmConfig.ulRoutPcmLaw ) return cOCT6100_ERR_CHANNEL_RIN_ROUT_LAW_CONVERSION; if ( f_pTempChanOpen->TdmConfig.ulSinPcmLaw != f_pTempChanOpen->TdmConfig.ulSoutPcmLaw ) return cOCT6100_ERR_CHANNEL_SIN_SOUT_LAW_CONVERSION; } /* If this channel is on a conference bridge, a few more things must be checked. */ if ( pChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) { /* If conferencing, law conversion cannot be applied. */ /* This check is done only if both input and output ports are assigned. */ if ( ( f_pTempChanOpen->TdmConfig.ulRinTimeslot != cOCT6100_UNASSIGNED ) && ( f_pTempChanOpen->TdmConfig.ulRoutTimeslot != cOCT6100_UNASSIGNED ) ) { /* Laws must be the same! */ if ( f_pTempChanOpen->TdmConfig.ulRinPcmLaw != f_pTempChanOpen->TdmConfig.ulRoutPcmLaw ) return cOCT6100_ERR_CHANNEL_RIN_ROUT_LAW_CONVERSION; } /* Check for Sin. */ if ( ( f_pTempChanOpen->TdmConfig.ulSinTimeslot != cOCT6100_UNASSIGNED ) && ( f_pTempChanOpen->TdmConfig.ulSoutTimeslot != cOCT6100_UNASSIGNED ) ) { /* Laws must be the same! */ if ( f_pTempChanOpen->TdmConfig.ulSinPcmLaw != f_pTempChanOpen->TdmConfig.ulSoutPcmLaw ) return cOCT6100_ERR_CHANNEL_SIN_SOUT_LAW_CONVERSION; } /* Check if ADPCM is requested. */ if ( f_pTempChanOpen->CodecConfig.ulEncoderPort != cOCT6100_NO_ENCODING && f_pTempChanOpen->CodecConfig.ulEncodingRate != cOCT6100_G711_64KBPS ) { /* No ADPCM in a conference bridge! */ return cOCT6100_ERR_CHANNEL_ENCODING_RATE; } if ( f_pTempChanOpen->CodecConfig.ulDecoderPort != cOCT6100_NO_DECODING && f_pTempChanOpen->CodecConfig.ulDecodingRate != cOCT6100_G711_64KBPS ) { /* No ADPCM in a conference bridge! */ return cOCT6100_ERR_CHANNEL_DECODING_RATE; } } if ( f_pTempChanOpen->CodecConfig.ulEncoderPort == cOCT6100_NO_ENCODING || f_pTempChanOpen->CodecConfig.ulDecoderPort == cOCT6100_NO_DECODING ) { /* Make sure no law conversion is attempted since it is not supported by the device.*/ if ( f_pTempChanOpen->TdmConfig.ulRinPcmLaw != f_pTempChanOpen->TdmConfig.ulRoutPcmLaw ) return cOCT6100_ERR_CHANNEL_RIN_ROUT_LAW_CONVERSION; if ( f_pTempChanOpen->TdmConfig.ulSinPcmLaw != f_pTempChanOpen->TdmConfig.ulSoutPcmLaw ) return cOCT6100_ERR_CHANNEL_SIN_SOUT_LAW_CONVERSION; } if ( pChanEntry->fEnableExtToneDetection == TRUE && f_pTempChanOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) return cOCT6100_ERR_CHANNEL_EXT_TONE_DETECTION_DECODER_PORT; /* A few special checks must be done if the configuration is to be applied */ /* to all opened channels. */ if ( f_pChannelModify->fApplyToAllChannels == TRUE ) { /* When the configuration to be applied is for all channels, */ /* check that the stream and timeslot parameters are not being assigned. */ /* Check the Rout port. */ if ( f_pChannelModify->TdmConfig.ulRoutStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Check that the Rout ports is being unassigned. */ if ( f_pTempChanOpen->TdmConfig.ulRoutStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_ROUT_STREAM_UNASSIGN; if ( f_pTempChanOpen->TdmConfig.ulRoutTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_ROUT_TIMESLOT_UNASSIGN; } /* Check the Rin port. */ if ( f_pChannelModify->TdmConfig.ulRinStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Check that the Rin ports is being unassigned. */ if ( f_pTempChanOpen->TdmConfig.ulRinStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_RIN_STREAM_UNASSIGN; if ( f_pTempChanOpen->TdmConfig.ulRinTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_RIN_TIMESLOT_UNASSIGN; } /* Check the Sout port. */ if ( f_pChannelModify->TdmConfig.ulSoutStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Check that the Sout ports is being unassigned. */ if ( f_pTempChanOpen->TdmConfig.ulSoutStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_SOUT_STREAM_UNASSIGN; if ( f_pTempChanOpen->TdmConfig.ulSoutTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT_UNASSIGN; } /* Check the Sin port. */ if ( f_pChannelModify->TdmConfig.ulSinStream != cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Check that the Sin ports is being unassigned. */ if ( f_pTempChanOpen->TdmConfig.ulSinStream != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_SIN_STREAM_UNASSIGN; if ( f_pTempChanOpen->TdmConfig.ulSinTimeslot != cOCT6100_UNASSIGNED ) return cOCT6100_ERR_CHANNEL_SIN_TIMESLOT_UNASSIGN; } } } /* Check the VQE config.*/ if ( f_pChannelModify->fVqeConfigModified == TRUE ) { ulResult = Oct6100ApiCheckVqeConfig( f_pApiInstance, &f_pTempChanOpen->VqeConfig, f_pTempChanOpen->fEnableToneDisabler ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Verify if the echo operation mode selected can be applied. */ if ( ( f_pTempChanOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) && ( f_pTempChanOpen->VqeConfig.fEnableNlp == FALSE ) ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_NLP_REQUIRED; if ( ( f_pTempChanOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) && ( f_pTempChanOpen->VqeConfig.fEnableNlp == FALSE ) ) return cOCT6100_ERR_CHANNEL_ECHO_OP_MODE_NLP_REQUIRED; /* Comfort noise must be activated for speech recognition mode to work. */ if ( ( f_pTempChanOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) && ( f_pTempChanOpen->VqeConfig.ulComfortNoiseMode == cOCT6100_COMFORT_NOISE_OFF ) ) return cOCT6100_ERR_CHANNEL_COMFORT_NOISE_REQUIRED; /* Check the Codec config.*/ if ( f_pChannelModify->fCodecConfigModified == TRUE ) { if ( f_pTempChanOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) ulDecoderNumTssts = f_pTempChanOpen->TdmConfig.ulRinNumTssts; else /* f_pTempChanOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ ulDecoderNumTssts = f_pTempChanOpen->TdmConfig.ulSinNumTssts; ulResult = Oct6100ApiCheckCodecConfig( f_pApiInstance, &f_pTempChanOpen->CodecConfig, ulDecoderNumTssts, f_pusNewPhasingTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* make sure that if silence suppression is activated, the NLP is enabled.*/ if ( f_pTempChanOpen->CodecConfig.fEnableSilenceSuppression == TRUE && f_pTempChanOpen->VqeConfig.fEnableNlp == FALSE ) return cOCT6100_ERR_CHANNEL_SIL_SUP_NLP_MUST_BE_ENABLED; /* Verify if the channel is currently part of a bidirectional channel, and if so perform the required checks.*/ if ( pChanEntry->fBiDirChannel == TRUE ) { /* Check the ports that must remain unassigned.*/ if ( f_pTempChanOpen->CodecConfig.ulEncoderPort != cOCT6100_NO_ENCODING && f_pTempChanOpen->CodecConfig.ulEncodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_CHANNEL_ENCODING_RATE; if ( f_pTempChanOpen->CodecConfig.ulDecoderPort != cOCT6100_NO_DECODING && f_pTempChanOpen->CodecConfig.ulDecodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_CHANNEL_DECODING_RATE; } } /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiModifyChannelResources Description: Reserves any new resources needed for the channel ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to echo cancellation channel configuration structure. f_usChanIndex Allocated entry in ECHO channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiModifyChannelResources UINT32 Oct6100ApiModifyChannelResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN UINT16 f_usChanIndex, OUT PUINT16 f_pusNewRinTsstIndex, OUT PUINT16 f_pusNewSinTsstIndex, OUT PUINT16 f_pusNewRoutTsstIndex, OUT PUINT16 f_pusNewSoutTsstIndex ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL_TDM pApiTdmConf; tPOCT6100_CHANNEL_MODIFY_TDM pModifyTdmConf; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar = cOCT6100_ERR_OK; UINT32 ulFreeMixerEventCnt; BOOL fRinReleased = FALSE; BOOL fSinReleased = FALSE; BOOL fRoutReleased = FALSE; BOOL fSoutReleased = FALSE; BOOL fRinReserved = FALSE; BOOL fSinReserved = FALSE; BOOL fRoutReserved = FALSE; BOOL fSoutReserved = FALSE; BOOL fReserveRin = FALSE; BOOL fReserveSin = FALSE; BOOL fReserveRout = FALSE; BOOL fReserveSout = FALSE; BOOL fRinRoutConversionMemReserved = FALSE; BOOL fSinSoutConversionMemReserved = FALSE; UINT32 ulRinNumTssts = 1; UINT32 ulSinNumTssts = 1; UINT32 ulRoutNumTssts = 1; UINT32 ulSoutNumTssts = 1; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain local pointer to the TDM configuration structure of the tPOCT6100_CHANNEL_MODIFY structure. */ pModifyTdmConf = &f_pChannelModify->TdmConfig; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) /* Obtain local pointer to the TDM configuration structure of the tPOCT6100_API_CHANNEL structure. */ pApiTdmConf = &pChanEntry->TdmConfig; /*===============================================================================*/ /* Modify TSST resources if required.*/ if ( f_pChannelModify->fTdmConfigModified == TRUE ) { /* First release any entry that need to be released.*/ if ( ( pModifyTdmConf->ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( pModifyTdmConf->ulRinNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) { if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { /* Release the previously reserved entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pChanEntry->TdmConfig.usRinTimeslot, pChanEntry->TdmConfig.usRinStream, pChanEntry->TdmConfig.byRinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { fRinReleased = TRUE; } } fReserveRin = TRUE; } /* Release SIN port.*/ if ( ( ulResult == cOCT6100_ERR_OK ) && ( ( pModifyTdmConf->ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( pModifyTdmConf->ulSinNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) ) { if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { /* Release the previously reserved entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pChanEntry->TdmConfig.usSinTimeslot, pChanEntry->TdmConfig.usSinStream, pChanEntry->TdmConfig.bySinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { fSinReleased = TRUE; } } fReserveSin = TRUE; } /* Release ROUT port.*/ if ( ( ulResult == cOCT6100_ERR_OK ) && ( ( pModifyTdmConf->ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( pModifyTdmConf->ulRoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) ) { if ( pChanEntry->usRoutTsstIndex != cOCT6100_INVALID_INDEX ) { /* Release the previously reserved entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pChanEntry->TdmConfig.usRoutTimeslot, pChanEntry->TdmConfig.usRoutStream, pChanEntry->TdmConfig.byRoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { fRoutReleased = TRUE; } } fReserveRout = TRUE; } /* Release the SOUT port.*/ if ( ( ulResult == cOCT6100_ERR_OK ) && ( ( pModifyTdmConf->ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( pModifyTdmConf->ulSoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) ) { if ( pChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) { /* Release the previously reserved entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pChanEntry->TdmConfig.usSoutTimeslot, pChanEntry->TdmConfig.usSoutStream, pChanEntry->TdmConfig.bySoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { fSoutReleased = TRUE; } } fReserveSout = TRUE; } /* Now reserve any new entry required.*/ /* Modify RIN port.*/ if ( ( fReserveRin == TRUE ) && ( ulResult == cOCT6100_ERR_OK ) ) { if ( pModifyTdmConf->ulRinTimeslot != cOCT6100_UNASSIGNED ) { /* Check what number of TSSTs should be reserved this time. */ if ( pModifyTdmConf->ulRinNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) { ulRinNumTssts = pApiTdmConf->byRinNumTssts; } else /* if ( pModifyTdmConf->ulRinNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* New number of TSSTs. */ ulRinNumTssts = pModifyTdmConf->ulRinNumTssts; } if ( pModifyTdmConf->ulRinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Reserve the new number of TSSTs. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pApiTdmConf->usRinTimeslot, pApiTdmConf->usRinStream, ulRinNumTssts, cOCT6100_INPUT_TSST, f_pusNewRinTsstIndex, NULL ); } else /* if ( pModifyTdmConf->ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* Reserve the new TSST.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pModifyTdmConf->ulRinTimeslot, pModifyTdmConf->ulRinStream, ulRinNumTssts, cOCT6100_INPUT_TSST, f_pusNewRinTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fRinReserved = TRUE; } } } else { *f_pusNewRinTsstIndex = cOCT6100_INVALID_INDEX; } } else { *f_pusNewRinTsstIndex = cOCT6100_INVALID_INDEX; } /* Modify SIN port.*/ if ( ( fReserveSin == TRUE ) && ( ulResult == cOCT6100_ERR_OK ) ) { if ( pModifyTdmConf->ulSinTimeslot != cOCT6100_UNASSIGNED ) { /* Check what number of TSSTs should be reserved this time. */ if ( pModifyTdmConf->ulSinNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) { ulSinNumTssts = pApiTdmConf->bySinNumTssts; } else /* if ( pModifyTdmConf->ulSinNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* New number of TSSTs. */ ulSinNumTssts = pModifyTdmConf->ulSinNumTssts; } if ( pModifyTdmConf->ulSinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Reserve the new number of TSSTs. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pApiTdmConf->usSinTimeslot, pApiTdmConf->usSinStream, ulSinNumTssts, cOCT6100_INPUT_TSST, f_pusNewSinTsstIndex, NULL ); } else /* if ( pModifyTdmConf->ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* Reserve the new TSST.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pModifyTdmConf->ulSinTimeslot, pModifyTdmConf->ulSinStream, ulSinNumTssts, cOCT6100_INPUT_TSST, f_pusNewSinTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fSinReserved = TRUE; } } } else { *f_pusNewSinTsstIndex = cOCT6100_INVALID_INDEX; } } else { *f_pusNewSinTsstIndex = cOCT6100_INVALID_INDEX; } /* Modify ROUT port.*/ if ( ( fReserveRout == TRUE ) && ( ulResult == cOCT6100_ERR_OK ) ) { if ( pModifyTdmConf->ulRoutTimeslot != cOCT6100_UNASSIGNED ) { /* Check what number of TSSTs should be reserved this time. */ if ( pModifyTdmConf->ulRoutNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) { ulRoutNumTssts = pApiTdmConf->byRoutNumTssts; } else /* if ( pModifyTdmConf->ulRoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* New number of TSSTs. */ ulRoutNumTssts = pModifyTdmConf->ulRoutNumTssts; } if ( pModifyTdmConf->ulRoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Reserve the new number of TSSTs. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pApiTdmConf->usRoutTimeslot, pApiTdmConf->usRoutStream, ulRoutNumTssts, cOCT6100_OUTPUT_TSST, f_pusNewRoutTsstIndex, NULL ); } else /* if ( pModifyTdmConf->ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* Reserve the new TSST.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pModifyTdmConf->ulRoutTimeslot, pModifyTdmConf->ulRoutStream, ulRoutNumTssts, cOCT6100_OUTPUT_TSST, f_pusNewRoutTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fRoutReserved = TRUE; } } } else { *f_pusNewRoutTsstIndex = cOCT6100_INVALID_INDEX; } } else { *f_pusNewRoutTsstIndex = cOCT6100_INVALID_INDEX; } /* Modify SOUT port.*/ if ( ( fReserveSout == TRUE ) && ( ulResult == cOCT6100_ERR_OK ) ) { if ( pModifyTdmConf->ulSoutTimeslot != cOCT6100_UNASSIGNED ) { /* Check what number of TSSTs should be reserved this time. */ if ( pModifyTdmConf->ulSoutNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) { ulSoutNumTssts = pApiTdmConf->bySoutNumTssts; } else /* if ( pModifyTdmConf->ulSoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* New number of TSSTs. */ ulSoutNumTssts = pModifyTdmConf->ulSoutNumTssts; } if ( pModifyTdmConf->ulSoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) { /* Reserve the new number of TSSTs. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pApiTdmConf->usSoutTimeslot, pApiTdmConf->usSoutStream, ulSoutNumTssts, cOCT6100_OUTPUT_TSST, f_pusNewSoutTsstIndex, NULL ); } else /* if ( pModifyTdmConf->ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) */ { /* Reserve the new TSST.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, pModifyTdmConf->ulSoutTimeslot, pModifyTdmConf->ulSoutStream, ulSoutNumTssts, cOCT6100_OUTPUT_TSST, f_pusNewSoutTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fSoutReserved = TRUE; } } } else { *f_pusNewSoutTsstIndex = cOCT6100_INVALID_INDEX; } } else { *f_pusNewSoutTsstIndex = cOCT6100_INVALID_INDEX; } } if ( f_pChannelModify->fCodecConfigModified == TRUE ) { if ( ulResult == cOCT6100_ERR_OK && pChanEntry->usRinRoutConversionMemIndex == cOCT6100_INVALID_INDEX && ( f_pChannelModify->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT || f_pChannelModify->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) ) { /* Reserve an ADPCM memory block.*/ ulResult = Oct6100ApiReserveConversionMemEntry( f_pApiInstance, &pChanEntry->usRinRoutConversionMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fRinRoutConversionMemReserved = TRUE; } } if ( ulResult == cOCT6100_ERR_OK && pChanEntry->usSinSoutConversionMemIndex == cOCT6100_INVALID_INDEX && ( f_pChannelModify->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT || f_pChannelModify->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN ) ) { /* Reserve an ADPCM memory block.*/ ulResult = Oct6100ApiReserveConversionMemEntry( f_pApiInstance, &pChanEntry->usSinSoutConversionMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fSinSoutConversionMemReserved = TRUE; } } } /*===============================================================================*/ /* Check if there are a couple of mixer events available for us. */ if ( ulResult == cOCT6100_ERR_OK ) { UINT32 ulMixerEventCntNeeded = 0; /* Calculate how many mixer events are needed. */ if ( pChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) { /* If the channel is in bidir mode, do not create the Rin silence event!!! */ if ( pChanEntry->fBiDirChannel == FALSE ) { if ( ( *f_pusNewRinTsstIndex == cOCT6100_INVALID_INDEX ) && ( pChanEntry->usRinSilenceEventIndex == cOCT6100_INVALID_INDEX ) ) ulMixerEventCntNeeded++; } } if ( ( *f_pusNewSinTsstIndex == cOCT6100_INVALID_INDEX ) && ( pChanEntry->usSinSilenceEventIndex == cOCT6100_INVALID_INDEX ) ) { ulMixerEventCntNeeded++; } /* If at least 1 mixer event is needed, check if those are available. */ if ( ulMixerEventCntNeeded != 0 ) { ulResult = Oct6100ApiGetFreeMixerEventCnt( f_pApiInstance, &ulFreeMixerEventCnt ); if ( ulResult == cOCT6100_ERR_OK ) { /* The API might need more mixer events if the ports have to be muted. */ /* Check if these are available. */ if ( ulFreeMixerEventCnt < ulMixerEventCntNeeded ) { ulResult = cOCT6100_ERR_CHANNEL_OUT_OF_MIXER_EVENTS; } } } } /*===============================================================================*/ /* Verify if an error occured. */ if ( ulResult != cOCT6100_ERR_OK ) { /* Release any resources newly reserved.*/ if ( fRinReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pModifyTdmConf->ulRinTimeslot, pModifyTdmConf->ulRinStream, ulRinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the SIN port.*/ if ( fSinReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pModifyTdmConf->ulSinTimeslot, pModifyTdmConf->ulSinStream, ulSinNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the ROUT port.*/ if ( fRoutReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pModifyTdmConf->ulRoutTimeslot, pModifyTdmConf->ulRoutStream, ulRoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the SOUT port.*/ if ( fSoutReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, pModifyTdmConf->ulSoutTimeslot, pModifyTdmConf->ulSoutStream, ulSoutNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* Now make sure any resources released gets reserved back again.*/ /* For the RIN port.*/ if ( fRinReleased == TRUE ) { /* Reserve the new TSST.*/ ulTempVar = Oct6100ApiReserveTsst( f_pApiInstance, pChanEntry->TdmConfig.usRinTimeslot, pChanEntry->TdmConfig.usRinStream, pChanEntry->TdmConfig.byRinNumTssts, cOCT6100_INPUT_TSST, &pChanEntry->usRinTsstIndex, NULL ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the SIN port.*/ if ( fSinReleased == TRUE ) { /* Reserve the new TSST.*/ ulTempVar = Oct6100ApiReserveTsst( f_pApiInstance, pChanEntry->TdmConfig.usSinTimeslot, pChanEntry->TdmConfig.usSinStream, pChanEntry->TdmConfig.bySinNumTssts, cOCT6100_INPUT_TSST, &pChanEntry->usSinTsstIndex, NULL ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the ROUT port.*/ if ( fRoutReleased == TRUE ) { /* Reserve the new TSST.*/ ulTempVar = Oct6100ApiReserveTsst( f_pApiInstance, pChanEntry->TdmConfig.usRoutTimeslot, pChanEntry->TdmConfig.usRoutStream, pChanEntry->TdmConfig.byRoutNumTssts, cOCT6100_OUTPUT_TSST, &pChanEntry->usRoutTsstIndex, NULL ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* For the SOUT port.*/ if ( fSoutReleased == TRUE ) { /* Reserve the new TSST.*/ ulTempVar = Oct6100ApiReserveTsst( f_pApiInstance, pChanEntry->TdmConfig.usSoutTimeslot, pChanEntry->TdmConfig.usSoutStream, pChanEntry->TdmConfig.bySoutNumTssts, cOCT6100_OUTPUT_TSST, &pChanEntry->usSoutTsstIndex, NULL ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* Release the conversion memories if they were reserved.*/ if ( fRinRoutConversionMemReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, pChanEntry->usRinRoutConversionMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fSinSoutConversionMemReserved == TRUE ) { ulTempVar = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, pChanEntry->usSinSoutConversionMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /* Now return the error.*/ return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiModifyChannelStructs Description: Performs all the required structure writes to configure the echo cancellation channel based on the new modifications. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to echo cancellation channel configuration structure. f_pChannelOpen Pointer to a structure used to store the multiple resources indexes. f_usChanIndex Index of the channel within the API's channel list. f_usNewPhasingTsstIndex Index of the new phasing TSST. f_pfSinSoutCodecActive Pointer to the state of the SIN/SOUT codec. f_pfRinRoutCodecActive Pointer to the state of the RIN/ROUT codec. f_usNewRinTsstIndex New RIN TSST memory index. f_usNewSinTsstIndex New SIN TSST memory index. f_usNewRoutTsstIndex New ROUT TSST memory index. f_usNewSoutTsstIndex New SOUT TSST memory index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiModifyChannelStructs UINT32 Oct6100ApiModifyChannelStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usNewPhasingTsstIndex, OUT PUINT8 f_pfSinSoutCodecActive, OUT PUINT8 f_pfRinRoutCodecActive, IN UINT16 f_usNewRinTsstIndex, IN UINT16 f_usNewSinTsstIndex, IN UINT16 f_usNewRoutTsstIndex, IN UINT16 f_usNewSoutTsstIndex ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_READ_PARAMS ReadParams; tOCT6100_WRITE_PARAMS WriteParams; tPOCT6100_API_CHANNEL_CODEC pApiCodecConf; tPOCT6100_API_CHANNEL_TDM pApiTdmConf; tPOCT6100_API_CHANNEL_VQE pApiVqeConf; UINT32 ulResult; UINT16 usReadData; UINT16 usSinTsstIndex; UINT16 usRinTsstIndex; UINT32 ulToneConfIndex; BOOL fClearPlayoutPointers = FALSE; BOOL fConversionEnabled = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) /* Obtain local pointer to the configuration structures of the tPOCT6100_API_CHANNEL structure. */ pApiCodecConf = &pChanEntry->CodecConfig; pApiTdmConf = &pChanEntry->TdmConfig; pApiVqeConf = &pChanEntry->VqeConfig; /*=======================================================================*/ /* Init the RIN and SIN TSST index */ usRinTsstIndex = pChanEntry->usRinTsstIndex; usSinTsstIndex = pChanEntry->usSinTsstIndex; /*==============================================================================*/ /* Clear the TSST that will be release.*/ if ( f_pChannelModify->fTdmConfigModified == TRUE ) { /* Modify RIN port.*/ if ( f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { /* Clear the previous entry */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pChanEntry->usRinTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Modify SIN port.*/ if ( f_pChannelModify->TdmConfig.ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { /* Clear the previous entry */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pChanEntry->usSinTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Modify ROUT port.*/ if ( f_pChannelModify->TdmConfig.ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( pChanEntry->usRoutTsstIndex != cOCT6100_INVALID_INDEX ) { /* Clear the previous entry */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pChanEntry->usRoutTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Modify SOUT port.*/ if ( f_pChannelModify->TdmConfig.ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING) { if ( pChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) { /* Clear the previous entry */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (pChanEntry->usSoutTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /*==============================================================================*/ /*==============================================================================*/ /* Now, Configure the Tsst control memory.*/ if ( f_pChannelModify->fTdmConfigModified == TRUE ) { /* Modify RIN port.*/ if ( f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { usRinTsstIndex = f_usNewRinTsstIndex; if ( f_usNewRinTsstIndex != cOCT6100_INVALID_INDEX ) { if ( pChanEntry->usExtraRinTsiMemIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usNewRinTsstIndex, pChanEntry->usExtraRinTsiMemIndex, f_pChannelOpen->TdmConfig.ulRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usNewRinTsstIndex, pChanEntry->usRinRoutTsiMemIndex, f_pChannelOpen->TdmConfig.ulRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } if ( f_pChannelModify->TdmConfig.ulRinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulRinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( pChanEntry->usExtraRinTsiMemIndex != cOCT6100_INVALID_INDEX ) { if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usRinTsstIndex, pChanEntry->usExtraRinTsiMemIndex, f_pChannelOpen->TdmConfig.ulRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { if ( pChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usRinTsstIndex, pChanEntry->usRinRoutTsiMemIndex, f_pChannelOpen->TdmConfig.ulRinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Modify SIN port.*/ if ( f_pChannelModify->TdmConfig.ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { usSinTsstIndex = f_usNewSinTsstIndex; if ( f_usNewSinTsstIndex != cOCT6100_INVALID_INDEX ) { if ( pChanEntry->usExtraSinTsiMemIndex != cOCT6100_INVALID_INDEX ) { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usNewSinTsstIndex, pChanEntry->usExtraSinTsiMemIndex, f_pChannelOpen->TdmConfig.ulSinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usNewSinTsstIndex, pChanEntry->usSinSoutTsiMemIndex, f_pChannelOpen->TdmConfig.ulSinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } if ( f_pChannelModify->TdmConfig.ulSinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING && f_pChannelModify->TdmConfig.ulSinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( pChanEntry->usExtraSinTsiMemIndex != cOCT6100_INVALID_INDEX ) { if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usSinTsstIndex , pChanEntry->usExtraSinTsiMemIndex, f_pChannelOpen->TdmConfig.ulSinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pChanEntry->usSinTsstIndex , pChanEntry->usSinSoutTsiMemIndex, f_pChannelOpen->TdmConfig.ulSinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Modify ROUT port.*/ if ( ( f_pChannelModify->TdmConfig.ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( f_pChannelModify->TdmConfig.ulRoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) { if ( f_usNewRoutTsstIndex != cOCT6100_INVALID_INDEX ) { if ( f_pChannelModify->TdmConfig.ulRoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* If this output port is not muted. */ if ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) == 0x0 ) { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usNewRoutTsstIndex, pApiCodecConf->byAdpcmNibblePosition, f_pChannelModify->TdmConfig.ulRoutNumTssts, pChanEntry->usRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { /* If this output port is not muted. */ if ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) == 0x0 ) { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usNewRoutTsstIndex, pApiCodecConf->byAdpcmNibblePosition, pApiTdmConf->byRoutNumTssts, pChanEntry->usRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } /* Modify SOUT port.*/ if ( ( f_pChannelModify->TdmConfig.ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) || ( f_pChannelModify->TdmConfig.ulSoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) ) { if ( f_usNewSoutTsstIndex != cOCT6100_INVALID_INDEX ) { if ( f_pChannelModify->TdmConfig.ulSoutNumTssts != cOCT6100_KEEP_PREVIOUS_SETTING ) { /* If this output port is not muted. */ if ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) == 0x0 ) { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usNewSoutTsstIndex, pApiCodecConf->byAdpcmNibblePosition, f_pChannelModify->TdmConfig.ulSoutNumTssts, pChanEntry->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { /* If this output port is not muted. */ if ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) == 0x0 ) { /* Write the new entry now.*/ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usNewSoutTsstIndex, pApiCodecConf->byAdpcmNibblePosition, pApiTdmConf->bySoutNumTssts, pChanEntry->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } } } /*==============================================================================*/ /*==============================================================================*/ /* Modify the Encoder/Decoder memory if required.*/ if ( f_pChannelModify->fCodecConfigModified == TRUE ) { UINT32 ulCompType = 0; UINT16 usTempTsiMemIndex; UINT16 usDecoderMemIndex; UINT16 usEncoderMemIndex; UINT32 ulPcmLaw; UINT16 usPhasingIndex; BOOL fModifyAdpcmMem = TRUE; /*==============================================================================*/ /* Reprogram the Decoder memory.*/ if ( pChanEntry->CodecConfig.byDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { usDecoderMemIndex = pChanEntry->usRinRoutConversionMemIndex; } else { usDecoderMemIndex = pChanEntry->usSinSoutConversionMemIndex; } if ( pChanEntry->CodecConfig.byEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { usEncoderMemIndex = pChanEntry->usRinRoutConversionMemIndex; } else { usEncoderMemIndex = pChanEntry->usSinSoutConversionMemIndex; } if ( usDecoderMemIndex != cOCT6100_INVALID_INDEX ) { switch( f_pChannelOpen->CodecConfig.ulDecodingRate ) { case cOCT6100_G711_64KBPS: ulCompType = 0x8; if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { if ( f_pChannelOpen->TdmConfig.ulRinPcmLaw == f_pChannelOpen->TdmConfig.ulRoutPcmLaw ) fModifyAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( f_pChannelOpen->TdmConfig.ulRinStream == cOCT6100_UNASSIGNED ) || ( f_pChannelOpen->TdmConfig.ulRoutStream == cOCT6100_UNASSIGNED ) ) fModifyAdpcmMem = FALSE; } else /* f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ { if ( f_pChannelOpen->TdmConfig.ulSinPcmLaw == f_pChannelOpen->TdmConfig.ulSoutPcmLaw ) fModifyAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( f_pChannelOpen->TdmConfig.ulSinStream == cOCT6100_UNASSIGNED ) || ( f_pChannelOpen->TdmConfig.ulSoutStream == cOCT6100_UNASSIGNED ) ) fModifyAdpcmMem = FALSE; } break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; fConversionEnabled = TRUE; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; fConversionEnabled = TRUE; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; fConversionEnabled = TRUE; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; fConversionEnabled = TRUE; break; case cOCT6100_G727_2C_ENCODED: ulCompType = 0x4; fConversionEnabled = TRUE; break; case cOCT6100_G727_3C_ENCODED: ulCompType = 0x5; fConversionEnabled = TRUE; break; case cOCT6100_G727_4C_ENCODED: ulCompType = 0x6; fConversionEnabled = TRUE; break; case cOCT6100_G726_ENCODED: ulCompType = 0x9; fConversionEnabled = TRUE; break; case cOCT6100_G711_G726_ENCODED: ulCompType = 0xA; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_2C_ENCODED: ulCompType = 0xC; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_3C_ENCODED: ulCompType = 0xD; fConversionEnabled = TRUE; break; case cOCT6100_G711_G727_4C_ENCODED: ulCompType = 0xE; fConversionEnabled = TRUE; break; default: return cOCT6100_ERR_FATAL_D6; } if ( fModifyAdpcmMem == TRUE ) { /* Set the chariot memory based on the selected port.*/ if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { usTempTsiMemIndex = pChanEntry->usRinRoutTsiMemIndex; ulPcmLaw = f_pChannelOpen->TdmConfig.ulRoutPcmLaw; /* Set the law for later use */ /* Flag the entry as active.*/ *f_pfRinRoutCodecActive = TRUE; } else /* f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ { usTempTsiMemIndex = pChanEntry->usSinSoutTsiMemIndex; ulPcmLaw = f_pChannelOpen->TdmConfig.ulSoutPcmLaw; /* Set the law for later use */ /* Flag the entry as active.*/ *f_pfSinSoutCodecActive = TRUE; } ulResult = Oct6100ApiWriteDecoderMemory( f_pApiInstance, usDecoderMemIndex, ulCompType, usTempTsiMemIndex, ulPcmLaw, pApiCodecConf->byAdpcmNibblePosition ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { ulResult = Oct6100ApiClearConversionMemory( f_pApiInstance, usDecoderMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Flag the entry as deactivated.*/ if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { *f_pfRinRoutCodecActive = FALSE; } else { *f_pfSinSoutCodecActive = FALSE; } } } /*==============================================================================*/ /*==============================================================================*/ /* Reprogram the Encoder memory.*/ if ( usEncoderMemIndex != cOCT6100_INVALID_INDEX ) { fModifyAdpcmMem = TRUE; /* Set the chariot memory based on the selected port.*/ if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { usTempTsiMemIndex = pChanEntry->usRinRoutTsiMemIndex; ulPcmLaw = f_pChannelOpen->TdmConfig.ulRoutPcmLaw; /* Set the law for later use */ } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { usTempTsiMemIndex = pChanEntry->usSinSoutTsiMemIndex; ulPcmLaw = f_pChannelOpen->TdmConfig.ulSoutPcmLaw; /* Set the law for later use */ } /* Set the phasing index .*/ if ( f_usNewPhasingTsstIndex != cOCT6100_INVALID_INDEX ) usPhasingIndex = f_usNewPhasingTsstIndex; else usPhasingIndex = pChanEntry->usPhasingTsstIndex; switch( f_pChannelOpen->CodecConfig.ulEncodingRate ) { case cOCT6100_G711_64KBPS: if ( ulPcmLaw == cOCT6100_PCM_U_LAW ) ulCompType = 0x4; else /* ulPcmLaw == cOCT6100_PCM_A_LAW */ ulCompType = 0x5; if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { if ( f_pChannelOpen->TdmConfig.ulRinPcmLaw == f_pChannelOpen->TdmConfig.ulRoutPcmLaw ) fModifyAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( f_pChannelOpen->TdmConfig.ulRinStream == cOCT6100_UNASSIGNED ) || ( f_pChannelOpen->TdmConfig.ulRoutStream == cOCT6100_UNASSIGNED ) ) fModifyAdpcmMem = FALSE; } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { if ( f_pChannelOpen->TdmConfig.ulSinPcmLaw == f_pChannelOpen->TdmConfig.ulSoutPcmLaw ) fModifyAdpcmMem = FALSE; /* Check if both ports are assigned. If not, no law conversion needed here.. */ if ( ( f_pChannelOpen->TdmConfig.ulSinStream == cOCT6100_UNASSIGNED ) || ( f_pChannelOpen->TdmConfig.ulSoutStream == cOCT6100_UNASSIGNED ) ) fModifyAdpcmMem = FALSE; } break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; fConversionEnabled = TRUE; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; fConversionEnabled = TRUE; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; fConversionEnabled = TRUE; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_4_1: ulCompType = 0xD; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_3_2: ulCompType = 0xA; fConversionEnabled = TRUE; break; case cOCT6100_G727_40KBPS_2_3: ulCompType = 0x6; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_4_0: ulCompType = 0xE; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_3_1: ulCompType = 0xB; fConversionEnabled = TRUE; break; case cOCT6100_G727_32KBPS_2_2: ulCompType = 0x7; fConversionEnabled = TRUE; break; case cOCT6100_G727_24KBPS_3_0: ulCompType = 0xC; fConversionEnabled = TRUE; break; case cOCT6100_G727_24KBPS_2_1: ulCompType = 0x8; fConversionEnabled = TRUE; break; case cOCT6100_G727_16KBPS_2_0: ulCompType = 0x9; fConversionEnabled = TRUE; break; default: return cOCT6100_ERR_FATAL_D7; } if ( fModifyAdpcmMem == TRUE ) { if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { *f_pfRinRoutCodecActive = TRUE; } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { *f_pfSinSoutCodecActive = TRUE; } ulResult = Oct6100ApiWriteEncoderMemory( f_pApiInstance, usEncoderMemIndex, ulCompType, usTempTsiMemIndex, f_pChannelOpen->CodecConfig.fEnableSilenceSuppression, pApiCodecConf->byAdpcmNibblePosition, usPhasingIndex, f_pChannelOpen->CodecConfig.ulPhasingType, f_pChannelOpen->CodecConfig.ulPhase ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { ulResult = Oct6100ApiClearConversionMemory( f_pApiInstance, usEncoderMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; if ( f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT ) { *f_pfRinRoutCodecActive = FALSE; } else /* f_pChannelOpen->CodecConfig.ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT */ { *f_pfSinSoutCodecActive = FALSE; } } } /*==============================================================================*/ } /*==============================================================================*/ /* Modify the VQE parameter if required.*/ if ( ( f_pChannelModify->fVqeConfigModified == TRUE ) || ( (UINT8)f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) || ( f_pChannelOpen->fEnableToneDisabler != pChanEntry->fEnableToneDisabler ) ) { ulResult = Oct6100ApiWriteVqeMemory( f_pApiInstance, &f_pChannelOpen->VqeConfig, f_pChannelOpen, f_usChanIndex, pChanEntry->usEchoMemIndex, FALSE, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /* Modify the Echo memory if required.*/ if ( f_pChannelModify->fEnableToneDisabler != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->ulEchoOperationMode != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulRinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulSinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulRoutPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING || f_pChannelModify->TdmConfig.ulSoutPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING ) { ulResult = Oct6100ApiWriteEchoMemory( f_pApiInstance, &f_pChannelOpen->TdmConfig, f_pChannelOpen, pChanEntry->usEchoMemIndex, pChanEntry->usRinRoutTsiMemIndex, pChanEntry->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Synch all the buffer playout field if needed by echo operation mode. */ /* Note that Oct6100ApiWriteVqeMemory does not clear the playout pointers */ /* since the flag is set to FALSE. */ if ( ( pSharedInfo->ImageInfo.fBufferPlayout == TRUE ) && ( ( f_pChannelModify->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_HT_FREEZE ) || ( f_pChannelModify->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN ) ) ) { /* Buffer playout must be stopped. */ fClearPlayoutPointers = TRUE; } } /*==============================================================================*/ /* Modify the Mixer events if law changes are requested. */ if ( pChanEntry->usSinCopyEventIndex != cOCT6100_INVALID_INDEX && f_pChannelModify->TdmConfig.ulSinPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING ) { ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Modify the value according to the new law.*/ if ( f_pChannelModify->TdmConfig.ulSinPcmLaw == cOCT6100_PCM_A_LAW ) WriteParams.usWriteData = (UINT16)( usReadData | ( f_pChannelModify->TdmConfig.ulSinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET )); else WriteParams.usWriteData = (UINT16)( usReadData & (~( f_pChannelModify->TdmConfig.ulSinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET ))); /* Write back the new value.*/ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pChanEntry->usSoutCopyEventIndex != cOCT6100_INVALID_INDEX && f_pChannelModify->TdmConfig.ulSoutPcmLaw != cOCT6100_KEEP_PREVIOUS_SETTING ) { ReadParams.ulReadAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usSoutCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Modify the value according to the new law.*/ if ( f_pChannelModify->TdmConfig.ulSoutPcmLaw == cOCT6100_PCM_A_LAW ) WriteParams.usWriteData = (UINT16)( usReadData | ( f_pChannelModify->TdmConfig.ulSoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET )); else WriteParams.usWriteData = (UINT16)( usReadData & (~( f_pChannelModify->TdmConfig.ulSoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET ))); /* Write back the new value.*/ WriteParams.ulWriteAddress = ReadParams.ulReadAddress; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /* Mute channel if required, this is done on a port basis */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, usRinTsstIndex, usSinTsstIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Completely disable tone detection? */ if ( f_pChannelModify->fDisableToneDetection == TRUE ) { /* Check if tone detection has been enabled on this channel. */ for (ulToneConfIndex = 0; ulToneConfIndex < ARRAY_SIZE(pChanEntry->aulToneConf); ulToneConfIndex++) { /* Check if some tone has been activated on this channel. */ if ( pChanEntry->aulToneConf[ ulToneConfIndex ] != 0 ) { tOCT6100_TONE_DETECTION_DISABLE ToneDetectDisable; /* Call the default function to make sure all parameters are assigned default values. */ ulResult = Oct6100ToneDetectionDisableDef( &ToneDetectDisable ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Form channel handle. */ ToneDetectDisable.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* Disable all tones activated on this channel. */ ToneDetectDisable.fDisableAll = TRUE; /* Call tone detection serialized function. */ ulResult = Oct6100ToneDetectionDisableSer( f_pApiInstance, &ToneDetectDisable ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get out of the loop, tone detection has been disabled! */ break; } } } /* Hard-stop buffer playout? */ if ( f_pChannelModify->fStopBufferPlayout == TRUE ) { /* Check if playout has been started on the Rout port. */ if ( ( pChanEntry->fRinBufPlaying == TRUE ) || ( pChanEntry->fRinBufAdded == TRUE ) ) { tOCT6100_BUFFER_PLAYOUT_STOP PlayoutStop; /* Call the default function to make sure all parameters are assigned default values. */ ulResult = Oct6100BufferPlayoutStopDef( &PlayoutStop ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Hard stop request. */ PlayoutStop.fStopCleanly = FALSE; /* Form channel handle. */ PlayoutStop.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* For the Rout port. */ PlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; /* Call buffer playout stop serialized function. */ ulResult = Oct6100BufferPlayoutStopSer( f_pApiInstance, &PlayoutStop ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { /* The chip might still be playing a last buffer. Make sure it hard-stops! */ fClearPlayoutPointers = TRUE; } /* Check if playout has been started on the Sout port. */ if ( ( pChanEntry->fSoutBufPlaying == TRUE ) || ( pChanEntry->fSoutBufAdded == TRUE ) ) { tOCT6100_BUFFER_PLAYOUT_STOP PlayoutStop; /* Call the default function to make sure all parameters are assigned default values. */ ulResult = Oct6100BufferPlayoutStopDef( &PlayoutStop ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Hard stop request. */ PlayoutStop.fStopCleanly = FALSE; /* Form channel handle. */ PlayoutStop.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* For the Rout port. */ PlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_SOUT; /* Call buffer playout stop serialized function. */ ulResult = Oct6100BufferPlayoutStopSer( f_pApiInstance, &PlayoutStop ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { /* The chip might still be playing a last buffer. Make sure it hard-stops! */ fClearPlayoutPointers = TRUE; } } /* Remove participant from bridge? */ if ( f_pChannelModify->fRemoveConfBridgeParticipant == TRUE ) { /* Check if this channel is on a bridge. */ if ( pChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) { /* Channel is on a bridge, remove it. */ tOCT6100_CONF_BRIDGE_CHAN_REMOVE BridgeChanRemove; /* Call the default function to make sure all parameters are assigned default values. */ ulResult = Oct6100ConfBridgeChanRemoveDef( &BridgeChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Form channel handle. */ BridgeChanRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* Do not remove all channels, only the one specified. */ BridgeChanRemove.fRemoveAll = FALSE; /* No need to assign conference bridge handle, the remove function will figure it out. */ /* Call conference bridge channel remove serialized function. */ ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &BridgeChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_CONF_BRIDGE_CHANNEL_TAP_DEPENDENCY ) { tPOCT6100_API_CHANNEL pTapChanEntry; /* Get a pointer to the tap channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTapChanEntry, pChanEntry->usTapChanIndex ) /* Form tap channel handle. */ BridgeChanRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pTapChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | pChanEntry->usTapChanIndex; ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &BridgeChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Re-form original channel handle. */ BridgeChanRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; ulResult = Oct6100ConfBridgeChanRemoveSer( f_pApiInstance, &BridgeChanRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else { return ulResult; } } } } /* Remove all broadcast TSSTs? */ if ( f_pChannelModify->fRemoveBroadcastTssts == TRUE ) { /* Check if broadcast TSSTs were used on the Rout port. */ if ( pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry != cOCT6100_INVALID_INDEX ) { tOCT6100_CHANNEL_BROADCAST_TSST_REMOVE BroadcastTsstRemove; ulResult = Oct6100ChannelBroadcastTsstRemoveDef( &BroadcastTsstRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Form channel handle. */ BroadcastTsstRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* Remove all broadcast TSSTs associated to the current channel. */ BroadcastTsstRemove.fRemoveAll = TRUE; /* On the Rout port. */ BroadcastTsstRemove.ulPort = cOCT6100_CHANNEL_PORT_ROUT; ulResult = Oct6100ChannelBroadcastTsstRemoveSer( f_pApiInstance, &BroadcastTsstRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if broadcast TSSTs were used on the Sout port. */ if ( pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry != cOCT6100_INVALID_INDEX ) { tOCT6100_CHANNEL_BROADCAST_TSST_REMOVE BroadcastTsstRemove; ulResult = Oct6100ChannelBroadcastTsstRemoveDef( &BroadcastTsstRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Form channel handle. */ BroadcastTsstRemove.ulChannelHndl = cOCT6100_HNDL_TAG_CHANNEL | ( pChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT ) | f_usChanIndex; /* Remove all broadcast TSSTs associated to the current channel. */ BroadcastTsstRemove.fRemoveAll = TRUE; /* On the Sout port. */ BroadcastTsstRemove.ulPort = cOCT6100_CHANNEL_PORT_SOUT; ulResult = Oct6100ChannelBroadcastTsstRemoveSer( f_pApiInstance, &BroadcastTsstRemove ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Check if have to make sure buffer playout is stopped. */ if ( fClearPlayoutPointers == TRUE ) { tOCT6100_BUFFER_PLAYOUT_STOP BufferPlayoutStop; Oct6100BufferPlayoutStopDef( &BufferPlayoutStop ); BufferPlayoutStop.fStopCleanly = FALSE; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, pChanEntry->usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_SOUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, pChanEntry->usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiModifyChannelEntry Description: Updates the channel structure in the ECHO channel list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelModify Pointer to echo cancellation channel modify structure. f_pChannelOpen Pointer to echo cancellation channel configuration structure. f_usChanIndex Index of the channel within the API's channel list. f_usNewPhasingTsstIndex Index of the new phasing TSST. f_fSinSoutCodecActive State of the SIN/SOUT codec. f_fRinRoutCodecActive State of the RIN/ROUT codec. f_usNewRinTsstIndex New RIN TSST memory index. f_usNewSinTsstIndex New SIN TSST memory index. f_usNewRoutTsstIndex New ROUT TSST memory index. f_usNewSoutTsstIndex New SOUT TSST memory index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiModifyChannelEntry UINT32 Oct6100ApiModifyChannelEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChannelModify, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usNewPhasingTsstIndex, IN UINT8 f_fSinSoutCodecActive, IN UINT8 f_fRinRoutCodecActive, IN UINT16 f_usNewRinTsstIndex, IN UINT16 f_usNewSinTsstIndex, IN UINT16 f_usNewRoutTsstIndex, IN UINT16 f_usNewSoutTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_CHANNEL_CODEC pApiCodecConf; tPOCT6100_API_CHANNEL_TDM pApiTdmConf; tPOCT6100_API_CHANNEL_VQE pApiVqeConf; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) /* Obtain local pointer to the configuration structures of the tPOCT6100_API_CHANNEL structure. */ pApiCodecConf = &pChanEntry->CodecConfig; pApiTdmConf = &pChanEntry->TdmConfig; pApiVqeConf = &pChanEntry->VqeConfig; /*=======================================================================*/ /* Copy the channel's general configuration. */ pChanEntry->ulUserChanId = f_pChannelOpen->ulUserChanId; pChanEntry->byEchoOperationMode = (UINT8)( f_pChannelOpen->ulEchoOperationMode & 0xFF ); pChanEntry->fEnableToneDisabler = (UINT8)( f_pChannelOpen->fEnableToneDisabler & 0xFF ); /* Save the codec state.*/ pChanEntry->fSinSoutCodecActive = (UINT8)( f_fSinSoutCodecActive & 0xFF ); pChanEntry->fRinRoutCodecActive = (UINT8)( f_fRinRoutCodecActive & 0xFF ); /*=======================================================================*/ /* Copy the channel's TDM configuration of all the modified fields. */ if ( f_pChannelModify->fTdmConfigModified == TRUE ) { pApiTdmConf->byRinPcmLaw = (UINT8)( f_pChannelOpen->TdmConfig.ulRinPcmLaw & 0xFF ); pApiTdmConf->bySinPcmLaw = (UINT8)( f_pChannelOpen->TdmConfig.ulSinPcmLaw & 0xFF ); pApiTdmConf->byRoutPcmLaw = (UINT8)( f_pChannelOpen->TdmConfig.ulRoutPcmLaw & 0xFF ); pApiTdmConf->bySoutPcmLaw = (UINT8)( f_pChannelOpen->TdmConfig.ulSoutPcmLaw & 0xFF ); pApiTdmConf->byRinNumTssts = (UINT8)( f_pChannelOpen->TdmConfig.ulRinNumTssts & 0xFF ); pApiTdmConf->bySinNumTssts = (UINT8)( f_pChannelOpen->TdmConfig.ulSinNumTssts & 0xFF ); pApiTdmConf->byRoutNumTssts = (UINT8)( f_pChannelOpen->TdmConfig.ulRoutNumTssts & 0xFF ); pApiTdmConf->bySoutNumTssts = (UINT8)( f_pChannelOpen->TdmConfig.ulSoutNumTssts & 0xFF ); if ( f_pChannelModify->TdmConfig.ulRinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_usNewRinTsstIndex != cOCT6100_INVALID_INDEX ) { pApiTdmConf->usRinStream = (UINT16)( f_pChannelOpen->TdmConfig.ulRinStream & 0xFFFF ); pApiTdmConf->usRinTimeslot = (UINT16)( f_pChannelOpen->TdmConfig.ulRinTimeslot & 0xFFFF ); pChanEntry->usRinTsstIndex = f_usNewRinTsstIndex; } else /* f_ulNewRinTsstIndex != cOCT6100_INVALID_INDEX */ { pApiTdmConf->usRinStream = cOCT6100_UNASSIGNED; pApiTdmConf->usRinTimeslot = cOCT6100_UNASSIGNED; pChanEntry->usRinTsstIndex = cOCT6100_INVALID_INDEX; } } if ( f_pChannelModify->TdmConfig.ulSinTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_usNewSinTsstIndex != cOCT6100_INVALID_INDEX ) { pApiTdmConf->usSinStream = (UINT16)( f_pChannelOpen->TdmConfig.ulSinStream & 0xFFFF ); pApiTdmConf->usSinTimeslot = (UINT16)( f_pChannelOpen->TdmConfig.ulSinTimeslot & 0xFFFF ); pChanEntry->usSinTsstIndex = f_usNewSinTsstIndex; } else /* f_ulNewSinTsstIndex != cOCT6100_INVALID_INDEX */ { pApiTdmConf->usSinStream = cOCT6100_UNASSIGNED; pApiTdmConf->usSinTimeslot = cOCT6100_UNASSIGNED; pChanEntry->usSinTsstIndex = cOCT6100_INVALID_INDEX; } } if ( f_pChannelModify->TdmConfig.ulRoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_usNewRoutTsstIndex != cOCT6100_INVALID_INDEX ) { pApiTdmConf->usRoutStream = (UINT16)( f_pChannelOpen->TdmConfig.ulRoutStream & 0xFFFF ); pApiTdmConf->usRoutTimeslot = (UINT16)( f_pChannelOpen->TdmConfig.ulRoutTimeslot & 0xFFFF ); pChanEntry->usRoutTsstIndex = f_usNewRoutTsstIndex; } else /* f_ulNewRoutTsstIndex != cOCT6100_INVALID_INDEX */ { pApiTdmConf->usRoutStream = cOCT6100_UNASSIGNED; pApiTdmConf->usRoutTimeslot = cOCT6100_UNASSIGNED; pChanEntry->usRoutTsstIndex = cOCT6100_INVALID_INDEX; } } if ( f_pChannelModify->TdmConfig.ulSoutTimeslot != cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_usNewSoutTsstIndex != cOCT6100_INVALID_INDEX ) { pApiTdmConf->usSoutStream = (UINT16)( f_pChannelOpen->TdmConfig.ulSoutStream & 0xFFFF ); pApiTdmConf->usSoutTimeslot = (UINT16)( f_pChannelOpen->TdmConfig.ulSoutTimeslot & 0xFFFF ); pChanEntry->usSoutTsstIndex = f_usNewSoutTsstIndex; } else /* f_ulNewSoutTsstIndex != cOCT6100_INVALID_INDEX */ { pApiTdmConf->usSoutStream = cOCT6100_UNASSIGNED; pApiTdmConf->usSoutTimeslot = cOCT6100_UNASSIGNED; pChanEntry->usSoutTsstIndex = cOCT6100_INVALID_INDEX; } } } /*=======================================================================*/ /* Copy the channel's VQE configuration of all the modified fields. */ if ( f_pChannelModify->fVqeConfigModified == TRUE ) { pApiVqeConf->fEnableNlp = (UINT8)( f_pChannelOpen->VqeConfig.fEnableNlp & 0xFF ); pApiVqeConf->byComfortNoiseMode = (UINT8)( f_pChannelOpen->VqeConfig.ulComfortNoiseMode & 0xFF ); pApiVqeConf->fSinDcOffsetRemoval = (UINT8)( f_pChannelOpen->VqeConfig.fSinDcOffsetRemoval & 0xFF ); pApiVqeConf->fRinDcOffsetRemoval = (UINT8)( f_pChannelOpen->VqeConfig.fRinDcOffsetRemoval & 0xFF ); pApiVqeConf->fRinLevelControl = (UINT8)( f_pChannelOpen->VqeConfig.fRinLevelControl & 0xFF ); pApiVqeConf->fSoutLevelControl = (UINT8)( f_pChannelOpen->VqeConfig.fSoutLevelControl & 0xFF ); pApiVqeConf->fRinAutomaticLevelControl = (UINT8)( f_pChannelOpen->VqeConfig.fRinAutomaticLevelControl & 0xFF ); pApiVqeConf->fSoutAutomaticLevelControl = (UINT8)( f_pChannelOpen->VqeConfig.fSoutAutomaticLevelControl & 0xFF ); pApiVqeConf->fRinHighLevelCompensation = (UINT8)( f_pChannelOpen->VqeConfig.fRinHighLevelCompensation & 0xFF ); pApiVqeConf->fSoutAdaptiveNoiseReduction = (UINT8)( f_pChannelOpen->VqeConfig.fSoutAdaptiveNoiseReduction & 0xFF ); pApiVqeConf->fSoutNoiseBleaching = (UINT8)( f_pChannelOpen->VqeConfig.fSoutNoiseBleaching & 0xFF ); pApiVqeConf->fSoutConferencingNoiseReduction = (UINT8)( f_pChannelOpen->VqeConfig.fSoutConferencingNoiseReduction & 0xFF ); pApiVqeConf->chRinLevelControlGainDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lRinLevelControlGainDb & 0xFF ); pApiVqeConf->chSoutLevelControlGainDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lSoutLevelControlGainDb & 0xFF ); pApiVqeConf->chRinAutomaticLevelControlTargetDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lRinAutomaticLevelControlTargetDb & 0xFF ); pApiVqeConf->chSoutAutomaticLevelControlTargetDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lSoutAutomaticLevelControlTargetDb & 0xFF ); pApiVqeConf->chRinHighLevelCompensationThresholdDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lRinHighLevelCompensationThresholdDb & 0xFF ); pApiVqeConf->fEnableTailDisplacement = (UINT8)( f_pChannelOpen->VqeConfig.fEnableTailDisplacement & 0xFF ); pApiVqeConf->usTailDisplacement = (UINT16)( f_pChannelOpen->VqeConfig.ulTailDisplacement & 0xFFFF ); pApiVqeConf->usTailLength = (UINT16)( f_pChannelOpen->VqeConfig.ulTailLength & 0xFFFF ); pApiVqeConf->fAcousticEcho = (UINT8)( f_pChannelOpen->VqeConfig.fAcousticEcho & 0xFF ); pApiVqeConf->fDtmfToneRemoval = (UINT8)( f_pChannelOpen->VqeConfig.fDtmfToneRemoval & 0xFF ); pApiVqeConf->chDefaultErlDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lDefaultErlDb & 0xFF ); pApiVqeConf->chAecDefaultErlDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lAecDefaultErlDb & 0xFF ); pApiVqeConf->usAecTailLength = (UINT16)( f_pChannelOpen->VqeConfig.ulAecTailLength & 0xFFFF ); pApiVqeConf->chAnrSnrEnhancementDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lAnrSnrEnhancementDb & 0xFF ); pApiVqeConf->byAnrVoiceNoiseSegregation = (UINT8)( f_pChannelOpen->VqeConfig.ulAnrVoiceNoiseSegregation & 0xFF ); pApiVqeConf->usToneDisablerVqeActivationDelay = (UINT16)( f_pChannelOpen->VqeConfig.ulToneDisablerVqeActivationDelay & 0xFFFF ); pApiVqeConf->byNonLinearityBehaviorA = (UINT8)( f_pChannelOpen->VqeConfig.ulNonLinearityBehaviorA & 0xFF ); pApiVqeConf->byNonLinearityBehaviorB = (UINT8)( f_pChannelOpen->VqeConfig.ulNonLinearityBehaviorB & 0xFF ); pApiVqeConf->byDoubleTalkBehavior = (UINT8)( f_pChannelOpen->VqeConfig.ulDoubleTalkBehavior & 0xFF ); pApiVqeConf->bySoutAutomaticListenerEnhancementGainDb = (UINT8)( f_pChannelOpen->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb & 0xFF ); pApiVqeConf->bySoutNaturalListenerEnhancementGainDb = (UINT8)( f_pChannelOpen->VqeConfig.ulSoutNaturalListenerEnhancementGainDb & 0xFF ); pApiVqeConf->fSoutNaturalListenerEnhancement = (UINT8)( f_pChannelOpen->VqeConfig.fSoutNaturalListenerEnhancement & 0xFF ); pApiVqeConf->fRoutNoiseReduction = (UINT8)( f_pChannelOpen->VqeConfig.fRoutNoiseReduction & 0xFF ); pApiVqeConf->chRoutNoiseReductionLevelGainDb = (OCT_INT8)( f_pChannelOpen->VqeConfig.lRoutNoiseReductionLevelGainDb & 0xFF ); pApiVqeConf->fEnableMusicProtection = (UINT8)( f_pChannelOpen->VqeConfig.fEnableMusicProtection & 0xFF ); pApiVqeConf->fIdleCodeDetection = (UINT8)( f_pChannelOpen->VqeConfig.fIdleCodeDetection & 0xFF ); } /*=======================================================================*/ /* Copy the channel's CODEC configuration of all the modified fields. */ if ( f_pChannelModify->fCodecConfigModified == TRUE ) { pApiCodecConf->byAdpcmNibblePosition = (UINT8)( f_pChannelOpen->CodecConfig.ulAdpcmNibblePosition & 0xFF ); pApiCodecConf->byEncoderPort = (UINT8)( f_pChannelOpen->CodecConfig.ulEncoderPort & 0xFF ); pApiCodecConf->byEncodingRate = (UINT8)( f_pChannelOpen->CodecConfig.ulEncodingRate & 0xFF ); pApiCodecConf->byDecoderPort = (UINT8)( f_pChannelOpen->CodecConfig.ulDecoderPort & 0xFF ); pApiCodecConf->byDecodingRate = (UINT8)( f_pChannelOpen->CodecConfig.ulDecodingRate & 0xFF ); pApiCodecConf->fEnableSilenceSuppression = (UINT8)( f_pChannelOpen->CodecConfig.fEnableSilenceSuppression & 0xFF ); pApiCodecConf->byPhase = (UINT8)( f_pChannelOpen->CodecConfig.ulPhase & 0xFF ); pApiCodecConf->byPhasingType = (UINT8)( f_pChannelOpen->CodecConfig.ulPhasingType & 0xFF ); /* Update the API phasing TSST structure */ if ( f_usNewPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { tPOCT6100_API_PHASING_TSST pPhasingTsst; /* Release the previous phasing TSST if the channel was already bound to one.*/ if ( pChanEntry->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pPhasingTsst, pChanEntry->usPhasingTsstIndex ); pPhasingTsst->usDependencyCnt--; } mOCT6100_GET_PHASING_TSST_ENTRY_PNT( pSharedInfo, pPhasingTsst, f_usNewPhasingTsstIndex ); pPhasingTsst->usDependencyCnt++; pChanEntry->usPhasingTsstIndex = f_usNewPhasingTsstIndex; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelBroadcastTsstAddSer Description: Assign a TSST to one of the port of an echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstAdd Pointer to TSST assign structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelBroadcastTsstAddSer UINT32 Oct6100ChannelBroadcastTsstAddSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd ) { UINT16 usChanIndex; UINT16 usNewTsstIndex; UINT16 usNewTsstEntry; UINT32 ulResult; ulResult = Oct6100ApiCheckChanTsstAddParams( f_pApiInstance, f_pChannelTsstAdd, &usChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReserveTsstAddResources( f_pApiInstance, f_pChannelTsstAdd, usChanIndex, &usNewTsstIndex, &usNewTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiWriteTsstAddStructs( f_pApiInstance, f_pChannelTsstAdd, usChanIndex, usNewTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiUpdateTsstAddChanEntry( f_pApiInstance, f_pChannelTsstAdd, usChanIndex, usNewTsstIndex, usNewTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChanTsstAddParams Description: Verify the validity of the tPOCT6100_CHANNEL_BROADCAST_TSST_ADD structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstAdd Pointer to echo cancellation channel open configuration structure. f_pusChanIndex Pointer to a structure used to store the multiple resources indexes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChanTsstAddParams UINT32 Oct6100ApiCheckChanTsstAddParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd, OUT PUINT16 f_pusChanIndex ) { tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; UINT32 ulNumTssts = 1; UINT32 ulEntryOpenCnt; /* Check the provided handle. */ if ( (f_pChannelTsstAdd->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelTsstAdd->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelTsstAdd->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* validate the port parameter.*/ if ( f_pChannelTsstAdd->ulPort != cOCT6100_CHANNEL_PORT_ROUT && f_pChannelTsstAdd->ulPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_CHANNEL_TSST_ADD_PORT; /* Get the required number of TSST based on the port.*/ switch( f_pChannelTsstAdd->ulPort ) { case cOCT6100_CHANNEL_PORT_ROUT: ulNumTssts = pChanEntry->TdmConfig.byRoutNumTssts; break; case cOCT6100_CHANNEL_PORT_SOUT: ulNumTssts = pChanEntry->TdmConfig.bySoutNumTssts; break; default: return cOCT6100_ERR_FATAL_B; } /* Check the validity of the timeslot and stream. */ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, ulNumTssts, f_pChannelTsstAdd->ulTimeslot, f_pChannelTsstAdd->ulStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_TSST_ADD_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_TSST_ADD_STREAM; } else { return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveTsstAddResources Description: Reserve the entry for the new broadcast TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstAdd Pointer to echo cancellation channel open configuration structure. f_usChanIndex Channel index within the API's channel list. f_pusNewTsstIndex Pointer to the new TSST index within the API's TSST memory. f_pusNewTsstEntry Pointer to the new TSST entry within the API's TSST list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveTsstAddResources UINT32 Oct6100ApiReserveTsstAddResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd, IN UINT16 f_usChanIndex, OUT PUINT16 f_pusNewTsstIndex, OUT PUINT16 f_pusNewTsstEntry ) { tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulResult; UINT32 ulNumTssts = 1; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_usChanIndex ); switch( f_pChannelTsstAdd->ulPort ) { case cOCT6100_CHANNEL_PORT_ROUT: ulNumTssts = pChanEntry->TdmConfig.byRoutNumTssts; break; case cOCT6100_CHANNEL_PORT_SOUT: ulNumTssts = pChanEntry->TdmConfig.bySoutNumTssts; break; default: return cOCT6100_ERR_FATAL_C; } /* Reserve the new entry.*/ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pChannelTsstAdd->ulTimeslot, f_pChannelTsstAdd->ulStream, ulNumTssts, cOCT6100_OUTPUT_TSST, f_pusNewTsstIndex, f_pusNewTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteTsstAddStructs Description: Configure the TSST control memory for the new TSST entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstAdd Pointer to echo cancellation channel open configuration structure. f_usChanIndex Channel index. f_usNewTsstIndex Tsst index in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteTsstAddStructs UINT32 Oct6100ApiWriteTsstAddStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd, IN UINT16 f_usChanIndex, IN UINT16 f_usNewTsstIndex ) { tPOCT6100_API_CHANNEL pChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult = cOCT6100_ERR_OK; UINT16 usTsiMemIndex; UINT32 ulNumTssts = 1; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_usChanIndex ); switch( f_pChannelTsstAdd->ulPort ) { case cOCT6100_CHANNEL_PORT_ROUT: usTsiMemIndex = pChanEntry->usRinRoutTsiMemIndex; ulNumTssts = pChanEntry->TdmConfig.byRoutNumTssts; break; case cOCT6100_CHANNEL_PORT_SOUT: usTsiMemIndex = pChanEntry->usSinSoutTsiMemIndex; ulNumTssts = pChanEntry->TdmConfig.bySoutNumTssts; break; default: return cOCT6100_ERR_FATAL_D; } /* Write the new entry now.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (f_usNewTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_TSST_CONTROL_MEM_OUTPUT_TSST; WriteParams.usWriteData |= (UINT16)( pChanEntry->CodecConfig.byAdpcmNibblePosition << cOCT6100_TSST_CONTROL_MEM_NIBBLE_POS_OFFSET ); WriteParams.usWriteData |= (UINT16)( (ulNumTssts - 1) << cOCT6100_TSST_CONTROL_MEM_TSST_NUM_OFFSET ); WriteParams.usWriteData |= (UINT16)( usTsiMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateTsstAddChanEntry Description: Update the associated channel API entry to add the new broacast TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstAdd Pointer to echo cancellation channel open configuration structure. f_usChanIndex Channel index. f_usNewTsstIndex TSST index within the TSST control memory. f_usNewTsstEntry TSST entry within the API TSST list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateTsstAddChanEntry UINT32 Oct6100ApiUpdateTsstAddChanEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_ADD f_pChannelTsstAdd, IN UINT16 f_usChanIndex, IN UINT16 f_usNewTsstIndex, IN UINT16 f_usNewTsstEntry ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_TSST_ENTRY pTsstEntry; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_usChanIndex ); mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, f_usNewTsstEntry ); /* Update the channel entry.*/ if ( f_pChannelTsstAdd->ulPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Add the new TSST entry to the broadcast list.*/ pTsstEntry->usNextEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry; pTsstEntry->usTsstMemoryIndex = (UINT16)f_usNewTsstIndex; pTsstEntry->usTsstValue = (UINT16)( (f_pChannelTsstAdd->ulTimeslot << 5) | f_pChannelTsstAdd->ulStream ); /* Modify the first entry pointer.*/ pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry = f_usNewTsstEntry; /* Increment the number of broadcast TSST. */ pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry++; } else /* f_pChannelTsstAdd->ulPort == cOCT6100_CHANNEL_PORT_SOUT */ { /* Add the new TSST entry to the broadcast list.*/ pTsstEntry->usNextEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry; pTsstEntry->usTsstMemoryIndex = (UINT16)f_usNewTsstIndex; pTsstEntry->usTsstValue = (UINT16)( (f_pChannelTsstAdd->ulTimeslot << 5) | f_pChannelTsstAdd->ulStream ); /* Modify the first entry pointer.*/ pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry = f_usNewTsstEntry; /* Increment the number of broadcast TSST. */ pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry++; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelBroadcastTsstRemoveSer Description: Removes a broadcast TSST from one of the output port of an echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstRemove Pointer to TSST remove structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelBroadcastTsstRemoveSer UINT32 Oct6100ChannelBroadcastTsstRemoveSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove) { UINT16 usChanIndex; UINT16 usTsstIndex; UINT16 usTsstEntry; UINT16 usPrevTsstEntry; UINT32 ulResult; ulResult = Oct6100ApiAssertChanTsstRemoveParams( f_pApiInstance, f_pChannelTsstRemove, &usChanIndex, &usTsstIndex, &usTsstEntry, &usPrevTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiInvalidateTsstRemoveStructs( f_pApiInstance, usChanIndex, usTsstIndex, f_pChannelTsstRemove->ulPort, f_pChannelTsstRemove->fRemoveAll ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseTsstRemoveResources( f_pApiInstance, f_pChannelTsstRemove, usChanIndex, usTsstIndex, usTsstEntry, usPrevTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertChanTsstRemoveParams Description: Verify the validity of the tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstRemove Pointer to echo cancellation channel open configuration structure. f_pulChanIndex Pointer to a channel index. f_pulNewTsstIndex Pointer to a TSST index within the TSST control memory. f_pulNewTsstEntry Pointer to a TSST entry within the API TSST list. f_pulPrevTsstEntry Pointer to the previous TSST entry. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertChanTsstRemoveParams UINT32 Oct6100ApiAssertChanTsstRemoveParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusTsstIndex, OUT PUINT16 f_pusTsstEntry, OUT PUINT16 f_pusPrevTsstEntry ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_TSST_ENTRY pTsstEntry; UINT32 ulResult; UINT32 ulNumTssts = 1; UINT32 ulEntryOpenCnt; UINT16 usCurrentEntry; UINT16 usTsstValue; UINT16 usNumEntry; /* Check the provided handle. */ if ( (f_pChannelTsstRemove->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelTsstRemove->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelTsstRemove->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* validate the port parameter.*/ if ( f_pChannelTsstRemove->ulPort != cOCT6100_CHANNEL_PORT_ROUT && f_pChannelTsstRemove->ulPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_CHANNEL_TSST_REMOVE_PORT; /* Verify that the requested entry is present in the channel's port broadcast TSST.*/ if ( f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_ROUT ) { usCurrentEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry; usNumEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry; } else /* f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_SOUT */ { usCurrentEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry; usNumEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry; } /* Verify if at least one TSST is present on the channel port.*/ if ( usNumEntry == 0 ) return cOCT6100_ERR_CHANNEL_TSST_REMOVE_NO_BROADCAST_TSST; /* Get the required number of TSST based on the port.*/ switch( f_pChannelTsstRemove->ulPort ) { case cOCT6100_CHANNEL_PORT_ROUT: ulNumTssts = pChanEntry->TdmConfig.byRoutNumTssts; break; case cOCT6100_CHANNEL_PORT_SOUT: ulNumTssts = pChanEntry->TdmConfig.bySoutNumTssts; break; default: return cOCT6100_ERR_FATAL_E; } /* Initialize the TSST entry to invalid.*/ *f_pusTsstEntry = cOCT6100_INVALID_INDEX; *f_pusPrevTsstEntry = cOCT6100_INVALID_INDEX; *f_pusTsstIndex = cOCT6100_INVALID_INDEX; if ( f_pChannelTsstRemove->fRemoveAll != TRUE ) { /* Check the validity of the timeslot and Stream.*/ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, ulNumTssts, f_pChannelTsstRemove->ulTimeslot, f_pChannelTsstRemove->ulStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_TSST_REMOVE_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_TSST_REMOVE_STREAM; } else { return ulResult; } } /* Set the TSST value based on the timeslot and stream value.*/ usTsstValue = (UINT16)( (f_pChannelTsstRemove->ulTimeslot << 5) | f_pChannelTsstRemove->ulStream ); while( usCurrentEntry != cOCT6100_INVALID_INDEX ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, usCurrentEntry ); if ( usTsstValue == pTsstEntry->usTsstValue ) { /* A match was found.*/ *f_pusTsstEntry = usCurrentEntry; *f_pusTsstIndex = pTsstEntry->usTsstMemoryIndex; break; } /* Move on to the next entry.*/ *f_pusPrevTsstEntry = usCurrentEntry; usCurrentEntry = pTsstEntry->usNextEntry; } if ( *f_pusTsstEntry == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_TSST_REMOVE_INVALID_TSST; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateTsstRemoveStructs Description: Invalidate the entry of the broadcast TSST. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Channel index. f_usTsstIndex TSST index within the TSST control memory. f_ulPort Channel port where the TSST are removed from. (only used if remove all == TRUE) f_fRemoveAll Remove all flag. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateTsstRemoveStructs UINT32 Oct6100ApiInvalidateTsstRemoveStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usTsstIndex, IN UINT32 f_ulPort, IN BOOL f_fRemoveAll ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; if ( f_fRemoveAll == FALSE ) { /* Deactivate the entry now.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (f_usTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* f_fRemoveAll == TRUE */ { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_TSST_ENTRY pTsstEntry; UINT16 usTsstEntry; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_usChanIndex ); /* Clear all entry associated to the selected port.*/ if ( f_ulPort == cOCT6100_CHANNEL_PORT_ROUT ) usTsstEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry; else usTsstEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry; do { mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, usTsstEntry ); /* Deactivate the entry now.*/ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( ( pTsstEntry->usTsstMemoryIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usTsstEntry = pTsstEntry->usNextEntry; } while ( usTsstEntry != cOCT6100_INVALID_INDEX ); } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseTsstRemoveResources Description: Release all API resources associated to the Removed TSST and update the channel entry accordingly. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelTsstRemove Pointer to echo cancellation channel open configuration structure. f_usChanIndex Channel index. f_usTsstIndex TSST index within the TSST control memory. f_usTsstEntry TSST entry within the API's TSST list. f_usPrevTsstEntry Previous TSST entry within the API's TSST list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseTsstRemoveResources UINT32 Oct6100ApiReleaseTsstRemoveResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_BROADCAST_TSST_REMOVE f_pChannelTsstRemove, IN UINT16 f_usChanIndex, IN UINT16 f_usTsstIndex, IN UINT16 f_usTsstEntry, IN UINT16 f_usPrevTsstEntry ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_API_TSST_ENTRY pTsstEntry; tPOCT6100_API_TSST_ENTRY pPrevTsstEntry; UINT16 usCurrentEntry; UINT32 ulResult; UINT32 ulTimeslot; UINT32 ulStream; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, f_usChanIndex ); if ( f_pChannelTsstRemove->fRemoveAll == FALSE ) { mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, f_usTsstEntry ); /* Update the channel entry.*/ if ( f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_ROUT ) { /* Check if the entry was the first in the list.*/ if ( f_usPrevTsstEntry == cOCT6100_INVALID_INDEX ) { pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry = pTsstEntry->usNextEntry; } else /* f_ulPrevTsstEntry != cOCT6100_INVALID_INDEX */ { /* Get a pointer to the previous entry.*/ mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPrevTsstEntry, f_usPrevTsstEntry ); pPrevTsstEntry->usNextEntry = pTsstEntry->usNextEntry; } /* Decrement the number of entry.*/ pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry--; } else /* f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_SOUT */ { /* Check if the entry was the first in the list.*/ if ( f_usPrevTsstEntry == cOCT6100_INVALID_INDEX ) { pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry = pTsstEntry->usNextEntry; } else /* f_ulPrevTsstEntry != cOCT6100_INVALID_INDEX */ { /* Get a pointer to the previous entry.*/ mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPrevTsstEntry, f_usPrevTsstEntry ); pPrevTsstEntry->usNextEntry = pTsstEntry->usNextEntry; } /* Decrement the number of entry.*/ pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry--; } ulTimeslot = pTsstEntry->usTsstValue >> 5; ulStream = pTsstEntry->usTsstValue & 0x1F; /* Release the entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, ulTimeslot, ulStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, f_usTsstEntry ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* f_pChannelTsstRemove->fRemoveAll == TRUE */ { /* Update the channel entry.*/ if ( f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_ROUT ) usCurrentEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry; else usCurrentEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry; do { mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, usCurrentEntry ); ulTimeslot = pTsstEntry->usTsstValue >> 5; ulStream = pTsstEntry->usTsstValue & 0x1F; /* Release the entry.*/ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, ulTimeslot, ulStream, cOCT6100_NUMBER_TSSTS_1, cOCT6100_OUTPUT_TSST, usCurrentEntry ); /* Release the entry.*/ if ( ulResult != cOCT6100_ERR_OK ) return ulResult; usCurrentEntry = pTsstEntry->usNextEntry; /* Clear the previous node.*/ pTsstEntry->usTsstMemoryIndex = 0xFFFF; pTsstEntry->usTsstValue = 0xFFFF; pTsstEntry->usNextEntry = cOCT6100_INVALID_INDEX; } while ( usCurrentEntry != cOCT6100_INVALID_INDEX ); /* Reset the channel status.*/ if ( f_pChannelTsstRemove->ulPort == cOCT6100_CHANNEL_PORT_ROUT ) { pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry = cOCT6100_INVALID_INDEX; pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry = 0; } else { pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry = cOCT6100_INVALID_INDEX; pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry = 0; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiChannelGetStatsSer Description: Serialized function that returns all the stats of the specified channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelStats Pointer to a channel stats structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiChannelGetStatsSer UINT32 Oct6100ApiChannelGetStatsSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_STATS f_pChannelStats ) { tOCT6100_READ_PARAMS ReadParams; tOCT6100_READ_BURST_PARAMS BurstParams; tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_TSST_ENTRY pTsstEntry; UINT32 ulEntryOpenCnt; UINT16 usCurrentEntry; UINT16 usTsstCount; UINT32 ulBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulTempData; UINT32 ulMask; UINT16 usChanIndex; UINT16 ausReadData[ 32 ]; BYTE byRinEnergyRaw; BYTE bySinEnergyRaw; BYTE bySoutEnergyRaw; INT32 lSoutEnergyIndB; BYTE byCnEnergyRaw; UINT16 usEchoDelayInFrames; UINT16 usErlRaw; UINT32 ulResult; UINT16 usReadData; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; BurstParams.pProcessContext = f_pApiInstance->pProcessContext; BurstParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; BurstParams.pusReadData = ausReadData; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /* Check the reset stats flag.*/ if ( f_pChannelStats->fResetStats != TRUE && f_pChannelStats->fResetStats != FALSE ) return cOCT6100_ERR_CHANNEL_STATS_RESET; /* Check the provided handle. */ if ( cOCT6100_HNDL_TAG_CHANNEL != (f_pChannelStats->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; usChanIndex = (UINT16)( f_pChannelStats->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( usChanIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pChanEntry, usChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelStats->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Check the value of the max broadcast tsst.*/ if ( f_pChannelStats->TdmConfig.ulMaxBroadcastTssts > cOCT6100_MAX_TSSTS ) return cOCT6100_ERR_CHANNEL_GET_STATS_MAX_BROADCAST_TSST; if ( f_pChannelStats->TdmConfig.ulMaxBroadcastTssts != 0 ) { /* Check if memory was allocated by the user for the stream and timeslot values.*/ if ( f_pChannelStats->TdmConfig.pulRoutBroadcastTimeslot == NULL ) return cOCT6100_ERR_CHANNEL_ROUT_BROADCAST_TIMESLOT; if ( f_pChannelStats->TdmConfig.pulRoutBroadcastStream == NULL ) return cOCT6100_ERR_CHANNEL_ROUT_BROADCAST_STREAM; if ( f_pChannelStats->TdmConfig.pulSoutBroadcastTimeslot == NULL ) return cOCT6100_ERR_CHANNEL_SOUT_BROADCAST_TIMESLOT; if ( f_pChannelStats->TdmConfig.pulSoutBroadcastStream == NULL ) return cOCT6100_ERR_CHANNEL_SOUT_BROADCAST_STREAM; } /* Copy the general configuration.*/ f_pChannelStats->ulUserChanId = pChanEntry->ulUserChanId; f_pChannelStats->ulEchoOperationMode = pChanEntry->byEchoOperationMode; f_pChannelStats->fEnableToneDisabler = pChanEntry->fEnableToneDisabler; f_pChannelStats->ulMutePortsMask = pChanEntry->usMutedPorts; f_pChannelStats->fEnableExtToneDetection = pChanEntry->fEnableExtToneDetection; /* Copy the TDM configuration.*/ f_pChannelStats->TdmConfig.ulNumRoutBroadcastTssts = pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry; f_pChannelStats->TdmConfig.ulNumSoutBroadcastTssts = pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry; f_pChannelStats->TdmConfig.ulSinNumTssts = pChanEntry->TdmConfig.bySinNumTssts; f_pChannelStats->TdmConfig.ulSinTimeslot = pChanEntry->TdmConfig.usSinTimeslot; f_pChannelStats->TdmConfig.ulSinStream = pChanEntry->TdmConfig.usSinStream; f_pChannelStats->TdmConfig.ulSinPcmLaw = pChanEntry->TdmConfig.bySinPcmLaw; f_pChannelStats->TdmConfig.ulSoutNumTssts = pChanEntry->TdmConfig.bySoutNumTssts; f_pChannelStats->TdmConfig.ulSoutTimeslot = pChanEntry->TdmConfig.usSoutTimeslot; f_pChannelStats->TdmConfig.ulSoutStream = pChanEntry->TdmConfig.usSoutStream; f_pChannelStats->TdmConfig.ulSoutPcmLaw = pChanEntry->TdmConfig.bySoutPcmLaw; /* Copy the SOUT Broadcast TSST into the Stream and timeslot array.*/ usCurrentEntry = pChanEntry->TdmConfig.usSoutBrdcastTsstFirstEntry; for( usTsstCount = 0; (usTsstCount < pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry) && (usTsstCount < f_pChannelStats->TdmConfig.ulMaxBroadcastTssts); usTsstCount++ ) { if ( usCurrentEntry == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_FATAL_F; mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, usCurrentEntry ); f_pChannelStats->TdmConfig.pulSoutBroadcastStream[ usTsstCount ] = pTsstEntry->usTsstValue & 0x1F; f_pChannelStats->TdmConfig.pulSoutBroadcastStream[ usTsstCount ] = pTsstEntry->usTsstValue >> 5; /* Obtain the index of the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; } /* Check if all Sout Broadcast TSST were returned.*/ if ( usTsstCount < pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry ) { f_pChannelStats->TdmConfig.fMoreSoutBroadcastTssts = TRUE; } else /* usTsstCount >= pChanEntry->TdmConfig.usSoutBrdcastTsstNumEntry */ { f_pChannelStats->TdmConfig.fMoreSoutBroadcastTssts = FALSE; } f_pChannelStats->TdmConfig.ulRinNumTssts = pChanEntry->TdmConfig.byRinNumTssts; f_pChannelStats->TdmConfig.ulRinTimeslot = pChanEntry->TdmConfig.usRinTimeslot; f_pChannelStats->TdmConfig.ulRinStream = pChanEntry->TdmConfig.usRinStream; f_pChannelStats->TdmConfig.ulRinPcmLaw = pChanEntry->TdmConfig.byRinPcmLaw; f_pChannelStats->TdmConfig.ulRoutNumTssts = pChanEntry->TdmConfig.byRoutNumTssts; f_pChannelStats->TdmConfig.ulRoutTimeslot = pChanEntry->TdmConfig.usRoutTimeslot; f_pChannelStats->TdmConfig.ulRoutStream = pChanEntry->TdmConfig.usRoutStream; f_pChannelStats->TdmConfig.ulRoutPcmLaw = pChanEntry->TdmConfig.byRoutPcmLaw; /* Copy the ROUT Broadcast TSST into the Stream and timeslot array.*/ usCurrentEntry = pChanEntry->TdmConfig.usRoutBrdcastTsstFirstEntry; for( usTsstCount = 0; (usTsstCount < pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry) && (usTsstCount < f_pChannelStats->TdmConfig.ulMaxBroadcastTssts); usTsstCount++ ) { if ( usCurrentEntry == cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_FATAL_10; mOCT6100_GET_TSST_LIST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pTsstEntry, usCurrentEntry ); f_pChannelStats->TdmConfig.pulRoutBroadcastStream[ usTsstCount ] = pTsstEntry->usTsstValue & 0x1F; f_pChannelStats->TdmConfig.pulRoutBroadcastStream[ usTsstCount ] = pTsstEntry->usTsstValue >> 5; /* Obtain the index of the next entry.*/ usCurrentEntry = pTsstEntry->usNextEntry; } /* Check if all Rout Broadcast TSST were returned.*/ if ( usTsstCount < pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry ) { f_pChannelStats->TdmConfig.fMoreRoutBroadcastTssts = TRUE; } else /* usTsstCount >= pChanEntry->TdmConfig.usRoutBrdcastTsstNumEntry */ { f_pChannelStats->TdmConfig.fMoreRoutBroadcastTssts = FALSE; } /* Copy the VQE configuration.*/ f_pChannelStats->VqeConfig.fEnableNlp = pChanEntry->VqeConfig.fEnableNlp; f_pChannelStats->VqeConfig.ulComfortNoiseMode = pChanEntry->VqeConfig.byComfortNoiseMode; f_pChannelStats->VqeConfig.fEnableTailDisplacement = pChanEntry->VqeConfig.fEnableTailDisplacement; if ( pChanEntry->VqeConfig.usTailDisplacement != cOCT6100_AUTO_SELECT_TAIL ) f_pChannelStats->VqeConfig.ulTailDisplacement = pChanEntry->VqeConfig.usTailDisplacement; else f_pChannelStats->VqeConfig.ulTailDisplacement = f_pApiInstance->pSharedInfo->ChipConfig.usTailDisplacement; if ( pChanEntry->VqeConfig.usTailLength != cOCT6100_AUTO_SELECT_TAIL ) f_pChannelStats->VqeConfig.ulTailLength = pChanEntry->VqeConfig.usTailLength; else f_pChannelStats->VqeConfig.ulTailLength = f_pApiInstance->pSharedInfo->ImageInfo.usMaxTailLength; f_pChannelStats->VqeConfig.fSinDcOffsetRemoval = pChanEntry->VqeConfig.fSinDcOffsetRemoval; f_pChannelStats->VqeConfig.fRinDcOffsetRemoval = pChanEntry->VqeConfig.fRinDcOffsetRemoval; f_pChannelStats->VqeConfig.fRinLevelControl = pChanEntry->VqeConfig.fRinLevelControl; f_pChannelStats->VqeConfig.fSoutLevelControl = pChanEntry->VqeConfig.fSoutLevelControl; f_pChannelStats->VqeConfig.fRinAutomaticLevelControl = pChanEntry->VqeConfig.fRinAutomaticLevelControl; f_pChannelStats->VqeConfig.fSoutAutomaticLevelControl = pChanEntry->VqeConfig.fSoutAutomaticLevelControl; f_pChannelStats->VqeConfig.fRinHighLevelCompensation = pChanEntry->VqeConfig.fRinHighLevelCompensation; f_pChannelStats->VqeConfig.fSoutAdaptiveNoiseReduction = pChanEntry->VqeConfig.fSoutAdaptiveNoiseReduction; f_pChannelStats->VqeConfig.fSoutNoiseBleaching = pChanEntry->VqeConfig.fSoutNoiseBleaching; f_pChannelStats->VqeConfig.fSoutConferencingNoiseReduction = pChanEntry->VqeConfig.fSoutConferencingNoiseReduction; f_pChannelStats->VqeConfig.lRinLevelControlGainDb = pChanEntry->VqeConfig.chRinLevelControlGainDb; f_pChannelStats->VqeConfig.lSoutLevelControlGainDb = pChanEntry->VqeConfig.chSoutLevelControlGainDb; f_pChannelStats->VqeConfig.lRinAutomaticLevelControlTargetDb = pChanEntry->VqeConfig.chRinAutomaticLevelControlTargetDb; f_pChannelStats->VqeConfig.lSoutAutomaticLevelControlTargetDb = pChanEntry->VqeConfig.chSoutAutomaticLevelControlTargetDb; f_pChannelStats->VqeConfig.lRinHighLevelCompensationThresholdDb = pChanEntry->VqeConfig.chRinHighLevelCompensationThresholdDb; f_pChannelStats->VqeConfig.fAcousticEcho = pChanEntry->VqeConfig.fAcousticEcho; f_pChannelStats->VqeConfig.fDtmfToneRemoval = pChanEntry->VqeConfig.fDtmfToneRemoval; f_pChannelStats->VqeConfig.lDefaultErlDb = pChanEntry->VqeConfig.chDefaultErlDb; f_pChannelStats->VqeConfig.lAecDefaultErlDb = pChanEntry->VqeConfig.chAecDefaultErlDb; f_pChannelStats->VqeConfig.ulAecTailLength = pChanEntry->VqeConfig.usAecTailLength; f_pChannelStats->VqeConfig.lAnrSnrEnhancementDb = pChanEntry->VqeConfig.chAnrSnrEnhancementDb; f_pChannelStats->VqeConfig.ulAnrVoiceNoiseSegregation = pChanEntry->VqeConfig.byAnrVoiceNoiseSegregation; f_pChannelStats->VqeConfig.ulToneDisablerVqeActivationDelay = pChanEntry->VqeConfig.usToneDisablerVqeActivationDelay; f_pChannelStats->VqeConfig.ulNonLinearityBehaviorA = pChanEntry->VqeConfig.byNonLinearityBehaviorA; f_pChannelStats->VqeConfig.ulNonLinearityBehaviorB = pChanEntry->VqeConfig.byNonLinearityBehaviorB; f_pChannelStats->VqeConfig.ulDoubleTalkBehavior = pChanEntry->VqeConfig.byDoubleTalkBehavior; f_pChannelStats->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = pChanEntry->VqeConfig.bySoutAutomaticListenerEnhancementGainDb; f_pChannelStats->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = pChanEntry->VqeConfig.bySoutNaturalListenerEnhancementGainDb; f_pChannelStats->VqeConfig.fSoutNaturalListenerEnhancement = pChanEntry->VqeConfig.fSoutNaturalListenerEnhancement; f_pChannelStats->VqeConfig.fRoutNoiseReduction = pChanEntry->VqeConfig.fRoutNoiseReduction; f_pChannelStats->VqeConfig.lRoutNoiseReductionLevelGainDb = pChanEntry->VqeConfig.chRoutNoiseReductionLevelGainDb; f_pChannelStats->VqeConfig.fEnableMusicProtection = pChanEntry->VqeConfig.fEnableMusicProtection; f_pChannelStats->VqeConfig.fIdleCodeDetection = pChanEntry->VqeConfig.fIdleCodeDetection; /* Copy the CODEC configuration.*/ f_pChannelStats->CodecConfig.ulAdpcmNibblePosition = pChanEntry->CodecConfig.byAdpcmNibblePosition; f_pChannelStats->CodecConfig.ulEncoderPort = pChanEntry->CodecConfig.byEncoderPort; f_pChannelStats->CodecConfig.ulEncodingRate = pChanEntry->CodecConfig.byEncodingRate; f_pChannelStats->CodecConfig.ulDecoderPort = pChanEntry->CodecConfig.byDecoderPort; f_pChannelStats->CodecConfig.ulDecodingRate = pChanEntry->CodecConfig.byDecodingRate; f_pChannelStats->CodecConfig.fEnableSilenceSuppression = pChanEntry->CodecConfig.fEnableSilenceSuppression; f_pChannelStats->CodecConfig.ulPhase = pChanEntry->CodecConfig.byPhase; f_pChannelStats->CodecConfig.ulPhasingType = pChanEntry->CodecConfig.byPhasingType; if ( pChanEntry->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { tPOCT6100_API_PHASING_TSST pPhasingTsstEntry; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingTsstEntry, pChanEntry->usPhasingTsstIndex ); f_pChannelStats->CodecConfig.ulPhasingTsstHndl = cOCT6100_HNDL_TAG_PHASING_TSST | (pPhasingTsstEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | pChanEntry->usPhasingTsstIndex; } else { f_pChannelStats->CodecConfig.ulPhasingTsstHndl = cOCT6100_INVALID_HANDLE; } /* Reset the stats and exit if the reset flag is set.*/ if ( f_pChannelStats->fResetStats == TRUE ) { pChanEntry->sMaxERLE = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->sMaxERL = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->usMaxEchoDelay = cOCT6100_INVALID_STAT_W; } /*---------------------------------------------------------------------*/ /* Update the API internal stats.*/ BurstParams.ulReadAddress = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase + (usChanIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ); BurstParams.ulReadAddress += f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoStatsOfst; BurstParams.ulReadLength = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoStatsSize / 2; /* Length in words.*/ mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Check if the energy stat are found in the new memory location. */ if ( ( pSharedInfo->ImageInfo.fRinEnergyStat == TRUE ) && ( pSharedInfo->ImageInfo.fSoutEnergyStat == TRUE ) ) { ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.RinEnergyStatFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = f_pApiInstance->pSharedInfo->MemoryMap.RinEnergyStatFieldOfst.byBitOffset; ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.RinEnergyStatFieldOfst.byFieldSize; ReadParams.ulReadAddress = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase + (usChanIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ); ReadParams.ulReadAddress += f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst + ulFeatureBytesOffset; /* Optimize this access by only reading the word we are interested in. */ if ( ulFeatureBitOffset < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulFeatureBitOffset < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; /* Clear previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= ulMask; /* Shift to get value. */ ulTempData = ulTempData >> ulFeatureBitOffset; /* Overwrite value read the old way. */ ausReadData[ 0 ] &= 0x00FF; ausReadData[ 0 ] |= (UINT16)( ( ulTempData << 8 ) & 0xFF00 ); ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.SoutEnergyStatFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = f_pApiInstance->pSharedInfo->MemoryMap.SoutEnergyStatFieldOfst.byBitOffset; ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.SoutEnergyStatFieldOfst.byFieldSize; ReadParams.ulReadAddress = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase + (usChanIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ); ReadParams.ulReadAddress += f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst + ulFeatureBytesOffset; /* Optimize this access by only reading the word we are interested in. */ if ( ulFeatureBitOffset < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulFeatureBitOffset < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; /* Clear previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= ulMask; /* Shift to get value. */ ulTempData = ulTempData >> ulFeatureBitOffset; /* Overwrite value read the old way. */ ausReadData[ 1 ] &= 0x00FF; ausReadData[ 1 ] |= (UINT16)( ( ulTempData << 8 ) & 0xFF00 ); } byRinEnergyRaw = (BYTE)(( ausReadData[ 0 ] >> 8 ) & 0xFF); bySinEnergyRaw = (BYTE)(( ausReadData[ 0 ] >> 0 ) & 0xFF); bySoutEnergyRaw = (BYTE)(( ausReadData[ 1 ] >> 8 ) & 0xFF); byCnEnergyRaw = (BYTE)(( ausReadData[ 5 ] >> 8 ) & 0xFF); usEchoDelayInFrames = (UINT16)(ausReadData[ 4 ]); usErlRaw = ausReadData[ 2 ]; pChanEntry->byToneDisablerStatus = (UINT8)(( ausReadData[ 5 ] >> 0 ) & 0xFF); if ( f_pChannelStats->fResetStats == TRUE ) { pChanEntry->usNumEchoPathChangesOfst = (UINT16)(ausReadData[ 3 ]); pChanEntry->usNumEchoPathChanges = 0; } else /* if ( f_pChannelStats->fResetStats == FALSE ) */ { pChanEntry->usNumEchoPathChanges = (UINT16)( ausReadData[ 3 ] - pChanEntry->usNumEchoPathChangesOfst ); } pChanEntry->sComfortNoiseLevel = (INT16)( Oct6100ApiOctFloatToDbEnergyByte( byCnEnergyRaw ) & 0xFFFF ); pChanEntry->sComfortNoiseLevel -= 12; pChanEntry->sRinLevel = (INT16)( Oct6100ApiOctFloatToDbEnergyByte( byRinEnergyRaw ) & 0xFFFF ); pChanEntry->sRinLevel -= 12; pChanEntry->sSinLevel = (INT16)( Oct6100ApiOctFloatToDbEnergyByte( bySinEnergyRaw ) & 0xFFFF ); pChanEntry->sSinLevel -= 12; lSoutEnergyIndB = Oct6100ApiOctFloatToDbEnergyByte( bySoutEnergyRaw ); lSoutEnergyIndB -= 12; /* Process some stats only if the channel is converged.*/ if ( ( usEchoDelayInFrames != cOCT6100_INVALID_ECHO_DELAY ) && ( pChanEntry->byEchoOperationMode != cOCT6100_ECHO_OP_MODE_POWER_DOWN ) && ( pChanEntry->byEchoOperationMode != cOCT6100_ECHO_OP_MODE_HT_RESET ) ) { /* Update the current ERL. */ pChanEntry->sCurrentERL = (INT16)( Oct6100ApiOctFloatToDbEnergyHalf( usErlRaw ) & 0xFFFF ); pChanEntry->sCurrentERLE = (INT16)( ( lSoutEnergyIndB - pChanEntry->sSinLevel ) & 0xFFFF ); pChanEntry->usCurrentEchoDelay = (UINT16)( usEchoDelayInFrames / 8 ); /* To convert in msec.*/ /* Update the max value if required.*/ if ( pChanEntry->usCurrentEchoDelay > pChanEntry->usMaxEchoDelay || pChanEntry->usMaxEchoDelay == cOCT6100_INVALID_STAT_W ) { pChanEntry->usMaxEchoDelay = pChanEntry->usCurrentEchoDelay; } if ( pChanEntry->sCurrentERL > pChanEntry->sMaxERL || pChanEntry->sMaxERL == cOCT6100_INVALID_SIGNED_STAT_W ) { pChanEntry->sMaxERL = pChanEntry->sCurrentERL; } if ( pChanEntry->sCurrentERLE > pChanEntry->sMaxERLE || pChanEntry->sMaxERLE == cOCT6100_INVALID_SIGNED_STAT_W ) { pChanEntry->sMaxERLE = pChanEntry->sCurrentERLE; } } else { pChanEntry->sCurrentERLE = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->sCurrentERL = cOCT6100_INVALID_SIGNED_STAT_W; pChanEntry->usCurrentEchoDelay = cOCT6100_INVALID_STAT_W; } if ( f_pApiInstance->pSharedInfo->ImageInfo.fRinAppliedGainStat == TRUE ) { /* Calculate base address for auto level control + high level compensation configuration. */ ulBaseAddress = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase + ( usChanIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst; ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.RinAppliedGainStatOfst.usDwordOffset * 4; ulFeatureBitOffset = f_pApiInstance->pSharedInfo->MemoryMap.RinAppliedGainStatOfst.byBitOffset; ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.RinAppliedGainStatOfst.byFieldSize; ReadParams.ulReadAddress = ulBaseAddress + ulFeatureBytesOffset; /* Optimize this access by only reading the word we are interested in. */ if ( ulFeatureBitOffset < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulFeatureBitOffset < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= ulMask; /* Shift to get value. */ ulTempData = ulTempData >> ulFeatureBitOffset; pChanEntry->sRinAppliedGain = (INT16)( 2 * (INT16)( Oct6100ApiOctFloatToDbEnergyHalf( (UINT16)( ulTempData & 0xFFFF ) ) & 0xFFFF ) ); } if ( f_pApiInstance->pSharedInfo->ImageInfo.fSoutAppliedGainStat == TRUE ) { /* Calculate base address for auto level control + high level compensation configuration. */ ulBaseAddress = f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemBase + ( usChanIndex * f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst; ulFeatureBytesOffset = f_pApiInstance->pSharedInfo->MemoryMap.SoutAppliedGainStatOfst.usDwordOffset * 4; ulFeatureBitOffset = f_pApiInstance->pSharedInfo->MemoryMap.SoutAppliedGainStatOfst.byBitOffset; ulFeatureFieldLength = f_pApiInstance->pSharedInfo->MemoryMap.SoutAppliedGainStatOfst.byFieldSize; ReadParams.ulReadAddress = ulBaseAddress + ulFeatureBytesOffset; /* Optimize this access by only reading the word we are interested in. */ if ( ulFeatureBitOffset < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulFeatureBitOffset < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; /* Clear previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= ulMask; /* Shift to get value. */ ulTempData = ulTempData >> ulFeatureBitOffset; pChanEntry->sSoutAppliedGain = (INT16)( 2 * (INT16)( Oct6100ApiOctFloatToDbEnergyHalf( (UINT16)( ulTempData & 0xFFFF ) ) & 0xFFFF ) ); } /*---------------------------------------------------------------------*/ /* Return the real stats.*/ f_pChannelStats->ulNumEchoPathChanges = pChanEntry->usNumEchoPathChanges; if ( usEchoDelayInFrames != cOCT6100_INVALID_ECHO_DELAY ) { f_pChannelStats->fEchoCancellerConverged = TRUE; } else { f_pChannelStats->fEchoCancellerConverged = FALSE; } if ( pChanEntry->sCurrentERL == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lCurrentERL = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lCurrentERL = pChanEntry->sCurrentERL; if ( pChanEntry->sMaxERL == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lMaxERL = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lMaxERL = pChanEntry->sMaxERL; if ( pChanEntry->usMaxEchoDelay == cOCT6100_INVALID_STAT_W ) f_pChannelStats->ulMaxEchoDelay = cOCT6100_INVALID_STAT; else f_pChannelStats->ulMaxEchoDelay = pChanEntry->usMaxEchoDelay; if ( pChanEntry->sRinLevel == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lRinLevel = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lRinLevel = pChanEntry->sRinLevel; if ( pSharedInfo->ImageInfo.fSinLevel == TRUE ) { if ( pChanEntry->sSinLevel == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lSinLevel = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lSinLevel = pChanEntry->sSinLevel; } else /* if ( pSharedInfo->ImageInfo.fSinLevel != TRUE ) */ { /* SIN level is not supported in this image. */ f_pChannelStats->lSinLevel = cOCT6100_INVALID_SIGNED_STAT; } f_pChannelStats->lRinAppliedGain = pChanEntry->VqeConfig.chRinLevelControlGainDb; if ( ( f_pApiInstance->pSharedInfo->ImageInfo.fRinAppliedGainStat == TRUE ) && ( ( pChanEntry->VqeConfig.fRinAutomaticLevelControl == TRUE ) || ( pChanEntry->VqeConfig.fRinHighLevelCompensation == TRUE ) ) ) { f_pChannelStats->lRinAppliedGain = pChanEntry->sRinAppliedGain; } f_pChannelStats->lSoutAppliedGain = pChanEntry->VqeConfig.chSoutLevelControlGainDb; if ( ( f_pApiInstance->pSharedInfo->ImageInfo.fSoutAppliedGainStat == TRUE ) && ( pChanEntry->VqeConfig.fSoutAutomaticLevelControl == TRUE ) ) { f_pChannelStats->lSoutAppliedGain = pChanEntry->sSoutAppliedGain; } if ( pChanEntry->usCurrentEchoDelay == cOCT6100_INVALID_STAT_W ) f_pChannelStats->ulCurrentEchoDelay = cOCT6100_INVALID_STAT; else f_pChannelStats->ulCurrentEchoDelay = pChanEntry->usCurrentEchoDelay; if ( pSharedInfo->ImageInfo.fSinLevel == TRUE ) { if ( pChanEntry->sCurrentERLE == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lCurrentERLE = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lCurrentERLE = pChanEntry->sCurrentERLE; } else /* if ( pSharedInfo->ImageInfo.fSinLevel != TRUE ) */ { f_pChannelStats->lCurrentERLE = cOCT6100_INVALID_SIGNED_STAT; } if ( pSharedInfo->ImageInfo.fSinLevel == TRUE ) { if ( pChanEntry->sMaxERLE == cOCT6100_INVALID_SIGNED_STAT_W ) f_pChannelStats->lMaxERLE = cOCT6100_INVALID_SIGNED_STAT; else f_pChannelStats->lMaxERLE = pChanEntry->sMaxERLE; } else /* if ( pSharedInfo->ImageInfo.fSinLevel != TRUE ) */ { f_pChannelStats->lMaxERLE = cOCT6100_INVALID_SIGNED_STAT; } f_pChannelStats->lComfortNoiseLevel = pChanEntry->sComfortNoiseLevel; f_pChannelStats->ulToneDisablerStatus = pChanEntry->byToneDisablerStatus; if ( f_pApiInstance->pSharedInfo->ImageInfo.fSinVoiceDetectedStat == TRUE ) { UINT32 ulVoiceDetectedBytesOfst = f_pApiInstance->pSharedInfo->MemoryMap.SinVoiceDetectedStatOfst.usDwordOffset * 4; UINT32 ulVoiceDetectedBitOfst = f_pApiInstance->pSharedInfo->MemoryMap.SinVoiceDetectedStatOfst.byBitOffset; UINT32 ulVoiceDetectedFieldSize = f_pApiInstance->pSharedInfo->MemoryMap.SinVoiceDetectedStatOfst.byFieldSize; /* Set the channel root base address.*/ UINT32 ulChannelRootBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( usChanIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanRootConfOfst; ReadParams.ulReadAddress = ulChannelRootBaseAddress + ulVoiceDetectedBytesOfst; /* Optimize this access by only reading the word we are interested in. */ if ( ulVoiceDetectedBitOfst < 16 ) ReadParams.ulReadAddress += 2; /* Must read in memory directly since this value is changed by hardware */ mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Move data at correct position according to what was read. */ if ( ulVoiceDetectedBitOfst < 16 ) ulTempData = usReadData; else ulTempData = usReadData << 16; mOCT6100_CREATE_FEATURE_MASK( ulVoiceDetectedFieldSize, ulVoiceDetectedBitOfst, &ulMask ); if ( ( ulTempData & ulMask ) != 0x0 ) f_pChannelStats->fSinVoiceDetected = TRUE; else f_pChannelStats->fSinVoiceDetected = FALSE; } /*---------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveEchoEntry Description: Reserves one of the echo channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusEchoIndex Resulting index reserved in the echo channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveEchoEntry UINT32 Oct6100ApiReserveEchoEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusEchoIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pEchoAlloc; UINT32 ulResult; UINT32 ulEchoIndex; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ALLOC_PNT( pSharedInfo, pEchoAlloc ) ulResult = OctapiLlmAllocAlloc( pEchoAlloc, &ulEchoIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_CHANNEL_ALL_CHANNELS_ARE_OPENED; else return cOCT6100_ERR_FATAL_11; } *f_pusEchoIndex = (UINT16)( ulEchoIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseEchoEntry Description: Releases the specified ECHO channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usEchoIndex Index reserved in the echo channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseEchoEntry UINT32 Oct6100ApiReleaseEchoEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEchoIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pEchoAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_CHANNEL_ALLOC_PNT( pSharedInfo, pEchoAlloc ) ulResult = OctapiLlmAllocDealloc( pEchoAlloc, f_usEchoIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_12; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveBiDirChanEntry Description: Reserves one of the bidirectional channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusBiDirChanIndex Resulting index reserved in the bidir channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveBiDirChanEntry UINT32 Oct6100ApiReserveBiDirChanEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusBiDirChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pChanAlloc; UINT32 ulResult; UINT32 ulBiDirChanIndex; /* Get local pointer to shared portion of the API instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_BIDIR_CHANNEL_ALLOC_PNT( pSharedInfo, pChanAlloc ) ulResult = OctapiLlmAllocAlloc( pChanAlloc, &ulBiDirChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_CHANNEL_ALL_BIDIR_CHANNELS_ARE_OPENED; else return cOCT6100_ERR_FATAL_9F; } *f_pusBiDirChanIndex = (UINT16)( ulBiDirChanIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBiDirChanEntry Description: Releases the specified bidirectional channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulBiDirChanIndex Bidirectional channel index within the API's Bidir channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBiDirChanEntry UINT32 Oct6100ApiReleaseBiDirChanEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulBiDirChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pChanAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_BIDIR_CHANNEL_ALLOC_PNT( pSharedInfo, pChanAlloc ) ulResult = OctapiLlmAllocDealloc( pChanAlloc, f_ulBiDirChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_A0; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckTdmConfig Description: This function will check the validity of the TDM config parameter of an Open TDM config structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTdmConfig TDM config of the channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckTdmConfig UINT32 Oct6100ApiCheckTdmConfig( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig ) { UINT32 ulResult; /*==============================================================================*/ /* Check the TDM configuration parameters.*/ /* Check the validity of the timeslot and Stream only if it is defined.*/ if ( f_pTdmConfig->ulRinTimeslot != cOCT6100_UNASSIGNED || f_pTdmConfig->ulRinStream != cOCT6100_UNASSIGNED ) { if ( f_pTdmConfig->ulRinNumTssts != 1 && f_pTdmConfig->ulRinNumTssts != 2 ) return cOCT6100_ERR_CHANNEL_RIN_NUM_TSSTS; /* Check the RIN TDM streams, timeslots component for errors.*/ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pTdmConfig->ulRinNumTssts, f_pTdmConfig->ulRinTimeslot, f_pTdmConfig->ulRinStream, cOCT6100_INPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_RIN_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_RIN_STREAM; } else { return ulResult; } } } /* Check the validity of the timeslot and Stream only if it is defined.*/ if ( f_pTdmConfig->ulRoutTimeslot != cOCT6100_UNASSIGNED || f_pTdmConfig->ulRoutStream != cOCT6100_UNASSIGNED ) { if ( f_pTdmConfig->ulRoutNumTssts != 1 && f_pTdmConfig->ulRoutNumTssts != 2 ) return cOCT6100_ERR_CHANNEL_ROUT_NUM_TSSTS; /* Check the ROUT TDM streams, timeslots component for errors.*/ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pTdmConfig->ulRoutNumTssts, f_pTdmConfig->ulRoutTimeslot, f_pTdmConfig->ulRoutStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_ROUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_ROUT_STREAM; } else { return ulResult; } } } /* Check the validity of the timeslot and Stream only if it is defined.*/ if ( f_pTdmConfig->ulSinTimeslot != cOCT6100_UNASSIGNED || f_pTdmConfig->ulSinStream != cOCT6100_UNASSIGNED ) { if ( f_pTdmConfig->ulSinNumTssts != 1 && f_pTdmConfig->ulSinNumTssts != 2 ) return cOCT6100_ERR_CHANNEL_SIN_NUM_TSSTS; /* Check the SIN TDM streams, timeslots component for errors.*/ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pTdmConfig->ulSinNumTssts, f_pTdmConfig->ulSinTimeslot, f_pTdmConfig->ulSinStream, cOCT6100_INPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_SIN_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_SIN_STREAM; } else { return ulResult; } } } /* Check the validity of the timeslot and Stream only if it is defined.*/ if ( f_pTdmConfig->ulSoutTimeslot != cOCT6100_UNASSIGNED || f_pTdmConfig->ulSoutStream != cOCT6100_UNASSIGNED ) { if ( f_pTdmConfig->ulSoutNumTssts != 1 && f_pTdmConfig->ulSoutNumTssts != 2 ) return cOCT6100_ERR_CHANNEL_SOUT_NUM_TSSTS; /* Check the ROUT TDM streams, timeslots component for errors.*/ ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pTdmConfig->ulSoutNumTssts, f_pTdmConfig->ulSoutTimeslot, f_pTdmConfig->ulSoutStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_CHANNEL_SOUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_CHANNEL_SOUT_STREAM; } else { return ulResult; } } } /* Check the PCM law parameters.*/ if ( f_pTdmConfig->ulRinPcmLaw != cOCT6100_PCM_U_LAW && f_pTdmConfig->ulRinPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_CHANNEL_RIN_PCM_LAW; if ( f_pTdmConfig->ulSinPcmLaw != cOCT6100_PCM_U_LAW && f_pTdmConfig->ulSinPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_CHANNEL_SIN_PCM_LAW; if ( f_pTdmConfig->ulRoutPcmLaw != cOCT6100_PCM_U_LAW && f_pTdmConfig->ulRoutPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_CHANNEL_ROUT_PCM_LAW; if ( f_pTdmConfig->ulSoutPcmLaw != cOCT6100_PCM_U_LAW && f_pTdmConfig->ulSoutPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_CHANNEL_SOUT_PCM_LAW; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckVqeConfig Description: This function will check the validity of the VQE config parameter of an Open VQE config structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig VQE config of the channel. f_fEnableToneDisabler Whether the tone disabler is active or not. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckVqeConfig UINT32 Oct6100ApiCheckVqeConfig( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN BOOL f_fEnableToneDisabler ) { tPOCT6100_API_IMAGE_INFO pImageInfo; pImageInfo = &f_pApiInstance->pSharedInfo->ImageInfo; if ( f_pVqeConfig->fEnableNlp != TRUE && f_pVqeConfig->fEnableNlp != FALSE ) return cOCT6100_ERR_CHANNEL_ENABLE_NLP; if ( f_pVqeConfig->fEnableNlp == TRUE && pImageInfo->fNlpControl == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NLP_CONTROL; /* Check the comfort noise mode.*/ if ( f_pVqeConfig->ulComfortNoiseMode != cOCT6100_COMFORT_NOISE_OFF && pImageInfo->fComfortNoise == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_BKG_NOISE_FREEZE; if ( f_pVqeConfig->ulComfortNoiseMode != cOCT6100_COMFORT_NOISE_NORMAL && f_pVqeConfig->ulComfortNoiseMode != cOCT6100_COMFORT_NOISE_EXTENDED && f_pVqeConfig->ulComfortNoiseMode != cOCT6100_COMFORT_NOISE_FAST_LATCH && f_pVqeConfig->ulComfortNoiseMode != cOCT6100_COMFORT_NOISE_OFF ) return cOCT6100_ERR_CHANNEL_COMFORT_NOISE_MODE; /* Check the DC offset removal.*/ if ( f_pVqeConfig->fSinDcOffsetRemoval != TRUE && f_pVqeConfig->fSinDcOffsetRemoval != FALSE ) return cOCT6100_ERR_CHANNEL_SIN_DC_OFFSET_REM; if ( f_pVqeConfig->fSinDcOffsetRemoval == TRUE && pImageInfo->fSinDcOffsetRemoval == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIN_DC_OFFSET_REM; if ( f_pVqeConfig->fRinDcOffsetRemoval != TRUE && f_pVqeConfig->fRinDcOffsetRemoval != FALSE ) return cOCT6100_ERR_CHANNEL_RIN_DC_OFFSET_REM; if ( f_pVqeConfig->fRinDcOffsetRemoval == TRUE && pImageInfo->fRinDcOffsetRemoval == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_DC_OFFSET_REM; /* Check the Level control.*/ if ( f_pVqeConfig->fRinLevelControl != TRUE && f_pVqeConfig->fRinLevelControl != FALSE ) return cOCT6100_ERR_CHANNEL_RIN_LEVEL_CONTROL; if ( f_pVqeConfig->fSoutLevelControl != TRUE && f_pVqeConfig->fSoutLevelControl != FALSE ) return cOCT6100_ERR_CHANNEL_SOUT_LEVEL_CONTROL; if ( ( f_pVqeConfig->lRinLevelControlGainDb < -24 ) || ( f_pVqeConfig->lRinLevelControlGainDb > 24 ) ) return cOCT6100_ERR_CHANNEL_RIN_LEVEL_CONTROL_GAIN; if ( ( f_pVqeConfig->lSoutLevelControlGainDb < -24 ) || ( f_pVqeConfig->lSoutLevelControlGainDb > 24 ) ) return cOCT6100_ERR_CHANNEL_SOUT_LEVEL_CONTROL_GAIN; if ( ( f_pVqeConfig->fRinAutomaticLevelControl != TRUE ) && ( f_pVqeConfig->fRinAutomaticLevelControl != FALSE ) ) return cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_CONTROL; if ( ( f_pVqeConfig->fRinHighLevelCompensation != TRUE ) && ( f_pVqeConfig->fRinHighLevelCompensation != FALSE ) ) return cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP; if ( ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) && ( pImageInfo->fRinAutoLevelControl == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_AUTO_LC; if ( ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) && ( pImageInfo->fRinHighLevelCompensation == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_RIN_HIGH_LEVEL_COMP; if ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) { if ( f_pVqeConfig->fRinLevelControl == TRUE ) return cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_MANUAL; if ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) return cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_HIGH_LEVEL_COMP; if ( ( f_pVqeConfig->lRinAutomaticLevelControlTargetDb < -40 || f_pVqeConfig->lRinAutomaticLevelControlTargetDb > 0 ) ) return cOCT6100_ERR_CHANNEL_RIN_AUTO_LEVEL_CONTROL_TARGET; } if ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) { if ( f_pVqeConfig->fRinLevelControl == TRUE ) return cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP_MANUAL; if ( ( f_pVqeConfig->lRinHighLevelCompensationThresholdDb < -40 || f_pVqeConfig->lRinHighLevelCompensationThresholdDb > 0 ) ) return cOCT6100_ERR_CHANNEL_RIN_HIGH_LEVEL_COMP_THRESHOLD; } if ( f_pVqeConfig->fSoutAutomaticLevelControl != TRUE && f_pVqeConfig->fSoutAutomaticLevelControl != FALSE ) return cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_CONTROL; if ( ( f_pVqeConfig->fSoutAutomaticLevelControl == TRUE ) && ( pImageInfo->fSoutAutoLevelControl == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SOUT_AUTO_LC; if ( f_pVqeConfig->fSoutAutomaticLevelControl == TRUE ) { if ( f_pVqeConfig->fSoutLevelControl == TRUE ) return cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_MANUAL; if ( ( f_pVqeConfig->lSoutAutomaticLevelControlTargetDb < -40 || f_pVqeConfig->lSoutAutomaticLevelControlTargetDb > 0 ) ) return cOCT6100_ERR_CHANNEL_SOUT_AUTO_LEVEL_CONTROL_TARGET; } if ( f_pVqeConfig->fSoutAdaptiveNoiseReduction != TRUE && f_pVqeConfig->fSoutAdaptiveNoiseReduction != FALSE ) return cOCT6100_ERR_CHANNEL_SOUT_ADAPT_NOISE_REDUCTION; if ( f_pVqeConfig->fSoutAdaptiveNoiseReduction == TRUE && pImageInfo->fAdaptiveNoiseReduction == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR; if ( f_pVqeConfig->fSoutConferencingNoiseReduction != TRUE && f_pVqeConfig->fSoutConferencingNoiseReduction != FALSE ) return cOCT6100_ERR_CHANNEL_SOUT_CONFERENCE_NOISE_REDUCTION; if ( f_pVqeConfig->fSoutConferencingNoiseReduction == TRUE && pImageInfo->fConferencingNoiseReduction == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_CNR; /* Validate Sout noise bleaching parameter. */ if ( f_pVqeConfig->fSoutNoiseBleaching != TRUE && f_pVqeConfig->fSoutNoiseBleaching != FALSE ) return cOCT6100_ERR_CHANNEL_SOUT_NOISE_BLEACHING; /* Check if firmware supports Sout noise bleaching. */ if ( f_pVqeConfig->fSoutNoiseBleaching == TRUE && pImageInfo->fSoutNoiseBleaching == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NOISE_BLEACHING; /* If Sout noise bleaching is requested, no ANR or CNR shall be activated. */ if ( f_pVqeConfig->fSoutNoiseBleaching == TRUE ) { /* No xNR! */ if ( ( f_pVqeConfig->fSoutConferencingNoiseReduction == TRUE ) || ( f_pVqeConfig->fSoutAdaptiveNoiseReduction == TRUE ) ) return cOCT6100_ERR_CHANNEL_SOUT_NOISE_BLEACHING_NR; } /* Cannot activate both ANR and CNR when noise bleaching is present */ if ( pImageInfo->fSoutNoiseBleaching == TRUE ) { if ( f_pVqeConfig->fSoutAdaptiveNoiseReduction == TRUE && f_pVqeConfig->fSoutConferencingNoiseReduction == TRUE ) return cOCT6100_ERR_CHANNEL_ANR_CNR_SIMULTANEOUSLY; } /* Validate the DTMF tone removal parameter.*/ if ( f_pVqeConfig->fDtmfToneRemoval != TRUE && f_pVqeConfig->fDtmfToneRemoval != FALSE ) return cOCT6100_ERR_CHANNEL_TONE_REMOVAL; if ( f_pVqeConfig->fDtmfToneRemoval == TRUE && pImageInfo->fToneRemoval == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TONE_REMOVAL; /* Check the Tail displacement enable.*/ if ( f_pVqeConfig->fEnableTailDisplacement != TRUE && f_pVqeConfig->fEnableTailDisplacement != FALSE ) return cOCT6100_ERR_CHANNEL_ENABLE_TAIL_DISPLACEMENT; if ( f_pVqeConfig->fEnableTailDisplacement == TRUE && pImageInfo->fTailDisplacement == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TAIL_DISPLACEMENT; /* Check the Tail displacement value.*/ if ( f_pVqeConfig->fEnableTailDisplacement == TRUE ) { if ( f_pVqeConfig->ulTailDisplacement != cOCT6100_AUTO_SELECT_TAIL ) { /* Check if this feature is supported by the image. */ if ( pImageInfo->fPerChannelTailDisplacement == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_PER_CHAN_TAIL; /* Check that this value is not greater then what the image supports. */ if ( f_pVqeConfig->ulTailDisplacement > pImageInfo->usMaxTailDisplacement ) return cOCT6100_ERR_CHANNEL_TAIL_DISPLACEMENT_INVALID; } } /* Check the tail length value. */ if ( f_pVqeConfig->ulTailLength != cOCT6100_AUTO_SELECT_TAIL ) { /* Check if this feature is supported by the image. */ if ( ( pImageInfo->fPerChannelTailLength == FALSE ) && ( (UINT16)( f_pVqeConfig->ulTailLength & 0xFFFF ) != pImageInfo->usMaxTailLength ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TAIL_LENGTH; if ( ( f_pVqeConfig->ulTailLength < 32 ) || ( f_pVqeConfig->ulTailLength > 128 ) || ( ( f_pVqeConfig->ulTailLength % 4 ) != 0x0 ) ) return cOCT6100_ERR_CHANNEL_TAIL_LENGTH; /* Check if the requested tail length is supported by the chip. */ if ( f_pVqeConfig->ulTailLength > pImageInfo->usMaxTailLength ) return cOCT6100_ERR_CHANNEL_TAIL_LENGTH_INVALID; } /* Validate the acoustic echo cancellation parameter.*/ if ( f_pVqeConfig->fAcousticEcho != TRUE && f_pVqeConfig->fAcousticEcho != FALSE ) return cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO; if ( f_pVqeConfig->fAcousticEcho == TRUE && pImageInfo->fAcousticEcho == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ACOUSTIC_ECHO; if ( f_pVqeConfig->fAcousticEcho == TRUE ) { /* Check if acoustic echo tail length configuration is supported in the image. */ if ( ( f_pVqeConfig->ulAecTailLength != 128 ) && ( pImageInfo->fAecTailLength == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ACOUSTIC_ECHO_TAIL_LENGTH; /* Check the requested acoustic echo tail length. */ if ( ( f_pVqeConfig->ulAecTailLength != 128 ) && ( f_pVqeConfig->ulAecTailLength != 256 ) && ( f_pVqeConfig->ulAecTailLength != 512 ) && ( f_pVqeConfig->ulAecTailLength != 1024 ) ) return cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO_TAIL_LENGTH; if ( f_pVqeConfig->fEnableTailDisplacement == TRUE ) { UINT32 ulTailSum; /* Start with requested tail displacement. */ if ( f_pVqeConfig->ulTailDisplacement == cOCT6100_AUTO_SELECT_TAIL ) { ulTailSum = f_pApiInstance->pSharedInfo->ChipConfig.usTailDisplacement; } else { ulTailSum = f_pVqeConfig->ulTailDisplacement; } /* Add requested tail length. */ if ( f_pVqeConfig->ulTailLength == cOCT6100_AUTO_SELECT_TAIL ) { ulTailSum += f_pApiInstance->pSharedInfo->ImageInfo.usMaxTailLength; } else { ulTailSum += f_pVqeConfig->ulTailLength; } /* The tail sum must be smaller then the requested AEC tail length. */ if ( ulTailSum > f_pVqeConfig->ulAecTailLength ) return cOCT6100_ERR_CHANNEL_ACOUSTIC_ECHO_TAIL_SUM; } } /* Validate the Default ERL parameter.*/ if ( f_pVqeConfig->lDefaultErlDb != -6 && pImageInfo->fDefaultErl == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DEFAULT_ERL; if ( ( f_pVqeConfig->lDefaultErlDb != 0 ) && ( f_pVqeConfig->lDefaultErlDb != -3 ) && ( f_pVqeConfig->lDefaultErlDb != -6 ) && ( f_pVqeConfig->lDefaultErlDb != -9 ) && ( f_pVqeConfig->lDefaultErlDb != -12 ) ) return cOCT6100_ERR_CHANNEL_DEFAULT_ERL; /* Validate the Default AEC ERL parameter.*/ if ( f_pVqeConfig->lAecDefaultErlDb != 0 && pImageInfo->fAecDefaultErl == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_AEC_DEFAULT_ERL; if ( f_pVqeConfig->lAecDefaultErlDb != 0 && f_pVqeConfig->lAecDefaultErlDb != -3 && f_pVqeConfig->lAecDefaultErlDb != -6 ) return cOCT6100_ERR_CHANNEL_AEC_DEFAULT_ERL; /* Validate the non-linearity A parameter.*/ if ( f_pVqeConfig->ulNonLinearityBehaviorA != 1 && pImageInfo->fNonLinearityBehaviorA == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DOUBLE_TALK; if ( f_pVqeConfig->ulNonLinearityBehaviorA >= 14 ) return cOCT6100_ERR_CHANNEL_DOUBLE_TALK; /* Validate the non-linearity B parameter.*/ if ( f_pVqeConfig->ulNonLinearityBehaviorB != 0 && pImageInfo->fNonLinearityBehaviorB == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NON_LINEARITY_B; if ( f_pVqeConfig->ulNonLinearityBehaviorB >= 9 ) return cOCT6100_ERR_CHANNEL_NON_LINEARITY_B; /* Check if configuring the double talk behavior is supported in the firmware. */ if ( f_pVqeConfig->ulDoubleTalkBehavior != cOCT6100_DOUBLE_TALK_BEH_NORMAL && pImageInfo->fDoubleTalkBehavior == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_DOUBLE_TALK_BEHAVIOR_MODE; /* Validate the double talk behavior mode parameter. */ if ( f_pVqeConfig->ulDoubleTalkBehavior != cOCT6100_DOUBLE_TALK_BEH_NORMAL && f_pVqeConfig->ulDoubleTalkBehavior != cOCT6100_DOUBLE_TALK_BEH_LESS_AGGRESSIVE ) return cOCT6100_ERR_CHANNEL_DOUBLE_TALK_MODE; /* Validate the Sout automatic listener enhancement ratio. */ if ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != 0 && pImageInfo->fListenerEnhancement == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ALE; if ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb > 30 ) return cOCT6100_ERR_CHANNEL_ALE_RATIO; /* Validate the Sout natural listener enhancement ratio. */ if ( f_pVqeConfig->fSoutNaturalListenerEnhancement != TRUE && f_pVqeConfig->fSoutNaturalListenerEnhancement != FALSE ) return cOCT6100_ERR_CHANNEL_NLE_FLAG; if ( f_pVqeConfig->fSoutNaturalListenerEnhancement == TRUE && pImageInfo->fListenerEnhancement == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_NLE; if ( f_pVqeConfig->fSoutNaturalListenerEnhancement == TRUE ) { if ( f_pVqeConfig->ulSoutNaturalListenerEnhancementGainDb > 30 ) return cOCT6100_ERR_CHANNEL_NLE_RATIO; } /* Both ALE and NLE cannot be activated simultaneously. */ if ( ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != 0 ) && ( f_pVqeConfig->fSoutNaturalListenerEnhancement == TRUE ) ) return cOCT6100_ERR_CHANNEL_ALE_NLE_SIMULTANEOUSLY; /* Validate Rout noise reduction. */ if ( f_pVqeConfig->fRoutNoiseReduction != TRUE && f_pVqeConfig->fRoutNoiseReduction != FALSE ) return cOCT6100_ERR_CHANNEL_ROUT_NOISE_REDUCTION; /* Check if Rout noise reduction is supported. */ if ( f_pVqeConfig->fRoutNoiseReduction == TRUE && pImageInfo->fRoutNoiseReduction == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ROUT_NR; /*Check if noise reduction level gain is supported*/ if ( ( pImageInfo->fRoutNoiseReductionLevel == FALSE ) && ( f_pVqeConfig->lRoutNoiseReductionLevelGainDb != -18 ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ROUT_NOISE_REDUCTION_GAIN; if ( ( f_pVqeConfig->lRoutNoiseReductionLevelGainDb != 0 ) && ( f_pVqeConfig->lRoutNoiseReductionLevelGainDb != -6 ) && ( f_pVqeConfig->lRoutNoiseReductionLevelGainDb != -12 ) && ( f_pVqeConfig->lRoutNoiseReductionLevelGainDb != -18 ) ) return cOCT6100_ERR_CHANNEL_ROUT_NOISE_REDUCTION_GAIN; /* Check if ANR SNRE is supported. */ if ( ( f_pVqeConfig->lAnrSnrEnhancementDb != -18 ) && ( pImageInfo->fAnrSnrEnhancement == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR_SNR_ENHANCEMENT; /* Validate Sout ANR SNR enhancement. */ if ( ( f_pVqeConfig->lAnrSnrEnhancementDb != -9 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -12 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -15 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -18 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -21 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -24 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -27 ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != -30 ) ) return cOCT6100_ERR_CHANNEL_ANR_SNR_ENHANCEMENT; /* Validate ANR voice-noise segregation. */ if ( f_pVqeConfig->ulAnrVoiceNoiseSegregation > 15 ) return cOCT6100_ERR_CHANNEL_ANR_SEGREGATION; /* Check if ANR VN segregation is supported. */ if ( ( f_pVqeConfig->ulAnrVoiceNoiseSegregation != 6 ) && ( pImageInfo->fAnrVoiceNoiseSegregation == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ANR_SEGREGATION; /* Check if the loaded image supports tone disabler VQE activation delay. */ if ( ( f_pVqeConfig->ulToneDisablerVqeActivationDelay != 300 ) && ( pImageInfo->fToneDisablerVqeActivationDelay == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_TONE_DISABLER_ACTIVATION_DELAY; /* Check if the specified tone disabler VQE activation delay is correct. */ if ( ( f_pVqeConfig->ulToneDisablerVqeActivationDelay < 300 ) || ( ( ( f_pVqeConfig->ulToneDisablerVqeActivationDelay - 300 ) % 512 ) != 0 ) ) return cOCT6100_ERR_CHANNEL_TONE_DISABLER_ACTIVATION_DELAY; /* Check the enable music protection flag. */ if ( ( f_pVqeConfig->fEnableMusicProtection != TRUE ) && ( f_pVqeConfig->fEnableMusicProtection != FALSE ) ) return cOCT6100_ERR_CHANNEL_ENABLE_MUSIC_PROTECTION; /* The music protection module can only be activated if the image supports it. */ if ( ( f_pVqeConfig->fEnableMusicProtection == TRUE ) && ( pImageInfo->fMusicProtection == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_MUSIC_PROTECTION; /* Check the enable idle code detection flag. */ if ( ( f_pVqeConfig->fIdleCodeDetection != TRUE ) && ( f_pVqeConfig->fIdleCodeDetection != FALSE ) ) return cOCT6100_ERR_CHANNEL_IDLE_CODE_DETECTION; /* The idle code detection module can only be activated if the image supports it. */ if ( ( f_pVqeConfig->fIdleCodeDetection == TRUE ) && ( pImageInfo->fIdleCodeDetection == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_IDLE_CODE_DETECTION; /* The idle code detection module can be disabled only if idle code detection configuration */ /* is supported in the image. */ if ( pImageInfo->fIdleCodeDetection == TRUE ) { if ( ( f_pVqeConfig->fIdleCodeDetection == FALSE ) && ( pImageInfo->fIdleCodeDetectionConfiguration == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_IDLE_CODE_DETECTION_CONFIG; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckCodecConfig Description: This function will check the validity of the Codec config parameter of an Open Codec config structure. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pCodecConfig Codec config of the channel. f_ulDecoderNumTssts Number of TSST for the decoder. f_pusPhasingTsstIndex Pointer to the Phasing TSST index within the API's phasing TSST list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckCodecConfig UINT32 Oct6100ApiCheckCodecConfig( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_CODEC f_pCodecConfig, IN UINT32 f_ulDecoderNumTssts, OUT PUINT16 f_pusPhasingTsstIndex ) { /* Verify the ADPCM nibble value.*/ if ( f_pCodecConfig->ulAdpcmNibblePosition != cOCT6100_ADPCM_IN_LOW_BITS && f_pCodecConfig->ulAdpcmNibblePosition != cOCT6100_ADPCM_IN_HIGH_BITS ) return cOCT6100_ERR_CHANNEL_ADPCM_NIBBLE; /* Verify the Encoder port.*/ if ( f_pCodecConfig->ulEncoderPort != cOCT6100_CHANNEL_PORT_ROUT && f_pCodecConfig->ulEncoderPort != cOCT6100_CHANNEL_PORT_SOUT && f_pCodecConfig->ulEncoderPort != cOCT6100_NO_ENCODING ) return cOCT6100_ERR_CHANNEL_ENCODER_PORT; /* Verify the Decoder port.*/ if ( f_pCodecConfig->ulDecoderPort != cOCT6100_CHANNEL_PORT_RIN && f_pCodecConfig->ulDecoderPort != cOCT6100_CHANNEL_PORT_SIN && f_pCodecConfig->ulDecoderPort != cOCT6100_NO_DECODING ) return cOCT6100_ERR_CHANNEL_DECODER_PORT; /* The codec cannot be on the same stream.*/ if ( f_pCodecConfig->ulEncoderPort == cOCT6100_CHANNEL_PORT_ROUT && f_pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) return cOCT6100_ERR_CHANNEL_INVALID_CODEC_POSITION; if ( f_pCodecConfig->ulEncoderPort == cOCT6100_CHANNEL_PORT_SOUT && f_pCodecConfig->ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN ) return cOCT6100_ERR_CHANNEL_INVALID_CODEC_POSITION; /* Verify if the requested functions are supported by the chip.*/ if ( f_pApiInstance->pSharedInfo->ImageInfo.fAdpcm == FALSE && f_pCodecConfig->ulEncoderPort != cOCT6100_NO_ENCODING ) { if ( f_pCodecConfig->ulEncodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_ENCODING; } if ( f_pApiInstance->pSharedInfo->ImageInfo.fAdpcm == FALSE && f_pCodecConfig->ulDecoderPort != cOCT6100_NO_DECODING ) { if ( f_pCodecConfig->ulDecodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_DECODING; } /* Check if encoder port has been specified when a rate has been set. */ if ( f_pCodecConfig->ulEncoderPort == cOCT6100_NO_ENCODING && f_pCodecConfig->ulEncodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_CHANNEL_ENCODER_PORT; /* Check if decoder port has been specified when a rate has been set. */ if ( f_pCodecConfig->ulDecoderPort == cOCT6100_NO_DECODING && f_pCodecConfig->ulDecodingRate != cOCT6100_G711_64KBPS ) return cOCT6100_ERR_CHANNEL_DECODER_PORT; /* Check Encoder related parameter if one is used.*/ if ( f_pCodecConfig->ulEncoderPort != cOCT6100_NO_ENCODING ) { /* Check the Encoder compression rate.*/ if ( ( f_pCodecConfig->ulEncodingRate != cOCT6100_G711_64KBPS ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G726_40KBPS ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G726_32KBPS ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G726_24KBPS ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G726_16KBPS ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_40KBPS_4_1 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_40KBPS_3_2 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_40KBPS_2_3 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_32KBPS_4_0 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_32KBPS_3_1 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_32KBPS_2_2 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_24KBPS_3_0 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_24KBPS_2_1 ) && ( f_pCodecConfig->ulEncodingRate != cOCT6100_G727_16KBPS_2_0 ) ) return cOCT6100_ERR_CHANNEL_ENCODING_RATE; /* Verify phasing information.*/ if ( f_pCodecConfig->ulPhasingType != cOCT6100_SINGLE_PHASING && f_pCodecConfig->ulPhasingType != cOCT6100_DUAL_PHASING && f_pCodecConfig->ulPhasingType != cOCT6100_NO_PHASING ) return cOCT6100_ERR_CHANNEL_PHASING_TYPE; /* Verify the silence suppression parameters.*/ if ( f_pCodecConfig->fEnableSilenceSuppression != TRUE && f_pCodecConfig->fEnableSilenceSuppression != FALSE ) return cOCT6100_ERR_CHANNEL_SIL_SUP_ENABLE; if ( f_pCodecConfig->fEnableSilenceSuppression == TRUE && f_pApiInstance->pSharedInfo->ImageInfo.fSilenceSuppression == FALSE ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIL_SUP; if ( f_pCodecConfig->fEnableSilenceSuppression == TRUE && f_pCodecConfig->ulPhasingType == cOCT6100_NO_PHASING ) return cOCT6100_ERR_CHANNEL_PHASE_TYPE_REQUIRED; if ( f_pCodecConfig->fEnableSilenceSuppression == TRUE && f_pCodecConfig->ulPhasingTsstHndl == cOCT6100_INVALID_HANDLE ) return cOCT6100_ERR_CHANNEL_PHASING_TSST_REQUIRED; if ( f_pCodecConfig->ulPhasingTsstHndl == cOCT6100_INVALID_HANDLE && f_pCodecConfig->ulPhasingType != cOCT6100_NO_PHASING ) return cOCT6100_ERR_CHANNEL_PHASING_TSST_REQUIRED; /* Silence suppression can only be performed if the encoder is using the SOUT port.*/ if ( f_pCodecConfig->fEnableSilenceSuppression == TRUE && f_pCodecConfig->ulEncoderPort != cOCT6100_CHANNEL_PORT_SOUT ) return cOCT6100_ERR_CHANNEL_SIL_SUP_INVALID_ENCODER_PORT; /* Check phasing TSST info if phasing is required.*/ if ( f_pCodecConfig->ulPhasingTsstHndl != cOCT6100_INVALID_HANDLE ) { tPOCT6100_API_PHASING_TSST pPhasingEntry; UINT32 ulEntryOpenCnt; /* Check the provided handle. */ if ( (f_pCodecConfig->ulPhasingTsstHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_PHASING_TSST ) return cOCT6100_ERR_CHANNEL_INVALID_PHASING_HANDLE; *f_pusPhasingTsstIndex = (UINT16)( f_pCodecConfig->ulPhasingTsstHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusPhasingTsstIndex >= f_pApiInstance->pSharedInfo->ChipConfig.usMaxPhasingTssts ) return cOCT6100_ERR_CHANNEL_INVALID_PHASING_HANDLE; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingEntry, *f_pusPhasingTsstIndex ); /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pCodecConfig->ulPhasingTsstHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Verify if the state of the phasing TSST.*/ if ( pPhasingEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_PHASING_TSST_NOT_OPEN; if ( ulEntryOpenCnt != pPhasingEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_PHASING_HANDLE; /* Check the specified phase value against the phasing length of the phasing TSST.*/ if ( ( f_pCodecConfig->ulPhase == 0 ) || ( f_pCodecConfig->ulPhase >= pPhasingEntry->usPhasingLength ) ) return cOCT6100_ERR_CHANNEL_PHASING_INVALID_PHASE; } else { *f_pusPhasingTsstIndex = cOCT6100_INVALID_INDEX; } } else { *f_pusPhasingTsstIndex = cOCT6100_INVALID_INDEX; } /* Check Decoder related parameter if one is used.*/ if ( f_pCodecConfig->ulDecoderPort != cOCT6100_NO_DECODING ) { /* Check the Decoding rate.*/ if ( f_pCodecConfig->ulDecodingRate != cOCT6100_G711_64KBPS && f_pCodecConfig->ulDecodingRate != cOCT6100_G726_40KBPS && f_pCodecConfig->ulDecodingRate != cOCT6100_G726_32KBPS && f_pCodecConfig->ulDecodingRate != cOCT6100_G726_24KBPS && f_pCodecConfig->ulDecodingRate != cOCT6100_G726_16KBPS && f_pCodecConfig->ulDecodingRate != cOCT6100_G726_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G711_G726_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G727_2C_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G727_3C_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G727_4C_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G711_G727_2C_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G711_G727_3C_ENCODED && f_pCodecConfig->ulDecodingRate != cOCT6100_G711_G727_4C_ENCODED ) return cOCT6100_ERR_CHANNEL_DECODING_RATE; /* Make sure that two timeslot are allocated if PCM-ECHO encoded is selected.*/ if ( (f_pCodecConfig->ulDecodingRate == cOCT6100_G711_G726_ENCODED || f_pCodecConfig->ulDecodingRate == cOCT6100_G711_G727_2C_ENCODED || f_pCodecConfig->ulDecodingRate == cOCT6100_G711_G727_3C_ENCODED || f_pCodecConfig->ulDecodingRate == cOCT6100_G711_G727_4C_ENCODED ) && f_ulDecoderNumTssts != 2 ) return cOCT6100_ERR_CHANNEL_MISSING_TSST; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteInputTsstControlMemory Description: This function configure a TSST control memory entry in internal memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usTsstIndex TSST index within the TSST control memory. f_usTsiMemIndex TSI index within the TSI chariot memory. f_ulTsstInputLaw PCM law of the input TSST. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteInputTsstControlMemory UINT32 Oct6100ApiWriteInputTsstControlMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulTsstInputLaw ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (f_usTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_TSST_CONTROL_MEM_INPUT_TSST; WriteParams.usWriteData |= f_usTsiMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK; /* Set the PCM law.*/ WriteParams.usWriteData |= f_ulTsstInputLaw << cOCT6100_TSST_CONTROL_MEM_PCM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteOutputTsstControlMemory Description: This function configure a TSST control memory entry in internal memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteOutputTsstControlMemory UINT32 Oct6100ApiWriteOutputTsstControlMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsstIndex, IN UINT32 f_ulAdpcmNibblePosition, IN UINT32 f_ulNumTssts, IN UINT16 f_usTsiMemIndex ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( (f_usTsstIndex & cOCT6100_TSST_INDEX_MASK) * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_TSST_CONTROL_MEM_OUTPUT_TSST; WriteParams.usWriteData |= f_ulAdpcmNibblePosition << cOCT6100_TSST_CONTROL_MEM_NIBBLE_POS_OFFSET; WriteParams.usWriteData |= (f_ulNumTssts - 1) << cOCT6100_TSST_CONTROL_MEM_TSST_NUM_OFFSET; WriteParams.usWriteData |= f_usTsiMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteEncoderMemory Description: This function configure a Encoded memory entry in internal memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulEncoderIndex Index of the encoder block within the ADPCM context memory. f_ulCompType Compression rate of the encoder. f_usTsiMemIndex TSI index within the TSI chariot memory used by the encoder. f_ulEnableSilenceSuppression Silence suppression enable flag. f_ulAdpcmNibblePosition ADPCM nibble position. f_usPhasingTsstIndex Phasing TSST index within the API's Phassing TSST list. f_ulPhasingType Type of the Phasing TSST. f_ulPhase Phase used with this encoder. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteEncoderMemory UINT32 Oct6100ApiWriteEncoderMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT32 f_ulEncoderIndex, IN UINT32 f_ulCompType, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulEnableSilenceSuppression, IN UINT32 f_ulAdpcmNibblePosition, IN UINT16 f_usPhasingTsstIndex, IN UINT32 f_ulPhasingType, IN UINT32 f_ulPhase ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*==============================================================================*/ /* Conversion Control Base */ WriteParams.ulWriteAddress = cOCT6100_CONVERSION_CONTROL_MEM_BASE + ( f_ulEncoderIndex * cOCT6100_CONVERSION_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_ENCODER; WriteParams.usWriteData |= f_ulCompType << cOCT6100_CONVERSION_CONTROL_MEM_COMP_OFFSET; WriteParams.usWriteData |= f_usTsiMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 2 */ WriteParams.ulWriteAddress += 2; /* Set the phasing TSST number.*/ if ( f_usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) WriteParams.usWriteData = (UINT16)( f_usPhasingTsstIndex << cOCT6100_CONVERSION_CONTROL_MEM_PHASE_OFFSET ); else WriteParams.usWriteData = 0; /* Set the phasing type and the phase value if required.*/ switch( f_ulPhasingType ) { case cOCT6100_NO_PHASING: WriteParams.usWriteData |= 0x1 << 10; break; case cOCT6100_SINGLE_PHASING: WriteParams.usWriteData |= f_ulPhase; break; case cOCT6100_DUAL_PHASING: WriteParams.usWriteData |= 0x1 << 11; WriteParams.usWriteData |= f_ulPhase; break; default: /* No problem. */ break; } /* Set the silence suppression flag.*/ WriteParams.usWriteData |= f_ulEnableSilenceSuppression << cOCT6100_CONVERSION_CONTROL_MEM_SIL_SUP_OFFSET; /* Set the nibble position.*/ WriteParams.usWriteData |= f_ulAdpcmNibblePosition << cOCT6100_CONVERSION_CONTROL_MEM_NIBBLE_POS_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 4 */ WriteParams.ulWriteAddress += 2; /* Set the reset mode */ WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_RST_ON_NEXT_FR; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 6 */ WriteParams.ulWriteAddress += 2; /* Set the reset mode */ WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_ACTIVATE_ENTRY; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteDecoderMemory Description: This function configure a Decoder memory entry in internal memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usDecoderIndex Index of the decoder block within the ADPCM context memory. f_ulCompType Decompression rate of the decoder. f_usTsiMemIndex TSI index within the TSI chariot memory. f_ulPcmLaw PCM law of the decoded samples. f_ulAdpcmNibblePosition ADPCM nibble position. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteDecoderMemory UINT32 Oct6100ApiWriteDecoderMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usDecoderIndex, IN UINT32 f_ulCompType, IN UINT16 f_usTsiMemIndex, IN UINT32 f_ulPcmLaw, IN UINT32 f_ulAdpcmNibblePosition ) { tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; /*==============================================================================*/ /* Conversion Control Base */ WriteParams.ulWriteAddress = cOCT6100_CONVERSION_CONTROL_MEM_BASE + ( f_usDecoderIndex * cOCT6100_CONVERSION_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_DECODER; WriteParams.usWriteData |= f_ulCompType << cOCT6100_CONVERSION_CONTROL_MEM_COMP_OFFSET; WriteParams.usWriteData |= f_usTsiMemIndex & cOCT6100_TSST_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 2 */ WriteParams.ulWriteAddress += 2; /* Set the nibble position.*/ WriteParams.usWriteData = (UINT16)( f_ulAdpcmNibblePosition << cOCT6100_CONVERSION_CONTROL_MEM_NIBBLE_POS_OFFSET ); /* Set the law.*/ WriteParams.usWriteData |= f_ulPcmLaw << cOCT6100_CONVERSION_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 4 */ WriteParams.ulWriteAddress += 2; /* Set the reset mode */ WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_RST_ON_NEXT_FR; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /* Conversion Control Base + 6 */ WriteParams.ulWriteAddress += 2; /* Set the reset mode */ WriteParams.usWriteData = cOCT6100_CONVERSION_CONTROL_MEM_ACTIVATE_ENTRY; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiClearConversionMemory Description: This function clears a conversion memory entry in internal memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usConversionMemIndex Index of the block within the conversion memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiClearConversionMemory UINT32 Oct6100ApiClearConversionMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usConversionMemIndex ) { tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_READ_PARAMS ReadParams; UINT32 ulResult; UINT32 ulBaseAddress; UINT16 usReadData; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; WriteParams.usWriteData = 0; ReadParams.pProcessContext = f_pApiInstance->pProcessContext; ReadParams.ulUserChipId = f_pApiInstance->pSharedInfo->ChipConfig.ulUserChipId; ReadParams.pusReadData = &usReadData; /*==============================================================================*/ /* Clear the entry */ ulBaseAddress = cOCT6100_CONVERSION_CONTROL_MEM_BASE + ( f_usConversionMemIndex * cOCT6100_CONVERSION_CONTROL_MEM_ENTRY_SIZE ); /* The "activate" bit at offset +6 must be cleared first. */ WriteParams.ulWriteAddress = ulBaseAddress + 6; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Read at 0x200 to make sure there is no corruption on channel 0. */ ReadParams.ulReadAddress = 0x200; mOCT6100_DRIVER_READ_API( ReadParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Then clear the rest of the structure. */ WriteParams.ulWriteAddress = ulBaseAddress + 4; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ulBaseAddress + 2; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress = ulBaseAddress; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteVqeMemory Description: This function configure an echo memory entry in internal memory and external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig Pointer to a VQE config structure. f_pChannelOpen Pointer to a channel configuration structure. f_usChanIndex Index of the echo channel in the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_fClearPlayoutPointers Flag indicating if the playout pointer should be cleared. f_fModifyOnly Flag indicating if the configuration should be modified only. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteVqeMemory UINT32 Oct6100ApiWriteVqeMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ) { UINT32 ulResult; /* Write the NLP software configuration structure. */ ulResult = Oct6100ApiWriteVqeNlpMemory( f_pApiInstance, f_pVqeConfig, f_pChannelOpen, f_usChanIndex, f_usEchoMemIndex, f_fClearPlayoutPointers, f_fModifyOnly ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write the AF software configuration structure. */ ulResult = Oct6100ApiWriteVqeAfMemory( f_pApiInstance, f_pVqeConfig, f_pChannelOpen, f_usChanIndex, f_usEchoMemIndex, f_fClearPlayoutPointers, f_fModifyOnly ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif UINT32 oct6100_retrieve_nlp_conf_dword(tPOCT6100_INSTANCE_API f_pApiInst, tPOCT6100_API_CHANNEL f_pChanEntry, UINT32 f_ulAddress, UINT32 *f_pulConfigDword) { tOCT6100_READ_PARAMS _ReadParams; UINT16 _usReadData; UINT32 ulResult = cOCT6100_ERR_FATAL_8E; (*f_pulConfigDword) = cOCT6100_INVALID_VALUE; _ReadParams.pProcessContext = f_pApiInst->pProcessContext; mOCT6100_ASSIGN_USER_READ_WRITE_OBJ(f_pApiInst, _ReadParams); _ReadParams.ulUserChipId = f_pApiInst->pSharedInfo->ChipConfig.ulUserChipId; _ReadParams.pusReadData = &_usReadData; /* Read the first 16 bits.*/ _ReadParams.ulReadAddress = f_ulAddress; mOCT6100_DRIVER_READ_API(_ReadParams, ulResult); if (ulResult == cOCT6100_ERR_OK) { /* Save data.*/ (*f_pulConfigDword) = _usReadData << 16; /* Read the last 16 bits .*/ _ReadParams.ulReadAddress += 2; mOCT6100_DRIVER_READ_API(_ReadParams, ulResult); if (ulResult == cOCT6100_ERR_OK) { /* Save data.*/ (*f_pulConfigDword) |= _usReadData; ulResult = cOCT6100_ERR_OK; } } return ulResult; } UINT32 oct6100_save_nlp_conf_dword(tPOCT6100_INSTANCE_API f_pApiInst, tPOCT6100_API_CHANNEL f_pChanEntry, UINT32 f_ulAddress, UINT32 f_ulConfigDword) { UINT32 ulResult; /* Write the config DWORD. */ tOCT6100_WRITE_PARAMS _WriteParams; _WriteParams.pProcessContext = f_pApiInst->pProcessContext; mOCT6100_ASSIGN_USER_READ_WRITE_OBJ(f_pApiInst, _WriteParams) _WriteParams.ulUserChipId = f_pApiInst->pSharedInfo->ChipConfig.ulUserChipId; /* Write the first 16 bits. */ _WriteParams.ulWriteAddress = f_ulAddress; _WriteParams.usWriteData = (UINT16)((f_ulConfigDword >> 16) & 0xFFFF); mOCT6100_DRIVER_WRITE_API(_WriteParams, ulResult); if (ulResult == cOCT6100_ERR_OK) { /* Write the last word. */ _WriteParams.ulWriteAddress = f_ulAddress + 2; _WriteParams.usWriteData = (UINT16)(f_ulConfigDword & 0xFFFF); mOCT6100_DRIVER_WRITE_API(_WriteParams, ulResult); } return ulResult; } /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteVqeNlpMemory Description: This function configures the NLP related VQE features of an echo channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig Pointer to a VQE config structure. f_pChannelOpen Pointer to a channel configuration structure. f_usChanIndex Index of the echo channel in the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_fClearPlayoutPointers Flag indicating if the playout pointer should be cleared. f_fModifyOnly Flag indicating if the configuration should be modified only. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteVqeNlpMemory UINT32 Oct6100ApiWriteVqeNlpMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; tOCT6100_BUFFER_PLAYOUT_STOP BufferPlayoutStop; UINT32 ulResult; UINT32 ulTempData; UINT32 ulNlpConfigBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; UINT16 usTempData; BOOL fEchoOperationModeChanged; pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ); /*==============================================================================*/ /* Configure the CPU NLP configuration of the channel feature by feature.*/ ulNlpConfigBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Set initial value to zero.*/ ulTempData = 0; /* Configure Adaptive Noise Reduction.*/ if (pSharedInfo->ImageInfo.fAdaptiveNoiseReduction == TRUE) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->fSoutAdaptiveNoiseReduction != pChanEntry->VqeConfig.fSoutAdaptiveNoiseReduction ) || ( f_pVqeConfig->fSoutNoiseBleaching != pChanEntry->VqeConfig.fSoutNoiseBleaching ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AdaptiveNoiseReductionOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AdaptiveNoiseReductionOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AdaptiveNoiseReductionOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set adaptive noise reduction on the SOUT port.*/ ulTempData |= ( ( (UINT32)f_pVqeConfig->fSoutAdaptiveNoiseReduction ) << ulFeatureBitOffset ); /* If SOUT noise bleaching is requested, ANR must be activated. */ ulTempData |= ( ( (UINT32)f_pVqeConfig->fSoutNoiseBleaching ) << ulFeatureBitOffset ); /* First read the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure Rout Noise Reduction. */ if (pSharedInfo->ImageInfo.fRoutNoiseReduction == TRUE) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fRoutNoiseReduction != pChanEntry->VqeConfig.fRoutNoiseReduction ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinAnrOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinAnrOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinAnrOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set noise reduction on the Rout port. */ ulTempData |= ( ( (UINT32)f_pVqeConfig->fRoutNoiseReduction ) << ulFeatureBitOffset ); /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } if (pSharedInfo->ImageInfo.fRoutNoiseReductionLevel == TRUE) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( (f_pVqeConfig->lRoutNoiseReductionLevelGainDb != pChanEntry->VqeConfig.chRoutNoiseReductionLevelGainDb ) ||( f_pVqeConfig->fRoutNoiseReduction != pChanEntry->VqeConfig.fRoutNoiseReduction ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinAnrValOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinAnrValOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinAnrValOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if (f_pVqeConfig->fRoutNoiseReduction == TRUE) { switch( f_pVqeConfig->lRoutNoiseReductionLevelGainDb) { case 0: ulTempData |= ( 0 << ulFeatureBitOffset ); break; case -6: ulTempData |= ( 1 << ulFeatureBitOffset ); break; case -12: ulTempData |= ( 2 << ulFeatureBitOffset ); break; case -18: ulTempData |= ( 3 << ulFeatureBitOffset ); break; default: ulTempData |= ( 0 << ulFeatureBitOffset ); break; } } else ulTempData |= ( 0 << ulFeatureBitOffset ); /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure Sout ANR SNR enhancement. */ if ( pSharedInfo->ImageInfo.fAnrSnrEnhancement == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->lAnrSnrEnhancementDb != pChanEntry->VqeConfig.chAnrSnrEnhancementDb ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AnrSnrEnhancementOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AnrSnrEnhancementOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AnrSnrEnhancementOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set ANR SNR enhancement on the Sout port. */ switch( f_pVqeConfig->lAnrSnrEnhancementDb ) { case -9: ulTempData |= ( 7 << ulFeatureBitOffset ); break; case -12: ulTempData |= ( 6 << ulFeatureBitOffset ); break; case -15: ulTempData |= ( 5 << ulFeatureBitOffset ); break; case -21: ulTempData |= ( 3 << ulFeatureBitOffset ); break; case -24: ulTempData |= ( 2 << ulFeatureBitOffset ); break; case -27: ulTempData |= ( 1 << ulFeatureBitOffset ); break; case -30: ulTempData |= ( 0 << ulFeatureBitOffset ); break; default: ulTempData |= ( 4 << ulFeatureBitOffset ); /* -18 */ break; } /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure Sout ANR voice-noise segregation. */ if ( pSharedInfo->ImageInfo.fAnrVoiceNoiseSegregation == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->ulAnrVoiceNoiseSegregation != pChanEntry->VqeConfig.byAnrVoiceNoiseSegregation ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AnrVoiceNoiseSegregationOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AnrVoiceNoiseSegregationOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AnrVoiceNoiseSegregationOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set ANR voice-noise segregation on the Sout port. */ ulTempData |= ( ( (UINT32)f_pVqeConfig->ulAnrVoiceNoiseSegregation ) << ulFeatureBitOffset ); /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure the tone disabler VQE activation delay. */ if ( pSharedInfo->ImageInfo.fToneDisablerVqeActivationDelay == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->ulToneDisablerVqeActivationDelay != pChanEntry->VqeConfig.usToneDisablerVqeActivationDelay ) || ( f_pChannelOpen->fEnableToneDisabler != pChanEntry->fEnableToneDisabler ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.ToneDisablerVqeActivationDelayOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ToneDisablerVqeActivationDelayOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ToneDisablerVqeActivationDelayOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set the tone disabler VQE activation delay. The VQE activation delay */ /* is only set if the tone disabler is activated. */ if ( f_pChannelOpen->fEnableToneDisabler == TRUE ) ulTempData |= ( ( (UINT32)( ( f_pVqeConfig->ulToneDisablerVqeActivationDelay - 300 ) / 512 ) ) << ulFeatureBitOffset ); else ulTempData |= ( 0 ) << ulFeatureBitOffset; /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure Conferencing Noise Reduction.*/ if ( pSharedInfo->ImageInfo.fConferencingNoiseReduction == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->fSoutConferencingNoiseReduction != pChanEntry->VqeConfig.fSoutConferencingNoiseReduction ) || ( f_pVqeConfig->fSoutNoiseBleaching != pChanEntry->VqeConfig.fSoutNoiseBleaching ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.ConferencingNoiseReductionOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ConferencingNoiseReductionOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ConferencingNoiseReductionOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set conferencing noise reduction on the SOUT port. */ ulTempData |= (f_pVqeConfig->fSoutConferencingNoiseReduction << ulFeatureBitOffset ); /* If SOUT noise bleaching is requested, CNR must be activated. */ ulTempData |= (f_pVqeConfig->fSoutNoiseBleaching << ulFeatureBitOffset ); /* Save the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the DC removal on RIN ports.*/ if ( pSharedInfo->ImageInfo.fRinDcOffsetRemoval == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fRinDcOffsetRemoval != pChanEntry->VqeConfig.fRinDcOffsetRemoval ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinDcOffsetRemovalOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinDcOffsetRemovalOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinDcOffsetRemovalOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set adaptive noise reduction on the SOUT port.*/ ulTempData |= ( ( (UINT32)f_pVqeConfig->fRinDcOffsetRemoval ) << ulFeatureBitOffset ); /* The write the new DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the DC removal on SIN ports.*/ if ( pSharedInfo->ImageInfo.fSinDcOffsetRemoval == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fSinDcOffsetRemoval != pChanEntry->VqeConfig.fSinDcOffsetRemoval ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.SinDcOffsetRemovalOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.SinDcOffsetRemovalOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.SinDcOffsetRemovalOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set adaptive noise reduction on the SOUT port.*/ ulTempData |= ( ( (UINT32)f_pVqeConfig->fSinDcOffsetRemoval ) << ulFeatureBitOffset ); /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the level control. */ if ( ( pChanEntry->byEchoOperationMode != f_pChannelOpen->ulEchoOperationMode ) && ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NORMAL ) ) fEchoOperationModeChanged = TRUE; else fEchoOperationModeChanged = FALSE; /* If opening the channel, all level control configuration must be written. */ if ( f_fModifyOnly == FALSE ) fEchoOperationModeChanged = TRUE; ulResult = Oct6100ApiSetChannelLevelControl( f_pApiInstance, f_pVqeConfig, f_usChanIndex, f_usEchoMemIndex, fEchoOperationModeChanged ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the background noise freeze.*/ if ( pSharedInfo->ImageInfo.fComfortNoise == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->ulComfortNoiseMode != pChanEntry->VqeConfig.byComfortNoiseMode ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.ComfortNoiseModeOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ComfortNoiseModeOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ComfortNoiseModeOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= ( f_pVqeConfig->ulComfortNoiseMode << ulFeatureBitOffset ); /* Save the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the state of the NLP */ if ( pSharedInfo->ImageInfo.fNlpControl == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fEnableNlp != pChanEntry->VqeConfig.fEnableNlp ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.NlpControlFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.NlpControlFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.NlpControlFieldOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fEnableNlp == FALSE ) ulTempData |= 0x1 << ulFeatureBitOffset; /* Save the new DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the tail configuration. */ ulResult = Oct6100ApiSetChannelTailConfiguration( f_pApiInstance, f_pVqeConfig, f_usChanIndex, f_usEchoMemIndex, f_fModifyOnly ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the Default ERL. */ if ( ( pSharedInfo->ImageInfo.fDefaultErl == TRUE ) && ( f_pVqeConfig->fAcousticEcho == FALSE ) ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->lDefaultErlDb != pChanEntry->VqeConfig.chDefaultErlDb ) || ( f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) || ( f_pVqeConfig->fAcousticEcho != pChanEntry->VqeConfig.fAcousticEcho ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.DefaultErlFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.DefaultErlFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.DefaultErlFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Convert the DB value to octasic's float format. (In energy) */ if ( ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NO_ECHO ) && ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) ) { usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lDefaultErlDb ); } else { /* Clear the defautl ERL when using the no echo cancellation operation mode. */ usTempData = 0x0; } if ( ulFeatureFieldLength < 16 ) usTempData = (UINT16)( usTempData >> ( 16 - ulFeatureFieldLength ) ); ulTempData |= ( usTempData << ulFeatureBitOffset ); /* Save the new DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the Acoustic echo control.*/ if ( pSharedInfo->ImageInfo.fAcousticEcho == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fAcousticEcho != pChanEntry->VqeConfig.fAcousticEcho ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AecFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AecFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AecFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= ( ( (UINT32)f_pVqeConfig->fAcousticEcho ) << ulFeatureBitOffset ); /* Then save the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the Acoustic Echo Default ERL. */ if ( ( pSharedInfo->ImageInfo.fAecDefaultErl == TRUE ) && ( f_pVqeConfig->fAcousticEcho == TRUE ) ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->lAecDefaultErlDb != pChanEntry->VqeConfig.chAecDefaultErlDb ) || ( f_pVqeConfig->fAcousticEcho != pChanEntry->VqeConfig.fAcousticEcho ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AecDefaultErlFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AecDefaultErlFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AecDefaultErlFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field. */ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NO_ECHO ) && ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) ) { /* Convert the DB value to octasic's float format. (In energy) */ usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lAecDefaultErlDb ); } else { /* Clear the AEC defautl ERL when using the no echo cancellation operation mode. */ usTempData = 0x0; } if ( ulFeatureFieldLength < 16 ) usTempData = (UINT16)( usTempData >> ( 16 - ulFeatureFieldLength ) ); ulTempData |= ( usTempData << ulFeatureBitOffset ); /* Then save the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the DTMF tone removal bit.*/ if ( pSharedInfo->ImageInfo.fToneRemoval == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fDtmfToneRemoval != pChanEntry->VqeConfig.fDtmfToneRemoval ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.ToneRemovalFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ToneRemovalFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ToneRemovalFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= ( ( (UINT32)f_pVqeConfig->fDtmfToneRemoval ) << ulFeatureBitOffset ); /* First read the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the non-linear behavior A.*/ if ( pSharedInfo->ImageInfo.fNonLinearityBehaviorA == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->ulNonLinearityBehaviorA != pChanEntry->VqeConfig.byNonLinearityBehaviorA ) || ( f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) ) ) ) { UINT16 ausLookupTable[ 14 ] = { 0x3663, 0x3906, 0x399C, 0x3A47, 0x3B06, 0x3B99, 0x3C47, 0x3D02, 0x3D99, 0x3E47, 0x3F00, 0x3F99, 0x4042, 0x4100 }; ulFeatureBytesOffset = pSharedInfo->MemoryMap.PcmLeakFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PcmLeakFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PcmLeakFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /*If we support ANR level the TLV is shared over 2 bits*/ if (ulFeatureBitOffset == 18) { ulFeatureBitOffset -= 2; ausLookupTable[ f_pVqeConfig->ulNonLinearityBehaviorA ] &= 0xFFFC; } if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) || ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) ) ulTempData |= ( 0x0 << ulFeatureBitOffset ); else ulTempData |= ( ausLookupTable[ f_pVqeConfig->ulNonLinearityBehaviorA ] << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Synch all the buffer playout field.*/ if ( pSharedInfo->ImageInfo.fBufferPlayout == TRUE && f_fClearPlayoutPointers == TRUE ) { Oct6100BufferPlayoutStopDef( &BufferPlayoutStop ); BufferPlayoutStop.ulChannelHndl = cOCT6100_INVALID_HANDLE; BufferPlayoutStop.fStopCleanly = TRUE; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_ROUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, f_usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; BufferPlayoutStop.ulPlayoutPort = cOCT6100_CHANNEL_PORT_SOUT; ulResult = Oct6100ApiInvalidateChanPlayoutStructs( f_pApiInstance, &BufferPlayoutStop, f_usChanIndex, f_usEchoMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /* Write the 2100 Hz Echo Disabling mode */ /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pChannelOpen->fEnableToneDisabler != pChanEntry->fEnableToneDisabler ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.ToneDisablerControlOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ToneDisablerControlOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ToneDisablerControlOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* This is a disable bit, so it must be set only if the enable flag is set to false. */ if ( f_pChannelOpen->fEnableToneDisabler == FALSE ) ulTempData |= 0x1 << ulFeatureBitOffset; /* Save the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /*==============================================================================*/ /* Write the Nlp Trivial enable flag. */ /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.NlpTrivialFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.NlpTrivialFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.NlpTrivialFieldOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) || ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) ) { ulTempData |= TRUE << ulFeatureBitOffset; } /* Then write the DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*==============================================================================*/ /*==============================================================================*/ /* Set the double talk behavior mode. */ if ( pSharedInfo->ImageInfo.fDoubleTalkBehaviorFieldOfst == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->ulDoubleTalkBehavior != pChanEntry->VqeConfig.byDoubleTalkBehavior ) ) ) { /* The field is located in the CPURO structure. */ ulFeatureBytesOffset = pSharedInfo->MemoryMap.DoubleTalkBehaviorFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.DoubleTalkBehaviorFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.DoubleTalkBehaviorFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= (f_pVqeConfig->ulDoubleTalkBehavior << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Set the music protection enable. */ if ( ( pSharedInfo->ImageInfo.fMusicProtection == TRUE ) && ( pSharedInfo->ImageInfo.fMusicProtectionConfiguration == TRUE ) ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fEnableMusicProtection != pChanEntry->VqeConfig.fEnableMusicProtection ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.MusicProtectionFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.MusicProtectionFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.MusicProtectionFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fEnableMusicProtection == TRUE ) ulTempData |= ( 1 << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteVqeAfMemory Description: This function configures the AF related VQE features of an echo channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig Pointer to a VQE config structure. f_pChannelOpen Pointer to a channel configuration structure. f_usChanIndex Index of the echo channel in the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_fClearPlayoutPointers Flag indicating if the playout pointer should be cleared. f_fModifyOnly Flag indicating if the configuration should be modified only. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteVqeAfMemory UINT32 Oct6100ApiWriteVqeAfMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearPlayoutPointers, IN BOOL f_fModifyOnly ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulTempData; UINT32 ulAfConfigBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; UINT16 usTempData; pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ); /*==============================================================================*/ /* Write the AF CPU configuration of the channel feature by feature.*/ /* Calculate AF CPU configuration base address. */ ulAfConfigBaseAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst; /* Set initial value to zero.*/ ulTempData = 0; /*==============================================================================*/ /* Program the Maximum echo point within the Main channel memory.*/ if ( pSharedInfo->ImageInfo.fMaxEchoPoint == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->lDefaultErlDb != pChanEntry->VqeConfig.chDefaultErlDb ) || ( f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) ) ) ) { /* Write the echo tail length */ ulFeatureBytesOffset = pSharedInfo->MemoryMap.ChanMainIoMaxEchoPointOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.ChanMainIoMaxEchoPointOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.ChanMainIoMaxEchoPointOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Convert the DB value to octasic's float format.*/ if ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_NO_ECHO ) { usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lDefaultErlDb ); } else { /* Clear max echo point. No echo cancellation here. */ usTempData = 0x0; } if ( ulFeatureFieldLength < 16 ) usTempData = (UINT16)( usTempData >> ( 16 - ulFeatureFieldLength ) ); ulTempData |= usTempData << ulFeatureBitOffset; /* First read the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Set the non-linear behavior B.*/ if ( pSharedInfo->ImageInfo.fNonLinearityBehaviorB == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->ulNonLinearityBehaviorB != pChanEntry->VqeConfig.byNonLinearityBehaviorB ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.NlpConvCapFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.NlpConvCapFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.NlpConvCapFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= (f_pVqeConfig->ulNonLinearityBehaviorB << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Set the listener enhancement feature. */ if ( pSharedInfo->ImageInfo.fListenerEnhancement == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != pChanEntry->VqeConfig.bySoutAutomaticListenerEnhancementGainDb ) || ( f_pVqeConfig->fSoutNaturalListenerEnhancement != pChanEntry->VqeConfig.fSoutNaturalListenerEnhancement ) || ( f_pVqeConfig->ulSoutNaturalListenerEnhancementGainDb != pChanEntry->VqeConfig.bySoutNaturalListenerEnhancementGainDb ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AdaptiveAleOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AdaptiveAleOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AdaptiveAleOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != 0 ) { UINT32 ulGainDb; ulGainDb = f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb / 3; /* Round up. */ if ( ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb % 3 ) != 0x0 ) ulGainDb ++; ulTempData |= ( ulGainDb << ulFeatureBitOffset ); } else if ( f_pVqeConfig->fSoutNaturalListenerEnhancement != 0 ) { UINT32 ulGainDb; ulGainDb = f_pVqeConfig->ulSoutNaturalListenerEnhancementGainDb / 3; /* Round up. */ if ( ( f_pVqeConfig->ulSoutNaturalListenerEnhancementGainDb % 3 ) != 0x0 ) ulGainDb ++; ulTempData |= ( ( 0x80 | ulGainDb ) << ulFeatureBitOffset ); } /* Now write the DWORD where the field is located containing the new configuration. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Set the idle code detection enable. */ if ( ( pSharedInfo->ImageInfo.fIdleCodeDetection == TRUE ) && ( pSharedInfo->ImageInfo.fIdleCodeDetectionConfiguration == TRUE ) ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->fIdleCodeDetection != pChanEntry->VqeConfig.fIdleCodeDetection ) ) ) { /* Calculate base address in the AF software configuration. */ ulFeatureBytesOffset = pSharedInfo->MemoryMap.IdleCodeDetectionFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.IdleCodeDetectionFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.IdleCodeDetectionFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fIdleCodeDetection == FALSE ) ulTempData |= ( 1 << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ /*==============================================================================*/ /* Set the AFT control field. */ if ( pSharedInfo->ImageInfo.fAftControl == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pChannelOpen->ulEchoOperationMode != pChanEntry->byEchoOperationMode ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AftControlOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AftControlOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AftControlOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* If the operation mode is no echo, set the field such that echo cancellation is disabled. */ if ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) { ulTempData |= ( 0x1234 << ulFeatureBitOffset ); } else if ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) { /* For clarity. */ ulTempData |= ( 0x0 << ulFeatureBitOffset ); } /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfigBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteEchoMemory Description: This function configure an echo memory entry in internal memory.and external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTdmConfig Pointer to a TDM config structure. f_pChannelOpen Pointer to a channel configuration structure. f_usEchoIndex Echo channel index within the SSPX memory. f_usRinRoutTsiIndex RIN/ROUT TSI index within the TSI chariot memory f_usSinSoutTsiIndex SIN/SOUT TSI index within the TSI chariot memory \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteEchoMemory UINT32 Oct6100ApiWriteEchoMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usEchoIndex, IN UINT16 f_usRinRoutTsiIndex, IN UINT16 f_usSinSoutTsiIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulTempData; UINT32 ulBaseAddress; UINT32 ulRinPcmLaw; UINT32 ulRoutPcmLaw; UINT32 ulSinPcmLaw; UINT32 ulSoutPcmLaw; pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Set immediately the PCM law to be programmed in the SSPX and NLP memory.*/ if ( f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_RIN ) { ulRinPcmLaw = f_pChannelOpen->TdmConfig.ulRoutPcmLaw; ulRoutPcmLaw = f_pChannelOpen->TdmConfig.ulRoutPcmLaw; ulSinPcmLaw = f_pChannelOpen->TdmConfig.ulSinPcmLaw; ulSoutPcmLaw = f_pChannelOpen->TdmConfig.ulSinPcmLaw; } else /* f_pChannelOpen->CodecConfig.ulDecoderPort == cOCT6100_CHANNEL_PORT_SIN */ { ulRinPcmLaw = f_pChannelOpen->TdmConfig.ulRinPcmLaw; ulRoutPcmLaw = f_pChannelOpen->TdmConfig.ulRinPcmLaw; ulSinPcmLaw = f_pChannelOpen->TdmConfig.ulSoutPcmLaw; ulSoutPcmLaw = f_pChannelOpen->TdmConfig.ulSoutPcmLaw; } /*==============================================================================*/ /* Configure the Global Static Configuration of the channel.*/ ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + cOCT6100_CHANNEL_ROOT_GLOBAL_CONF_OFFSET; /* Set the PGSP context base address. */ ulTempData = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + cOCT6100_CH_MAIN_PGSP_CONTEXT_OFFSET; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_PGSP_CONTEXT_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the PGSP init context base address. */ ulTempData = ( cOCT6100_IMAGE_FILE_BASE + 0x200 ) & 0x07FFFFFF; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_PGSP_INIT_CONTEXT_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the RIN circular buffer base address. */ ulTempData = ( pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainRinCBMemOfst) & 0x07FFFF00; ulTempData |= ( ulRoutPcmLaw << cOCT6100_GSC_BUFFER_LAW_OFFSET ); /* Set the circular buffer size.*/ if (( pSharedInfo->MemoryMap.ulChanMainRinCBMemSize & 0xFFFF00FF ) != 0 ) return cOCT6100_ERR_CHANNEL_INVALID_RIN_CB_SIZE; ulTempData |= pSharedInfo->MemoryMap.ulChanMainRinCBMemSize >> 8; WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_RIN_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the SIN circular buffer base address. */ ulTempData = ( pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainSinCBMemOfst) & 0x07FFFF00; ulTempData |= ( ulSinPcmLaw << cOCT6100_GSC_BUFFER_LAW_OFFSET ); WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_SIN_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the SOUT circular buffer base address. */ ulTempData = ( pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainSoutCBMemOfst ) & 0x07FFFF00; ulTempData |= ( ulSoutPcmLaw << cOCT6100_GSC_BUFFER_LAW_OFFSET ); WriteParams.ulWriteAddress = ulBaseAddress + cOCT6100_GSC_SOUT_CIRC_BUFFER_BASE_ADD_OFFSET; WriteParams.usWriteData = (UINT16)( ulTempData >> 16 ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( ulTempData & 0xFFFF ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* ECHO SSPX Memory configuration.*/ WriteParams.ulWriteAddress = cOCT6100_ECHO_CONTROL_MEM_BASE + ( f_usEchoIndex * cOCT6100_ECHO_CONTROL_MEM_ENTRY_SIZE ); /* ECHO memory BASE + 2 */ WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = 0x0000; /* Set the echo control field.*/ if ( ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_NO_ECHO ) || ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION ) ) { WriteParams.usWriteData |= cOCT6100_ECHO_OP_MODE_NORMAL << cOCT6100_ECHO_CONTROL_MEM_AF_CONTROL; } else if ( f_pChannelOpen->ulEchoOperationMode != cOCT6100_ECHO_OP_MODE_EXTERNAL ) { WriteParams.usWriteData |= f_pChannelOpen->ulEchoOperationMode << cOCT6100_ECHO_CONTROL_MEM_AF_CONTROL; } /* Set the SIN/SOUT law.*/ WriteParams.usWriteData |= ulSinPcmLaw << cOCT6100_ECHO_CONTROL_MEM_INPUT_LAW_OFFSET; WriteParams.usWriteData |= ulSoutPcmLaw << cOCT6100_ECHO_CONTROL_MEM_OUTPUT_LAW_OFFSET; /* Set the TSI chariot memory field.*/ WriteParams.usWriteData |= f_usSinSoutTsiIndex & cOCT6100_ECHO_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* ECHO memory BASE */ WriteParams.ulWriteAddress -= 2; WriteParams.usWriteData = cOCT6100_ECHO_CONTROL_MEM_ACTIVATE_ENTRY; /* Set the RIN/ROUT law.*/ WriteParams.usWriteData |= ulRinPcmLaw << cOCT6100_ECHO_CONTROL_MEM_INPUT_LAW_OFFSET; WriteParams.usWriteData |= ulRoutPcmLaw << cOCT6100_ECHO_CONTROL_MEM_OUTPUT_LAW_OFFSET; /* Set the RIN external echo control bit.*/ if ( f_pChannelOpen->ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_EXTERNAL ) WriteParams.usWriteData |= cOCT6100_ECHO_CONTROL_MEM_EXTERNAL_AF_CTRL; /* Set the TSI chariot memory field.*/ WriteParams.usWriteData |= f_usRinRoutTsiIndex & cOCT6100_ECHO_CONTROL_MEM_TSI_MEM_MASK; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateOpenStruct Description: This function will copy the new parameter from the modify structure into a channel open structure to be processed later by the same path as the channel open function. If a parameter is set to keep previous, it's current value will be extracted from the channel entry in the API. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- IN f_pApiInstance Pointer to an API instance structure. IN f_pChanModify Pointer to a channel modify structure. IN OUT f_pChanOpen Pointer to a channel open structure. IN f_pChanEntry Pointer to an API channel structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateOpenStruct UINT32 Oct6100ApiUpdateOpenStruct( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MODIFY f_pChanModify, IN OUT tPOCT6100_CHANNEL_OPEN f_pChanOpen, IN tPOCT6100_API_CHANNEL f_pChanEntry ) { /* Check the generic Echo parameters.*/ if ( f_pChanModify->ulEchoOperationMode == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->ulEchoOperationMode = f_pChanEntry->byEchoOperationMode; else f_pChanOpen->ulEchoOperationMode = f_pChanModify->ulEchoOperationMode; if ( f_pChanModify->fEnableToneDisabler == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->fEnableToneDisabler = f_pChanEntry->fEnableToneDisabler; else f_pChanOpen->fEnableToneDisabler = f_pChanModify->fEnableToneDisabler; if ( f_pChanModify->ulUserChanId == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->ulUserChanId = f_pChanEntry->ulUserChanId; else f_pChanOpen->ulUserChanId = f_pChanModify->ulUserChanId; /*======================================================================*/ /* Now update the TDM config.*/ /* Rin PCM LAW */ if ( f_pChanModify->TdmConfig.ulRinPcmLaw == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRinPcmLaw = f_pChanEntry->TdmConfig.byRinPcmLaw; else f_pChanOpen->TdmConfig.ulRinPcmLaw = f_pChanModify->TdmConfig.ulRinPcmLaw; /* Sin PCM LAW */ if ( f_pChanModify->TdmConfig.ulSinPcmLaw == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSinPcmLaw = f_pChanEntry->TdmConfig.bySinPcmLaw; else f_pChanOpen->TdmConfig.ulSinPcmLaw = f_pChanModify->TdmConfig.ulSinPcmLaw; /* Rout PCM LAW */ if ( f_pChanModify->TdmConfig.ulRoutPcmLaw == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRoutPcmLaw = f_pChanEntry->TdmConfig.byRoutPcmLaw; else f_pChanOpen->TdmConfig.ulRoutPcmLaw = f_pChanModify->TdmConfig.ulRoutPcmLaw; /* Sout PCM LAW */ if ( f_pChanModify->TdmConfig.ulSoutPcmLaw == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSoutPcmLaw = f_pChanEntry->TdmConfig.bySoutPcmLaw; else f_pChanOpen->TdmConfig.ulSoutPcmLaw = f_pChanModify->TdmConfig.ulSoutPcmLaw; /* Rin Timeslot */ if ( f_pChanModify->TdmConfig.ulRinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRinTimeslot = f_pChanEntry->TdmConfig.usRinTimeslot; else f_pChanOpen->TdmConfig.ulRinTimeslot = f_pChanModify->TdmConfig.ulRinTimeslot; /* Rin Stream */ if ( f_pChanModify->TdmConfig.ulRinStream == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRinStream = f_pChanEntry->TdmConfig.usRinStream; else f_pChanOpen->TdmConfig.ulRinStream = f_pChanModify->TdmConfig.ulRinStream; /* Rin Num TSSTs */ if ( f_pChanModify->TdmConfig.ulRinNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRinNumTssts = f_pChanEntry->TdmConfig.byRinNumTssts; else f_pChanOpen->TdmConfig.ulRinNumTssts = f_pChanModify->TdmConfig.ulRinNumTssts; /* Sin Timeslot */ if ( f_pChanModify->TdmConfig.ulSinTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSinTimeslot = f_pChanEntry->TdmConfig.usSinTimeslot; else f_pChanOpen->TdmConfig.ulSinTimeslot = f_pChanModify->TdmConfig.ulSinTimeslot; /* Sin Stream */ if ( f_pChanModify->TdmConfig.ulSinStream == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSinStream = f_pChanEntry->TdmConfig.usSinStream; else f_pChanOpen->TdmConfig.ulSinStream = f_pChanModify->TdmConfig.ulSinStream; /* Sin Num TSSTs */ if ( f_pChanModify->TdmConfig.ulSinNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSinNumTssts = f_pChanEntry->TdmConfig.bySinNumTssts; else f_pChanOpen->TdmConfig.ulSinNumTssts = f_pChanModify->TdmConfig.ulSinNumTssts; /* Rout Timeslot */ if ( f_pChanModify->TdmConfig.ulRoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRoutTimeslot = f_pChanEntry->TdmConfig.usRoutTimeslot; else f_pChanOpen->TdmConfig.ulRoutTimeslot = f_pChanModify->TdmConfig.ulRoutTimeslot; /* Rout Stream */ if ( f_pChanModify->TdmConfig.ulRoutStream == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRoutStream = f_pChanEntry->TdmConfig.usRoutStream; else f_pChanOpen->TdmConfig.ulRoutStream = f_pChanModify->TdmConfig.ulRoutStream; /* Rout Num TSSTs */ if ( f_pChanModify->TdmConfig.ulRoutNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulRoutNumTssts = f_pChanEntry->TdmConfig.byRoutNumTssts; else f_pChanOpen->TdmConfig.ulRoutNumTssts = f_pChanModify->TdmConfig.ulRoutNumTssts; /* Sout Timeslot */ if ( f_pChanModify->TdmConfig.ulSoutTimeslot == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSoutTimeslot = f_pChanEntry->TdmConfig.usSoutTimeslot; else f_pChanOpen->TdmConfig.ulSoutTimeslot = f_pChanModify->TdmConfig.ulSoutTimeslot; /* Sout Stream */ if ( f_pChanModify->TdmConfig.ulSoutStream == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSoutStream = f_pChanEntry->TdmConfig.usSoutStream; else f_pChanOpen->TdmConfig.ulSoutStream = f_pChanModify->TdmConfig.ulSoutStream; /* Sout Num TSSTs */ if ( f_pChanModify->TdmConfig.ulSoutNumTssts == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->TdmConfig.ulSoutNumTssts = f_pChanEntry->TdmConfig.bySoutNumTssts; else f_pChanOpen->TdmConfig.ulSoutNumTssts = f_pChanModify->TdmConfig.ulSoutNumTssts; /*======================================================================*/ /*======================================================================*/ /* Now update the VQE config.*/ if ( f_pChanModify->VqeConfig.ulComfortNoiseMode == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulComfortNoiseMode = f_pChanEntry->VqeConfig.byComfortNoiseMode; else f_pChanOpen->VqeConfig.ulComfortNoiseMode = f_pChanModify->VqeConfig.ulComfortNoiseMode; if ( f_pChanModify->VqeConfig.fEnableNlp == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fEnableNlp = f_pChanEntry->VqeConfig.fEnableNlp; else f_pChanOpen->VqeConfig.fEnableNlp = f_pChanModify->VqeConfig.fEnableNlp; if ( f_pChanModify->VqeConfig.fEnableTailDisplacement == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fEnableTailDisplacement = f_pChanEntry->VqeConfig.fEnableTailDisplacement; else f_pChanOpen->VqeConfig.fEnableTailDisplacement = f_pChanModify->VqeConfig.fEnableTailDisplacement; if ( f_pChanModify->VqeConfig.ulTailDisplacement == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulTailDisplacement = f_pChanEntry->VqeConfig.usTailDisplacement; else f_pChanOpen->VqeConfig.ulTailDisplacement = f_pChanModify->VqeConfig.ulTailDisplacement; /* Tail length cannot be modifed. */ f_pChanOpen->VqeConfig.ulTailLength = f_pChanEntry->VqeConfig.usTailLength; if ( f_pChanModify->VqeConfig.fRinDcOffsetRemoval == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fRinDcOffsetRemoval = f_pChanEntry->VqeConfig.fRinDcOffsetRemoval; else f_pChanOpen->VqeConfig.fRinDcOffsetRemoval = f_pChanModify->VqeConfig.fRinDcOffsetRemoval; if ( f_pChanModify->VqeConfig.fRinLevelControl == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fRinLevelControl = f_pChanEntry->VqeConfig.fRinLevelControl; else f_pChanOpen->VqeConfig.fRinLevelControl = f_pChanModify->VqeConfig.fRinLevelControl; if ( f_pChanModify->VqeConfig.fRinAutomaticLevelControl == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fRinAutomaticLevelControl = f_pChanEntry->VqeConfig.fRinAutomaticLevelControl; else f_pChanOpen->VqeConfig.fRinAutomaticLevelControl = f_pChanModify->VqeConfig.fRinAutomaticLevelControl; if ( f_pChanModify->VqeConfig.fRinHighLevelCompensation == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fRinHighLevelCompensation = f_pChanEntry->VqeConfig.fRinHighLevelCompensation; else f_pChanOpen->VqeConfig.fRinHighLevelCompensation = f_pChanModify->VqeConfig.fRinHighLevelCompensation; if ( f_pChanModify->VqeConfig.lRinHighLevelCompensationThresholdDb == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.lRinHighLevelCompensationThresholdDb = f_pChanEntry->VqeConfig.chRinHighLevelCompensationThresholdDb; else f_pChanOpen->VqeConfig.lRinHighLevelCompensationThresholdDb = f_pChanModify->VqeConfig.lRinHighLevelCompensationThresholdDb; if ( f_pChanModify->VqeConfig.fSinDcOffsetRemoval == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSinDcOffsetRemoval = f_pChanEntry->VqeConfig.fSinDcOffsetRemoval; else f_pChanOpen->VqeConfig.fSinDcOffsetRemoval = f_pChanModify->VqeConfig.fSinDcOffsetRemoval; if ( f_pChanModify->VqeConfig.fSoutAdaptiveNoiseReduction == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutAdaptiveNoiseReduction = f_pChanEntry->VqeConfig.fSoutAdaptiveNoiseReduction; else f_pChanOpen->VqeConfig.fSoutAdaptiveNoiseReduction = f_pChanModify->VqeConfig.fSoutAdaptiveNoiseReduction; if ( f_pChanModify->VqeConfig.fSoutConferencingNoiseReduction == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutConferencingNoiseReduction = f_pChanEntry->VqeConfig.fSoutConferencingNoiseReduction; else f_pChanOpen->VqeConfig.fSoutConferencingNoiseReduction = f_pChanModify->VqeConfig.fSoutConferencingNoiseReduction; if ( f_pChanModify->VqeConfig.fSoutNoiseBleaching == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutNoiseBleaching = f_pChanEntry->VqeConfig.fSoutNoiseBleaching; else f_pChanOpen->VqeConfig.fSoutNoiseBleaching = f_pChanModify->VqeConfig.fSoutNoiseBleaching; if ( f_pChanModify->VqeConfig.fSoutLevelControl == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutLevelControl = f_pChanEntry->VqeConfig.fSoutLevelControl; else f_pChanOpen->VqeConfig.fSoutLevelControl = f_pChanModify->VqeConfig.fSoutLevelControl; if ( f_pChanModify->VqeConfig.fSoutAutomaticLevelControl == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutAutomaticLevelControl = f_pChanEntry->VqeConfig.fSoutAutomaticLevelControl; else f_pChanOpen->VqeConfig.fSoutAutomaticLevelControl = f_pChanModify->VqeConfig.fSoutAutomaticLevelControl; if ( f_pChanModify->VqeConfig.lRinLevelControlGainDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lRinLevelControlGainDb = f_pChanEntry->VqeConfig.chRinLevelControlGainDb; else f_pChanOpen->VqeConfig.lRinLevelControlGainDb = f_pChanModify->VqeConfig.lRinLevelControlGainDb; if ( f_pChanModify->VqeConfig.lSoutLevelControlGainDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lSoutLevelControlGainDb = f_pChanEntry->VqeConfig.chSoutLevelControlGainDb; else f_pChanOpen->VqeConfig.lSoutLevelControlGainDb = f_pChanModify->VqeConfig.lSoutLevelControlGainDb; if ( f_pChanModify->VqeConfig.lRinAutomaticLevelControlTargetDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lRinAutomaticLevelControlTargetDb = f_pChanEntry->VqeConfig.chRinAutomaticLevelControlTargetDb; else f_pChanOpen->VqeConfig.lRinAutomaticLevelControlTargetDb = f_pChanModify->VqeConfig.lRinAutomaticLevelControlTargetDb; if ( f_pChanModify->VqeConfig.lSoutAutomaticLevelControlTargetDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lSoutAutomaticLevelControlTargetDb = f_pChanEntry->VqeConfig.chSoutAutomaticLevelControlTargetDb; else f_pChanOpen->VqeConfig.lSoutAutomaticLevelControlTargetDb = f_pChanModify->VqeConfig.lSoutAutomaticLevelControlTargetDb; if ( f_pChanModify->VqeConfig.lDefaultErlDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lDefaultErlDb = f_pChanEntry->VqeConfig.chDefaultErlDb; else f_pChanOpen->VqeConfig.lDefaultErlDb = f_pChanModify->VqeConfig.lDefaultErlDb; if ( f_pChanModify->VqeConfig.lAecDefaultErlDb == ( (INT32)cOCT6100_KEEP_PREVIOUS_SETTING ) ) f_pChanOpen->VqeConfig.lAecDefaultErlDb = f_pChanEntry->VqeConfig.chAecDefaultErlDb; else f_pChanOpen->VqeConfig.lAecDefaultErlDb = f_pChanModify->VqeConfig.lAecDefaultErlDb; if ( f_pChanModify->VqeConfig.ulAecTailLength == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulAecTailLength = f_pChanEntry->VqeConfig.usAecTailLength; else f_pChanOpen->VqeConfig.ulAecTailLength = f_pChanModify->VqeConfig.ulAecTailLength; if ( f_pChanModify->VqeConfig.fAcousticEcho == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fAcousticEcho = f_pChanEntry->VqeConfig.fAcousticEcho; else f_pChanOpen->VqeConfig.fAcousticEcho = f_pChanModify->VqeConfig.fAcousticEcho; if ( f_pChanModify->VqeConfig.fDtmfToneRemoval == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fDtmfToneRemoval = f_pChanEntry->VqeConfig.fDtmfToneRemoval; else f_pChanOpen->VqeConfig.fDtmfToneRemoval = f_pChanModify->VqeConfig.fDtmfToneRemoval; if ( f_pChanModify->VqeConfig.ulNonLinearityBehaviorA == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulNonLinearityBehaviorA = f_pChanEntry->VqeConfig.byNonLinearityBehaviorA; else f_pChanOpen->VqeConfig.ulNonLinearityBehaviorA = f_pChanModify->VqeConfig.ulNonLinearityBehaviorA; if ( f_pChanModify->VqeConfig.ulNonLinearityBehaviorB == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulNonLinearityBehaviorB = f_pChanEntry->VqeConfig.byNonLinearityBehaviorB; else f_pChanOpen->VqeConfig.ulNonLinearityBehaviorB = f_pChanModify->VqeConfig.ulNonLinearityBehaviorB; if ( f_pChanModify->VqeConfig.ulDoubleTalkBehavior == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulDoubleTalkBehavior = f_pChanEntry->VqeConfig.byDoubleTalkBehavior; else f_pChanOpen->VqeConfig.ulDoubleTalkBehavior = f_pChanModify->VqeConfig.ulDoubleTalkBehavior; if ( f_pChanModify->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = f_pChanEntry->VqeConfig.bySoutAutomaticListenerEnhancementGainDb; else f_pChanOpen->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb = f_pChanModify->VqeConfig.ulSoutAutomaticListenerEnhancementGainDb; if ( f_pChanModify->VqeConfig.ulSoutNaturalListenerEnhancementGainDb == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = f_pChanEntry->VqeConfig.bySoutNaturalListenerEnhancementGainDb; else f_pChanOpen->VqeConfig.ulSoutNaturalListenerEnhancementGainDb = f_pChanModify->VqeConfig.ulSoutNaturalListenerEnhancementGainDb; if ( f_pChanModify->VqeConfig.fSoutNaturalListenerEnhancement == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fSoutNaturalListenerEnhancement = f_pChanEntry->VqeConfig.fSoutNaturalListenerEnhancement; else f_pChanOpen->VqeConfig.fSoutNaturalListenerEnhancement = f_pChanModify->VqeConfig.fSoutNaturalListenerEnhancement; if ( f_pChanModify->VqeConfig.fRoutNoiseReduction == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fRoutNoiseReduction = f_pChanEntry->VqeConfig.fRoutNoiseReduction; else f_pChanOpen->VqeConfig.fRoutNoiseReduction = f_pChanModify->VqeConfig.fRoutNoiseReduction; if ( f_pChanModify->VqeConfig.lRoutNoiseReductionLevelGainDb == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.lRoutNoiseReductionLevelGainDb = f_pChanEntry->VqeConfig.chRoutNoiseReductionLevelGainDb; else f_pChanOpen->VqeConfig.lRoutNoiseReductionLevelGainDb = f_pChanModify->VqeConfig.lRoutNoiseReductionLevelGainDb; if ( f_pChanModify->VqeConfig.lAnrSnrEnhancementDb == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.lAnrSnrEnhancementDb = f_pChanEntry->VqeConfig.chAnrSnrEnhancementDb; else f_pChanOpen->VqeConfig.lAnrSnrEnhancementDb = f_pChanModify->VqeConfig.lAnrSnrEnhancementDb; if ( f_pChanModify->VqeConfig.ulAnrVoiceNoiseSegregation == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulAnrVoiceNoiseSegregation = f_pChanEntry->VqeConfig.byAnrVoiceNoiseSegregation; else f_pChanOpen->VqeConfig.ulAnrVoiceNoiseSegregation = f_pChanModify->VqeConfig.ulAnrVoiceNoiseSegregation; if ( f_pChanModify->VqeConfig.ulToneDisablerVqeActivationDelay == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.ulToneDisablerVqeActivationDelay = f_pChanEntry->VqeConfig.usToneDisablerVqeActivationDelay; else f_pChanOpen->VqeConfig.ulToneDisablerVqeActivationDelay = f_pChanModify->VqeConfig.ulToneDisablerVqeActivationDelay; if ( f_pChanModify->VqeConfig.fEnableMusicProtection == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fEnableMusicProtection = f_pChanEntry->VqeConfig.fEnableMusicProtection; else f_pChanOpen->VqeConfig.fEnableMusicProtection = f_pChanModify->VqeConfig.fEnableMusicProtection; if ( f_pChanModify->VqeConfig.fIdleCodeDetection == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->VqeConfig.fIdleCodeDetection = f_pChanEntry->VqeConfig.fIdleCodeDetection; else f_pChanOpen->VqeConfig.fIdleCodeDetection = f_pChanModify->VqeConfig.fIdleCodeDetection; /*======================================================================*/ /*======================================================================*/ /* Finaly the codec config.*/ if ( f_pChanModify->CodecConfig.ulDecoderPort == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulDecoderPort = f_pChanEntry->CodecConfig.byDecoderPort; else f_pChanOpen->CodecConfig.ulDecoderPort = f_pChanModify->CodecConfig.ulDecoderPort; if ( f_pChanModify->CodecConfig.ulDecodingRate == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulDecodingRate = f_pChanEntry->CodecConfig.byDecodingRate; else f_pChanOpen->CodecConfig.ulDecodingRate = f_pChanModify->CodecConfig.ulDecodingRate; if ( f_pChanModify->CodecConfig.ulEncoderPort == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulEncoderPort = f_pChanEntry->CodecConfig.byEncoderPort; else f_pChanOpen->CodecConfig.ulEncoderPort = f_pChanModify->CodecConfig.ulEncoderPort; if ( f_pChanModify->CodecConfig.ulEncodingRate == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulEncodingRate = f_pChanEntry->CodecConfig.byEncodingRate; else f_pChanOpen->CodecConfig.ulEncodingRate = f_pChanModify->CodecConfig.ulEncodingRate; if ( f_pChanModify->CodecConfig.fEnableSilenceSuppression == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.fEnableSilenceSuppression = f_pChanEntry->CodecConfig.fEnableSilenceSuppression; else f_pChanOpen->CodecConfig.fEnableSilenceSuppression = f_pChanModify->CodecConfig.fEnableSilenceSuppression; if ( f_pChanModify->CodecConfig.ulPhasingType == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulPhasingType = f_pChanEntry->CodecConfig.byPhasingType; else f_pChanOpen->CodecConfig.ulPhasingType = f_pChanModify->CodecConfig.ulPhasingType; if ( f_pChanModify->CodecConfig.ulPhase == cOCT6100_KEEP_PREVIOUS_SETTING ) f_pChanOpen->CodecConfig.ulPhase = f_pChanEntry->CodecConfig.byPhase; else f_pChanOpen->CodecConfig.ulPhase = f_pChanModify->CodecConfig.ulPhase; if ( f_pChanModify->CodecConfig.ulPhasingTsstHndl == cOCT6100_KEEP_PREVIOUS_SETTING ) { if ( f_pChanEntry->usPhasingTsstIndex != cOCT6100_INVALID_INDEX ) { tPOCT6100_API_PHASING_TSST pPhasingEntry; mOCT6100_GET_PHASING_TSST_ENTRY_PNT( f_pApiInstance->pSharedInfo, pPhasingEntry, f_pChanEntry->usPhasingTsstIndex ); /* Now recreate the Phasing TSST handle.*/ f_pChanOpen->CodecConfig.ulPhasingTsstHndl = cOCT6100_HNDL_TAG_PHASING_TSST | (pPhasingEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_pChanEntry->usPhasingTsstIndex; } else { f_pChanOpen->CodecConfig.ulPhasingTsstHndl = cOCT6100_INVALID_HANDLE; } } else { f_pChanOpen->CodecConfig.ulPhasingTsstHndl = f_pChanModify->CodecConfig.ulPhasingTsstHndl; } f_pChanOpen->CodecConfig.ulAdpcmNibblePosition = f_pChanEntry->CodecConfig.byAdpcmNibblePosition; /*======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiRetrieveNlpConfDword Description: This function is used by the API to store on a per channel basis the various confguration DWORD from the device. The API performs less read to the chip that way since it is always in synch with the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChanEntry Pointer to an API channel structure.. f_ulAddress Address that needs to be modified.. f_pulConfigDword Pointer to the content stored in the API located at the desired address. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiRetrieveNlpConfDword UINT32 Oct6100ApiRetrieveNlpConfDword( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_CHANNEL f_pChanEntry, IN UINT32 f_ulAddress, OUT PUINT32 f_pulConfigDword ) { UINT32 ulResult; UINT32 ulFirstEmptyIndex = 0xFFFFFFFF; UINT32 i; /* Search for the Dword.*/ for ( i = 0; i < cOCT6100_MAX_NLP_CONF_DWORD; i++ ) { if ( ( ulFirstEmptyIndex == 0xFFFFFFFF ) && ( f_pChanEntry->aulNlpConfDword[ i ][ 0 ] == 0x0 ) ) ulFirstEmptyIndex = i; if ( f_pChanEntry->aulNlpConfDword[ i ][ 0 ] == f_ulAddress ) { /* We found the matching Dword.*/ *f_pulConfigDword = f_pChanEntry->aulNlpConfDword[ i ][ 1 ]; return cOCT6100_ERR_OK; } } if ( i == cOCT6100_MAX_NLP_CONF_DWORD && ulFirstEmptyIndex == 0xFFFFFFFF ) return cOCT6100_ERR_FATAL_8E; /* We did not found any entry, let's create a new entry.*/ f_pChanEntry->aulNlpConfDword[ ulFirstEmptyIndex ][ 0 ] = f_ulAddress; /* Read the DWORD where the field is located.*/ ulResult = Oct6100ApiReadDword( f_pApiInstance, f_ulAddress, f_pulConfigDword ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiSaveNlpConfDword Description: This function stores a configuration Dword within an API channel structure and then writes it into the chip. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChanEntry Pointer to an API channel structure.. f_ulAddress Address that needs to be modified.. f_pulConfigDword content to be stored in the API located at the desired address. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiSaveNlpConfDword UINT32 Oct6100ApiSaveNlpConfDword( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_API_CHANNEL f_pChanEntry, IN UINT32 f_ulAddress, IN UINT32 f_ulConfigDword ) { UINT32 ulResult; UINT32 i; /* Search for the Dword.*/ for ( i = 0; i < cOCT6100_MAX_NLP_CONF_DWORD; i++ ) { if ( f_pChanEntry->aulNlpConfDword[ i ][ 0 ] == f_ulAddress ) { /* We found the matching Dword.*/ f_pChanEntry->aulNlpConfDword[ i ][ 1 ] = f_ulConfigDword; break; } } if ( i == cOCT6100_MAX_NLP_CONF_DWORD ) return cOCT6100_ERR_FATAL_8F; /* Write the config DWORD.*/ ulResult = Oct6100ApiWriteDword( f_pApiInstance, f_ulAddress, f_ulConfigDword ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelCreateBiDirSer Description: Creates a bidirectional echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelCreateBiDir Pointer to a create bidirectionnal channel structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelCreateBiDirSer UINT32 Oct6100ChannelCreateBiDirSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir ) { UINT16 usFirstChanIndex; UINT16 usFirstChanExtraTsiIndex; UINT16 usFirstChanSinCopyEventIndex; UINT16 usFirstChanSoutCopyEventIndex; UINT16 usSecondChanIndex; UINT16 usSecondChanExtraTsiIndex; UINT16 usSecondChanSinCopyEventIndex; UINT16 usSecondChanSoutCopyEventIndex; UINT16 usBiDirChanIndex; UINT32 ulResult; /* Check the user's configuration of the bidir channel for errors. */ ulResult = Oct6100ApiCheckChannelCreateBiDirParams( f_pApiInstance, f_pChannelCreateBiDir, &usFirstChanIndex, &usFirstChanExtraTsiIndex, &usFirstChanSinCopyEventIndex, &usSecondChanIndex, &usSecondChanExtraTsiIndex, &usSecondChanSinCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the bidir channel. */ ulResult = Oct6100ApiReserveChannelCreateBiDirResources(f_pApiInstance, &usBiDirChanIndex, &usFirstChanExtraTsiIndex, &usFirstChanSinCopyEventIndex, &usFirstChanSoutCopyEventIndex, &usSecondChanExtraTsiIndex, &usSecondChanSinCopyEventIndex, &usSecondChanSoutCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write all necessary structures to activate the echo cancellation channel. */ ulResult = Oct6100ApiWriteChannelCreateBiDirStructs( f_pApiInstance, usFirstChanIndex, usFirstChanExtraTsiIndex, usFirstChanSinCopyEventIndex, usFirstChanSoutCopyEventIndex, usSecondChanIndex, usSecondChanExtraTsiIndex, usSecondChanSinCopyEventIndex, usSecondChanSoutCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the new echo cancellation channels's entry in the ECHO channel list. */ ulResult = Oct6100ApiUpdateBiDirChannelEntry( f_pApiInstance, f_pChannelCreateBiDir, usBiDirChanIndex, usFirstChanIndex, usFirstChanExtraTsiIndex, usFirstChanSinCopyEventIndex, usFirstChanSoutCopyEventIndex, usSecondChanIndex, usSecondChanExtraTsiIndex, usSecondChanSinCopyEventIndex, usSecondChanSoutCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckChannelCreateBiDirParams Description: Checks the user's parameter passed to the create bidirectional channel function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelCreateBiDir Pointer to a create bidirectionnal channel structure. f_pusFirstChanIndex Pointer to the first channel index. f_pusFirstChanExtraTsiIndex Pointer to the first channel extra TSI index. f_pusFirstChanSinCopyEventIndex Pointer to the first channel Sin copy event index. f_pusSecondChanIndex Pointer to the second channel index. f_pusSecondChanExtraTsiIndex Pointer to the second channel extra TSI index. f_pusSecondChanSinCopyEventIndex Pointer to the second channel Sin copy event index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckChannelCreateBiDirParams UINT32 Oct6100ApiCheckChannelCreateBiDirParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir, OUT PUINT16 f_pusFirstChanIndex, OUT PUINT16 f_pusFirstChanExtraTsiIndex, OUT PUINT16 f_pusFirstChanSinCopyEventIndex, OUT PUINT16 f_pusSecondChanIndex, OUT PUINT16 f_pusSecondChanExtraTsiIndex, OUT PUINT16 f_pusSecondChanSinCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pFirstChanEntry; tPOCT6100_API_CHANNEL pSecondChanEntry; UINT32 ulEntryOpenCnt; BOOL fCheckTssts = TRUE; /* Obtain shared resources pointer.*/ pSharedInfo = f_pApiInstance->pSharedInfo; /* validate the bidirectional channel handle memory.*/ if ( f_pChannelCreateBiDir->pulBiDirChannelHndl == NULL ) return cOCT6100_ERR_CHANNEL_BIDIR_CHANNEL_HANDLE; /* Check if bi-dir channels are activated. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxBiDirChannels == 0 ) return cOCT6100_ERR_CHANNEL_BIDIR_DISABLED; /*=======================================================================*/ /* Verify the first channel handle. */ if ( (f_pChannelCreateBiDir->ulFirstChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_BIDIR_FIRST_CHANNEL_HANDLE; *f_pusFirstChanIndex = (UINT16)( f_pChannelCreateBiDir->ulFirstChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusFirstChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_BIDIR_FIRST_CHANNEL_HANDLE; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pFirstChanEntry, *f_pusFirstChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelCreateBiDir->ulFirstChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pFirstChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pFirstChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_BIDIR_FIRST_CHANNEL_HANDLE; /* Check the specific state of the channel.*/ if ( pFirstChanEntry->fRinRoutCodecActive == TRUE && pFirstChanEntry->CodecConfig.byEncoderPort != cOCT6100_CHANNEL_PORT_ROUT) return cOCT6100_ERR_CHANNEL_CODEC_ACTIVATED; if ( pFirstChanEntry->fSinSoutCodecActive == TRUE && pFirstChanEntry->CodecConfig.byEncoderPort != cOCT6100_CHANNEL_PORT_SOUT) return cOCT6100_ERR_CHANNEL_CODEC_ACTIVATED; if ( pFirstChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CHANNEL_ALREADY_BIDIR; if ( pFirstChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_FIRST_CHAN_IN_CONFERENCE; if ( fCheckTssts == TRUE ) { if ( pFirstChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_FIRST_CHAN_SOUT_PORT; if ( pFirstChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_FIRST_CHAN_RIN_PORT; } /* Return the desired info.*/ *f_pusFirstChanExtraTsiIndex = pFirstChanEntry->usExtraSinTsiMemIndex; *f_pusFirstChanSinCopyEventIndex = pFirstChanEntry->usSinCopyEventIndex; /*=======================================================================*/ /*=======================================================================*/ /* Verify the second channel handle. */ if ( (f_pChannelCreateBiDir->ulSecondChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_BIDIR_SECOND_CHANNEL_HANDLE; *f_pusSecondChanIndex = (UINT16)( f_pChannelCreateBiDir->ulSecondChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusSecondChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_BIDIR_SECOND_CHANNEL_HANDLE; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSecondChanEntry, *f_pusSecondChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelCreateBiDir->ulSecondChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pSecondChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pSecondChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_BIDIR_SECOND_CHANNEL_HANDLE; /* Check the specific state of the channel.*/ if ( pSecondChanEntry->fRinRoutCodecActive == TRUE && pSecondChanEntry->CodecConfig.byEncoderPort != cOCT6100_CHANNEL_PORT_ROUT) return cOCT6100_ERR_CHANNEL_CODEC_ACTIVATED; if ( pSecondChanEntry->fSinSoutCodecActive == TRUE && pSecondChanEntry->CodecConfig.byEncoderPort != cOCT6100_CHANNEL_PORT_SOUT) { return cOCT6100_ERR_CHANNEL_CODEC_ACTIVATED; } if ( pSecondChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CHANNEL_ALREADY_BIDIR; if ( fCheckTssts == TRUE ) { if ( pSecondChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_SECOND_CHAN_SOUT_PORT; if ( pSecondChanEntry->usRinTsstIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_SECOND_CHAN_RIN_PORT; } if ( pSecondChanEntry->usBridgeIndex != cOCT6100_INVALID_INDEX ) return cOCT6100_ERR_CHANNEL_SECOND_CHAN_IN_CONFERENCE; /* Return the desired info.*/ *f_pusSecondChanExtraTsiIndex = pSecondChanEntry->usExtraSinTsiMemIndex; *f_pusSecondChanSinCopyEventIndex = pSecondChanEntry->usSinCopyEventIndex; /*=======================================================================*/ /* Check the law compatibility.*/ if ( pFirstChanEntry->TdmConfig.bySoutPcmLaw != pSecondChanEntry->TdmConfig.byRinPcmLaw || pFirstChanEntry->TdmConfig.byRinPcmLaw != pSecondChanEntry->TdmConfig.bySoutPcmLaw ) return cOCT6100_ERR_CHANNEL_BIDIR_PCM_LAW; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveChannelCreateBiDirResources Description: Reserves all resources needed for the new bidirectional channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusBiDirChanIndex Pointer to the index of the bidirectionnal channel within the API instance. f_pusFirstChanExtraTsiIndex Pointer to the first channel extra TSI index. f_pusFirstChanSinCopyEventIndex Pointer to the first channel Sin copy event index. f_pusFirstChanSoutCopyEventIndex Pointer to the first channel Sout copy event index. f_pusSecondChanExtraTsiIndex Pointer to the second channel extra TSI index. f_pusSecondChanSinCopyEventIndex Pointer to the second channel Sin copy event index. f_pusSecondChanSoutCopyEventIndex Pointer to the second channel Sout copy event index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveChannelCreateBiDirResources UINT32 Oct6100ApiReserveChannelCreateBiDirResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusBiDirChanIndex, IN OUT PUINT16 f_pusFirstChanExtraTsiIndex, IN OUT PUINT16 f_pusFirstChanSinCopyEventIndex, OUT PUINT16 f_pusFirstChanSoutCopyEventIndex, IN OUT PUINT16 f_pusSecondChanExtraTsiIndex, IN OUT PUINT16 f_pusSecondChanSinCopyEventIndex, OUT PUINT16 f_pusSecondChanSoutCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult = cOCT6100_ERR_OK; UINT32 ulTempVar; BOOL fBiDirChanIndex = FALSE; BOOL fFirstExtraTsi = FALSE; BOOL fSecondExtraTsi = FALSE; BOOL fFirstSinCopyEvent = FALSE; BOOL fSecondSinCopyEvent = FALSE; BOOL fFirstSoutCopyEvent = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /*===============================================================================*/ /* Verify and reserve the resources that might already by allocated. */ { if ( *f_pusFirstChanExtraTsiIndex == cOCT6100_INVALID_INDEX ) { /* Reserve the first Extra TSI memory entry */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, f_pusFirstChanExtraTsiIndex ); if ( ulResult == cOCT6100_ERR_OK ) fFirstExtraTsi = TRUE; } if ( *f_pusFirstChanSinCopyEventIndex == cOCT6100_INVALID_INDEX && ulResult == cOCT6100_ERR_OK ) { /* Reserve the Sin copy event for the first channel.*/ ulResult = Oct6100ApiReserveMixerEventEntry ( f_pApiInstance, f_pusFirstChanSinCopyEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) fFirstSinCopyEvent = TRUE; } } if ( *f_pusSecondChanExtraTsiIndex == cOCT6100_INVALID_INDEX && ulResult == cOCT6100_ERR_OK ) { /* Reserve the second Extra TSI memory entry */ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, f_pusSecondChanExtraTsiIndex ); if ( ulResult == cOCT6100_ERR_OK ) fSecondExtraTsi = TRUE; } if ( *f_pusSecondChanSinCopyEventIndex == cOCT6100_INVALID_INDEX && ulResult == cOCT6100_ERR_OK ) { /* Reserve the Sin copy event for the second channel.*/ ulResult = Oct6100ApiReserveMixerEventEntry ( f_pApiInstance, f_pusSecondChanSinCopyEventIndex ); if ( ulResult == cOCT6100_ERR_OK ) fSecondSinCopyEvent = TRUE; } /*===============================================================================*/ /*===============================================================================*/ /* Now reserve all the resources specific to bidirectional channels */ if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReserveBiDirChanEntry( f_pApiInstance, f_pusBiDirChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fBiDirChanIndex = TRUE; { /* Reserve the first channel Sout copy mixer event.*/ ulResult = Oct6100ApiReserveMixerEventEntry ( f_pApiInstance, f_pusFirstChanSoutCopyEventIndex ); } if ( ulResult == cOCT6100_ERR_OK ) { fFirstSoutCopyEvent = TRUE; /* Reserve the second channel Sout copy mixer event.*/ ulResult = Oct6100ApiReserveMixerEventEntry ( f_pApiInstance, f_pusSecondChanSoutCopyEventIndex ); } } } /*===============================================================================*/ /*===============================================================================*/ /* Release the resources if something went wrong */ if ( ulResult != cOCT6100_ERR_OK ) { /*===============================================================================*/ /* Release the previously reserved echo resources .*/ if ( fBiDirChanIndex == TRUE ) { ulTempVar = Oct6100ApiReleaseBiDirChanEntry( f_pApiInstance, *f_pusBiDirChanIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fFirstExtraTsi == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, *f_pusFirstChanExtraTsiIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fSecondExtraTsi == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, *f_pusSecondChanExtraTsiIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fFirstSinCopyEvent == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusFirstChanSinCopyEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( fSecondSinCopyEvent == TRUE ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusSecondChanSinCopyEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if ( ( fFirstSoutCopyEvent == TRUE ) ) { ulTempVar = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, *f_pusFirstChanSoutCopyEventIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } /*===============================================================================*/ return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteChannelCreateBiDirStructs Description: Performs all the required structure writes to configure the new echo cancellation channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usFirstChanIndex Pointer to the first channel index. f_usFirstChanExtraTsiIndex Pointer to the first channel extra TSI index. f_usFirstChanSinCopyEventIndex Pointer to the first channel Sin copy event index. f_usFirstChanSoutCopyEventIndex Pointer to the first channel Sout copy event index. f_usFirstChanIndex Pointer to the second channel index. f_usSecondChanExtraTsiIndex Pointer to the second channel extra TSI index. f_usSecondChanSinCopyEventIndex Pointer to the second channel Sin copy event index. f_usSecondChanSoutCopyEventIndex Pointer to the second channel Sout copy event index. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteChannelCreateBiDirStructs UINT32 Oct6100ApiWriteChannelCreateBiDirStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usFirstChanExtraTsiIndex, IN UINT16 f_usFirstChanSinCopyEventIndex, IN UINT16 f_usFirstChanSoutCopyEventIndex, IN UINT16 f_usSecondChanIndex, IN UINT16 f_usSecondChanExtraTsiIndex, IN UINT16 f_usSecondChanSinCopyEventIndex, IN UINT16 f_usSecondChanSoutCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pFirstChanEntry; tPOCT6100_API_CHANNEL pSecondChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*==============================================================================*/ /* Get a pointer to the two channel entry.*/ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pFirstChanEntry, f_usFirstChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSecondChanEntry, f_usSecondChanIndex ); { /*==============================================================================*/ /* Configure the Tsst control memory and add the Sin copy event if necessary. */ /*=======================================================================*/ /* Program the Sin Copy event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usFirstChanSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= f_usFirstChanExtraTsiIndex; WriteParams.usWriteData |= pFirstChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( pFirstChanEntry->usSinSoutTsiMemIndex ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Configure the TSST memory.*/ if ( pFirstChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pFirstChanEntry->usSinTsstIndex, f_usFirstChanExtraTsiIndex, pFirstChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now insert the event into the event list.*/ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usFirstChanSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usFirstChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ } /*==============================================================================*/ /* Configure the Tsst control memory and add the Sin copy event if necessary.*/ /*=======================================================================*/ /* Program the Sin Copy event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSecondChanSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= f_usSecondChanExtraTsiIndex; WriteParams.usWriteData |= pSecondChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = (UINT16)( pSecondChanEntry->usSinSoutTsiMemIndex ); mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Configure the TSST memory.*/ if ( pSecondChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pSecondChanEntry->usSinTsstIndex, f_usSecondChanExtraTsiIndex, pSecondChanEntry->TdmConfig.bySinPcmLaw ); } if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now insert the event into the event list.*/ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usSecondChanSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY, f_usSecondChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Now, let's configure the two Sout copy events.*/ /* First event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usFirstChanSoutCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= pFirstChanEntry->usSinSoutTsiMemIndex; WriteParams.usWriteData |= pFirstChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pSecondChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usFirstChanSoutCopyEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY, f_usFirstChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Second event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( f_usSecondChanSoutCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= pSecondChanEntry->usSinSoutTsiMemIndex; WriteParams.usWriteData |= pSecondChanEntry->TdmConfig.bySoutPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pFirstChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, f_usSecondChanSoutCopyEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY, f_usSecondChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Clear + release the silence events if they were created. */ if ( pFirstChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pFirstChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pFirstChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E0; pFirstChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } if ( ( pSecondChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pSecondChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pSecondChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E0; pSecondChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateBiDirChannelEntry Description: Updates the new bidir channel and the channel used to create that channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateBiDirChannelEntry UINT32 Oct6100ApiUpdateBiDirChannelEntry( IN tPOCT6100_INSTANCE_API f_pApiInstance, OUT tPOCT6100_CHANNEL_CREATE_BIDIR f_pChannelCreateBiDir, IN UINT16 f_usBiDirChanIndex, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usFirstChanExtraTsiIndex, IN UINT16 f_usFirstChanSinCopyEventIndex, IN UINT16 f_usFirstChanSoutCopyEventIndex, IN UINT16 f_usSecondChanIndex, IN UINT16 f_usSecondChanExtraTsiIndex, IN UINT16 f_usSecondChanSinCopyEventIndex, IN UINT16 f_usSecondChanSoutCopyEventIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pFirstChanEntry; tPOCT6100_API_CHANNEL pSecondChanEntry; tPOCT6100_API_BIDIR_CHANNEL pBiDirChanEntry; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_BIDIR_CHANNEL_ENTRY_PNT( pSharedInfo, pBiDirChanEntry, f_usBiDirChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pFirstChanEntry, f_usFirstChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSecondChanEntry, f_usSecondChanIndex ); /*=======================================================================*/ /* Copy the channel's configuration and allocated resources. */ pFirstChanEntry->usExtraSinTsiMemIndex = f_usFirstChanExtraTsiIndex; pFirstChanEntry->usSinCopyEventIndex = f_usFirstChanSinCopyEventIndex; pFirstChanEntry->usSoutCopyEventIndex = f_usFirstChanSoutCopyEventIndex; pSecondChanEntry->usExtraSinTsiMemIndex = f_usSecondChanExtraTsiIndex; pSecondChanEntry->usSinCopyEventIndex = f_usSecondChanSinCopyEventIndex; pSecondChanEntry->usSoutCopyEventIndex = f_usSecondChanSoutCopyEventIndex; /* Save the channel info in the bidir channel.*/ pBiDirChanEntry->usFirstChanIndex = f_usFirstChanIndex; pBiDirChanEntry->usSecondChanIndex = f_usSecondChanIndex; /* Increment the extra TSI memory dependency count.*/ pFirstChanEntry->usExtraSinTsiDependencyCnt++; pSecondChanEntry->usExtraSinTsiDependencyCnt++; /* Set the bidir flag in the channel structure.*/ pFirstChanEntry->fBiDirChannel = TRUE; pSecondChanEntry->fBiDirChannel = TRUE; /*=======================================================================*/ /* Form handle returned to user. */ *f_pChannelCreateBiDir->pulBiDirChannelHndl = cOCT6100_HNDL_TAG_BIDIR_CHANNEL | (pBiDirChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usBiDirChanIndex; /* Finally, mark the channel as open. */ pBiDirChanEntry->fReserved = TRUE; /* Increment the number of channel open.*/ f_pApiInstance->pSharedInfo->ChipStats.usNumberBiDirChannels++; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelDestroyBiDirSer Description: Closes a bidirectional channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelDestroyBiDir Pointer to a destroy bidirectionnal channel structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelDestroyBiDirSer UINT32 Oct6100ChannelDestroyBiDirSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir ) { UINT16 usBiDirChanIndex; UINT16 usFirstChanIndex; UINT16 usSecondChanIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertDestroyBiDirChanParams( f_pApiInstance, f_pChannelDestroyBiDir, &usBiDirChanIndex, &usFirstChanIndex, &usSecondChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiInvalidateBiDirChannelStructs( f_pApiInstance, usFirstChanIndex, usSecondChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the echo cancellation channel. */ ulResult = Oct6100ApiReleaseBiDirChannelResources( f_pApiInstance, usBiDirChanIndex, usFirstChanIndex, usSecondChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle.*/ f_pChannelDestroyBiDir->ulBiDirChannelHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertDestroyBiDirChanParams Description: Validate the handle given by the user and verify the state of the channel about to be closed. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelDestroyBiDir Pointer to a destroy bidirectional channel structure. f_pusBiDirChanIndex Pointer to the bidir channel entry within the API's list. f_pusFirstChanIndex Pointer to the first channel index part of the bidir channel. f_pusFirstChanIndex Pointer to the second channel index part of the bidir channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertDestroyBiDirChanParams UINT32 Oct6100ApiAssertDestroyBiDirChanParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_DESTROY_BIDIR f_pChannelDestroyBiDir, IN OUT PUINT16 f_pusBiDirChanIndex, IN OUT PUINT16 f_pusFirstChanIndex, IN OUT PUINT16 f_pusSecondChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BIDIR_CHANNEL pBiDirChanEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pChannelDestroyBiDir->ulBiDirChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_BIDIR_CHANNEL ) return cOCT6100_ERR_CHANNEL_BIDIR_CHANNEL_HANDLE; *f_pusBiDirChanIndex = (UINT16)( f_pChannelDestroyBiDir->ulBiDirChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusBiDirChanIndex >= pSharedInfo->ChipConfig.usMaxBiDirChannels ) return cOCT6100_ERR_CHANNEL_BIDIR_CHANNEL_HANDLE; /*=======================================================================*/ /* Get a pointer to the bidir channel's list entry. */ mOCT6100_GET_BIDIR_CHANNEL_ENTRY_PNT( pSharedInfo, pBiDirChanEntry, *f_pusBiDirChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelDestroyBiDir->ulBiDirChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pBiDirChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_BIDIR_CHAN_NOT_OPEN; if ( ulEntryOpenCnt != pBiDirChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_BIDIR_CHANNEL_HANDLE; /*=======================================================================*/ /* Return the index of the channel used to create this bidirectional channel.*/ *f_pusFirstChanIndex = pBiDirChanEntry->usFirstChanIndex; *f_pusSecondChanIndex = pBiDirChanEntry->usSecondChanIndex; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateBiDirChannelStructs Description: Destroy the link between the two channels. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateBiDirChannelStructs UINT32 Oct6100ApiInvalidateBiDirChannelStructs( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usSecondChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pFirstChanEntry; tPOCT6100_API_CHANNEL pSecondChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get pointers to the API entry of the two channel used to create the bidir channel.*/ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pFirstChanEntry, f_usFirstChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSecondChanEntry, f_usSecondChanIndex ); /* Clear the SIN copy event of the first channel and release the Extra TSI memory if this feature was the only one using it. */ { if ( pFirstChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /*=======================================================================*/ /* Clear the Sin Copy event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pFirstChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Configure the TSST memory.*/ if ( pFirstChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pFirstChanEntry->usSinTsstIndex, pFirstChanEntry->usSinSoutTsiMemIndex, pFirstChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pFirstChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Clear the SIN copy event of the first channel and release the Extra TSI memory if this feature was the only one using it. */ if ( pSecondChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /*=======================================================================*/ /* Clear the Sin Copy event.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSecondChanEntry->usSinCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Configure the TSST memory.*/ if ( pSecondChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, pSecondChanEntry->usSinTsstIndex, pSecondChanEntry->usSinSoutTsiMemIndex, pSecondChanEntry->TdmConfig.bySinPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pSecondChanEntry->usSinCopyEventIndex, cOCT6100_EVENT_TYPE_SIN_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now remove the sout copy of the first channel.*/ { /*=======================================================================*/ /* Clear the Sout Copy event of the first channel.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pFirstChanEntry->usSoutCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pFirstChanEntry->usSoutCopyEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Now remove the sout copy of the second channel.*/ /*=======================================================================*/ /* Clear the Sout Copy event of the second channel.*/ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSecondChanEntry->usSoutCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_NO_OP; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pSecondChanEntry->usSoutCopyEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseBiDirChannelResources Description: Release and clear the API entry associated to the bidirectional channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usBiDirChanIndex Index of the bidirectionnal channel in the API's bidir channel list. f_usFirstChanIndex Index of the first channel used to create the bidir channel. f_usSecondChanIndex Index of the second channel used to create the bidir channel. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseBiDirChannelResources UINT32 Oct6100ApiReleaseBiDirChannelResources( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usBiDirChanIndex, IN UINT16 f_usFirstChanIndex, IN UINT16 f_usSecondChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_BIDIR_CHANNEL pBiDirChanEntry; tPOCT6100_API_CHANNEL pFirstChanEntry; tPOCT6100_API_CHANNEL pSecondChanEntry; tPOCT6100_API_MIXER_EVENT pTempEventEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_BIDIR_CHANNEL_ENTRY_PNT( pSharedInfo, pBiDirChanEntry, f_usBiDirChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pFirstChanEntry, f_usFirstChanIndex ); mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pSecondChanEntry, f_usSecondChanIndex ); /* Release the bidir entry.*/ ulResult = Oct6100ApiReleaseBiDirChanEntry( f_pApiInstance, f_usBiDirChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_AC; /* Release the Extra TSI memory and the SIN copy event if required.*/ { if ( pFirstChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the two TSI chariot memory entries.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pFirstChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A3; /* Relese the SIN copy event.*/ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pFirstChanEntry->usSinCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A4; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, pFirstChanEntry->usSinCopyEventIndex ); /* Invalidate the entry.*/ pTempEventEntry->fReserved = FALSE; pTempEventEntry->usEventType = cOCT6100_INVALID_EVENT; pTempEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; pFirstChanEntry->usExtraSinTsiDependencyCnt--; pFirstChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; pFirstChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; } else { pFirstChanEntry->usExtraSinTsiDependencyCnt--; } } if ( pSecondChanEntry->usExtraSinTsiDependencyCnt == 1 ) { /* Release the two TSI chariot memory entries.*/ ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pSecondChanEntry->usExtraSinTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A5; /* Relese the SIN copy event.*/ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pSecondChanEntry->usSinCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A6; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, pSecondChanEntry->usSinCopyEventIndex ); /* Invalidate the entry.*/ pTempEventEntry->fReserved = FALSE; pTempEventEntry->usEventType = cOCT6100_INVALID_EVENT; pTempEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; pSecondChanEntry->usExtraSinTsiDependencyCnt--; pSecondChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX; pSecondChanEntry->usSinCopyEventIndex = cOCT6100_INVALID_INDEX; } else { pSecondChanEntry->usExtraSinTsiDependencyCnt--; } { /* Release the SOUT copy event of the first channel.*/ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pFirstChanEntry->usSoutCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A7; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, pFirstChanEntry->usSoutCopyEventIndex ); /* Invalidate the entry.*/ pTempEventEntry->fReserved = FALSE; pTempEventEntry->usEventType = cOCT6100_INVALID_EVENT; pTempEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; } /* Release the SOUT copy event of the second channel.*/ ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pSecondChanEntry->usSoutCopyEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_A8; mOCT6100_GET_MIXER_EVENT_ENTRY_PNT( pSharedInfo, pTempEventEntry, pSecondChanEntry->usSoutCopyEventIndex ); /* Invalidate the entry.*/ pTempEventEntry->fReserved = FALSE; pTempEventEntry->usEventType = cOCT6100_INVALID_EVENT; pTempEventEntry->usNextEventPtr = cOCT6100_INVALID_INDEX; /*=======================================================================*/ /* Update the first channel's list entry. */ /* Mark the channel as closed. */ pFirstChanEntry->usSoutCopyEventIndex = cOCT6100_INVALID_INDEX; pFirstChanEntry->fBiDirChannel = FALSE; /*=======================================================================*/ /*=======================================================================*/ /* Update the second channel's list entry. */ /* Mark the channel as closed. */ pSecondChanEntry->usSoutCopyEventIndex = cOCT6100_INVALID_INDEX; pSecondChanEntry->fBiDirChannel = FALSE; /*=======================================================================*/ /*=======================================================================*/ /* Update the bidirectional channel's list entry. */ /* Mark the channel as closed. */ pBiDirChanEntry->fReserved = FALSE; pBiDirChanEntry->byEntryOpenCnt++; pBiDirChanEntry->usFirstChanIndex = cOCT6100_INVALID_INDEX; pBiDirChanEntry->usSecondChanIndex = cOCT6100_INVALID_INDEX; /* Decrement the number of channel open.*/ f_pApiInstance->pSharedInfo->ChipStats.usNumberBiDirChannels--; /*=======================================================================*/ /*=======================================================================*/ /* Check if some of the ports must be muted back. */ ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usFirstChanIndex, pFirstChanEntry->usRinTsstIndex, pFirstChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usSecondChanIndex, pSecondChanEntry->usRinTsstIndex, pSecondChanEntry->usSinTsstIndex, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100ApiOctFloatToDbEnergyByte INT32 Oct6100ApiOctFloatToDbEnergyByte(UINT8 x) { INT32 lResult; lResult = Oct6100ApiOctFloatToDbEnergyHalf( (UINT16)(x << 8) ); return lResult; } #endif #if !SKIP_Oct6100ApiOctFloatToDbEnergyHalf INT32 Oct6100ApiOctFloatToDbEnergyHalf(UINT16 x) { INT32 y; UINT16 m; y = (((x >> 8) & 0x7F) - 0x41) * 3; m = (UINT16)((x & 0x00E0) >> 5); if (m < 2) y += 0; else if (m < 5) y += 1; else y += 2; return y; } #endif #if !SKIP_Oct6100ApiDbAmpHalfToOctFloat UINT16 Oct6100ApiDbAmpHalfToOctFloat(INT32 x) { INT32 db_div6; INT32 db_mod6; UINT16 rval; INT32 x_unsigned; if(x < 0) { x_unsigned = -x; } else { x_unsigned = x; } db_div6 = x_unsigned / 6; db_mod6 = x_unsigned % 6; if(x < 0) { if(db_mod6 == 0) { /* Change nothing! */ db_div6 = -db_div6; } else { /* When we are negative, round down, and then adjust modulo. For example, if x is -1, then db_div6 is 0 and db_mod6 is 1. We adjust so db_div6 = -1 and db_mod6 = 5, which gives the correct adjustment. */ db_div6 = -db_div6-1; db_mod6 = 6 - db_mod6; } } rval = (UINT16)(0x4100 + db_div6 * 0x100); if(db_mod6 == 0) { rval += 0x0000; } else if(db_mod6 == 1) { rval += 0x0020; } else if(db_mod6 == 2) { rval += 0x0040; } else if(db_mod6 == 3) { rval += 0x0070; } else if(db_mod6 == 4) { rval += 0x0090; } else /* if(db_mod6 == 5) */ { rval += 0x00D0; } return rval; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteDebugChanMemory Description: This function configure a debug channel echo memory entry in internal memory.and external memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pTdmConfig Pointer to a TDM configuration structure. f_pVqeConfig Pointer to a VQE configuration structure. f_pChannelOpen Pointer to a channel configuration structure. f_usChanIndex Index of the echo channel in the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_usRinRoutTsiIndex RIN/ROUT TSI index within the TSI chariot memory. f_usSinSoutTsiIndex SIN/SOUT TSI index within the TSI chariot memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteDebugChanMemory UINT32 Oct6100ApiWriteDebugChanMemory( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_TDM f_pTdmConfig, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN tPOCT6100_CHANNEL_OPEN f_pChannelOpen, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN UINT16 f_usRinRoutTsiIndex, IN UINT16 f_usSinSoutTsiIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; /* Obtain pointer to local portion of the instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /*==============================================================================*/ /* Write the VQE configuration of the debug channel. */ ulResult = Oct6100ApiWriteVqeMemory( f_pApiInstance, f_pVqeConfig, f_pChannelOpen, f_usChanIndex, f_usEchoMemIndex, TRUE, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ /*==============================================================================*/ /* Write the echo memory configuration of the debug channel. */ ulResult = Oct6100ApiWriteEchoMemory( f_pApiInstance, f_pTdmConfig, f_pChannelOpen, f_usEchoMemIndex, f_usRinRoutTsiIndex, f_usSinSoutTsiIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*==============================================================================*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiDebugChannelOpen Description: Internal function used to open a debug channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiDebugChannelOpen UINT32 Oct6100ApiDebugChannelOpen( IN tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_CHANNEL_OPEN TempChanOpen; UINT32 ulResult; UINT16 usChanIndex; UINT16 usDummyEchoIndex; pSharedInfo = f_pApiInstance->pSharedInfo; /* Let's program the channel memory.*/ Oct6100ChannelOpenDef( &TempChanOpen ); TempChanOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_HT_RESET; /* Activate the channel in reset.*/ TempChanOpen.VqeConfig.fEnableNlp = FALSE; TempChanOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL; TempChanOpen.VqeConfig.fSinDcOffsetRemoval = FALSE; TempChanOpen.VqeConfig.fRinDcOffsetRemoval = FALSE; TempChanOpen.VqeConfig.lDefaultErlDb = 0; /* Loop to reserve the proper entry for the debug channel */ for( usChanIndex = 0; usChanIndex < ( pSharedInfo->DebugInfo.usRecordChanIndex + 1 ); usChanIndex ++ ) { ulResult = Oct6100ApiReserveEchoEntry( f_pApiInstance, &usDummyEchoIndex ); if( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Loop to free all entries except the one for the debug channel */ for( usChanIndex = pSharedInfo->DebugInfo.usRecordChanIndex; usChanIndex > 0; ) { usChanIndex--; ulResult = Oct6100ApiReleaseEchoEntry( f_pApiInstance, usChanIndex ); if( ulResult != cOCT6100_ERR_OK ) return ulResult; } ulResult = Oct6100ApiWriteDebugChanMemory( f_pApiInstance, &TempChanOpen.TdmConfig, &TempChanOpen.VqeConfig, &TempChanOpen, pSharedInfo->DebugInfo.usRecordChanIndex, pSharedInfo->DebugInfo.usRecordMemIndex, pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex, pSharedInfo->DebugInfo.usRecordSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMuteChannelPort Description: This function will verify if a input TSST is bound to the RIN and SIN port. If not, the port will be muted. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMutePorts UINT32 Oct6100ApiMutePorts( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usEchoIndex, IN UINT16 f_usRinTsstIndex, IN UINT16 f_usSinTsstIndex, IN BOOL f_fCheckBridgeIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Obtain a pointer to the new buffer's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usEchoIndex ); /* Mute the Rin port. */ if ( ( f_fCheckBridgeIndex == FALSE ) || ( ( f_fCheckBridgeIndex == TRUE ) && ( pChanEntry->usBridgeIndex == cOCT6100_INVALID_INDEX ) ) ) { /* If the channel is in bidir mode, do not create the Rin silence event!!! */ if ( pChanEntry->fBiDirChannel == FALSE ) { if ( ( ( f_usRinTsstIndex == cOCT6100_INVALID_INDEX ) || ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_RIN ) != 0x0 ) ) && ( pChanEntry->usRinSilenceEventIndex == cOCT6100_INVALID_INDEX ) ) { ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now, write the mixer event used to copy the RIN signal of the silence channel into the RIN signal of the current channel. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usRinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= 1534; WriteParams.usWriteData |= cOCT6100_PCM_U_LAW << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pChanEntry->usRinRoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Now insert the Sin copy event into the list.*/ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, pChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY, f_usEchoIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Mute the Sin port. */ if ( ( ( f_usSinTsstIndex == cOCT6100_INVALID_INDEX ) || ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) ) && ( pChanEntry->usSinSilenceEventIndex == cOCT6100_INVALID_INDEX ) ) { ulResult = Oct6100ApiReserveMixerEventEntry( f_pApiInstance, &pChanEntry->usSinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Now, write the mixer event used to copy the SIN signal of the silence channel into the SIN signal of the current channel. */ WriteParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pChanEntry->usSinSilenceEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = cOCT6100_MIXER_CONTROL_MEM_COPY; WriteParams.usWriteData |= 1534; WriteParams.usWriteData |= cOCT6100_PCM_U_LAW << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; WriteParams.ulWriteAddress += 2; WriteParams.usWriteData = pChanEntry->usSinSoutTsiMemIndex; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*=======================================================================*/ /*=======================================================================*/ /* Now insert the Sin copy event into the list.*/ ulResult = Oct6100ApiMixerEventAdd( f_pApiInstance, pChanEntry->usSinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY, f_usEchoIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Unmute the Rin port if it was muted. */ if ( ( ( f_usRinTsstIndex != cOCT6100_INVALID_INDEX ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_RIN ) == 0x0 ) ) && ( pChanEntry->usRinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usRinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usRinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E1; pChanEntry->usRinSilenceEventIndex = cOCT6100_INVALID_INDEX; } /* Unmute the Sin port if it was muted. */ if ( ( ( f_usSinTsstIndex != cOCT6100_INVALID_INDEX ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN ) == 0x0 ) ) && ( pChanEntry->usSinSilenceEventIndex != cOCT6100_INVALID_INDEX ) ) { /* Remove the event from the list.*/ ulResult = Oct6100ApiMixerEventRemove( f_pApiInstance, pChanEntry->usSinSilenceEventIndex, cOCT6100_EVENT_TYPE_SOUT_COPY ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; ulResult = Oct6100ApiReleaseMixerEventEntry( f_pApiInstance, pChanEntry->usSinSilenceEventIndex ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_E2; pChanEntry->usSinSilenceEventIndex = cOCT6100_INVALID_INDEX; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiSetChannelLevelControl Description: This function will configure the level control on a given channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig VQE config of the channel. f_usChanIndex Index of the channel within the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_fClearAlcHlcStatusBit If this is set, the ALC-HLC status bit must be incremented. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiSetChannelLevelControl UINT32 Oct6100ApiSetChannelLevelControl( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fClearAlcHlcStatusBit ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; UINT32 ulTempData; UINT32 ulBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; UINT32 i; UINT16 usTempData; UINT8 byLastStatus; BOOL fDisableAlcFirst; /* Get local pointer to shared portion of the API instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a pointer to the channel list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ); /* Before doing anything, check if the configuration has changed. */ if ( ( f_fClearAlcHlcStatusBit == TRUE ) || ( f_pVqeConfig->fRinLevelControl != pChanEntry->VqeConfig.fRinLevelControl ) || ( f_pVqeConfig->lRinLevelControlGainDb != pChanEntry->VqeConfig.chRinLevelControlGainDb ) || ( f_pVqeConfig->fRinAutomaticLevelControl != pChanEntry->VqeConfig.fRinAutomaticLevelControl ) || ( f_pVqeConfig->lRinAutomaticLevelControlTargetDb != pChanEntry->VqeConfig.chRinAutomaticLevelControlTargetDb ) || ( f_pVqeConfig->fRinHighLevelCompensation != pChanEntry->VqeConfig.fRinHighLevelCompensation ) || ( f_pVqeConfig->lRinHighLevelCompensationThresholdDb != pChanEntry->VqeConfig.chRinHighLevelCompensationThresholdDb ) || ( f_pVqeConfig->fSoutLevelControl != pChanEntry->VqeConfig.fSoutLevelControl ) || ( f_pVqeConfig->lSoutLevelControlGainDb != pChanEntry->VqeConfig.chSoutLevelControlGainDb ) || ( f_pVqeConfig->fSoutAutomaticLevelControl != pChanEntry->VqeConfig.fSoutAutomaticLevelControl ) || ( f_pVqeConfig->lSoutAutomaticLevelControlTargetDb != pChanEntry->VqeConfig.chSoutAutomaticLevelControlTargetDb ) || ( f_pVqeConfig->fSoutNaturalListenerEnhancement != pChanEntry->VqeConfig.fSoutNaturalListenerEnhancement ) || ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != pChanEntry->VqeConfig.bySoutAutomaticListenerEnhancementGainDb ) || ( f_pVqeConfig->ulSoutNaturalListenerEnhancementGainDb != pChanEntry->VqeConfig.bySoutNaturalListenerEnhancementGainDb ) ) { /* Calculate base address for manual level control configuration. */ ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; /* Set the Level control on RIN port.*/ ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinLevelControlOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinLevelControlOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinLevelControlOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( ( f_pVqeConfig->fRinLevelControl == TRUE ) || ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) || ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) ) { /* Set the level control value.*/ if ( ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) || ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) ) ulTempData |= ( 0xFF << ulFeatureBitOffset ); else { /* Convert the dB value into OctFloat format.*/ usTempData = Oct6100ApiDbAmpHalfToOctFloat( f_pVqeConfig->lRinLevelControlGainDb ); usTempData -= 0x3800; usTempData &= 0x0FF0; usTempData >>= 4; ulTempData |= ( usTempData << ulFeatureBitOffset ); } } else /* ( ( f_pVqeConfig->fRinLevelControl == FALSE ) && ( f_pVqeConfig->fRinAutomaticLevelControl == FALSE ) && ( f_pVqeConfig->fRinHighLevelCompensation == FALSE ) ) */ { ulTempData |= ( cOCT6100_PASS_THROUGH_LEVEL_CONTROL << ulFeatureBitOffset ); } /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the Level control on SOUT port.*/ ulFeatureBytesOffset = pSharedInfo->MemoryMap.SoutLevelControlOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.SoutLevelControlOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.SoutLevelControlOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( ( f_pVqeConfig->fSoutLevelControl == TRUE ) || ( f_pVqeConfig->fSoutAutomaticLevelControl == TRUE ) || ( f_pVqeConfig->fSoutNaturalListenerEnhancement == TRUE ) || ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != 0x0 ) ) { /* Set the level control value.*/ if ( ( f_pVqeConfig->fSoutAutomaticLevelControl == TRUE ) || ( f_pVqeConfig->fSoutNaturalListenerEnhancement == TRUE ) || ( f_pVqeConfig->ulSoutAutomaticListenerEnhancementGainDb != 0x0 ) ) ulTempData |= ( 0xFF << ulFeatureBitOffset ); else { /* Convert the dB value into OctFloat format.*/ usTempData = Oct6100ApiDbAmpHalfToOctFloat( f_pVqeConfig->lSoutLevelControlGainDb ); usTempData -= 0x3800; usTempData &= 0x0FF0; usTempData >>= 4; ulTempData |= ( usTempData << ulFeatureBitOffset ); } } else { ulTempData |= ( cOCT6100_PASS_THROUGH_LEVEL_CONTROL << ulFeatureBitOffset ); } /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Calculate base address for auto level control + high level compensation configuration. */ ulBaseAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + f_pApiInstance->pSharedInfo->MemoryMap.ulChanMainIoMemOfst; /* Check which one is to be disabled first. */ if ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) fDisableAlcFirst = FALSE; else fDisableAlcFirst = TRUE; for ( i = 0; i < 2; i ++ ) { /* Set the auto level control target Db for the Rin port. */ if ( ( ( i == 0 ) && ( fDisableAlcFirst == TRUE ) ) || ( ( i == 1 ) && ( fDisableAlcFirst == FALSE ) ) ) { if ( pSharedInfo->ImageInfo.fRinAutoLevelControl == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinAutoLevelControlTargetOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinAutoLevelControlTargetOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinAutoLevelControlTargetOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fRinAutomaticLevelControl == TRUE ) { /* Convert the dB value into OctFloat format.*/ usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lRinAutomaticLevelControlTargetDb ); /* Set auto level control target on the Rin port. */ ulTempData |= ( usTempData << ulFeatureBitOffset ); } else /* if ( f_pVqeConfig->fRinAutomaticLevelControl == FALSE ) */ { /* Disable auto level control. */ ulTempData |= ( 0xFFFF << ulFeatureBitOffset ); } /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } else { /* Set the high level compensation threshold Db for the Rin port. */ if ( pSharedInfo->ImageInfo.fRinHighLevelCompensation == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.RinHighLevelCompensationThresholdOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.RinHighLevelCompensationThresholdOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.RinHighLevelCompensationThresholdOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fRinHighLevelCompensation == TRUE ) { /* Convert the dB value into OctFloat format.*/ usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lRinHighLevelCompensationThresholdDb ); /* Set high level compensation threshold on the Rin port. */ ulTempData |= ( usTempData << ulFeatureBitOffset ); } else /* if ( f_pVqeConfig->fRinHighLevelCompensation == FALSE ) */ { /* Disable high level compensation. */ ulTempData |= ( 0xFFFF << ulFeatureBitOffset ); } /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } } /* Set the auto level control target Db for the Sout port. */ if ( pSharedInfo->ImageInfo.fRinAutoLevelControl == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.SoutAutoLevelControlTargetOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.SoutAutoLevelControlTargetOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.SoutAutoLevelControlTargetOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->fSoutAutomaticLevelControl == TRUE ) { /* Convert the dB value into OctFloat format.*/ usTempData = Oct6100ApiDbAmpHalfToOctFloat( 2 * f_pVqeConfig->lSoutAutomaticLevelControlTargetDb ); /* Set auto level control target on the Sout port. */ ulTempData |= ( usTempData << ulFeatureBitOffset ); } else /* if ( f_pVqeConfig->fSoutAutomaticLevelControl == FALSE ) */ { /* Disable auto level control. */ ulTempData |= ( 0xFFFF << ulFeatureBitOffset ); } /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Set the high level compensation threshold Db for the Sout port. */ if ( pSharedInfo->ImageInfo.fSoutHighLevelCompensation == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.SoutHighLevelCompensationThresholdOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.SoutHighLevelCompensationThresholdOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.SoutHighLevelCompensationThresholdOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Disable high level compensation on Sout for now. */ ulTempData |= ( 0xFFFF << ulFeatureBitOffset ); /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Check if have to clear the ALC-HLC status. */ if ( ( pSharedInfo->ImageInfo.fAlcHlcStatus == TRUE ) && ( ( f_fClearAlcHlcStatusBit == TRUE ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AlcHlcStatusOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AlcHlcStatusOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AlcHlcStatusOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Get previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Retrieve last status. */ byLastStatus = (UINT8)( ( ( ulTempData & ulMask ) >> ulFeatureBitOffset ) & 0xFF ); /* Increment to reset context. */ byLastStatus ++; /* Just in case, not to overwrite some context in external memory. */ byLastStatus &= ( 0x1 << ulFeatureFieldLength ) - 1; /* Clear last status. */ ulTempData &= (~ulMask); /* Set new status. */ ulTempData |= ( byLastStatus << ulFeatureBitOffset ); /* Save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiSetChannelTailConfiguration Description: This function will configure the tail displacement and length on a given channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pVqeConfig VQE config of the channel. f_usChanIndex Index of the channel within the API instance. f_usEchoMemIndex Index of the echo channel within the SSPX memory. f_fModifyOnly Function called from a modify or open? \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiSetChannelTailConfiguration UINT32 Oct6100ApiSetChannelTailConfiguration( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_OPEN_VQE f_pVqeConfig, IN UINT16 f_usChanIndex, IN UINT16 f_usEchoMemIndex, IN BOOL f_fModifyOnly ) { tPOCT6100_API_CHANNEL pChanEntry; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; UINT32 ulTempData; UINT32 ulNlpConfBaseAddress; UINT32 ulAfConfBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; UINT32 ulTailSum; BOOL fTailDisplacementModified = FALSE; /* Get local pointer to shared portion of the API instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Obtain a pointer to the channel list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ); /* Calculate base addresses of NLP + AF configuration structure for the specified channel. */ ulNlpConfBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; ulAfConfBaseAddress = pSharedInfo->MemoryMap.ulChanMainMemBase + ( f_usEchoMemIndex * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->MemoryMap.ulChanMainIoMemOfst; /* Set the tail displacement.*/ if ( pSharedInfo->ImageInfo.fTailDisplacement == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->fEnableTailDisplacement != pChanEntry->VqeConfig.fEnableTailDisplacement ) || ( f_pVqeConfig->ulTailDisplacement != pChanEntry->VqeConfig.usTailDisplacement ) || ( f_pVqeConfig->fAcousticEcho != pChanEntry->VqeConfig.fAcousticEcho ) ) ) ) { /* Remember that the tail displacement parameters were changed. */ fTailDisplacementModified = TRUE; /* Check if we must set the tail displacement value. */ if ( ( f_pVqeConfig->fEnableTailDisplacement == TRUE ) && ( pSharedInfo->ImageInfo.fPerChannelTailDisplacement == TRUE ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.PerChanTailDisplacementFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PerChanTailDisplacementFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PerChanTailDisplacementFieldOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( ( f_pVqeConfig->fEnableTailDisplacement == TRUE ) && ( f_pVqeConfig->ulTailDisplacement != 0x0 ) ) { if ( pSharedInfo->ImageInfo.fAfTailDisplacement == FALSE ) { if ( f_pVqeConfig->ulTailDisplacement == cOCT6100_AUTO_SELECT_TAIL ) { ulTempData |= ( ( ( pSharedInfo->ChipConfig.usTailDisplacement / 16 ) ) << ulFeatureBitOffset ); } else { ulTempData |= ( ( ( f_pVqeConfig->ulTailDisplacement / 16 ) ) << ulFeatureBitOffset ); } } else /* if ( pSharedInfo->ImageInfo.fAfTailDisplacement == TRUE ) */ { /* If AEC is not activated, this must be set to the requested tail displacement. */ if ( f_pVqeConfig->fAcousticEcho == FALSE ) { if ( f_pVqeConfig->ulTailDisplacement == cOCT6100_AUTO_SELECT_TAIL ) { ulTailSum = pSharedInfo->ChipConfig.usTailDisplacement; } else { ulTailSum = f_pVqeConfig->ulTailDisplacement; } if ( ulTailSum == 0 ) { ulTempData |= ( ( 0 ) << ulFeatureBitOffset ); } else if ( ulTailSum <= 128 ) { ulTempData |= ( ( 1 ) << ulFeatureBitOffset ); } else if ( ulTailSum <= 384 ) { ulTempData |= ( ( 3 ) << ulFeatureBitOffset ); } else /* if ( ulTailSum <= 896 ) */ { ulTempData |= ( ( 7 ) << ulFeatureBitOffset ); } } else /* if ( f_pVqeConfig->fAcousticEcho == FALSE ) */ { /* Otherwise, the tail displacement is configured differently. This field stays to 0. */ ulTempData |= ( 0x0 << ulFeatureBitOffset ); } } } /* Then save the new DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } if ( pSharedInfo->ImageInfo.fAfTailDisplacement == TRUE ) { /* Set the tail displacement offset in the AF. */ ulFeatureBytesOffset = pSharedInfo->MemoryMap.AfTailDisplacementFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AfTailDisplacementFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AfTailDisplacementFieldOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); if ( f_pVqeConfig->ulTailDisplacement == cOCT6100_AUTO_SELECT_TAIL ) { ulTempData |= ( ( ( pSharedInfo->ChipConfig.usTailDisplacement / 16 ) ) << ulFeatureBitOffset ); } else { ulTempData |= ( ( ( f_pVqeConfig->ulTailDisplacement / 16 ) ) << ulFeatureBitOffset ); } /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } ulFeatureBytesOffset = pSharedInfo->MemoryMap.TailDisplEnableOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.TailDisplEnableOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.TailDisplEnableOfst.byFieldSize; /* First read the DWORD where the field is located.*/ ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); ulTempData |= ( ( (UINT32)f_pVqeConfig->fEnableTailDisplacement ) << ulFeatureBitOffset ); /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Set the tail length. */ if ( pSharedInfo->ImageInfo.fPerChannelTailLength == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( ( f_fModifyOnly == TRUE ) && ( f_pVqeConfig->ulTailLength != pChanEntry->VqeConfig.usTailLength ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.PerChanTailLengthFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.PerChanTailLengthFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.PerChanTailLengthFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Check if must automatically select maximum or if must use user specific value. */ if ( f_pVqeConfig->ulTailLength == cOCT6100_AUTO_SELECT_TAIL ) { ulTempData |= ( ( ( pSharedInfo->ImageInfo.usMaxTailLength - 32 ) / 4 ) << ulFeatureBitOffset ); } else { ulTempData |= ( ( ( f_pVqeConfig->ulTailLength - 32 ) / 4 ) << ulFeatureBitOffset ); } /* Then save the DWORD where the field is located.*/ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulAfConfBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } /* Configure AEC tail length. */ if ( pSharedInfo->ImageInfo.fAecTailLength == TRUE ) { /* Check if the configuration has been changed. */ if ( ( f_fModifyOnly == FALSE ) || ( fTailDisplacementModified == TRUE ) || ( ( f_fModifyOnly == TRUE ) && ( ( f_pVqeConfig->ulAecTailLength != pChanEntry->VqeConfig.usAecTailLength ) || ( f_pVqeConfig->fAcousticEcho != pChanEntry->VqeConfig.fAcousticEcho ) ) ) ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.AecTailLengthFieldOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.AecTailLengthFieldOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.AecTailLengthFieldOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); ulTempData &= (~ulMask); /* Set acoustic echo tail length. */ if ( f_pVqeConfig->fAcousticEcho == TRUE ) { switch( f_pVqeConfig->ulAecTailLength ) { case 1024: ulTempData |= ( ( 3 ) << ulFeatureBitOffset ); break; case 512: ulTempData |= ( ( 2 ) << ulFeatureBitOffset ); break; case 256: ulTempData |= ( ( 1 ) << ulFeatureBitOffset ); break; case 128: default: ulTempData |= ( ( 0 ) << ulFeatureBitOffset ); break; } } else if ( f_pVqeConfig->fEnableTailDisplacement == TRUE ) { /* No acoustic echo case. */ /* Start with requested tail displacement. */ if ( f_pVqeConfig->ulTailDisplacement == cOCT6100_AUTO_SELECT_TAIL ) { ulTailSum = pSharedInfo->ChipConfig.usTailDisplacement; } else { ulTailSum = f_pVqeConfig->ulTailDisplacement; } /* Add requested tail length. */ if ( f_pVqeConfig->ulTailLength == cOCT6100_AUTO_SELECT_TAIL ) { ulTailSum += pSharedInfo->ImageInfo.usMaxTailLength; } else { ulTailSum += f_pVqeConfig->ulTailLength; } /* Round this value up. */ if ( ulTailSum <= 128 ) { ulTempData |= ( ( 0 ) << ulFeatureBitOffset ); } else if ( ulTailSum <= 256 ) { ulTempData |= ( ( 1 ) << ulFeatureBitOffset ); } else if ( ulTailSum <= 512 ) { ulTempData |= ( ( 2 ) << ulFeatureBitOffset ); } else /* if ( ulTailSum <= 1024 ) */ { ulTempData |= ( ( 3 ) << ulFeatureBitOffset ); } } else { /* Keep this to zero. */ ulTempData |= ( ( 0 ) << ulFeatureBitOffset ); } /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulNlpConfBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelMuteSer Description: This function will mute some of the ports on a given channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelMute What channel/ports to mute. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelMuteSer UINT32 Oct6100ChannelMuteSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MUTE f_pChannelMute ) { UINT32 ulResult; UINT16 usChanIndex; UINT16 usPortMask; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertChannelMuteParams( f_pApiInstance, f_pChannelMute, &usChanIndex, &usPortMask ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Call the actual channel mute ports function. */ ulResult = Oct6100ApiMuteChannelPorts( f_pApiInstance, usChanIndex, usPortMask, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertChannelMuteParams Description: Check the user parameters passed to the channel mute function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelMute What channel/ports to mute. f_pusChanIndex Resulting channel index where the muting should be applied. f_pusPorts Port mask on which to apply the muting. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertChannelMuteParams UINT32 Oct6100ApiAssertChannelMuteParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_MUTE f_pChannelMute, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusPorts ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pChannelMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; if ( pChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CHANNEL_PART_OF_BIDIR_CHANNEL; /*=======================================================================*/ /* Check the provided port mask. */ if ( ( f_pChannelMute->ulPortMask & ~( cOCT6100_CHANNEL_MUTE_PORT_NONE | cOCT6100_CHANNEL_MUTE_PORT_RIN | cOCT6100_CHANNEL_MUTE_PORT_ROUT | cOCT6100_CHANNEL_MUTE_PORT_SIN | cOCT6100_CHANNEL_MUTE_PORT_SOUT | cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) ) != 0 ) return cOCT6100_ERR_CHANNEL_MUTE_MASK; /* Sin + Sin with features cannot be muted simultaneously. */ if ( ( ( f_pChannelMute->ulPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) && ( ( f_pChannelMute->ulPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) ) return cOCT6100_ERR_CHANNEL_MUTE_MASK_SIN; /* Check if Sin mute with features is supported by the firmware. */ if ( ( ( f_pChannelMute->ulPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) && ( pSharedInfo->ImageInfo.fSinMute == FALSE ) ) return cOCT6100_ERR_NOT_SUPPORTED_CHANNEL_SIN_MUTE_FEATURES; /* Return the ports to the calling function. */ *f_pusPorts = (UINT16)( f_pChannelMute->ulPortMask & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ChannelUnMuteSer Description: This function will unmute some of the ports on a given channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelUnMute What channel/ports to unmute. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ChannelUnMuteSer UINT32 Oct6100ChannelUnMuteSer( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute ) { UINT32 ulResult; UINT16 usChanIndex; UINT16 usPortMask; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertChannelUnMuteParams( f_pApiInstance, f_pChannelUnMute, &usChanIndex, &usPortMask ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Call the actual channel mute ports function. */ ulResult = Oct6100ApiMuteChannelPorts( f_pApiInstance, usChanIndex, usPortMask, FALSE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertChannelUnMuteParams Description: Check the user parameters passed to the channel unmute function. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pChannelUnMute What channel/ports to Unmute. f_pusChanIndex Resulting channel index where the muting should be applied. f_pusPorts Port mask on which to apply the muting. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertChannelUnMuteParams UINT32 Oct6100ApiAssertChannelUnMuteParams( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_CHANNEL_UNMUTE f_pChannelUnMute, OUT PUINT16 f_pusChanIndex, OUT PUINT16 f_pusPorts ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pChannelUnMute->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; *f_pusChanIndex = (UINT16)( f_pChannelUnMute->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusChanIndex >= pSharedInfo->ChipConfig.usMaxChannels ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; /*=======================================================================*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, *f_pusChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = ( f_pChannelUnMute->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pChanEntry->fReserved != TRUE ) return cOCT6100_ERR_CHANNEL_NOT_OPEN; if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_CHANNEL_INVALID_HANDLE; if ( pChanEntry->fBiDirChannel == TRUE ) return cOCT6100_ERR_CHANNEL_PART_OF_BIDIR_CHANNEL; /*=======================================================================*/ /* Check the provided port mask. */ if ( ( f_pChannelUnMute->ulPortMask & ~( cOCT6100_CHANNEL_MUTE_PORT_NONE | cOCT6100_CHANNEL_MUTE_PORT_RIN | cOCT6100_CHANNEL_MUTE_PORT_ROUT | cOCT6100_CHANNEL_MUTE_PORT_SIN | cOCT6100_CHANNEL_MUTE_PORT_SOUT | cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) ) != 0 ) return cOCT6100_ERR_CHANNEL_MUTE_MASK; /* Return the ports to the calling function. */ *f_pusPorts = (UINT16)( f_pChannelUnMute->ulPortMask & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMuteSinWithFeatures Description: Mute or Unmute the sin with features port. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Resulting channel index where the muting should be applied. f_fEnableSinWithFeatures Whether to enable the feature or not. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMuteSinWithFeatures UINT32 Oct6100ApiMuteSinWithFeatures( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN BOOL f_fEnableSinWithFeatures ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulTempData; UINT32 ulBaseAddress; UINT32 ulFeatureBytesOffset; UINT32 ulFeatureBitOffset; UINT32 ulFeatureFieldLength; UINT32 ulMask; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) ulBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( pChanEntry->usEchoMemIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; if ( pSharedInfo->ImageInfo.fSinMute == TRUE ) { ulFeatureBytesOffset = pSharedInfo->MemoryMap.SinMuteOfst.usDwordOffset * 4; ulFeatureBitOffset = pSharedInfo->MemoryMap.SinMuteOfst.byBitOffset; ulFeatureFieldLength = pSharedInfo->MemoryMap.SinMuteOfst.byFieldSize; ulResult = oct6100_retrieve_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, &ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Clear previous value set in the feature field.*/ mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask ); /* Clear the mute flag. */ ulTempData &= (~ulMask); /* Set the mute flag on the Sin port.*/ if ( f_fEnableSinWithFeatures == TRUE ) ulTempData |= ( 0x1 << ulFeatureBitOffset ); /* Write the new DWORD where the field is located. */ ulResult = oct6100_save_nlp_conf_dword(f_pApiInstance, pChanEntry, ulBaseAddress + ulFeatureBytesOffset, ulTempData); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiMuteChannelPorts Description: Mute or Unmute the specified ports, according to the mask. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usChanIndex Resulting channel index where the muting should be applied. f_usPortMask Port mask on which to apply the muting/unmuting. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiMuteChannelPorts UINT32 Oct6100ApiMuteChannelPorts( IN tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usChanIndex, IN UINT16 f_usPortMask, IN BOOL f_fMute ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_CHANNEL pChanEntry; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; BOOL fDisableSinWithFeatures = FALSE; BOOL fEnableSinWithFeatures = FALSE; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /* Get a pointer to the channel's list entry. */ mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, f_usChanIndex ) /* Rin port. */ if ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_RIN ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_RIN ) == 0x0 ) ) { /* Mute this port. */ pChanEntry->usMutedPorts |= cOCT6100_CHANNEL_MUTE_PORT_RIN; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pChanEntry->usRinTsstIndex, pChanEntry->usSinTsstIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) { pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_RIN; return ulResult; } } else if ( ( f_fMute == FALSE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_RIN ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_RIN ) != 0x0 ) ) { /* Unmute this port. */ pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_RIN; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pChanEntry->usRinTsstIndex, pChanEntry->usSinTsstIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Rout port. */ if ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) == 0x0 ) ) { /* Mute this port. */ if ( pChanEntry->usRoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, pChanEntry->usRoutTsstIndex, pChanEntry->CodecConfig.byAdpcmNibblePosition, pChanEntry->TdmConfig.byRoutNumTssts, 1534 ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } pChanEntry->usMutedPorts |= cOCT6100_CHANNEL_MUTE_PORT_ROUT; } else if ( ( f_fMute == FALSE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_ROUT ) != 0x0 ) ) { /* Unmute this port. */ if ( pChanEntry->usRoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, pChanEntry->usRoutTsstIndex, pChanEntry->CodecConfig.byAdpcmNibblePosition, pChanEntry->TdmConfig.byRoutNumTssts, pChanEntry->usRinRoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_ROUT; } /* Sin port. */ if ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN ) == 0x0 ) ) { /* Mute this port. */ pChanEntry->usMutedPorts |= cOCT6100_CHANNEL_MUTE_PORT_SIN; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pChanEntry->usRinTsstIndex, pChanEntry->usSinTsstIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) { pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_SIN; return ulResult; } } else if ( ( ( f_fMute == FALSE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) ) || ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) ) ) { /* Unmute this port. */ pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_SIN; ulResult = Oct6100ApiMutePorts( f_pApiInstance, f_usChanIndex, pChanEntry->usRinTsstIndex, pChanEntry->usSinTsstIndex, TRUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /* Sout port. */ if ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) == 0x0 ) ) { /* Mute this port. */ if ( pChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, pChanEntry->usSoutTsstIndex, pChanEntry->CodecConfig.byAdpcmNibblePosition, pChanEntry->TdmConfig.bySoutNumTssts, 1534 ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } pChanEntry->usMutedPorts |= cOCT6100_CHANNEL_MUTE_PORT_SOUT; } else if ( ( f_fMute == FALSE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SOUT ) != 0x0 ) ) { /* Unmute this port. */ if ( pChanEntry->usSoutTsstIndex != cOCT6100_INVALID_INDEX ) { ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, pChanEntry->usSoutTsstIndex, pChanEntry->CodecConfig.byAdpcmNibblePosition, pChanEntry->TdmConfig.bySoutNumTssts, pChanEntry->usSinSoutTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_SOUT; } /* Sin with features port. */ if ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) == 0x0 ) ) { /* Mute this port. */ pChanEntry->usMutedPorts |= cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES; fEnableSinWithFeatures = TRUE; } else if ( ( ( f_fMute == FALSE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) ) || ( ( f_fMute == TRUE ) && ( ( f_usPortMask & cOCT6100_CHANNEL_MUTE_PORT_SIN ) != 0x0 ) && ( ( pChanEntry->usMutedPorts & cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES ) != 0x0 ) ) ) { /* Unmute this port. */ pChanEntry->usMutedPorts &= ~cOCT6100_CHANNEL_MUTE_PORT_SIN_WITH_FEATURES; fDisableSinWithFeatures = TRUE; } /* Check if must enable or disable SIN mute with features. */ if ( fDisableSinWithFeatures == TRUE || fEnableSinWithFeatures == TRUE ) { ulResult = Oct6100ApiMuteSinWithFeatures( f_pApiInstance, f_usChanIndex, fEnableSinWithFeatures ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_api/oct6100_adpcm_chan.c0000644000175000017500000013127511431317470031525 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_adpcm_chan.c Copyright (c) 2001-2007 Octasic Inc. Description: This file contains functions used to open and close ADPCM channels. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 16 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ /***************************** INCLUDE FILES *******************************/ #include "octdef.h" #include "oct6100api/oct6100_defines.h" #include "oct6100api/oct6100_errors.h" #include "oct6100api/oct6100_apiud.h" #include "apilib/octapi_llman.h" #include "oct6100api/oct6100_tlv_inst.h" #include "oct6100api/oct6100_chip_open_inst.h" #include "oct6100api/oct6100_chip_stats_inst.h" #include "oct6100api/oct6100_interrupts_inst.h" #include "oct6100api/oct6100_channel_inst.h" #include "oct6100api/oct6100_remote_debug_inst.h" #include "oct6100api/oct6100_debug_inst.h" #include "oct6100api/oct6100_api_inst.h" #include "oct6100api/oct6100_adpcm_chan_inst.h" #include "oct6100api/oct6100_interrupts_pub.h" #include "oct6100api/oct6100_chip_open_pub.h" #include "oct6100api/oct6100_channel_pub.h" #include "oct6100api/oct6100_adpcm_chan_pub.h" #include "oct6100_chip_open_priv.h" #include "oct6100_miscellaneous_priv.h" #include "oct6100_memory_priv.h" #include "oct6100_tsst_priv.h" #include "oct6100_channel_priv.h" #include "oct6100_adpcm_chan_priv.h" /**************************** PUBLIC FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100AdpcmChanOpen Description: This function opens an ADPCM channel between two TDM timeslots. This channel will perform ADPCM compression or decompression depending on the channel mode. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to ADPCM channel open structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100AdpcmChanOpenDef UINT32 Oct6100AdpcmChanOpenDef( tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ) { f_pAdpcmChanOpen->pulChanHndl = NULL; f_pAdpcmChanOpen->ulInputTimeslot = cOCT6100_INVALID_TIMESLOT; f_pAdpcmChanOpen->ulInputStream = cOCT6100_INVALID_STREAM; f_pAdpcmChanOpen->ulInputNumTssts = 1; f_pAdpcmChanOpen->ulInputPcmLaw = cOCT6100_PCM_U_LAW; f_pAdpcmChanOpen->ulOutputTimeslot = cOCT6100_INVALID_TIMESLOT; f_pAdpcmChanOpen->ulOutputStream = cOCT6100_INVALID_STREAM; f_pAdpcmChanOpen->ulOutputPcmLaw = cOCT6100_PCM_U_LAW; f_pAdpcmChanOpen->ulOutputNumTssts = 1; f_pAdpcmChanOpen->ulChanMode = cOCT6100_ADPCM_ENCODING; f_pAdpcmChanOpen->ulEncodingRate = cOCT6100_G726_32KBPS; f_pAdpcmChanOpen->ulDecodingRate = cOCT6100_G726_32KBPS; f_pAdpcmChanOpen->ulAdpcmNibblePosition = cOCT6100_ADPCM_IN_LOW_BITS; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100AdpcmChanOpen UINT32 Oct6100AdpcmChanOpen( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100AdpcmChanOpenSer( f_pApiInstance, f_pAdpcmChanOpen ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100AdpcmChanClose Description: This function closes an opened ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanClose Pointer to ADPCM channel close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100AdpcmChanCloseDef UINT32 Oct6100AdpcmChanCloseDef( tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ) { f_pAdpcmChanClose->ulChanHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif #if !SKIP_Oct6100AdpcmChanClose UINT32 Oct6100AdpcmChanClose( tPOCT6100_INSTANCE_API f_pApiInstance, tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ) { tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; UINT32 ulSerRes = cOCT6100_ERR_OK; UINT32 ulFncRes = cOCT6100_ERR_OK; /* Set the process context of the serialize structure.*/ SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; /* Seize all list semaphores needed by this function. */ SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); if ( ulSerRes == cOCT6100_ERR_OK ) { /* Call the serialized function. */ ulFncRes = Oct6100AdpcmChanCloseSer( f_pApiInstance, f_pAdpcmChanClose ); } else { return ulSerRes; } /* Release the seized semaphores. */ ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); /* If an error occured then return the error code. */ if ( ulSerRes != cOCT6100_ERR_OK ) return ulSerRes; if ( ulFncRes != cOCT6100_ERR_OK ) return ulFncRes; return cOCT6100_ERR_OK; } #endif /**************************** PRIVATE FUNCTIONS ****************************/ /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiGetAdpcmChanSwSizes Description: Gets the sizes of all portions of the API instance pertinent to the management of the ADPCM memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pOpenChip Pointer to chip configuration struct. f_pInstSizes Pointer to struct containing instance sizes. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiGetAdpcmChanSwSizes UINT32 Oct6100ApiGetAdpcmChanSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) { UINT32 ulTempVar; UINT32 ulResult; /* Determine the amount of memory required for the API ADPCM channel list.*/ f_pInstSizes->ulAdpcmChannelList = f_pOpenChip->ulMaxAdpcmChannels * sizeof( tOCT6100_API_ADPCM_CHAN ); if ( f_pOpenChip->ulMaxAdpcmChannels > 0 ) { /* Calculate memory needed for ADPCM memory allocation */ ulResult = OctapiLlmAllocGetSize( f_pOpenChip->ulMaxAdpcmChannels, &f_pInstSizes->ulAdpcmChannelAlloc ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_48; } else { f_pInstSizes->ulAdpcmChannelAlloc = 0; } mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulAdpcmChannelList, ulTempVar ) mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulAdpcmChannelAlloc, ulTempVar ) return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAdpcmChanSwInit Description: Initializes all elements of the instance structure associated to the ADPCM memory. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAdpcmChanSwInit UINT32 Oct6100ApiAdpcmChanSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ) { tPOCT6100_API_ADPCM_CHAN pChannelsTsiList; tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulMaxAdpcmChannels; PVOID pAdpcmChannelsAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Initialize the ADPCM channel API list.*/ ulMaxAdpcmChannels = pSharedInfo->ChipConfig.usMaxAdpcmChannels; /* Set all entries in the ADPCM channel list to unused. */ mOCT6100_GET_ADPCM_CHAN_LIST_PNT( pSharedInfo, pChannelsTsiList ) /* Clear the memory */ Oct6100UserMemSet( pChannelsTsiList, 0x00, sizeof(tOCT6100_API_ADPCM_CHAN) * ulMaxAdpcmChannels ); /* Initialize the ADPCM channel allocation structures to "all free". */ if ( ulMaxAdpcmChannels > 0 ) { mOCT6100_GET_ADPCM_CHAN_ALLOC_PNT( pSharedInfo, pAdpcmChannelsAlloc ) ulResult = OctapiLlmAllocInit( &pAdpcmChannelsAlloc, ulMaxAdpcmChannels ); if ( ulResult != cOCT6100_ERR_OK ) return cOCT6100_ERR_FATAL_BD; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100AdpcmChanOpenSer Description: Opens an ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to an ADPCM channel open structure \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100AdpcmChanOpenSer UINT32 Oct6100AdpcmChanOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ) { UINT16 usAdpcmChanIndex; UINT16 usTsiMemIndex; UINT16 usAdpcmMemIndex; UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; UINT32 ulResult; /* Check the user's configuration of the ADPCM channel open structure for errors. */ ulResult = Oct6100ApiCheckAdpcmChanParams( f_pApiInstance, f_pAdpcmChanOpen ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Reserve all resources needed by the ADPCM channel. */ ulResult = Oct6100ApiReserveAdpcmChanResources( f_pApiInstance, f_pAdpcmChanOpen, &usAdpcmChanIndex, &usAdpcmMemIndex, &usTsiMemIndex, &usInputTsstIndex, &usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Write all necessary structures to activate the ADPCM channel. */ ulResult = Oct6100ApiWriteAdpcmChanStructs( f_pApiInstance, f_pAdpcmChanOpen, usAdpcmMemIndex, usTsiMemIndex, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Update the ADPCM channel entry in the API list. */ ulResult = Oct6100ApiUpdateAdpcmChanEntry( f_pApiInstance, f_pAdpcmChanOpen, usAdpcmChanIndex, usAdpcmMemIndex, usTsiMemIndex, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiCheckAdpcmChanParams Description: Checks the user's ADPCM channel open configuration for errors. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to ADPCM channel open configuration structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiCheckAdpcmChanParams UINT32 Oct6100ApiCheckAdpcmChanParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ) { UINT32 ulResult; /* Check for errors. */ if ( f_pApiInstance->pSharedInfo->ChipConfig.usMaxAdpcmChannels == 0 ) return cOCT6100_ERR_ADPCM_CHAN_DISABLED; if ( f_pAdpcmChanOpen->pulChanHndl == NULL ) return cOCT6100_ERR_ADPCM_CHAN_INVALID_HANDLE; /* Check the input TDM streams, timeslots component for errors. */ if ( f_pAdpcmChanOpen->ulInputNumTssts != 1 && f_pAdpcmChanOpen->ulInputNumTssts != 2 ) return cOCT6100_ERR_ADPCM_CHAN_INPUT_NUM_TSSTS; ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pAdpcmChanOpen->ulInputNumTssts, f_pAdpcmChanOpen->ulInputTimeslot, f_pAdpcmChanOpen->ulInputStream, cOCT6100_INPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_ADPCM_CHAN_INPUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_ADPCM_CHAN_INPUT_STREAM; } else { return ulResult; } } if( f_pAdpcmChanOpen->ulInputPcmLaw != cOCT6100_PCM_U_LAW && f_pAdpcmChanOpen->ulInputPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_ADPCM_CHAN_INPUT_PCM_LAW; /* Check the output TDM streams, timeslots component for errors. */ if ( f_pAdpcmChanOpen->ulOutputNumTssts != 1 && f_pAdpcmChanOpen->ulOutputNumTssts != 2 ) return cOCT6100_ERR_ADPCM_CHAN_OUTPUT_NUM_TSSTS; ulResult = Oct6100ApiValidateTsst( f_pApiInstance, f_pAdpcmChanOpen->ulOutputNumTssts, f_pAdpcmChanOpen->ulOutputTimeslot, f_pAdpcmChanOpen->ulOutputStream, cOCT6100_OUTPUT_TSST ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == cOCT6100_ERR_TSST_TIMESLOT ) { return cOCT6100_ERR_ADPCM_CHAN_OUTPUT_TIMESLOT; } else if ( ulResult == cOCT6100_ERR_TSST_STREAM ) { return cOCT6100_ERR_ADPCM_CHAN_OUTPUT_STREAM; } else { return ulResult; } } if( f_pAdpcmChanOpen->ulOutputPcmLaw != cOCT6100_PCM_U_LAW && f_pAdpcmChanOpen->ulOutputPcmLaw != cOCT6100_PCM_A_LAW ) return cOCT6100_ERR_ADPCM_CHAN_OUTPUT_PCM_LAW; /* Now, check the channel mode. */ if ( f_pAdpcmChanOpen->ulChanMode != cOCT6100_ADPCM_ENCODING && f_pAdpcmChanOpen->ulChanMode != cOCT6100_ADPCM_DECODING ) return cOCT6100_ERR_ADPCM_CHAN_MODE; if ( f_pAdpcmChanOpen->ulChanMode == cOCT6100_ADPCM_ENCODING ) { /* Check the encoding rate. */ if ( ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G711_64KBPS ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G726_40KBPS ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G726_32KBPS ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G726_24KBPS ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G726_16KBPS ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_40KBPS_4_1 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_40KBPS_3_2 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_40KBPS_2_3 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_32KBPS_4_0 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_32KBPS_3_1 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_32KBPS_2_2 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_24KBPS_3_0 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_24KBPS_2_1 ) && ( f_pAdpcmChanOpen->ulEncodingRate != cOCT6100_G727_16KBPS_2_0 ) ) return cOCT6100_ERR_ADPCM_CHAN_ENCODING_RATE; } else /* if ( f_pAdpcmChanOpen->ulChanMode != cOCT6100_ADPCM_DECODING ) */ { /* Check the decoding rate. */ if ( f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G711_64KBPS && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G726_40KBPS && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G726_32KBPS && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G726_24KBPS && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G726_16KBPS && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G726_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G711_G726_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G727_2C_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G727_3C_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G727_4C_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G711_G727_2C_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G711_G727_3C_ENCODED && f_pAdpcmChanOpen->ulDecodingRate != cOCT6100_G711_G727_4C_ENCODED ) return cOCT6100_ERR_ADPCM_CHAN_DECODING_RATE; /* Make sure that two timeslots are allocated if PCM-ECHO encoded is selected. */ if ( (f_pAdpcmChanOpen->ulDecodingRate == cOCT6100_G711_G726_ENCODED || f_pAdpcmChanOpen->ulDecodingRate == cOCT6100_G711_G727_2C_ENCODED || f_pAdpcmChanOpen->ulDecodingRate == cOCT6100_G711_G727_3C_ENCODED || f_pAdpcmChanOpen->ulDecodingRate == cOCT6100_G711_G727_4C_ENCODED ) && f_pAdpcmChanOpen->ulInputNumTssts != 2 ) return cOCT6100_ERR_ADPCM_CHAN_INCOMPATIBLE_NUM_TSSTS; } /* Check the nibble position. */ if ( f_pAdpcmChanOpen->ulAdpcmNibblePosition != cOCT6100_ADPCM_IN_LOW_BITS && f_pAdpcmChanOpen->ulAdpcmNibblePosition != cOCT6100_ADPCM_IN_HIGH_BITS ) return cOCT6100_ERR_ADPCM_CHAN_ADPCM_NIBBLE_POSITION; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveAdpcmChanResources Description: Reserves all resources needed for the new ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to ADPCM channel configuration structure. f_pusAdpcmChanIndex Allocated entry in ADPCM channel list. f_pusAdpcmMemIndex Allocated entry in the ADPCM control memory. f_pusTsiMemIndex Allocated entry in the TSI chariot memory. f_pusInputTsstIndex TSST memory index of the input samples. f_pusOutputTsstIndex TSST memory index of the output samples. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveAdpcmChanResources UINT32 Oct6100ApiReserveAdpcmChanResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, OUT PUINT16 f_pusAdpcmChanIndex, OUT PUINT16 f_pusAdpcmMemIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; UINT32 ulResult; UINT32 ulTempVar; BOOL fAdpcmChanEntry = FALSE; BOOL fAdpcmMemEntry = FALSE; BOOL fTsiMemEntry = FALSE; BOOL fInputTsst = FALSE; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Reserve an entry in the ADPCM channel list. */ ulResult = Oct6100ApiReserveAdpcmChanEntry( f_pApiInstance, f_pusAdpcmChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fAdpcmChanEntry = TRUE; /* Find a TSI memory entry.*/ ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, f_pusTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fTsiMemEntry = TRUE; /* Find a conversion memory entry. */ ulResult = Oct6100ApiReserveConversionMemEntry( f_pApiInstance, f_pusAdpcmMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { fAdpcmMemEntry = TRUE; /* Reserve the input TSST entry. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pAdpcmChanOpen->ulInputTimeslot, f_pAdpcmChanOpen->ulInputStream, f_pAdpcmChanOpen->ulInputNumTssts, cOCT6100_INPUT_TSST, f_pusInputTsstIndex, NULL ); if ( ulResult == cOCT6100_ERR_OK ) { fInputTsst = TRUE; /* Reserve the output TSST entry. */ ulResult = Oct6100ApiReserveTsst( f_pApiInstance, f_pAdpcmChanOpen->ulOutputTimeslot, f_pAdpcmChanOpen->ulOutputStream, f_pAdpcmChanOpen->ulOutputNumTssts, cOCT6100_OUTPUT_TSST, f_pusOutputTsstIndex, NULL ); } } } else { /* Return an error other than a fatal error. */ ulResult = cOCT6100_ERR_ADPCM_CHAN_NO_MORE_TSI_AVAILABLE; } } if ( ulResult != cOCT6100_ERR_OK ) { if( fAdpcmChanEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseAdpcmChanEntry( f_pApiInstance, *f_pusAdpcmChanIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fTsiMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, *f_pusTsiMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fAdpcmMemEntry == TRUE ) { ulTempVar = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, *f_pusAdpcmMemIndex ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } if( fInputTsst == TRUE ) { ulTempVar = Oct6100ApiReleaseTsst( f_pApiInstance, f_pAdpcmChanOpen->ulInputTimeslot, f_pAdpcmChanOpen->ulInputStream, f_pAdpcmChanOpen->ulInputNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulTempVar != cOCT6100_ERR_OK ) return ulTempVar; } return ulResult; } return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiWriteAdpcmChanStructs Description: Performs all the required structure writes to configure the new ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to ADPCM channel configuration structure. f_pusAdpcmChanIndex Allocated entry in ADPCM channel list. f_pusAdpcmMemIndex Allocated entry in the ADPCM control memory. f_pusTsiMemIndex Allocated entry in the TSI chariot memory. f_pusInputTsstIndex TSST memory index of the input samples. f_pusOutputTsstIndex TSST memory index of the output samples. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiWriteAdpcmChanStructs UINT32 Oct6100ApiWriteAdpcmChanStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; UINT32 ulCompType = 0; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*------------------------------------------------------------------------------*/ /* Configure the TSST control memory. */ /* Set the input TSST control entry. */ ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance, f_usInputTsstIndex, f_usTsiMemIndex, f_pAdpcmChanOpen->ulInputPcmLaw ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the output TSST control entry. */ ulResult = Oct6100ApiWriteOutputTsstControlMemory( f_pApiInstance, f_usOutputTsstIndex, f_pAdpcmChanOpen->ulAdpcmNibblePosition, f_pAdpcmChanOpen->ulOutputNumTssts, f_usTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Configure the ADPCM memory. */ if ( f_pAdpcmChanOpen->ulChanMode == cOCT6100_ADPCM_ENCODING ) { switch( f_pAdpcmChanOpen->ulEncodingRate ) { case cOCT6100_G711_64KBPS: if ( f_pAdpcmChanOpen->ulOutputPcmLaw == cOCT6100_PCM_U_LAW ) ulCompType = 0x4; else /* if ( f_pAdpcmChanOpen->ulOutputPcmLaw != cOCT6100_PCM_U_LAW ) */ ulCompType = 0x5; break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; break; case cOCT6100_G727_40KBPS_4_1: ulCompType = 0xD; break; case cOCT6100_G727_40KBPS_3_2: ulCompType = 0xA; break; case cOCT6100_G727_40KBPS_2_3: ulCompType = 0x6; break; case cOCT6100_G727_32KBPS_4_0: ulCompType = 0xE; break; case cOCT6100_G727_32KBPS_3_1: ulCompType = 0xB; break; case cOCT6100_G727_32KBPS_2_2: ulCompType = 0x7; break; case cOCT6100_G727_24KBPS_3_0: ulCompType = 0xC; break; case cOCT6100_G727_24KBPS_2_1: ulCompType = 0x8; break; case cOCT6100_G727_16KBPS_2_0: ulCompType = 0x9; break; } ulResult = Oct6100ApiWriteEncoderMemory( f_pApiInstance, f_usAdpcmMemIndex, ulCompType, f_usTsiMemIndex, FALSE, f_pAdpcmChanOpen->ulAdpcmNibblePosition, cOCT6100_INVALID_INDEX, cOCT6100_INVALID_VALUE, cOCT6100_INVALID_VALUE ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } else /* if ( f_pAdpcmChanOpen->ulChanMode != cOCT6100_ADPCM_DECODING ) */ { switch( f_pAdpcmChanOpen->ulDecodingRate ) { case cOCT6100_G711_64KBPS: ulCompType = 0x8; break; case cOCT6100_G726_40KBPS: ulCompType = 0x3; break; case cOCT6100_G726_32KBPS: ulCompType = 0x2; break; case cOCT6100_G726_24KBPS: ulCompType = 0x1; break; case cOCT6100_G726_16KBPS: ulCompType = 0x0; break; case cOCT6100_G727_2C_ENCODED: ulCompType = 0x4; break; case cOCT6100_G727_3C_ENCODED: ulCompType = 0x5; break; case cOCT6100_G727_4C_ENCODED: ulCompType = 0x6; break; case cOCT6100_G726_ENCODED: ulCompType = 0x9; break; case cOCT6100_G711_G726_ENCODED: ulCompType = 0xA; break; case cOCT6100_G711_G727_2C_ENCODED: ulCompType = 0xC; break; case cOCT6100_G711_G727_3C_ENCODED: ulCompType = 0xD; break; case cOCT6100_G711_G727_4C_ENCODED: ulCompType = 0xE; break; } ulResult = Oct6100ApiWriteDecoderMemory( f_pApiInstance, f_usAdpcmMemIndex, ulCompType, f_usTsiMemIndex, f_pAdpcmChanOpen->ulOutputPcmLaw, f_pAdpcmChanOpen->ulAdpcmNibblePosition ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; } /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiUpdateAdpcmChanEntry Description: Updates the new ADPCM channel in the ADPCM channel list. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanOpen Pointer to ADPCM channel open configuration structure. f_usAdpcmChanIndex Allocated entry in the ADPCM channel list. f_usAdpcmMemIndex Allocated entry in ADPCM memory. f_usTsiMemIndex Allocated entry in TSI chariot memory. f_usInputTsstIndex TSST control memory index of the input TSST. f_usOutputTsstIndex TSST control memory index of the output TSST. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiUpdateAdpcmChanEntry UINT32 Oct6100ApiUpdateAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, IN UINT16 f_usAdpcmChanIndex, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_API_ADPCM_CHAN pAdpcmChanEntry; /*------------------------------------------------------------------------------*/ /* Obtain a pointer to the new ADPCM channel's list entry. */ mOCT6100_GET_ADPCM_CHAN_ENTRY_PNT( f_pApiInstance->pSharedInfo, pAdpcmChanEntry, f_usAdpcmChanIndex ) /* Copy the buffer's configuration and allocated resources. */ pAdpcmChanEntry->usInputTimeslot = (UINT16)( f_pAdpcmChanOpen->ulInputTimeslot & 0xFFFF ); pAdpcmChanEntry->usInputStream = (UINT16)( f_pAdpcmChanOpen->ulInputStream & 0xFFFF ); pAdpcmChanEntry->byInputNumTssts = (UINT8)( f_pAdpcmChanOpen->ulInputNumTssts & 0xFF ); pAdpcmChanEntry->byInputPcmLaw = (UINT8)( f_pAdpcmChanOpen->ulInputPcmLaw & 0xFF ); pAdpcmChanEntry->usOutputTimeslot = (UINT16)( f_pAdpcmChanOpen->ulOutputTimeslot & 0xFFFF ); pAdpcmChanEntry->usOutputStream = (UINT16)( f_pAdpcmChanOpen->ulOutputStream & 0xFFFF ); pAdpcmChanEntry->byOutputNumTssts = (UINT8)( f_pAdpcmChanOpen->ulOutputNumTssts & 0xFF ); pAdpcmChanEntry->byOutputPcmLaw = (UINT8)( f_pAdpcmChanOpen->ulOutputPcmLaw & 0xFF ); /* Store hardware related information. */ pAdpcmChanEntry->usTsiMemIndex = f_usTsiMemIndex; pAdpcmChanEntry->usAdpcmMemIndex = f_usAdpcmMemIndex; pAdpcmChanEntry->usInputTsstIndex = f_usInputTsstIndex; pAdpcmChanEntry->usOutputTsstIndex = f_usOutputTsstIndex; /* Form handle returned to user. */ *f_pAdpcmChanOpen->pulChanHndl = cOCT6100_HNDL_TAG_ADPCM_CHANNEL | (pAdpcmChanEntry->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_usAdpcmChanIndex; /* Finally, mark the ADPCM channel as opened. */ pAdpcmChanEntry->fReserved = TRUE; /* Increment the number of ADPCM channel opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberAdpcmChans++; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100AdpcmChanCloseSer Description: Closes an ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanClose Pointer to ADPCM channel close structure. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100AdpcmChanCloseSer UINT32 Oct6100AdpcmChanCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ) { UINT16 usAdpcmChanIndex; UINT16 usTsiMemIndex; UINT16 usAdpcmMemIndex; UINT16 usInputTsstIndex; UINT16 usOutputTsstIndex; UINT32 ulResult; /* Verify that all the parameters given match the state of the API. */ ulResult = Oct6100ApiAssertAdpcmChanParams( f_pApiInstance, f_pAdpcmChanClose, &usAdpcmChanIndex, &usAdpcmMemIndex, &usTsiMemIndex, &usInputTsstIndex, &usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the ADPCM channel. */ ulResult = Oct6100ApiInvalidateAdpcmChanStructs( f_pApiInstance, usAdpcmMemIndex, usInputTsstIndex, usOutputTsstIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Release all resources associated to the ADPCM channel. */ ulResult = Oct6100ApiReleaseAdpcmChanResources( f_pApiInstance, usAdpcmChanIndex, usAdpcmMemIndex, usTsiMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Invalidate the handle. */ f_pAdpcmChanClose->ulChanHndl = cOCT6100_INVALID_HANDLE; return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiAssertAdpcmChanParams Description: Validate the handle given by the user and verify the state of the ADPCM channel about to be closed. Also return all required information to deactivate the channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pAdpcmChanClose Pointer to ADPCM channel close structure. f_pusAdpcmChanIndex Index of the ADPCM channel structure in the API list. f_pusAdpcmMemIndex Index of the ADPCM memory structure in the API list. f_pusTsiMemIndex Index of the TSI chariot memory used for this channel. f_pusInputTsstIndex Index of the input entry in the TSST control memory. f_pusOutputTsstIndex Index of the output entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiAssertAdpcmChanParams UINT32 Oct6100ApiAssertAdpcmChanParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose, OUT PUINT16 f_pusAdpcmChanIndex, OUT PUINT16 f_pusAdpcmMemIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_ADPCM_CHAN pAdpcmChanEntry; UINT32 ulEntryOpenCnt; /* Get local pointer(s). */ pSharedInfo = f_pApiInstance->pSharedInfo; /* Check the provided handle. */ if ( (f_pAdpcmChanClose->ulChanHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_ADPCM_CHANNEL ) return cOCT6100_ERR_ADPCM_CHAN_INVALID_HANDLE; *f_pusAdpcmChanIndex = (UINT16)( f_pAdpcmChanClose->ulChanHndl & cOCT6100_HNDL_INDEX_MASK ); if ( *f_pusAdpcmChanIndex >= pSharedInfo->ChipConfig.usMaxAdpcmChannels ) return cOCT6100_ERR_ADPCM_CHAN_INVALID_HANDLE; /*------------------------------------------------------------------------------*/ /* Get a pointer to the channel's list entry. */ mOCT6100_GET_ADPCM_CHAN_ENTRY_PNT( pSharedInfo, pAdpcmChanEntry, *f_pusAdpcmChanIndex ) /* Extract the entry open count from the provided handle. */ ulEntryOpenCnt = (f_pAdpcmChanClose->ulChanHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK; /* Check for errors. */ if ( pAdpcmChanEntry->fReserved != TRUE ) return cOCT6100_ERR_ADPCM_CHAN_NOT_OPEN; if ( ulEntryOpenCnt != pAdpcmChanEntry->byEntryOpenCnt ) return cOCT6100_ERR_ADPCM_CHAN_INVALID_HANDLE; /* Return info needed to close the channel and release all resources. */ *f_pusInputTsstIndex = pAdpcmChanEntry->usInputTsstIndex; *f_pusOutputTsstIndex = pAdpcmChanEntry->usOutputTsstIndex; *f_pusTsiMemIndex = pAdpcmChanEntry->usTsiMemIndex; *f_pusAdpcmMemIndex = pAdpcmChanEntry->usAdpcmMemIndex; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiInvalidateAdpcmChanStructs Description: Closes an ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usAdpcmMemIndex Index of the ADPCM memory. f_usInputTsstIndex Index of the input entry in the TSST control memory. f_usOutputTsstIndex Index of the output entry in the TSST control memory. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiInvalidateAdpcmChanStructs UINT32 Oct6100ApiInvalidateAdpcmChanStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tOCT6100_WRITE_PARAMS WriteParams; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; WriteParams.pProcessContext = f_pApiInstance->pProcessContext; WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; /*------------------------------------------------------------------------------*/ /* Deactivate the TSST control memory. */ /* Set the input TSST control entry to unused. */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usInputTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /* Set the output TSST control entry to unused. */ WriteParams.ulWriteAddress = cOCT6100_TSST_CONTROL_MEM_BASE + ( f_usOutputTsstIndex * cOCT6100_TSST_CONTROL_MEM_ENTRY_SIZE ); WriteParams.usWriteData = 0x0000; mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Clear the ADPCM memory. */ ulResult = Oct6100ApiClearConversionMemory( f_pApiInstance, f_usAdpcmMemIndex ); if ( ulResult != cOCT6100_ERR_OK ) return ulResult; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseAdpcmChanResources Description: Release and clear the API entry associated to the ADPCM channel. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_ulAdpcmChanIndex Index of the ADPCM channel in the API list. f_usAdpcmMemIndex Index of the ADPCM memory used. f_usTsiMemIndex Index of the TSI memory used. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseAdpcmChanResources UINT32 Oct6100ApiReleaseAdpcmChanResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usAdpcmChanIndex, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; tPOCT6100_API_ADPCM_CHAN pAdpcmChanEntry; UINT32 ulResult; /* Obtain local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_ADPCM_CHAN_ENTRY_PNT( pSharedInfo, pAdpcmChanEntry, f_usAdpcmChanIndex ); /*------------------------------------------------------------------------------*/ /* Release all resources associated with ADPCM channel. */ /* Release the entry in the ADPCM channel list. */ ulResult = Oct6100ApiReleaseAdpcmChanEntry( f_pApiInstance, f_usAdpcmChanIndex ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReleaseConversionMemEntry( f_pApiInstance, f_usAdpcmMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, f_usTsiMemIndex ); if ( ulResult == cOCT6100_ERR_OK ) { /* Release the input TSST entry. */ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pAdpcmChanEntry->usInputTimeslot, pAdpcmChanEntry->usInputStream, pAdpcmChanEntry->byInputNumTssts, cOCT6100_INPUT_TSST, cOCT6100_INVALID_INDEX ); if ( ulResult == cOCT6100_ERR_OK ) { /* Release the output TSST entry. */ ulResult = Oct6100ApiReleaseTsst( f_pApiInstance, pAdpcmChanEntry->usOutputTimeslot, pAdpcmChanEntry->usOutputStream, pAdpcmChanEntry->byOutputNumTssts, cOCT6100_OUTPUT_TSST, cOCT6100_INVALID_INDEX ); } } } } /* Check if an error occured while releasing the reserved resources. */ if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult >= cOCT6100_ERR_FATAL ) return ulResult; else return cOCT6100_ERR_FATAL_4A; } /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /* Update the ADPCM channel's list entry. */ /* Mark the channel as closed. */ pAdpcmChanEntry->fReserved = FALSE; pAdpcmChanEntry->byEntryOpenCnt++; /* Decrement the number of ADPCM channels opened. */ f_pApiInstance->pSharedInfo->ChipStats.usNumberAdpcmChans--; /*------------------------------------------------------------------------------*/ return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReserveAdpcmChanEntry Description: Reserves one of the ADPCM channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_pusAdpcmChanIndex Resulting index reserved in the ADPCM channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReserveAdpcmChanEntry UINT32 Oct6100ApiReserveAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusAdpcmChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pAdpcmChanAlloc; UINT32 ulResult; UINT32 ulAdpcmChanIndex; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_ADPCM_CHAN_ALLOC_PNT( pSharedInfo, pAdpcmChanAlloc ) ulResult = OctapiLlmAllocAlloc( pAdpcmChanAlloc, &ulAdpcmChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) { if ( ulResult == OCTAPI_LLM_NO_STRUCTURES_LEFT ) return cOCT6100_ERR_ADPCM_CHAN_ALL_ADPCM_CHAN_ARE_OPENED; else return cOCT6100_ERR_FATAL_BE; } *f_pusAdpcmChanIndex = (UINT16)( ulAdpcmChanIndex & 0xFFFF ); return cOCT6100_ERR_OK; } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ Function: Oct6100ApiReleaseAdpcmChanEntry Description: Releases the specified ADPCM channel API entry. ------------------------------------------------------------------------------- | Argument | Description ------------------------------------------------------------------------------- f_pApiInstance Pointer to API instance. This memory is used to keep the present state of the chip and all its resources. f_usAdpcmChanIndex Index reserved in the ADPCM channel list. \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if !SKIP_Oct6100ApiReleaseAdpcmChanEntry UINT32 Oct6100ApiReleaseAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usAdpcmChanIndex ) { tPOCT6100_SHARED_INFO pSharedInfo; PVOID pAdpcmChanAlloc; UINT32 ulResult; /* Get local pointer to shared portion of instance. */ pSharedInfo = f_pApiInstance->pSharedInfo; mOCT6100_GET_ADPCM_CHAN_ALLOC_PNT( pSharedInfo, pAdpcmChanAlloc ) ulResult = OctapiLlmAllocDealloc( pAdpcmChanAlloc, f_usAdpcmChanIndex ); if ( ulResult != cOCT6100_ERR_OK ) { return cOCT6100_ERR_FATAL_BF; } return cOCT6100_ERR_OK; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/oct612x/octdeviceapi/oct6100api/oct6100_adpcm_chan_priv.h0000644000175000017500000001177311431317470030645 0ustar tzafrirtzafrir/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ File: oct6100_adpcm_chan_priv.h Copyright (c) 2001-2007 Octasic Inc. Description: File containing all private defines, macros, structures and prototypes pertaining to the file oct6100_adpcm_chan.c. All elements defined in this file are for private usage of the API. All public elements are defined in the oct6100_adpcm_chan_pub.h file. This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The OCT6100 GPL API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the OCT6100 GPL API; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. $Octasic_Release: OCT612xAPI-01.00-PR49 $ $Octasic_Revision: 7 $ \*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #ifndef __OCT6100_ADPCM_CHAN_PRIV_H__ #define __OCT6100_ADPCM_CHAN_PRIV_H__ /***************************** INCLUDE FILES *******************************/ /***************************** DEFINES *************************************/ /* ADPCM channel list pointer macros. */ #define mOCT6100_GET_ADPCM_CHAN_LIST_PNT( pSharedInfo, pList ) \ pList = ( tPOCT6100_API_ADPCM_CHAN )(( PUINT8 )pSharedInfo + pSharedInfo->ulAdpcmChanListOfst ); #define mOCT6100_GET_ADPCM_CHAN_ENTRY_PNT( pSharedInfo, pEntry, ulIndex ) \ pEntry = (( tPOCT6100_API_ADPCM_CHAN )(( PUINT8 )pSharedInfo + pSharedInfo->ulAdpcmChanListOfst)) + ulIndex; #define mOCT6100_GET_ADPCM_CHAN_ALLOC_PNT( pSharedInfo, pAlloc ) \ pAlloc = ( PVOID )(( PUINT8 )pSharedInfo + pSharedInfo->ulAdpcmChanAllocOfst); /***************************** TYPES ***************************************/ /************************** FUNCTION PROTOTYPES *****************************/ UINT32 Oct6100ApiGetAdpcmChanSwSizes( IN tPOCT6100_CHIP_OPEN f_pOpenChip, OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ); UINT32 Oct6100ApiAdpcmChanSwInit( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance ); UINT32 Oct6100AdpcmChanOpenSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ); UINT32 Oct6100ApiCheckAdpcmChanParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen ); UINT32 Oct6100ApiReserveAdpcmChanResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusAdpcmMemIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ); UINT32 Oct6100ApiWriteAdpcmChanStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100ApiUpdateAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN OUT tPOCT6100_ADPCM_CHAN_OPEN f_pAdpcmChanOpen, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100AdpcmChanCloseSer( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose ); UINT32 Oct6100ApiAssertAdpcmChanParams( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN tPOCT6100_ADPCM_CHAN_CLOSE f_pAdpcmChanClose, OUT PUINT16 f_pusTsiChanIndex, OUT PUINT16 f_pusAdpcmMemIndex, OUT PUINT16 f_pusTsiMemIndex, OUT PUINT16 f_pusInputTsstIndex, OUT PUINT16 f_pusOutputTsstIndex ); UINT32 Oct6100ApiInvalidateAdpcmChanStructs( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usAdpcmChanIndex, IN UINT16 f_usInputTsstIndex, IN UINT16 f_usOutputTsstIndex ); UINT32 Oct6100ApiReleaseAdpcmChanResources( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usTsiChanIndex, IN UINT16 f_usAdpcmMemIndex, IN UINT16 f_usTsiMemIndex ); UINT32 Oct6100ApiReserveAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, OUT PUINT16 f_pusAdpcmChanIndex ); UINT32 Oct6100ApiReleaseAdpcmChanEntry( IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, IN UINT16 f_usAdpcmChanIndex ); #endif /* __OCT6100_ADPCM_CHAN_PRIV_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/dahdi-base.c0000644000175000017500000077452611612051467020713 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface Driver * * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Special thanks to Steve Underwood * for substantial contributions to signal processing functions * in DAHDI and the Zapata library. * * Yury Bokhoncovich * Adaptation for 2.4.20+ kernels (HDLC API was changed) * The work has been performed as a part of our move * from Cisco 3620 to IBM x305 here in F1 Group * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001 - 2011 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) #include #endif #include #include #define DAHDI_PRINK_MACROS_USE_debug #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) /* Grab fasthdlc with tables */ #define FAST_HDLC_NEED_TABLES #include #include "ecdis.h" #include "dahdi.h" #ifdef CONFIG_DAHDI_PPP #include #include #include #endif #ifdef CONFIG_DAHDI_NET #include #endif #include "hpec/hpec_user.h" #include #if defined(EMPULSE) && defined(EMFLASH) #error "You cannot define both EMPULSE and EMFLASH" #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) #ifndef CONFIG_BKL #warning "No CONFIG_BKL is an experimental configuration." #endif #endif /* Get helper arithmetic */ #include "arith.h" #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) #include #endif #define hdlc_to_chan(h) (((struct dahdi_hdlc *)(h))->chan) #define netdev_to_chan(h) (((struct dahdi_hdlc *)(dev_to_hdlc(h)->priv))->chan) #define chan_to_netdev(h) ((h)->hdlcnetdev->netdev) /* macro-oni for determining a unit (channel) number */ #define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev) EXPORT_SYMBOL(dahdi_transcode_fops); EXPORT_SYMBOL(dahdi_init_tone_state); EXPORT_SYMBOL(dahdi_mf_tone); EXPORT_SYMBOL(dahdi_register); EXPORT_SYMBOL(dahdi_unregister); EXPORT_SYMBOL(__dahdi_mulaw); EXPORT_SYMBOL(__dahdi_alaw); #ifdef CONFIG_CALC_XLAW EXPORT_SYMBOL(__dahdi_lineartoulaw); EXPORT_SYMBOL(__dahdi_lineartoalaw); #else EXPORT_SYMBOL(__dahdi_lin2mu); EXPORT_SYMBOL(__dahdi_lin2a); #endif EXPORT_SYMBOL(dahdi_rbsbits); EXPORT_SYMBOL(dahdi_qevent_nolock); EXPORT_SYMBOL(dahdi_qevent_lock); EXPORT_SYMBOL(dahdi_hooksig); EXPORT_SYMBOL(dahdi_alarm_notify); EXPORT_SYMBOL(dahdi_set_dynamic_ioctl); EXPORT_SYMBOL(dahdi_hdlc_abort); EXPORT_SYMBOL(dahdi_hdlc_finish); EXPORT_SYMBOL(dahdi_hdlc_getbuf); EXPORT_SYMBOL(dahdi_hdlc_putbuf); EXPORT_SYMBOL(dahdi_alarm_channel); EXPORT_SYMBOL(dahdi_register_echocan_factory); EXPORT_SYMBOL(dahdi_unregister_echocan_factory); EXPORT_SYMBOL(dahdi_set_hpec_ioctl); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *root_proc_entry; #endif static int deftaps = 64; int debug; #define DEBUG_MAIN (1 << 0) #define DEBUG_RBS (1 << 5) static int hwec_overrides_swec = 1; /*! * \brief states for transmit signalling */ enum dahdi_txstate { DAHDI_TXSTATE_ONHOOK, DAHDI_TXSTATE_OFFHOOK, DAHDI_TXSTATE_START, DAHDI_TXSTATE_PREWINK, DAHDI_TXSTATE_WINK, DAHDI_TXSTATE_PREFLASH, DAHDI_TXSTATE_FLASH, DAHDI_TXSTATE_DEBOUNCE, DAHDI_TXSTATE_AFTERSTART, DAHDI_TXSTATE_RINGON, DAHDI_TXSTATE_RINGOFF, DAHDI_TXSTATE_KEWL, DAHDI_TXSTATE_AFTERKEWL, DAHDI_TXSTATE_PULSEBREAK, DAHDI_TXSTATE_PULSEMAKE, DAHDI_TXSTATE_PULSEAFTER, }; typedef short sumtype[DAHDI_MAX_CHUNKSIZE]; static sumtype sums[(DAHDI_MAX_CONF + 1) * 3]; /* Translate conference aliases into actual conferences and vice-versa */ static short confalias[DAHDI_MAX_CONF + 1]; static short confrev[DAHDI_MAX_CONF + 1]; static sumtype *conf_sums_next; static sumtype *conf_sums; static sumtype *conf_sums_prev; static struct dahdi_span *master; struct file_operations *dahdi_transcode_fops = NULL; #ifdef CONFIG_DAHDI_CORE_TIMER static struct core_timer { struct timer_list timer; struct timespec start_interval; unsigned long interval; atomic_t count; atomic_t shutdown; atomic_t last_count; } core_timer; #endif /* CONFIG_DAHDI_CORE_TIMER */ enum dahdi_digit_mode { DIGIT_MODE_DTMF, DIGIT_MODE_MFR1, DIGIT_MODE_PULSE, DIGIT_MODE_MFR2_FWD, DIGIT_MODE_MFR2_REV, }; /* At the end of silence, the tone stops */ static struct dahdi_tone dtmf_silence = { .tonesamples = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_DTMF_LENGTH), }; /* At the end of silence, the tone stops */ static struct dahdi_tone mfr1_silence = { .tonesamples = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_MFR1_LENGTH), }; /* At the end of silence, the tone stops */ static struct dahdi_tone mfr2_silence = { .tonesamples = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_MFR2_LENGTH), }; /* A pause in the dialing */ static struct dahdi_tone tone_pause = { .tonesamples = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_PAUSE_LENGTH), }; static struct dahdi_dialparams global_dialparams = { .dtmf_tonelen = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_DTMF_LENGTH), .mfv1_tonelen = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_MFR1_LENGTH), .mfr2_tonelen = DAHDI_MS_TO_SAMPLES(DAHDI_CONFIG_DEFAULT_MFR2_LENGTH), }; static DEFINE_MUTEX(global_dialparamslock); static int dahdi_chan_ioctl(struct file *file, unsigned int cmd, unsigned long data); #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) #if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_I386) struct fpu_save_buf { unsigned long cr0; unsigned long fpu_buf[128]; }; static DEFINE_PER_CPU(struct fpu_save_buf, fpu_buf); /** dahdi_kernel_fpu_begin() - Save floating point registers * * This function is similar to kernel_fpu_begin() . However it is * designed to work in an interrupt context. Restoring must be done with * dahdi_kernel_fpu_end(). * * Furthermore, the whole code between the call to * dahdi_kernel_fpu_begin() and dahdi_kernel_fpu_end() must reside * inside a spinlock. Otherwise the context might be restored to the * wrong process. * * Current implementation is x86/ia32-specific and will not even build on * x86_64) * */ static inline void dahdi_kernel_fpu_begin(void) { struct fpu_save_buf *buf = &__get_cpu_var(fpu_buf); __asm__ __volatile__ ("movl %%cr0,%0; clts" : "=r" (buf->cr0)); __asm__ __volatile__ ("fnsave %0" : "=m" (buf->fpu_buf)); } /** dahdi_kernel_fpu_end() - restore floating point context * * Must be used with context saved by dahdi_kernel_fpu_begin(). See its * documentation for further information. */ static inline void dahdi_kernel_fpu_end(void) { struct fpu_save_buf *buf = &__get_cpu_var(fpu_buf); __asm__ __volatile__ ("frstor %0" : "=m" (buf->fpu_buf)); __asm__ __volatile__ ("movl %0,%%cr0" : : "r" (buf->cr0)); } #else /* We haven't fixed FP context saving/restoring yet */ /* Very strange things can happen when the context is not properly * restored. OTOH, some people do report success with this. Hence we * so far just issue a warning */ #warning CONFIG_DAHDI_MMX may behave randomly on this platform #define dahdi_kernel_fpu_begin kernel_fpu_begin #define dahdi_kernel_fpu_end kernel_fpu_end #endif #endif struct dahdi_timer { int ms; /* Countdown */ int pos; /* Position */ int ping; /* Whether we've been ping'd */ int tripped; /* Whether we're tripped */ struct list_head list; wait_queue_head_t sel; }; static LIST_HEAD(dahdi_timers); static DEFINE_SPINLOCK(dahdi_timer_lock); #define DEFAULT_TONE_ZONE (-1) struct dahdi_zone { int ringcadence[DAHDI_MAX_CADENCE]; struct dahdi_tone *tones[DAHDI_TONE_MAX]; /* Each of these is a circular list of dahdi_tones to generate what we want. Use NULL if the tone is unavailable */ struct dahdi_tone dtmf[16]; /* DTMF tones for this zone, with desired length */ struct dahdi_tone dtmf_continuous[16]; /* DTMF tones for this zone, continuous play */ struct dahdi_tone mfr1[15]; /* MFR1 tones for this zone, with desired length */ struct dahdi_tone mfr2_fwd[15]; /* MFR2 FWD tones for this zone, with desired length */ struct dahdi_tone mfr2_rev[15]; /* MFR2 REV tones for this zone, with desired length */ struct dahdi_tone mfr2_fwd_continuous[16]; /* MFR2 FWD tones for this zone, continuous play */ struct dahdi_tone mfr2_rev_continuous[16]; /* MFR2 REV tones for this zone, continuous play */ struct list_head node; struct kref refcount; const char *name; /* Informational, only */ u8 num; }; static void tone_zone_release(struct kref *kref) { struct dahdi_zone *z = container_of(kref, struct dahdi_zone, refcount); kfree(z->name); kfree(z); } /** * tone_zone_put() - Release the reference on the tone_zone. * * On old kernels, since kref_put does not have a return value, we'll just * always report that we released the memory. * */ static inline int tone_zone_put(struct dahdi_zone *z) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) kref_put(&z->refcount, tone_zone_release); return 1; #else return kref_put(&z->refcount, tone_zone_release); #endif } static inline void tone_zone_get(struct dahdi_zone *z) { kref_get(&z->refcount); } static DEFINE_SPINLOCK(zone_lock); /* The first zone on the list is the default zone. */ static LIST_HEAD(tone_zones); /* Protects the span_list and pseudo_chans lists from concurrent access in * process context. The spin_lock is needed to synchronize with the interrupt * handler. */ static DEFINE_SPINLOCK(chan_lock); struct pseudo_chan { struct dahdi_chan chan; struct list_head node; }; static inline struct pseudo_chan *chan_to_pseudo(struct dahdi_chan *chan) { return container_of(chan, struct pseudo_chan, chan); } enum { FIRST_PSEUDO_CHANNEL = 0x8000, }; /* This list is protected by the chan_lock. */ static LIST_HEAD(pseudo_chans); /** * is_pseudo_chan() - By definition pseudo channels are not on a span. */ static inline bool is_pseudo_chan(const struct dahdi_chan *chan) { return (NULL == chan->span); } static DEFINE_MUTEX(registration_mutex); static LIST_HEAD(span_list); static unsigned long __for_each_channel(unsigned long (*func)(struct dahdi_chan *chan, unsigned long data), unsigned long data) { int res; struct dahdi_span *s; struct pseudo_chan *pseudo; list_for_each_entry(s, &span_list, node) { unsigned long x; for (x = 0; x < s->channels; x++) { struct dahdi_chan *const chan = s->chans[x]; res = func(chan, data); if (res) return res; } } list_for_each_entry(pseudo, &pseudo_chans, node) { res = func(&pseudo->chan, data); if (res) return res; } return 0; } /** * _chan_from_num - Lookup a channel * * Must be called with the registration_mutex held. * */ static struct dahdi_chan *_chan_from_num(unsigned int channo) { struct dahdi_span *s; struct pseudo_chan *pseudo; if (channo >= FIRST_PSEUDO_CHANNEL) { list_for_each_entry(pseudo, &pseudo_chans, node) { if (pseudo->chan.channo == channo) return &pseudo->chan; } return NULL; } /* When searching for the channel amongst the spans, we can use the * fact that channels on a span must be numbered consecutively to skip * checking each individual channel. */ list_for_each_entry(s, &span_list, node) { unsigned int basechan; struct dahdi_chan *chan; if (unlikely(!s->channels)) continue; basechan = s->chans[0]->channo; if (channo >= (basechan + s->channels)) continue; /* Since all the spans should be on the list in sorted order, * if channo is less than base chan, the caller must be * looking for a channel that has already been removed. */ if (unlikely(channo < basechan)) return NULL; chan = s->chans[channo - basechan]; WARN_ON(chan->channo != channo); return chan; } return NULL; } static struct dahdi_chan *chan_from_num(unsigned int channo) { struct dahdi_chan *chan; mutex_lock(®istration_mutex); chan = _chan_from_num(channo); mutex_unlock(®istration_mutex); return chan; } static inline struct dahdi_chan *chan_from_file(struct file *file) { return (file->private_data) ? file->private_data : chan_from_num(UNIT(file)); } /** * _find_span() - Find a span by span number. * * Must be called with registration_mutex held. * */ static struct dahdi_span *_find_span(int spanno) { struct dahdi_span *s; list_for_each_entry(s, &span_list, node) { if (s->spanno == spanno) { return s; } } return NULL; } /** * span_find_and_get() - Search for the span by number, and if found take out * a reference on it. * * When you are no longer using the returned pointer, you must release it with * a put_span call. * */ static struct dahdi_span *span_find_and_get(int spanno) { struct dahdi_span *found; mutex_lock(®istration_mutex); found = _find_span(spanno); if (found && !try_module_get(found->ops->owner)) found = NULL; mutex_unlock(®istration_mutex); return found; } static void put_span(struct dahdi_span *span) { module_put(span->ops->owner); } static unsigned int span_count(void) { unsigned int count = 0; struct dahdi_span *s; unsigned long flags; spin_lock_irqsave(&chan_lock, flags); list_for_each_entry(s, &span_list, node) ++count; spin_unlock_irqrestore(&chan_lock, flags); return count; } static inline bool can_provide_timing(const struct dahdi_span *const s) { return !s->cannot_provide_timing; } static int maxconfs; short __dahdi_mulaw[256]; short __dahdi_alaw[256]; #ifndef CONFIG_CALC_XLAW u_char __dahdi_lin2mu[16384]; u_char __dahdi_lin2a[16384]; #endif static u_char defgain[256]; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) #define __RW_LOCK_UNLOCKED() RW_LOCK_UNLOCKED #endif #define NUM_SIGS 10 static DEFINE_SPINLOCK(ecfactory_list_lock); static LIST_HEAD(ecfactory_list); struct ecfactory { const struct dahdi_echocan_factory *ec; struct list_head list; }; int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec) { struct ecfactory *cur; struct ecfactory *new; WARN_ON(!ec->owner); new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) return -ENOMEM; INIT_LIST_HEAD(&new->list); spin_lock(&ecfactory_list_lock); /* make sure it isn't already registered */ list_for_each_entry(cur, &ecfactory_list, list) { if (cur->ec == ec) { spin_unlock(&ecfactory_list_lock); kfree(new); return -EPERM; } } new->ec = ec; list_add_tail(&new->list, &ecfactory_list); spin_unlock(&ecfactory_list_lock); return 0; } void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec) { struct ecfactory *cur, *next; spin_lock(&ecfactory_list_lock); list_for_each_entry_safe(cur, next, &ecfactory_list, list) { if (cur->ec == ec) { list_del(&cur->list); kfree(cur); break; } } spin_unlock(&ecfactory_list_lock); } static inline void rotate_sums(void) { /* Rotate where we sum and so forth */ static int pos = 0; conf_sums_prev = sums + (DAHDI_MAX_CONF + 1) * pos; conf_sums = sums + (DAHDI_MAX_CONF + 1) * ((pos + 1) % 3); conf_sums_next = sums + (DAHDI_MAX_CONF + 1) * ((pos + 2) % 3); pos = (pos + 1) % 3; memset(conf_sums_next, 0, maxconfs * sizeof(sumtype)); } /** * is_chan_dacsed() - True if chan is sourcing it's data from another channel. * */ static inline bool is_chan_dacsed(const struct dahdi_chan *const chan) { return (NULL != chan->dacs_chan); } /** * can_dacs_chans() - Returns true if it may be possible to dacs two channels. * */ static bool can_dacs_chans(struct dahdi_chan *dst, struct dahdi_chan *src) { if (src && dst && src->span && dst->span && src->span->ops && dst->span->ops && src->span->ops->dacs && (src->span->ops->dacs == dst->span->ops->dacs)) return true; else return false; } /** * dahdi_chan_dacs() - Cross (or uncross) connect two channels. * @dst: Channel on which to transmit the src data. * @src: NULL to disable cross connect, otherwise the source of the * data. * * This allows those boards that support it to cross connect one channel to * another in hardware. If the cards cannot be crossed, uncross the * destination channel by default.. * */ static int dahdi_chan_dacs(struct dahdi_chan *dst, struct dahdi_chan *src) { int ret = 0; if (can_dacs_chans(dst, src)) ret = dst->span->ops->dacs(dst, src); else if (dst->span && dst->span->ops->dacs) ret = dst->span->ops->dacs(dst, NULL); return ret; } static void dahdi_disable_dacs(struct dahdi_chan *chan) { dahdi_chan_dacs(chan, NULL); } /*! * \return quiescent (idle) signalling states, for the various signalling types */ static int dahdi_q_sig(struct dahdi_chan *chan) { int x; static const unsigned int in_sig[NUM_SIGS][2] = { { DAHDI_SIG_NONE, 0 }, { DAHDI_SIG_EM, (DAHDI_ABIT << 8) }, { DAHDI_SIG_FXSLS, DAHDI_BBIT | (DAHDI_BBIT << 8) }, { DAHDI_SIG_FXSGS, DAHDI_ABIT | DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, { DAHDI_SIG_FXSKS, DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, { DAHDI_SIG_FXOLS, (DAHDI_ABIT << 8) }, { DAHDI_SIG_FXOGS, DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, { DAHDI_SIG_FXOKS, (DAHDI_ABIT << 8) }, { DAHDI_SIG_SF, 0 }, { DAHDI_SIG_EM_E1, DAHDI_DBIT | ((DAHDI_ABIT | DAHDI_DBIT) << 8) }, }; /* must have span to begin with */ if (!chan->span) return -1; /* if RBS does not apply, return error */ if (!(chan->span->flags & DAHDI_FLAG_RBS) || !chan->span->ops->rbsbits) return -1; if (chan->sig == DAHDI_SIG_CAS) return chan->idlebits; for (x = 0; x < NUM_SIGS; x++) { if (in_sig[x][0] == chan->sig) return in_sig[x][1]; } return -1; /* not found -- error */ } #ifdef CONFIG_PROC_FS static const char *sigstr(int sig) { switch (sig) { case DAHDI_SIG_FXSLS: return "FXSLS"; case DAHDI_SIG_FXSKS: return "FXSKS"; case DAHDI_SIG_FXSGS: return "FXSGS"; case DAHDI_SIG_FXOLS: return "FXOLS"; case DAHDI_SIG_FXOKS: return "FXOKS"; case DAHDI_SIG_FXOGS: return "FXOGS"; case DAHDI_SIG_EM: return "E&M"; case DAHDI_SIG_EM_E1: return "E&M-E1"; case DAHDI_SIG_CLEAR: return "Clear"; case DAHDI_SIG_HDLCRAW: return "HDLCRAW"; case DAHDI_SIG_HDLCFCS: return "HDLCFCS"; case DAHDI_SIG_HDLCNET: return "HDLCNET"; case DAHDI_SIG_HARDHDLC: return "Hardware-assisted HDLC"; case DAHDI_SIG_MTP2: return "MTP2"; case DAHDI_SIG_SLAVE: return "Slave"; case DAHDI_SIG_CAS: return "CAS"; case DAHDI_SIG_DACS: return "DACS"; case DAHDI_SIG_DACS_RBS: return "DACS+RBS"; case DAHDI_SIG_SF: return "SF (ToneOnly)"; case DAHDI_SIG_NONE: default: return "Unconfigured"; } } static int fill_alarm_string(char *buf, int count, int alarms) { int len; if (alarms <= 0) return 0; len = snprintf(buf, count, "%s%s%s%s%s%s", (alarms & DAHDI_ALARM_BLUE) ? "BLUE " : "", (alarms & DAHDI_ALARM_YELLOW) ? "YELLOW " : "", (alarms & DAHDI_ALARM_RED) ? "RED " : "", (alarms & DAHDI_ALARM_LOOPBACK) ? "LOOP " : "", (alarms & DAHDI_ALARM_RECOVER) ? "RECOVERING " : "", (alarms & DAHDI_ALARM_NOTOPEN) ? "NOTOPEN " : ""); return len; } /* * Sequential proc interface */ static void seq_fill_alarm_string(struct seq_file *sfile, int alarms) { char tmp[70]; if (fill_alarm_string(tmp, sizeof(tmp), alarms)) seq_printf(sfile, "%s", tmp); } static int dahdi_seq_show(struct seq_file *sfile, void *v) { long spanno = (long)sfile->private; int x; struct dahdi_span *s; s = span_find_and_get(spanno); if (!s) return -ENODEV; if (s->name) seq_printf(sfile, "Span %d: %s ", s->spanno, s->name); if (s->desc) seq_printf(sfile, "\"%s\"", s->desc); else seq_printf(sfile, "\"\""); if (s == master) seq_printf(sfile, " (MASTER)"); if (s->lineconfig) { /* framing first */ if (s->lineconfig & DAHDI_CONFIG_B8ZS) seq_printf(sfile, " B8ZS/"); else if (s->lineconfig & DAHDI_CONFIG_AMI) seq_printf(sfile, " AMI/"); else if (s->lineconfig & DAHDI_CONFIG_HDB3) seq_printf(sfile, " HDB3/"); /* then coding */ if (s->lineconfig & DAHDI_CONFIG_ESF) seq_printf(sfile, "ESF"); else if (s->lineconfig & DAHDI_CONFIG_D4) seq_printf(sfile, "D4"); else if (s->lineconfig & DAHDI_CONFIG_CCS) seq_printf(sfile, "CCS"); /* E1's can enable CRC checking */ if (s->lineconfig & DAHDI_CONFIG_CRC4) seq_printf(sfile, "/CRC4"); } seq_printf(sfile, " "); /* list alarms */ seq_fill_alarm_string(sfile, s->alarms); if (s->syncsrc && (s->syncsrc == s->spanno)) seq_printf(sfile, "ClockSource "); seq_printf(sfile, "\n"); if (s->count.bpv) seq_printf(sfile, "\tBPV count: %d\n", s->count.bpv); if (s->count.crc4) seq_printf(sfile, "\tCRC4 error count: %d\n", s->count.crc4); if (s->count.ebit) seq_printf(sfile, "\tE-bit error count: %d\n", s->count.ebit); if (s->count.fas) seq_printf(sfile, "\tFAS error count: %d\n", s->count.fas); if (s->irqmisses) seq_printf(sfile, "\tIRQ misses: %d\n", s->irqmisses); if (s->timingslips) seq_printf(sfile, "\tTiming slips: %d\n", s->timingslips); seq_printf(sfile, "\n"); for (x = 0; x < s->channels; x++) { struct dahdi_chan *chan = s->chans[x]; if (chan->name) seq_printf(sfile, "\t%4d %s ", chan->channo, chan->name); if (chan->sig) { if (chan->sig == DAHDI_SIG_SLAVE) seq_printf(sfile, "%s ", sigstr(chan->master->sig)); else { seq_printf(sfile, "%s ", sigstr(chan->sig)); if (chan->nextslave && (chan->master->channo == chan->channo)) seq_printf(sfile, "Master "); } } else if (!chan->sigcap) { seq_printf(sfile, "Reserved "); } if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) seq_printf(sfile, "(In use) "); #ifdef OPTIMIZE_CHANMUTE if (chan->chanmute) seq_printf(sfile, "(no pcm) "); #endif seq_fill_alarm_string(sfile, chan->chan_alarms); if (chan->ec_factory) seq_printf(sfile, "(EC: %s - %s) ", chan->ec_factory->get_name(chan), chan->ec_state ? "ACTIVE" : "INACTIVE"); seq_printf(sfile, "\n"); } put_span(s); return 0; } static int dahdi_proc_open(struct inode *inode, struct file *file) { return single_open(file, dahdi_seq_show, PDE(inode)->data); } static const struct file_operations dahdi_proc_ops = { .owner = THIS_MODULE, .open = dahdi_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #endif static int dahdi_first_empty_alias(void) { /* Find the first conference which has no alias pointing to it */ int x; for (x=1;x 0; x--) { if (confrev[x]) { maxconfs = x + 1; return; } } maxconfs = 0; } static int dahdi_first_empty_conference(void) { /* Find the first conference which has no alias */ int x; for (x = DAHDI_MAX_CONF - 1; x > 0; x--) { if (!confalias[x]) return x; } return -1; } static int dahdi_get_conf_alias(int x) { int a; if (confalias[x]) return confalias[x]; /* Allocate an alias */ a = dahdi_first_empty_alias(); confalias[x] = a; confrev[a] = x; /* Highest conference may have changed */ recalc_maxconfs(); return a; } static unsigned long _chan_in_conf(struct dahdi_chan *chan, unsigned long x) { const int confmode = chan->confmode & DAHDI_CONF_MODE_MASK; return (chan && (chan->confna == x) && (confmode == DAHDI_CONF_CONF || confmode == DAHDI_CONF_CONFANN || confmode == DAHDI_CONF_CONFMON || confmode == DAHDI_CONF_CONFANNMON || confmode == DAHDI_CONF_REALANDPSEUDO)) ? 1 : 0; } static void dahdi_check_conf(int x) { unsigned long res; unsigned long flags; /* return if no valid conf number */ if (x <= 0) return; /* Return if there is no alias */ if (!confalias[x]) return; spin_lock_irqsave(&chan_lock, flags); res = __for_each_channel(_chan_in_conf, x); spin_unlock_irqrestore(&chan_lock, flags); if (res) return; /* If we get here, nobody is in the conference anymore. Clear it out both forward and reverse */ confrev[confalias[x]] = 0; confalias[x] = 0; /* Highest conference may have changed */ recalc_maxconfs(); } /* enqueue an event on a channel */ static void __qevent(struct dahdi_chan *chan, int event) { /* if full, ignore */ if ((chan->eventoutidx == 0) && (chan->eventinidx == (DAHDI_MAX_EVENTSIZE - 1))) return; /* if full, ignore */ if (chan->eventinidx == (chan->eventoutidx - 1)) return; /* save the event */ chan->eventbuf[chan->eventinidx++] = event; /* wrap the index, if necessary */ if (chan->eventinidx >= DAHDI_MAX_EVENTSIZE) chan->eventinidx = 0; /* wake em all up */ wake_up_interruptible(&chan->waitq); return; } void dahdi_qevent_nolock(struct dahdi_chan *chan, int event) { __qevent(chan, event); } void dahdi_qevent_lock(struct dahdi_chan *chan, int event) { unsigned long flags; spin_lock_irqsave(&chan->lock, flags); __qevent(chan, event); spin_unlock_irqrestore(&chan->lock, flags); } static inline void calc_fcs(struct dahdi_chan *ss, int inwritebuf) { int x; unsigned int fcs = PPP_INITFCS; unsigned char *data = ss->writebuf[inwritebuf]; int len = ss->writen[inwritebuf]; /* Not enough space to do FCS calculation */ if (len < 2) return; for (x = 0; x < len - 2; x++) fcs = PPP_FCS(fcs, data[x]); fcs ^= 0xffff; /* Send out the FCS */ data[len - 2] = (fcs & 0xff); data[len - 1] = (fcs >> 8) & 0xff; } static int dahdi_reallocbufs(struct dahdi_chan *ss, int blocksize, int numbufs) { unsigned char *newtxbuf = NULL; unsigned char *newrxbuf = NULL; unsigned char *oldtxbuf = NULL; unsigned char *oldrxbuf = NULL; unsigned long flags; int x; /* Check numbufs */ if (numbufs < 2) numbufs = 2; if (numbufs > DAHDI_MAX_NUM_BUFS) numbufs = DAHDI_MAX_NUM_BUFS; /* We need to allocate our buffers now */ if (blocksize) { newtxbuf = kzalloc(blocksize * numbufs, GFP_KERNEL); if (NULL == newtxbuf) return -ENOMEM; newrxbuf = kzalloc(blocksize * numbufs, GFP_KERNEL); if (NULL == newrxbuf) { kfree(newtxbuf); return -ENOMEM; } } /* Now that we've allocated our new buffers, we can safely move things around... */ spin_lock_irqsave(&ss->lock, flags); ss->blocksize = blocksize; /* set the blocksize */ oldrxbuf = ss->readbuf[0]; /* Keep track of the old buffer */ oldtxbuf = ss->writebuf[0]; ss->readbuf[0] = NULL; if (newrxbuf) { BUG_ON(NULL == newtxbuf); for (x = 0; x < numbufs; x++) { ss->readbuf[x] = newrxbuf + x * blocksize; ss->writebuf[x] = newtxbuf + x * blocksize; } } else { for (x = 0; x < numbufs; x++) { ss->readbuf[x] = NULL; ss->writebuf[x] = NULL; } } /* Mark all buffers as empty */ for (x = 0; x < numbufs; x++) { ss->writen[x] = ss->writeidx[x]= ss->readn[x]= ss->readidx[x] = 0; } /* Keep track of where our data goes (if it goes anywhere at all) */ if (newrxbuf) { ss->inreadbuf = 0; ss->inwritebuf = 0; } else { ss->inreadbuf = -1; ss->inwritebuf = -1; } ss->outreadbuf = -1; ss->outwritebuf = -1; ss->numbufs = numbufs; if ((ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ss->txbufpolicy == DAHDI_POLICY_HALF_FULL)) ss->txdisable = 1; else ss->txdisable = 0; if (ss->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) ss->rxdisable = 1; else ss->rxdisable = 0; spin_unlock_irqrestore(&ss->lock, flags); kfree(oldtxbuf); kfree(oldrxbuf); return 0; } static int dahdi_hangup(struct dahdi_chan *chan); static void dahdi_set_law(struct dahdi_chan *chan, int law); /* Pull a DAHDI_CHUNKSIZE piece off the queue. Returns 0 on success or -1 on failure. If failed, provides silence */ static int __buf_pull(struct confq *q, u_char *data, struct dahdi_chan *c) { int oldoutbuf = q->outbuf; /* Ain't nuffin to read */ if (q->outbuf < 0) { if (data) memset(data, DAHDI_LIN2X(0,c), DAHDI_CHUNKSIZE); return -1; } if (data) memcpy(data, q->buf[q->outbuf], DAHDI_CHUNKSIZE); q->outbuf = (q->outbuf + 1) % DAHDI_CB_SIZE; /* Won't be nuffin next time */ if (q->outbuf == q->inbuf) { q->outbuf = -1; } /* If they thought there was no space then there is now where we just read */ if (q->inbuf < 0) q->inbuf = oldoutbuf; return 0; } /* Returns a place to put stuff, or NULL if there is no room */ static u_char *__buf_pushpeek(struct confq *q) { if (q->inbuf < 0) return NULL; return q->buf[q->inbuf]; } static u_char *__buf_peek(struct confq *q) { if (q->outbuf < 0) return NULL; return q->buf[q->outbuf]; } /* Push something onto the queue, or assume what is there is valid if data is NULL */ static int __buf_push(struct confq *q, const u_char *data) { int oldinbuf = q->inbuf; if (q->inbuf < 0) { return -1; } if (data) /* Copy in the data */ memcpy(q->buf[q->inbuf], data, DAHDI_CHUNKSIZE); /* Advance the inbuf pointer */ q->inbuf = (q->inbuf + 1) % DAHDI_CB_SIZE; if (q->inbuf == q->outbuf) { /* No space anymore... */ q->inbuf = -1; } /* If they don't think data is ready, let them know it is now */ if (q->outbuf < 0) { q->outbuf = oldinbuf; } return 0; } static void reset_conf(struct dahdi_chan *chan) { int x; /* Empty out buffers and reset to initialization */ for (x = 0; x < DAHDI_CB_SIZE; x++) chan->confin.buf[x] = chan->confin.buffer + DAHDI_CHUNKSIZE * x; chan->confin.inbuf = 0; chan->confin.outbuf = -1; for (x = 0; x < DAHDI_CB_SIZE; x++) chan->confout.buf[x] = chan->confout.buffer + DAHDI_CHUNKSIZE * x; chan->confout.inbuf = 0; chan->confout.outbuf = -1; } static const struct dahdi_echocan_factory *find_echocan(const char *name) { struct ecfactory *cur; char *name_upper; char *c; const char *d; char modname_buf[128] = "dahdi_echocan_"; unsigned int tried_once = 0; name_upper = kmalloc(strlen(name) + 1, GFP_KERNEL); if (!name_upper) return NULL; for (c = name_upper, d = name; *d; c++, d++) { *c = toupper(*d); } *c = '\0'; retry: spin_lock(&ecfactory_list_lock); list_for_each_entry(cur, &ecfactory_list, list) { if (!strcmp(name_upper, cur->ec->get_name(NULL))) { if (try_module_get(cur->ec->owner)) { spin_unlock(&ecfactory_list_lock); kfree(name_upper); return cur->ec; } else { spin_unlock(&ecfactory_list_lock); kfree(name_upper); return NULL; } } } spin_unlock(&ecfactory_list_lock); if (tried_once) { kfree(name_upper); return NULL; } /* couldn't find it, let's try to load it */ for (c = &modname_buf[strlen(modname_buf)], d = name; *d; c++, d++) { *c = tolower(*d); } request_module("%s", modname_buf); tried_once = 1; /* and try one more time */ goto retry; } static void release_echocan(const struct dahdi_echocan_factory *ec) { if (ec) module_put(ec->owner); } /** * is_gain_allocated() - True if gain tables were dynamically allocated. * @chan: The channel to check. */ static inline bool is_gain_allocated(const struct dahdi_chan *chan) { return (chan->rxgain && (chan->rxgain != defgain)); } static const char *hwec_def_name = "HWEC"; static const char *hwec_get_name(const struct dahdi_chan *chan) { if (chan && chan->span && chan->span->ops->echocan_name) return chan->span->ops->echocan_name(chan); else return hwec_def_name; } static int hwec_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { if (chan->span && chan->span->ops->echocan_create) return chan->span->ops->echocan_create(chan, ecp, p, ec); else return -ENODEV; } static const struct dahdi_echocan_factory hwec_factory = { .get_name = hwec_get_name, .owner = THIS_MODULE, .echocan_create = hwec_echocan_create, }; /** * dahdi_enable_hw_preechocan - Let the board driver enable hwpreec if possible. * @chan: The channel to monitor. * * Returns 0 on success, if there is a software echocanceler attached on * the channel, or the span does not have an enable_hw_preechocan callback. * Otherwise an error code. * */ static int dahdi_enable_hw_preechocan(struct dahdi_chan *chan) { int res; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); if (chan->ec_factory != &hwec_factory) res = -ENODEV; else res = 0; spin_unlock_irqrestore(&chan->lock, flags); if (-ENODEV == res) return 0; if (chan->span->ops->enable_hw_preechocan) return chan->span->ops->enable_hw_preechocan(chan); else return 0; } /** * dahdi_disable_hw_preechocan - Disable any hardware pre echocan monitoring. * @chan: The channel to stop monitoring. * * Give the board driver the option to free any resources needed to monitor * the preechocan stream. * */ static void dahdi_disable_hw_preechocan(struct dahdi_chan *chan) { if (chan->span->ops->disable_hw_preechocan) chan->span->ops->disable_hw_preechocan(chan); } /* * close_channel - close the channel, resetting any channel variables * @chan: the dahdi_chan to close * * This function is called before either the parent span is linked into the * span list, or for pseudos, place on the psuedo_list. Therefore, this * function nor it's callers should depend on the channel being findable * via those methods. */ static void close_channel(struct dahdi_chan *chan) { unsigned long flags; const void *rxgain = NULL; struct dahdi_echocan_state *ec_state; const struct dahdi_echocan_factory *ec_current; int oldconf; short *readchunkpreec; #ifdef CONFIG_DAHDI_PPP struct ppp_channel *ppp; #endif might_sleep(); if (chan->conf_chan && ((DAHDI_CONF_MONITOR_RX_PREECHO == chan->confmode) || (DAHDI_CONF_MONITOR_TX_PREECHO == chan->confmode) || (DAHDI_CONF_MONITORBOTH_PREECHO == chan->confmode))) { void *readchunkpreec; spin_lock_irqsave(&chan->conf_chan->lock, flags); readchunkpreec = chan->conf_chan->readchunkpreec; chan->conf_chan->readchunkpreec = NULL; spin_unlock_irqrestore(&chan->conf_chan->lock, flags); if (readchunkpreec) { dahdi_disable_hw_preechocan(chan->conf_chan); kfree(readchunkpreec); } } /* XXX Buffers should be send out before reallocation!!! XXX */ if (!(chan->flags & DAHDI_FLAG_NOSTDTXRX)) dahdi_reallocbufs(chan, 0, 0); spin_lock_irqsave(&chan->lock, flags); #ifdef CONFIG_DAHDI_PPP ppp = chan->ppp; chan->ppp = NULL; #endif ec_state = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; readchunkpreec = chan->readchunkpreec; chan->readchunkpreec = NULL; chan->curtone = NULL; if (chan->curzone) { struct dahdi_zone *zone = chan->curzone; chan->curzone = NULL; tone_zone_put(zone); } chan->cadencepos = 0; chan->pdialcount = 0; dahdi_hangup(chan); chan->itimerset = chan->itimer = 0; chan->pulsecount = 0; chan->pulsetimer = 0; chan->ringdebtimer = 0; chan->txdialbuf[0] = '\0'; chan->digitmode = DIGIT_MODE_DTMF; chan->dialing = 0; chan->afterdialingtimer = 0; /* initialize IO MUX mask */ chan->iomask = 0; /* save old conf number, if any */ oldconf = chan->confna; /* initialize conference variables */ chan->_confn = 0; chan->confna = 0; chan->confmode = 0; if ((chan->sig & __DAHDI_SIG_DACS) != __DAHDI_SIG_DACS) chan->dacs_chan = NULL; chan->confmute = 0; chan->gotgs = 0; reset_conf(chan); chan->dacs_chan = NULL; if (is_gain_allocated(chan)) rxgain = chan->rxgain; chan->rxgain = defgain; chan->txgain = defgain; chan->eventinidx = chan->eventoutidx = 0; chan->flags &= ~(DAHDI_FLAG_LOOPED | DAHDI_FLAG_LINEAR | DAHDI_FLAG_PPP | DAHDI_FLAG_SIGFREEZE); dahdi_set_law(chan, DAHDI_LAW_DEFAULT); memset(chan->conflast, 0, sizeof(chan->conflast)); memset(chan->conflast1, 0, sizeof(chan->conflast1)); memset(chan->conflast2, 0, sizeof(chan->conflast2)); if (chan->span && oldconf) dahdi_disable_dacs(chan); spin_unlock_irqrestore(&chan->lock, flags); if (ec_state) { ec_state->ops->echocan_free(chan, ec_state); release_echocan(ec_current); } /* release conference resource, if any to release */ if (oldconf) dahdi_check_conf(oldconf); if (rxgain) kfree(rxgain); if (readchunkpreec) { dahdi_disable_hw_preechocan(chan); kfree(readchunkpreec); } #ifdef CONFIG_DAHDI_PPP if (ppp) { tasklet_kill(&chan->ppp_calls); skb_queue_purge(&chan->ppp_rq); ppp_unregister_channel(ppp); kfree(ppp); } #endif } static int dahdi_ioctl_freezone(unsigned long data) { struct dahdi_zone *z; struct dahdi_zone *found = NULL; int num; if (get_user(num, (int __user *) data)) return -EFAULT; spin_lock(&zone_lock); list_for_each_entry(z, &tone_zones, node) { if (z->num == num) { found = z; break; } } if (found) { list_del(&found->node); } spin_unlock(&zone_lock); if (found) { if (debug) { module_printk(KERN_INFO, "Unregistering tone zone %d (%s)\n", found->num, found->name); } tone_zone_put(found); } return 0; } static int dahdi_register_tone_zone(struct dahdi_zone *zone) { struct dahdi_zone *cur; int res = 0; kref_init(&zone->refcount); spin_lock(&zone_lock); list_for_each_entry(cur, &tone_zones, node) { if (cur->num == zone->num) { res = -EINVAL; break; } } if (!res) { list_add_tail(&zone->node, &tone_zones); if (debug) { module_printk(KERN_INFO, "Registered tone zone %d (%s)\n", zone->num, zone->name); } } spin_unlock(&zone_lock); return res; } static int start_tone_digit(struct dahdi_chan *chan, int tone) { struct dahdi_tone *playtone = NULL; int base, max; if (!chan->curzone) return -ENODATA; switch (chan->digitmode) { case DIGIT_MODE_DTMF: /* Set dialing so that a dial operation doesn't interrupt this tone */ chan->dialing = 1; base = DAHDI_TONE_DTMF_BASE; max = DAHDI_TONE_DTMF_MAX; break; case DIGIT_MODE_MFR2_FWD: base = DAHDI_TONE_MFR2_FWD_BASE; max = DAHDI_TONE_MFR2_FWD_MAX; break; case DIGIT_MODE_MFR2_REV: base = DAHDI_TONE_MFR2_REV_BASE; max = DAHDI_TONE_MFR2_REV_MAX; break; default: return -EINVAL; } if ((tone < base) || (tone > max)) return -EINVAL; switch (chan->digitmode) { case DIGIT_MODE_DTMF: playtone = &chan->curzone->dtmf_continuous[tone - base]; break; case DIGIT_MODE_MFR2_FWD: playtone = &chan->curzone->mfr2_fwd_continuous[tone - base]; break; case DIGIT_MODE_MFR2_REV: playtone = &chan->curzone->mfr2_rev_continuous[tone - base]; break; } if (!playtone || !playtone->tonesamples) return -ENOSYS; chan->curtone = playtone; return 0; } static int start_tone(struct dahdi_chan *chan, int tone) { int res = -EINVAL; /* Stop the current tone, no matter what */ chan->tonep = 0; chan->curtone = NULL; chan->pdialcount = 0; chan->txdialbuf[0] = '\0'; chan->dialing = 0; if (tone == -1) { /* Just stop the current tone */ res = 0; } else if (!chan->curzone) { static int __warnonce = 1; if (__warnonce) { __warnonce = 0; /* The tonezones are loaded by dahdi_cfg based on /etc/dahdi/system.conf. */ module_printk(KERN_WARNING, "DAHDI: Cannot start tones until tone zone is loaded.\n"); } /* Note that no tone zone exists at the moment */ res = -ENODATA; } else if ((tone >= 0 && tone <= DAHDI_TONE_MAX)) { /* Have a tone zone */ if (chan->curzone->tones[tone]) { chan->curtone = chan->curzone->tones[tone]; res = 0; } else { /* Indicate that zone is loaded but no such tone exists */ res = -ENOSYS; } } else if (chan->digitmode == DIGIT_MODE_DTMF || chan->digitmode == DIGIT_MODE_MFR2_FWD || chan->digitmode == DIGIT_MODE_MFR2_REV) { res = start_tone_digit(chan, tone); } else { chan->dialing = 0; res = -EINVAL; } if (chan->curtone) dahdi_init_tone_state(&chan->ts, chan->curtone); return res; } static int set_tone_zone(struct dahdi_chan *chan, int zone) { int res = 0; struct dahdi_zone *cur; struct dahdi_zone *z; unsigned long flags; z = NULL; spin_lock(&zone_lock); if ((DEFAULT_TONE_ZONE == zone) && !list_empty(&tone_zones)) { z = list_entry(tone_zones.next, struct dahdi_zone, node); tone_zone_get(z); } else { list_for_each_entry(cur, &tone_zones, node) { if (cur->num != (u8)zone) continue; z = cur; tone_zone_get(z); break; } } spin_unlock(&zone_lock); if (unlikely(!z)) return -ENODATA; spin_lock_irqsave(&chan->lock, flags); if (chan->curzone) { struct dahdi_zone *zone = chan->curzone; chan->curzone = NULL; tone_zone_put(zone); } chan->curzone = z; memcpy(chan->ringcadence, z->ringcadence, sizeof(chan->ringcadence)); spin_unlock_irqrestore(&chan->lock, flags); return res; } static void dahdi_set_law(struct dahdi_chan *chan, int law) { if (DAHDI_LAW_DEFAULT == law) { if (chan->deflaw) law = chan->deflaw; else if (chan->span) law = chan->span->deflaw; else law = DAHDI_LAW_MULAW; } if (law == DAHDI_LAW_ALAW) { chan->xlaw = __dahdi_alaw; #ifdef CONFIG_CALC_XLAW chan->lineartoxlaw = __dahdi_lineartoalaw; #else chan->lin2x = __dahdi_lin2a; #endif } else { chan->xlaw = __dahdi_mulaw; #ifdef CONFIG_CALC_XLAW chan->lineartoxlaw = __dahdi_lineartoulaw; #else chan->lin2x = __dahdi_lin2mu; #endif } } static void dahdi_chan_reg(struct dahdi_chan *chan) { might_sleep(); spin_lock_init(&chan->lock); init_waitqueue_head(&chan->waitq); if (!chan->master) chan->master = chan; if (!chan->readchunk) chan->readchunk = chan->sreadchunk; if (!chan->writechunk) chan->writechunk = chan->swritechunk; chan->rxgain = NULL; chan->txgain = NULL; dahdi_set_law(chan, 0); dahdi_set_law(chan, DAHDI_LAW_DEFAULT); close_channel(chan); /* set this AFTER running close_channel() so that HDLC channels wont cause hangage */ set_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags); } /** * dahdi_lboname() - Convert line build out number to string. * */ const char *dahdi_lboname(int lbo) { /* names of tx level settings */ static const char *const dahdi_txlevelnames[] = { "0 db (CSU)/0-133 feet (DSX-1)", "133-266 feet (DSX-1)", "266-399 feet (DSX-1)", "399-533 feet (DSX-1)", "533-655 feet (DSX-1)", "-7.5db (CSU)", "-15db (CSU)", "-22.5db (CSU)" }; if ((lbo < 0) || (lbo > 7)) return "Unknown"; return dahdi_txlevelnames[lbo]; } EXPORT_SYMBOL(dahdi_lboname); #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) static inline void print_debug_writebuf(struct dahdi_chan* ss, struct sk_buff *skb, int oldbuf) { #ifdef CONFIG_DAHDI_DEBUG int x; module_printk(KERN_NOTICE, "Buffered %d bytes to go out in buffer %d\n", ss->writen[oldbuf], oldbuf); module_printk(KERN_DEBUG ""); for (x=0;xwriten[oldbuf];x++) printk("%02x ", ss->writebuf[oldbuf][x]); printk("\n"); #endif } #endif #ifdef CONFIG_DAHDI_NET #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) static inline struct net_device_stats *hdlc_stats(struct net_device *dev) { return &dev->stats; } #endif static int dahdi_net_open(struct net_device *dev) { int res = hdlc_open(dev); struct dahdi_chan *ms = netdev_to_chan(dev); /* if (!dev->hard_start_xmit) return res; is this really necessary? --byg */ if (res) /* this is necessary to avoid kernel panic when UNSPEC link encap, proven --byg */ return res; if (!ms) { module_printk(KERN_NOTICE, "dahdi_net_open: nothing??\n"); return -EINVAL; } if (test_bit(DAHDI_FLAGBIT_OPEN, &ms->flags)) { module_printk(KERN_NOTICE, "%s is already open!\n", ms->name); return -EBUSY; } if (!dahdi_have_netdev(ms)) { module_printk(KERN_NOTICE, "%s is not a net device!\n", ms->name); return -EINVAL; } ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE; ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS); if (res) return res; fasthdlc_init(&ms->rxhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); fasthdlc_init(&ms->txhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); ms->infcs = PPP_INITFCS; netif_start_queue(chan_to_netdev(ms)); #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "DAHDINET: Opened channel %d name %s\n", ms->channo, ms->name); #endif return 0; } static int dahdi_register_hdlc_device(struct net_device *dev, const char *dev_name) { int result; if (dev_name && *dev_name) { if ((result = dev_alloc_name(dev, dev_name)) < 0) return result; } result = register_netdev(dev); if (result != 0) return -EIO; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14) if (netif_carrier_ok(dev)) netif_carrier_off(dev); /* no carrier until DCD goes up */ #endif return 0; } static int dahdi_net_stop(struct net_device *dev) { hdlc_device *h = dev_to_hdlc(dev); struct dahdi_hdlc *hdlc = h->priv; struct dahdi_chan *ms = hdlc_to_chan(hdlc); if (!ms) { module_printk(KERN_NOTICE, "dahdi_net_stop: nothing??\n"); return 0; } if (!dahdi_have_netdev(ms)) { module_printk(KERN_NOTICE, "dahdi_net_stop: %s is not a net device!\n", ms->name); return 0; } /* Not much to do here. Just deallocate the buffers */ netif_stop_queue(chan_to_netdev(ms)); dahdi_reallocbufs(ms, 0, 0); hdlc_close(dev); return 0; } /* kernel 2.4.20+ has introduced attach function, dunno what to do, just copy sources from dscc4 to be sure and ready for further mastering, NOOP right now (i.e. really a stub) --byg */ static int dahdi_net_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { /* struct net_device *dev = hdlc_to_dev(hdlc); struct dscc4_dev_priv *dpriv = dscc4_priv(dev); if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI && encoding != ENCODING_FM_MARK && encoding != ENCODING_FM_SPACE && encoding != ENCODING_MANCHESTER) return -EINVAL; if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0_CCITT && parity != PARITY_CRC16_PR1_CCITT && parity != PARITY_CRC32_PR0_CCITT && parity != PARITY_CRC32_PR1_CCITT) return -EINVAL; dpriv->encoding = encoding; dpriv->parity = parity;*/ return 0; } static struct dahdi_hdlc *dahdi_hdlc_alloc(void) { return kzalloc(sizeof(struct dahdi_hdlc), GFP_KERNEL); } static int dahdi_xmit(struct sk_buff *skb, struct net_device *dev) { /* FIXME: this construction seems to be not very optimal for me but I * could find nothing better at the moment (Friday, 10PM :( ) --byg * */ struct dahdi_chan *ss = netdev_to_chan(dev); struct net_device_stats *stats = hdlc_stats(dev); int retval = 1; int x,oldbuf; unsigned int fcs; unsigned char *data; unsigned long flags; /* See if we have any buffers */ spin_lock_irqsave(&ss->lock, flags); if (skb->len > ss->blocksize - 2) { module_printk(KERN_ERR, "dahdi_xmit(%s): skb is too large (%d > %d)\n", dev->name, skb->len, ss->blocksize -2); stats->tx_dropped++; retval = 0; } else if (ss->inwritebuf >= 0) { /* We have a place to put this packet */ /* XXX We should keep the SKB and avoid the memcpy XXX */ data = ss->writebuf[ss->inwritebuf]; memcpy(data, skb->data, skb->len); ss->writen[ss->inwritebuf] = skb->len; ss->writeidx[ss->inwritebuf] = 0; /* Calculate the FCS */ fcs = PPP_INITFCS; for (x=0;xlen;x++) fcs = PPP_FCS(fcs, data[x]); /* Invert it */ fcs ^= 0xffff; /* Send it out LSB first */ data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff); data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff; /* Advance to next window */ oldbuf = ss->inwritebuf; ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs; if (ss->inwritebuf == ss->outwritebuf) { /* Whoops, no more space. */ ss->inwritebuf = -1; netif_stop_queue(chan_to_netdev(ss)); } if (ss->outwritebuf < 0) { /* Let the interrupt handler know there's some space for us */ ss->outwritebuf = oldbuf; } dev->trans_start = jiffies; stats->tx_packets++; stats->tx_bytes += ss->writen[oldbuf]; print_debug_writebuf(ss, skb, oldbuf); retval = 0; /* Free the SKB */ dev_kfree_skb_any(skb); } spin_unlock_irqrestore(&ss->lock, flags); return retval; } static int dahdi_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { return hdlc_ioctl(dev, ifr, cmd); } #endif #ifdef CONFIG_DAHDI_PPP static int dahdi_ppp_xmit(struct ppp_channel *ppp, struct sk_buff *skb) { /* * If we can't handle the packet right now, return 0. If we * we handle or drop it, return 1. Always free if we return * 1 and never if we return 0 */ struct dahdi_chan *ss = ppp->private; int x,oldbuf; unsigned int fcs; unsigned char *data; unsigned long flags; int retval = 0; /* See if we have any buffers */ spin_lock_irqsave(&ss->lock, flags); if (!(test_bit(DAHDI_FLAGBIT_OPEN, &ss->flags))) { module_printk(KERN_ERR, "Can't transmit on closed channel\n"); retval = 1; } else if (skb->len > ss->blocksize - 4) { module_printk(KERN_ERR, "dahdi_ppp_xmit(%s): skb is too large (%d > %d)\n", ss->name, skb->len, ss->blocksize -2); retval = 1; } else if (ss->inwritebuf >= 0) { /* We have a place to put this packet */ /* XXX We should keep the SKB and avoid the memcpy XXX */ data = ss->writebuf[ss->inwritebuf]; /* Start with header of two bytes */ /* Add "ALL STATIONS" and "UNNUMBERED" */ data[0] = 0xff; data[1] = 0x03; ss->writen[ss->inwritebuf] = 2; /* Copy real data and increment amount written */ memcpy(data + 2, skb->data, skb->len); ss->writen[ss->inwritebuf] += skb->len; /* Re-set index back to zero */ ss->writeidx[ss->inwritebuf] = 0; /* Calculate the FCS */ fcs = PPP_INITFCS; for (x=0;xlen + 2;x++) fcs = PPP_FCS(fcs, data[x]); /* Invert it */ fcs ^= 0xffff; /* Point past the real data now */ data += (skb->len + 2); /* Send FCS out LSB first */ data[0] = (fcs & 0xff); data[1] = (fcs >> 8) & 0xff; /* Account for FCS length */ ss->writen[ss->inwritebuf]+=2; /* Advance to next window */ oldbuf = ss->inwritebuf; ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs; if (ss->inwritebuf == ss->outwritebuf) { /* Whoops, no more space. */ ss->inwritebuf = -1; } if (ss->outwritebuf < 0) { /* Let the interrupt handler know there's some space for us */ ss->outwritebuf = oldbuf; } print_debug_writebuf(ss, skb, oldbuf); retval = 1; } spin_unlock_irqrestore(&ss->lock, flags); if (retval) { /* Get rid of the SKB if we're returning non-zero */ /* N.B. this is called in process or BH context so dev_kfree_skb is OK. */ dev_kfree_skb(skb); } return retval; } static int dahdi_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags) { return -EIO; } static struct ppp_channel_ops ztppp_ops = { .start_xmit = dahdi_ppp_xmit, .ioctl = dahdi_ppp_ioctl, }; #endif /** * is_monitor_mode() - True if the confmode indicates that one channel is monitoring another. * */ static bool is_monitor_mode(int confmode) { confmode &= DAHDI_CONF_MODE_MASK; if ((confmode == DAHDI_CONF_MONITOR) || (confmode == DAHDI_CONF_MONITORTX) || (confmode == DAHDI_CONF_MONITORBOTH) || (confmode == DAHDI_CONF_MONITOR_RX_PREECHO) || (confmode == DAHDI_CONF_MONITOR_TX_PREECHO) || (confmode == DAHDI_CONF_MONITORBOTH_PREECHO)) { return true; } else { return false; } } static unsigned long _chan_cleanup(struct dahdi_chan *pos, unsigned long data) { unsigned long flags; struct dahdi_chan *const chan = (struct dahdi_chan *)data; /* Remove anyone pointing to us as master and make them their own thing */ if (pos->master == chan) pos->master = pos; if (((pos->confna == chan->channo) && is_monitor_mode(pos->confmode)) || (pos->dacs_chan == chan) || (pos->conf_chan == chan)) { /* Take them out of conference with us */ /* release conference resource if any */ if (pos->confna) dahdi_check_conf(pos->confna); dahdi_disable_dacs(pos); spin_lock_irqsave(&pos->lock, flags); pos->confna = 0; pos->_confn = 0; pos->confmode = 0; pos->conf_chan = NULL; pos->dacs_chan = NULL; spin_unlock_irqrestore(&pos->lock, flags); } return 0; } static void dahdi_chan_unreg(struct dahdi_chan *chan) { unsigned long flags; might_sleep(); /* In the case of surprise removal of hardware, make sure any open * file handles to this channel are disassociated with the actual * dahdi_chan. */ if (chan->file) { chan->file->private_data = NULL; if (chan->span) module_put(chan->span->ops->owner); } release_echocan(chan->ec_factory); #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(chan)) { unregister_hdlc_device(chan->hdlcnetdev->netdev); free_netdev(chan->hdlcnetdev->netdev); kfree(chan->hdlcnetdev); chan->hdlcnetdev = NULL; } #endif clear_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags); #ifdef CONFIG_DAHDI_PPP if (chan->ppp) { module_printk(KERN_NOTICE, "HUH??? PPP still attached??\n"); } #endif spin_lock_irqsave(&chan_lock, flags); __for_each_channel(_chan_cleanup, (unsigned long)chan); spin_unlock_irqrestore(&chan_lock, flags); chan->channo = -1; } static ssize_t dahdi_chan_read(struct file *file, char __user *usrbuf, size_t count, loff_t *ppos) { struct dahdi_chan *chan = file->private_data; int amnt; int res, rv; int oldbuf,x; unsigned long flags; /* Make sure count never exceeds 65k, and make sure it's unsigned */ count &= 0xffff; if (unlikely(!chan)) { /* We would typically be here because of surprise hardware * removal or driver unbinding while a user space application * has a channel open. Most telephony applications are run at * elevated priorities so this sleep can prevent the high * priority threads from consuming the CPU if they're not * expecting surprise device removal. */ msleep(5); return -ENODEV; } if (unlikely(count < 1)) return -EINVAL; for (;;) { spin_lock_irqsave(&chan->lock, flags); if (chan->eventinidx != chan->eventoutidx) { spin_unlock_irqrestore(&chan->lock, flags); return -ELAST /* - chan->eventbuf[chan->eventoutidx]*/; } res = chan->outreadbuf; if (chan->rxdisable) res = -1; spin_unlock_irqrestore(&chan->lock, flags); if (res >= 0) break; if (file->f_flags & O_NONBLOCK) return -EAGAIN; rv = wait_event_interruptible(chan->waitq, (chan->outreadbuf > -1)); if (rv) return rv; } amnt = count; if (chan->flags & DAHDI_FLAG_LINEAR) { if (amnt > (chan->readn[res] << 1)) amnt = chan->readn[res] << 1; if (amnt) { /* There seems to be a max stack size, so we have to do this in smaller pieces */ short lindata[128]; int left = amnt >> 1; /* amnt is in bytes */ int pos = 0; int pass; while (left) { pass = left; if (pass > 128) pass = 128; for (x = 0; x < pass; x++) lindata[x] = DAHDI_XLAW(chan->readbuf[res][x + pos], chan); if (copy_to_user(usrbuf + (pos << 1), lindata, pass << 1)) return -EFAULT; left -= pass; pos += pass; } } } else { if (amnt > chan->readn[res]) amnt = chan->readn[res]; if (amnt) { if (copy_to_user(usrbuf, chan->readbuf[res], amnt)) return -EFAULT; } } spin_lock_irqsave(&chan->lock, flags); chan->readidx[res] = 0; chan->readn[res] = 0; oldbuf = res; chan->outreadbuf = (res + 1) % chan->numbufs; if (chan->outreadbuf == chan->inreadbuf) { /* Out of stuff */ chan->outreadbuf = -1; if (chan->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) chan->rxdisable = 1; } if (chan->inreadbuf < 0) { /* Notify interrupt handler that we have some space now */ chan->inreadbuf = oldbuf; } spin_unlock_irqrestore(&chan->lock, flags); return amnt; } static int num_filled_bufs(struct dahdi_chan *chan) { int range1, range2; if (chan->inwritebuf < 0) { return chan->numbufs; } if (chan->outwritebuf < 0) { return 0; } if (chan->outwritebuf <= chan->inwritebuf) { return chan->inwritebuf - chan->outwritebuf; } /* This means (in > out) and we have wrap around */ range1 = chan->numbufs - chan->outwritebuf; range2 = chan->inwritebuf; return range1 + range2; } static ssize_t dahdi_chan_write(struct file *file, const char __user *usrbuf, size_t count, loff_t *ppos) { unsigned long flags; struct dahdi_chan *chan = file->private_data; int res, amnt, oldbuf, rv, x; /* Make sure count never exceeds 65k, and make sure it's unsigned */ count &= 0xffff; if (unlikely(!chan)) { /* We would typically be here because of surprise hardware * removal or driver unbinding while a user space application * has a channel open. Most telephony applications are run at * elevated priorities so this sleep can prevent the high * priority threads from consuming the CPU if they're not * expecting surprise device removal. */ msleep(5); return -ENODEV; } if (unlikely(count < 1)) return -EINVAL; for (;;) { spin_lock_irqsave(&chan->lock, flags); if ((chan->curtone || chan->pdialcount) && !is_pseudo_chan(chan)) { chan->curtone = NULL; chan->tonep = 0; chan->dialing = 0; chan->txdialbuf[0] = '\0'; chan->pdialcount = 0; } if (chan->eventinidx != chan->eventoutidx) { spin_unlock_irqrestore(&chan->lock, flags); return -ELAST; } res = chan->inwritebuf; spin_unlock_irqrestore(&chan->lock, flags); if (res >= 0) break; if (file->f_flags & O_NONBLOCK) { #ifdef BUFFER_DEBUG printk("Error: Nonblock\n"); #endif return -EAGAIN; } /* Wait for something to be available */ rv = wait_event_interruptible(chan->waitq, (chan->inwritebuf >= 0)); if (rv) return rv; } amnt = count; if (chan->flags & DAHDI_FLAG_LINEAR) { if (amnt > (chan->blocksize << 1)) amnt = chan->blocksize << 1; } else { if (amnt > chan->blocksize) amnt = chan->blocksize; } #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "dahdi_chan_write(chan: %d, res: %d, outwritebuf: %d amnt: %d\n", chan->channo, res, chan->outwritebuf, amnt); #endif if (amnt) { if (chan->flags & DAHDI_FLAG_LINEAR) { /* There seems to be a max stack size, so we have to do this in smaller pieces */ short lindata[128]; int left = amnt >> 1; /* amnt is in bytes */ int pos = 0; int pass; while (left) { pass = left; if (pass > 128) pass = 128; if (copy_from_user(lindata, usrbuf + (pos << 1), pass << 1)) { return -EFAULT; } left -= pass; for (x = 0; x < pass; x++) chan->writebuf[res][x + pos] = DAHDI_LIN2X(lindata[x], chan); pos += pass; } chan->writen[res] = amnt >> 1; } else { if (copy_from_user(chan->writebuf[res], usrbuf, amnt)) { return -EFAULT; } chan->writen[res] = amnt; } #ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX if ((chan->ec_state) && (ECHO_MODE_ACTIVE == chan->ec_state->status.mode) && (chan->ec_state->ops->echocan_process_tx)) { struct ec_state *const ec_state = chan->ec_state; for (x = 0; x < chan->writen[res]; ++x) { short tx; tx = DAHDI_XLAW(chan->writebuf[res][x], chan); ec_state->ops->echocan_process_tx(ec_state, &tx, 1); chan->writebuf[res][x] = DAHDI_LIN2X((int) tx, chan); } } #endif chan->writeidx[res] = 0; if (chan->flags & DAHDI_FLAG_FCS) calc_fcs(chan, res); oldbuf = res; spin_lock_irqsave(&chan->lock, flags); chan->inwritebuf = (res + 1) % chan->numbufs; if (chan->inwritebuf == chan->outwritebuf) { /* Don't stomp on the transmitter, just wait for them to wake us up */ chan->inwritebuf = -1; /* Make sure the transmitter is transmitting in case of POLICY_WHEN_FULL */ chan->txdisable = 0; } if (chan->outwritebuf < 0) { /* Okay, the interrupt handler has been waiting for us. Give them a buffer */ chan->outwritebuf = oldbuf; } if ((chan->txbufpolicy == DAHDI_POLICY_HALF_FULL) && (chan->txdisable)) { if (num_filled_bufs(chan) >= (chan->numbufs >> 1)) { #ifdef BUFFER_DEBUG printk("Reached buffer fill mark of %d\n", num_filled_bufs(chan)); #endif chan->txdisable = 0; } } #ifdef BUFFER_DEBUG if ((chan->statcount <= 0) || (amnt != 128) || (num_filled_bufs(chan) != chan->lastnumbufs)) { printk("amnt: %d Number of filled buffers: %d\n", amnt, num_filled_bufs(chan)); chan->statcount = 32000; chan->lastnumbufs = num_filled_bufs(chan); } #endif spin_unlock_irqrestore(&chan->lock, flags); if (chan->flags & DAHDI_FLAG_NOSTDTXRX && chan->span->ops->hdlc_hard_xmit) chan->span->ops->hdlc_hard_xmit(chan); } return amnt; } static int dahdi_ctl_open(struct file *file) { /* Nothing to do, really */ return 0; } static int dahdi_chan_open(struct file *file) { /* Nothing to do here for now either */ return 0; } static int dahdi_ctl_release(struct file *file) { /* Nothing to do */ return 0; } static int dahdi_chan_release(struct file *file) { /* Nothing to do for now */ return 0; } static void set_txtone(struct dahdi_chan *ss, int fac, int init_v2, int init_v3) { if (fac == 0) { ss->v2_1 = 0; ss->v3_1 = 0; return; } ss->txtone = fac; ss->v1_1 = 0; ss->v2_1 = init_v2; ss->v3_1 = init_v3; return; } static void dahdi_rbs_sethook(struct dahdi_chan *chan, int txsig, int txstate, int timeout) { static const struct { unsigned int sig_type; /* Index is dahdi_txsig enum */ unsigned int bits[DAHDI_TXSIG_TOTAL]; } outs[NUM_SIGS] = { { /* * We set the idle case of the DAHDI_SIG_NONE to this pattern to make idle E1 CAS * channels happy. Should not matter with T1, since on an un-configured channel, * who cares what the sig bits are as long as they are stable */ .sig_type = DAHDI_SIG_NONE, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_ACD, }, { .sig_type = DAHDI_SIG_EM, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, }, { .sig_type = DAHDI_SIG_FXSLS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, }, { .sig_type = DAHDI_SIG_FXSGS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, #ifndef CONFIG_CAC_GROUNDSTART .bits[DAHDI_TXSIG_START] = DAHDI_BITS_AC, #endif }, { .sig_type = DAHDI_SIG_FXSKS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, }, { .sig_type = DAHDI_SIG_FXOLS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, }, { .sig_type = DAHDI_SIG_FXOGS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, }, { .sig_type = DAHDI_SIG_FXOKS, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, .bits[DAHDI_TXSIG_KEWL] = DAHDI_BITS_ABCD, }, { .sig_type = DAHDI_SIG_SF, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BCD, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, .bits[DAHDI_TXSIG_KEWL] = DAHDI_BITS_BCD, }, { .sig_type = DAHDI_SIG_EM_E1, .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_DBIT, .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABD, .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABD, .bits[DAHDI_TXSIG_KEWL] = DAHDI_DBIT, } }; int x; /* if no span, return doing nothing */ if (!chan->span) return; if (!(chan->span->flags & DAHDI_FLAG_RBS)) { module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name); return; } if ((txsig > 3) || (txsig < 0)) { module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state %d (> 3) on channel %s\n", txsig, chan->name); return; } if (!chan->span->ops->rbsbits && !chan->span->ops->hooksig) { module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state %d on channel %s while span %s lacks rbsbits or hooksig function\n", txsig, chan->name, chan->span->name); return; } /* Don't do anything for RBS */ if (chan->sig == DAHDI_SIG_DACS_RBS) return; chan->txstate = txstate; /* if tone signalling */ if (chan->sig == DAHDI_SIG_SF) { chan->txhooksig = txsig; if (chan->txtone) { /* if set to make tone for tx */ if ((txsig && !(chan->toneflags & DAHDI_REVERSE_TXTONE)) || ((!txsig) && (chan->toneflags & DAHDI_REVERSE_TXTONE))) { set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3); } else { set_txtone(chan,0,0,0); } } chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ return; } if (chan->span->ops->hooksig) { if (chan->txhooksig != txsig) { chan->txhooksig = txsig; chan->span->ops->hooksig(chan, txsig); } chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ return; } else { for (x = 0; x < NUM_SIGS; x++) { if (outs[x].sig_type == chan->sig) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Setting bits to %d for channel %s state %d in %d signalling\n", outs[x].bits[txsig], chan->name, txsig, chan->sig); #endif chan->txhooksig = txsig; chan->txsig = outs[x].bits[txsig]; chan->span->ops->rbsbits(chan, chan->txsig); chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ return; } } } module_printk(KERN_NOTICE, "dahdi_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name); } static int dahdi_cas_setbits(struct dahdi_chan *chan, int bits) { /* if no span, return as error */ if (!chan->span) return -1; if (chan->span->ops->rbsbits) { chan->txsig = bits; chan->span->ops->rbsbits(chan, bits); } else { module_printk(KERN_NOTICE, "Huh? CAS setbits, but no RBS bits function\n"); } return 0; } static int dahdi_hangup(struct dahdi_chan *chan) { int x, res = 0; /* Can't hangup pseudo channels */ if (!chan->span) return 0; /* Can't hang up a clear channel */ if (chan->flags & (DAHDI_FLAG_CLEAR | DAHDI_FLAG_NOSTDTXRX)) return -EINVAL; chan->kewlonhook = 0; if ((chan->sig == DAHDI_SIG_FXSLS) || (chan->sig == DAHDI_SIG_FXSKS) || (chan->sig == DAHDI_SIG_FXSGS)) { chan->ringdebtimer = RING_DEBOUNCE_TIME; } if (chan->span->flags & DAHDI_FLAG_RBS) { if (chan->sig == DAHDI_SIG_CAS) { dahdi_cas_setbits(chan, chan->idlebits); } else if ((chan->sig == DAHDI_SIG_FXOKS) && (chan->txstate != DAHDI_TXSTATE_ONHOOK) /* if other party is already on-hook we shouldn't do any battery drop */ && !((chan->rxhooksig == DAHDI_RXSIG_ONHOOK) && (chan->itimer <= 0))) { /* Do RBS signalling on the channel's behalf */ dahdi_rbs_sethook(chan, DAHDI_TXSIG_KEWL, DAHDI_TXSTATE_KEWL, DAHDI_KEWLTIME); } else dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); } else { /* Let the driver hang up the line if it wants to */ if (chan->span->ops->sethook) { if (chan->txhooksig != DAHDI_ONHOOK) { chan->txhooksig = DAHDI_ONHOOK; res = chan->span->ops->sethook(chan, DAHDI_ONHOOK); } else res = 0; } } /* if not registered yet, just return here */ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) return res; /* Mark all buffers as empty */ for (x = 0; x < chan->numbufs; x++) { chan->writen[x] = chan->writeidx[x]= chan->readn[x]= chan->readidx[x] = 0; } if (chan->readbuf[0]) { chan->inreadbuf = 0; chan->inwritebuf = 0; } else { chan->inreadbuf = -1; chan->inwritebuf = -1; } chan->outreadbuf = -1; chan->outwritebuf = -1; chan->dialing = 0; chan->afterdialingtimer = 0; chan->curtone = NULL; chan->pdialcount = 0; chan->cadencepos = 0; chan->txdialbuf[0] = 0; return res; } static int initialize_channel(struct dahdi_chan *chan) { int res; unsigned long flags; const void *rxgain = NULL; struct dahdi_echocan_state *ec_state; const struct dahdi_echocan_factory *ec_current; if ((res = dahdi_reallocbufs(chan, DAHDI_DEFAULT_BLOCKSIZE, DAHDI_DEFAULT_NUM_BUFS))) return res; spin_lock_irqsave(&chan->lock, flags); chan->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; chan->txbufpolicy = DAHDI_POLICY_IMMEDIATE; ec_state = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; chan->txdisable = 0; chan->rxdisable = 0; chan->digitmode = DIGIT_MODE_DTMF; chan->dialing = 0; chan->afterdialingtimer = 0; chan->cadencepos = 0; chan->firstcadencepos = 0; /* By default loop back to first cadence position */ /* HDLC & FCS stuff */ fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); chan->infcs = PPP_INITFCS; /* Timings for RBS */ chan->prewinktime = DAHDI_DEFAULT_PREWINKTIME; chan->preflashtime = DAHDI_DEFAULT_PREFLASHTIME; chan->winktime = DAHDI_DEFAULT_WINKTIME; chan->flashtime = DAHDI_DEFAULT_FLASHTIME; if (chan->sig & __DAHDI_SIG_FXO) chan->starttime = DAHDI_DEFAULT_RINGTIME; else chan->starttime = DAHDI_DEFAULT_STARTTIME; chan->rxwinktime = DAHDI_DEFAULT_RXWINKTIME; chan->rxflashtime = DAHDI_DEFAULT_RXFLASHTIME; chan->debouncetime = DAHDI_DEFAULT_DEBOUNCETIME; chan->pulsemaketime = DAHDI_DEFAULT_PULSEMAKETIME; chan->pulsebreaktime = DAHDI_DEFAULT_PULSEBREAKTIME; chan->pulseaftertime = DAHDI_DEFAULT_PULSEAFTERTIME; /* Initialize RBS timers */ chan->itimerset = chan->itimer = chan->otimer = 0; chan->ringdebtimer = 0; /* Reset conferences */ reset_conf(chan); chan->dacs_chan = NULL; /* I/O Mask, etc */ chan->iomask = 0; /* release conference resource if any */ if (chan->confna) dahdi_check_conf(chan->confna); if ((chan->sig & __DAHDI_SIG_DACS) != __DAHDI_SIG_DACS) { chan->confna = 0; chan->confmode = 0; chan->conf_chan = NULL; dahdi_disable_dacs(chan); } chan->_confn = 0; memset(chan->conflast, 0, sizeof(chan->conflast)); memset(chan->conflast1, 0, sizeof(chan->conflast1)); memset(chan->conflast2, 0, sizeof(chan->conflast2)); chan->confmute = 0; chan->gotgs = 0; chan->curtone = NULL; chan->tonep = 0; chan->pdialcount = 0; if (is_gain_allocated(chan)) rxgain = chan->rxgain; chan->rxgain = defgain; chan->txgain = defgain; chan->eventinidx = chan->eventoutidx = 0; dahdi_set_law(chan, DAHDI_LAW_DEFAULT); dahdi_hangup(chan); /* Make sure that the audio flag is cleared on a clear channel */ if ((chan->sig & DAHDI_SIG_CLEAR) || (chan->sig & DAHDI_SIG_HARDHDLC)) chan->flags &= ~DAHDI_FLAG_AUDIO; if ((chan->sig == DAHDI_SIG_CLEAR) || (chan->sig == DAHDI_SIG_HARDHDLC)) chan->flags &= ~(DAHDI_FLAG_PPP | DAHDI_FLAG_FCS | DAHDI_FLAG_HDLC); chan->flags &= ~DAHDI_FLAG_LINEAR; if (chan->curzone) { /* Take cadence from tone zone */ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence)); } else { /* Do a default */ memset(chan->ringcadence, 0, sizeof(chan->ringcadence)); chan->ringcadence[0] = chan->starttime; chan->ringcadence[1] = DAHDI_RINGOFFTIME; } if (ec_state) { ec_state->ops->echocan_free(chan, ec_state); release_echocan(ec_current); } spin_unlock_irqrestore(&chan->lock, flags); set_tone_zone(chan, DEFAULT_TONE_ZONE); if (rxgain) kfree(rxgain); return 0; } static int dahdi_timing_open(struct file *file) { struct dahdi_timer *t; unsigned long flags; if (!(t = kzalloc(sizeof(*t), GFP_KERNEL))) return -ENOMEM; init_waitqueue_head(&t->sel); INIT_LIST_HEAD(&t->list); file->private_data = t; spin_lock_irqsave(&dahdi_timer_lock, flags); list_add(&t->list, &dahdi_timers); spin_unlock_irqrestore(&dahdi_timer_lock, flags); return 0; } static int dahdi_timer_release(struct file *file) { struct dahdi_timer *t, *cur, *next; unsigned long flags; if (!(t = file->private_data)) return 0; spin_lock_irqsave(&dahdi_timer_lock, flags); list_for_each_entry_safe(cur, next, &dahdi_timers, list) { if (t == cur) { list_del(&cur->list); break; } } spin_unlock_irqrestore(&dahdi_timer_lock, flags); if (!cur) { module_printk(KERN_NOTICE, "Timer: Not on list??\n"); return 0; } kfree(cur); return 0; } static const struct file_operations dahdi_chan_fops; static int dahdi_specchan_open(struct file *file) { int res = 0; struct dahdi_chan *const chan = chan_from_file(file); if (chan && chan->sig) { /* Make sure we're not already open, a net device, or a slave device */ if (dahdi_have_netdev(chan)) res = -EBUSY; else if (chan->master != chan) res = -EBUSY; else if ((chan->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) res = -EBUSY; else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) { unsigned long flags; res = initialize_channel(chan); if (res) { /* Reallocbufs must have failed */ clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); return res; } spin_lock_irqsave(&chan->lock, flags); if (is_pseudo_chan(chan)) chan->flags |= DAHDI_FLAG_AUDIO; if (chan->span) { const struct dahdi_span_ops *const ops = chan->span->ops; if (!try_module_get(ops->owner)) { res = -ENXIO; } else if (ops->open) { res = ops->open(chan); if (res) module_put(ops->owner); } } if (!res) { chan->file = file; file->private_data = chan; /* Since we know we're a channel now, we can * update the f_op pointer and bypass a few of * the checks on the minor number. */ file->f_op = &dahdi_chan_fops; spin_unlock_irqrestore(&chan->lock, flags); } else { spin_unlock_irqrestore(&chan->lock, flags); close_channel(chan); clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); } } else { res = -EBUSY; } } else res = -ENXIO; return res; } static int dahdi_specchan_release(struct file *file) { int res=0; unsigned long flags; struct dahdi_chan *chan = chan_from_file(file); if (chan) { /* Chan lock protects contents against potentially non atomic accesses. * So if the pointer setting is not atomic, we should protect */ #ifdef CONFIG_DAHDI_MIRROR if (chan->srcmirror) { struct dahdi_chan *const srcmirror = chan->srcmirror; spin_lock_irqsave(&srcmirror->lock, flags); if (chan == srcmirror->txmirror) { module_printk(KERN_INFO, "Chan %d tx mirror " \ "to %d stopped\n", srcmirror->txmirror->channo, srcmirror->channo); srcmirror->txmirror = NULL; } if (chan == srcmirror->rxmirror) { module_printk(KERN_INFO, "Chan %d rx mirror " \ "to %d stopped\n", srcmirror->rxmirror->channo, srcmirror->channo); chan->srcmirror->rxmirror = NULL; } spin_unlock_irqrestore(&chan->srcmirror->lock, flags); } #endif /* CONFIG_DAHDI_MIRROR */ spin_lock_irqsave(&chan->lock, flags); chan->file = NULL; file->private_data = NULL; #ifdef CONFIG_DAHDI_MIRROR chan->srcmirror = NULL; #endif /* CONFIG_DAHDI_MIRROR */ spin_unlock_irqrestore(&chan->lock, flags); close_channel(chan); clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); if (chan->span) { struct module *owner = chan->span->ops->owner; if (chan->span->ops->close) res = chan->span->ops->close(chan); module_put(owner); } } else res = -ENXIO; return res; } static int can_open_timer(void) { #ifdef CONFIG_DAHDI_CORE_TIMER return 1; #else return (list_empty(&span_list)) ? 0 : 1; #endif } static unsigned int max_pseudo_channels = 512; static unsigned int num_pseudo_channels; static struct dahdi_chan *dahdi_alloc_pseudo(struct file *file) { struct pseudo_chan *pseudo; unsigned long flags; unsigned int channo; struct pseudo_chan *p; struct list_head *pos = &pseudo_chans; /* Don't allow /dev/dahdi/pseudo to open if there is not a timing * source. */ if (!can_open_timer()) return NULL; if (unlikely(num_pseudo_channels >= max_pseudo_channels)) return NULL; pseudo = kzalloc(sizeof(*pseudo), GFP_KERNEL); if (NULL == pseudo) return NULL; pseudo->chan.sig = DAHDI_SIG_CLEAR; pseudo->chan.sigcap = DAHDI_SIG_CLEAR; pseudo->chan.flags = DAHDI_FLAG_AUDIO; pseudo->chan.span = NULL; /* No span == psuedo channel */ mutex_lock(®istration_mutex); channo = FIRST_PSEUDO_CHANNEL; list_for_each_entry(p, &pseudo_chans, node) { if (channo != p->chan.channo) break; pos = &p->node; ++channo; } pseudo->chan.channo = channo; pseudo->chan.chanpos = channo - FIRST_PSEUDO_CHANNEL + 1; dahdi_chan_reg(&pseudo->chan); snprintf(pseudo->chan.name, sizeof(pseudo->chan.name)-1, "Pseudo/%d", pseudo->chan.chanpos); file->private_data = &pseudo->chan; /* Once we place the pseudo chan on the list...it's registered and * live. */ spin_lock_irqsave(&chan_lock, flags); ++num_pseudo_channels; list_add(&pseudo->node, pos); spin_unlock_irqrestore(&chan_lock, flags); mutex_unlock(®istration_mutex); return &pseudo->chan; } static void dahdi_free_pseudo(struct dahdi_chan *chan) { struct pseudo_chan *pseudo; unsigned long flags; if (!chan) return; mutex_lock(®istration_mutex); pseudo = chan_to_pseudo(chan); spin_lock_irqsave(&chan_lock, flags); list_del(&pseudo->node); --num_pseudo_channels; spin_unlock_irqrestore(&chan_lock, flags); dahdi_chan_unreg(chan); mutex_unlock(®istration_mutex); kfree(pseudo); } static int dahdi_open(struct inode *inode, struct file *file) { int unit = UNIT(file); struct dahdi_chan *chan; /* Minor 0: Special "control" descriptor */ if (unit == DAHDI_CTL) return dahdi_ctl_open(file); if (unit == DAHDI_TRANSCODE) { if (!dahdi_transcode_fops) { if (request_module("dahdi_transcode")) { return -ENXIO; } } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) __MOD_INC_USE_COUNT (dahdi_transcode_fops->owner); #else if (!try_module_get(dahdi_transcode_fops->owner)) { return -ENXIO; } #endif if (dahdi_transcode_fops && dahdi_transcode_fops->open) { return dahdi_transcode_fops->open(inode, file); } else { /* dahdi_transcode module should have exported a * file_operations table. */ WARN_ON(1); } return -ENXIO; } if (unit == DAHDI_TIMER) { if (can_open_timer()) { return dahdi_timing_open(file); } else { return -ENXIO; } } if (unit == DAHDI_CHANNEL) return dahdi_chan_open(file); if (unit == DAHDI_PSEUDO) { chan = dahdi_alloc_pseudo(file); if (unlikely(!chan)) return -ENOMEM; return dahdi_specchan_open(file); } return dahdi_specchan_open(file); } /** * dahdi_ioctl_defaultzone() - Set defzone to the default. * @defzone: The number of the default zone. * * The default zone is the zone that will be used if the channels request the * default zone in dahdi_ioctl_chanconfig. The first entry on the tone_zones * list is the default zone. This function searches the list for the zone, * and if found, moves it to the head of the list. */ static int dahdi_ioctl_defaultzone(unsigned long data) { int defzone; struct dahdi_zone *cur; struct dahdi_zone *dz = NULL; if (get_user(defzone, (int __user *)data)) return -EFAULT; spin_lock(&zone_lock); list_for_each_entry(cur, &tone_zones, node) { if (cur->num != defzone) continue; dz = cur; break; } if (dz) list_move(&dz->node, &tone_zones); spin_unlock(&zone_lock); return (dz) ? 0 : -EINVAL; } /* No bigger than 32k for everything per tone zone */ #define MAX_SIZE 32768 /* No more than 128 subtones */ #define MAX_TONES 128 /* The tones to be loaded can (will) be a mix of regular tones, DTMF tones and MF tones. We need to load DTMF and MF tones a bit differently than regular tones because their storage format is much simpler (an array structure field of the zone structure, rather an array of pointers). */ static int dahdi_ioctl_loadzone(unsigned long data) { struct load_zone_workarea { struct dahdi_tone *samples[MAX_TONES]; short next[MAX_TONES]; struct dahdi_tone_def_header th; struct dahdi_tone_def td; } *work; size_t space; size_t size; int res; int x; void *ptr; struct dahdi_zone *z = NULL; struct dahdi_tone *t = NULL; void __user * user_data = (void __user *)data; const unsigned char MAX_ZONE = -1; work = kzalloc(sizeof(*work), GFP_KERNEL); if (!work) return -ENOMEM; if (copy_from_user(&work->th, user_data, sizeof(work->th))) { res = -EFAULT; goto error_exit; } if ((work->th.zone < 0) || (work->th.zone > MAX_ZONE)) { res = -EINVAL; goto error_exit; } user_data += sizeof(work->th); if ((work->th.count < 0) || (work->th.count > MAX_TONES)) { module_printk(KERN_NOTICE, "Too many tones included\n"); res = -EINVAL; goto error_exit; } space = size = sizeof(*z) + work->th.count * sizeof(*t); if (size > MAX_SIZE) { res = -E2BIG; goto error_exit; } z = ptr = kzalloc(size, GFP_KERNEL); if (!z) { res = -ENOMEM; goto error_exit; } ptr = (char *) ptr + sizeof(*z); space -= sizeof(*z); z->name = kasprintf(GFP_KERNEL, work->th.name); if (!z->name) { res = -ENOMEM; goto error_exit; } for (x = 0; x < DAHDI_MAX_CADENCE; x++) z->ringcadence[x] = work->th.ringcadence[x]; mutex_lock(&global_dialparamslock); for (x = 0; x < work->th.count; x++) { enum { REGULAR_TONE, DTMF_TONE, MFR1_TONE, MFR2_FWD_TONE, MFR2_REV_TONE, } tone_type; if (space < sizeof(*t)) { module_printk(KERN_NOTICE, "Insufficient tone zone space\n"); res = -EINVAL; goto unlock_error_exit; } res = copy_from_user(&work->td, user_data, sizeof(work->td)); if (res) { res = -EFAULT; goto unlock_error_exit; } user_data += sizeof(work->td); if ((work->td.tone >= 0) && (work->td.tone < DAHDI_TONE_MAX)) { tone_type = REGULAR_TONE; t = work->samples[x] = ptr; space -= sizeof(*t); ptr = (char *) ptr + sizeof(*t); /* Remember which sample is work->next */ work->next[x] = work->td.next; /* Make sure the "next" one is sane */ if ((work->next[x] >= work->th.count) || (work->next[x] < 0)) { module_printk(KERN_NOTICE, "Invalid 'next' pointer: %d\n", work->next[x]); res = -EINVAL; goto unlock_error_exit; } } else if ((work->td.tone >= DAHDI_TONE_DTMF_BASE) && (work->td.tone <= DAHDI_TONE_DTMF_MAX)) { tone_type = DTMF_TONE; work->td.tone -= DAHDI_TONE_DTMF_BASE; t = &z->dtmf[work->td.tone]; } else if ((work->td.tone >= DAHDI_TONE_MFR1_BASE) && (work->td.tone <= DAHDI_TONE_MFR1_MAX)) { tone_type = MFR1_TONE; work->td.tone -= DAHDI_TONE_MFR1_BASE; t = &z->mfr1[work->td.tone]; } else if ((work->td.tone >= DAHDI_TONE_MFR2_FWD_BASE) && (work->td.tone <= DAHDI_TONE_MFR2_FWD_MAX)) { tone_type = MFR2_FWD_TONE; work->td.tone -= DAHDI_TONE_MFR2_FWD_BASE; t = &z->mfr2_fwd[work->td.tone]; } else if ((work->td.tone >= DAHDI_TONE_MFR2_REV_BASE) && (work->td.tone <= DAHDI_TONE_MFR2_REV_MAX)) { tone_type = MFR2_REV_TONE; work->td.tone -= DAHDI_TONE_MFR2_REV_BASE; t = &z->mfr2_rev[work->td.tone]; } else { module_printk(KERN_NOTICE, "Invalid tone (%d) defined\n", work->td.tone); res = -EINVAL; goto unlock_error_exit; } t->fac1 = work->td.fac1; t->init_v2_1 = work->td.init_v2_1; t->init_v3_1 = work->td.init_v3_1; t->fac2 = work->td.fac2; t->init_v2_2 = work->td.init_v2_2; t->init_v3_2 = work->td.init_v3_2; t->modulate = work->td.modulate; switch (tone_type) { case REGULAR_TONE: t->tonesamples = work->td.samples; if (!z->tones[work->td.tone]) z->tones[work->td.tone] = t; break; case DTMF_TONE: t->tonesamples = global_dialparams.dtmf_tonelen; t->next = &dtmf_silence; z->dtmf_continuous[work->td.tone] = *t; z->dtmf_continuous[work->td.tone].next = &z->dtmf_continuous[work->td.tone]; break; case MFR1_TONE: switch (work->td.tone + DAHDI_TONE_MFR1_BASE) { case DAHDI_TONE_MFR1_KP: case DAHDI_TONE_MFR1_ST: case DAHDI_TONE_MFR1_STP: case DAHDI_TONE_MFR1_ST2P: case DAHDI_TONE_MFR1_ST3P: /* signaling control tones are always 100ms */ t->tonesamples = 100 * DAHDI_CHUNKSIZE; break; default: t->tonesamples = global_dialparams.mfv1_tonelen; break; } t->next = &mfr1_silence; break; case MFR2_FWD_TONE: t->tonesamples = global_dialparams.mfr2_tonelen; t->next = &dtmf_silence; z->mfr2_fwd_continuous[work->td.tone] = *t; z->mfr2_fwd_continuous[work->td.tone].next = &z->mfr2_fwd_continuous[work->td.tone]; break; case MFR2_REV_TONE: t->tonesamples = global_dialparams.mfr2_tonelen; t->next = &dtmf_silence; z->mfr2_rev_continuous[work->td.tone] = *t; z->mfr2_rev_continuous[work->td.tone].next = &z->mfr2_rev_continuous[work->td.tone]; break; } } mutex_unlock(&global_dialparamslock); for (x = 0; x < work->th.count; x++) { if (work->samples[x]) work->samples[x]->next = work->samples[work->next[x]]; } z->num = work->th.zone; /* After we call dahdi_register_tone_zone, the only safe way to free * the zone is with a tone_zone_put call. */ res = dahdi_register_tone_zone(z); if (res) tone_zone_put(z); kfree(work); return res; unlock_error_exit: mutex_unlock(&global_dialparamslock); error_exit: if (z) kfree(z->name); kfree(z); kfree(work); return res; } void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt) { ts->v1_1 = 0; ts->v2_1 = zt->init_v2_1; ts->v3_1 = zt->init_v3_1; ts->v1_2 = 0; ts->v2_2 = zt->init_v2_2; ts->v3_2 = zt->init_v3_2; ts->modulate = zt->modulate; } struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode) { unsigned int tone_index; if (!chan->curzone) { static int __warnonce = 1; if (__warnonce) { __warnonce = 0; /* The tonezones are loaded by dahdi_cfg based on /etc/dahdi/system.conf. */ module_printk(KERN_WARNING, "Cannot get dtmf tone until tone zone is loaded.\n"); } return NULL; } switch (digitmode) { case DIGIT_MODE_PULSE: /* We should only get here with a pulse digit if we need * to "dial" 'W' (wait 0.5 second) */ if (digit == 'W') return &tone_pause; return NULL; case DIGIT_MODE_DTMF: switch (digit) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tone_index = DAHDI_TONE_DTMF_0 + (digit - '0'); break; case '*': tone_index = DAHDI_TONE_DTMF_s; break; case '#': tone_index = DAHDI_TONE_DTMF_p; break; case 'A': case 'B': case 'C': case 'D': tone_index = DAHDI_TONE_DTMF_A + (digit - 'A'); break; case 'W': return &tone_pause; default: return NULL; } return &chan->curzone->dtmf[tone_index - DAHDI_TONE_DTMF_BASE]; case DIGIT_MODE_MFR1: switch (digit) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tone_index = DAHDI_TONE_MFR1_0 + (digit - '0'); break; case '*': tone_index = DAHDI_TONE_MFR1_KP; break; case '#': tone_index = DAHDI_TONE_MFR1_ST; break; case 'A': tone_index = DAHDI_TONE_MFR1_STP; break; case 'B': tone_index = DAHDI_TONE_MFR1_ST2P; break; case 'C': tone_index = DAHDI_TONE_MFR1_ST3P; break; case 'W': return &tone_pause; default: return NULL; } return &chan->curzone->mfr1[tone_index - DAHDI_TONE_MFR1_BASE]; case DIGIT_MODE_MFR2_FWD: switch (digit) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tone_index = DAHDI_TONE_MFR2_FWD_1 + (digit - '1'); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': tone_index = DAHDI_TONE_MFR2_FWD_10 + (digit - 'A'); break; case 'W': return &tone_pause; default: return NULL; } return &chan->curzone->mfr2_fwd[tone_index - DAHDI_TONE_MFR2_FWD_BASE]; case DIGIT_MODE_MFR2_REV: switch (digit) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': tone_index = DAHDI_TONE_MFR2_REV_1 + (digit - '1'); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': tone_index = DAHDI_TONE_MFR2_REV_10 + (digit - 'A'); break; case 'W': return &tone_pause; default: return NULL; } return &chan->curzone->mfr2_rev[tone_index - DAHDI_TONE_MFR2_REV_BASE]; default: return NULL; } } static void __do_dtmf(struct dahdi_chan *chan) { char c; /* Called with chan->lock held */ while ((c = chan->txdialbuf[0])) { memmove(chan->txdialbuf, chan->txdialbuf + 1, sizeof(chan->txdialbuf) - 1); switch (c) { case 'T': chan->digitmode = DIGIT_MODE_DTMF; chan->tonep = 0; break; case 'M': chan->digitmode = DIGIT_MODE_MFR1; chan->tonep = 0; break; case 'O': chan->digitmode = DIGIT_MODE_MFR2_FWD; chan->tonep = 0; break; case 'R': chan->digitmode = DIGIT_MODE_MFR2_REV; chan->tonep = 0; break; case 'P': chan->digitmode = DIGIT_MODE_PULSE; chan->tonep = 0; break; default: if ((c != 'W') && (chan->digitmode == DIGIT_MODE_PULSE)) { if ((c >= '0') && (c <= '9') && (chan->txhooksig == DAHDI_TXSIG_OFFHOOK)) { chan->pdialcount = (c == '0') ? 10 : c - '0'; dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_PULSEBREAK, chan->pulsebreaktime); return; } } else { chan->curtone = dahdi_mf_tone(chan, c, chan->digitmode); chan->tonep = 0; if (chan->curtone) { dahdi_init_tone_state(&chan->ts, chan->curtone); return; } } } } /* Notify userspace process if there is nothing left */ chan->dialing = 0; __qevent(chan, DAHDI_EVENT_DIALCOMPLETE); } static int dahdi_release(struct inode *inode, struct file *file) { int unit = UNIT(file); int res; struct dahdi_chan *chan; if (unit == DAHDI_CTL) return dahdi_ctl_release(file); if (unit == DAHDI_TIMER) { return dahdi_timer_release(file); } if (unit == DAHDI_TRANSCODE) { /* We should not be here because the dahdi_transcode.ko module * should have updated the file_operations for this file * handle when the file was opened. */ WARN_ON(1); return -EFAULT; } if (unit == DAHDI_CHANNEL) { chan = file->private_data; if (!chan) return dahdi_chan_release(file); else return dahdi_specchan_release(file); } if (unit == DAHDI_PSEUDO) { chan = file->private_data; if (chan) { res = dahdi_specchan_release(file); dahdi_free_pseudo(chan); } else { module_printk(KERN_NOTICE, "Pseudo release and no private data??\n"); res = 0; } return res; } return dahdi_specchan_release(file); } /** * dahdi_alarm_channel() - notify userspace channel is (not) in alarm * @chan: the DAHDI channel * @alarms: alarm bits set * * Notify userspace about a change in alarm status of this channel. * * Note that channel drivers should only use this function directly if * they have a single port per channel. Whole-span alarms should be sent * using dahdi_alarm_notify() . * * Does nothing if alarms on the channel have not changed. If they have, * triggers sending either DAHDI_EVENT_NOALARM (if they were cleared) or * DAHDI_EVENT_ALARM (otherwise). * * Currently it is only used by drivers of FXO ports to notify (with a * red alarm) they have no battery current. */ void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms) { unsigned long flags; spin_lock_irqsave(&chan->lock, flags); if (chan->chan_alarms != alarms) { chan->chan_alarms = alarms; dahdi_qevent_nolock(chan, alarms ? DAHDI_EVENT_ALARM : DAHDI_EVENT_NOALARM); } spin_unlock_irqrestore(&chan->lock, flags); } static inline bool is_analog_span(const struct dahdi_span *s) { return (s->linecompat == 0); } static void __dahdi_find_master_span(void) { struct dahdi_span *s; unsigned long flags; struct dahdi_span *old_master; spin_lock_irqsave(&chan_lock, flags); old_master = master; list_for_each_entry(s, &span_list, node) { if (s->alarms) continue; if (!is_analog_span(s) && !test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags)) continue; if (!can_provide_timing(s)) continue; if (master == s) continue; master = s; break; } spin_unlock_irqrestore(&chan_lock, flags); if ((debug & DEBUG_MAIN) && (old_master != master)) module_printk(KERN_NOTICE, "Master changed to %s\n", s->name); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void _dahdi_find_master_span(void *work) { __dahdi_find_master_span(); } static DECLARE_WORK(find_master_work, _dahdi_find_master_span, NULL); #else static void _dahdi_find_master_span(struct work_struct *work) { __dahdi_find_master_span(); } static DECLARE_WORK(find_master_work, _dahdi_find_master_span); #endif static void dahdi_find_master_span(void) { schedule_work(&find_master_work); } void dahdi_alarm_notify(struct dahdi_span *span) { int x; span->alarms &= ~DAHDI_ALARM_LOOPBACK; /* Determine maint status */ if (span->maintstat || span->mainttimer) span->alarms |= DAHDI_ALARM_LOOPBACK; /* DON'T CHANGE THIS AGAIN. THIS WAS DONE FOR A REASON. The expression (a != b) does *NOT* do the same thing as ((!a) != (!b)) */ /* if change in general state */ if ((!span->alarms) != (!span->lastalarms)) { span->lastalarms = span->alarms; for (x = 0; x < span->channels; x++) dahdi_alarm_channel(span->chans[x], span->alarms); /* If we're going into or out of alarm we should try to find a * new master that may be a better fit. */ dahdi_find_master_span(); /* Report more detailed alarms */ if (debug & DEBUG_MAIN) { if (span->alarms & DAHDI_ALARM_LOS) { module_printk(KERN_NOTICE, "Span %d: Loss of signal\n", span->spanno); } if (span->alarms & DAHDI_ALARM_LFA) { module_printk(KERN_NOTICE, "Span %d: Loss of Frame Alignment\n", span->spanno); } if (span->alarms & DAHDI_ALARM_LMFA) { module_printk(KERN_NOTICE, "Span %d: Loss of Multi-Frame "\ "Alignment\n", span->spanno); } } } } static int dahdi_timer_ioctl(struct file *file, unsigned int cmd, unsigned long data, struct dahdi_timer *timer) { int j; unsigned long flags; switch(cmd) { case DAHDI_TIMERCONFIG: get_user(j, (int __user *)data); if (j < 0) j = 0; spin_lock_irqsave(&dahdi_timer_lock, flags); timer->ms = timer->pos = j; spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; case DAHDI_TIMERACK: get_user(j, (int __user *)data); spin_lock_irqsave(&dahdi_timer_lock, flags); if ((j < 1) || (j > timer->tripped)) j = timer->tripped; timer->tripped -= j; spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; case DAHDI_GETEVENT: /* Get event on queue */ j = DAHDI_EVENT_NONE; spin_lock_irqsave(&dahdi_timer_lock, flags); /* set up for no event */ if (timer->tripped) j = DAHDI_EVENT_TIMER_EXPIRED; if (timer->ping) j = DAHDI_EVENT_TIMER_PING; spin_unlock_irqrestore(&dahdi_timer_lock, flags); put_user(j, (int __user *)data); break; case DAHDI_TIMERPING: spin_lock_irqsave(&dahdi_timer_lock, flags); timer->ping = 1; wake_up_interruptible(&timer->sel); spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; case DAHDI_TIMERPONG: spin_lock_irqsave(&dahdi_timer_lock, flags); timer->ping = 0; spin_unlock_irqrestore(&dahdi_timer_lock, flags); break; default: return -ENOTTY; } return 0; } static int dahdi_ioctl_getgains(struct file *file, unsigned long data) { int res = 0; struct dahdi_gains *gain; int j; void __user * const user_data = (void __user *)data; struct dahdi_chan *chan; gain = kzalloc(sizeof(*gain), GFP_KERNEL); if (!gain) return -ENOMEM; if (copy_from_user(gain, user_data, sizeof(*gain))) { res = -EFAULT; goto cleanup; } chan = (!gain->chan) ? chan_from_file(file) : chan_from_num(gain->chan); if (!chan) { res = -EINVAL; goto cleanup; } if (!(chan->flags & DAHDI_FLAG_AUDIO)) { res = -EINVAL; goto cleanup; } gain->chan = chan->channo; for (j = 0; j < 256; ++j) { gain->txgain[j] = chan->txgain[j]; gain->rxgain[j] = chan->rxgain[j]; } if (copy_to_user(user_data, gain, sizeof(*gain))) { res = -EFAULT; goto cleanup; } cleanup: kfree(gain); return res; } static int dahdi_ioctl_setgains(struct file *file, unsigned long data) { int res = 0; struct dahdi_gains *gain; unsigned char *txgain, *rxgain; int j; unsigned long flags; const int GAIN_TABLE_SIZE = sizeof(defgain); void __user * const user_data = (void __user *)data; struct dahdi_chan *chan; gain = kzalloc(sizeof(*gain), GFP_KERNEL); if (!gain) return -ENOMEM; if (copy_from_user(gain, user_data, sizeof(*gain))) { res = -EFAULT; goto cleanup; } chan = (!gain->chan) ? chan_from_file(file) : chan_from_num(gain->chan); if (!chan) { res = -EINVAL; goto cleanup; } if (!(chan->flags & DAHDI_FLAG_AUDIO)) { res = -EINVAL; goto cleanup; } rxgain = kzalloc(GAIN_TABLE_SIZE*2, GFP_KERNEL); if (!rxgain) { res = -ENOMEM; goto cleanup; } gain->chan = chan->channo; txgain = rxgain + GAIN_TABLE_SIZE; for (j = 0; j < GAIN_TABLE_SIZE; ++j) { rxgain[j] = gain->rxgain[j]; txgain[j] = gain->txgain[j]; } if (!memcmp(rxgain, defgain, GAIN_TABLE_SIZE) && !memcmp(txgain, defgain, GAIN_TABLE_SIZE)) { kfree(rxgain); spin_lock_irqsave(&chan->lock, flags); if (is_gain_allocated(chan)) kfree(chan->rxgain); chan->rxgain = defgain; chan->txgain = defgain; spin_unlock_irqrestore(&chan->lock, flags); } else { /* This is a custom gain setting */ spin_lock_irqsave(&chan->lock, flags); if (is_gain_allocated(chan)) kfree(chan->rxgain); chan->rxgain = rxgain; chan->txgain = txgain; spin_unlock_irqrestore(&chan->lock, flags); } if (copy_to_user(user_data, gain, sizeof(*gain))) { res = -EFAULT; goto cleanup; } cleanup: kfree(gain); return res; } static int dahdi_ioctl_chandiag(struct file *file, unsigned long data) { unsigned long flags; int channo; /* there really is no need to initialize this structure because when it is used it has * already been completely overwritten, but apparently the compiler cannot figure that * out and warns about uninitialized usage... so initialize it. */ struct dahdi_echocan_state ec_state = { .ops = NULL, }; struct dahdi_chan *chan; struct dahdi_chan *temp; /* get channel number from user */ get_user(channo, (int __user *)data); chan = chan_from_num(channo); if (!chan) return -EINVAL; temp = kmalloc(sizeof(*chan), GFP_KERNEL); if (!temp) return -ENOMEM; spin_lock_irqsave(&chan->lock, flags); *temp = *chan; if (temp->ec_state) ec_state = *temp->ec_state; if (temp->curzone) tone_zone_get(temp->curzone); spin_unlock_irqrestore(&chan->lock, flags); module_printk(KERN_INFO, "Dump of DAHDI Channel %d (%s,%d,%d):\n\n", channo, temp->name, temp->channo, temp->chanpos); module_printk(KERN_INFO, "flags: %x hex, writechunk: %p, readchunk: %p\n", (unsigned int) temp->flags, temp->writechunk, temp->readchunk); module_printk(KERN_INFO, "rxgain: %p, txgain: %p, gainalloc: %d\n", temp->rxgain, temp->txgain, is_gain_allocated(temp)); module_printk(KERN_INFO, "span: %p, sig: %x hex, sigcap: %x hex\n", temp->span, temp->sig, temp->sigcap); module_printk(KERN_INFO, "inreadbuf: %d, outreadbuf: %d, inwritebuf: %d, outwritebuf: %d\n", temp->inreadbuf, temp->outreadbuf, temp->inwritebuf, temp->outwritebuf); module_printk(KERN_INFO, "blocksize: %d, numbufs: %d, txbufpolicy: %d, txbufpolicy: %d\n", temp->blocksize, temp->numbufs, temp->txbufpolicy, temp->rxbufpolicy); module_printk(KERN_INFO, "txdisable: %d, rxdisable: %d, iomask: %d\n", temp->txdisable, temp->rxdisable, temp->iomask); module_printk(KERN_INFO, "curzone: %p, tonezone: %d, curtone: %p, tonep: %d\n", temp->curzone, ((temp->curzone) ? temp->curzone->num : -1), temp->curtone, temp->tonep); module_printk(KERN_INFO, "digitmode: %d, txdialbuf: %s, dialing: %d, aftdialtimer: %d, cadpos. %d\n", temp->digitmode, temp->txdialbuf, temp->dialing, temp->afterdialingtimer, temp->cadencepos); module_printk(KERN_INFO, "confna: %d, confn: %d, confmode: %d, confmute: %d\n", temp->confna, temp->_confn, temp->confmode, temp->confmute); module_printk(KERN_INFO, "ec: %p, deflaw: %d, xlaw: %p\n", temp->ec_state, temp->deflaw, temp->xlaw); if (temp->ec_state) { module_printk(KERN_INFO, "echostate: %02x, echotimer: %d, echolastupdate: %d\n", ec_state.status.mode, ec_state.status.pretrain_timer, ec_state.status.last_train_tap); } module_printk(KERN_INFO, "itimer: %d, otimer: %d, ringdebtimer: %d\n\n", temp->itimer, temp->otimer, temp->ringdebtimer); if (temp->curzone) tone_zone_put(temp->curzone); kfree(temp); return 0; } /** * dahdi_ioctl_getparams() - Get channel parameters. * */ static int dahdi_ioctl_getparams(struct file *file, unsigned long data) { size_t size_to_copy; struct dahdi_params param; bool return_master = false; struct dahdi_chan *chan; int j; size_to_copy = sizeof(struct dahdi_params); if (copy_from_user(¶m, (void __user *)data, size_to_copy)) return -EFAULT; /* check to see if the caller wants to receive our master channel * number */ if (param.channo & DAHDI_GET_PARAMS_RETURN_MASTER) { return_master = true; param.channo &= ~DAHDI_GET_PARAMS_RETURN_MASTER; } /* Pick the right channo's */ chan = chan_from_file(file); if (!chan) chan = chan_from_num(param.channo); if (!chan) return -EINVAL; /* point to relevant structure */ param.sigtype = chan->sig; /* get signalling type */ /* return non-zero if rx not in idle state */ if (chan->span) { j = dahdi_q_sig(chan); if (j >= 0) { /* if returned with success */ param.rxisoffhook = ((chan->rxsig & (j >> 8)) != (j & 0xff)); } else { const int sig = chan->rxhooksig; param.rxisoffhook = ((sig != DAHDI_RXSIG_ONHOOK) && (sig != DAHDI_RXSIG_INITIAL)); } } else if ((chan->txstate == DAHDI_TXSTATE_KEWL) || (chan->txstate == DAHDI_TXSTATE_AFTERKEWL)) { param.rxisoffhook = 1; } else { param.rxisoffhook = 0; } if (chan->span && chan->span->ops->rbsbits && !(chan->sig & DAHDI_SIG_CLEAR)) { param.rxbits = chan->rxsig; param.txbits = chan->txsig; param.idlebits = chan->idlebits; } else { param.rxbits = -1; param.txbits = -1; param.idlebits = 0; } if (chan->span && (chan->span->ops->rbsbits || chan->span->ops->hooksig) && !(chan->sig & DAHDI_SIG_CLEAR)) { param.rxhooksig = chan->rxhooksig; param.txhooksig = chan->txhooksig; } else { param.rxhooksig = -1; param.txhooksig = -1; } param.prewinktime = chan->prewinktime; param.preflashtime = chan->preflashtime; param.winktime = chan->winktime; param.flashtime = chan->flashtime; param.starttime = chan->starttime; param.rxwinktime = chan->rxwinktime; param.rxflashtime = chan->rxflashtime; param.debouncetime = chan->debouncetime; param.channo = chan->channo; param.chan_alarms = chan->chan_alarms; /* if requested, put the master channel number in the top 16 bits of * the result */ if (return_master) param.channo |= chan->master->channo << 16; param.pulsemaketime = chan->pulsemaketime; param.pulsebreaktime = chan->pulsebreaktime; param.pulseaftertime = chan->pulseaftertime; param.spanno = (chan->span) ? chan->span->spanno : 0; strlcpy(param.name, chan->name, sizeof(param.name)); param.chanpos = chan->chanpos; param.sigcap = chan->sigcap; /* Return current law */ if (chan->xlaw == __dahdi_alaw) param.curlaw = DAHDI_LAW_ALAW; else param.curlaw = DAHDI_LAW_MULAW; if (copy_to_user((void __user *)data, ¶m, size_to_copy)) return -EFAULT; return 0; } /** * dahdi_ioctl_setparams() - Set channel parameters. * */ static int dahdi_ioctl_setparams(struct file *file, unsigned long data) { struct dahdi_params param; struct dahdi_chan *chan; if (copy_from_user(¶m, (void __user *)data, sizeof(param))) return -EFAULT; param.chan_alarms = 0; /* be explicit about the above */ /* Pick the right channo's */ chan = chan_from_file(file); if (!chan) chan = chan_from_num(param.channo); if (!chan) return -EINVAL; /* point to relevant structure */ /* NOTE: sigtype is *not* included in this */ /* get timing paramters */ chan->prewinktime = param.prewinktime; chan->preflashtime = param.preflashtime; chan->winktime = param.winktime; chan->flashtime = param.flashtime; chan->starttime = param.starttime; /* Update ringtime if not using a tone zone */ if (!chan->curzone) chan->ringcadence[0] = chan->starttime; chan->rxwinktime = param.rxwinktime; chan->rxflashtime = param.rxflashtime; chan->debouncetime = param.debouncetime; chan->pulsemaketime = param.pulsemaketime; chan->pulsebreaktime = param.pulsebreaktime; chan->pulseaftertime = param.pulseaftertime; return 0; } /** * dahdi_ioctl_spanstat() - Return statistics for a span. * */ static int dahdi_ioctl_spanstat(struct file *file, unsigned long data) { int ret = 0; struct dahdi_spaninfo spaninfo; struct dahdi_span *s; int j; size_t size_to_copy; bool via_chan = false; size_to_copy = sizeof(struct dahdi_spaninfo); if (copy_from_user(&spaninfo, (void __user *)data, size_to_copy)) return -EFAULT; if (!spaninfo.spanno) { struct dahdi_chan *const chan = chan_from_file(file); if (!chan) return -EINVAL; s = chan->span; via_chan = true; } else { s = span_find_and_get(spaninfo.spanno); } if (!s) return -EINVAL; spaninfo.spanno = s->spanno; /* put the span # in here */ spaninfo.totalspans = span_count(); strlcpy(spaninfo.desc, s->desc, sizeof(spaninfo.desc)); strlcpy(spaninfo.name, s->name, sizeof(spaninfo.name)); spaninfo.alarms = s->alarms; /* get alarm status */ spaninfo.rxlevel = s->rxlevel; /* get rx level */ spaninfo.txlevel = s->txlevel; /* get tx level */ spaninfo.bpvcount = s->count.bpv; spaninfo.crc4count = s->count.crc4; spaninfo.ebitcount = s->count.ebit; spaninfo.fascount = s->count.fas; spaninfo.fecount = s->count.fe; spaninfo.cvcount = s->count.cv; spaninfo.becount = s->count.be; spaninfo.prbs = s->count.prbs; spaninfo.errsec = s->count.errsec; spaninfo.irqmisses = s->irqmisses; /* get IRQ miss count */ spaninfo.syncsrc = s->syncsrc; /* get active sync source */ spaninfo.totalchans = s->channels; spaninfo.numchans = 0; for (j = 0; j < s->channels; j++) { if (s->chans[j]->sig) spaninfo.numchans++; } spaninfo.lbo = s->lbo; spaninfo.lineconfig = s->lineconfig; spaninfo.irq = s->irq; spaninfo.linecompat = s->linecompat; strlcpy(spaninfo.lboname, dahdi_lboname(s->lbo), sizeof(spaninfo.lboname)); if (s->manufacturer) { strlcpy(spaninfo.manufacturer, s->manufacturer, sizeof(spaninfo.manufacturer)); } if (s->devicetype) { strlcpy(spaninfo.devicetype, s->devicetype, sizeof(spaninfo.devicetype)); } strlcpy(spaninfo.location, s->location, sizeof(spaninfo.location)); if (s->spantype) { strlcpy(spaninfo.spantype, s->spantype, sizeof(spaninfo.spantype)); } if (copy_to_user((void __user *)data, &spaninfo, size_to_copy)) ret = -EFAULT; if (!via_chan) put_span(s); return ret; } /** * dahdi_ioctl_spanstat_v1() - Return statistics for a span in a legacy format. * */ static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data) { int ret = 0; struct dahdi_spaninfo_v1 spaninfo_v1; struct dahdi_span *s; int j; bool via_chan = false; if (copy_from_user(&spaninfo_v1, (void __user *)data, sizeof(spaninfo_v1))) { return -EFAULT; } if (!spaninfo_v1.spanno) { struct dahdi_chan *const chan = chan_from_file(file); if (!chan) return -EINVAL; s = chan->span; via_chan = true; } else { s = span_find_and_get(spaninfo_v1.spanno); } if (!s) return -EINVAL; spaninfo_v1.spanno = s->spanno; /* put the span # in here */ spaninfo_v1.totalspans = 0; spaninfo_v1.totalspans = span_count(); strlcpy(spaninfo_v1.desc, s->desc, sizeof(spaninfo_v1.desc)); strlcpy(spaninfo_v1.name, s->name, sizeof(spaninfo_v1.name)); spaninfo_v1.alarms = s->alarms; spaninfo_v1.bpvcount = s->count.bpv; spaninfo_v1.rxlevel = s->rxlevel; spaninfo_v1.txlevel = s->txlevel; spaninfo_v1.crc4count = s->count.crc4; spaninfo_v1.ebitcount = s->count.ebit; spaninfo_v1.fascount = s->count.fas; spaninfo_v1.irqmisses = s->irqmisses; spaninfo_v1.syncsrc = s->syncsrc; spaninfo_v1.totalchans = s->channels; spaninfo_v1.numchans = 0; for (j = 0; j < s->channels; j++) { if (s->chans[j]->sig) spaninfo_v1.numchans++; } spaninfo_v1.lbo = s->lbo; spaninfo_v1.lineconfig = s->lineconfig; spaninfo_v1.irq = s->irq; spaninfo_v1.linecompat = s->linecompat; strlcpy(spaninfo_v1.lboname, dahdi_lboname(s->lbo), sizeof(spaninfo_v1.lboname)); if (s->manufacturer) { strlcpy(spaninfo_v1.manufacturer, s->manufacturer, sizeof(spaninfo_v1.manufacturer)); } if (s->devicetype) { strlcpy(spaninfo_v1.devicetype, s->devicetype, sizeof(spaninfo_v1.devicetype)); } strlcpy(spaninfo_v1.location, s->location, sizeof(spaninfo_v1.location)); if (s->spantype) { strlcpy(spaninfo_v1.spantype, s->spantype, sizeof(spaninfo_v1.spantype)); } if (copy_to_user((void __user *)data, &spaninfo_v1, sizeof(spaninfo_v1))) { ret = -EFAULT; } if (!via_chan) put_span(s); return ret; } static int dahdi_common_ioctl(struct file *file, unsigned int cmd, unsigned long data) { switch (cmd) { /* get channel parameters */ case DAHDI_GET_PARAMS_V1: /* Intentional drop through. */ case DAHDI_GET_PARAMS: return dahdi_ioctl_getparams(file, data); case DAHDI_SET_PARAMS: return dahdi_ioctl_setparams(file, data); case DAHDI_GETGAINS_V1: /* Intentional drop through. */ case DAHDI_GETGAINS: /* get gain stuff */ return dahdi_ioctl_getgains(file, data); case DAHDI_SETGAINS: /* set gain stuff */ return dahdi_ioctl_setgains(file, data); case DAHDI_SPANSTAT: return dahdi_ioctl_spanstat(file, data); case DAHDI_SPANSTAT_V1: return dahdi_ioctl_spanstat_v1(file, data); case DAHDI_CHANDIAG_V1: /* Intentional drop through. */ case DAHDI_CHANDIAG: return dahdi_ioctl_chandiag(file, data); default: return -ENOTTY; } return 0; } static int (*dahdi_dynamic_ioctl)(unsigned int cmd, unsigned long data); void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)) { dahdi_dynamic_ioctl = func; } static int (*dahdi_hpec_ioctl)(unsigned int cmd, unsigned long data); void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data)) { dahdi_hpec_ioctl = func; } static void recalc_slaves(struct dahdi_chan *chan) { int x; struct dahdi_chan *last = chan; /* Makes no sense if you don't have a span */ if (!chan->span) return; #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Recalculating slaves on %s\n", chan->name); #endif /* Link all slaves appropriately */ for (x=chan->chanpos;xspan->channels;x++) if (chan->span->chans[x]->master == chan) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Channel %s, slave to %s, last is %s, its next will be %d\n", chan->span->chans[x]->name, chan->name, last->name, x); #endif last->nextslave = chan->span->chans[x]; last = last->nextslave; } /* Terminate list */ last->nextslave = NULL; #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Done Recalculating slaves on %s (last is %s)\n", chan->name, last->name); #endif } #if defined(CONFIG_DAHDI_NET) && defined(HAVE_NET_DEVICE_OPS) static const struct net_device_ops dahdi_netdev_ops = { .ndo_open = dahdi_net_open, .ndo_stop = dahdi_net_stop, .ndo_do_ioctl = dahdi_net_ioctl, .ndo_start_xmit = dahdi_xmit, }; #endif static int dahdi_ioctl_chanconfig(struct file *file, unsigned long data) { int res = 0; int y; struct dahdi_chanconfig ch; struct dahdi_chan *newmaster; struct dahdi_chan *chan; struct dahdi_chan *dacs_chan = NULL; unsigned long flags; int sigcap; if (copy_from_user(&ch, (void __user *)data, sizeof(ch))) return -EFAULT; chan = chan_from_num(ch.chan); if (!chan) return -EINVAL; if (ch.sigtype == DAHDI_SIG_SLAVE) { newmaster = chan_from_num(ch.master); if (!newmaster) return -EINVAL; ch.sigtype = newmaster->sig; } else if ((ch.sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) { newmaster = chan; dacs_chan = chan_from_num(ch.idlebits); if (!dacs_chan) return -EINVAL; } else { newmaster = chan; } spin_lock_irqsave(&chan->lock, flags); #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(chan)) { if (chan_to_netdev(chan)->flags & IFF_UP) { spin_unlock_irqrestore(&chan->lock, flags); module_printk(KERN_WARNING, "Can't switch HDLC net mode on channel %s, since current interface is up\n", chan->name); return -EBUSY; } spin_unlock_irqrestore(&chan->lock, flags); unregister_hdlc_device(chan->hdlcnetdev->netdev); spin_lock_irqsave(&chan->lock, flags); free_netdev(chan->hdlcnetdev->netdev); kfree(chan->hdlcnetdev); chan->hdlcnetdev = NULL; clear_bit(DAHDI_FLAGBIT_NETDEV, &chan->flags); } #else if (ch.sigtype == DAHDI_SIG_HDLCNET) { spin_unlock_irqrestore(&chan->lock, flags); module_printk(KERN_WARNING, "DAHDI networking not supported by this build.\n"); return -ENOSYS; } #endif sigcap = chan->sigcap; /* If they support clear channel, then they support the HDLC and such through us. */ if (sigcap & DAHDI_SIG_CLEAR) sigcap |= (DAHDI_SIG_HDLCRAW | DAHDI_SIG_HDLCFCS | DAHDI_SIG_HDLCNET | DAHDI_SIG_DACS); if ((sigcap & ch.sigtype) != ch.sigtype) res = -EINVAL; if (chan->master != chan) { struct dahdi_chan *oldmaster = chan->master; /* Clear the master channel */ chan->master = chan; chan->nextslave = NULL; /* Unlink this channel from the master's channel list */ recalc_slaves(oldmaster); } if (!res) { chan->sig = ch.sigtype; if (chan->sig == DAHDI_SIG_CAS) chan->idlebits = ch.idlebits; else chan->idlebits = 0; if ((ch.sigtype & DAHDI_SIG_CLEAR) == DAHDI_SIG_CLEAR) { /* Set clear channel flag if appropriate */ chan->flags &= ~DAHDI_FLAG_AUDIO; chan->flags |= DAHDI_FLAG_CLEAR; } else { /* Set audio flag and not clear channel otherwise */ chan->flags |= DAHDI_FLAG_AUDIO; chan->flags &= ~DAHDI_FLAG_CLEAR; } if ((ch.sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW) { /* Set the HDLC flag */ chan->flags |= DAHDI_FLAG_HDLC; } else { /* Clear the HDLC flag */ chan->flags &= ~DAHDI_FLAG_HDLC; } if ((ch.sigtype & DAHDI_SIG_HDLCFCS) == DAHDI_SIG_HDLCFCS) { /* Set FCS to be calculated if appropriate */ chan->flags |= DAHDI_FLAG_FCS; } else { /* Clear FCS flag */ chan->flags &= ~DAHDI_FLAG_FCS; } if ((ch.sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) { if (unlikely(!dacs_chan)) { spin_unlock_irqrestore(&chan->lock, flags); return -EINVAL; } /* Setup conference properly */ chan->confmode = DAHDI_CONF_DIGITALMON; chan->confna = ch.idlebits; chan->dacs_chan = dacs_chan; res = dahdi_chan_dacs(chan, dacs_chan); } else { dahdi_disable_dacs(chan); } chan->master = newmaster; /* Note new slave if we are not our own master */ if (newmaster != chan) { recalc_slaves(chan->master); } if ((ch.sigtype & DAHDI_SIG_HARDHDLC) == DAHDI_SIG_HARDHDLC) { chan->flags &= ~DAHDI_FLAG_FCS; chan->flags &= ~DAHDI_FLAG_HDLC; chan->flags |= DAHDI_FLAG_NOSTDTXRX; } else { chan->flags &= ~DAHDI_FLAG_NOSTDTXRX; } if ((ch.sigtype & DAHDI_SIG_MTP2) == DAHDI_SIG_MTP2) chan->flags |= DAHDI_FLAG_MTP2; else chan->flags &= ~DAHDI_FLAG_MTP2; } /* Chanconfig can block, do not call through the function pointer with * the channel lock held. */ spin_unlock_irqrestore(&chan->lock, flags); if (!res && chan->span->ops->chanconfig) res = chan->span->ops->chanconfig(file, chan, ch.sigtype); spin_lock_irqsave(&chan->lock, flags); #ifdef CONFIG_DAHDI_NET if (!res && (newmaster == chan) && (chan->sig == DAHDI_SIG_HDLCNET)) { chan->hdlcnetdev = dahdi_hdlc_alloc(); if (chan->hdlcnetdev) { /* struct hdlc_device *hdlc = chan->hdlcnetdev; struct net_device *d = hdlc_to_dev(hdlc); mmm...get it right later --byg */ chan->hdlcnetdev->netdev = alloc_hdlcdev(chan->hdlcnetdev); if (chan->hdlcnetdev->netdev) { chan->hdlcnetdev->chan = chan; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) SET_MODULE_OWNER(chan->hdlcnetdev->netdev); #endif chan->hdlcnetdev->netdev->irq = chan->span->irq; chan->hdlcnetdev->netdev->tx_queue_len = 50; #ifdef HAVE_NET_DEVICE_OPS chan->hdlcnetdev->netdev->netdev_ops = &dahdi_netdev_ops; #else chan->hdlcnetdev->netdev->do_ioctl = dahdi_net_ioctl; chan->hdlcnetdev->netdev->open = dahdi_net_open; chan->hdlcnetdev->netdev->stop = dahdi_net_stop; #endif dev_to_hdlc(chan->hdlcnetdev->netdev)->attach = dahdi_net_attach; dev_to_hdlc(chan->hdlcnetdev->netdev)->xmit = dahdi_xmit; spin_unlock_irqrestore(&chan->lock, flags); /* Briefly restore interrupts while we register the device */ res = dahdi_register_hdlc_device(chan->hdlcnetdev->netdev, ch.netdev_name); spin_lock_irqsave(&chan->lock, flags); } else { module_printk(KERN_NOTICE, "Unable to allocate hdlc: *shrug*\n"); res = -1; } if (!res) set_bit(DAHDI_FLAGBIT_NETDEV, &chan->flags); } else { module_printk(KERN_NOTICE, "Unable to allocate netdev: out of memory\n"); res = -1; } } #endif if ((chan->sig == DAHDI_SIG_HDLCNET) && (chan == newmaster) && !dahdi_have_netdev(chan)) module_printk(KERN_NOTICE, "Unable to register HDLC device for channel %s\n", chan->name); if (!res) { /* Setup default law */ chan->deflaw = ch.deflaw; /* Copy back any modified settings */ spin_unlock_irqrestore(&chan->lock, flags); if (copy_to_user((void __user *)data, &ch, sizeof(ch))) return -EFAULT; spin_lock_irqsave(&chan->lock, flags); /* And hangup */ dahdi_hangup(chan); y = dahdi_q_sig(chan) & 0xff; if (y >= 0) chan->rxsig = (unsigned char) y; chan->rxhooksig = DAHDI_RXSIG_INITIAL; } #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Configured channel %s, flags %04lx, sig %04x\n", chan->name, chan->flags, chan->sig); #endif spin_unlock_irqrestore(&chan->lock, flags); return res; } /** * dahdi_ioctl_set_dialparms - Set the global dial parameters. * @data: Pointer to user space that contains dahdi_dialparams. */ static int dahdi_ioctl_set_dialparams(unsigned long data) { unsigned int i; struct dahdi_dialparams tdp; struct dahdi_zone *z; struct dahdi_dialparams *const gdp = &global_dialparams; if (copy_from_user(&tdp, (void __user *)data, sizeof(tdp))) return -EFAULT; mutex_lock(&global_dialparamslock); if ((tdp.dtmf_tonelen >= 10) && (tdp.dtmf_tonelen <= 4000)) gdp->dtmf_tonelen = tdp.dtmf_tonelen; if ((tdp.mfv1_tonelen >= 10) && (tdp.mfv1_tonelen <= 4000)) gdp->mfv1_tonelen = tdp.mfv1_tonelen; if ((tdp.mfr2_tonelen >= 10) && (tdp.mfr2_tonelen <= 4000)) gdp->mfr2_tonelen = tdp.mfr2_tonelen; /* update the lengths in all currently loaded zones */ spin_lock(&zone_lock); list_for_each_entry(z, &tone_zones, node) { for (i = 0; i < ARRAY_SIZE(z->dtmf); i++) { z->dtmf[i].tonesamples = gdp->dtmf_tonelen * DAHDI_CHUNKSIZE; } /* for MFR1, we only adjust the length of the digits */ for (i = DAHDI_TONE_MFR1_0; i <= DAHDI_TONE_MFR1_9; i++) { z->mfr1[i - DAHDI_TONE_MFR1_BASE].tonesamples = gdp->mfv1_tonelen * DAHDI_CHUNKSIZE; } for (i = 0; i < ARRAY_SIZE(z->mfr2_fwd); i++) { z->mfr2_fwd[i].tonesamples = gdp->mfr2_tonelen * DAHDI_CHUNKSIZE; } for (i = 0; i < ARRAY_SIZE(z->mfr2_rev); i++) { z->mfr2_rev[i].tonesamples = gdp->mfr2_tonelen * DAHDI_CHUNKSIZE; } } spin_unlock(&zone_lock); dtmf_silence.tonesamples = gdp->dtmf_tonelen * DAHDI_CHUNKSIZE; mfr1_silence.tonesamples = gdp->mfv1_tonelen * DAHDI_CHUNKSIZE; mfr2_silence.tonesamples = gdp->mfr2_tonelen * DAHDI_CHUNKSIZE; mutex_unlock(&global_dialparamslock); return 0; } static int dahdi_ioctl_get_dialparams(unsigned long data) { struct dahdi_dialparams tdp; mutex_lock(&global_dialparamslock); tdp = global_dialparams; mutex_unlock(&global_dialparamslock); if (copy_to_user((void __user *)data, &tdp, sizeof(tdp))) return -EFAULT; return 0; } static int dahdi_ioctl_indirect(struct file *file, unsigned long data) { int res; struct dahdi_indirect_data ind; void *old; static bool warned; struct dahdi_chan *chan; if (copy_from_user(&ind, (void __user *)data, sizeof(ind))) return -EFAULT; chan = chan_from_num(ind.chan); if (!chan) return -EINVAL; if (!warned) { warned = true; module_printk(KERN_WARNING, "Using deprecated " \ "DAHDI_INDIRECT. Please update " \ "dahdi-tools.\n"); } /* Since dahdi_chan_ioctl expects to be called on file handles * associated with channels, we'll temporarily set the * private_data pointer on the ctl file handle just for this * call. */ old = file->private_data; file->private_data = chan; res = dahdi_chan_ioctl(file, ind.op, (unsigned long) ind.data); file->private_data = old; return res; } static int dahdi_ioctl_spanconfig(struct file *file, unsigned long data) { int res = 0; struct dahdi_lineconfig lc; struct dahdi_span *s; if (copy_from_user(&lc, (void __user *)data, sizeof(lc))) return -EFAULT; s = span_find_and_get(lc.span); if (!s) return -ENXIO; if ((lc.lineconfig & 0x1ff0 & s->linecompat) != (lc.lineconfig & 0x1ff0)) { put_span(s); return -EINVAL; } if (s->ops->spanconfig) { s->lineconfig = lc.lineconfig; s->lbo = lc.lbo; s->txlevel = lc.lbo; s->rxlevel = 0; res = s->ops->spanconfig(file, s, &lc); } put_span(s); return res; } static int dahdi_ioctl_startup(struct file *file, unsigned long data) { /* I/O CTL's for control interface */ int j; int res = 0; int x, y; unsigned long flags; struct dahdi_span *s; if (get_user(j, (int __user *)data)) return -EFAULT; s = span_find_and_get(j); if (!s) return -ENXIO; if (s->flags & DAHDI_FLAG_RUNNING) { put_span(s); return 0; } if (s->ops->startup) res = s->ops->startup(file, s); if (!res) { /* Mark as running and hangup any channels */ s->flags |= DAHDI_FLAG_RUNNING; for (x = 0; x < s->channels; x++) { y = dahdi_q_sig(s->chans[x]) & 0xff; if (y >= 0) s->chans[x]->rxsig = (unsigned char)y; spin_lock_irqsave(&s->chans[x]->lock, flags); dahdi_hangup(s->chans[x]); spin_unlock_irqrestore(&s->chans[x]->lock, flags); /* * Set the rxhooksig back to * DAHDI_RXSIG_INITIAL so that new events are * queued on the channel with the actual * received hook state. * */ s->chans[x]->rxhooksig = DAHDI_RXSIG_INITIAL; } } put_span(s); return 0; } static int dahdi_ioctl_shutdown(unsigned long data) { /* I/O CTL's for control interface */ int j; int x; struct dahdi_span *s; if (get_user(j, (int __user *)data)) return -EFAULT; s = span_find_and_get(j); if (!s) return -ENXIO; /* Unconfigure channels */ for (x = 0; x < s->channels; x++) s->chans[x]->sig = 0; if (s->ops->shutdown) { int res = s->ops->shutdown(s); if (res) { put_span(s); return res; } } s->flags &= ~DAHDI_FLAG_RUNNING; put_span(s); return 0; } /** * dahdi_is_hwec_available - Is hardware echocan available on a channel? * @chan: The channel to check * * Returns true if there is a hardware echocan available for the attached * channel, or false otherwise. * */ static bool dahdi_is_hwec_available(const struct dahdi_chan *chan) { if (!chan->span || !chan->span->ops->echocan_name || !hwec_factory.get_name(chan)) return false; return true; } static int dahdi_ioctl_attach_echocan(unsigned long data) { unsigned long flags; struct dahdi_chan *chan; struct dahdi_attach_echocan ae; const struct dahdi_echocan_factory *new = NULL, *old; if (copy_from_user(&ae, (void __user *)data, sizeof(ae))) return -EFAULT; chan = chan_from_num(ae.chan); if (!chan) return -EINVAL; ae.echocan[sizeof(ae.echocan) - 1] = '\0'; if (dahdi_is_hwec_available(chan)) { if (hwec_overrides_swec) { chan_dbg(GENERAL, chan, "Using echocan '%s' instead of requested " \ "'%s'.\n", hwec_def_name, ae.echocan); /* If there is a hardware echocan available we'll * always use it instead of any configured software * echocan. This matches the behavior in dahdi 2.4.1.2 * and earlier releases. */ strlcpy(ae.echocan, hwec_def_name, sizeof(ae.echocan)); } else if (strcasecmp(ae.echocan, hwec_def_name) != 0) { chan_dbg(GENERAL, chan, "Using '%s' on channel even though '%s' is " \ "available.\n", ae.echocan, hwec_def_name); } } if (ae.echocan[0]) { new = find_echocan(ae.echocan); if (!new) return -EINVAL; if (!new->get_name(chan)) { release_echocan(new); return -EINVAL; } } spin_lock_irqsave(&chan->lock, flags); old = chan->ec_factory; chan->ec_factory = new; spin_unlock_irqrestore(&chan->lock, flags); if (old) release_echocan(old); return 0; } static int dahdi_ioctl_sfconfig(unsigned long data) { int res = 0; unsigned long flags; struct dahdi_chan *chan; struct dahdi_sfconfig sf; if (copy_from_user(&sf, (void __user *)data, sizeof(sf))) return -EFAULT; chan = chan_from_num(sf.chan); if (!chan) return -EINVAL; if (chan->sig != DAHDI_SIG_SF) return -EINVAL; spin_lock_irqsave(&chan->lock, flags); chan->rxp1 = sf.rxp1; chan->rxp2 = sf.rxp2; chan->rxp3 = sf.rxp3; chan->txtone = sf.txtone; chan->tx_v2 = sf.tx_v2; chan->tx_v3 = sf.tx_v3; chan->toneflags = sf.toneflag; if (sf.txtone) { /* if set to make tone for tx */ if ((chan->txhooksig && !(sf.toneflag & DAHDI_REVERSE_TXTONE)) || ((!chan->txhooksig) && (sf.toneflag & DAHDI_REVERSE_TXTONE))) { set_txtone(chan, sf.txtone, sf.tx_v2, sf.tx_v3); } else { set_txtone(chan, 0, 0, 0); } } spin_unlock_irqrestore(&chan->lock, flags); return res; } static int dahdi_ioctl_get_version(unsigned long data) { struct dahdi_versioninfo vi; struct ecfactory *cur; size_t space = sizeof(vi.echo_canceller) - 1; memset(&vi, 0, sizeof(vi)); strlcpy(vi.version, dahdi_version, sizeof(vi.version)); spin_lock(&ecfactory_list_lock); list_for_each_entry(cur, &ecfactory_list, list) { strncat(vi.echo_canceller + strlen(vi.echo_canceller), cur->ec->get_name(NULL), space); space -= strlen(cur->ec->get_name(NULL)); if (space < 1) break; if (cur->list.next && (cur->list.next != &ecfactory_list)) { strncat(vi.echo_canceller + strlen(vi.echo_canceller), ", ", space); space -= 2; if (space < 1) break; } } spin_unlock(&ecfactory_list_lock); if (copy_to_user((void __user *)data, &vi, sizeof(vi))) return -EFAULT; return 0; } static int dahdi_ioctl_maint(unsigned long data) { int i; unsigned long flags; int rv; struct dahdi_span *s; struct dahdi_maintinfo maint; /* get struct from user */ if (copy_from_user(&maint, (void __user *)data, sizeof(maint))) return -EFAULT; s = span_find_and_get(maint.spanno); if (!s) return -EINVAL; if (!s->ops->maint) { put_span(s); return -ENOSYS; } spin_lock_irqsave(&s->lock, flags); /* save current maint state */ i = s->maintstat; /* set maint mode */ s->maintstat = maint.command; switch (maint.command) { case DAHDI_MAINT_NONE: case DAHDI_MAINT_LOCALLOOP: case DAHDI_MAINT_NETWORKLINELOOP: case DAHDI_MAINT_NETWORKPAYLOADLOOP: /* if same, ignore it */ if (i == maint.command) break; rv = s->ops->maint(s, maint.command); spin_unlock_irqrestore(&s->lock, flags); if (rv) { put_span(s); return rv; } spin_lock_irqsave(&s->lock, flags); break; case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: s->mainttimer = DAHDI_LOOPCODE_TIME * DAHDI_CHUNKSIZE; rv = s->ops->maint(s, maint.command); spin_unlock_irqrestore(&s->lock, flags); if (rv) { put_span(s); return rv; } spin_lock_irqsave(&s->lock, flags); break; case DAHDI_MAINT_FAS_DEFECT: case DAHDI_MAINT_MULTI_DEFECT: case DAHDI_MAINT_CRC_DEFECT: case DAHDI_MAINT_CAS_DEFECT: case DAHDI_MAINT_PRBS_DEFECT: case DAHDI_MAINT_BIPOLAR_DEFECT: case DAHDI_MAINT_PRBS: case DAHDI_RESET_COUNTERS: case DAHDI_MAINT_ALARM_SIM: /* Prevent notifying an alarm state for generic maintenance functions, unless the driver is already in a maint state */ if (!i) s->maintstat = 0; rv = s->ops->maint(s, maint.command); spin_unlock_irqrestore(&s->lock, flags); if (rv) { put_span(s); return rv; } spin_lock_irqsave(&s->lock, flags); break; default: spin_unlock_irqrestore(&s->lock, flags); module_printk(KERN_NOTICE, "Unknown maintenance event: %d\n", maint.command); put_span(s); return -ENOSYS; } dahdi_alarm_notify(s); /* process alarm-related events */ spin_unlock_irqrestore(&s->lock, flags); put_span(s); return 0; } static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long data) { switch (cmd) { case DAHDI_INDIRECT: return dahdi_ioctl_indirect(file, data); case DAHDI_SPANCONFIG: return dahdi_ioctl_spanconfig(file, data); case DAHDI_STARTUP: return dahdi_ioctl_startup(file, data); case DAHDI_SHUTDOWN: return dahdi_ioctl_shutdown(data); case DAHDI_ATTACH_ECHOCAN: return dahdi_ioctl_attach_echocan(data); case DAHDI_CHANCONFIG: return dahdi_ioctl_chanconfig(file, data); case DAHDI_SFCONFIG: return dahdi_ioctl_sfconfig(data); case DAHDI_DEFAULTZONE: return dahdi_ioctl_defaultzone(data); case DAHDI_LOADZONE: return dahdi_ioctl_loadzone(data); case DAHDI_FREEZONE: return dahdi_ioctl_freezone(data); case DAHDI_SET_DIALPARAMS: return dahdi_ioctl_set_dialparams(data); case DAHDI_GET_DIALPARAMS: return dahdi_ioctl_get_dialparams(data); case DAHDI_GETVERSION: return dahdi_ioctl_get_version(data); case DAHDI_MAINT: return dahdi_ioctl_maint(data); case DAHDI_DYNAMIC_CREATE: case DAHDI_DYNAMIC_DESTROY: if (dahdi_dynamic_ioctl) { return dahdi_dynamic_ioctl(cmd, data); } else { request_module("dahdi_dynamic"); if (dahdi_dynamic_ioctl) return dahdi_dynamic_ioctl(cmd, data); } return -ENOSYS; case DAHDI_EC_LICENSE_CHALLENGE: case DAHDI_EC_LICENSE_RESPONSE: if (dahdi_hpec_ioctl) { return dahdi_hpec_ioctl(cmd, data); } else { request_module("dahdi_echocan_hpec"); if (dahdi_hpec_ioctl) return dahdi_hpec_ioctl(cmd, data); } return -ENOSYS; } return dahdi_common_ioctl(file, cmd, data); } static int ioctl_dahdi_dial(struct dahdi_chan *chan, unsigned long data) { struct dahdi_dialoperation *tdo; unsigned long flags; char *s; int rv; void __user * const user_data = (void __user *)data; tdo = kmalloc(sizeof(*tdo), GFP_KERNEL); if (!tdo) return -ENOMEM; if (copy_from_user(tdo, user_data, sizeof(*tdo))) return -EFAULT; rv = 0; /* Force proper NULL termination and uppercase entry */ tdo->dialstr[DAHDI_MAX_DTMF_BUF - 1] = '\0'; for (s = tdo->dialstr; *s; s++) *s = toupper(*s); spin_lock_irqsave(&chan->lock, flags); if (!chan->curzone) { spin_unlock_irqrestore(&chan->lock, flags); /* The tone zones are loaded by dahdi_cfg from /etc/dahdi/system.conf */ module_printk(KERN_WARNING, "Cannot dial until a tone zone is loaded.\n"); return -ENODATA; } switch (tdo->op) { case DAHDI_DIAL_OP_CANCEL: chan->curtone = NULL; chan->dialing = 0; chan->txdialbuf[0] = '\0'; chan->tonep = 0; chan->pdialcount = 0; break; case DAHDI_DIAL_OP_REPLACE: strcpy(chan->txdialbuf, tdo->dialstr); chan->dialing = 1; __do_dtmf(chan); break; case DAHDI_DIAL_OP_APPEND: if (strlen(tdo->dialstr) + strlen(chan->txdialbuf) >= (DAHDI_MAX_DTMF_BUF - 1)) { rv = -EBUSY; break; } strlcpy(chan->txdialbuf + strlen(chan->txdialbuf), tdo->dialstr, DAHDI_MAX_DTMF_BUF - strlen(chan->txdialbuf)); if (!chan->dialing) { chan->dialing = 1; __do_dtmf(chan); } break; default: rv = -EINVAL; } spin_unlock_irqrestore(&chan->lock, flags); return rv; } static int dahdi_ioctl_setconf(struct file *file, unsigned long data) { struct dahdi_confinfo conf; struct dahdi_chan *chan; struct dahdi_chan *conf_chan = NULL; unsigned long flags; unsigned int confmode; int oldconf; enum {NONE, ENABLE_HWPREEC, DISABLE_HWPREEC} preec = NONE; if (copy_from_user(&conf, (void __user *)data, sizeof(conf))) return -EFAULT; confmode = conf.confmode & DAHDI_CONF_MODE_MASK; chan = (conf.chan) ? chan_from_num(conf.chan) : chan_from_file(file); if (!chan) return -EINVAL; if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; if ((DAHDI_CONF_DIGITALMON == confmode) || is_monitor_mode(conf.confmode)) { conf_chan = chan_from_num(conf.confno); if (!conf_chan) return -EINVAL; } else { /* make sure conf number makes sense, too */ if ((conf.confno < -1) || (conf.confno > DAHDI_MAX_CONF)) return -EINVAL; } /* if taking off of any conf, must have 0 mode */ if ((!conf.confno) && conf.confmode) return -EINVAL; /* likewise if 0 mode must have no conf */ if ((!conf.confmode) && conf.confno) return -EINVAL; dahdi_check_conf(conf.confno); conf.chan = chan->channo; /* return with real channel # */ spin_lock_irqsave(&chan_lock, flags); spin_lock(&chan->lock); if (conf.confno == -1) conf.confno = dahdi_first_empty_conference(); if ((conf.confno < 1) && (conf.confmode)) { /* No more empty conferences */ spin_unlock(&chan->lock); spin_unlock_irqrestore(&chan_lock, flags); return -EBUSY; } /* if changing confs, clear last added info */ if (conf.confno != chan->confna) { memset(chan->conflast, 0, DAHDI_MAX_CHUNKSIZE); memset(chan->conflast1, 0, DAHDI_MAX_CHUNKSIZE); memset(chan->conflast2, 0, DAHDI_MAX_CHUNKSIZE); } oldconf = chan->confna; /* save old conference number */ chan->confna = conf.confno; /* set conference number */ chan->conf_chan = conf_chan; chan->confmode = conf.confmode; /* set conference mode */ chan->_confn = 0; /* Clear confn */ if (chan->span && chan->span->ops->dacs) { if ((confmode == DAHDI_CONF_DIGITALMON) && (chan->txgain == defgain) && (chan->rxgain == defgain) && (conf_chan->txgain == defgain) && (conf_chan->rxgain == defgain)) { dahdi_chan_dacs(chan, conf_chan); } else { dahdi_disable_dacs(chan); } } /* if we are going onto a conf */ if (conf.confno && (confmode == DAHDI_CONF_CONF || confmode == DAHDI_CONF_CONFANN || confmode == DAHDI_CONF_CONFMON || confmode == DAHDI_CONF_CONFANNMON || confmode == DAHDI_CONF_REALANDPSEUDO)) { /* Get alias */ chan->_confn = dahdi_get_conf_alias(conf.confno); } spin_unlock(&chan->lock); if (conf_chan) { if ((confmode == DAHDI_CONF_MONITOR_RX_PREECHO) || (confmode == DAHDI_CONF_MONITOR_TX_PREECHO) || (confmode == DAHDI_CONF_MONITORBOTH_PREECHO)) { if (!conf_chan->readchunkpreec) { void *temp = kmalloc(sizeof(short) * DAHDI_CHUNKSIZE, GFP_ATOMIC); if (temp) { preec = ENABLE_HWPREEC; spin_lock(&conf_chan->lock); conf_chan->readchunkpreec = temp; spin_unlock(&conf_chan->lock); } } } else { preec = DISABLE_HWPREEC; spin_lock(&conf_chan->lock); kfree(conf_chan->readchunkpreec); conf_chan->readchunkpreec = NULL; spin_unlock(&conf_chan->lock); } } spin_unlock_irqrestore(&chan_lock, flags); if (ENABLE_HWPREEC == preec) { int res = dahdi_enable_hw_preechocan(conf_chan); if (res) { spin_lock_irqsave(&chan_lock, flags); spin_lock(&conf_chan->lock); kfree(conf_chan->readchunkpreec); conf_chan->readchunkpreec = NULL; spin_unlock(&conf_chan->lock); spin_unlock_irqrestore(&chan_lock, flags); } return res; } else if (DISABLE_HWPREEC == preec) { dahdi_disable_hw_preechocan(conf_chan); } dahdi_check_conf(oldconf); if (copy_to_user((void __user *)data, &conf, sizeof(conf))) return -EFAULT; return 0; } /** * dahdi_ioctl_confdiag() - Output debug info about conferences to console. * * This is a pure debugging aide since the only result is to the console. * * TODO: Does anyone use this anymore? Should it be hidden behind a debug * compile time option? */ static int dahdi_ioctl_confdiag(struct file *file, unsigned long data) { struct dahdi_chan *chan; unsigned long flags; int i; int j; int c; chan = chan_from_file(file); if (!chan) return -EINVAL; if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; get_user(j, (int __user *)data); /* get conf # */ /* loop thru the interesting ones */ for (i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++) { struct dahdi_span *s; struct pseudo_chan *pseudo; c = 0; spin_lock_irqsave(&chan_lock, flags); list_for_each_entry(s, &span_list, node) { int k; for (k = 0; k < s->channels; k++) { chan = s->chans[k]; if (chan->confna != i) continue; if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n", i); c = 1; module_printk(KERN_NOTICE, "chan %d, mode %x\n", chan->channo, chan->confmode); } } list_for_each_entry(pseudo, &pseudo_chans, node) { /* skip if not in this conf */ if (pseudo->chan.confna != i) continue; if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n", i); c = 1; module_printk(KERN_NOTICE, "chan %d, mode %x\n", pseudo->chan.channo, pseudo->chan.confmode); } spin_unlock_irqrestore(&chan_lock, flags); if (c) module_printk(KERN_NOTICE, "\n"); } return 0; } static int dahdi_ioctl_getconf(struct file *file, unsigned long data) { struct dahdi_confinfo conf; struct dahdi_chan *chan; if (copy_from_user(&conf, (void __user *)data, sizeof(conf))) return -EFAULT; chan = (!conf.chan) ? chan_from_file(file) : chan_from_num(conf.chan); if (!chan) return -EINVAL; if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; conf.chan = chan->channo; /* get channel number */ conf.confno = chan->confna; /* get conference number */ conf.confmode = chan->confmode; /* get conference mode */ if (copy_to_user((void __user *)data, &conf, sizeof(conf))) return -EFAULT; return 0; } /** * dahdi_ioctl_iomux() - Wait for *something* to happen. * * This is now basically like the wait_event_interruptible function, but with * a much more involved wait condition. */ static int dahdi_ioctl_iomux(struct file *file, unsigned long data) { struct dahdi_chan *const chan = chan_from_file(file); unsigned long flags; unsigned int iomask; DEFINE_WAIT(wait); if (get_user(iomask, (int __user *)data)) return -EFAULT; if (unlikely(!iomask || !chan)) return -EINVAL; while (1) { unsigned int wait_result; wait_result = 0; prepare_to_wait(&chan->waitq, &wait, TASK_INTERRUPTIBLE); spin_lock_irqsave(&chan->lock, flags); chan->iomask = iomask; if (iomask & DAHDI_IOMUX_READ) { if ((chan->outreadbuf > -1) && !chan->rxdisable) wait_result |= DAHDI_IOMUX_READ; } if (iomask & DAHDI_IOMUX_WRITE) { if (chan->inwritebuf > -1) wait_result |= DAHDI_IOMUX_WRITE; } if (iomask & DAHDI_IOMUX_WRITEEMPTY) { /* if everything empty -- be sure the transmitter is * enabled */ chan->txdisable = 0; if (chan->outwritebuf < 0) wait_result |= DAHDI_IOMUX_WRITEEMPTY; } if (iomask & DAHDI_IOMUX_SIGEVENT) { if (chan->eventinidx != chan->eventoutidx) wait_result |= DAHDI_IOMUX_SIGEVENT; } spin_unlock_irqrestore(&chan->lock, flags); if (wait_result || (iomask & DAHDI_IOMUX_NOWAIT)) { put_user(wait_result, (int __user *)data); break; } if (signal_pending(current)) { finish_wait(&chan->waitq, &wait); return -ERESTARTSYS; } schedule(); } finish_wait(&chan->waitq, &wait); spin_lock_irqsave(&chan->lock, flags); chan->iomask = 0; spin_unlock_irqrestore(&chan->lock, flags); return 0; } #ifdef CONFIG_DAHDI_MIRROR static int dahdi_ioctl_rxmirror(struct file *file, unsigned long data) { int res; int i; unsigned long flags; struct dahdi_chan *const chan = chan_from_file(file); struct dahdi_chan *srcmirror; if (!chan || chan->srcmirror) return -ENODEV; res = get_user(i, (int __user *)data); if (res) return res; srcmirror = chan_from_num(i); if (!srcmirror) return -EINVAL; module_printk(KERN_INFO, "Chan %d rx mirrored to %d\n", srcmirror->channo, chan->channo); spin_lock_irqsave(&srcmirror->lock, flags); if (srcmirror->rxmirror == NULL) srcmirror->rxmirror = chan; spin_unlock_irqrestore(&srcmirror->lock, flags); if (srcmirror->rxmirror != chan) { module_printk(KERN_INFO, "Chan %d cannot be rxmirrored, " \ "already in use\n", srcmirror->channo); return -EFAULT; } spin_lock_irqsave(&chan->lock, flags); chan->srcmirror = srcmirror; chan->flags = srcmirror->flags; chan->sig = srcmirror->sig; clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); spin_unlock_irqrestore(&chan->lock, flags); return 0; } static int dahdi_ioctl_txmirror(struct file *file, unsigned long data) { int res; int i; unsigned long flags; struct dahdi_chan *const chan = chan_from_file(file); struct dahdi_chan *srcmirror; if (!chan || chan->srcmirror) return -ENODEV; res = get_user(i, (int __user *)data); if (res) return res; srcmirror = chan_from_num(i); if (!srcmirror) return -EINVAL; module_printk(KERN_INFO, "Chan %d tx mirrored to %d\n", srcmirror->channo, chan->channo); spin_lock_irqsave(&srcmirror->lock, flags); srcmirror->txmirror = chan; if (srcmirror->txmirror == NULL) srcmirror->txmirror = chan; spin_unlock_irqrestore(&srcmirror->lock, flags); if (srcmirror->txmirror != chan) { module_printk(KERN_INFO, "Chan %d cannot be txmirrored, " \ "already in use\n", i); return -EFAULT; } spin_lock_irqsave(&chan->lock, flags); chan->srcmirror = srcmirror; chan->flags = srcmirror->flags; chan->sig = srcmirror->sig; clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); spin_unlock_irqrestore(&chan->lock, flags); return 0; } #endif /* CONFIG_DAHDI_MIRROR */ static int dahdi_chanandpseudo_ioctl(struct file *file, unsigned int cmd, unsigned long data) { struct dahdi_chan *chan = chan_from_file(file); union { struct dahdi_bufferinfo bi; struct dahdi_ring_cadence cad; } stack; unsigned long flags; int i, j, rv; void __user * const user_data = (void __user *)data; if (!chan) return -EINVAL; switch(cmd) { #ifdef CONFIG_DAHDI_MIRROR case DAHDI_RXMIRROR: return dahdi_ioctl_rxmirror(file, data); case DAHDI_TXMIRROR: return dahdi_ioctl_txmirror(file, data); #endif /* CONFIG_DAHDI_MIRROR */ case DAHDI_DIALING: spin_lock_irqsave(&chan->lock, flags); j = chan->dialing; spin_unlock_irqrestore(&chan->lock, flags); if (copy_to_user(user_data, &j, sizeof(int))) return -EFAULT; return 0; case DAHDI_DIAL: return ioctl_dahdi_dial(chan, data); case DAHDI_GET_BUFINFO: memset(&stack.bi, 0, sizeof(stack.bi)); stack.bi.rxbufpolicy = chan->rxbufpolicy; stack.bi.txbufpolicy = chan->txbufpolicy; stack.bi.numbufs = chan->numbufs; stack.bi.bufsize = chan->blocksize; /* XXX FIXME! XXX */ stack.bi.readbufs = -1; stack.bi.writebufs = -1; if (copy_to_user(user_data, &stack.bi, sizeof(stack.bi))) return -EFAULT; break; case DAHDI_SET_BUFINFO: if (copy_from_user(&stack.bi, user_data, sizeof(stack.bi))) return -EFAULT; if (stack.bi.bufsize > DAHDI_MAX_BLOCKSIZE) return -EINVAL; if (stack.bi.bufsize < 16) return -EINVAL; if (stack.bi.bufsize * stack.bi.numbufs > DAHDI_MAX_BUF_SPACE) return -EINVAL; /* It does not make sense to allow user mode to change the * receive buffering policy. DAHDI always provides received * buffers to upper layers immediately. Transmission is * different since we might want to allow the kernel to build * up a buffer in order to prevent underruns from the * interrupt context. */ chan->txbufpolicy = stack.bi.txbufpolicy & 0x3; if ((rv = dahdi_reallocbufs(chan, stack.bi.bufsize, stack.bi.numbufs))) return (rv); break; case DAHDI_GET_BLOCKSIZE: /* get blocksize */ /* return block size */ put_user(chan->blocksize, (int __user *)data); break; case DAHDI_SET_BLOCKSIZE: /* set blocksize */ get_user(j, (int __user *)data); /* cannot be larger than max amount */ if (j > DAHDI_MAX_BLOCKSIZE) return(-EINVAL); /* cannot be less then 16 */ if (j < 16) return(-EINVAL); /* allocate a single kernel buffer which we then sub divide into four pieces */ if ((rv = dahdi_reallocbufs(chan, j, chan->numbufs))) return (rv); break; case DAHDI_FLUSH: /* flush input buffer, output buffer, and/or event queue */ get_user(i, (int __user *)data); /* get param */ spin_lock_irqsave(&chan->lock, flags); if (i & DAHDI_FLUSH_READ) /* if for read (input) */ { /* initialize read buffers and pointers */ chan->inreadbuf = 0; chan->outreadbuf = -1; for (j=0;jnumbufs;j++) { /* Do we need this? */ chan->readn[j] = 0; chan->readidx[j] = 0; } wake_up_interruptible(&chan->waitq); /* wake_up_interruptible waiting on read */ } if (i & DAHDI_FLUSH_WRITE) /* if for write (output) */ { /* initialize write buffers and pointers */ chan->outwritebuf = -1; chan->inwritebuf = 0; for (j=0;jnumbufs;j++) { /* Do we need this? */ chan->writen[j] = 0; chan->writeidx[j] = 0; } wake_up_interruptible(&chan->waitq); /* wake_up_interruptible waiting on write */ } if (i & DAHDI_FLUSH_EVENT) /* if for events */ { /* initialize the event pointers */ chan->eventinidx = chan->eventoutidx = 0; } spin_unlock_irqrestore(&chan->lock, flags); break; case DAHDI_SYNC: /* wait for no tx */ for(;;) /* loop forever */ { spin_lock_irqsave(&chan->lock, flags); /* Know if there is a write pending */ i = (chan->outwritebuf > -1); spin_unlock_irqrestore(&chan->lock, flags); if (!i) break; /* skip if none */ rv = wait_event_interruptible(chan->waitq, (chan->outwritebuf > -1)); if (rv) return rv; } break; case DAHDI_IOMUX: /* wait for something to happen */ return dahdi_ioctl_iomux(file, data); case DAHDI_GETEVENT: /* Get event on queue */ /* set up for no event */ j = DAHDI_EVENT_NONE; spin_lock_irqsave(&chan->lock, flags); /* if some event in queue */ if (chan->eventinidx != chan->eventoutidx) { j = chan->eventbuf[chan->eventoutidx++]; /* get the data, bump index */ /* if index overflow, set to beginning */ if (chan->eventoutidx >= DAHDI_MAX_EVENTSIZE) chan->eventoutidx = 0; } spin_unlock_irqrestore(&chan->lock, flags); put_user(j, (int __user *)data); break; case DAHDI_CONFMUTE: /* set confmute flag */ get_user(j, (int __user *)data); /* get conf # */ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); spin_lock_irqsave(&chan_lock, flags); chan->confmute = j; spin_unlock_irqrestore(&chan_lock, flags); break; case DAHDI_GETCONFMUTE: /* get confmute flag */ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); j = chan->confmute; put_user(j, (int __user *)data); /* get conf # */ rv = 0; break; case DAHDI_SETTONEZONE: get_user(j, (int __user *) data); rv = set_tone_zone(chan, j); return rv; case DAHDI_GETTONEZONE: spin_lock_irqsave(&chan->lock, flags); j = (chan->curzone) ? chan->curzone->num : 0; spin_unlock_irqrestore(&chan->lock, flags); put_user(j, (int __user *) data); break; case DAHDI_SENDTONE: get_user(j, (int __user *)data); spin_lock_irqsave(&chan->lock, flags); rv = start_tone(chan, j); spin_unlock_irqrestore(&chan->lock, flags); return rv; case DAHDI_GETCONF_V1: /* intentional drop through */ case DAHDI_GETCONF: /* get conf stuff */ return dahdi_ioctl_getconf(file, data); case DAHDI_SETCONF_V1: /* Intentional fall through. */ case DAHDI_SETCONF: /* set conf stuff */ return dahdi_ioctl_setconf(file, data); case DAHDI_CONFDIAG_V1: /* Intentional fall-through */ case DAHDI_CONFDIAG: /* output diagnostic info to console */ return dahdi_ioctl_confdiag(file, data); case DAHDI_CHANNO: /* get channel number of stream */ /* return channel number */ put_user(chan->channo, (int __user *)data); break; case DAHDI_SETLAW: get_user(j, (int __user *)data); if ((j < 0) || (j > DAHDI_LAW_ALAW)) return -EINVAL; dahdi_set_law(chan, j); break; case DAHDI_SETLINEAR: get_user(j, (int __user *)data); /* Makes no sense on non-audio channels */ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; if (j) chan->flags |= DAHDI_FLAG_LINEAR; else chan->flags &= ~DAHDI_FLAG_LINEAR; break; case DAHDI_SETCADENCE: if (data) { /* Use specific ring cadence */ if (copy_from_user(&stack.cad, user_data, sizeof(stack.cad))) { return -EFAULT; } memcpy(chan->ringcadence, &stack.cad, sizeof(chan->ringcadence)); chan->firstcadencepos = 0; /* Looking for negative ringing time indicating where to loop back into ringcadence */ for (i=0; iringcadence[i]<0) { chan->ringcadence[i] *= -1; chan->firstcadencepos = i; break; } } } else { /* Reset to default */ chan->firstcadencepos = 0; if (chan->curzone) { memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence)); /* Looking for negative ringing time indicating where to loop back into ringcadence */ for (i=0; iringcadence[i]<0) { chan->ringcadence[i] *= -1; chan->firstcadencepos = i; break; } } } else { memset(chan->ringcadence, 0, sizeof(chan->ringcadence)); chan->ringcadence[0] = chan->starttime; chan->ringcadence[1] = DAHDI_RINGOFFTIME; } } break; default: /* Check for common ioctl's and private ones */ rv = dahdi_common_ioctl(file, cmd, data); /* if no span, just return with value */ if (!chan->span) return rv; if ((rv == -ENOTTY) && chan->span->ops->ioctl) rv = chan->span->ops->ioctl(chan, cmd, data); return rv; } return 0; } #ifdef CONFIG_DAHDI_PPP /* * This is called at softirq (BH) level when there are calls * we need to make to the ppp_generic layer. We do it this * way because the ppp_generic layer functions may not be called * at interrupt level. */ static void do_ppp_calls(unsigned long data) { struct dahdi_chan *chan = (struct dahdi_chan *) data; struct sk_buff *skb; if (!chan->ppp) return; if (chan->do_ppp_wakeup) { chan->do_ppp_wakeup = 0; ppp_output_wakeup(chan->ppp); } while ((skb = skb_dequeue(&chan->ppp_rq)) != NULL) ppp_input(chan->ppp, skb); if (chan->do_ppp_error) { chan->do_ppp_error = 0; ppp_input_error(chan->ppp, 0); } } #endif static int ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, const void __user *data) { struct dahdi_echocan_state *ec = NULL, *ec_state; const struct dahdi_echocan_factory *ec_current; struct dahdi_echocanparam *params; int ret = 0; unsigned long flags; if (ecp->param_count > DAHDI_MAX_ECHOCANPARAMS) return -E2BIG; if (ecp->tap_length == 0) { /* disable mode, don't need to inspect params */ spin_lock_irqsave(&chan->lock, flags); ec_state = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; spin_unlock_irqrestore(&chan->lock, flags); if (ec_state) { ec_state->ops->echocan_free(chan, ec_state); release_echocan(ec_current); } return 0; } params = kmalloc(sizeof(params[0]) * DAHDI_MAX_ECHOCANPARAMS, GFP_KERNEL); if (!params) return -ENOMEM; /* enable mode, need the params */ if (copy_from_user(params, data, sizeof(params[0]) * ecp->param_count)) { ret = -EFAULT; goto exit_with_free; } /* free any echocan that may be on the channel already */ spin_lock_irqsave(&chan->lock, flags); ec_state = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; spin_unlock_irqrestore(&chan->lock, flags); if (ec_state) { ec_state->ops->echocan_free(chan, ec_state); release_echocan(ec_current); } switch (ecp->tap_length) { case 32: case 64: case 128: case 256: case 512: case 1024: break; default: ecp->tap_length = deftaps; } ec_current = NULL; if (chan->ec_factory) { /* try to get another reference to the module providing this channel's echo canceler */ if (!try_module_get(chan->ec_factory->owner)) { module_printk(KERN_ERR, "Cannot get a reference to the" " '%s' echo canceler\n", chan->ec_factory->get_name(chan)); goto exit_with_free; } /* got the reference, copy the pointer and use it for making an echo canceler instance if possible */ ec_current = chan->ec_factory; ret = ec_current->echocan_create(chan, ecp, params, &ec); if (ret) { release_echocan(ec_current); goto exit_with_free; } if (!ec) { module_printk(KERN_ERR, "%s failed to allocate an " \ "dahdi_echocan_state instance.\n", ec_current->get_name(chan)); ret = -EFAULT; goto exit_with_free; } } if (ec) { spin_lock_irqsave(&chan->lock, flags); chan->ec_current = ec_current; chan->ec_state = ec; ec->status.mode = ECHO_MODE_ACTIVE; if (!ec->features.CED_tx_detect) { echo_can_disable_detector_init(&chan->ec_state->txecdis); } if (!ec->features.CED_rx_detect) { echo_can_disable_detector_init(&chan->ec_state->rxecdis); } spin_unlock_irqrestore(&chan->lock, flags); } exit_with_free: kfree(params); return ret; } static void set_echocan_fax_mode(struct dahdi_chan *chan, unsigned int channo, const char *reason, unsigned int enable) { if (enable) { if (!chan->ec_state) module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for channel %d with no echo canceller\n", reason, channo); else if (chan->ec_state->status.mode == ECHO_MODE_FAX) module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller already in FAX mode on channel %d\n", reason, channo); else if (chan->ec_state->status.mode != ECHO_MODE_ACTIVE) module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller not in active mode on channel %d\n", reason, channo); else if (chan->ec_state->features.NLP_automatic) { /* for echocans that automatically do the right thing, just * mark it as being in FAX mode without making any * changes, as none are necessary. */ chan->ec_state->status.mode = ECHO_MODE_FAX; } else if (chan->ec_state->features.NLP_toggle) { module_printk(KERN_NOTICE, "Disabled echo canceller NLP because of %s on channel %d\n", reason, channo); dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED); chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 0); chan->ec_state->status.mode = ECHO_MODE_FAX; } else { module_printk(KERN_NOTICE, "Idled echo canceller because of %s on channel %d\n", reason, channo); chan->ec_state->status.mode = ECHO_MODE_IDLE; } } else { if (!chan->ec_state) module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for channel %d with no echo canceller\n", reason, channo); else if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller already in voice mode on channel %d\n", reason, channo); else if ((chan->ec_state->status.mode != ECHO_MODE_FAX) && (chan->ec_state->status.mode != ECHO_MODE_IDLE)) module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller not in FAX or idle mode on channel %d\n", reason, channo); else if (chan->ec_state->features.NLP_automatic) { /* for echocans that automatically do the right thing, just * mark it as being in active mode without making any * changes, as none are necessary. */ chan->ec_state->status.mode = ECHO_MODE_ACTIVE; } else if (chan->ec_state->features.NLP_toggle) { module_printk(KERN_NOTICE, "Enabled echo canceller NLP because of %s on channel %d\n", reason, channo); dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED); chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 1); chan->ec_state->status.mode = ECHO_MODE_ACTIVE; } else { module_printk(KERN_NOTICE, "Activated echo canceller because of %s on channel %d\n", reason, channo); chan->ec_state->status.mode = ECHO_MODE_ACTIVE; } } } static inline bool is_txstate(struct dahdi_chan *const chan, const int txstate) { bool ret; unsigned long flags; spin_lock_irqsave(&chan->lock, flags); ret = (txstate == chan->txstate); spin_unlock_irqrestore(&chan->lock, flags); return ret; } static int dahdi_chan_ioctl(struct file *file, unsigned int cmd, unsigned long data) { struct dahdi_chan *const chan = chan_from_file(file); unsigned long flags; int j; int ret; int oldconf; const void *rxgain = NULL; if (!chan) return -ENOSYS; WARN_ON(!chan->master); switch(cmd) { case DAHDI_SETSIGFREEZE: get_user(j, (int __user *)data); spin_lock_irqsave(&chan->lock, flags); if (j) { chan->flags |= DAHDI_FLAG_SIGFREEZE; } else { chan->flags &= ~DAHDI_FLAG_SIGFREEZE; } spin_unlock_irqrestore(&chan->lock, flags); break; case DAHDI_GETSIGFREEZE: spin_lock_irqsave(&chan->lock, flags); if (chan->flags & DAHDI_FLAG_SIGFREEZE) j = 1; else j = 0; spin_unlock_irqrestore(&chan->lock, flags); put_user(j, (int __user *)data); break; case DAHDI_AUDIOMODE: /* Only literal clear channels can be put in */ if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); get_user(j, (int __user *)data); if (j) { spin_lock_irqsave(&chan->lock, flags); chan->flags |= DAHDI_FLAG_AUDIO; chan->flags &= ~(DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); spin_unlock_irqrestore(&chan->lock, flags); } else { /* Coming out of audio mode, also clear all conferencing and gain related info as well as echo canceller */ struct dahdi_echocan_state *ec_state; const struct dahdi_echocan_factory *ec_current; spin_lock_irqsave(&chan->lock, flags); chan->flags &= ~DAHDI_FLAG_AUDIO; /* save old conf number, if any */ oldconf = chan->confna; /* initialize conference variables */ chan->_confn = 0; chan->confna = 0; chan->conf_chan = NULL; dahdi_disable_dacs(chan); chan->confmode = 0; chan->confmute = 0; memset(chan->conflast, 0, sizeof(chan->conflast)); memset(chan->conflast1, 0, sizeof(chan->conflast1)); memset(chan->conflast2, 0, sizeof(chan->conflast2)); ec_state = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; /* release conference resource, if any to release */ reset_conf(chan); if (is_gain_allocated(chan)) rxgain = chan->rxgain; else rxgain = NULL; chan->rxgain = defgain; chan->txgain = defgain; spin_unlock_irqrestore(&chan->lock, flags); if (ec_state) { ec_state->ops->echocan_free(chan, ec_state); release_echocan(ec_current); } if (rxgain) kfree(rxgain); if (oldconf) dahdi_check_conf(oldconf); } #ifdef DAHDI_AUDIO_NOTIFY if (chan->span->ops->audio_notify) chan->span->ops->audio_notify(chan, j); #endif break; case DAHDI_HDLCPPP: #ifdef CONFIG_DAHDI_PPP if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); get_user(j, (int __user *)data); if (j) { if (!chan->ppp) { chan->ppp = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); if (chan->ppp) { struct dahdi_echocan_state *tec; const struct dahdi_echocan_factory *ec_current; chan->ppp->private = chan; chan->ppp->ops = &ztppp_ops; chan->ppp->mtu = DAHDI_DEFAULT_MTU_MRU; chan->ppp->hdrlen = 0; skb_queue_head_init(&chan->ppp_rq); chan->do_ppp_wakeup = 0; tasklet_init(&chan->ppp_calls, do_ppp_calls, (unsigned long)chan); if ((ret = dahdi_reallocbufs(chan, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS))) { kfree(chan->ppp); chan->ppp = NULL; return ret; } if ((ret = ppp_register_channel(chan->ppp))) { kfree(chan->ppp); chan->ppp = NULL; return ret; } tec = chan->ec_state; chan->ec_state = NULL; ec_current = chan->ec_current; chan->ec_current = NULL; /* Make sure there's no gain */ if (is_gain_allocated(chan)) kfree(chan->rxgain); chan->rxgain = defgain; chan->txgain = defgain; chan->flags &= ~DAHDI_FLAG_AUDIO; chan->flags |= (DAHDI_FLAG_PPP | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); if (tec) { tec->ops->echocan_free(chan, tec); release_echocan(ec_current); } } else return -ENOMEM; } } else { chan->flags &= ~(DAHDI_FLAG_PPP | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); if (chan->ppp) { struct ppp_channel *ppp = chan->ppp; chan->ppp = NULL; tasklet_kill(&chan->ppp_calls); skb_queue_purge(&chan->ppp_rq); ppp_unregister_channel(ppp); kfree(ppp); } } #else module_printk(KERN_NOTICE, "PPP support not compiled in\n"); return -ENOSYS; #endif break; case DAHDI_HDLCRAWMODE: if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); get_user(j, (int __user *)data); chan->flags &= ~(DAHDI_FLAG_AUDIO | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); if (j) { chan->flags |= DAHDI_FLAG_HDLC; fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); } break; case DAHDI_HDLCFCSMODE: if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); get_user(j, (int __user *)data); chan->flags &= ~(DAHDI_FLAG_AUDIO | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); if (j) { chan->flags |= DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS; fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); } break; case DAHDI_HDLC_RATE: get_user(j, (int __user *)data); if (j == 56) { chan->flags |= DAHDI_FLAG_HDLC56; } else { chan->flags &= ~DAHDI_FLAG_HDLC56; } fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); break; case DAHDI_ECHOCANCEL_PARAMS: { struct dahdi_echocanparams ecp; if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; ret = copy_from_user(&ecp, (struct dahdi_echocanparams __user *)data, sizeof(ecp)); if (ret) return -EFAULT; data += sizeof(ecp); ret = ioctl_echocancel(chan, &ecp, (void __user *)data); if (ret) return ret; break; } case DAHDI_ECHOCANCEL: { struct dahdi_echocanparams ecp; if (!(chan->flags & DAHDI_FLAG_AUDIO)) return -EINVAL; get_user(j, (int __user *) data); ecp.tap_length = j; ecp.param_count = 0; if ((ret = ioctl_echocancel(chan, &ecp, NULL))) return ret; break; } case DAHDI_ECHOTRAIN: /* get pre-training time from user */ get_user(j, (int __user *)data); if ((j < 0) || (j >= DAHDI_MAX_PRETRAINING)) return -EINVAL; j <<= 3; spin_lock_irqsave(&chan->lock, flags); if (chan->ec_state) { /* Start pretraining stage */ if (chan->ec_state->ops->echocan_traintap) { chan->ec_state->status.mode = ECHO_MODE_PRETRAINING; chan->ec_state->status.pretrain_timer = j; } spin_unlock_irqrestore(&chan->lock, flags); } else { spin_unlock_irqrestore(&chan->lock, flags); return -EINVAL; } break; case DAHDI_ECHOCANCEL_FAX_MODE: if (!chan->ec_state) { return -EINVAL; } else { get_user(j, (int __user *) data); spin_lock_irqsave(&chan->lock, flags); set_echocan_fax_mode(chan, chan->channo, "ioctl", j ? 1 : 0); spin_unlock_irqrestore(&chan->lock, flags); } break; case DAHDI_SETTXBITS: if (chan->sig != DAHDI_SIG_CAS) return -EINVAL; get_user(j, (int __user *)data); dahdi_cas_setbits(chan, j); break; case DAHDI_GETRXBITS: put_user(chan->rxsig, (int __user *)data); break; case DAHDI_LOOPBACK: get_user(j, (int __user *)data); spin_lock_irqsave(&chan->lock, flags); if (j) chan->flags |= DAHDI_FLAG_LOOPED; else chan->flags &= ~DAHDI_FLAG_LOOPED; spin_unlock_irqrestore(&chan->lock, flags); break; case DAHDI_HOOK: get_user(j, (int __user *)data); if (chan->flags & DAHDI_FLAG_CLEAR) return -EINVAL; if (chan->sig == DAHDI_SIG_CAS) return -EINVAL; /* if no span, just do nothing */ if (!chan->span) return(0); spin_lock_irqsave(&chan->lock, flags); /* if dialing, stop it */ chan->curtone = NULL; chan->dialing = 0; chan->txdialbuf[0] = '\0'; chan->tonep = 0; chan->pdialcount = 0; spin_unlock_irqrestore(&chan->lock, flags); if (chan->span->flags & DAHDI_FLAG_RBS) { switch (j) { case DAHDI_ONHOOK: spin_lock_irqsave(&chan->lock, flags); dahdi_hangup(chan); spin_unlock_irqrestore(&chan->lock, flags); break; case DAHDI_OFFHOOK: spin_lock_irqsave(&chan->lock, flags); if ((chan->txstate == DAHDI_TXSTATE_KEWL) || (chan->txstate == DAHDI_TXSTATE_AFTERKEWL)) { spin_unlock_irqrestore(&chan->lock, flags); return -EBUSY; } dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_DEBOUNCE, chan->debouncetime); spin_unlock_irqrestore(&chan->lock, flags); break; case DAHDI_RING: case DAHDI_START: spin_lock_irqsave(&chan->lock, flags); if (!chan->curzone) { spin_unlock_irqrestore(&chan->lock, flags); module_printk(KERN_WARNING, "Cannot start tone until a tone zone is loaded.\n"); return -ENODATA; } if (chan->txstate != DAHDI_TXSTATE_ONHOOK) { spin_unlock_irqrestore(&chan->lock, flags); return -EBUSY; } if (chan->sig & __DAHDI_SIG_FXO) { ret = 0; chan->cadencepos = 0; ret = chan->ringcadence[0]; dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_RINGON, ret); } else dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_START, chan->starttime); spin_unlock_irqrestore(&chan->lock, flags); if (file->f_flags & O_NONBLOCK) return -EINPROGRESS; break; case DAHDI_WINK: spin_lock_irqsave(&chan->lock, flags); if (chan->txstate != DAHDI_TXSTATE_ONHOOK) { spin_unlock_irqrestore(&chan->lock, flags); return -EBUSY; } dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_PREWINK, chan->prewinktime); spin_unlock_irqrestore(&chan->lock, flags); if (file->f_flags & O_NONBLOCK) return -EINPROGRESS; wait_event_interruptible(chan->waitq, is_txstate(chan, DAHDI_TXSIG_ONHOOK)); if (signal_pending(current)) return -ERESTARTSYS; break; case DAHDI_FLASH: spin_lock_irqsave(&chan->lock, flags); if (chan->txstate != DAHDI_TXSTATE_OFFHOOK) { spin_unlock_irqrestore(&chan->lock, flags); return -EBUSY; } dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_PREFLASH, chan->preflashtime); spin_unlock_irqrestore(&chan->lock, flags); if (file->f_flags & O_NONBLOCK) return -EINPROGRESS; wait_event_interruptible(chan->waitq, is_txstate(chan, DAHDI_TXSIG_OFFHOOK)); if (signal_pending(current)) return -ERESTARTSYS; break; case DAHDI_RINGOFF: spin_lock_irqsave(&chan->lock, flags); dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); spin_unlock_irqrestore(&chan->lock, flags); break; default: return -EINVAL; } } else if (chan->span->ops->sethook) { if (chan->txhooksig != j) { chan->txhooksig = j; chan->span->ops->sethook(chan, j); } } else return -ENOSYS; break; #ifdef CONFIG_DAHDI_PPP case PPPIOCGCHAN: if (chan->flags & DAHDI_FLAG_PPP) { return put_user(ppp_channel_index(chan->ppp), (int __user *)data) ? -EFAULT : 0; } else { return -EINVAL; } break; case PPPIOCGUNIT: if (chan->flags & DAHDI_FLAG_PPP) { return put_user(ppp_unit_number(chan->ppp), (int __user *)data) ? -EFAULT : 0; } else { return -EINVAL; } break; #endif case DAHDI_BUFFER_EVENTS: if (get_user(j, (int __user *)data)) return -EFAULT; if (j) set_bit(DAHDI_FLAGBIT_BUFEVENTS, &chan->flags); else clear_bit(DAHDI_FLAGBIT_BUFEVENTS, &chan->flags); break; default: return dahdi_chanandpseudo_ioctl(file, cmd, data); } return 0; } static int dahdi_prechan_ioctl(struct file *file, unsigned int cmd, unsigned long data) { int channo; int res; if (file->private_data) { module_printk(KERN_NOTICE, "Huh? Prechan already has private data??\n"); } switch(cmd) { case DAHDI_SPECIFY: get_user(channo, (int __user *)data); file->private_data = chan_from_num(channo); if (!file->private_data) return -EINVAL; res = dahdi_specchan_open(file); if (res) file->private_data = NULL; return res; default: return -ENOSYS; } return 0; } static long dahdi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data) { int unit = UNIT(file); struct dahdi_timer *timer; int ret; #if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) lock_kernel(); #endif if (unit == DAHDI_CTL) { ret = dahdi_ctl_ioctl(file, cmd, data); goto unlock_exit; } if (unit == DAHDI_TRANSCODE) { /* dahdi_transcode should have updated the file_operations on * this file object on open, so we shouldn't be here. */ WARN_ON(1); ret = -EFAULT; goto unlock_exit; } if (unit == DAHDI_TIMER) { timer = file->private_data; if (timer) ret = dahdi_timer_ioctl(file, cmd, data, timer); else ret = -EINVAL; goto unlock_exit; } if (unit == DAHDI_CHANNEL) { if (file->private_data) ret = dahdi_chan_ioctl(file, cmd, data); else ret = dahdi_prechan_ioctl(file, cmd, data); goto unlock_exit; } if (unit == DAHDI_PSEUDO) { if (!file->private_data) { module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n"); ret = -EINVAL; goto unlock_exit; } ret = dahdi_chanandpseudo_ioctl(file, cmd, data); goto unlock_exit; } if (!file->private_data) { ret = -ENXIO; goto unlock_exit; } ret = dahdi_chan_ioctl(file, cmd, data); unlock_exit: #if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) unlock_kernel(); #endif return ret; } #ifndef HAVE_UNLOCKED_IOCTL static int dahdi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { return dahdi_unlocked_ioctl(file, cmd, data); } #endif #ifdef HAVE_COMPAT_IOCTL static long dahdi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long data) { if (cmd == DAHDI_SFCONFIG) return -ENOTTY; /* Not supported yet */ return dahdi_unlocked_ioctl(file, cmd, data); } #endif /** * _get_next_channo - Return the next taken channel number from the span list. * @span: The span with which to start the search. * * Returns -1 if there aren't any channels on span or any of the following * spans, otherwise, returns the channel number of the first channel. * * Must be callled with registration_mutex held. * */ static int _get_next_channo(const struct dahdi_span *span) { const struct list_head *pos = &span->node; while (pos != &span_list) { span = list_entry(pos, struct dahdi_span, node); if (span->channels) return span->chans[0]->channo; pos = pos->next; } return -1; } /** * _find_spanno_and_channo - Find the next available span and channel number. * * Must be called with registration_mutex held. * */ static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span, int *spanno, int *channo, struct list_head *loc) { struct dahdi_span *pos; int next_channo; *spanno = 1; *channo = 1; list_for_each_entry(pos, &span_list, node) { bool skip_span; loc = &pos->node; next_channo = _get_next_channo(pos); skip_span = (pos->spanno == *spanno) || ((next_channo > 1) && ((*channo + span->channels) > next_channo)); if (!skip_span) break; *spanno = pos->spanno + 1; if (pos->channels) *channo = next_channo + pos->channels; } return loc; } /** * _dahdi_register - Register the span. * * NOTE: Must be called with the registration_mutex held. * */ static int _dahdi_register(struct dahdi_span *span, int prefmaster) { unsigned int spanno; unsigned int x; struct list_head *loc = &span_list; unsigned long flags; unsigned int channo; int res = 0; if (!span || !span->ops || !span->ops->owner) return -EINVAL; if (span->ops->enable_hw_preechocan || span->ops->disable_hw_preechocan) { if ((NULL == span->ops->enable_hw_preechocan) || (NULL == span->ops->disable_hw_preechocan)) return -EINVAL; } if (!span->deflaw) { module_printk(KERN_NOTICE, "Span %s didn't specify default law. " "Assuming mulaw, please fix driver!\n", span->name); span->deflaw = DAHDI_LAW_MULAW; } spin_lock_init(&span->lock); /* Look through the span list to find the first available span number. * The spans are kept on this list in sorted order. We'll also save * off the next available channel number to use. */ loc = _find_spanno_and_channo(span, &spanno, &channo, loc); if (unlikely(channo >= FIRST_PSEUDO_CHANNEL)) return -EINVAL; span->spanno = spanno; for (x = 0; x < span->channels; x++) { span->chans[x]->span = span; span->chans[x]->channo = channo + x; dahdi_chan_reg(span->chans[x]); } #ifdef CONFIG_PROC_FS { char tempfile[17]; snprintf(tempfile, sizeof(tempfile), "%d", span->spanno); span->proc_entry = create_proc_entry(tempfile, 0444, root_proc_entry); if (!span->proc_entry) { res = -EFAULT; span_err(span, "Error creating procfs entry\n"); goto cleanup; } span->proc_entry->data = (void *)(long)span->spanno; span->proc_entry->proc_fops = &dahdi_proc_ops; } #endif res = span_sysfs_create(span); if (res) goto cleanup; if (debug & DEBUG_MAIN) { module_printk(KERN_NOTICE, "Registered Span %d ('%s') with " "%d channels\n", span->spanno, span->name, span->channels); } spin_lock_irqsave(&chan_lock, flags); if (loc == &span_list) list_add_tail(&span->node, &span_list); else list_add(&span->node, loc); spin_unlock_irqrestore(&chan_lock, flags); set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); __dahdi_find_master_span(); return 0; cleanup: #ifdef CONFIG_PROC_FS if (span->proc_entry) { char tempfile[17]; snprintf(tempfile, sizeof(tempfile), "dahdi/%d", span->spanno); remove_proc_entry(tempfile, NULL); span->proc_entry = NULL; } #endif for (x = 0; x < span->channels; x++) { struct dahdi_chan *chan = span->chans[x]; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) dahdi_chan_unreg(chan); } return res; } /** * dahdi_register() - unregister a new DAHDI span * @span: the DAHDI span * @prefmaster: will the new span be preferred as a master? * * Registers a span for usage with DAHDI. All the channel numbers in it * will get the lowest available channel numbers. * * If prefmaster is set to anything > 0, span will attempt to become the * master DAHDI span at registration time. If 0: it will only become * master if no other span is currently the master (i.e.: it is the * first one). * */ int dahdi_register(struct dahdi_span *span, int prefmaster) { int ret; mutex_lock(®istration_mutex); ret = _dahdi_register(span, prefmaster); mutex_unlock(®istration_mutex); return ret; } static int _dahdi_unregister(struct dahdi_span *span) { int x; struct dahdi_span *new_master, *s; unsigned long flags; if (span != _find_span(span->spanno)) { module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name); return -1; } spin_lock_irqsave(&chan_lock, flags); list_del_init(&span->node); spin_unlock_irqrestore(&chan_lock, flags); span->spanno = 0; clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); /* Shutdown the span if it's running */ if ((span->flags & DAHDI_FLAG_RUNNING) && span->ops->shutdown) span->ops->shutdown(span); if (debug & DEBUG_MAIN) module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels); #ifdef CONFIG_PROC_FS remove_proc_entry(span->proc_entry->name, root_proc_entry); #endif /* CONFIG_PROC_FS */ span_sysfs_remove(span); for (x=0;xchannels;x++) dahdi_chan_unreg(span->chans[x]); new_master = master; /* FIXME: locking */ if (master == span) new_master = NULL; spin_lock_irqsave(&chan_lock, flags); list_for_each_entry(s, &span_list, node) { if ((s == new_master) || !can_provide_timing(s)) continue; new_master = s; break; } spin_unlock_irqrestore(&chan_lock, flags); if (master != new_master) { if (debug & DEBUG_MAIN) { module_printk(KERN_NOTICE, "%s: Span ('%s') is new master\n", __FUNCTION__, (new_master)? new_master->name: "no master"); } } master = new_master; return 0; } /** * dahdi_unregister() - unregister a DAHDI span * @span: the DAHDI span * * Unregisters a span that has been previously registered with * dahdi_register(). */ int dahdi_unregister(struct dahdi_span *span) { int ret; mutex_lock(®istration_mutex); ret = _dahdi_unregister(span); mutex_unlock(®istration_mutex); return ret; } /* ** This routine converts from linear to ulaw ** ** Craig Reese: IDA/Supercomputing Research Center ** Joe Campbell: Department of Defense ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) "A New Digital Technique for Implementation of Any ** Continuous PCM Companding Law," Villeret, Michel, ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, ** 1973, pg. 11.12-11.17 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: Signed 16 bit linear sample ** Output: 8 bit ulaw sample */ #define ZEROTRAP /* turn on the trap as per the MIL-STD */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 #ifdef CONFIG_CALC_XLAW unsigned char #else static unsigned char __init #endif __dahdi_lineartoulaw(short sample) { static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; int sign, exponent, mantissa; unsigned char ulawbyte; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if (sign != 0) sample = -sample; /* get magnitude */ if (sample > CLIP) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = sample + BIAS; exponent = exp_lut[(sample >> 7) & 0xFF]; mantissa = (sample >> (exponent + 3)) & 0x0F; ulawbyte = ~(sign | (exponent << 4) | mantissa); #ifdef ZEROTRAP if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ #endif if (ulawbyte == 0xff) ulawbyte = 0x7f; /* never return 0xff */ return(ulawbyte); } #define AMI_MASK 0x55 #ifdef CONFIG_CALC_XLAW unsigned char #else static inline unsigned char __init #endif __dahdi_lineartoalaw (short linear) { int mask; int seg; int pcm_val; static int seg_end[8] = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF }; pcm_val = linear; if (pcm_val >= 0) { /* Sign (7th) bit = 1 */ mask = AMI_MASK | 0x80; } else { /* Sign bit = 0 */ mask = AMI_MASK; pcm_val = -pcm_val; } /* Convert the scaled magnitude to segment number. */ for (seg = 0; seg < 8; seg++) { if (pcm_val <= seg_end[seg]) break; } /* Combine the sign, segment, and quantization bits. */ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; } /*- End of function --------------------------------------------------------*/ static inline short int __init alaw2linear (uint8_t alaw) { int i; int seg; alaw ^= AMI_MASK; i = ((alaw & 0x0F) << 4); seg = (((int) alaw & 0x70) >> 4); if (seg) i = (i + 0x100) << (seg - 1); return (short int) ((alaw & 0x80) ? i : -i); } /*- End of function --------------------------------------------------------*/ static void __init dahdi_conv_init(void) { int i; /* * Set up mu-law conversion table */ for(i = 0;i < 256;i++) { short mu,e,f,y; static short etab[]={0,132,396,924,1980,4092,8316,16764}; mu = 255-i; e = (mu & 0x70)/16; f = mu & 0x0f; y = f * (1 << (e + 3)); y += etab[e]; if (mu & 0x80) y = -y; __dahdi_mulaw[i] = y; __dahdi_alaw[i] = alaw2linear(i); /* Default (0.0 db) gain table */ defgain[i] = i; } #ifndef CONFIG_CALC_XLAW /* set up the reverse (mu-law) conversion table */ for(i = -32768; i < 32768; i += 4) { __dahdi_lin2mu[((unsigned short)(short)i) >> 2] = __dahdi_lineartoulaw(i); __dahdi_lin2a[((unsigned short)(short)i) >> 2] = __dahdi_lineartoalaw(i); } #endif } static inline void __dahdi_process_getaudio_chunk(struct dahdi_chan *ss, unsigned char *txb) { /* We transmit data from our master channel */ /* Called with ss->lock held */ struct dahdi_chan *ms = ss->master; /* Linear representation */ short getlin[DAHDI_CHUNKSIZE], k[DAHDI_CHUNKSIZE]; int x; /* Okay, now we've got something to transmit */ for (x=0;xec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_tx_detect) { for (x = 0; x < DAHDI_CHUNKSIZE; x++) { if (echo_can_disable_detector_update(&ms->ec_state->txecdis, getlin[x])) { set_echocan_fax_mode(ms, ss->channo, "CED tx detected", 1); dahdi_qevent_nolock(ms, DAHDI_EVENT_TX_CED_DETECTED); break; } } } #endif if ((!ms->confmute && !ms->dialing) || (is_pseudo_chan(ms))) { struct dahdi_chan *const conf_chan = ms->conf_chan; /* Handle conferencing on non-clear channel and non-HDLC channels */ switch(ms->confmode & DAHDI_CONF_MODE_MASK) { case DAHDI_CONF_NORMAL: /* Do nuffin */ break; case DAHDI_CONF_MONITOR: /* Monitor a channel's rx mode */ /* if a pseudo-channel, ignore */ if (is_pseudo_chan(ms)) break; /* Add monitored channel */ if (is_pseudo_chan(conf_chan)) ACSS(getlin, conf_chan->getlin); else ACSS(getlin, conf_chan->putlin); for (x=0;xputlin); else ACSS(getlin, conf_chan->getlin); for (x=0;xputlin); ACSS(getlin, conf_chan->getlin); for (x=0;xreadchunkpreec) break; /* Add monitored channel */ ACSS(getlin, is_pseudo_chan(conf_chan) ? conf_chan->readchunkpreec : conf_chan->putlin); for (x = 0; x < DAHDI_CHUNKSIZE; x++) txb[x] = DAHDI_LIN2X(getlin[x], ms); break; case DAHDI_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ /* if a pseudo-channel, ignore */ if (is_pseudo_chan(ms)) break; if (!conf_chan->readchunkpreec) break; /* Add monitored channel */ ACSS(getlin, is_pseudo_chan(conf_chan) ? conf_chan->putlin : conf_chan->readchunkpreec); for (x = 0; x < DAHDI_CHUNKSIZE; x++) txb[x] = DAHDI_LIN2X(getlin[x], ms); break; case DAHDI_CONF_MONITORBOTH_PREECHO: /* monitor a channel's rx and tx mode */ /* if a pseudo-channel, ignore */ if (is_pseudo_chan(ms)) break; if (!conf_chan->readchunkpreec) break; ACSS(getlin, conf_chan->putlin); ACSS(getlin, conf_chan->readchunkpreec); for (x = 0; x < DAHDI_CHUNKSIZE; x++) txb[x] = DAHDI_LIN2X(getlin[x], ms); break; case DAHDI_CONF_REALANDPSEUDO: /* This strange mode takes the transmit buffer and puts it on the conference, minus its last sample, then outputs from the conference minus the real channel's last sample. */ /* if to talk on conf */ if (ms->confmode & DAHDI_CONF_PSEUDO_TALKER) { /* Store temp value */ memcpy(k, getlin, DAHDI_CHUNKSIZE * sizeof(short)); /* Add conf value */ ACSS(k, conf_sums_next[ms->_confn]); /* save last one */ memcpy(ms->conflast2, ms->conflast1, DAHDI_CHUNKSIZE * sizeof(short)); memcpy(ms->conflast1, k, DAHDI_CHUNKSIZE * sizeof(short)); /* get amount actually added */ SCSS(ms->conflast1, conf_sums_next[ms->_confn]); /* Really add in new value */ ACSS(conf_sums_next[ms->_confn], ms->conflast1); } else { memset(ms->conflast1, 0, DAHDI_CHUNKSIZE * sizeof(short)); memset(ms->conflast2, 0, DAHDI_CHUNKSIZE * sizeof(short)); } memset(getlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); txb[0] = DAHDI_LIN2X(0, ms); memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); /* fall through to normal conf mode */ case DAHDI_CONF_CONF: /* Normal conference mode */ if (is_pseudo_chan(ms)) /* if pseudo-channel */ { /* if to talk on conf */ if (ms->confmode & DAHDI_CONF_TALKER) { /* Store temp value */ memcpy(k, getlin, DAHDI_CHUNKSIZE * sizeof(short)); /* Add conf value */ ACSS(k, conf_sums[ms->_confn]); /* get amount actually added */ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); SCSS(ms->conflast, conf_sums[ms->_confn]); /* Really add in new value */ ACSS(conf_sums[ms->_confn], ms->conflast); memcpy(ms->getlin, getlin, DAHDI_CHUNKSIZE * sizeof(short)); } else { memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); memcpy(getlin, ms->getlin, DAHDI_CHUNKSIZE * sizeof(short)); } txb[0] = DAHDI_LIN2X(0, ms); memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); break; } /* fall through */ case DAHDI_CONF_CONFMON: /* Conference monitor mode */ if (ms->confmode & DAHDI_CONF_LISTENER) { /* Subtract out last sample written to conf */ SCSS(getlin, ms->conflast); /* Add in conference */ ACSS(getlin, conf_sums[ms->_confn]); } for (x=0;x_confn], getlin); /* Start with silence */ memset(getlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); /* If a listener on the conf... */ if (ms->confmode & DAHDI_CONF_LISTENER) { /* Subtract last value written */ SCSS(getlin, ms->conflast); /* Add in conf */ ACSS(getlin, conf_sums[ms->_confn]); } for (x=0;xec_state) { for (x = 0; x < DAHDI_CHUNKSIZE; x++) txb[x] = DAHDI_LIN2X(conf_chan->getlin[x], ms); } else { memcpy(txb, conf_chan->getraw, DAHDI_CHUNKSIZE); } } else { if (ms->ec_state) { for (x = 0; x < DAHDI_CHUNKSIZE; x++) txb[x] = DAHDI_LIN2X(conf_chan->putlin[x], ms); } else { memcpy(txb, conf_chan->putraw, DAHDI_CHUNKSIZE); } } for (x = 0; x < DAHDI_CHUNKSIZE; x++) getlin[x] = DAHDI_XLAW(txb[x], ms); break; } } if (ms->confmute || (ms->ec_state && (ms->ec_state->status.mode) & __ECHO_MODE_MUTE)) { txb[0] = DAHDI_LIN2X(0, ms); memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_STARTTRAINING)) { /* Transmit impulse now */ txb[0] = DAHDI_LIN2X(16384, ms); ms->ec_state->status.mode = ECHO_MODE_AWAITINGECHO; } } /* save value from last chunk */ memcpy(ms->getlin_lastchunk, ms->getlin, DAHDI_CHUNKSIZE * sizeof(short)); /* save value from current */ memcpy(ms->getlin, getlin, DAHDI_CHUNKSIZE * sizeof(short)); /* save value from current */ memcpy(ms->getraw, txb, DAHDI_CHUNKSIZE); /* if to make tx tone */ if (ms->v1_1 || ms->v2_1 || ms->v3_1) { for (x=0;xtxgain[txb[x]]; } static void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int bytes); static inline void __dahdi_getbuf_chunk(struct dahdi_chan *ss, unsigned char *txb) { #ifdef CONFIG_DAHDI_MIRROR unsigned char *orig_txb = txb; #endif /* CONFIG_DAHDI_MIRROR */ /* Called with ss->lock held */ /* We transmit data from our master channel */ struct dahdi_chan *ms = ss->master; /* Buffer we're using */ unsigned char *buf; /* Old buffer number */ int oldbuf; /* Linear representation */ int getlin; /* How many bytes we need to process */ int bytes = DAHDI_CHUNKSIZE, left; bool needtxunderrun = false; int x; /* Let's pick something to transmit. First source to try is our write-out buffer. Always check it first because its our 'fast path' for whatever that's worth. */ while(bytes) { if ((ms->outwritebuf > -1) && !ms->txdisable) { buf= ms->writebuf[ms->outwritebuf]; left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf]; if (left > bytes) left = bytes; if (ms->flags & DAHDI_FLAG_HDLC) { /* If this is an HDLC channel we only send a byte of HDLC. */ for(x=0;xtxhdlc)) /* Load a byte of data only if needed */ fasthdlc_tx_load_nocheck(&ms->txhdlc, buf[ms->writeidx[ms->outwritebuf]++]); *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); } bytes -= left; } else { memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left); ms->writeidx[ms->outwritebuf]+=left; txb += left; bytes -= left; } /* Check buffer status */ if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) { /* We've reached the end of our buffer. Go to the next. */ oldbuf = ms->outwritebuf; /* Clear out write index and such */ ms->writeidx[oldbuf] = 0; ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs; if (!(ms->flags & DAHDI_FLAG_MTP2)) { ms->writen[oldbuf] = 0; if (ms->outwritebuf == ms->inwritebuf) { /* Whoopsies, we're run out of buffers. Mark ours as -1 and wait for the filler to notify us that there is something to write */ ms->outwritebuf = -1; if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ms->waitq); /* If we're only supposed to start when full, disable the transmitter */ if ((ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ms->txbufpolicy == DAHDI_POLICY_HALF_FULL)) ms->txdisable = 1; } } else { if (ms->outwritebuf == ms->inwritebuf) { ms->outwritebuf = oldbuf; if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ms->waitq); /* If we're only supposed to start when full, disable the transmitter */ if ((ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ms->txbufpolicy == DAHDI_POLICY_HALF_FULL)) ms->txdisable = 1; } } if (ms->inwritebuf < 0) { /* The filler doesn't have a place to put data. Now that we're done with this buffer, notify them. */ ms->inwritebuf = oldbuf; } /* In the very orignal driver, it was quite well known to me (Jim) that there was a possibility that a channel sleeping on a write block needed to be potentially woken up EVERY time a buffer was emptied, not just on the first one, because if only done on the first one there is a slight timing potential of missing the wakeup (between where it senses the (lack of) active condition (with interrupts disabled) and where it does the sleep (interrupts enabled) in the read or iomux call, etc). That is why the write and iomux calls start with an infinite loop that gets broken out of upon an active condition, otherwise keeps sleeping and looking. The part in this code got "optimized" out in the later versions, and is put back now. */ if (!(ms->flags & DAHDI_FLAG_PPP) || !dahdi_have_netdev(ms)) { wake_up_interruptible(&ms->waitq); } /* Transmit a flag if this is an HDLC channel */ if (ms->flags & DAHDI_FLAG_HDLC) fasthdlc_tx_frame_nocheck(&ms->txhdlc); #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(ms)) netif_wake_queue(chan_to_netdev(ms)); #endif #ifdef CONFIG_DAHDI_PPP if (ms->flags & DAHDI_FLAG_PPP) { ms->do_ppp_wakeup = 1; tasklet_schedule(&ms->ppp_calls); } #endif } } else if (ms->curtone && !is_pseudo_chan(ms)) { left = ms->curtone->tonesamples - ms->tonep; if (left > bytes) left = bytes; for (x=0;xts, ms->curtone); *(txb++) = DAHDI_LIN2X(getlin, ms); } ms->tonep+=left; bytes -= left; if (ms->tonep >= ms->curtone->tonesamples) { struct dahdi_tone *last; /* Go to the next sample of the tone */ ms->tonep = 0; last = ms->curtone; ms->curtone = ms->curtone->next; if (!ms->curtone) { /* No more tones... Is this dtmf or mf? If so, go to the next digit */ if (ms->dialing) __do_dtmf(ms); } else { if (last != ms->curtone) dahdi_init_tone_state(&ms->ts, ms->curtone); } } } else if (ms->flags & DAHDI_FLAG_LOOPED) { for (x = 0; x < bytes; x++) txb[x] = ms->readchunk[x]; bytes = 0; } else if (ms->flags & DAHDI_FLAG_HDLC) { for (x=0;xtxhdlc)) fasthdlc_tx_frame_nocheck(&ms->txhdlc); *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); } bytes = 0; } else if (ms->flags & DAHDI_FLAG_CLEAR) { /* Clear channels that are idle in audio mode need to send silence; in non-audio mode, always send 0xff so stupid switches won't consider the channel active */ if (ms->flags & DAHDI_FLAG_AUDIO) { memset(txb, DAHDI_LIN2X(0, ms), bytes); } else { memset(txb, 0xFF, bytes); } needtxunderrun += bytes; bytes = 0; } else { memset(txb, DAHDI_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */ needtxunderrun += bytes; bytes = 0; } } if (needtxunderrun) { if (!test_bit(DAHDI_FLAGBIT_TXUNDERRUN, &ms->flags)) { if (test_bit(DAHDI_FLAGBIT_BUFEVENTS, &ms->flags)) __qevent(ms, DAHDI_EVENT_WRITE_UNDERRUN); set_bit(DAHDI_FLAGBIT_TXUNDERRUN, &ms->flags); } } else { clear_bit(DAHDI_FLAGBIT_TXUNDERRUN, &ms->flags); } #ifdef CONFIG_DAHDI_MIRROR if (ss->txmirror) { spin_lock(&ss->txmirror->lock); __putbuf_chunk(ss->txmirror, orig_txb, DAHDI_CHUNKSIZE); spin_unlock(&ss->txmirror->lock); } #endif /* CONFIG_DAHDI_MIRROR */ } static inline void rbs_itimer_expire(struct dahdi_chan *chan) { /* the only way this could have gotten here, is if a channel went onf hook longer then the wink or flash detect timeout */ /* Called with chan->lock held */ switch(chan->sig) { case DAHDI_SIG_FXOLS: /* if FXO, its definitely on hook */ case DAHDI_SIG_FXOGS: case DAHDI_SIG_FXOKS: __qevent(chan,DAHDI_EVENT_ONHOOK); chan->gotgs = 0; break; #if defined(EMFLASH) || defined(EMPULSE) case DAHDI_SIG_EM: case DAHDI_SIG_EM_E1: if (chan->rxhooksig == DAHDI_RXSIG_ONHOOK) { __qevent(chan,DAHDI_EVENT_ONHOOK); break; } __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); break; #endif #ifdef FXSFLASH case DAHDI_SIG_FXSKS: if (chan->rxhooksig == DAHDI_RXSIG_ONHOOK) { __qevent(chan, DAHDI_EVENT_ONHOOK); break; } #endif /* fall thru intentionally */ default: /* otherwise, its definitely off hook */ __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); break; } } static inline void __rbs_otimer_expire(struct dahdi_chan *chan) { int len = 0; /* Called with chan->lock held */ chan->otimer = 0; /* Move to the next timer state */ switch(chan->txstate) { case DAHDI_TXSTATE_RINGOFF: /* Turn on the ringer now that the silent time has passed */ ++chan->cadencepos; if (chan->cadencepos >= DAHDI_MAX_CADENCE) chan->cadencepos = chan->firstcadencepos; len = chan->ringcadence[chan->cadencepos]; if (!len) { chan->cadencepos = chan->firstcadencepos; len = chan->ringcadence[chan->cadencepos]; } dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_RINGON, len); __qevent(chan, DAHDI_EVENT_RINGERON); break; case DAHDI_TXSTATE_RINGON: /* Turn off the ringer now that the loud time has passed */ ++chan->cadencepos; if (chan->cadencepos >= DAHDI_MAX_CADENCE) chan->cadencepos = 0; len = chan->ringcadence[chan->cadencepos]; if (!len) { chan->cadencepos = 0; len = chan->curzone->ringcadence[chan->cadencepos]; } dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_RINGOFF, len); __qevent(chan, DAHDI_EVENT_RINGEROFF); break; case DAHDI_TXSTATE_START: /* If we were starting, go off hook now ready to debounce */ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_AFTERSTART, DAHDI_AFTERSTART_TIME); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_PREWINK: /* Actually wink */ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_WINK, chan->winktime); break; case DAHDI_TXSTATE_WINK: /* Wink complete, go on hook and stabalize */ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); if (chan->file && (chan->file->f_flags & O_NONBLOCK)) __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_PREFLASH: /* Actually flash */ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_FLASH, chan->flashtime); break; case DAHDI_TXSTATE_FLASH: dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); if (chan->file && (chan->file->f_flags & O_NONBLOCK)) __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_DEBOUNCE: dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); /* See if we've gone back on hook */ if ((chan->rxhooksig == DAHDI_RXSIG_ONHOOK) && (chan->rxflashtime > 2)) chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_AFTERSTART: dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); if (chan->file && (chan->file->f_flags & O_NONBLOCK)) __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_KEWL: dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_AFTERKEWL, DAHDI_AFTERKEWLTIME); if (chan->file && (chan->file->f_flags & O_NONBLOCK)) __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_AFTERKEWL: if (chan->kewlonhook) { __qevent(chan,DAHDI_EVENT_ONHOOK); } chan->txstate = DAHDI_TXSTATE_ONHOOK; chan->gotgs = 0; break; case DAHDI_TXSTATE_PULSEBREAK: dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_PULSEMAKE, chan->pulsemaketime); wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_PULSEMAKE: if (chan->pdialcount) chan->pdialcount--; if (chan->pdialcount) { dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_PULSEBREAK, chan->pulsebreaktime); break; } chan->txstate = DAHDI_TXSTATE_PULSEAFTER; chan->otimer = chan->pulseaftertime * DAHDI_CHUNKSIZE; wake_up_interruptible(&chan->waitq); break; case DAHDI_TXSTATE_PULSEAFTER: chan->txstate = DAHDI_TXSTATE_OFFHOOK; __do_dtmf(chan); wake_up_interruptible(&chan->waitq); break; default: break; } } static void __dahdi_hooksig_pvt(struct dahdi_chan *chan, enum dahdi_rxsig rxsig) { /* State machines for receive hookstate transitions called with chan->lock held */ if ((chan->rxhooksig) == rxsig) return; if ((chan->flags & DAHDI_FLAG_SIGFREEZE)) return; chan->rxhooksig = rxsig; #ifdef RINGBEGIN if ((chan->sig & __DAHDI_SIG_FXS) && (rxsig == DAHDI_RXSIG_RING) && (!chan->ringdebtimer)) __qevent(chan,DAHDI_EVENT_RINGBEGIN); #endif switch(chan->sig) { case DAHDI_SIG_EM: /* E and M */ case DAHDI_SIG_EM_E1: switch(rxsig) { case DAHDI_RXSIG_OFFHOOK: /* went off hook */ /* The interface is going off hook */ #ifdef EMFLASH if (chan->itimer) { __qevent(chan,DAHDI_EVENT_WINKFLASH); chan->itimerset = chan->itimer = 0; break; } #endif #ifdef EMPULSE if (chan->itimer) /* if timer still running */ { int plen = chan->itimerset - chan->itimer; if (plen <= DAHDI_MAXPULSETIME) { if (plen >= DAHDI_MINPULSETIME) { chan->pulsecount++; chan->pulsetimer = DAHDI_PULSETIMEOUT; chan->itimerset = chan->itimer = 0; if (chan->pulsecount == 1) __qevent(chan,DAHDI_EVENT_PULSE_START); } } break; } #endif /* set wink timer */ chan->itimerset = chan->itimer = chan->rxwinktime * DAHDI_CHUNKSIZE; break; case DAHDI_RXSIG_ONHOOK: /* went on hook */ /* This interface is now going on hook. Check for WINK, etc */ if (chan->itimer) __qevent(chan,DAHDI_EVENT_WINKFLASH); #if defined(EMFLASH) || defined(EMPULSE) else { #ifdef EMFLASH chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; #else /* EMFLASH */ chan->itimerset = chan->itimer = chan->rxwinktime * DAHDI_CHUNKSIZE; #endif /* EMFLASH */ chan->gotgs = 0; break; } #else /* EMFLASH || EMPULSE */ else { __qevent(chan,DAHDI_EVENT_ONHOOK); chan->gotgs = 0; } #endif chan->itimerset = chan->itimer = 0; break; default: break; } break; case DAHDI_SIG_FXSKS: /* FXS Kewlstart */ /* ignore a bit error if loop not closed and stable */ if (chan->txstate != DAHDI_TXSTATE_OFFHOOK) break; #ifdef FXSFLASH if (rxsig == DAHDI_RXSIG_ONHOOK) { chan->itimer = DAHDI_FXSFLASHMAXTIME * DAHDI_CHUNKSIZE; break; } else if (rxsig == DAHDI_RXSIG_OFFHOOK) { if (chan->itimer) { /* did the offhook occur in the window? if not, ignore both events */ if (chan->itimer <= ((DAHDI_FXSFLASHMAXTIME - DAHDI_FXSFLASHMINTIME) * DAHDI_CHUNKSIZE)) __qevent(chan, DAHDI_EVENT_WINKFLASH); } chan->itimer = 0; break; } #endif /* fall through intentionally */ case DAHDI_SIG_FXSGS: /* FXS Groundstart */ if (rxsig == DAHDI_RXSIG_ONHOOK) { chan->ringdebtimer = RING_DEBOUNCE_TIME; chan->ringtrailer = 0; if (chan->txstate != DAHDI_TXSTATE_DEBOUNCE) { chan->gotgs = 0; __qevent(chan,DAHDI_EVENT_ONHOOK); } } break; case DAHDI_SIG_FXOGS: /* FXO Groundstart */ if (rxsig == DAHDI_RXSIG_START) { /* if havent got gs, report it */ if (!chan->gotgs) { __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); chan->gotgs = 1; } } /* fall through intentionally */ case DAHDI_SIG_FXOLS: /* FXO Loopstart */ case DAHDI_SIG_FXOKS: /* FXO Kewlstart */ switch(rxsig) { case DAHDI_RXSIG_OFFHOOK: /* went off hook */ /* if asserti ng ring, stop it */ if (chan->txstate == DAHDI_TXSTATE_START) { dahdi_rbs_sethook(chan,DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_AFTERSTART, DAHDI_AFTERSTART_TIME); } chan->kewlonhook = 0; #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Off hook on channel %d, itimer = %d, gotgs = %d\n", chan->channo, chan->itimer, chan->gotgs); #endif if (chan->itimer) /* if timer still running */ { int plen = chan->itimerset - chan->itimer; if (plen <= DAHDI_MAXPULSETIME) { if (plen >= DAHDI_MINPULSETIME) { chan->pulsecount++; chan->pulsetimer = DAHDI_PULSETIMEOUT; chan->itimer = chan->itimerset; if (chan->pulsecount == 1) __qevent(chan,DAHDI_EVENT_PULSE_START); } } else __qevent(chan,DAHDI_EVENT_WINKFLASH); } else { /* if havent got GS detect */ if (!chan->gotgs) { __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); chan->gotgs = 1; chan->itimerset = chan->itimer = 0; } } chan->itimerset = chan->itimer = 0; break; case DAHDI_RXSIG_ONHOOK: /* went on hook */ /* if not during offhook debounce time */ if ((chan->txstate != DAHDI_TXSTATE_DEBOUNCE) && (chan->txstate != DAHDI_TXSTATE_KEWL) && (chan->txstate != DAHDI_TXSTATE_AFTERKEWL)) { chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; } if (chan->txstate == DAHDI_TXSTATE_KEWL) chan->kewlonhook = 1; break; default: break; } default: break; } } /** * dahdi_hooksig() - send a signal on a channel to userspace * @chan: the DAHDI channel * @rxsig: signal (number) to send * * Called from a channel driver to send a DAHDI signal to userspace. * The signal will be queued for delivery to userspace. * * If the signal is the same as previous one sent, it won't be re-sent. */ void dahdi_hooksig(struct dahdi_chan *chan, enum dahdi_rxsig rxsig) { /* skip if no change */ unsigned long flags; spin_lock_irqsave(&chan->lock, flags); __dahdi_hooksig_pvt(chan,rxsig); spin_unlock_irqrestore(&chan->lock, flags); } /** * dahdi_rbsbits() - set Rx RBS bits on the channel * @chan: the DAHDI channel * @cursig: the bits to set * * Set the channel's rxsig (received: from device to userspace) and act * accordingly. */ void dahdi_rbsbits(struct dahdi_chan *chan, int cursig) { unsigned long flags; if (cursig == chan->rxsig) return; if ((chan->flags & DAHDI_FLAG_SIGFREEZE)) return; spin_lock_irqsave(&chan->lock, flags); switch(chan->sig) { case DAHDI_SIG_FXOGS: /* FXO Groundstart */ /* B-bit only matters for FXO GS */ if (!(cursig & DAHDI_BBIT)) { __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_START); break; } /* Fall through */ case DAHDI_SIG_EM: /* E and M */ case DAHDI_SIG_EM_E1: case DAHDI_SIG_FXOLS: /* FXO Loopstart */ case DAHDI_SIG_FXOKS: /* FXO Kewlstart */ if (cursig & DAHDI_ABIT) /* off hook */ __dahdi_hooksig_pvt(chan,DAHDI_RXSIG_OFFHOOK); else /* on hook */ __dahdi_hooksig_pvt(chan,DAHDI_RXSIG_ONHOOK); break; case DAHDI_SIG_FXSKS: /* FXS Kewlstart */ case DAHDI_SIG_FXSGS: /* FXS Groundstart */ /* Fall through */ case DAHDI_SIG_FXSLS: if (!(cursig & DAHDI_BBIT)) { /* Check for ringing first */ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_RING); break; } if ((chan->sig != DAHDI_SIG_FXSLS) && (cursig & DAHDI_ABIT)) { /* if went on hook */ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_ONHOOK); } else { __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_OFFHOOK); } break; case DAHDI_SIG_CAS: /* send event that something changed */ __qevent(chan, DAHDI_EVENT_BITSCHANGED); break; default: break; } /* Keep track of signalling for next time */ chan->rxsig = cursig; spin_unlock_irqrestore(&chan->lock, flags); if ((debug & DEBUG_RBS) && printk_ratelimit()) { chan_notice(chan, "Detected sigbits change to %04x\n", cursig); } } static void process_echocan_events(struct dahdi_chan *chan) { union dahdi_echocan_events events = chan->ec_state->events; if (events.bit.CED_tx_detected) { dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CED_DETECTED); if (chan->ec_state) { if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) set_echocan_fax_mode(chan, chan->channo, "CED tx detected", 1); else module_printk(KERN_NOTICE, "Detected CED tone (tx) on channel %d\n", chan->channo); } } if (events.bit.CED_rx_detected) { dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CED_DETECTED); if (chan->ec_state) { if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) set_echocan_fax_mode(chan, chan->channo, "CED rx detected", 1); else module_printk(KERN_NOTICE, "Detected CED tone (rx) on channel %d\n", chan->channo); } } if (events.bit.CNG_tx_detected) dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CNG_DETECTED); if (events.bit.CNG_rx_detected) dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CNG_DETECTED); if (events.bit.NLP_auto_disabled) { dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED); chan->ec_state->status.mode = ECHO_MODE_FAX; } if (events.bit.NLP_auto_enabled) { dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED); chan->ec_state->status.mode = ECHO_MODE_ACTIVE; } } /** * __dahdi_ec_chunk() - process echo for a single channel * @ss: DAHDI channel * @rxchunk: buffer to store audio with cancelled audio * @preecchunk: chunk of audio on which to cancel echo * @txchunk: reference chunk from the other direction * * The echo canceller function fixes received (from device to userspace) * audio. In order to fix it it uses the transmitted audio as a * reference. This call updates the echo canceller for a single chunk (8 * bytes). * * Call with local interrupts disabled. */ void __dahdi_ec_chunk(struct dahdi_chan *ss, u8 *rxchunk, const u8 *preecchunk, const u8 *txchunk) { short rxlin; int x; spin_lock(&ss->lock); if (ss->readchunkpreec) { /* Save a copy of the audio before the echo can has its way with it */ for (x = 0; x < DAHDI_CHUNKSIZE; x++) /* We only ever really need to deal with signed linear - let's just convert it now */ ss->readchunkpreec[x] = DAHDI_XLAW(preecchunk[x], ss); } /* Perform echo cancellation on a chunk if necessary */ if (ss->ec_state) { #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) dahdi_kernel_fpu_begin(); #endif if (ss->ec_state->status.mode & __ECHO_MODE_MUTE) { /* Special stuff for training the echo can */ for (x=0;xec_state->status.mode == ECHO_MODE_PRETRAINING) { if (--ss->ec_state->status.pretrain_timer <= 0) { ss->ec_state->status.pretrain_timer = 0; ss->ec_state->status.mode = ECHO_MODE_STARTTRAINING; } } if (ss->ec_state->status.mode == ECHO_MODE_AWAITINGECHO) { ss->ec_state->status.last_train_tap = 0; ss->ec_state->status.mode = ECHO_MODE_TRAINING; } if ((ss->ec_state->status.mode == ECHO_MODE_TRAINING) && (ss->ec_state->ops->echocan_traintap)) { if (ss->ec_state->ops->echocan_traintap(ss->ec_state, ss->ec_state->status.last_train_tap++, rxlin)) { ss->ec_state->status.mode = ECHO_MODE_ACTIVE; } } rxlin = 0; rxchunk[x] = DAHDI_LIN2X((int)rxlin, ss); } } else if (ss->ec_state->status.mode != ECHO_MODE_IDLE) { ss->ec_state->events.all = 0; if (ss->ec_state->ops->echocan_process) { short rxlins[DAHDI_CHUNKSIZE], txlins[DAHDI_CHUNKSIZE]; for (x = 0; x < DAHDI_CHUNKSIZE; x++) { rxlins[x] = DAHDI_XLAW(preecchunk[x], ss); txlins[x] = DAHDI_XLAW(txchunk[x], ss); } ss->ec_state->ops->echocan_process(ss->ec_state, rxlins, txlins, DAHDI_CHUNKSIZE); for (x = 0; x < DAHDI_CHUNKSIZE; x++) rxchunk[x] = DAHDI_LIN2X((int) rxlins[x], ss); } else if (ss->ec_state->ops->echocan_events) ss->ec_state->ops->echocan_events(ss->ec_state); if (ss->ec_state->events.all) process_echocan_events(ss); } #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) dahdi_kernel_fpu_end(); #endif } spin_unlock(&ss->lock); } EXPORT_SYMBOL(__dahdi_ec_chunk); /** * dahdi_ec_span() - process echo for all channels in a span. * @span: DAHDI span * * Similar to calling dahdi_ec_chunk() for each of the channels in the * span. Uses dahdi_chunk.write_chunk for the rxchunk (the chunk to fix) * and dahdi_chan.readchunk as the txchunk (the reference chunk). */ void _dahdi_ec_span(struct dahdi_span *span) { int x; for (x = 0; x < span->channels; x++) { struct dahdi_chan *const chan = span->chans[x]; if (!chan->ec_current) continue; _dahdi_ec_chunk(chan, chan->readchunk, chan->writechunk); } } EXPORT_SYMBOL(_dahdi_ec_span); /* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */ /* modifies buffer pointed to by 'amp' with notched-out values */ static inline int sf_detect(struct sf_detect_state *s, short *amp, int samples,long p1, long p2, long p3) { int i,rv = 0; long x,y; #define SF_DETECT_SAMPLES (DAHDI_CHUNKSIZE * 5) #define SF_DETECT_MIN_ENERGY 500 #define NB 14 /* number of bits to shift left */ /* determine energy level before filtering */ for(i = 0; i < samples; i++) { if (amp[i] < 0) s->e1 -= amp[i]; else s->e1 += amp[i]; } /* do 2nd order IIR notch filter at given freq. and calculate energy */ for(i = 0; i < samples; i++) { x = amp[i] << NB; y = s->x2 + (p1 * (s->x1 >> NB)) + x; y += (p2 * (s->y2 >> NB)) + (p3 * (s->y1 >> NB)); s->x2 = s->x1; s->x1 = x; s->y2 = s->y1; s->y1 = y; amp[i] = y >> NB; if (amp[i] < 0) s->e2 -= amp[i]; else s->e2 += amp[i]; } s->samps += i; /* if time to do determination */ if ((s->samps) >= SF_DETECT_SAMPLES) { rv = 1; /* default to no tone */ /* if enough energy, it is determined to be a tone */ if (((s->e1 - s->e2) / s->samps) > SF_DETECT_MIN_ENERGY) rv = 2; /* reset energy processing variables */ s->samps = 0; s->e1 = s->e2 = 0; } return(rv); } static inline void __dahdi_process_putaudio_chunk(struct dahdi_chan *ss, unsigned char *rxb) { /* We transmit data from our master channel */ /* Called with ss->lock held */ struct dahdi_chan *ms = ss->master; /* Linear version of received data */ short putlin[DAHDI_CHUNKSIZE],k[DAHDI_CHUNKSIZE]; int x,r; if (ms->dialing) ms->afterdialingtimer = 50; else if (ms->afterdialingtimer) ms->afterdialingtimer--; if (ms->afterdialingtimer && !is_pseudo_chan(ms)) { /* Be careful since memset is likely a macro */ rxb[0] = DAHDI_LIN2X(0, ms); memset(&rxb[1], rxb[0], DAHDI_CHUNKSIZE - 1); /* receive as silence if dialing */ } for (x=0;xrxgain[rxb[x]]; putlin[x] = DAHDI_XLAW(rxb[x], ms); } #ifndef CONFIG_DAHDI_NO_ECHOCAN_DISABLE if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_rx_detect) { for (x = 0; x < DAHDI_CHUNKSIZE; x++) { if (echo_can_disable_detector_update(&ms->ec_state->rxecdis, putlin[x])) { set_echocan_fax_mode(ms, ss->channo, "CED rx detected", 1); dahdi_qevent_nolock(ms, DAHDI_EVENT_RX_CED_DETECTED); break; } } } #endif /* if doing rx tone decoding */ if (ms->rxp1 && ms->rxp2 && ms->rxp3) { r = sf_detect(&ms->rd,putlin,DAHDI_CHUNKSIZE,ms->rxp1, ms->rxp2,ms->rxp3); /* Convert back */ for(x=0;xrd.lastdetect) { if (((r == 2) && !(ms->toneflags & DAHDI_REVERSE_RXTONE)) || ((r == 1) && (ms->toneflags & DAHDI_REVERSE_RXTONE))) { __qevent(ms,DAHDI_EVENT_RINGOFFHOOK); } else { __qevent(ms,DAHDI_EVENT_ONHOOK); } ms->rd.lastdetect = r; } } } if (!is_pseudo_chan(ms)) { memcpy(ms->putlin, putlin, DAHDI_CHUNKSIZE * sizeof(short)); memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE); } /* Take the rxc, twiddle it for conferencing if appropriate and put it back */ if ((!ms->confmute && !ms->afterdialingtimer) || is_pseudo_chan(ms)) { struct dahdi_chan *const conf_chan = ms->conf_chan; switch(ms->confmode & DAHDI_CONF_MODE_MASK) { case DAHDI_CONF_NORMAL: /* Normal mode */ /* Do nothing. rx goes output */ break; case DAHDI_CONF_MONITOR: /* Monitor a channel's rx mode */ /* if not a pseudo-channel, ignore */ if (!is_pseudo_chan(ms)) break; /* Add monitored channel */ if (is_pseudo_chan(conf_chan)) ACSS(putlin, conf_chan->getlin); else ACSS(putlin, conf_chan->putlin); /* Convert back */ for(x=0;xputlin); else ACSS(putlin, conf_chan->getlin); /* Convert back */ for(x=0;xgetlin); ACSS(putlin, conf_chan->putlin); /* Convert back */ for(x=0;xreadchunkpreec) break; /* Add monitored channel */ ACSS(putlin, is_pseudo_chan(conf_chan) ? conf_chan->getlin : conf_chan->readchunkpreec); for (x = 0; x < DAHDI_CHUNKSIZE; x++) rxb[x] = DAHDI_LIN2X(putlin[x], ms); break; case DAHDI_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ /* if not a pseudo-channel, ignore */ if (!is_pseudo_chan(ms)) break; if (!conf_chan->readchunkpreec) break; /* Add monitored channel */ ACSS(putlin, is_pseudo_chan(conf_chan) ? conf_chan->readchunkpreec : conf_chan->getlin); for (x = 0; x < DAHDI_CHUNKSIZE; x++) rxb[x] = DAHDI_LIN2X(putlin[x], ms); break; case DAHDI_CONF_MONITORBOTH_PREECHO: /* Monitor a channel's tx and rx mode */ /* if not a pseudo-channel, ignore */ if (!is_pseudo_chan(ms)) break; if (!conf_chan->readchunkpreec) break; /* Note: Technically, saturation should be done at the end of the whole addition, but for performance reasons, we don't do that. Besides, it only matters when you're so loud you're clipping anyway */ ACSS(putlin, conf_chan->getlin); ACSS(putlin, conf_chan->readchunkpreec); for (x = 0; x < DAHDI_CHUNKSIZE; x++) rxb[x] = DAHDI_LIN2X(putlin[x], ms); break; case DAHDI_CONF_REALANDPSEUDO: /* do normal conf mode processing */ if (ms->confmode & DAHDI_CONF_TALKER) { /* Store temp value */ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); /* Add conf value */ ACSS(k, conf_sums_next[ms->_confn]); /* get amount actually added */ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); SCSS(ms->conflast, conf_sums_next[ms->_confn]); /* Really add in new value */ ACSS(conf_sums_next[ms->_confn], ms->conflast); } else memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); /* do the pseudo-channel part processing */ memset(putlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); if (ms->confmode & DAHDI_CONF_PSEUDO_LISTENER) { /* Subtract out previous last sample written to conf */ SCSS(putlin, ms->conflast2); /* Add in conference */ ACSS(putlin, conf_sums[ms->_confn]); } /* Convert back */ for(x=0;xconfmode & DAHDI_CONF_LISTENER) { /* Subtract out last sample written to conf */ SCSS(putlin, ms->conflast); /* Add in conference */ ACSS(putlin, conf_sums[ms->_confn]); } /* Convert back */ for(x=0;xputlin, putlin, DAHDI_CHUNKSIZE * sizeof(short)); break; } /* fall through */ case DAHDI_CONF_CONFANN: /* Conference with announce */ if (ms->confmode & DAHDI_CONF_TALKER) { /* Store temp value */ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); /* Add conf value */ ACSS(k, conf_sums_next[ms->_confn]); /* get amount actually added */ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); SCSS(ms->conflast, conf_sums_next[ms->_confn]); /* Really add in new value */ ACSS(conf_sums_next[ms->_confn], ms->conflast); } else memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); /* rxc unmodified */ break; case DAHDI_CONF_CONFMON: case DAHDI_CONF_CONFANNMON: if (ms->confmode & DAHDI_CONF_TALKER) { /* Store temp value */ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); /* Subtract last value */ SCSS(conf_sums[ms->_confn], ms->conflast); /* Add conf value */ ACSS(k, conf_sums[ms->_confn]); /* get amount actually added */ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); SCSS(ms->conflast, conf_sums[ms->_confn]); /* Really add in new value */ ACSS(conf_sums[ms->_confn], ms->conflast); } else memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); for (x=0;x_confn][x], ms); break; case DAHDI_CONF_DIGITALMON: /* if not a pseudo-channel, ignore */ if (!is_pseudo_chan(ms)) break; /* Add monitored channel */ if (is_pseudo_chan(conf_chan)) memcpy(rxb, conf_chan->getraw, DAHDI_CHUNKSIZE); else memcpy(rxb, conf_chan->putraw, DAHDI_CHUNKSIZE); break; } } } /* HDLC (or other) receiver buffer functions for read side */ static void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int bytes) { /* We transmit data from our master channel */ /* Called with ss->lock held */ struct dahdi_chan *ms = ss->master; /* Our receive buffer */ unsigned char *buf; #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) /* SKB for receiving network stuff */ struct sk_buff *skb=NULL; #endif int oldbuf; int eof=0; int abort=0; int res; int left, x; while(bytes) { #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) skb = NULL; #endif abort = 0; eof = 0; /* Next, figure out if we've got a buffer to receive into */ if (ms->inreadbuf > -1) { /* Read into the current buffer */ buf = ms->readbuf[ms->inreadbuf]; left = ms->blocksize - ms->readidx[ms->inreadbuf]; if (left > bytes) left = bytes; if (ms->flags & DAHDI_FLAG_HDLC) { for (x=0;xrxhdlc, *(rxb++)); bytes--; res = fasthdlc_rx_run(&ms->rxhdlc); /* If there is nothing there, continue */ if (res & RETURN_EMPTY_FLAG) continue; else if (res & RETURN_COMPLETE_FLAG) { /* Only count this if it's a non-empty frame */ if (ms->readidx[ms->inreadbuf]) { if ((ms->flags & DAHDI_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) { abort = DAHDI_EVENT_BADFCS; } else eof=1; break; } continue; } else if (res & RETURN_DISCARD_FLAG) { /* This could be someone idling with "idle" instead of "flag" */ if (!ms->readidx[ms->inreadbuf]) continue; abort = DAHDI_EVENT_ABORT; break; } else { unsigned char rxc; rxc = res; ms->infcs = PPP_FCS(ms->infcs, rxc); buf[ms->readidx[ms->inreadbuf]++] = rxc; /* Pay attention to the possibility of an overrun */ if (ms->readidx[ms->inreadbuf] >= ms->blocksize) { if (!ss->span->alarms) module_printk(KERN_WARNING, "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name); abort=DAHDI_EVENT_OVERRUN; /* Force the HDLC state back to frame-search mode */ ms->rxhdlc.state = 0; ms->rxhdlc.bits = 0; ms->readidx[ms->inreadbuf]=0; break; } } } } else { /* Not HDLC */ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left); rxb += left; ms->readidx[ms->inreadbuf] += left; bytes -= left; /* End of frame is decided by block size of 'N' */ eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize); if (eof && (ss->flags & DAHDI_FLAG_NOSTDTXRX)) { eof = 0; abort = DAHDI_EVENT_OVERRUN; } } if (eof) { /* Finished with this buffer, try another. */ oldbuf = ms->inreadbuf; ms->infcs = PPP_INITFCS; ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf]; #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "EOF, len is %d\n", ms->readn[ms->inreadbuf]); #endif #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) if ((ms->flags & DAHDI_FLAG_PPP) || dahdi_have_netdev(ms)) { #ifdef CONFIG_DAHDI_NET #endif /* CONFIG_DAHDI_NET */ /* Our network receiver logic is MUCH different. We actually only use a single buffer */ if (ms->readn[ms->inreadbuf] > 1) { /* Drop the FCS */ ms->readn[ms->inreadbuf] -= 2; /* Allocate an SKB */ #ifdef CONFIG_DAHDI_PPP if (!ms->do_ppp_error) #endif skb = dev_alloc_skb(ms->readn[ms->inreadbuf] + 2); if (skb) { unsigned char cisco_addr = *(ms->readbuf[ms->inreadbuf]); if (cisco_addr != 0x0f && cisco_addr != 0x8f) skb_reserve(skb, 2); /* XXX Get rid of this memcpy XXX */ memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]); skb_put(skb, ms->readn[ms->inreadbuf]); #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(ms)) { struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); stats->rx_packets++; stats->rx_bytes += ms->readn[ms->inreadbuf]; } #endif } else { #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(ms)) { struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); stats->rx_dropped++; } #endif #ifdef CONFIG_DAHDI_PPP if (ms->flags & DAHDI_FLAG_PPP) { abort = DAHDI_EVENT_OVERRUN; } #endif #if 1 #ifdef CONFIG_DAHDI_PPP if (!ms->do_ppp_error) #endif module_printk(KERN_NOTICE, "Memory squeeze, dropped one\n"); #endif } } /* We don't cycle through buffers, just reuse the same one */ ms->readn[ms->inreadbuf] = 0; ms->readidx[ms->inreadbuf] = 0; } else #endif { /* This logic might confuse and astound. Basically we need to find * the previous buffer index. It should be safe because, regardless * of whether or not it has been copied to user space, nothing should * have messed around with it since then */ int comparemessage; /* Shut compiler up */ int myres = 0; if (ms->flags & DAHDI_FLAG_MTP2) { comparemessage = (ms->inreadbuf - 1) & (ms->numbufs - 1); myres = memcmp(ms->readbuf[comparemessage], ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]); } if ((ms->flags & DAHDI_FLAG_MTP2) && !myres) { /* Our messages are the same, so discard - * Don't advance buffers, reset indexes and buffer sizes. */ ms->readn[ms->inreadbuf] = 0; ms->readidx[ms->inreadbuf] = 0; } else { ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs; if (ms->inreadbuf == ms->outreadbuf) { /* Whoops, we're full, and have no where else to store into at the moment. We'll drop it until there's a buffer available */ #ifdef BUFFER_DEBUG module_printk(KERN_NOTICE, "Out of storage space\n"); #endif ms->inreadbuf = -1; /* Enable the receiver in case they've got POLICY_WHEN_FULL */ ms->rxdisable = 0; } if (ms->outreadbuf < 0) { /* start out buffer if not already */ ms->outreadbuf = oldbuf; /* if there are processes waiting in poll() on this channel, wake them up */ if (!ms->rxdisable) { wake_up_interruptible(&ms->waitq); } } /* In the very orignal driver, it was quite well known to me (Jim) that there was a possibility that a channel sleeping on a receive block needed to be potentially woken up EVERY time a buffer was filled, not just on the first one, because if only done on the first one there is a slight timing potential of missing the wakeup (between where it senses the (lack of) active condition (with interrupts disabled) and where it does the sleep (interrupts enabled) in the read or iomux call, etc). That is why the read and iomux calls start with an infinite loop that gets broken out of upon an active condition, otherwise keeps sleeping and looking. The part in this code got "optimized" out in the later versions, and is put back now. Note that this is *NOT* needed for poll() waiters, because the poll_wait() function that is used there is atomic enough for this purpose; it will not go to sleep before ensuring that the waitqueue is empty. */ if (!ms->rxdisable) { /* if receiver enabled */ /* Notify a blocked reader that there is data available to be read, unless we're waiting for it to be full */ #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Notifying reader data in block %d\n", oldbuf); #endif wake_up_interruptible(&ms->waitq); } } } } if (abort) { /* Start over reading frame */ ms->readidx[ms->inreadbuf] = 0; ms->infcs = PPP_INITFCS; #ifdef CONFIG_DAHDI_NET if (dahdi_have_netdev(ms)) { struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); stats->rx_errors++; if (abort == DAHDI_EVENT_OVERRUN) stats->rx_over_errors++; if (abort == DAHDI_EVENT_BADFCS) stats->rx_crc_errors++; if (abort == DAHDI_EVENT_ABORT) stats->rx_frame_errors++; } else #endif #ifdef CONFIG_DAHDI_PPP if (ms->flags & DAHDI_FLAG_PPP) { ms->do_ppp_error = 1; tasklet_schedule(&ms->ppp_calls); } else #endif if (test_bit(DAHDI_FLAGBIT_OPEN, &ms->flags) && !ss->span->alarms) { /* Notify the receiver... */ __qevent(ss->master, abort); } } } else /* No place to receive -- drop on the floor */ break; #ifdef CONFIG_DAHDI_NET if (skb && dahdi_have_netdev(ms)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) skb->mac.raw = skb->data; #else skb_reset_mac_header(skb); #endif skb->dev = chan_to_netdev(ms); #ifdef DAHDI_HDLC_TYPE_TRANS skb->protocol = hdlc_type_trans(skb, chan_to_netdev(ms)); #else skb->protocol = htons (ETH_P_HDLC); #endif netif_rx(skb); } #endif #ifdef CONFIG_DAHDI_PPP if (skb && (ms->flags & DAHDI_FLAG_PPP)) { unsigned char *tmp; tmp = skb->data; skb_pull(skb, 2); /* Make sure that it's addressed to ALL STATIONS and UNNUMBERED */ if (!tmp || (tmp[0] != 0xff) || (tmp[1] != 0x03)) { /* Invalid SKB -- drop */ if (tmp) module_printk(KERN_NOTICE, "Received invalid SKB (%02x, %02x)\n", tmp[0], tmp[1]); dev_kfree_skb_irq(skb); } else { skb_queue_tail(&ms->ppp_rq, skb); tasklet_schedule(&ms->ppp_calls); } } #endif } if (bytes) { if (!test_bit(DAHDI_FLAGBIT_RXOVERRUN, &ms->flags)) { if (test_bit(DAHDI_FLAGBIT_BUFEVENTS, &ms->flags)) __qevent(ms, DAHDI_EVENT_READ_OVERRUN); set_bit(DAHDI_FLAGBIT_RXOVERRUN, &ms->flags); } } else { clear_bit(DAHDI_FLAGBIT_RXOVERRUN, &ms->flags); } } static inline void __dahdi_putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb) { __putbuf_chunk(ss, rxb, DAHDI_CHUNKSIZE); #ifdef CONFIG_DAHDI_MIRROR if (ss->rxmirror) { spin_lock(&ss->rxmirror->lock); __putbuf_chunk(ss->rxmirror, rxb, DAHDI_CHUNKSIZE); spin_unlock(&ss->rxmirror->lock); } #endif /* CONFIG_DAHDI_MIRROR */ } static void __dahdi_hdlc_abort(struct dahdi_chan *ss, int event) { if (ss->inreadbuf >= 0) ss->readidx[ss->inreadbuf] = 0; if (test_bit(DAHDI_FLAGBIT_OPEN, &ss->flags) && !ss->span->alarms) __qevent(ss->master, event); } void dahdi_hdlc_abort(struct dahdi_chan *ss, int event) { unsigned long flags; spin_lock_irqsave(&ss->lock, flags); __dahdi_hdlc_abort(ss, event); spin_unlock_irqrestore(&ss->lock, flags); } void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes) { unsigned long flags; int left; spin_lock_irqsave(&ss->lock, flags); if (ss->inreadbuf < 0) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "No place to receive HDLC frame\n"); #endif spin_unlock_irqrestore(&ss->lock, flags); return; } /* Read into the current buffer */ left = ss->blocksize - ss->readidx[ss->inreadbuf]; if (left > bytes) left = bytes; if (left > 0) { memcpy(ss->readbuf[ss->inreadbuf] + ss->readidx[ss->inreadbuf], rxb, left); rxb += left; ss->readidx[ss->inreadbuf] += left; bytes -= left; } /* Something isn't fit into buffer */ if (bytes) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "HDLC frame isn't fit into buffer space\n"); #endif __dahdi_hdlc_abort(ss, DAHDI_EVENT_OVERRUN); } spin_unlock_irqrestore(&ss->lock, flags); } void dahdi_hdlc_finish(struct dahdi_chan *ss) { int oldreadbuf; unsigned long flags; spin_lock_irqsave(&ss->lock, flags); if ((oldreadbuf = ss->inreadbuf) < 0) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "No buffers to finish\n"); #endif spin_unlock_irqrestore(&ss->lock, flags); return; } if (!ss->readidx[ss->inreadbuf]) { #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Empty HDLC frame received\n"); #endif spin_unlock_irqrestore(&ss->lock, flags); return; } ss->readn[ss->inreadbuf] = ss->readidx[ss->inreadbuf]; ss->inreadbuf = (ss->inreadbuf + 1) % ss->numbufs; if (ss->inreadbuf == ss->outreadbuf) { ss->inreadbuf = -1; #ifdef CONFIG_DAHDI_DEBUG module_printk(KERN_NOTICE, "Notifying reader data in block %d\n", oldreadbuf); #endif ss->rxdisable = 0; } if (ss->outreadbuf < 0) { ss->outreadbuf = oldreadbuf; } if (!ss->rxdisable) wake_up_interruptible(&ss->waitq); spin_unlock_irqrestore(&ss->lock, flags); } /* Returns 1 if EOF, 0 if data is still in frame, -1 if EOF and no buffers left */ int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size) { unsigned char *buf; unsigned long flags; int left = 0; int res; int oldbuf; spin_lock_irqsave(&ss->lock, flags); if (ss->outwritebuf > -1) { buf = ss->writebuf[ss->outwritebuf]; left = ss->writen[ss->outwritebuf] - ss->writeidx[ss->outwritebuf]; /* Strip off the empty HDLC CRC end */ left -= 2; if (left <= *size) { *size = left; res = 1; } else res = 0; memcpy(bufptr, &buf[ss->writeidx[ss->outwritebuf]], *size); ss->writeidx[ss->outwritebuf] += *size; if (res) { /* Rotate buffers */ oldbuf = ss->outwritebuf; ss->writeidx[oldbuf] = 0; ss->writen[oldbuf] = 0; ss->outwritebuf = (ss->outwritebuf + 1) % ss->numbufs; if (ss->outwritebuf == ss->inwritebuf) { ss->outwritebuf = -1; if (ss->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ss->waitq); /* If we're only supposed to start when full, disable the transmitter */ if ((ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ss->txbufpolicy == DAHDI_POLICY_HALF_FULL)) ss->txdisable = 1; res = -1; } if (ss->inwritebuf < 0) ss->inwritebuf = oldbuf; if (!(ss->flags & DAHDI_FLAG_PPP) || !dahdi_have_netdev(ss)) { wake_up_interruptible(&ss->waitq); } } } else { res = -1; *size = 0; } spin_unlock_irqrestore(&ss->lock, flags); return res; } static void process_timers(void) { struct dahdi_timer *cur; if (list_empty(&dahdi_timers)) return; spin_lock(&dahdi_timer_lock); list_for_each_entry(cur, &dahdi_timers, list) { if (cur->ms) { cur->pos -= DAHDI_CHUNKSIZE; if (cur->pos <= 0) { cur->tripped++; cur->pos = cur->ms; wake_up_interruptible(&cur->sel); } } } spin_unlock(&dahdi_timer_lock); } static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct *wait_table) { struct dahdi_timer *timer = file->private_data; unsigned long flags; int ret = 0; if (timer) { poll_wait(file, &timer->sel, wait_table); spin_lock_irqsave(&dahdi_timer_lock, flags); if (timer->tripped || timer->ping) ret |= POLLPRI; spin_unlock_irqrestore(&dahdi_timer_lock, flags); } else ret = -EINVAL; return ret; } /* device poll routine */ static unsigned int dahdi_chan_poll(struct file *file, struct poll_table_struct *wait_table) { struct dahdi_chan *const c = file->private_data; int ret = 0; unsigned long flags; if (unlikely(!c)) return -EINVAL; poll_wait(file, &c->waitq, wait_table); spin_lock_irqsave(&c->lock, flags); ret |= (c->inwritebuf > -1) ? POLLOUT|POLLWRNORM : 0; ret |= ((c->outreadbuf > -1) && !c->rxdisable) ? POLLIN|POLLRDNORM : 0; ret |= (c->eventoutidx != c->eventinidx) ? POLLPRI : 0; spin_unlock_irqrestore(&c->lock, flags); return ret; } static unsigned int dahdi_poll(struct file *file, struct poll_table_struct *wait_table) { const int unit = UNIT(file); if (likely(unit == DAHDI_TIMER)) return dahdi_timer_poll(file, wait_table); /* transcoders and channels should have updated their file_operations * before poll is ever called. */ return -EINVAL; } static void __dahdi_transmit_chunk(struct dahdi_chan *chan, unsigned char *buf) { unsigned char silly[DAHDI_CHUNKSIZE]; /* Called with chan->lock locked */ #ifdef OPTIMIZE_CHANMUTE if(likely(chan->chanmute)) return; #endif if (!buf) buf = silly; __dahdi_getbuf_chunk(chan, buf); if ((chan->flags & DAHDI_FLAG_AUDIO) || (chan->confmode)) { #ifdef CONFIG_DAHDI_MMX dahdi_kernel_fpu_begin(); #endif __dahdi_process_getaudio_chunk(chan, buf); #ifdef CONFIG_DAHDI_MMX dahdi_kernel_fpu_end(); #endif } } static inline void __dahdi_real_transmit(struct dahdi_chan *chan) { /* Called with chan->lock held */ #ifdef OPTIMIZE_CHANMUTE if(likely(chan->chanmute)) return; #endif if (chan->confmode) { /* Pull queued data off the conference */ __buf_pull(&chan->confout, chan->writechunk, chan); } else { __dahdi_transmit_chunk(chan, chan->writechunk); } } static void __dahdi_getempty(struct dahdi_chan *ms, unsigned char *buf) { int bytes = DAHDI_CHUNKSIZE; int left; unsigned char *txb = buf; int x; short getlin; /* Called with ms->lock held */ while(bytes) { /* Receive silence, or tone */ if (ms->curtone) { left = ms->curtone->tonesamples - ms->tonep; if (left > bytes) left = bytes; for (x=0;xts, ms->curtone); *(txb++) = DAHDI_LIN2X(getlin, ms); } ms->tonep+=left; bytes -= left; if (ms->tonep >= ms->curtone->tonesamples) { struct dahdi_tone *last; /* Go to the next sample of the tone */ ms->tonep = 0; last = ms->curtone; ms->curtone = ms->curtone->next; if (!ms->curtone) { /* No more tones... Is this dtmf or mf? If so, go to the next digit */ if (ms->dialing) __do_dtmf(ms); } else { if (last != ms->curtone) dahdi_init_tone_state(&ms->ts, ms->curtone); } } } else { /* Use silence */ memset(txb, DAHDI_LIN2X(0, ms), bytes); bytes = 0; } } } static void __dahdi_receive_chunk(struct dahdi_chan *chan, unsigned char *buf) { /* Receive chunk of audio -- called with chan->lock held */ unsigned char waste[DAHDI_CHUNKSIZE]; #ifdef OPTIMIZE_CHANMUTE if(likely(chan->chanmute)) return; #endif if (!buf) { memset(waste, DAHDI_LIN2X(0, chan), sizeof(waste)); buf = waste; } if ((chan->flags & DAHDI_FLAG_AUDIO) || (chan->confmode)) { #ifdef CONFIG_DAHDI_MMX dahdi_kernel_fpu_begin(); #endif __dahdi_process_putaudio_chunk(chan, buf); #ifdef CONFIG_DAHDI_MMX dahdi_kernel_fpu_end(); #endif } __dahdi_putbuf_chunk(chan, buf); } static inline void __dahdi_real_receive(struct dahdi_chan *chan) { /* Called with chan->lock held */ #ifdef OPTIMIZE_CHANMUTE if(likely(chan->chanmute)) return; #endif if (chan->confmode) { /* Load into queue if we have space */ __buf_push(&chan->confin, chan->readchunk); } else { __dahdi_receive_chunk(chan, chan->readchunk); } } /** * __transmit_to_slaves() - Distribute the tx data to all the slave channels. * */ static void __transmit_to_slaves(struct dahdi_chan *const chan) { u_char data[DAHDI_CHUNKSIZE]; int i; int pos = DAHDI_CHUNKSIZE; struct dahdi_chan *slave; for (i = 0; i < DAHDI_CHUNKSIZE; i++) { for (slave = chan; (NULL != slave); slave = slave->nextslave) { if (pos == DAHDI_CHUNKSIZE) { __dahdi_transmit_chunk(chan, data); pos = 0; } slave->writechunk[i] = data[pos++]; } } } int _dahdi_transmit(struct dahdi_span *span) { unsigned int x; for (x=0;xchannels;x++) { struct dahdi_chan *const chan = span->chans[x]; spin_lock(&chan->lock); if (unlikely(chan->flags & DAHDI_FLAG_NOSTDTXRX)) { spin_unlock(&chan->lock); continue; } if (chan == chan->master) { if (is_chan_dacsed(chan)) { struct dahdi_chan *const src = chan->dacs_chan; memcpy(chan->writechunk, src->readchunk, DAHDI_CHUNKSIZE); if (chan->sig == DAHDI_SIG_DACS_RBS) { /* Just set bits for our destination */ if (chan->txsig != src->rxsig) { chan->txsig = src->rxsig; span->ops->rbsbits(chan, src->rxsig); } } /* there is no further processing to do for * DACS channels, so jump to the next channel * in the span */ spin_unlock(&chan->lock); continue; } else if (chan->nextslave) { __transmit_to_slaves(chan); } else { /* Process a normal channel */ __dahdi_real_transmit(chan); } if (chan->otimer) { chan->otimer -= DAHDI_CHUNKSIZE; if (chan->otimer <= 0) __rbs_otimer_expire(chan); } } spin_unlock(&chan->lock); } if (span->mainttimer) { span->mainttimer -= DAHDI_CHUNKSIZE; if (span->mainttimer <= 0) { span->mainttimer = 0; span->maintstat = 0; } } return 0; } EXPORT_SYMBOL(_dahdi_transmit); static inline void __pseudo_rx_audio(struct dahdi_chan *chan) { unsigned char tmp[DAHDI_CHUNKSIZE]; spin_lock(&chan->lock); __dahdi_getempty(chan, tmp); __dahdi_receive_chunk(chan, tmp); spin_unlock(&chan->lock); } #ifdef CONFIG_DAHDI_MIRROR static inline void pseudo_rx_audio(struct dahdi_chan *chan) { if (!chan->srcmirror) __pseudo_rx_audio(chan); } #else static inline void pseudo_rx_audio(struct dahdi_chan *chan) { __pseudo_rx_audio(chan); } #endif /* CONFIG_DAHDI_MIRROR */ #ifdef DAHDI_SYNC_TICK static inline void dahdi_sync_tick(struct dahdi_span *const s) { if (s->ops->sync_tick) s->ops->sync_tick(s, s == master); } #else #define dahdi_sync_tick(x) do { ; } while (0) #endif /** * _process_masterspan - Handle conferencing and timers. * * There are three sets of conference sum accumulators. One for the current * sample chunk (conf_sums), one for the next sample chunk (conf_sums_next), and * one for the previous sample chunk (conf_sums_prev). The following routine * (rotate_sums) "rotates" the pointers to these accululator arrays as part * of the events of sample chink processing as follows: * * 1. All (real span) receive chunks are processed (with putbuf). The last one * to be processed is the master span. The data received is loaded into the * accumulators for the next chunk (conf_sums_next), to be in alignment with * current data after rotate_sums() is called (which immediately follows). * Keep in mind that putbuf is *also* a transmit routine for the pseudo parts * of channels that are in the REALANDPSEUDO conference mode. These channels * are processed from data in the current sample chunk (conf_sums), being * that this is a "transmit" function (for the pseudo part). * * 2. rotate_sums() is called. * * 3. All pseudo channel receive chunks are processed. This data is loaded into * the current sample chunk accumulators (conf_sums). * * 4. All conference links are processed (being that all receive data for this * chunk has already been processed by now). * * 5. All pseudo channel transmit chunks are processed. This data is loaded from * the current sample chunk accumulators (conf_sums). * * 6. All (real span) transmit chunks are processed (with getbuf). This data is * loaded from the current sample chunk accumulators (conf_sums). Keep in mind * that getbuf is *also* a receive routine for the pseudo part of channels that * are in the REALANDPSEUDO conference mode. These samples are loaded into * the next sample chunk accumulators (conf_sums_next) to be processed as part * of the next sample chunk's data (next time around the world). * */ static void _process_masterspan(void) { int x; struct pseudo_chan *pseudo; struct dahdi_span *s; u_char *data; #ifdef CONFIG_DAHDI_CORE_TIMER /* We increment the calls since start here, so that if we switch over * to the core timer, we know how many times we need to call * process_masterspan in order to catch up since this function needs * to be called (1000 / (DAHDI_CHUNKSIZE / 8)) times per second. */ atomic_inc(&core_timer.count); #endif /* Hold the chan_lock for the duration of major activities which touch all sorts of channels */ spin_lock(&chan_lock); /* Process any timers */ process_timers(); list_for_each_entry(s, &span_list, node) { for (x = 0; x < s->channels; ++x) { struct dahdi_chan *const chan = s->chans[x]; if (!chan->confmode) continue; spin_lock(&chan->lock); data = __buf_peek(&chan->confin); __dahdi_receive_chunk(chan, data); if (data) __buf_pull(&chan->confin, NULL, chan); spin_unlock(&chan->lock); } } /* This is the master channel, so make things switch over */ rotate_sums(); /* do all the pseudo and/or conferenced channel receives (getbuf's) */ list_for_each_entry(pseudo, &pseudo_chans, node) { spin_lock(&pseudo->chan.lock); __dahdi_transmit_chunk(&pseudo->chan, NULL); spin_unlock(&pseudo->chan.lock); } /* do all the pseudo/conferenced channel transmits (putbuf's) */ list_for_each_entry(pseudo, &pseudo_chans, node) { pseudo_rx_audio(&pseudo->chan); } list_for_each_entry(s, &span_list, node) { for (x = 0; x < s->channels; x++) { struct dahdi_chan *const chan = s->chans[x]; if (!chan->confmode) continue; spin_lock(&chan->lock); data = __buf_pushpeek(&chan->confout); __dahdi_transmit_chunk(chan, data); if (data) __buf_push(&chan->confout, NULL); spin_unlock(&chan->lock); } dahdi_sync_tick(s); } spin_unlock(&chan_lock); } #ifndef CONFIG_DAHDI_CORE_TIMER static void coretimer_init(void) { return; } static void coretimer_cleanup(void) { return; } #else static unsigned long core_diff_ms(struct timespec *t0, struct timespec *t1) { long nanosec, sec; unsigned long ms; sec = (t1->tv_sec - t0->tv_sec); nanosec = (t1->tv_nsec - t0->tv_nsec); while (nanosec >= NSEC_PER_SEC) { nanosec -= NSEC_PER_SEC; ++sec; } while (nanosec < 0) { nanosec += NSEC_PER_SEC; --sec; } ms = (sec * 1000) + (nanosec / 1000000L); return ms; } static inline unsigned long msecs_processed(const struct core_timer *const ct) { return atomic_read(&ct->count) * DAHDI_MSECS_PER_CHUNK; } static void coretimer_func(unsigned long param) { unsigned long flags; unsigned long ms_since_start; struct timespec now; const unsigned long MAX_INTERVAL = 100000L; const unsigned long ONESEC_INTERVAL = HZ; const long MS_LIMIT = 3000; long difference; now = current_kernel_time(); if (atomic_read(&core_timer.count) == atomic_read(&core_timer.last_count)) { /* This is the code path if a board driver is not calling * dahdi_receive, and therefore the core of dahdi needs to * perform the master span processing itself. */ if (!atomic_read(&core_timer.shutdown)) { mod_timer(&core_timer.timer, jiffies + core_timer.interval); } ms_since_start = core_diff_ms(&core_timer.start_interval, &now); /* * If the system time has changed, it is possible for us to be * far behind. If we are more than MS_LIMIT milliseconds * behind (or ahead in time), just reset our time base and * continue so that we do not hang the system here. * */ difference = ms_since_start - msecs_processed(&core_timer); if (unlikely((difference > MS_LIMIT) || (difference < 0))) { if (printk_ratelimit()) { module_printk(KERN_INFO, "Detected time shift.\n"); } atomic_set(&core_timer.count, 0); atomic_set(&core_timer.last_count, 0); core_timer.start_interval = now; return; } local_irq_save(flags); while (ms_since_start > msecs_processed(&core_timer)) _process_masterspan(); local_irq_restore(flags); if (ms_since_start > MAX_INTERVAL) { atomic_set(&core_timer.count, 0); atomic_set(&core_timer.last_count, 0); core_timer.start_interval = now; } else { atomic_set(&core_timer.last_count, atomic_read(&core_timer.count)); } } else { /* It looks like a board driver is calling dahdi_receive. We * will just check again in a second. */ atomic_set(&core_timer.count, 0); atomic_set(&core_timer.last_count, 0); core_timer.start_interval = now; if (!atomic_read(&core_timer.shutdown)) mod_timer(&core_timer.timer, jiffies + ONESEC_INTERVAL); } } static void coretimer_init(void) { init_timer(&core_timer.timer); core_timer.timer.function = coretimer_func; core_timer.start_interval = current_kernel_time(); core_timer.timer.expires = jiffies + HZ; atomic_set(&core_timer.count, 0); atomic_set(&core_timer.shutdown, 0); core_timer.interval = max(msecs_to_jiffies(DAHDI_MSECS_PER_CHUNK), 1UL); if (core_timer.interval < (HZ/250)) core_timer.interval = (HZ/250); add_timer(&core_timer.timer); } static void coretimer_cleanup(void) { atomic_set(&core_timer.shutdown, 1); del_timer_sync(&core_timer.timer); } #endif /* CONFIG_DAHDI_CORE_TIMER */ /** * __receive_from_slaves() - Collect the rx data from all the slave channels. * */ static void __receive_from_slaves(struct dahdi_chan *const chan) { u_char data[DAHDI_CHUNKSIZE]; int i; int pos = 0; struct dahdi_chan *slave; for (i = 0; i < DAHDI_CHUNKSIZE; ++i) { for (slave = chan; (NULL != slave); slave = slave->nextslave) { data[pos++] = slave->readchunk[i]; if (pos == DAHDI_CHUNKSIZE) { __dahdi_receive_chunk(chan, data); pos = 0; } } } } static inline bool should_skip_receive(const struct dahdi_chan *const chan) { return (unlikely(chan->flags & DAHDI_FLAG_NOSTDTXRX) || (chan->master != chan) || is_chan_dacsed(chan)); } int _dahdi_receive(struct dahdi_span *span) { unsigned int x; #ifdef CONFIG_DAHDI_WATCHDOG span->watchcounter--; #endif for (x = 0; x < span->channels; x++) { struct dahdi_chan *const chan = span->chans[x]; spin_lock(&chan->lock); if (should_skip_receive(chan)) { spin_unlock(&chan->lock); continue; } if (chan->nextslave) { __receive_from_slaves(chan); } else { /* Process a normal channel */ __dahdi_real_receive(chan); } if (chan->itimer) { chan->itimer -= DAHDI_CHUNKSIZE; if (chan->itimer <= 0) rbs_itimer_expire(chan); } if (chan->ringdebtimer) chan->ringdebtimer--; if (chan->sig & __DAHDI_SIG_FXS) { if (chan->rxhooksig == DAHDI_RXSIG_RING) chan->ringtrailer = DAHDI_RINGTRAILER; else if (chan->ringtrailer) { chan->ringtrailer -= DAHDI_CHUNKSIZE; /* See if RING trailer is expired */ if (!chan->ringtrailer && !chan->ringdebtimer) __qevent(chan, DAHDI_EVENT_RINGOFFHOOK); } } if (chan->pulsetimer) { chan->pulsetimer--; if (chan->pulsetimer <= 0) { if (chan->pulsecount) { if (chan->pulsecount > 12) { module_printk(KERN_NOTICE, "Got pulse digit %d on %s???\n", chan->pulsecount, chan->name); } else if (chan->pulsecount > 11) { __qevent(chan, DAHDI_EVENT_PULSEDIGIT | '#'); } else if (chan->pulsecount > 10) { __qevent(chan, DAHDI_EVENT_PULSEDIGIT | '*'); } else if (chan->pulsecount > 9) { __qevent(chan, DAHDI_EVENT_PULSEDIGIT | '0'); } else { __qevent(chan, DAHDI_EVENT_PULSEDIGIT | ('0' + chan->pulsecount)); } chan->pulsecount = 0; } } } #ifdef BUFFER_DEBUG chan->statcount -= DAHDI_CHUNKSIZE; #endif spin_unlock(&chan->lock); } if (span == master) _process_masterspan(); return 0; } EXPORT_SYMBOL(_dahdi_receive); MODULE_AUTHOR("Mark Spencer "); MODULE_DESCRIPTION("DAHDI Telephony Interface"); MODULE_LICENSE("GPL v2"); /* DAHDI now provides timing. If anybody wants dahdi_dummy it's probably * for that. So make dahdi provide it for now. This alias may be removed * in the future, and users are encouraged not to rely on it. */ MODULE_ALIAS("dahdi_dummy"); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Sets debugging verbosity as a bitfield, to see"\ " general debugging set this to 1. To see RBS debugging set"\ " this to 32"); module_param(deftaps, int, 0644); module_param(max_pseudo_channels, int, 0644); MODULE_PARM_DESC(max_pseudo_channels, "Maximum number of pseudo channels."); module_param(hwec_overrides_swec, int, 0644); MODULE_PARM_DESC(hwec_overrides_swec, "When true, a hardware echo canceller is used instead of configured SWEC."); static const struct file_operations dahdi_fops = { .owner = THIS_MODULE, .open = dahdi_open, .release = dahdi_release, #ifdef HAVE_UNLOCKED_IOCTL .unlocked_ioctl = dahdi_unlocked_ioctl, #ifdef HAVE_COMPAT_IOCTL .compat_ioctl = dahdi_ioctl_compat, #endif #else .ioctl = dahdi_ioctl, #endif .poll = dahdi_poll, }; static const struct file_operations dahdi_chan_fops = { .owner = THIS_MODULE, .open = dahdi_open, .release = dahdi_release, #ifdef HAVE_UNLOCKED_IOCTL .unlocked_ioctl = dahdi_unlocked_ioctl, #ifdef HAVE_COMPAT_IOCTL .compat_ioctl = dahdi_ioctl_compat, #endif #else .ioctl = dahdi_ioctl, #endif .read = dahdi_chan_read, .write = dahdi_chan_write, .poll = dahdi_chan_poll, }; #ifdef CONFIG_DAHDI_WATCHDOG static struct timer_list watchdogtimer; static void watchdog_check(unsigned long ignored) { unsigned long flags; static int wdcheck=0; struct dahdi_span *s; spin_lock_irqsave(&span_list_lock, flags); list_for_each_entry(s, &span_list, node) { if (s->flags & DAHDI_FLAG_RUNNING) { if (s->watchcounter == DAHDI_WATCHDOG_INIT) { /* Whoops, dead card */ if ((s->watchstate == DAHDI_WATCHSTATE_OK) || (s->watchstate == DAHDI_WATCHSTATE_UNKNOWN)) { s->watchstate = DAHDI_WATCHSTATE_RECOVERING; if (s->watchdog) { module_printk(KERN_NOTICE, "Kicking span %s\n", s->name); s->watchdog(spans[x], DAHDI_WATCHDOG_NOINTS); } else { module_printk(KERN_NOTICE, "Span %s is dead with no revival\n", s->name); s->watchstate = DAHDI_WATCHSTATE_FAILED; } } } else { if ((s->watchstate != DAHDI_WATCHSTATE_OK) && (s->watchstate != DAHDI_WATCHSTATE_UNKNOWN)) module_printk(KERN_NOTICE, "Span %s is alive!\n", s->name); s->watchstate = DAHDI_WATCHSTATE_OK; } s->watchcounter = DAHDI_WATCHDOG_INIT; } } spin_unlock_irqrestore(&span_list_lock, flags); if (!wdcheck) { module_printk(KERN_NOTICE, "watchdog on duty!\n"); wdcheck=1; } mod_timer(&watchdogtimer, jiffies + 2); } static int __init watchdog_init(void) { init_timer(&watchdogtimer); watchdogtimer.expires = 0; watchdogtimer.data =0; watchdogtimer.function = watchdog_check; /* Run every couple of jiffy or so */ mod_timer(&watchdogtimer, jiffies + 2); return 0; } static void __exit watchdog_cleanup(void) { del_timer(&watchdogtimer); } #endif static int __init dahdi_init(void) { int res = 0; #ifdef CONFIG_PROC_FS root_proc_entry = proc_mkdir("dahdi", NULL); if (!root_proc_entry) { dahdi_err("dahdi init: Failed creating /proc/dahdi\n"); return -EEXIST; } #endif res = dahdi_sysfs_init(&dahdi_fops); if (res) goto failed_driver_init; dahdi_conv_init(); fasthdlc_precalc(); rotate_sums(); #ifdef CONFIG_DAHDI_WATCHDOG watchdog_init(); #endif coretimer_init(); res = dahdi_register_echocan_factory(&hwec_factory); if (res) { WARN_ON(1); goto failed_register_ec_factory; } return 0; failed_register_ec_factory: coretimer_cleanup(); dahdi_sysfs_exit(); failed_driver_init: if (root_proc_entry) { remove_proc_entry("dahdi", NULL); root_proc_entry = NULL; } return res; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) static inline void flush_find_master_work(void) { flush_scheduled_work(); } #else static inline void flush_find_master_work(void) { cancel_work_sync(&find_master_work); } #endif static void __exit dahdi_cleanup(void) { struct dahdi_zone *z; dahdi_unregister_echocan_factory(&hwec_factory); coretimer_cleanup(); dahdi_sysfs_exit(); #ifdef CONFIG_PROC_FS if (root_proc_entry) { remove_proc_entry("dahdi", NULL); root_proc_entry = NULL; } #endif module_printk(KERN_INFO, "Telephony Interface Unloaded\n"); spin_lock(&zone_lock); while (!list_empty(&tone_zones)) { z = list_entry(tone_zones.next, struct dahdi_zone, node); list_del(&z->node); if (!tone_zone_put(z)) { module_printk(KERN_WARNING, "Potential memory leak detected in %s\n", __func__); } } spin_unlock(&zone_lock); #ifdef CONFIG_DAHDI_WATCHDOG watchdog_cleanup(); #endif flush_find_master_work(); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) char *dahdi_kasprintf(gfp_t gfp, const char *fmt, ...) { va_list ap; char *p; char *temp; unsigned int len; temp = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!temp) return NULL; va_start(ap, fmt); len = vsnprintf(temp, PAGE_SIZE, fmt, ap); va_end(ap); p = kzalloc(len + 1, gfp); if (!p) { kfree(temp); return NULL; } memcpy(p, temp, len + 1); kfree(temp); return p; } EXPORT_SYMBOL(dahdi_kasprintf); #endif module_init(dahdi_init); module_exit(dahdi_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi-sysfs.c0000644000175000017500000001346511532727335021141 0ustar tzafrirtzafrir#include #include #define DAHDI_PRINK_MACROS_USE_debug #include #include #include #include "dahdi.h" /* FIXME: Move to kernel.h */ #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) #define CLASS_DEV_CREATE(class, devt, device, name) \ device_create(class, device, devt, NULL, "%s", name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #define CLASS_DEV_CREATE(class, devt, device, name) \ device_create(class, device, devt, name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) #define CLASS_DEV_CREATE(class, devt, device, name) \ class_device_create(class, NULL, devt, device, name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) #define CLASS_DEV_CREATE(class, devt, device, name) \ class_device_create(class, devt, device, name) #else #define CLASS_DEV_CREATE(class, devt, device, name) \ class_simple_device_add(class, devt, device, name) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #define CLASS_DEV_DESTROY(class, devt) \ device_destroy(class, devt) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) #define CLASS_DEV_DESTROY(class, devt) \ class_device_destroy(class, devt) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) #define CLASS_DEV_DESTROY(class, devt) \ class_simple_device_remove(devt) #else #define CLASS_DEV_DESTROY(class, devt) \ class_simple_device_remove(class, devt) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) static struct class *dahdi_class = NULL; #else static struct class_simple *dahdi_class = NULL; #define class_create class_simple_create #define class_destroy class_simple_destroy #endif int dahdi_register_chardev(struct dahdi_chardev *dev) { static const char *DAHDI_STRING = "dahdi!"; char *udevname; udevname = kzalloc(strlen(dev->name) + sizeof(DAHDI_STRING) + 1, GFP_KERNEL); if (!udevname) return -ENOMEM; strcpy(udevname, DAHDI_STRING); strcat(udevname, dev->name); CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor), NULL, udevname); kfree(udevname); return 0; } EXPORT_SYMBOL(dahdi_register_chardev); int dahdi_unregister_chardev(struct dahdi_chardev *dev) { CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor)); return 0; } EXPORT_SYMBOL(dahdi_unregister_chardev); void span_sysfs_remove(struct dahdi_span *span) { int x; for (x = 0; x < span->channels; x++) { struct dahdi_chan *chan = span->chans[x]; if (!test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags)) continue; CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, chan->channo)); clear_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags); } } int span_sysfs_create(struct dahdi_span *span) { int res = 0; int x; for (x = 0; x < span->channels; x++) { struct dahdi_chan *chan = span->chans[x]; char chan_name[32]; void *dummy; if (chan->channo >= 250) continue; if (test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags)) continue; snprintf(chan_name, sizeof(chan_name), "dahdi!%d", chan->channo); dummy = (void *)CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, chan->channo), NULL, chan_name); if (IS_ERR(dummy)) { res = PTR_ERR(dummy); chan_err(chan, "Failed creating sysfs device: %d\n", res); goto cleanup; } set_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags); } return 0; cleanup: span_sysfs_remove(span); return res; } #define MAKE_DAHDI_DEV(num, name) \ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, num), NULL, name) #define DEL_DAHDI_DEV(num) \ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, num)) /* Only used to flag that the device exists: */ static struct { unsigned int ctl:1; unsigned int timer:1; unsigned int channel:1; unsigned int pseudo:1; } dummy_dev; void dahdi_sysfs_exit(void) { if (dummy_dev.pseudo) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/pseudo:\n"); DEL_DAHDI_DEV(DAHDI_PSEUDO); dummy_dev.pseudo = 0; } if (dummy_dev.channel) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/channel:\n"); DEL_DAHDI_DEV(DAHDI_CHANNEL); dummy_dev.channel = 0; } if (dummy_dev.timer) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/timer:\n"); DEL_DAHDI_DEV(DAHDI_TIMER); dummy_dev.timer = 0; } if (dummy_dev.ctl) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/ctl:\n"); DEL_DAHDI_DEV(DAHDI_CTL); dummy_dev.ctl = 0; } if (dahdi_class) { dahdi_dbg(DEVICES, "Destroying DAHDI class:\n"); class_destroy(dahdi_class); dahdi_class = NULL; } unregister_chrdev(DAHDI_MAJOR, "dahdi"); } int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops) { int res = 0; void *dev; res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops); if (res) { module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR); return res; } module_printk(KERN_INFO, "Telephony Interface Registered on major %d\n", DAHDI_MAJOR); module_printk(KERN_INFO, "Version: %s\n", dahdi_version); dahdi_class = class_create(THIS_MODULE, "dahdi"); if (!dahdi_class) { res = -EEXIST; goto cleanup; } dahdi_dbg(DEVICES, "Creating /dev/dahdi/timer:\n"); dev = MAKE_DAHDI_DEV(DAHDI_TIMER, "dahdi!timer"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.timer = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/channel:\n"); dev = MAKE_DAHDI_DEV(DAHDI_CHANNEL, "dahdi!channel"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.channel = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/pseudo:\n"); dev = MAKE_DAHDI_DEV(DAHDI_PSEUDO, "dahdi!pseudo"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.pseudo = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/ctl:\n"); dev = MAKE_DAHDI_DEV(DAHDI_CTL, "dahdi!ctl"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.ctl = 1; return 0; cleanup: dahdi_sysfs_exit(); return res; } dahdi-linux-2.5.0.1/drivers/dahdi/fxo_modes.h0000644000175000017500000002460611546370430020705 0ustar tzafrirtzafrir/* * FXO port mode settings for various regions * * Copyright (C) 2008 Digium, Inc. * * extracted from wctdm.c by * Kevin P. Fleming * * All rights reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _FXO_MODES_H #define _FXO_MODES_H static const struct fxo_mode { const char *name; unsigned char ohs:1; unsigned char ohs2:1; unsigned char rz:1; unsigned char rt:1; unsigned char ilim:1; unsigned char dcv:2; unsigned char mini:2; unsigned char acim:4; unsigned short int ring_osc; unsigned short int ring_x; unsigned short int battdebounce; /* in milliseconds */ unsigned short int battalarm; /* in milliseconds */ unsigned short int battthresh; /* unknown units */ } fxo_modes[] = { /* US, Canada */ { .name = "FCC", .rt = 1, .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, /* Austria, Belgium, Denmark, Finland, France, Germany, Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands, Norway, Portugal, Spain, Sweden, Switzerland, and UK */ { .name = "TBR21", .ilim = 1, .dcv = 0x3, .acim = 0x2, .ring_osc = 0x7e6c, .ring_x = 0x023a, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ARGENTINA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "AUSTRALIA", .ohs = 1, .mini = 0x3, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "AUSTRIA", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "BAHRAIN", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "BELGIUM", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "BRAZIL", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "BULGARIA", .ilim = 1, .dcv = 0x3, .mini = 0x0, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CANADA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CHILE", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CHINA", .mini = 0x3, .acim = 0xf, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "COLOMBIA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CROATIA", .ilim = 1, .dcv = 0x3, .mini = 0, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CYPRUS", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "CZECH", .ilim = 1, .dcv = 0x3, .mini = 0, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "DENMARK", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ECUADOR", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "EGYPT", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ELSALVADOR", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "FINLAND", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "FRANCE", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .mini = 0, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "GERMANY", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "GREECE", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "GUAM", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "HONGKONG", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "HUNGARY", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ICELAND", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "INDIA", .dcv = 0x3, .acim = 0x4, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "INDONESIA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "IRELAND", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ISRAEL", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ITALY", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "JAPAN", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "JORDAN", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "KAZAKHSTAN", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "KUWAIT", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "LATVIA", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "LEBANON", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "LUXEMBOURG", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "MACAO", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, /* Current loop >= 20ma */ { .name = "MALAYSIA", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "MALTA", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "MEXICO", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "MOROCCO", .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "NETHERLANDS", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "NEWZEALAND", .dcv = 0x3, .acim = 0x4, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "NIGERIA", .ilim = 0x1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "NORWAY", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "OMAN", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "PAKISTAN", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "PERU", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "PHILIPPINES", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "POLAND", .rz = 1, .rt = 1, .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "PORTUGAL", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "ROMANIA", .dcv = 3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "RUSSIA", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SAUDIARABIA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SINGAPORE", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SLOVAKIA", .dcv = 0x3, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SLOVENIA", .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SOUTHAFRICA", .ohs = 1, .rz = 1, .dcv = 0x3, .acim = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SOUTHKOREA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SPAIN", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SWEDEN", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SWITZERLAND", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x2, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "SYRIA", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "TAIWAN", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "THAILAND", .mini = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "UAE", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "UK", .ohs2 = 1, .ilim = 1, .dcv = 0x3, .acim = 0x5, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "USA", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, { .name = "YEMEN", .dcv = 0x3, .battdebounce = 64, .battalarm = 1000, .battthresh = 3, }, }; #endif /* _FXO_MODES_H */ dahdi-linux-2.5.0.1/drivers/dahdi/tor2.c0000644000175000017500000013467611571766036017625 0ustar tzafrirtzafrir/* * Tormenta 2 Quad-T1 PCI Driver * * Written by Mark Spencer * Based on previous works, designs, and archetectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2008, Digium, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #define NEED_PCI_IDS #include "tor2-hw.h" #include "tor2fw.h" /* * Tasklets provide better system interactive response at the cost of the * possibility of losing a frame of data at very infrequent intervals. If * you are more concerned with the performance of your machine, enable the * tasklets. If you are strict about absolutely no drops, then do not enable * tasklets. */ /* #define ENABLE_TASKLETS */ /* this stuff needs to work for 64 bit systems, however using the macro causes it to take twice as long */ /* #define FIXTHISFOR64 */ /* as of now, un-comment for 32 bit only system */ #define SPANS_PER_CARD 4 #define MAX_SPANS 16 #define FLAG_STARTED (1 << 0) #define TYPE_T1 1 /* is a T1 card */ #define TYPE_E1 2 /* is an E1 card */ struct tor2_chan { /* Private pointer for channel. We want to know our channel and span */ struct tor2 *tor; int span; /* Index from 0 */ }; struct tor2_span { /* Private pointer for span. We want to know our span number and pointer to the tor device */ struct tor2 *tor; int span; /* Index from 0 */ struct dahdi_span dahdi_span; }; struct tor2 { /* This structure exists one per card */ struct pci_dev *pci; /* Pointer to PCI device */ int num; /* Which card we are */ int syncsrc; /* active sync source */ int syncs[SPANS_PER_CARD]; /* sync sources */ int psyncs[SPANS_PER_CARD]; /* span-relative sync sources */ int alarmtimer[SPANS_PER_CARD]; /* Alarm timer */ char *type; /* Type of tormenta 2 card */ int irq; /* IRQ used by device */ int order; /* Order */ int flags; /* Device flags */ int syncpos[SPANS_PER_CARD]; /* span-relative sync sources */ int master; /* Are we master */ unsigned long plx_region; /* phy addr of PCI9030 registers */ unsigned long plx_len; /* length of PLX window */ __iomem volatile unsigned short *plx; /* Virtual representation of local space */ unsigned long xilinx32_region; /* 32 bit Region allocated to Xilinx */ unsigned long xilinx32_len; /* Length of 32 bit Xilinx region */ __iomem volatile unsigned int *mem32; /* Virtual representation of 32 bit Xilinx memory area */ unsigned long xilinx8_region; /* 8 bit Region allocated to Xilinx */ unsigned long xilinx8_len; /* Length of 8 bit Xilinx region */ __iomem volatile unsigned char *mem8; /* Virtual representation of 8 bit Xilinx memory area */ struct tor2_span tspans[SPANS_PER_CARD]; /* Span data */ struct dahdi_chan **chans[SPANS_PER_CARD]; /* Pointers to card channels */ struct tor2_chan tchans[32 * SPANS_PER_CARD]; /* Channel user data */ unsigned char txsigs[SPANS_PER_CARD][16]; /* Copy of tx sig registers */ int loopupcnt[SPANS_PER_CARD]; /* loop up code counter */ int loopdowncnt[SPANS_PER_CARD];/* loop down code counter */ int spansstarted; /* number of spans started */ spinlock_t lock; /* lock context */ unsigned char leds; /* copy of LED register */ unsigned char ec_chunk1[SPANS_PER_CARD][32][DAHDI_CHUNKSIZE]; /* first EC chunk buffer */ unsigned char ec_chunk2[SPANS_PER_CARD][32][DAHDI_CHUNKSIZE]; /* second EC chunk buffer */ #ifdef ENABLE_TASKLETS int taskletrun; int taskletsched; int taskletpending; int taskletexec; int txerrors; struct tasklet_struct tor2_tlet; #endif int cardtype; /* card type, T1 or E1 */ unsigned int *datxlt; /* pointer to datxlt structure */ unsigned int passno; /* number of interrupt passes */ }; #define t1out(tor, span, reg, val) \ writeb(val, &tor->mem8[((span - 1) * 0x100) + reg]) #define t1in(tor, span, reg) readb(&tor->mem8[((span - 1) * 0x100) + reg]) #ifdef ENABLE_TASKLETS static void tor2_tasklet(unsigned long data); #endif #define GPIOC (PLX_LOC_GPIOC >> 1) /* word-oriented address for PLX GPIOC reg. (32 bit reg.) */ #define LAS2BRD (0x30 >> 1) #define LAS3BRD (0x34 >> 1) #define INTCSR (0x4c >> 1) /* word-oriented address for PLX INTCSR reg. */ #define PLX_INTENA 0x43 /* enable, hi-going, level trigger */ #define SYNCREG 0x400 #define CTLREG 0x401 #define LEDREG 0x402 #define STATREG 0x400 #define SWREG 0x401 #define CTLREG1 0x404 #define INTENA (1 + ((loopback & 3) << 5)) #define OUTBIT (2 + ((loopback & 3) << 5)) #define E1DIV 0x10 #define INTACK (0x80 + ((loopback & 3) << 5)) #define INTACTIVE 2 #define MASTER (1 << 3) /* un-define this if you dont want NON-REV A hardware support */ /* #define NONREVA 1 */ #define SYNCSELF 0 #define SYNC1 1 #define SYNC2 2 #define SYNC3 3 #define SYNC4 4 #define SYNCEXTERN 5 #define LEDRED 2 #define LEDGREEN 1 #define MAX_TOR_CARDS 64 static struct tor2 *cards[MAX_TOR_CARDS]; /* signalling bits */ #define TOR_ABIT 8 #define TOR_BBIT 4 static int debug; static int japan; static int loopback; static int highestorder; static int timingcable; static void set_clear(struct tor2 *tor); static int tor2_startup(struct file *file, struct dahdi_span *span); static int tor2_shutdown(struct dahdi_span *span); static int tor2_rbsbits(struct dahdi_chan *chan, int bits); static int tor2_maint(struct dahdi_span *span, int cmd); static int tor2_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data); DAHDI_IRQ_HANDLER(tor2_intr); /* translations of data channels for 24 channels in a 32 bit PCM highway */ static unsigned datxlt_t1[] = { 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 }; /* translations of data channels for 30/31 channels in a 32 bit PCM highway */ static unsigned datxlt_e1[] = { 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31 }; static int tor2_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { int i; struct tor2_span *p = container_of(span, struct tor2_span, dahdi_span); if (debug) printk(KERN_INFO "Tor2: Configuring span %d\n", span->spanno); if ((lc->sync < 0) || (lc->sync > SPANS_PER_CARD)) { printk(KERN_WARNING "%s %d: invalid span timing value %d.\n", THIS_MODULE->name, span->spanno, lc->sync); return -EINVAL; } span->syncsrc = p->tor->syncsrc; /* remove this span number from the current sync sources, if there */ for (i = 0; i < SPANS_PER_CARD; i++) { if (p->tor->syncs[i] == span->spanno) { p->tor->syncs[i] = 0; p->tor->psyncs[i] = 0; } } p->tor->syncpos[p->span] = lc->sync; /* if a sync src, put it in the proper place */ if (lc->sync) { p->tor->syncs[lc->sync - 1] = span->spanno; p->tor->psyncs[lc->sync - 1] = p->span + 1; } /* If we're already running, then go ahead and apply the changes */ if (span->flags & DAHDI_FLAG_RUNNING) return tor2_startup(file, span); return 0; } static int tor2_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { int alreadyrunning; unsigned long flags; struct tor2_chan *p = chan->pvt; alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING; if (debug) { if (alreadyrunning) printk(KERN_INFO "Tor2: Reconfigured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype); else printk(KERN_INFO "Tor2: Configured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype); } /* nothing more to do if an E1 */ if (p->tor->cardtype == TYPE_E1) return 0; spin_lock_irqsave(&p->tor->lock, flags); if (alreadyrunning) set_clear(p->tor); spin_unlock_irqrestore(&p->tor->lock, flags); return 0; } static int tor2_open(struct dahdi_chan *chan) { return 0; } static int tor2_close(struct dahdi_chan *chan) { return 0; } static const struct dahdi_span_ops tor2_span_ops = { .owner = THIS_MODULE, .spanconfig = tor2_spanconfig, .chanconfig = tor2_chanconfig, .startup = tor2_startup, .shutdown = tor2_shutdown, .rbsbits = tor2_rbsbits, .maint = tor2_maint, .open = tor2_open, .close = tor2_close, .ioctl = tor2_ioctl, }; static void init_spans(struct tor2 *tor) { int x, y, c; /* TODO: a debug printk macro */ for (x = 0; x < SPANS_PER_CARD; x++) { struct dahdi_span *const s = &tor->tspans[x].dahdi_span; sprintf(s->name, "Tor2/%d/%d", tor->num, x + 1); snprintf(s->desc, sizeof(s->desc) - 1, "Tormenta 2 (PCI) Quad %s Card %d Span %d", (tor->cardtype == TYPE_T1) ? "T1" : "E1", tor->num, x + 1); s->manufacturer = "Digium"; strlcpy(s->devicetype, tor->type, sizeof(s->devicetype)); snprintf(s->location, sizeof(s->location) - 1, "PCI Bus %02d Slot %02d", tor->pci->bus->number, PCI_SLOT(tor->pci->devfn) + 1); if (tor->cardtype == TYPE_T1) { s->channels = 24; s->deflaw = DAHDI_LAW_MULAW; s->linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; s->spantype = "T1"; } else { s->channels = 31; s->deflaw = DAHDI_LAW_ALAW; s->linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; s->spantype = "E1"; } s->chans = tor->chans[x]; s->flags = DAHDI_FLAG_RBS; s->ops = &tor2_span_ops; tor->tspans[x].tor = tor; tor->tspans[x].span = x; for (y = 0; y < s->channels; y++) { struct dahdi_chan *mychans = tor->chans[x][y]; sprintf(mychans->name, "Tor2/%d/%d/%d", tor->num, x + 1, y + 1); mychans->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF | DAHDI_SIG_EM_E1; c = (x * s->channels) + y; mychans->pvt = &tor->tchans[c]; mychans->chanpos = y + 1; tor->tchans[c].span = x; tor->tchans[c].tor = tor; } } } static int __devinit tor2_launch(struct tor2 *tor) { struct dahdi_span *s; int i; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &tor->tspans[0].dahdi_span.flags)) return 0; printk(KERN_INFO "Tor2: Launching card: %d\n", tor->order); for (i = 0; i < SPANS_PER_CARD; ++i) { s = &tor->tspans[i].dahdi_span; if (dahdi_register(s, 0)) { printk(KERN_ERR "Unable to register span %s\n", s->name); goto error_exit; } } writew(PLX_INTENA, &tor->plx[INTCSR]); /* enable PLX interrupt */ #ifdef ENABLE_TASKLETS tasklet_init(&tor->tor2_tlet, tor2_tasklet, (unsigned long)tor); #endif return 0; error_exit: for (i = 0; i < SPANS_PER_CARD; ++i) { s = &tor->tspans[i].dahdi_span; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags)) dahdi_unregister(s); } return -1; } static void free_tor(struct tor2 *tor) { unsigned int x, f; for (x = 0; x < SPANS_PER_CARD; x++) { for (f = 0; f < (tor->cardtype == TYPE_E1 ? 31 : 24); f++) { if (tor->chans[x][f]) { kfree(tor->chans[x][f]); } } if (tor->chans[x]) kfree(tor->chans[x]); } kfree(tor); } static int __devinit tor2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int res,x,f; int ret = -ENODEV; struct tor2 *tor; unsigned long endjif; __iomem volatile unsigned long *gpdata_io, *lasdata_io; unsigned long gpdata,lasdata; res = pci_enable_device(pdev); if (res) return res; tor = kmalloc(sizeof(struct tor2), GFP_KERNEL); if (!tor) return -ENOMEM; memset(tor,0,sizeof(struct tor2)); spin_lock_init(&tor->lock); /* Load the resources */ tor->pci = pdev; tor->irq = pdev->irq; if (tor->irq < 1) { printk(KERN_ERR "No IRQ allocated for device\n"); goto err_out_free_tor; } tor->plx_region = pci_resource_start(pdev, 0); tor->plx_len = pci_resource_len(pdev, 0); tor->plx = ioremap(tor->plx_region, tor->plx_len); /* We don't use the I/O space, so we dont do anything with section 1 */ tor->xilinx32_region = pci_resource_start(pdev, 2); tor->xilinx32_len = pci_resource_len(pdev, 2); tor->mem32 = ioremap(tor->xilinx32_region, tor->xilinx32_len); tor->xilinx8_region = pci_resource_start(pdev, 3); tor->xilinx8_len = pci_resource_len(pdev, 3); tor->mem8 = ioremap(tor->xilinx8_region, tor->xilinx8_len); /* Record what type */ tor->type = (char *)ent->driver_data; /* Verify existence and accuracy of resources */ if (!tor->plx_region || !tor->plx || (pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { printk(KERN_ERR "Invalid PLX 9030 Base resource\n"); goto err_out_free_tor; } if (!tor->xilinx32_region || !tor->mem32 || (pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { printk(KERN_ERR "Invalid Xilinx 32 bit Base resource\n"); goto err_out_free_tor; } if (!tor->xilinx8_region || !tor->mem8 || (pci_resource_flags(pdev, 3) & IORESOURCE_IO)) { printk(KERN_ERR "Invalid Xilinx 8 bit Base resource\n"); goto err_out_free_tor; } /* Request regions */ if (!request_mem_region(tor->plx_region, tor->plx_len, tor->type)) { printk(KERN_ERR "Unable to reserve PLX memory %08lx window at %08lx\n", tor->plx_len, tor->plx_region); goto err_out_free_tor; } if (!request_mem_region(tor->xilinx32_region, tor->xilinx32_len, tor->type)) { printk(KERN_ERR "Unable to reserve Xilinx 32 bit memory %08lx window at %08lx\n", tor->xilinx32_len, tor->xilinx32_region); goto err_out_release_plx_region; } if (!request_mem_region(tor->xilinx8_region, tor->xilinx8_len, tor->type)) { printk(KERN_ERR "Unable to reserve Xilinx memory %08lx window at %08lx\n", tor->xilinx8_len, tor->xilinx8_region); goto err_out_release_plx_region; } pci_set_drvdata(pdev, tor); printk(KERN_INFO "Detected %s at 0x%lx/0x%lx irq %d\n", tor->type, tor->xilinx32_region, tor->xilinx8_region,tor->irq); for (x = 0; x < MAX_TOR_CARDS; x++) { if (!cards[x]) break; } if (x >= MAX_TOR_CARDS) { printk(KERN_ERR "No cards[] slot available!!\n"); goto err_out_release_all; } tor->num = x; cards[x] = tor; /* start programming mode */ gpdata_io = (__iomem unsigned long *) &tor->plx[GPIOC]; gpdata = readl(gpdata_io); gpdata |= GPIO_WRITE; /* make sure WRITE is not asserted */ writel(gpdata, gpdata_io); gpdata &= ~GPIO_PROGRAM; /* activate the PROGRAM signal */ writel(gpdata, gpdata_io); /* wait for INIT and DONE to go low */ endjif = jiffies + 10; while (readl(gpdata_io) & (GPIO_INIT | GPIO_DONE) && (jiffies <= endjif)) { ; } if (endjif < jiffies) { printk(KERN_ERR "Timeout waiting for INIT and DONE to go low\n"); goto err_out_release_all; } if (debug) printk(KERN_ERR "fwload: Init and done gone to low\n"); gpdata |= GPIO_PROGRAM; writel(gpdata, gpdata_io); /* de-activate the PROGRAM signal */ /* wait for INIT to go high (clearing done */ endjif = jiffies + 10; while (!(readl(gpdata_io) & GPIO_INIT) && (jiffies <= endjif)) ; if (endjif < jiffies) { printk(KERN_ERR "Timeout waiting for INIT to go high\n"); goto err_out_release_all; } if (debug) printk(KERN_ERR "fwload: Init went high (clearing done)\nNow loading...\n"); /* assert WRITE signal */ gpdata &= ~GPIO_WRITE; writel(gpdata, gpdata_io); for (x = 0; x < sizeof(tor2fw); x++) { /* write the byte */ writeb(tor2fw[x], tor->mem8); /* if DONE signal, we're done, exit */ if (readl(gpdata_io) & GPIO_DONE) break; /* if INIT drops, we're screwed, exit */ if (!(readl(gpdata_io) & GPIO_INIT)) break; } if (debug) printk(KERN_DEBUG "fwload: Transferred %d bytes into chip\n",x); /* Wait for FIFO to clear */ endjif = jiffies + 2; while (jiffies < endjif); /* wait */ /* de-assert write signal */ gpdata |= GPIO_WRITE; writel(gpdata, gpdata_io); if (debug) printk(KERN_DEBUG "fwload: Loading done!\n"); /* Wait for FIFO to clear */ endjif = jiffies + 2; while (jiffies < endjif); /* wait */ if (!(readl(gpdata_io) & GPIO_INIT)) { printk(KERN_ERR "Drove Init low!! CRC Error!!!\n"); goto err_out_release_all; } if (!(readl(gpdata_io) & GPIO_DONE)) { printk(KERN_ERR "Did not get DONE signal. Short file maybe??\n"); goto err_out_release_all; } printk(KERN_INFO "Xilinx Chip successfully loaded, configured and started!!\n"); writeb(0, &tor->mem8[SYNCREG]); writeb(0, &tor->mem8[CTLREG]); writeb(0, &tor->mem8[CTLREG1]); writeb(0, &tor->mem8[LEDREG]); /* set the LA2BRD register so that we enable block transfer, read pre-fetch, and set to maximum read pre-fetch size */ lasdata_io = (__iomem unsigned long *) &tor->plx[LAS2BRD]; lasdata = readl(lasdata_io); lasdata |= 0x39; writel(lasdata, lasdata_io); /* set the LA3BRD register so that we enable block transfer */ lasdata_io = (__iomem unsigned long *) &tor->plx[LAS3BRD]; lasdata = readl(lasdata_io); lasdata |= 1; writel(lasdata, lasdata_io); /* check part revision data */ x = t1in(tor,1,0xf) & 15; #ifdef NONREVA if (x > 3) { tor->mem8[CTLREG1] = NONREVA; } #endif for (x = 0; x < 256; x++) writel(0x7f7f7f7f, &tor->mem32[x]); if (request_irq(tor->irq, tor2_intr, DAHDI_IRQ_SHARED_DISABLED, "tor2", tor)) { printk(KERN_ERR "Unable to request tormenta IRQ %d\n", tor->irq); goto err_out_release_all; } if (t1in(tor,1,0xf) & 0x80) { printk(KERN_INFO "Tormenta 2 Quad E1/PRA Card\n"); tor->cardtype = TYPE_E1; tor->datxlt = datxlt_e1; } else { printk(KERN_INFO "Tormenta 2 Quad T1/PRI Card\n"); tor->cardtype = TYPE_T1; tor->datxlt = datxlt_t1; } for (x = 0; x < SPANS_PER_CARD; x++) { int num_chans = tor->cardtype == TYPE_E1 ? 31 : 24; if (!(tor->chans[x] = kmalloc(num_chans * sizeof(*tor->chans[x]), GFP_KERNEL))) { printk(KERN_ERR "tor2: Not enough memory for chans[%d]\n", x); ret = -ENOMEM; goto err_out_release_all; } for (f = 0; f < (num_chans); f++) { if (!(tor->chans[x][f] = kmalloc(sizeof(*tor->chans[x][f]), GFP_KERNEL))) { printk(KERN_ERR "tor2: Not enough memory for chans[%d][%d]\n", x, f); ret = -ENOMEM; goto err_out_release_all; } memset(tor->chans[x][f], 0, sizeof(*tor->chans[x][f])); } } init_spans(tor); tor->order = readb(&tor->mem8[SWREG]); printk(KERN_INFO "Detected Card number: %d\n", tor->order); /* Launch cards as appropriate */ x = 0; for (;;) { /* Find a card to activate */ f = 0; for (x=0;cards[x];x++) { if (cards[x]->order <= highestorder) { tor2_launch(cards[x]); if (cards[x]->order == highestorder) f = 1; } } /* If we found at least one, increment the highest order and search again, otherwise stop */ if (f) highestorder++; else break; } return 0; err_out_release_all: release_mem_region(tor->xilinx32_region, tor->xilinx32_len); release_mem_region(tor->xilinx8_region, tor->xilinx8_len); err_out_release_plx_region: release_mem_region(tor->plx_region, tor->plx_len); err_out_free_tor: if (tor->plx) iounmap(tor->plx); if (tor->mem8) iounmap(tor->mem8); if (tor->mem32) iounmap(tor->mem32); if (tor) { free_tor(tor); } return ret; } static struct pci_driver tor2_driver; static void __devexit tor2_remove(struct pci_dev *pdev) { struct tor2 *tor; int i; tor = pci_get_drvdata(pdev); if (!tor) BUG(); writeb(0, &tor->mem8[SYNCREG]); writeb(0, &tor->mem8[CTLREG]); writeb(0, &tor->mem8[LEDREG]); writew(0, &tor->plx[INTCSR]); free_irq(tor->irq, tor); for (i = 0; i < SPANS_PER_CARD; ++i) { struct dahdi_span *s = &tor->tspans[i].dahdi_span; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags)) dahdi_unregister(s); } release_mem_region(tor->plx_region, tor->plx_len); release_mem_region(tor->xilinx32_region, tor->xilinx32_len); release_mem_region(tor->xilinx8_region, tor->xilinx8_len); if (tor->plx) iounmap(tor->plx); if (tor->mem8) iounmap(tor->mem8); if (tor->mem32) iounmap(tor->mem32); cards[tor->num] = NULL; pci_set_drvdata(pdev, NULL); free_tor(tor); } static struct pci_driver tor2_driver = { .name = "tormenta2", .probe = tor2_probe, .remove = __devexit_p(tor2_remove), .id_table = tor2_pci_ids, }; static int __init tor2_init(void) { int res; res = dahdi_pci_module(&tor2_driver); printk(KERN_INFO "Registered Tormenta2 PCI\n"); return res; } static void __exit tor2_cleanup(void) { pci_unregister_driver(&tor2_driver); printk(KERN_INFO "Unregistered Tormenta2\n"); } static void set_clear(struct tor2 *tor) { int i,j,s; unsigned short val=0; for (s = 0; s < SPANS_PER_CARD; s++) { struct dahdi_span *span = &tor->tspans[s].dahdi_span; for (i = 0; i < 24; i++) { j = (i/8); if (span->chans[i]->flags & DAHDI_FLAG_CLEAR) val |= 1 << (i % 8); if ((i % 8)==7) { #if 0 printk(KERN_DEBUG "Putting %d in register %02x on span %d\n", val, 0x39 + j, 1 + s); #endif t1out(tor,1 + s, 0x39 + j, val); val = 0; } } } } static int tor2_rbsbits(struct dahdi_chan *chan, int bits) { u_char m,c; int k,n,b; struct tor2_chan *p = chan->pvt; unsigned long flags; #if 0 printk(KERN_DEBUG "Setting bits to %d on channel %s\n", bits, chan->name); #endif if (p->tor->cardtype == TYPE_E1) { /* do it E1 way */ if (chan->chanpos == 16) return 0; n = chan->chanpos - 1; if (chan->chanpos > 16) n--; k = p->span; b = (n % 15) + 1; c = p->tor->txsigs[k][b]; m = (n / 15) * 4; /* nibble selector */ c &= (15 << m); /* keep the other nibble */ c |= (bits & 15) << (4 - m); /* put our new nibble here */ p->tor->txsigs[k][b] = c; /* output them to the chip */ t1out(p->tor,k + 1,0x40 + b,c); return 0; } n = chan->chanpos - 1; k = p->span; b = (n / 8); /* get byte number */ m = 1 << (n & 7); /* get mask */ c = p->tor->txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (bits & DAHDI_ABIT) c |= m; p->tor->txsigs[k][b] = c; spin_lock_irqsave(&p->tor->lock, flags); t1out(p->tor,k + 1,0x70 + b,c); b += 3; /* now points to b bit stuff */ /* get current signalling values */ c = p->tor->txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (bits & DAHDI_BBIT) c |= m; /* save new signalling values */ p->tor->txsigs[k][b] = c; /* output them into the chip */ t1out(p->tor,k + 1,0x70 + b,c); b += 3; /* now points to c bit stuff */ /* get current signalling values */ c = p->tor->txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (bits & DAHDI_CBIT) c |= m; /* save new signalling values */ p->tor->txsigs[k][b] = c; /* output them into the chip */ t1out(p->tor,k + 1,0x70 + b,c); b += 3; /* now points to d bit stuff */ /* get current signalling values */ c = p->tor->txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (bits & DAHDI_DBIT) c |= m; /* save new signalling values */ p->tor->txsigs[k][b] = c; /* output them into the chip */ t1out(p->tor,k + 1,0x70 + b,c); spin_unlock_irqrestore(&p->tor->lock, flags); return 0; } static int tor2_shutdown(struct dahdi_span *span) { int i; int tspan; int wasrunning; unsigned long flags; struct tor2_span *const p = container_of(span, struct tor2_span, dahdi_span); struct tor2 *const tor = p->tor; tspan = p->span + 1; if (tspan < 0) { printk(KERN_DEBUG "Tor2: Span '%d' isn't us?\n", span->spanno); return -1; } spin_lock_irqsave(&tor->lock, flags); wasrunning = span->flags & DAHDI_FLAG_RUNNING; span->flags &= ~DAHDI_FLAG_RUNNING; /* Zero out all registers */ if (tor->cardtype == TYPE_E1) { for (i = 0; i < 192; i++) t1out(tor, tspan, i, 0); } else { for (i = 0; i < 160; i++) t1out(tor, tspan, i, 0); } if (wasrunning) tor->spansstarted--; spin_unlock_irqrestore(&tor->lock, flags); if (!(tor->tspans[0].dahdi_span.flags & DAHDI_FLAG_RUNNING) && !(tor->tspans[1].dahdi_span.flags & DAHDI_FLAG_RUNNING) && !(tor->tspans[2].dahdi_span.flags & DAHDI_FLAG_RUNNING) && !(tor->tspans[3].dahdi_span.flags & DAHDI_FLAG_RUNNING)) /* No longer in use, disable interrupts */ writeb(0, &tor->mem8[CTLREG]); if (debug) printk(KERN_DEBUG"Span %d (%s) shutdown\n", span->spanno, span->name); return 0; } static int tor2_startup(struct file *file, struct dahdi_span *span) { unsigned long endjif; int i; int tspan; unsigned long flags; char *coding; char *framing; char *crcing; int alreadyrunning; struct tor2_span *p = container_of(span, struct tor2_span, dahdi_span); tspan = p->span + 1; if (tspan < 0) { printk(KERN_DEBUG "Tor2: Span '%d' isn't us?\n", span->spanno); return -1; } spin_lock_irqsave(&p->tor->lock, flags); alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; /* initialize the start value for the entire chunk of last ec buffer */ for (i = 0; i < span->channels; i++) { memset(p->tor->ec_chunk1[p->span][i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); memset(p->tor->ec_chunk2[p->span][i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); } /* Force re-evaluation of the timing source */ if (timingcable) p->tor->syncsrc = -1; if (p->tor->cardtype == TYPE_E1) { /* if this is an E1 card */ unsigned char tcr1,ccr1,tcr2; if (!alreadyrunning) { writeb(SYNCSELF, &p->tor->mem8[SYNCREG]); writeb(E1DIV, &p->tor->mem8[CTLREG]); writeb(0, &p->tor->mem8[LEDREG]); /* Force re-evaluation of sync src */ /* Zero out all registers */ for (i = 0; i < 192; i++) t1out(p->tor,tspan, i, 0); /* Set up for Interleaved Serial Bus operation in byte mode */ /* Set up all the spans every time, so we are sure they are in a consistent state. If we don't, a card without all its spans configured misbehaves in strange ways. */ t1out(p->tor,1,0xb5,9); t1out(p->tor,2,0xb5,8); t1out(p->tor,3,0xb5,8); t1out(p->tor,4,0xb5,8); t1out(p->tor,tspan,0x1a,4); /* CCR2: set LOTCMC */ for (i = 0; i <= 8; i++) t1out(p->tor,tspan,i,0); for (i = 0x10; i <= 0x4f; i++) if (i != 0x1a) t1out(p->tor,tspan,i,0); t1out(p->tor,tspan,0x10,0x20); /* RCR1: Rsync as input */ t1out(p->tor,tspan,0x11,6); /* RCR2: Sysclk=2.048 Mhz */ t1out(p->tor,tspan,0x12,9); /* TCR1: TSiS mode */ } ccr1 = 0; crcing = ""; tcr1 = 9; /* base TCR1 value: TSis mode */ tcr2 = 0; if (span->lineconfig & DAHDI_CONFIG_CCS) { ccr1 |= 8; /* CCR1: Rx Sig mode: CCS */ coding = "CCS"; } else { tcr1 |= 0x20; coding = "CAS"; } if (span->lineconfig & DAHDI_CONFIG_HDB3) { ccr1 |= 0x44; /* CCR1: TX and RX HDB3 */ framing = "HDB3"; } else framing = "AMI"; if (span->lineconfig & DAHDI_CONFIG_CRC4) { ccr1 |= 0x11; /* CCR1: TX and TX CRC4 */ tcr2 |= 0x02; /* TCR2: CRC4 bit auto */ crcing = "/CRC4"; } t1out(p->tor,tspan,0x12,tcr1); t1out(p->tor,tspan,0x13,tcr2); t1out(p->tor,tspan,0x14,ccr1); t1out(p->tor,tspan, 0x18, 0x20); /* 120 Ohm, normal */ if (!alreadyrunning) { t1out(p->tor,tspan,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */ t1out(p->tor,tspan,0x20,0x1b); /* TAFR */ t1out(p->tor,tspan,0x21,0x5f); /* TNAFR */ t1out(p->tor,tspan,0x40,0xb); /* TSR1 */ for (i = 0x41; i <= 0x4f; i++) t1out(p->tor,tspan,i,0x55); for (i = 0x22; i <= 0x25; i++) t1out(p->tor,tspan,i,0xff); /* Wait 100 ms */ endjif = jiffies + 10; spin_unlock_irqrestore(&p->tor->lock, flags); while (jiffies < endjif); /* wait 100 ms */ spin_lock_irqsave(&p->tor->lock, flags); t1out(p->tor,tspan,0x1b,0x9a); /* CCR3: set also ESR */ t1out(p->tor,tspan,0x1b,0x82); /* CCR3: TSCLKM only now */ span->flags |= DAHDI_FLAG_RUNNING; p->tor->spansstarted++; /* enable interrupts */ writeb(INTENA | E1DIV, &p->tor->mem8[CTLREG]); } spin_unlock_irqrestore(&p->tor->lock, flags); if (debug) { if (alreadyrunning) printk(KERN_INFO "Tor2: Reconfigured span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing); else printk(KERN_INFO "Tor2: Startup span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing); } } else { /* is a T1 card */ if (!alreadyrunning) { writeb(SYNCSELF, &p->tor->mem8[SYNCREG]); writeb(0, &p->tor->mem8[CTLREG]); writeb(0, &p->tor->mem8[LEDREG]); /* Zero out all registers */ for (i = 0; i < 160; i++) t1out(p->tor,tspan, i, 0); /* Set up for Interleaved Serial Bus operation in byte mode */ /* Set up all the spans every time, so we are sure they are in a consistent state. If we don't, a card without all its spans configured misbehaves in strange ways. */ t1out(p->tor,1,0x94,9); t1out(p->tor,2,0x94,8); t1out(p->tor,3,0x94,8); t1out(p->tor,4,0x94,8); /* Full-on Sync required (RCR1) */ t1out(p->tor,tspan, 0x2b, 8); /* RSYNC is an input (RCR2) */ t1out(p->tor,tspan, 0x2c, 8); /* RBS enable (TCR1) */ t1out(p->tor,tspan, 0x35, 0x10); /* TSYNC to be output (TCR2) */ t1out(p->tor,tspan, 0x36, 4); /* Tx & Rx Elastic store, sysclk(s) = 2.048 mhz, loopback controls (CCR1) */ t1out(p->tor,tspan, 0x37, 0x9c); /* Set up received loopup and loopdown codes */ t1out(p->tor,tspan, 0x12, 0x22); t1out(p->tor,tspan, 0x14, 0x80); t1out(p->tor,tspan, 0x15, 0x80); /* Setup japanese mode if appropriate */ t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */ t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */ } /* Enable F bits pattern */ i = 0x20; if (span->lineconfig & DAHDI_CONFIG_ESF) i = 0x88; if (span->lineconfig & DAHDI_CONFIG_B8ZS) i |= 0x44; t1out(p->tor,tspan, 0x38, i); if (i & 0x80) coding = "ESF"; else coding = "SF"; if (i & 0x40) framing = "B8ZS"; else { framing = "AMI"; t1out(p->tor,tspan,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */ } t1out(p->tor,tspan, 0x7c, span->txlevel << 5); if (!alreadyrunning) { /* LIRST to reset line interface */ t1out(p->tor,tspan, 0x0a, 0x80); /* Wait 100 ms */ endjif = jiffies + 10; spin_unlock_irqrestore(&p->tor->lock, flags); while (jiffies < endjif); /* wait 100 ms */ spin_lock_irqsave(&p->tor->lock, flags); t1out(p->tor,tspan,0x0a,0x30); /* LIRST back to normal, Resetting elastic stores */ span->flags |= DAHDI_FLAG_RUNNING; p->tor->spansstarted++; /* enable interrupts */ writeb(INTENA, &p->tor->mem8[CTLREG]); } set_clear(p->tor); spin_unlock_irqrestore(&p->tor->lock, flags); if (debug) { if (alreadyrunning) printk(KERN_INFO "Tor2: Reconfigured span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, dahdi_lboname(span->txlevel)); else printk(KERN_INFO "Tor2: Startup span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, dahdi_lboname(span->txlevel)); } } if (p->tor->syncs[0] == span->spanno) printk(KERN_INFO "SPAN %d: Primary Sync Source\n",span->spanno); if (p->tor->syncs[1] == span->spanno) printk(KERN_INFO "SPAN %d: Secondary Sync Source\n",span->spanno); if (p->tor->syncs[2] == span->spanno) printk(KERN_INFO "SPAN %d: Tertiary Sync Source\n",span->spanno); if (p->tor->syncs[3] == span->spanno) printk(KERN_INFO "SPAN %d: Quaternary Sync Source\n",span->spanno); return 0; } static int tor2_maint(struct dahdi_span *span, int cmd) { struct tor2_span *p = container_of(span, struct tor2_span, dahdi_span); int tspan = p->span + 1; if (p->tor->cardtype == TYPE_E1) { switch(cmd) { case DAHDI_MAINT_NONE: t1out(p->tor,tspan,0xa8,0); /* no loops */ break; case DAHDI_MAINT_LOCALLOOP: t1out(p->tor,tspan,0xa8,0x40); /* local loop */ break; case DAHDI_MAINT_REMOTELOOP: t1out(p->tor,tspan,0xa8,0x80); /* remote loop */ break; case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: return -ENOSYS; default: printk(KERN_NOTICE "Tor2: Unknown maint command: %d\n", cmd); break; } return 0; } switch(cmd) { case DAHDI_MAINT_NONE: t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */ t1out(p->tor,tspan,0x0a,0); /* no remote loop */ t1out(p->tor, tspan, 0x30, 0); /* stop sending loopup code */ break; case DAHDI_MAINT_LOCALLOOP: t1out(p->tor,tspan,0x19,0x40 | (japan ? 0x80 : 0x00)); /* local loop */ t1out(p->tor,tspan,0x0a,0); /* no remote loop */ break; case DAHDI_MAINT_REMOTELOOP: t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */ t1out(p->tor,tspan,0x0a,0x40); /* remote loop */ break; case DAHDI_MAINT_LOOPUP: t1out(p->tor,tspan,0x30,2); /* send loopup code */ t1out(p->tor,tspan,0x12,0x22); /* send loopup code */ t1out(p->tor,tspan,0x13,0x80); /* send loopup code */ break; case DAHDI_MAINT_LOOPDOWN: t1out(p->tor,tspan,0x30,2); /* send loopdown code */ t1out(p->tor,tspan,0x12,0x62); /* send loopdown code */ t1out(p->tor,tspan,0x13,0x90); /* send loopdown code */ break; default: printk(KERN_NOTICE "Tor2: Unknown maint command: %d\n", cmd); break; } return 0; } static inline void tor2_run(struct tor2 *tor) { int x,y; for (x = 0; x < SPANS_PER_CARD; x++) { struct dahdi_span *const s = &tor->tspans[x].dahdi_span; if (s->flags & DAHDI_FLAG_RUNNING) { /* since the Tormenta 2 PCI is double-buffered, you need to delay the transmit data 2 entire chunks so that the transmit will be in sync with the receive */ for (y = 0; y < s->channels; y++) { dahdi_ec_chunk(s->chans[y], s->chans[y]->readchunk, tor->ec_chunk2[x][y]); memcpy(tor->ec_chunk2[x][y],tor->ec_chunk1[x][y], DAHDI_CHUNKSIZE); memcpy(tor->ec_chunk1[x][y], s->chans[y]->writechunk, DAHDI_CHUNKSIZE); } dahdi_receive(s); } } for (x = 0; x < SPANS_PER_CARD; x++) { struct dahdi_span *const s = &tor->tspans[x].dahdi_span; if (s->flags & DAHDI_FLAG_RUNNING) dahdi_transmit(s); } } #ifdef ENABLE_TASKLETS static void tor2_tasklet(unsigned long data) { struct tor2 *tor = (struct tor2 *)data; tor->taskletrun++; if (tor->taskletpending) { tor->taskletexec++; tor2_run(tor); } tor->taskletpending = 0; } #endif static int syncsrc = 0; static int syncnum = 0 /* -1 */; static int syncspan = 0; static DEFINE_SPINLOCK(synclock); static int tor2_findsync(struct tor2 *tor) { int i; int x; unsigned long flags; int p; int nonzero; int newsyncsrc = 0; /* DAHDI span number */ int newsyncnum = 0; /* tor2 card number */ int newsyncspan = 0; /* span on given tor2 card */ spin_lock_irqsave(&synclock, flags); #if 1 if (!tor->num) { /* If we're the first card, go through all the motions, up to 8 levels of sync source */ p = 1; while (p < 8) { nonzero = 0; for (x=0;cards[x];x++) { for (i = 0; i < SPANS_PER_CARD; i++) { if (cards[x]->syncpos[i]) { nonzero = 1; if ((cards[x]->syncpos[i] == p) && !(cards[x]->tspans[i].dahdi_span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK)) && (cards[x]->tspans[i].dahdi_span.flags & DAHDI_FLAG_RUNNING)) { /* This makes a good sync source */ newsyncsrc = cards[x]->tspans[i].dahdi_span.spanno; newsyncnum = x; newsyncspan = i + 1; /* Jump out */ goto found; } } } } if (nonzero) p++; else break; } found: if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) { syncnum = newsyncnum; syncsrc = newsyncsrc; syncspan = newsyncspan; if (debug) printk(KERN_DEBUG "New syncnum: %d, syncsrc: %d, syncspan: %d\n", syncnum, syncsrc, syncspan); } } #endif /* update sync src info */ if (tor->syncsrc != syncsrc) { tor->syncsrc = syncsrc; /* Update sync sources */ for (i = 0; i < SPANS_PER_CARD; i++) { tor->tspans[i].dahdi_span.syncsrc = tor->syncsrc; } if (syncnum == tor->num) { #if 1 /* actually set the sync register */ writeb(syncspan, &tor->mem8[SYNCREG]); #endif if (debug) printk(KERN_DEBUG "Card %d, using sync span %d, master\n", tor->num, syncspan); tor->master = MASTER; } else { #if 1 /* time from the timing cable */ writeb(SYNCEXTERN, &tor->mem8[SYNCREG]); #endif tor->master = 0; if (debug) printk(KERN_DEBUG "Card %d, using Timing Bus, NOT master\n", tor->num); } } spin_unlock_irqrestore(&synclock, flags); return 0; } DAHDI_IRQ_HANDLER(tor2_intr) { int n, i, j, k, newsyncsrc; unsigned int rxword,txword; unsigned char c, rxc; unsigned char abits, bbits; struct tor2 *tor = (struct tor2 *) dev_id; /* make sure its a real interrupt for us */ if (!(readb(&tor->mem8[STATREG]) & INTACTIVE)) /* if not, just return */ { return IRQ_NONE; } if (tor->cardtype == TYPE_E1) { /* set outbit, interrupt enable, and ack interrupt */ writeb(OUTBIT | INTENA | INTACK | E1DIV | tor->master, &tor->mem8[CTLREG]); } else { /* set outbit, interrupt enable, and ack interrupt */ writeb(OUTBIT | INTENA | INTACK | tor->master, &tor->mem8[CTLREG]); } #if 0 if (!tor->passno) printk(KERN_DEBUG "Interrupt handler\n"); #endif /* do the transmit output */ for (n = 0; n < tor->tspans[0].dahdi_span.channels; n++) { for (i = 0; i < DAHDI_CHUNKSIZE; i++) { /* span 1 */ txword = tor->tspans[0].dahdi_span.chans[n]->writechunk[i] << 24; /* span 2 */ txword |= tor->tspans[1].dahdi_span.chans[n]->writechunk[i] << 16; /* span 3 */ txword |= tor->tspans[2].dahdi_span.chans[n]->writechunk[i] << 8; /* span 4 */ txword |= tor->tspans[3].dahdi_span.chans[n]->writechunk[i]; /* write to part */ #ifdef FIXTHISFOR64 tor->mem32[tor->datxlt[n] + (32 * i)] = txword; #else writel(txword, &tor->mem32[tor->datxlt[n] + (32 * i)]); #endif } } /* Do the receive input */ for (n = 0; n < tor->tspans[0].dahdi_span.channels; n++) { for (i = 0; i < DAHDI_CHUNKSIZE; i++) { /* read from */ #ifdef FIXTHISFOR64 rxword = tor->mem32[tor->datxlt[n] + (32 * i)]; #else rxword = readl(&tor->mem32[tor->datxlt[n] + (32 * i)]); #endif /* span 1 */ tor->tspans[0].dahdi_span.chans[n]->readchunk[i] = rxword >> 24; /* span 2 */ tor->tspans[1].dahdi_span.chans[n]->readchunk[i] = (rxword & 0xff0000) >> 16; /* span 3 */ tor->tspans[2].dahdi_span.chans[n]->readchunk[i] = (rxword & 0xff00) >> 8; /* span 4 */ tor->tspans[3].dahdi_span.chans[n]->readchunk[i] = rxword & 0xff; } } i = tor->passno & 15; /* if an E1 card, do rx signalling for it */ if ((i < 3) && (tor->cardtype == TYPE_E1)) { /* if an E1 card */ for (j = (i * 5); j < (i * 5) + 5; j++) { for (k = 1; k <= SPANS_PER_CARD; k++) { c = t1in(tor,k,0x31 + j); rxc = c & 15; if (rxc != tor->tspans[k - 1].dahdi_span.chans[j + 16]->rxsig) { /* Check for changes in received bits */ if (!(tor->tspans[k - 1].dahdi_span.chans[j + 16]->sig & DAHDI_SIG_CLEAR)) dahdi_rbsbits(tor->tspans[k - 1].dahdi_span.chans[j + 16], rxc); } rxc = c >> 4; if (rxc != tor->tspans[k - 1].dahdi_span.chans[j]->rxsig) { /* Check for changes in received bits */ if (!(tor->tspans[k - 1].dahdi_span.chans[j]->sig & DAHDI_SIG_CLEAR)) dahdi_rbsbits(tor->tspans[k - 1].dahdi_span.chans[j], rxc); } } } } /* if a T1, do the signalling */ if ((i < 12) && (tor->cardtype == TYPE_T1)) { k = (i / 3); /* get span */ n = (i % 3); /* get base */ abits = t1in(tor,k + 1, 0x60 + n); bbits = t1in(tor,k + 1, 0x63 + n); for (j=0; j< 8; j++) { /* Get channel number */ i = (n * 8) + j; rxc = 0; if (abits & (1 << j)) rxc |= DAHDI_ABIT; if (bbits & (1 << j)) rxc |= DAHDI_BBIT; if (tor->tspans[k].dahdi_span.chans[i]->rxsig != rxc) { /* Check for changes in received bits */ if (!(tor->tspans[k].dahdi_span.chans[i]->sig & DAHDI_SIG_CLEAR)) dahdi_rbsbits(tor->tspans[k].dahdi_span.chans[i], rxc); } } } for (i = 0; i < SPANS_PER_CARD; i++) { /* Go thru all the spans */ /* if alarm timer, and it's timed out */ if (tor->alarmtimer[i]) { if (!--tor->alarmtimer[i]) { /* clear recover status */ tor->tspans[i].dahdi_span.alarms &= ~DAHDI_ALARM_RECOVER; if (tor->cardtype == TYPE_E1) t1out(tor,i + 1,0x21,0x5f); /* turn off yel */ else t1out(tor,i + 1,0x35,0x10); /* turn off yel */ dahdi_alarm_notify(&tor->tspans[i].dahdi_span); /* let them know */ } } } i = tor->passno & 15; if ((i >= 10) && (i <= 13) && !(tor->passno & 0x30)) { j = 0; /* clear this alarm status */ i -= 10; if (tor->cardtype == TYPE_T1) { c = t1in(tor,i + 1,0x31); /* get RIR2 */ tor->tspans[i].dahdi_span.rxlevel = c >> 6; /* get rx level */ t1out(tor,i + 1,0x20,0xff); c = t1in(tor,i + 1,0x20); /* get the status */ /* detect the code, only if we are not sending one */ if ((!tor->tspans[i].dahdi_span.mainttimer) && (c & 0x80)) /* if loop-up code detected */ { /* set into remote loop, if not there already */ if ((tor->loopupcnt[i]++ > 80) && (tor->tspans[i].dahdi_span.maintstat != DAHDI_MAINT_REMOTELOOP)) { t1out(tor,i + 1,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */ t1out(tor,i + 1,0x0a,0x40); /* remote loop */ tor->tspans[i].dahdi_span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else tor->loopupcnt[i] = 0; /* detect the code, only if we are not sending one */ if ((!tor->tspans[i].dahdi_span.mainttimer) && (c & 0x40)) /* if loop-down code detected */ { /* if in remote loop, get out of it */ if ((tor->loopdowncnt[i]++ > 80) && (tor->tspans[i].dahdi_span.maintstat == DAHDI_MAINT_REMOTELOOP)) { t1out(tor,i + 1,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */ t1out(tor,i + 1,0x0a,0); /* no remote loop */ tor->tspans[i].dahdi_span.maintstat = DAHDI_MAINT_NONE; } } else tor->loopdowncnt[i] = 0; if (c & 3) /* if red alarm */ { j |= DAHDI_ALARM_RED; } if (c & 8) /* if blue alarm */ { j |= DAHDI_ALARM_BLUE; } } else { /* its an E1 card */ t1out(tor,i + 1,6,0xff); c = t1in(tor,i + 1,6); /* get the status */ if (c & 9) /* if red alarm */ { j |= DAHDI_ALARM_RED; } if (c & 2) /* if blue alarm */ { j |= DAHDI_ALARM_BLUE; } } /* only consider previous carrier alarm state */ tor->tspans[i].dahdi_span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); n = 1; /* set to 1 so will not be in yellow alarm if we dont care about open channels */ /* if to have yellow alarm if nothing open */ if (tor->tspans[i].dahdi_span.lineconfig & DAHDI_CONFIG_NOTOPEN) { /* go thru all chans, and count # open */ for (n = 0, k = 0; k < tor->tspans[i].dahdi_span.channels; k++) { if (((tor->chans[i][k])->flags & DAHDI_FLAG_OPEN) || dahdi_have_netdev(tor->chans[i][k])) n++; } /* if none open, set alarm condition */ if (!n) j |= DAHDI_ALARM_NOTOPEN; } /* if no more alarms, and we had some */ if ((!j) && tor->tspans[i].dahdi_span.alarms) tor->alarmtimer[i] = DAHDI_ALARMSETTLE_TIME; if (tor->alarmtimer[i]) j |= DAHDI_ALARM_RECOVER; /* if going into alarm state, set yellow alarm */ if ((j) && (!tor->tspans[i].dahdi_span.alarms)) { if (tor->cardtype == TYPE_E1) t1out(tor,i + 1,0x21,0x7f); else t1out(tor,i + 1,0x35,0x11); } if (c & 4) /* if yellow alarm */ j |= DAHDI_ALARM_YELLOW; if (tor->tspans[i].dahdi_span.maintstat || tor->tspans[i].dahdi_span.mainttimer) j |= DAHDI_ALARM_LOOPBACK; tor->tspans[i].dahdi_span.alarms = j; c = (LEDRED | LEDGREEN) << (2 * i); tor->leds &= ~c; /* mask out bits for this span */ /* light LED's if span configured and running */ if (tor->tspans[i].dahdi_span.flags & DAHDI_FLAG_RUNNING) { if (j & DAHDI_ALARM_RED) tor->leds |= LEDRED << (2 * i); else if (j & DAHDI_ALARM_YELLOW) tor->leds |= (LEDRED | LEDGREEN) << (2 * i); else tor->leds |= LEDGREEN << (2 * i); } writeb(tor->leds, &tor->mem8[LEDREG]); dahdi_alarm_notify(&tor->tspans[i].dahdi_span); } if (!(tor->passno % 1000)) /* even second boundary */ { /* do all spans */ for (i = 1; i <= SPANS_PER_CARD; i++) { if (tor->cardtype == TYPE_E1) { /* add this second's BPV count to total one */ tor->tspans[i - 1].dahdi_span.count.bpv += t1in(tor, i, 1) + (t1in(tor, i, 0)<<8); if (tor->tspans[i - 1].dahdi_span.lineconfig & DAHDI_CONFIG_CRC4) { tor->tspans[i - 1].dahdi_span.count.crc4 += t1in(tor, i, 3) + ((t1in(tor, i, 2) & 3) << 8); tor->tspans[i - 1].dahdi_span.count.ebit += t1in(tor, i, 5) + ((t1in(tor, i, 4) & 3) << 8); } tor->tspans[i - 1].dahdi_span.count.fas += (t1in(tor, i, 4) >> 2) + ((t1in(tor, i, 2) & 0x3F) << 6); } else { /* add this second's BPV count to total one */ tor->tspans[i - 1].dahdi_span.count.bpv += t1in(tor, i, 0x24) + (t1in(tor, i, 0x23) << 8); } } } if (!timingcable) { /* re-evaluate active sync src (no cable version) */ tor->syncsrc = 0; newsyncsrc = 0; /* if primary sync specified, see if we can use it */ if (tor->psyncs[0]) { /* if no alarms, use it */ if (!(tor->tspans[tor->psyncs[0] - 1].dahdi_span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK))) { tor->syncsrc = tor->psyncs[0]; newsyncsrc = tor->syncs[0]; } } /* if any others specified, see if we can use them */ for (i = 1; i < SPANS_PER_CARD; i++) { /* if we dont have one yet, and there is one specified at this level, see if we can use it */ if ((!tor->syncsrc) && (tor->psyncs[i])) { /* if no alarms, use it */ if (!(tor->tspans[tor->psyncs[i] - 1].dahdi_span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK))) { tor->syncsrc = tor->psyncs[i]; newsyncsrc = tor->syncs[i]; } } } /* update sync src info */ for (i = 0; i < SPANS_PER_CARD; i++) tor->tspans[i].dahdi_span.syncsrc = newsyncsrc; /* actually set the sync register */ writeb(tor->syncsrc, &tor->mem8[SYNCREG]); } else /* Timing cable version */ tor2_findsync(tor); tor->passno++; #ifdef ENABLE_TASKLETS if (!tor->taskletpending) { tor->taskletpending = 1; tor->taskletsched++; tasklet_hi_schedule(&tor->tor2_tlet); } else { tor->txerrors++; } #else tor2_run(tor); #endif /* We are not the timing bus master */ if (tor->cardtype == TYPE_E1) /* clear OUTBIT and enable interrupts */ writeb(INTENA | E1DIV | tor->master, &tor->mem8[CTLREG]); else /* clear OUTBIT and enable interrupts */ writeb(INTENA | tor->master, &tor->mem8[CTLREG]); return IRQ_RETVAL(1); } static int tor2_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { switch(cmd) { default: return -ENOTTY; } return 0; } MODULE_AUTHOR("Mark Spencer"); MODULE_DESCRIPTION("Tormenta 2 PCI Quad T1 or E1 DAHDI Driver"); MODULE_LICENSE("GPL v2"); module_param(debug, int, 0600); module_param(loopback, int, 0600); module_param(timingcable, int, 0600); module_param(japan, int, 0600); MODULE_DEVICE_TABLE(pci, tor2_pci_ids); module_init(tor2_init); module_exit(tor2_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/0000755000175000017500000000000011631523354017350 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_pri.h0000644000175000017500000000167710751714440021317 0ustar tzafrirtzafrir#ifndef CARD_PRI_H #define CARD_PRI_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" enum pri_opcodes { XPROTO_NAME(PRI, SET_LED) = 0x33, }; #endif /* CARD_PRI_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/init_card_5_300000755000175000017500000000005511603166347021764 0ustar tzafrirtzafrir#!/bin/true # ATM this script does nothing. dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_global.c0000644000175000017500000004774011566461444021771 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include "xdefs.h" #include "xpd.h" #include "xpp_dahdi.h" #include "xproto.h" #include "dahdi_debug.h" #include "xbus-core.h" #include "parport_debug.h" static const char rcsid[] = "$Id: card_global.c 9916 2011-05-23 13:37:40Z tzafrir $"; DEF_PARM(charp,initdir, "/usr/share/dahdi", 0644, "The directory of card initialization scripts"); #define CHIP_REGISTERS "chipregs" extern int debug; /*---------------- GLOBAL PROC handling -----------------------------------*/ static int parse_hexbyte(const char *buf) { char *endp; unsigned val; val = simple_strtoul(buf, &endp, 16); if(*endp != '\0' || val > 0xFF) return -EBADR; return (byte)val; } static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[]) { int argno; char num_args; int portno; bool writing; int op; /* [W]rite, [R]ead */ int addr_mode; /* [D]irect, [I]ndirect, [Mm]ulti */ bool do_subreg = 0; int regnum; int subreg; int data_low; bool do_datah; int data_high; int ret = -EBADR; num_args = 2; /* port + operation */ if(argc < num_args) { XPD_ERR(xpd, "Not enough arguments (%d)\n", argc); XPD_ERR(xpd, "Any Command is composed of at least %d words (got only %d)\n", num_args, argc); goto out; } /* Process the arguments */ argno = 0; if(strcmp(argv[argno], "*") == 0) { portno = PORT_BROADCAST; //XPD_DBG(REGS, xpd, "Port broadcast\n"); } else { portno = parse_hexbyte(argv[argno]); if(portno < 0 || portno >= 8) { XPD_ERR(xpd, "Illegal port number '%s'\n", argv[argno]); goto out; } //XPD_DBG(REGS, xpd, "Port is %d\n", portno); } argno++; if(strlen(argv[argno]) != 2) { XPD_ERR(xpd, "Wrong operation codes '%s'\n", argv[argno]); goto out; } op = argv[argno][0]; switch(op) { case 'W': writing = 1; num_args++; /* data low */ //XPD_DBG(REGS, xpd, "WRITING\n"); break; case 'R': writing = 0; //XPD_DBG(REGS, xpd, "READING\n"); break; default: XPD_ERR(xpd, "Unknown operation type '%c'\n", op); goto out; } addr_mode = argv[argno][1]; switch(addr_mode) { case 'I': XPD_NOTICE(xpd, "'I' is deprecated in register commands. Use 'S' instead.\n"); /* fall through */ case 'S': do_subreg = 1; num_args += 2; /* register + subreg */ //XPD_DBG(REGS, xpd, "SUBREG\n"); break; case 'D': do_subreg = 0; num_args++; /* register */ //XPD_DBG(REGS, xpd, "DIRECT\n"); break; case 'M': case 'm': if(op != 'W') { XPD_ERR(xpd, "Can use Multibyte (%c) only with op 'W'\n", addr_mode); goto out; } num_args--; /* No data low */ //XPD_DBG(REGS, xpd, "Multibyte (%c)\n", addr_mode); break; default: XPD_ERR(xpd, "Unknown addressing type '%c'\n", addr_mode); goto out; } if(argv[argno][2] != '\0') { XPD_ERR(xpd, "Bad operation field '%s'\n", argv[argno]); goto out; } if(argc < num_args) { XPD_ERR(xpd, "Command \"%s\" is composed of at least %d words (got only %d)\n", argv[argno], num_args, argc); goto out; } argno++; if(addr_mode == 'M' || addr_mode == 'm') { if(argno < argc) { XPD_ERR(xpd, "Magic-Multibyte(%c) with %d extra arguments\n", addr_mode, argc - argno); goto out; } ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, portno, addr_mode == 'm', NULL, 0); goto out; } /* Normal (non-Magic) register commands */ do_datah = 0; if(argno >= argc) { XPD_ERR(xpd, "Missing register number\n"); goto out; } regnum = parse_hexbyte(argv[argno]); if(regnum < 0) { XPD_ERR(xpd, "Illegal register number '%s'\n", argv[argno]); goto out; } //XPD_DBG(REGS, xpd, "Register is %X\n", regnum); argno++; if(do_subreg) { if(argno >= argc) { XPD_ERR(xpd, "Missing subregister number\n"); goto out; } subreg = parse_hexbyte(argv[argno]); if(subreg < 0) { XPD_ERR(xpd, "Illegal subregister number '%s'\n", argv[argno]); goto out; } //XPD_DBG(REGS, xpd, "Subreg is %X\n", subreg); argno++; } else subreg = 0; if(writing) { if(argno >= argc) { XPD_ERR(xpd, "Missing data low number\n"); goto out; } data_low = parse_hexbyte(argv[argno]); if(data_low < 0) { XPD_ERR(xpd, "Illegal data_low number '%s'\n", argv[argno]); goto out; } //XPD_DBG(REGS, xpd, "Data Low is %X\n", data_low); argno++; } else data_low = 0; if(argno < argc) { do_datah = 1; if(!argv[argno]) { XPD_ERR(xpd, "Missing data high number\n"); goto out; } data_high = parse_hexbyte(argv[argno]); if(data_high < 0) { XPD_ERR(xpd, "Illegal data_high number '%s'\n", argv[argno]); goto out; } //XPD_DBG(REGS, xpd, "Data High is %X\n", data_high); argno++; } else data_high = 0; if(argno < argc) { XPD_ERR(xpd, "Command contains an extra %d argument\n", argc - argno); goto out; } #if 0 XPD_DBG(REGS, xpd, "portno=%d writing=%d regnum=%d do_subreg=%d subreg=%d dataL=%d do_datah=%d dataH=%d\n", portno, /* portno */ writing, /* writing */ regnum, do_subreg, /* use subreg */ subreg, /* subreg */ data_low, do_datah, /* use data_high*/ data_high); #endif ret = xpp_register_request(xpd->xbus, xpd, portno, writing, regnum, do_subreg, subreg, data_low, do_datah, data_high, 1); out: return ret; } int parse_chip_command(xpd_t *xpd, char *cmdline) { xbus_t *xbus; int ret = -EBADR; byte buf[MAX_PROC_WRITE]; char *str; char *p; static const int MAX_ARGS = 10; char *argv[MAX_ARGS + 1]; int argc; int i; BUG_ON(!xpd); xbus = xpd->xbus; if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_DBG(GENERAL, xbus, "Dropped packet. Disconnected.\n"); return -EBUSY; } strlcpy(buf, cmdline, MAX_PROC_WRITE); /* Save a copy */ if(buf[0] == '#' || buf[0] == ';') XPD_DBG(REGS, xpd, "Note: '%s'\n", buf); if((p = strchr(buf, '#')) != NULL) /* Truncate comments */ *p = '\0'; if((p = strchr(buf, ';')) != NULL) /* Truncate comments */ *p = '\0'; for(p = buf; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ ; str = p; for(i = 0; (p = strsep(&str, " \t")) != NULL && i < MAX_ARGS; ) { if(*p != '\0') { argv[i] = p; // XPD_DBG(REGS, xpd, "ARG %d = '%s'\n", i, p); i++; } } argv[i] = NULL; argc = i; if(p) { XPD_ERR(xpd, "Too many words (%d) to process. Last was '%s'\n", i, p); goto out; } if(argc) ret = execute_chip_command(xpd, argc, argv); else ret = 0; /* empty command - no op */ out: return ret; } /*---------------- GLOBAL Protocol Commands -------------------------------*/ static bool global_packet_is_valid(xpacket_t *pack); static void global_packet_dump(const char *msg, xpacket_t *pack); /*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/ /* 0x07 */ HOSTCMD(GLOBAL, AB_REQUEST) { int ret = -ENODEV; xframe_t *xframe; xpacket_t *pack; if(!xbus) { DBG(DEVICES, "NO XBUS\n"); return -EINVAL; } if (xbus_check_unique(xbus)) return -EBUSY; XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, AB_REQUEST, 0); RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, rev) = XPP_PROTOCOL_VERSION; RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, reserved) = 0; XBUS_DBG(DEVICES, xbus, "Protocol Version %d\n", XPP_PROTOCOL_VERSION); if(xbus_setstate(xbus, XBUS_STATE_SENT_REQUEST)) ret = send_cmd_frame(xbus, xframe); return ret; } int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno, bool writing, byte regnum, bool do_subreg, byte subreg, byte data_low, bool do_datah, byte data_high, bool should_reply) { int ret = 0; xframe_t *xframe; xpacket_t *pack; reg_cmd_t *reg_cmd; if(!xbus) { DBG(REGS, "NO XBUS\n"); return -EINVAL; } XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx); LINE_DBG(REGS, xpd, portno, "%c%c %02X %02X %02X %02X\n", (writing)?'W':'R', (do_subreg)?'S':'D', regnum, subreg, data_low, data_high); reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd); reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field reg_cmd->is_multibyte = 0; if(portno == PORT_BROADCAST) { reg_cmd->portnum = 0; REG_FIELD(reg_cmd, all_ports_broadcast) = 1; } else { reg_cmd->portnum = portno; REG_FIELD(reg_cmd, all_ports_broadcast) = 0; } reg_cmd->eoframe = 0; REG_FIELD(reg_cmd, reserved) = 0; /* force reserved bits to 0 */ REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1; REG_FIELD(reg_cmd, do_subreg) = do_subreg; REG_FIELD(reg_cmd, regnum) = regnum; REG_FIELD(reg_cmd, subreg) = subreg; REG_FIELD(reg_cmd, do_datah) = do_datah; REG_FIELD(reg_cmd, data_low) = data_low; REG_FIELD(reg_cmd, data_high) = data_high; if(should_reply) xpd->requested_reply = *reg_cmd; if(debug & DBG_REGS) { dump_reg_cmd("REG_REQ", 1, xbus, xpd->addr.unit, reg_cmd->portnum, reg_cmd); dump_packet("REG_REQ", pack, 1); } if(!xframe->usec_towait) { /* default processing time of SPI */ if(subreg) xframe->usec_towait = 2000; else xframe->usec_towait = 1000; } ret = send_cmd_frame(xbus, xframe); return ret; } int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno, bool eoftx, byte *buf, unsigned len) { xframe_t *xframe; xpacket_t *pack; reg_cmd_t *reg_cmd; int ret; /* * Zero length multibyte is legal and has special meaning for the * firmware: * eoftx==1: Start sending us D-channel packets. * eoftx==0: Stop sending us D-channel packets. */ if(len > MULTIBYTE_MAX_LEN) { PORT_ERR(xbus, unit, portno, "%s: len=%d is too long. dropping.\n", __FUNCTION__, len); return -EINVAL; } XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, unit); reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd); reg_cmd->bytes = len; reg_cmd->is_multibyte = 1; reg_cmd->portnum = portno; reg_cmd->eoframe = eoftx; if(len > 0) { memcpy(REG_XDATA(reg_cmd), (byte *)buf, len); } else { PORT_DBG(REGS, xbus, unit, portno, "Magic Packet (eoftx=%d)\n", eoftx); } if(debug & DBG_REGS) dump_xframe(__FUNCTION__, xbus, xframe, debug); ret = send_cmd_frame(xbus, xframe); if(ret < 0) PORT_ERR(xbus, unit, portno, "%s: failed sending xframe\n", __FUNCTION__); return ret; } /* * The XPD parameter is totaly ignored by the driver and firmware as well. */ /* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift) { xframe_t *xframe; xpacket_t *pack; const char *mode_name; BUG_ON(!xbus); if((mode_name = sync_mode_name(mode)) == NULL) { XBUS_ERR(xbus, "SYNC_SOURCE: bad sync_mode=0x%X\n", mode); return -EINVAL; } XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift); XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, SYNC_SOURCE, 0); RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, sync_mode) = mode; RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, drift) = drift; send_cmd_frame(xbus, xframe); return 0; } /* 0x23 */ HOSTCMD(GLOBAL, RESET_SYNC_COUNTERS) { xframe_t *xframe; xpacket_t *pack; BUG_ON(!xbus); //XBUS_DBG(SYNC, xbus, "\n"); XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, RESET_SYNC_COUNTERS, 0); RPACKET_FIELD(pack, GLOBAL, RESET_SYNC_COUNTERS, mask) = 0x10; send_cmd_frame(xbus, xframe); return 0; } /*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/ HANDLER_DEF(GLOBAL, NULL_REPLY) { XBUS_DBG(GENERAL, xbus, "got len=%d\n", XPACKET_LEN(pack)); return 0; } HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ { struct xbus_workqueue *worker; byte rev; struct unit_descriptor *units; int count_units; int i; int ret = 0; if (!xbus) { NOTICE("%s: xbus is gone!!!\n", __func__); goto out; } rev = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, rev); units = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, unit_descriptor); count_units = XPACKET_LEN(pack) - ((byte *)units - (byte *)pack); count_units /= sizeof(*units); if(rev != XPP_PROTOCOL_VERSION) { XBUS_NOTICE(xbus, "Bad protocol version %d (should be %d)\n", rev, XPP_PROTOCOL_VERSION); ret = -EPROTO; goto proto_err; } if(count_units > NUM_UNITS) { XBUS_NOTICE(xbus, "Too many units %d (should be %d)\n", count_units, NUM_UNITS); ret = -EPROTO; goto proto_err; } if(count_units <= 0) { XBUS_NOTICE(xbus, "Empty astribank? (%d units)\n", count_units); ret = -EPROTO; goto proto_err; } if(!xbus_setstate(xbus, XBUS_STATE_RECVD_DESC)) { ret = -EPROTO; goto proto_err; } XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev); if (xbus_check_unique(xbus)) return -EBUSY; xbus->revision = rev; worker = &xbus->worker; if (!worker->wq) { XBUS_ERR(xbus, "missing worker thread\n"); ret = -ENODEV; goto out; } for(i = 0; i < count_units; i++) { struct unit_descriptor *this_unit = &units[i]; struct card_desc_struct *card_desc; unsigned long flags; if((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) { XBUS_ERR(xbus, "Card description allocation failed.\n"); ret = -ENOMEM; goto out; } card_desc->magic = CARD_DESC_MAGIC; INIT_LIST_HEAD(&card_desc->card_list); card_desc->type = this_unit->type; card_desc->subtype = this_unit->subtype; card_desc->xpd_addr = this_unit->addr; card_desc->numchips = this_unit->numchips; card_desc->ports_per_chip = this_unit->ports_per_chip; card_desc->port_dir = this_unit->port_dir; card_desc->ports = card_desc->numchips * card_desc->ports_per_chip; XBUS_INFO(xbus, " CARD %d type=%d.%d ports=%d (%dx%d), port-dir=0x%02X\n", card_desc->xpd_addr.unit, card_desc->type, card_desc->subtype, card_desc->ports, card_desc->numchips, card_desc->ports_per_chip, card_desc->port_dir ); spin_lock_irqsave(&worker->worker_lock, flags); worker->num_units++; XBUS_COUNTER(xbus, UNITS)++; list_add_tail(&card_desc->card_list, &worker->card_list); spin_unlock_irqrestore(&worker->worker_lock, flags); } if (!xbus_process_worker(xbus)) { ret = -ENODEV; goto out; } goto out; proto_err: dump_packet("AB_DESCRIPTION", pack, DBG_ANY); out: return ret; } HANDLER_DEF(GLOBAL, REGISTER_REPLY) { reg_cmd_t *reg = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REPLY, regcmd); if(!xpd) { static int rate_limit; if((rate_limit++ % 1003) < 5) notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), ""); return -EPROTO; } if(debug & DBG_REGS) { dump_reg_cmd("REG_REPLY", 0, xbus, xpd->addr.unit, reg->portnum, reg); dump_packet("REG_REPLY", pack, 1); } if (! XMETHOD(card_register_reply, xpd)) { XPD_ERR(xpd, "REGISTER_REPLY: without card_register_reply() method\n"); return -EINVAL; } return CALL_XMETHOD(card_register_reply, xpd, reg); } HANDLER_DEF(GLOBAL, SYNC_REPLY) { byte mode = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, sync_mode); byte drift = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, drift); const char *mode_name; BUG_ON(!xbus); if((mode_name = sync_mode_name(mode)) == NULL) { XBUS_ERR(xbus, "SYNC_REPLY: bad sync_mode=0x%X\n", mode); return -EINVAL; } XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift); //dump_packet("SYNC_REPLY", pack, debug & DBG_SYNC); got_new_syncer(xbus, mode, drift); return 0; } #define TMP_NAME_LEN (XBUS_NAMELEN + XPD_NAMELEN + 5) HANDLER_DEF(GLOBAL, ERROR_CODE) { char tmp_name[TMP_NAME_LEN]; static long rate_limit; byte category_code; byte errorbits; BUG_ON(!xbus); if((rate_limit++ % 5003) > 200) return 0; category_code = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, category_code); errorbits = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorbits); if(!xpd) { snprintf(tmp_name, TMP_NAME_LEN, "%s(%1d%1d)", xbus->busname, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); } else { snprintf(tmp_name, TMP_NAME_LEN, "%s/%s", xbus->busname, xpd->xpdname); } NOTICE("%s: FIRMWARE %s: category=%d errorbits=0x%02X (rate_limit=%ld)\n", tmp_name, cmd->name, category_code, errorbits, rate_limit); dump_packet("FIRMWARE: ", pack, 1); /* * FIXME: Should implement an error recovery plan */ return 0; } xproto_table_t PROTO_TABLE(GLOBAL) = { .entries = { /* Prototable Card Opcode */ XENTRY( GLOBAL, GLOBAL, NULL_REPLY ), XENTRY( GLOBAL, GLOBAL, AB_DESCRIPTION ), XENTRY( GLOBAL, GLOBAL, SYNC_REPLY ), XENTRY( GLOBAL, GLOBAL, ERROR_CODE ), XENTRY( GLOBAL, GLOBAL, REGISTER_REPLY ), }, .name = "GLOBAL", .packet_is_valid = global_packet_is_valid, .packet_dump = global_packet_dump, }; static bool global_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe; //DBG(GENERAL, "\n"); xe = xproto_global_entry(XPACKET_OP(pack)); return xe != NULL; } static void global_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } #define MAX_ENV_STR 40 #define MAX_PATH_STR 128 int run_initialize_registers(xpd_t *xpd) { int ret; xbus_t *xbus; char busstr[MAX_ENV_STR]; char busnumstr[MAX_ENV_STR]; char unitstr[MAX_ENV_STR]; char subunitsstr[MAX_ENV_STR]; char typestr[MAX_ENV_STR]; char directionstr[MAX_ENV_STR]; char revstr[MAX_ENV_STR]; char connectorstr[MAX_ENV_STR]; char xbuslabel[MAX_ENV_STR]; char init_card[MAX_PATH_STR]; byte direction_mask; int i; char *argv[] = { init_card, NULL }; char *envp[] = { busstr, busnumstr, unitstr, subunitsstr, typestr, directionstr, revstr, connectorstr, xbuslabel, NULL }; BUG_ON(!xpd); xbus = xpd->xbus; if(!initdir || !initdir[0]) { XPD_NOTICE(xpd, "Missing initdir parameter\n"); ret = -EINVAL; goto err; } if(!xpd_setstate(xpd, XPD_STATE_INIT_REGS)) { ret = -EINVAL; goto err; } direction_mask = 0; for(i = 0; i < xpd->subunits; i++) { xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i); if(!su) { XPD_ERR(xpd, "Have %d subunits, but not subunit #%d\n", xpd->subunits, i); continue; } direction_mask |= (PHONEDEV(su).direction == TO_PHONE) ? BIT(i) : 0; } snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname); snprintf(busnumstr, MAX_ENV_STR, "XBUS_NUMBER=%d", xbus->num); snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit); snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type); snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits); snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d", direction_mask); snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision); snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->connector); snprintf(xbuslabel, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label); if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d", initdir, xpd->type, xbus->revision) > MAX_PATH_STR) { XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR); ret = -E2BIG; goto err; } if(!XBUS_IS(xbus, RECVD_DESC)) { XBUS_ERR(xbus, "Skipped register initialization. In state %s.\n", xbus_statename(XBUS_STATE(xbus))); ret = -ENODEV; goto err; } XPD_DBG(DEVICES, xpd, "running '%s' for type=%d revision=%d\n", init_card, xpd->type, xbus->revision); ret = call_usermodehelper(init_card, argv, envp, 1); /* * Carefully report results */ if(ret == 0) XPD_DBG(DEVICES, xpd, "'%s' finished OK\n", init_card); else if(ret < 0) { XPD_ERR(xpd, "Failed running '%s' (errno %d)\n", init_card, ret); } else { byte exitval = ((unsigned)ret >> 8) & 0xFF; byte sigval = ret & 0xFF; if(!exitval) { XPD_ERR(xpd, "'%s' killed by signal %d\n", init_card, sigval); } else { XPD_ERR(xpd, "'%s' aborted with exitval %d\n", init_card, exitval); } ret = -EINVAL; } err: return ret; } EXPORT_SYMBOL(sync_mode_name); EXPORT_SYMBOL(run_initialize_registers); EXPORT_SYMBOL(xpp_register_request); EXPORT_SYMBOL(send_multibyte_request); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xbus-pcm.c0000644000175000017500000010607111602416004021246 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2007, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include "xbus-pcm.h" #include "xbus-core.h" #include "xpp_dahdi.h" #include "dahdi_debug.h" #include "parport_debug.h" static const char rcsid[] = "$Id: xbus-pcm.c 9993 2011-06-28 18:23:00Z tzafrir $"; extern int debug; #ifdef OPTIMIZE_CHANMUTE static DEF_PARM_BOOL(optimize_chanmute, 1, 0644, "Optimize by muting inactive channels"); #endif static DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions"); #ifdef DEBUG_PCMTX DEF_PARM(int, pcmtx, -1, 0644, "Forced PCM value to transmit (negative to disable)"); DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value"); #endif static DEF_PARM_BOOL(disable_pll_sync, 0, 0644, "Disable automatic adjustment of AB clocks"); static xbus_t *syncer; /* current syncer */ static atomic_t xpp_tick_counter = ATOMIC_INIT(0); static struct xpp_ticker dahdi_ticker; /* * The ref_ticker points to the current referece tick source. * I.e: one of our AB or dahdi_ticker */ static struct xpp_ticker *ref_ticker = NULL; static DEFINE_SPINLOCK(ref_ticker_lock); static DEFINE_SPINLOCK(elect_syncer_lock); static bool force_dahdi_sync = 0; /* from /sys/bus/astribanks/drivers/xppdrv/sync */ static xbus_t *global_ticker; static struct xpp_ticker global_ticks_series; #define PROC_SYNC "sync" #define SYNC_CYCLE 500 /* Sampling cycle in usec */ #define SYNC_CYCLE_SAMPLE 100 /* Samples from end of SYNC_CYCLE */ #define SYNC_CONVERGE 10 /* Number of SYNC_CYCLE's to converge speed */ #define SYNC_CENTER 500 /* Offset from ref_ticker to other AB's */ #define SYNC_DELTA 40 /* If within +/-SYNC_DELTA, try to stay there */ #define BIG_TICK_INTERVAL 1000 #define SYNC_ADJ_MAX 20 /* maximal firmware drift unit (hardware limit 63) */ /* * The USB bulk endpoints have a large jitter in the timing of frames * from the AB to the ehci-hcd. This is because we cannot predict * in which USB micro-frame our data passes. Each micro-frame is * A 125 usec. */ #define SYNC_ADJ_QUICK 1000 #define SYNC_ADJ_SLOW 10000 #ifdef DAHDI_SYNC_TICK static unsigned int dahdi_tick_count = 0; #endif /*------------------------- SYNC Handling --------------------------*/ static void send_drift(xbus_t *xbus, int drift); static void ticker_set_cycle(struct xpp_ticker *ticker, int cycle) { unsigned long flags; spin_lock_irqsave(&ticker->lock, flags); if(cycle < SYNC_ADJ_QUICK) cycle = SYNC_ADJ_QUICK; if(cycle > SYNC_ADJ_SLOW) cycle = SYNC_ADJ_SLOW; ticker->cycle = cycle; spin_unlock_irqrestore(&ticker->lock, flags); } static void xpp_ticker_init(struct xpp_ticker *ticker) { memset(ticker, 0, sizeof(*ticker)); spin_lock_init(&ticker->lock); do_gettimeofday(&ticker->last_sample.tv); ticker->first_sample = ticker->last_sample; ticker_set_cycle(ticker, SYNC_ADJ_QUICK); } static int xpp_ticker_step(struct xpp_ticker *ticker, const struct timeval *t) { unsigned long flags; long usec; bool cycled = 0; spin_lock_irqsave(&ticker->lock, flags); ticker->last_sample.tv = *t; if((ticker->count % ticker->cycle) == ticker->cycle - 1) { /* rate adjust */ usec = (long)usec_diff( &ticker->last_sample.tv, &ticker->first_sample.tv); ticker->first_sample = ticker->last_sample; ticker->tick_period = usec / ticker->cycle; cycled = 1; } ticker->count++; spin_unlock_irqrestore(&ticker->lock, flags); return cycled; } /* * No locking. It is called only from: * - update_sync_master() in a globall spinlock protected code. * - initalization. */ static inline void xbus_drift_clear(xbus_t *xbus) { struct xpp_drift *di = &xbus->drift; do_gettimeofday(&di->last_lost_tick.tv); ticker_set_cycle(&xbus->ticker, SYNC_ADJ_QUICK); di->max_speed = -SYNC_ADJ_MAX; di->min_speed = SYNC_ADJ_MAX; } void xpp_drift_init(xbus_t *xbus) { memset(&xbus->drift, 0, sizeof(xbus->drift)); spin_lock_init(&xbus->drift.lock); xpp_ticker_init(&xbus->ticker); xbus_drift_clear(xbus); } #ifdef SAMPLE_TICKS static void sample_tick(xbus_t *xbus, int sample) { if(!xbus->sample_running) return; if(xbus->sample_pos < SAMPLE_SIZE) xbus->sample_ticks[xbus->sample_pos++] = sample; else { xbus->sample_running = 0; xbus->sample_pos = 0; } } #else #define sample_tick(x,y) #endif /* * The following function adjust the clock of an astribank according * to our reference clock (another astribank or another DAHDI device). * * It is VERY hard to stabilise these corrections: * - The measurments are affected by 125usec USB micro-frames. * - However, if we are off by more than +/-500usec we are risking * loosing frames. * * Every change must be tested rigorously with many device combinations * including abrupt changes in sync -- to verify the stability of the * algorithm. */ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv) { struct xpp_drift *di = &xbus->drift; struct xpp_ticker *ticker = &xbus->ticker; unsigned long flags; spin_lock_irqsave(&di->lock, flags); xpp_ticker_step(&xbus->ticker, tv); /* * Do we need to be synchronized and is there an established reference * ticker (another Astribank or another DAHDI device) already? */ if(ref_ticker && ref_ticker != &xbus->ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) { int new_delta_tick = ticker->count - ref_ticker->count; int lost_ticks = new_delta_tick - di->delta_tick; long usec_delta; di->delta_tick = new_delta_tick; if(lost_ticks) { static int rate_limit; /* * We just lost some ticks. Just report it and don't * try to adjust anything until we are stable again. */ di->lost_ticks++; di->lost_tick_count += abs(lost_ticks); if((rate_limit++ % 1003) == 0) { /* FIXME: This should be a NOTICE. * However we have several false ones at * startup. */ XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n", lost_ticks, (abs(lost_ticks) > 1) ? "s": ""); } if(abs(lost_ticks) > 100) { xbus_drift_clear(xbus); ticker->count = ref_ticker->count; } } else { /* Sample a delta */ usec_delta = (long)usec_diff( &ticker->last_sample.tv, &ref_ticker->last_sample.tv); sample_tick(xbus, usec_delta); if ((ticker->count % SYNC_CYCLE) > (SYNC_CYCLE - SYNC_CYCLE_SAMPLE)) di->delta_sum += usec_delta; if((ticker->count % SYNC_CYCLE) == 0) { /* * Full sampling cycle passed. Let's calculate */ int offset = di->delta_sum / SYNC_CYCLE_SAMPLE - SYNC_CENTER; int offset_prev = di->offset_prev; int speed = xbus->sync_adjustment; int fix = 0; int best_speed = (di->max_speed + di->min_speed) >> 1; if (offset > 0 && offset < SYNC_DELTA) { speed = best_speed - 1; } else if (offset < 0 && offset > -SYNC_DELTA) { speed = best_speed + 1; } else { if (offset > 0) { if (offset > offset_prev) fix--; } else { if (offset < offset_prev) fix++; } speed += fix; } if (speed < -SYNC_ADJ_MAX) speed = -SYNC_ADJ_MAX; if (speed > SYNC_ADJ_MAX) speed = SYNC_ADJ_MAX; if (speed < di->min_speed) di->min_speed = speed; if (speed > di->max_speed) di->max_speed = speed; if(offset > di->offset_max) di->offset_max = offset; if(offset < di->offset_min) di->offset_min = offset; XBUS_DBG(SYNC, xbus, "offset: %d, min_speed=%d, max_speed=%d, usec_delta(last)=%ld\n", offset_prev, di->min_speed, di->max_speed, usec_delta); XBUS_DBG(SYNC, xbus, "ADJ: speed=%d (best_speed=%d) fix=%d\n", speed, best_speed, fix); xbus->sync_adjustment_offset = speed; if(xbus != syncer && xbus->sync_adjustment != speed) send_drift(xbus, speed); di->sync_inaccuracy = abs(offset) + abs(di->offset_range) / 2; if(ticker->count >= SYNC_CYCLE * SYNC_CONVERGE) { di->offset_range = di->offset_max - di->offset_min; di->offset_min = INT_MAX; di->offset_max = -INT_MAX; if(di->max_speed > best_speed) di->max_speed--; if(di->min_speed < best_speed) di->min_speed++; } di->offset_prev = offset; di->delta_sum = 0; } } } spin_unlock_irqrestore(&di->lock, flags); } const char *sync_mode_name(enum sync_mode mode) { static const char *sync_mode_names[] = { [SYNC_MODE_AB] = "AB", [SYNC_MODE_NONE] = "NONE", [SYNC_MODE_PLL] = "PLL", [SYNC_MODE_QUERY] = "QUERY", }; if(mode >= ARRAY_SIZE(sync_mode_names)) return NULL; return sync_mode_names[mode]; } /* * Caller must aquire/release the 'ref_ticker_lock' spinlock */ static void xpp_set_syncer(xbus_t *xbus, bool on) { if(!xbus) { /* Special case, no more syncers */ DBG(SYNC, "No more syncers\n"); syncer = NULL; if(ref_ticker != &dahdi_ticker) ref_ticker = NULL; return; } if(syncer != xbus && on) { XBUS_DBG(SYNC, xbus, "New syncer\n"); syncer = xbus; } else if(syncer == xbus && !on) { XBUS_DBG(SYNC, xbus, "Lost syncer\n"); syncer = NULL; if(ref_ticker != &dahdi_ticker) ref_ticker = NULL; } else XBUS_DBG(SYNC, xbus, "ignore %s (current syncer: %s)\n", (on)?"ON":"OFF", (syncer) ? syncer->busname : "NO-SYNC"); } static void xbus_command_timer(unsigned long param) { xbus_t *xbus = (xbus_t *)param; struct timeval now; BUG_ON(!xbus); do_gettimeofday(&now); xbus_command_queue_tick(xbus); if(!xbus->self_ticking) mod_timer(&xbus->command_timer, jiffies + 1); /* Must be 1KHz rate */ } void xbus_set_command_timer(xbus_t *xbus, bool on) { XBUS_DBG(SYNC, xbus, "%s\n", (on)?"ON":"OFF"); if(on) { if(!timer_pending(&xbus->command_timer)) { XBUS_DBG(SYNC, xbus, "add_timer\n"); xbus->command_timer.function = xbus_command_timer; xbus->command_timer.data = (unsigned long)xbus; xbus->command_timer.expires = jiffies + 1; add_timer(&xbus->command_timer); } } else if(timer_pending(&xbus->command_timer)) { XBUS_DBG(SYNC, xbus, "del_timer\n"); del_timer(&xbus->command_timer); } xbus->self_ticking = ! on; } /* * Called when the Astribank replies to a sync change request */ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift) { unsigned long flags; unsigned long flags2; spin_lock_irqsave(&xbus->lock, flags); spin_lock_irqsave(&ref_ticker_lock, flags2); xbus->sync_adjustment = (signed char)drift; if(xbus->sync_mode == mode) { XBUS_DBG(SYNC, xbus, "Already in mode '%s'. Ignored\n", sync_mode_name(mode)); goto out; } XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n", sync_mode_name(mode), mode, drift, atomic_read(&xbus->pcm_rx_counter)); switch(mode) { case SYNC_MODE_AB: xbus->sync_mode = mode; xbus_set_command_timer(xbus, 0); xpp_set_syncer(xbus, 1); global_ticker = xbus; break; case SYNC_MODE_PLL: xbus->sync_mode = mode; xbus_set_command_timer(xbus, 0); xpp_set_syncer(xbus, 0); global_ticker = xbus; break; case SYNC_MODE_NONE: /* lost sync source */ xbus->sync_mode = mode; xbus_set_command_timer(xbus, 1); xpp_set_syncer(xbus, 0); break; case SYNC_MODE_QUERY: /* ignore */ break; default: XBUS_ERR(xbus, "%s: unknown mode=0x%X\n", __FUNCTION__, mode); } out: spin_unlock_irqrestore(&ref_ticker_lock, flags2); spin_unlock_irqrestore(&xbus->lock, flags); } void xbus_request_sync(xbus_t *xbus, enum sync_mode mode) { unsigned long flags; BUG_ON(!xbus); XBUS_DBG(SYNC, xbus, "sent request (mode=%d)\n", mode); CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, mode, 0); if(mode == SYNC_MODE_NONE) { /* * We must deselect the syncer *now* and not wait for the * reply from the AB. Otherwise, a disconnect of the syncing * AB would result in a corrupted 'syncer'. */ spin_lock_irqsave(&ref_ticker_lock, flags); xpp_set_syncer(xbus, 0); spin_unlock_irqrestore(&ref_ticker_lock, flags); /* * We must activate timer now since the commands go to * the command queue, and we should maintain something to * "tick" meanwhile until the AB get these commands and * start being "self_ticking". */ xbus_set_command_timer(xbus, 1); } } static void reset_sync_counters(void) { int i; //DBG(SYNC, "%d\n", atomic_read(&xpp_tick_counter)); for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(__func__, i); if (xbus == NULL) continue; /* * Don't send to non self_ticking Astribanks: * - Maybe they didn't finish initialization * - Or maybe they didn't answer us in the first place (e.g: wrong firmware version, etc). */ if(xbus->self_ticking) { if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); } else { /* Reset sync LEDs once in a while */ CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL); } } put_xbus(__func__, xbus); } } static void send_drift(xbus_t *xbus, int drift) { struct timeval now; const char *msg; BUG_ON(abs(drift) > SYNC_ADJ_MAX); do_gettimeofday(&now); if(drift > xbus->sync_adjustment) msg = "up"; else msg = "down"; XBUS_DBG(SYNC, xbus, "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n", (disable_pll_sync) ? "Fake " : "", msg, drift, now.tv_sec - xbus->pll_updated_at); if(!disable_pll_sync) CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift); xbus->pll_updated_at = now.tv_sec; } static void global_tick(void) { struct timeval now; do_gettimeofday(&now); atomic_inc(&xpp_tick_counter); if((atomic_read(&xpp_tick_counter) % BIG_TICK_INTERVAL) == 0) reset_sync_counters(); xpp_ticker_step(&global_ticks_series, &now); } #ifdef DAHDI_SYNC_TICK void dahdi_sync_tick(struct dahdi_span *span, int is_master) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); static int redundant_ticks; /* for extra spans */ struct timeval now; if(!force_dahdi_sync) goto noop; do_gettimeofday(&now); BUG_ON(!xpd); /* * Detect if any of our spans is dahdi sync master */ if(is_master) { static int rate_limit; if((rate_limit++ % 10003) == 0) XPD_NOTICE(xpd, "Is a DAHDI sync master: ignore sync from DAHDI\n"); goto noop; } /* Now we know for sure someone else is dahdi sync master */ if(syncer) { static int rate_limit; if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, syncer, "is a SYNCer: ignore sync from DAHDI\n"); goto noop; } /* ignore duplicate calls from all our registered spans */ if((redundant_ticks++ % total_registered_spans()) != 0) { #if 0 static int rate_limit; if((rate_limit++ % 1003) < 16) XPD_NOTICE(xpd, "boop (%d)\n", dahdi_tick_count); #endif goto noop; } xpp_ticker_step(&dahdi_ticker, &now); dahdi_tick_count++; //flip_parport_bit(1); noop: return; } #endif /* * called from elect_syncer() * if new_syncer is NULL, than we move all to SYNC_MODE_PLL * for DAHDI sync. */ static void update_sync_master(xbus_t *new_syncer, bool force_dahdi) { const char *msg; int i; unsigned long flags; WARN_ON(new_syncer && force_dahdi); /* Ambigous */ force_dahdi_sync = force_dahdi; msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"; DBG(SYNC, "%s => %s\n", (syncer) ? syncer->busname : msg, (new_syncer) ? new_syncer->busname : msg); /* * This global locking protects: * - The ref_ticker so it won't be used while we change it. * - The xbus_drift_clear() from corrupting driftinfo data. * It's important to set ref_ticker now: * - We cannot make the new xbus a syncer yet (until we get * a reply from AB). Maybe it's still not self_ticking, so * we must keep the timer for the command_queue to function. * - However, we must not send drift commands to it, because * they'll revert it to PLL instead of AB. */ spin_lock_irqsave(&ref_ticker_lock, flags); if(syncer) xbus_drift_clear(syncer); /* Clean old data */ if(new_syncer) { XBUS_DBG(SYNC, new_syncer, "pcm_rx_counter=%d\n", atomic_read(&new_syncer->pcm_rx_counter)); force_dahdi_sync = 0; ref_ticker = &new_syncer->ticker; xbus_drift_clear(new_syncer); /* Clean new data */ xpp_set_syncer(new_syncer, 1); xbus_request_sync(new_syncer, SYNC_MODE_AB); } else if(force_dahdi_sync) { ref_ticker = &dahdi_ticker; } else { ref_ticker = NULL; } spin_unlock_irqrestore(&ref_ticker_lock, flags); DBG(SYNC, "stop unwanted syncers\n"); /* Shut all down except the wanted sync master */ for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(__func__, i); if (xbus == NULL) continue; if(XBUS_FLAGS(xbus, CONNECTED) && xbus != new_syncer) { if(xbus->self_ticking) xbus_request_sync(xbus, xbus->sync_mode_default); else XBUS_DBG(SYNC, xbus, "Not self_ticking yet. Ignore\n"); } put_xbus(__func__, xbus); } } void elect_syncer(const char *msg) { int i; int j; uint timing_priority = INT_MAX; xpd_t *best_xpd = NULL; xbus_t *the_xbus = NULL; unsigned long flags; spin_lock_irqsave(&elect_syncer_lock, flags); DBG(SYNC, "%s: %s syncer=%s\n", __func__, msg, (syncer) ? syncer->busname : "NULL"); for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(__func__, i); if (xbus == NULL) continue; if(XBUS_IS(xbus, READY)) { if(!the_xbus) the_xbus = xbus; /* First candidate */ for(j = 0; j < MAX_XPDS; j++) { xpd_t *xpd = xpd_of(xbus, j); int prio; if(!xpd || !xpd->card_present || !IS_PHONEDEV(xpd)) continue; prio = CALL_PHONE_METHOD(card_timing_priority, xpd); if (prio < 0) { DBG(SYNC, "%s/%s: skip sync\n", xbus->busname, xpd->xpdname); continue; } if (prio > 0 && prio < timing_priority) { timing_priority = prio; best_xpd = xpd; } } } put_xbus(__func__, xbus); } if(best_xpd) { the_xbus = best_xpd->xbus; XPD_DBG(SYNC, best_xpd, "%s: elected with priority %d\n", msg, timing_priority); } else if(the_xbus) { XBUS_DBG(SYNC, the_xbus, "%s: elected\n", msg); } else { unsigned long flags; DBG(SYNC, "%s: No more syncers\n", msg); spin_lock_irqsave(&ref_ticker_lock, flags); xpp_set_syncer(NULL, 0); spin_unlock_irqrestore(&ref_ticker_lock, flags); the_xbus = NULL; } if(the_xbus != syncer) update_sync_master(the_xbus, force_dahdi_sync); spin_unlock_irqrestore(&elect_syncer_lock, flags); } /* * This function should be called with the xpd already locked */ void update_wanted_pcm_mask(xpd_t *xpd, xpp_line_t new_mask, uint new_pcm_len) { PHONEDEV(xpd).pcm_len = new_pcm_len; PHONEDEV(xpd).wanted_pcm_mask = new_mask; XPD_DBG(SIGNAL, xpd, "pcm_len=%d wanted_pcm_mask=0x%X\n", PHONEDEV(xpd).pcm_len, PHONEDEV(xpd).wanted_pcm_mask); } /* * This function is used by FXS/FXO. The pcm_mask argument signifies * channels which should be *added* to the automatic calculation. * Normally, this argument is 0. */ void generic_card_pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) { int i; int line_count = 0; unsigned long flags; uint pcm_len; spin_lock_irqsave(&PHONEDEV(xpd).lock_recompute_pcm, flags); //XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); /* Add/remove all the trivial cases */ pcm_mask |= PHONEDEV(xpd).offhook_state; pcm_mask |= PHONEDEV(xpd).oht_pcm_pass; pcm_mask &= ~(PHONEDEV(xpd).digital_inputs); pcm_mask &= ~(PHONEDEV(xpd).digital_outputs); for_each_line(xpd, i) if(IS_SET(pcm_mask, i)) line_count++; /* * FIXME: Workaround a bug in sync code of the Astribank. * Send dummy PCM for sync. */ if(xpd->addr.unit == 0 && pcm_mask == 0) { pcm_mask = BIT(0); line_count = 1; } pcm_len = (line_count) ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE : 0L; update_wanted_pcm_mask(xpd, pcm_mask, pcm_len); spin_unlock_irqrestore(&PHONEDEV(xpd).lock_recompute_pcm, flags); } void fill_beep(u_char *buf, int num, int duration) { bool alternate = (duration) ? (jiffies/(duration*1000)) & 0x1 : 0; int which; u_char *snd; /* * debug tones */ static u_char beep[] = { 0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41, /* Dima */ 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */ }; static u_char beep_alt[] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */ }; if(alternate) { which = num % ARRAY_SIZE(beep_alt); snd = &beep_alt[which]; } else { which = num % ARRAY_SIZE(beep); snd = &beep[which]; } memcpy(buf, snd, DAHDI_CHUNKSIZE); } static void do_ec(xpd_t *xpd) { int i; for (i = 0;i < PHONEDEV(xpd).span.channels; i++) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); if(unlikely(IS_SET(PHONEDEV(xpd).digital_signalling, i))) /* Don't echo cancel BRI D-chans */ continue; if(!IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i)) /* No ec for unwanted PCM */ continue; dahdi_ec_chunk(chan, chan->readchunk, PHONEDEV(xpd).ec_chunk2[i]); memcpy(PHONEDEV(xpd).ec_chunk2[i], PHONEDEV(xpd).ec_chunk1[i], DAHDI_CHUNKSIZE); memcpy(PHONEDEV(xpd).ec_chunk1[i], chan->writechunk, DAHDI_CHUNKSIZE); } } #if 0 /* Okay, now we get to the signalling. You have several options: */ /* Option 1: If you're a T1 like interface, you can just provide a rbsbits function and we'll assert robbed bits for you. Be sure to set the DAHDI_FLAG_RBS in this case. */ /* Opt: If the span uses A/B bits, set them here */ int (*rbsbits)(struct dahdi_chan *chan, int bits); /* Option 2: If you don't know about sig bits, but do have their equivalents (i.e. you can disconnect battery, detect off hook, generate ring, etc directly) then you can just specify a sethook function, and we'll call you with appropriate hook states to set. Still set the DAHDI_FLAG_RBS in this case as well */ int (*hooksig)(struct dahdi_chan *chan, enum dahdi_txsig hookstate); /* Option 3: If you can't use sig bits, you can write a function which handles the individual hook states */ int (*sethook)(struct dahdi_chan *chan, int hookstate); #endif static bool pcm_valid(xpd_t *xpd, xpacket_t *pack) { xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines); int i; int count = 0; uint16_t good_len; BUG_ON(!pack); BUG_ON(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_READ)); /* * Don't use for_each_line(xpd, i) here because for BRI it will * ignore the channels of the other xpd's in the same unit. */ for (i = 0; i < CHANNELS_PERXPD; i++) if(IS_SET(lines, i)) count++; /* FRAMES: include opcode in calculation */ good_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + count * 8; if(XPACKET_LEN(pack) != good_len) { static int rate_limit = 0; XPD_COUNTER(xpd, RECV_ERRORS)++; if((rate_limit++ % 1000) <= 10) { XPD_ERR(xpd, "BAD PCM REPLY: packet_len=%d (should be %d), count=%d\n", XPACKET_LEN(pack), good_len, count); dump_packet("BAD PCM REPLY", pack, 1); } return 0; } return 1; } static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe) { unsigned long flags; struct timeval now; unsigned long usec; spin_lock_irqsave(&xbus->lock, flags); do_gettimeofday(&now); if(unlikely(disable_pcm || !XBUS_IS(xbus, READY))) goto dropit; if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) { usec = usec_diff(&now, &xbus->last_tx_sync); xbus->last_tx_sync = now; /* ignore startup statistics */ if(likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) { if(abs(usec - 1000) > TICK_TOLERANCE) { static int rate_limit; if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, xbus, "Bad PCM TX timing(%d): usec=%ld.\n", rate_limit, usec); } if(usec > xbus->max_tx_sync) xbus->max_tx_sync = usec; if(usec < xbus->min_tx_sync) xbus->min_tx_sync = usec; } } spin_unlock_irqrestore(&xbus->lock, flags); /* OK, really send it */ if(debug & DBG_PCM ) dump_xframe("TX_XFRAME_PCM", xbus, xframe, debug); send_pcm_frame(xbus, xframe); XBUS_COUNTER(xbus, TX_XFRAME_PCM)++; return; dropit: spin_unlock_irqrestore(&xbus->lock, flags); FREE_SEND_XFRAME(xbus, xframe); } /* * Generic implementations of card_pcmfromspan()/card_pcmtospan() * For FXS/FXO */ void generic_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack) { byte *pcm; unsigned long flags; xpp_line_t wanted_lines; int i; BUG_ON(!xpd); BUG_ON(!pack); wanted_lines = PHONEDEV(xpd).wanted_pcm_mask; RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = wanted_lines; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); for (i = 0; i < PHONEDEV(xpd).channels; i++) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX int channo = chan->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); else #endif memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } } XPD_COUNTER(xpd, PCM_WRITE)++; spin_unlock_irqrestore(&xpd->lock, flags); } void generic_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack) { byte *pcm; xpp_line_t pcm_mask; xpp_line_t pcm_mute; unsigned long flags; int i; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines); spin_lock_irqsave(&xpd->lock, flags); /* * Calculate the channels we want to mute */ pcm_mute = ~(PHONEDEV(xpd).wanted_pcm_mask); pcm_mute |= PHONEDEV(xpd).mute_dtmf | PHONEDEV(xpd).silence_pcm; if(!SPAN_REGISTERED(xpd)) goto out; for (i = 0; i < PHONEDEV(xpd).channels; i++) { volatile u_char *r = XPD_CHAN(xpd, i)->readchunk; bool got_data = IS_SET(pcm_mask, i); if(got_data && !IS_SET(pcm_mute, i)) { /* We have and want real data */ // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); } else if(IS_SET(PHONEDEV(xpd).wanted_pcm_mask | PHONEDEV(xpd).silence_pcm, i)) { /* Inject SILENCE */ memset((u_char *)r, 0x7F, DAHDI_CHUNKSIZE); if(IS_SET(PHONEDEV(xpd).silence_pcm, i)) { /* * This will clear the EC buffers until next tick * So we don't have noise residues from the past. */ memset(PHONEDEV(xpd).ec_chunk2[i], 0x7F, DAHDI_CHUNKSIZE); memset(PHONEDEV(xpd).ec_chunk1[i], 0x7F, DAHDI_CHUNKSIZE); } } if(got_data) pcm += DAHDI_CHUNKSIZE; } out: XPD_COUNTER(xpd, PCM_READ)++; spin_unlock_irqrestore(&xpd->lock, flags); } int generic_echocancel_timeslot(xpd_t *xpd, int pos) { return xpd->addr.unit * 32 + pos; } EXPORT_SYMBOL(generic_echocancel_timeslot); int generic_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask) { int i; BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "0x%8X\n", ec_mask); if (!ECHOOPS(xpd->xbus)) { XPD_DBG(GENERAL, xpd, "No echo canceller in XBUS: Doing nothing.\n"); return -EINVAL; } for (i = 0; i < PHONEDEV(xpd).channels; i++) { int on = BIT(i) & ec_mask; CALL_EC_METHOD(ec_set, xpd->xbus, xpd, i, on); } CALL_EC_METHOD(ec_update, xpd->xbus, xpd->xbus); return 0; } EXPORT_SYMBOL(generic_echocancel_setmask); static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe) { byte *xframe_end; xpacket_t *pack; byte *p; int ret = -EPROTO; /* Assume error */ if(debug & DBG_PCM) dump_xframe("RX_XFRAME_PCM", xbus, xframe, debug); /* handle content */ p = xframe->packets; xframe_end = p + XFRAME_LEN(xframe); do { int len; xpd_t *xpd; pack = (xpacket_t *)p; len = XPACKET_LEN(pack); /* Sanity checks */ if(unlikely(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ))) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "%s: Non-PCM packet within a PCM xframe. (%d)\n", __FUNCTION__, rate_limit); dump_xframe("In PCM xframe", xbus, xframe, debug); } goto out; } p += len; if(p > xframe_end || len < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "%s: Invalid packet length %d. (%d)\n", __FUNCTION__, len, rate_limit); dump_xframe("BAD LENGTH", xbus, xframe, debug); } goto out; } xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); if(unlikely(!xpd)) { static int rate_limit; if((rate_limit++ % 1003) == 0) { notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM"); dump_xframe("Unknown XPD addr", xbus, xframe, debug); } goto out; } if(!pcm_valid(xpd, pack)) goto out; if(SPAN_REGISTERED(xpd)) { XBUS_COUNTER(xbus, RX_PACK_PCM)++; CALL_PHONE_METHOD(card_pcm_tospan, xpd, pack); } } while(p < xframe_end); ret = 0; /* all good */ XBUS_COUNTER(xbus, RX_XFRAME_PCM)++; out: FREE_RECV_XFRAME(xbus, xframe); return ret; } int generic_timing_priority(xpd_t *xpd) { return PHONEDEV(xpd).timing_priority; } static void xbus_tick(xbus_t *xbus) { int i; xpd_t *xpd; xframe_t *xframe = NULL; xpacket_t *pack = NULL; bool sent_sync_bit = 0; /* * Update dahdi */ for(i = 0; i < MAX_XPDS; i++) { xpd = xpd_of(xbus, i); if(xpd && SPAN_REGISTERED(xpd)) { #ifdef OPTIMIZE_CHANMUTE int j; xpp_line_t xmit_mask = PHONEDEV(xpd).wanted_pcm_mask; xmit_mask |= PHONEDEV(xpd).silence_pcm; xmit_mask |= PHONEDEV(xpd).digital_signalling; for_each_line(xpd, j) { XPD_CHAN(xpd, j)->chanmute = (optimize_chanmute) ? !IS_SET(xmit_mask, j) : 0; } #endif /* * calls to dahdi_transmit should be out of spinlocks, as it may call back * our hook setting methods. */ dahdi_transmit(&PHONEDEV(xpd).span); } } /* * Fill xframes */ for(i = 0; i < MAX_XPDS; i++) { if((xpd = xpd_of(xbus, i)) == NULL) continue; if (!IS_PHONEDEV(xpd)) continue; if(SPAN_REGISTERED(xpd)) { size_t pcm_len = PHONEDEV(xpd).pcm_len; if(pcm_len && xpd->card_present) { do { // pack = NULL; /* FORCE single packet frames */ if(xframe && !pack) { /* FULL frame */ pcm_frame_out(xbus, xframe); xframe = NULL; XBUS_COUNTER(xbus, TX_PCM_FRAG)++; } if(!xframe) { /* Alloc frame */ xframe = ALLOC_SEND_XFRAME(xbus); if (!xframe) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "%s: failed to allocate new xframe\n", __FUNCTION__); return; } } pack = xframe_next_packet(xframe, pcm_len); } while(!pack); XPACKET_INIT(pack, GLOBAL, PCM_WRITE, xpd->xbus_idx, 1, 0); XPACKET_LEN(pack) = pcm_len; if(!sent_sync_bit) { XPACKET_ADDR_SYNC(pack) = 1; sent_sync_bit = 1; } CALL_PHONE_METHOD(card_pcm_fromspan, xpd, pack); XBUS_COUNTER(xbus, TX_PACK_PCM)++; } } } if(xframe) /* clean any leftovers */ pcm_frame_out(xbus, xframe); /* * Receive PCM */ while((xframe = xframe_dequeue(&xbus->pcm_tospan)) != NULL) { copy_pcm_tospan(xbus, xframe); if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) { struct timeval now; unsigned long usec; do_gettimeofday(&now); usec = usec_diff(&now, &xbus->last_rx_sync); xbus->last_rx_sync = now; /* ignore startup statistics */ if(likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) { if(abs(usec - 1000) > TICK_TOLERANCE) { static int rate_limit; if((rate_limit++ % 5003) == 0) XBUS_DBG(SYNC, xbus, "Bad PCM RX timing(%d): usec=%ld.\n", rate_limit, usec); } if(usec > xbus->max_rx_sync) xbus->max_rx_sync = usec; if(usec < xbus->min_rx_sync) xbus->min_rx_sync = usec; } } } for(i = 0; i < MAX_XPDS; i++) { xpd = xpd_of(xbus, i); if(!xpd || !xpd->card_present) continue; if (IS_PHONEDEV(xpd)) { if(SPAN_REGISTERED(xpd)) { do_ec(xpd); dahdi_receive(&PHONEDEV(xpd).span); } PHONEDEV(xpd).silence_pcm = 0; /* silence was injected */ } xpd->timer_count = xbus->global_counter; /* * Must be called *after* tx/rx so * D-Chan counters may be cleared */ CALL_XMETHOD(card_tick, xpd); } } static void do_tick(xbus_t *xbus, const struct timeval *tv_received) { int counter = atomic_read(&xpp_tick_counter); unsigned long flags; xbus_command_queue_tick(xbus); if(global_ticker == xbus) global_tick(); /* called from here or dahdi_sync_tick() */ spin_lock_irqsave(&ref_ticker_lock, flags); xpp_drift_step(xbus, tv_received); spin_unlock_irqrestore(&ref_ticker_lock, flags); if(likely(xbus->self_ticking)) xbus_tick(xbus); xbus->global_counter = counter; } void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe) { if(!xframe_enqueue(&xbus->pcm_tospan, xframe)) { static int rate_limit; if((rate_limit++ % 1003) == 0) XBUS_DBG(SYNC, xbus, "Failed to enqueue received pcm frame. (%d)\n", rate_limit); FREE_RECV_XFRAME(xbus, xframe); } /* * The sync_master bit is marked at the first packet * of the frame, regardless of the XPD that is sync master. * FIXME: what about PRI split? */ if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) { do_tick(xbus, &xframe->tv_received); atomic_inc(&xbus->pcm_rx_counter); } else xbus->xbus_frag_count++; } int exec_sync_command(const char *buf, size_t count) { int ret = count; int xbusno; xbus_t *xbus; if(strncmp("DAHDI", buf, 6) == 0) { /* Ignore the newline */ DBG(SYNC, "DAHDI"); update_sync_master(NULL, 1); } else if(sscanf(buf, "SYNC=%d", &xbusno) == 1) { DBG(SYNC, "SYNC=%d\n", xbusno); xbus = get_xbus(__func__, xbusno); if (xbus == NULL) { ERR("No bus %d exists\n", xbusno); return -ENXIO; } update_sync_master(xbus, 0); put_xbus(__func__, xbus); } else if(sscanf(buf, "QUERY=%d", &xbusno) == 1) { DBG(SYNC, "QUERY=%d\n", xbusno); xbus = get_xbus(__func__, xbusno); if (xbus == NULL) { ERR("No bus %d exists\n", xbusno); return -ENXIO; } CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0); put_xbus(__func__, xbus); } else { ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf); ret = -EINVAL; } return ret; } int fill_sync_string(char *buf, size_t count) { int len = 0; if(!syncer) { len += snprintf(buf, count, "%s\n", (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"); } else len += snprintf(buf, count, "SYNC=%02d\n", syncer->num); return len; } int xbus_pcm_init(void *toplevel) { int ret = 0; #ifdef OPTIMIZE_CHANMUTE INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n", (optimize_chanmute)?"":"de"); #endif #ifdef DAHDI_SYNC_TICK INFO("FEATURE: with sync_tick() from DAHDI\n"); #else INFO("FEATURE: without sync_tick() from DAHDI\n"); #endif xpp_ticker_init(&global_ticks_series); xpp_ticker_init(&dahdi_ticker); return ret; } void xbus_pcm_shutdown(void) { } EXPORT_SYMBOL(xbus_request_sync); EXPORT_SYMBOL(got_new_syncer); EXPORT_SYMBOL(elect_syncer); #ifdef DAHDI_SYNC_TICK EXPORT_SYMBOL(dahdi_sync_tick); #endif EXPORT_SYMBOL(update_wanted_pcm_mask); EXPORT_SYMBOL(generic_card_pcm_recompute); EXPORT_SYMBOL(generic_card_pcm_tospan); EXPORT_SYMBOL(generic_card_pcm_fromspan); EXPORT_SYMBOL(generic_timing_priority); #ifdef DEBUG_PCMTX EXPORT_SYMBOL(pcmtx); EXPORT_SYMBOL(pcmtx_chan); #endif dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_bri.h0000644000175000017500000000167610751714440021300 0ustar tzafrirtzafrir#ifndef CARD_BRI_H #define CARD_BRI_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" enum bri_opcodes { XPROTO_NAME(BRI, SET_LED) = 0x33, }; #endif /* CARD_BRI_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xproto.c0000644000175000017500000003210711602416004021041 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" #include "xproto.h" #include "xpp_dahdi.h" #include "xbus-core.h" #include "dahdi_debug.h" #include #include static const char rcsid[] = "$Id: xproto.c 9993 2011-06-28 18:23:00Z tzafrir $"; extern int debug; static const xproto_table_t *xprotocol_tables[XPD_TYPE_NOMODULE]; #if MAX_UNIT*MAX_SUBUNIT > MAX_XPDS #error MAX_XPDS is too small #endif bool valid_xpd_addr(const struct xpd_addr *addr) { return ((addr->subunit & ~BITMASK(SUBUNIT_BITS)) == 0) && ((addr->unit & ~BITMASK(UNIT_BITS)) == 0); } /*---------------- General Protocol Management ----------------------------*/ const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode) { const xproto_entry_t *xe; //DBG(GENERAL, "\n"); xe = &table->entries[opcode]; return (xe->handler != NULL) ? xe : NULL; } const xproto_entry_t *xproto_global_entry(byte opcode) { const xproto_entry_t *xe; xe = xproto_card_entry(&PROTO_TABLE(GLOBAL), opcode); //DBG(GENERAL, "opcode=0x%X xe=%p\n", opcode, xe); return xe; } xproto_handler_t xproto_global_handler(byte opcode) { return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode); } static const xproto_table_t *xproto_table(xpd_type_t cardtype) { if(cardtype >= XPD_TYPE_NOMODULE) return NULL; return xprotocol_tables[cardtype]; } const xproto_table_t *xproto_get(xpd_type_t cardtype) { const xproto_table_t *xtable; if(cardtype >= XPD_TYPE_NOMODULE) return NULL; xtable = xprotocol_tables[cardtype]; if(!xtable) { /* Try to load the relevant module */ int ret = request_module(XPD_TYPE_PREFIX "%d", cardtype); if(ret != 0) { NOTICE("%s: Failed to load module for type=%d. exit status=%d.\n", __FUNCTION__, cardtype, ret); /* Drop through: we may be lucky... */ } xtable = xprotocol_tables[cardtype]; } if(xtable) { BUG_ON(!xtable->owner); #ifdef CONFIG_MODULE_UNLOAD DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner)); #endif if(!try_module_get(xtable->owner)) { ERR("%s: try_module_get for %s failed.\n", __FUNCTION__, xtable->name); return NULL; } } return xtable; } void xproto_put(const xproto_table_t *xtable) { BUG_ON(!xtable); #ifdef CONFIG_MODULE_UNLOAD DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner)); BUG_ON(module_refcount(xtable->owner) <= 0); #endif module_put(xtable->owner); } xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode) { const xproto_entry_t *xe; //DBG(GENERAL, "\n"); xe = xproto_card_entry(table, opcode); return xe->handler; } void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg) { XBUS_NOTICE(xbus, "%s: non-existing address (%1d%1d): %s\n", funcname, addr.unit, addr.subunit, msg); } static int packet_process(xbus_t *xbus, xpacket_t *pack) { byte op; const xproto_entry_t *xe; xproto_handler_t handler; xproto_table_t *table; xpd_t *xpd; int ret = -EPROTO; BUG_ON(!pack); if(!valid_xpd_addr(&XPACKET_ADDR(pack))) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n", __FUNCTION__, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); dump_packet("packet_process -- bad address", pack, debug); } goto out; } op = XPACKET_OP(pack); xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); /* XPD may be NULL (e.g: during bus polling */ xe = xproto_global_entry(op); /*-------- Validations -----------*/ if(!xe) { const xproto_table_t *xtable; if(!xpd) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: from %d%d opcode=0x%02X: no such global command.\n", __FUNCTION__, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), op); dump_packet("packet_process -- no such global command", pack, 1); } goto out; } xtable = xproto_table(xpd->type); if(!xtable) { if(printk_ratelimit()) XPD_ERR(xpd, "%s: no protocol table (type=%d)\n", __FUNCTION__, xpd->type); goto out; } xe = xproto_card_entry(xtable, op); if(!xe) { if(printk_ratelimit()) { XPD_NOTICE(xpd, "%s: bad command (type=%d,opcode=0x%x)\n", __FUNCTION__, xpd->type, op); dump_packet("packet_process -- bad command", pack, 1); } goto out; } } table = xe->table; BUG_ON(!table); if(!table->packet_is_valid(pack)) { if(printk_ratelimit()) { ERR("xpp: %s: wrong size %d for opcode=0x%02X\n", __FUNCTION__, XPACKET_LEN(pack), op); dump_packet("packet_process -- wrong size", pack, debug); } goto out; } ret = 0; /* All well */ handler = xe->handler; BUG_ON(!handler); XBUS_COUNTER(xbus, RX_BYTES) += XPACKET_LEN(pack); handler(xbus, xpd, xe, pack); out: return ret; } static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe) { byte *xframe_end; xpacket_t *pack; byte *p; int len; int ret; if(debug & DBG_COMMANDS) dump_xframe("RX-CMD", xbus, xframe, DBG_ANY); p = xframe->packets; xframe_end = p + XFRAME_LEN(xframe); do { pack = (xpacket_t *)p; len = XPACKET_LEN(pack); /* Sanity checks */ if(unlikely(XPACKET_OP(pack) == XPROTO_NAME(GLOBAL,PCM_READ))) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n"); dump_xframe("In Non-PCM xframe", xbus, xframe, debug); } ret = -EPROTO; goto out; } p += len; if(p > xframe_end || len < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "Invalid packet length %d\n", len); dump_xframe("BAD LENGTH", xbus, xframe, debug); } ret = -EPROTO; goto out; } ret = packet_process(xbus, pack); if(unlikely(ret < 0)) break; } while(p < xframe_end); out: FREE_RECV_XFRAME(xbus, xframe); return ret; } int xframe_receive(xbus_t *xbus, xframe_t *xframe) { int ret = 0; struct timeval now; struct timeval tv_received; int usec; if(XFRAME_LEN(xframe) < RPACKET_HEADERSIZE) { static int rate_limit; if((rate_limit++ % 1003) == 0) { XBUS_NOTICE(xbus, "short xframe\n"); dump_xframe("short xframe", xbus, xframe, debug); } FREE_RECV_XFRAME(xbus, xframe); return -EPROTO; } if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is shutting down.\n"); return -ENODEV; } tv_received = xframe->tv_received; /* * We want to check that xframes do not mix PCM and other commands */ if(XPACKET_IS_PCM((xpacket_t *)xframe->packets)) { if(!XBUS_IS(xbus, READY)) FREE_RECV_XFRAME(xbus, xframe); else xframe_receive_pcm(xbus, xframe); } else { XBUS_COUNTER(xbus, RX_CMD)++; ret = xframe_receive_cmd(xbus, xframe); } /* Calculate total processing time */ do_gettimeofday(&now); usec = (now.tv_sec - tv_received.tv_sec) * 1000000 + now.tv_usec - tv_received.tv_usec; if(usec > xbus->max_rx_process) xbus->max_rx_process = usec; return ret; } #define VERBOSE_DEBUG 1 #define ERR_REPORT_LIMIT 20 void dump_packet(const char *msg, const xpacket_t *packet, bool debug) { byte op = XPACKET_OP(packet); byte *addr = (byte *)&XPACKET_ADDR(packet); if(!debug) return; printk(KERN_DEBUG "%s: XPD=%1X-%1X%c (0x%X) OP=0x%02X LEN=%d", msg, XPACKET_ADDR_UNIT(packet), XPACKET_ADDR_SUBUNIT(packet), (XPACKET_ADDR_SYNC(packet))?'+':' ', *addr, op, XPACKET_LEN(packet)); #if VERBOSE_DEBUG { int i; byte *p = (byte *)packet; printk(" BYTES: "); for(i = 0; i < XPACKET_LEN(packet); i++) { static int limiter = 0; if(i >= sizeof(xpacket_t)) { if(limiter < ERR_REPORT_LIMIT) { ERR("%s: length overflow i=%d > sizeof(xpacket_t)=%lu\n", __FUNCTION__, i+1, (long)sizeof(xpacket_t)); } else if(limiter == ERR_REPORT_LIMIT) { ERR("%s: error packet #%d... squelsh reports.\n", __FUNCTION__, limiter); } limiter++; break; } if (debug) printk("%02X ", p[i]); } } #endif printk("\n"); } void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, byte unit, xportno_t port, const reg_cmd_t *regcmd) { char action; char modifier; char port_buf[MAX_PROC_WRITE]; char reg_buf[MAX_PROC_WRITE]; char data_buf[MAX_PROC_WRITE]; if(regcmd->bytes > sizeof(*regcmd) - 1) { /* The size byte is not included */ PORT_NOTICE(xbus, unit, port, "%s: %s: Too long: regcmd->bytes = %d\n", __FUNCTION__, msg, regcmd->bytes); return; } if(regcmd->is_multibyte) { char buf[MAX_PROC_WRITE + 1]; int i; int n = 0; size_t len = regcmd->bytes; const byte *p = REG_XDATA(regcmd); buf[0] = '\0'; for(i = 0; i < len && n < MAX_PROC_WRITE; i++) n += snprintf(&buf[n], MAX_PROC_WRITE - n, "%02X ", p[i]); PORT_DBG(REGS, xbus, unit, port, "UNIT-%d PORT-%d: Multibyte(eoframe=%d) %s[0..%zd]: %s%s\n", unit, port, regcmd->eoframe, msg, len-1, buf, (n >= MAX_PROC_WRITE)?"...":""); return; } if(regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */ PORT_NOTICE(xbus, unit, port, "%s: %s: Wrong size: regcmd->bytes = %d\n", __FUNCTION__, msg, regcmd->bytes); return; } snprintf(port_buf, MAX_PROC_WRITE, "%d%s", regcmd->portnum, (REG_FIELD(regcmd, all_ports_broadcast)) ? "*" : ""); action = (REG_FIELD(regcmd, read_request)) ? 'R' : 'W'; modifier = 'D'; if(REG_FIELD(regcmd, do_subreg)) { snprintf(reg_buf, MAX_PROC_WRITE, "%02X %02X", REG_FIELD(regcmd, regnum), REG_FIELD(regcmd, subreg)); modifier = 'S'; } else { snprintf(reg_buf, MAX_PROC_WRITE, "%02X", REG_FIELD(regcmd, regnum)); } if(REG_FIELD(regcmd, read_request)) { data_buf[0] = '\0'; } else if(REG_FIELD(regcmd, do_datah)) { snprintf(data_buf, MAX_PROC_WRITE, "%02X %02X", REG_FIELD(regcmd, data_low), REG_FIELD(regcmd, data_high)); modifier = 'I'; } else { snprintf(data_buf, MAX_PROC_WRITE, "%02X", REG_FIELD(regcmd, data_low)); } PORT_DBG(REGS, xbus, unit, port, "%s: %s %c%c %s %s\n", msg, port_buf, action, modifier, reg_buf, data_buf); } const char *xproto_name(xpd_type_t xpd_type) { const xproto_table_t *proto_table; BUG_ON(xpd_type >= XPD_TYPE_NOMODULE); proto_table = xprotocol_tables[xpd_type]; if(!proto_table) return NULL; return proto_table->name; } #define CHECK_XOP(xops, f) \ if(!(xops)->f) { \ ERR("%s: missing xmethod %s [%s (%d)]\n", __FUNCTION__, #f, name, type); \ return -EINVAL; \ } #define CHECK_PHONEOP(phoneops, f) \ if(!(phoneops)->f) { \ ERR("%s: missing phone method %s [%s (%d)]\n", __FUNCTION__, #f, name, type); \ return -EINVAL; \ } int xproto_register(const xproto_table_t *proto_table) { int type; const char *name; const struct xops *xops; const struct phoneops *phoneops; BUG_ON(!proto_table); type = proto_table->type; name = proto_table->name; if(type >= XPD_TYPE_NOMODULE) { NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type); return -EINVAL; } DBG(GENERAL, "%s (%d)\n", name, type); if(xprotocol_tables[type]) NOTICE("%s: overriding registration of %s (%d)\n", __FUNCTION__, name, type); xops = proto_table->xops; CHECK_XOP(xops, card_new); CHECK_XOP(xops, card_init); CHECK_XOP(xops, card_remove); CHECK_XOP(xops, card_tick); CHECK_XOP(xops, card_register_reply); phoneops = proto_table->phoneops; if (phoneops) { CHECK_PHONEOP(phoneops, card_pcm_recompute); CHECK_PHONEOP(phoneops, card_pcm_fromspan); CHECK_PHONEOP(phoneops, card_pcm_tospan); CHECK_PHONEOP(phoneops, echocancel_timeslot); CHECK_PHONEOP(phoneops, echocancel_setmask); CHECK_PHONEOP(phoneops, card_dahdi_preregistration); CHECK_PHONEOP(phoneops, card_dahdi_postregistration); /* optional method -- call after testing: */ /*CHECK_PHONEOP(phoneops, card_ioctl);*/ } xprotocol_tables[type] = proto_table; return 0; } void xproto_unregister(const xproto_table_t *proto_table) { int type; const char *name; BUG_ON(!proto_table); type = proto_table->type; name = proto_table->name; DBG(GENERAL, "%s (%d)\n", name, type); if(type >= XPD_TYPE_NOMODULE) { NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type); return; } if(!xprotocol_tables[type]) NOTICE("%s: xproto type %s (%d) is already unregistered\n", __FUNCTION__, name, type); xprotocol_tables[type] = NULL; } EXPORT_SYMBOL(dump_packet); EXPORT_SYMBOL(dump_reg_cmd); EXPORT_SYMBOL(xframe_receive); EXPORT_SYMBOL(notify_bad_xpd); EXPORT_SYMBOL(valid_xpd_addr); EXPORT_SYMBOL(xproto_global_entry); EXPORT_SYMBOL(xproto_card_entry); EXPORT_SYMBOL(xproto_name); EXPORT_SYMBOL(xproto_register); EXPORT_SYMBOL(xproto_unregister); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/dahdi_debug.c0000644000175000017500000000413511026520667021740 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include #include #include "dahdi_debug.h" #include "xdefs.h" static const char rcsid[] = "$Id: dahdi_debug.c 4418 2008-06-19 18:13:11Z tzafrir $"; #define P_(x) [ x ] = { .value = x, .name = #x, } static struct { int value; char *name; } poll_names[] = { P_(POLLIN), P_(POLLPRI), P_(POLLOUT), P_(POLLERR), P_(POLLHUP), P_(POLLNVAL), P_(POLLRDNORM), P_(POLLRDBAND), P_(POLLWRNORM), P_(POLLWRBAND), P_(POLLMSG), P_(POLLREMOVE) }; #undef P_ void dump_poll(int debug, const char *msg, int poll) { int i; for(i = 0; i < ARRAY_SIZE(poll_names); i++) { if(poll & poll_names[i].value) DBG(GENERAL, "%s: %s\n", msg, poll_names[i].name); } } void alarm2str(int alarm, char *buf, int buflen) { char *p = buf; int left = buflen; int i; int n; if(!alarm) { snprintf(buf, buflen, "NONE"); return; } memset(buf, 0, buflen); for(i = 0; i < 8; i++) { if(left && (alarm & BIT(i))) { n = snprintf(p, left, "%s,", alarmbit2str(i)); p += n; left -= n; } } if(p > buf) /* kill last comma */ *(p - 1) = '\0'; } EXPORT_SYMBOL(dump_poll); EXPORT_SYMBOL(alarm2str); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/XppConfig.pm0000644000175000017500000000155711031722314021602 0ustar tzafrirtzafrirpackage XppConfig; # # Written by Oron Peled # Copyright (C) 2008, Xorcom # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # # $Id: XppConfig.pm 4480 2008-06-29 15:05:48Z tzafrir $ # use strict; my $conf_file = "/etc/dahdi/xpp.conf"; sub import { my $pack = shift || die "Import without package?"; my $init_dir = shift || die "$pack::import -- missing init_dir parameter"; my $local_conf = "$init_dir/xpp.conf"; $conf_file = $local_conf if -r $local_conf; } sub read_config($) { my $opts = shift || die; open(F, $conf_file) || return (); while() { chomp; s/#.*//; # strip comments next unless /\S/; s/\s*$//; # Trim trailing whitespace my ($key, $value) = split(/\s+/, $_, 2); $opts->{$key} = $value; } close F; $opts->{'xppconf'} = $conf_file; return %{$opts}; } 1; dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_echo.h0000644000175000017500000000173611602416004021426 0ustar tzafrirtzafrir#ifndef CARD_ECHO_H #define CARD_ECHO_H /* * Written by Oron Peled * Copyright (C) 2011, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" enum echo_opcodes { XPROTO_NAME(ECHO, SET) = 0x39, XPROTO_NAME(ECHO, SET_REPLY) = 0x3A, }; #endif /* CARD_ECHO_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/print_fxo_modes.c0000644000175000017500000000162611026460317022715 0ustar tzafrirtzafrir#include int main(int argc, char *argv[]) { size_t i; for (i=0; i<(sizeof(fxo_modes)/sizeof(struct fxo_mode)); i++) { if (fxo_modes[i].name == NULL) break; int reg16=0, reg26=0, reg30=0, reg31=0x20; char ring_osc[BUFSIZ]="", ring_x[BUFSIZ] = ""; reg16 |= (fxo_modes[i].ohs << 6); reg16 |= (fxo_modes[i].rz << 1); reg16 |= (fxo_modes[i].rt); reg26 |= (fxo_modes[i].dcv << 6); reg26 |= (fxo_modes[i].mini << 4); reg26 |= (fxo_modes[i].ilim << 1); reg30 = (fxo_modes[i].acim); reg31 |= (fxo_modes[i].ohs2 << 3); if (fxo_modes[i].ring_osc) snprintf(ring_osc, BUFSIZ, "ring_osc=%04X", fxo_modes[i].ring_osc); if (fxo_modes[i].ring_x) snprintf(ring_x, BUFSIZ, "ring_x=%04X", fxo_modes[i].ring_x); printf("%-15s\treg16=%02X\treg26=%02X\treg30=%02X\treg31=%02X\t%s\t%s\n", fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x); } return 0; } dahdi-linux-2.5.0.1/drivers/dahdi/xpp/init_card_4_300000755000175000017500000003224011521324631021753 0ustar tzafrirtzafrir#! /usr/bin/perl -w use strict; # Make warnings fatal local $SIG{__WARN__} = sub { die @_ }; # # $Id: init_card_4_30 9709 2011-01-30 18:10:33Z tzafrir $ # # # Written by Oron Peled # Copyright (C) 2007, Xorcom # # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # See the file LICENSE in the top level of this tarball. # # This script is run from the xpp kernel module upon detection # of a new XPD. # # Expects the following environment variables to be set: # XBUS_NAME - bus name # UNIT_NUMBER - xpd unit number # UNIT_SUBUNITS - number of subunits in this xpd # UNIT_TYPE - xpd type number (from protocol reply): # 1 - FXS # 2 - FXO # 3 - BRI # 4 - PRI # XBUS_REVISION - xbus revision number # XBUS_CONNECTOR - xbus connector string # XBUS_LABEL - xbus label string # # Output data format: # - An optional comment start with ';' or '#' until the end of line # - Optional Blank lines are ignored # - Fields are whitespace separated (spaces or tabs) # # The fields are (in command line order): # 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number) # 2. Command word: # - RD Read Direct register. # - WD Write Direct register. # 3. Register number in hexadecimal. # 5. Data byte in hexadecimal. (for WD command only). # package main; use File::Basename; use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; getopts('o:', \%opts); my %settings; sub logit { print STDERR "$unit_id: @_\n"; } sub debug { logit @_ if $settings{debug}; } # Arrange for error logging if (-t STDERR) { $unit_id = 'Interactive'; debug "Interactive startup"; } else { $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}"; open (STDERR, "| logger -t $program -p kern.info") || die; debug "Non Interactive startup"; foreach my $k (qw( XBUS_NAME XBUS_NUMBER UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR XBUS_LABEL)) { unless(defined $ENV{$k}) { logit "Missing ENV{$k}\n"; die; } } } sub select_subunit($) { my $subunit = shift; die unless defined $subunit; my $output; if($opts{o}) { $output = $opts{o}; } else { $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit; if(! -f $output) { my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit); $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs"; logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc" if -f $output; } } open(REG, ">$output") || die "Failed to open '$output': $!\n"; my $oldfh = select REG; print "# Selecting subunit $subunit\n" if $opts{o}; return $oldfh; } package PRI; sub gen { my $fmt = shift; $| = 1; printf "$fmt\n", @_; } sub init_quad() { main::select_subunit(0); PRI::gen "0 WD D6 20"; # GPC6.COMP_DIS=1 # (Compatibility Mode Disable) # Tuning of clocking unit to the 16.384 MHz reference frequence # by setting Global Clock Mode registers (GCM[1:8]), same for E1 and T1/J1 PRI::gen "0 WD 92 00"; # GCM1 PRI::gen "0 WD 93 18"; # GCM2 PRI::gen "0 WD 94 FB"; # GCM3 PRI::gen "0 WD 95 0B"; # GCM4 PRI::gen "0 WD 96 01"; # GCM5 PRI::gen "0 WD 97 0B"; # GCM6 PRI::gen "0 WD 98 DB"; # GCM7 PRI::gen "0 WD 99 DF"; # GCM8 } sub finish_quad() { PRI::gen "0 WD BB 2C"; # REGFP PRI::gen "0 WD BC FF"; # REGFD PRI::gen "0 WD BB AC"; # REGFP PRI::gen "0 WD BB 2B"; # REGFP PRI::gen "0 WD BC 00"; # REGFD PRI::gen "0 WD BB AB"; # REGFP PRI::gen "0 WD BB 2A"; # REGFP PRI::gen "0 WD BC FF"; # REGFD PRI::gen "0 WD BB AA"; # REGFP PRI::gen "0 WD BB 29"; # REGFP PRI::gen "0 WD BC FF"; # REGFD PRI::gen "0 WD BB A9"; # REGFP PRI::gen "0 WD BB 28"; # REGFP PRI::gen "0 WD BC 00"; # REGFD PRI::gen "0 WD BB A8"; # REGFP PRI::gen "0 WD BB 27"; # REGFP PRI::gen "0 WD BC FF"; # REGFD PRI::gen "0 WD BB A7"; # REGFP PRI::gen "0 WD BB 00"; # REGFP # PRI::gen "0 WD 80 00"; # PC1 (Port configuration 1): RPB_1.SYPR , XPB_1.SYPX } sub read_defaults() { if(XppConfig::read_config(\%settings)) { main::logit "Defaults from $settings{xppconf}"; } else { main::logit "No defaults file, use hard-coded defaults."; } } package PRI::Port; sub new { my $pack = shift; my $port = { @_ }; bless $port, $pack; return $port; } sub get_pri_protocol { my $port = shift; my $subunit = $port->{PORT_NUM}; my $xpd_name = "XPD-$ENV{UNIT_NUMBER}$subunit"; my $pri_protocol; my @keys = ( "pri_protocol/connector:$ENV{XBUS_CONNECTOR}/$xpd_name", "pri_protocol/label:$ENV{XBUS_LABEL}/$xpd_name", "pri_protocol/$ENV{XBUS_NAME}/$xpd_name", "pri_protocol" ); foreach my $k (@keys) { $k = lc($k); # Lowercase $pri_protocol = $settings{$k}; if(defined $pri_protocol) { $port->{pri_protocol} = $pri_protocol; return $pri_protocol; } } return undef; } sub write_pri_info { my $port = shift; my $subunit = $port->{PORT_NUM}; my $pri_protocol = $port->get_pri_protocol; my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit); if(defined $pri_protocol) { main::logit "$xpd_name: pri_protocol $pri_protocol"; my $file = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/pri_protocol", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit; if(! -f $file) { $file = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/pri_info"; main::logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc" if -f $file; } open(INFO, ">$file") || die "Failed to open '$file': $!\n"; print INFO "$pri_protocol\n" || die "Failed writing '$pri_protocol' to '$file': $!\n"; close INFO || die "Failed during close of '$file': $!\n"; } else { main::logit "$xpd_name: pri_protocol not given. Driver will use defaults."; } } sub port_setup($) { my $port = shift; my $portno = $port->{PORT_NUM}; my $pri_protocol = $port->get_pri_protocol; PRI::gen "$portno WD 28 40"; # XPM2.XLT Tristate my $cmr5 = sprintf("%x", ($portno << 5)); PRI::gen "$portno WD 42 $cmr5"; # CMR5.DRSS=portno PRI::gen "$portno WD 26 F6"; # XPM0: Pulse Shape Programming for R1=18Ohms PRI::gen "$portno WD 27 02"; # XPM1: ...3V Pulse Level at the line (Vp-p=6v) # if (unchannelized) #PRI::gen "$portno WD 1F 22"; # LOOP (Channel Looback): # ECLB (Enable Channel Loop-Back) # CLA (Channel Address) PRI::gen "$portno WD 2B EF"; # IDL (Idle): # If channel loopback is enabled than transmit this code on the outgoing PRI::gen "$portno WD 1F 00"; # LOOP (Channel Looback): #if($portno eq 0){ # PRI::gen "0 WD 1F 00"; # LOOP (Channel Looback): # # channels (XL1/XL2) #}else { # PRI::gen "0 WD 1F 20"; # LOOP (Channel Looback): #} # only one of the following loopbacks can be activated in the same time my $LIM1_RL = 0 << 1; # RL (Remote Loopback) my $lim1 = 0xB0 | $LIM1_RL; PRI::gen "$portno WD 37 %02X", $lim1; # LIM1: ~RL (Remote Loop bit 0x02), # ~DRS (Dual Rail Select, latch receive data while trasmit), # RIL1, RIL0 (Receive Input Treshold 0.62 V), # CLOS (Clear data in case of LOS) PRI::gen "$portno WD 3A 20"; # LIM2: SLT1, SLT0 = 01 # (Receiver Slicer Threshold, the receive slicer # generates a mark (digital one) if the voltage at # RL1/2 exceeds 50% of the peak amplitude, # default, recommended in E1 mode). PRI::gen "$portno WD 38 0A"; # PCD: (Pulse Count Detection, LOS Detection after 176 consecutive 0s) PRI::gen "$portno WD 39 15"; # PCR: (Pulse Count Recovery, LOS Recovery after 22 ones in PCD interval) # Configure system interface PRI::gen "$portno WD 3E C2"; # SIC1: SSC1 (System clock ) is 8.192 Mhz, # SSD1 (System Data rate) is 8.192 Mbit/s, # ~BIM (Byte interleaved mode), # XBS (Transmit Buffer Size) is 2 frames PRI::gen "$portno WD 40 04"; # SIC3: Edges for capture, Synchronous Pulse Receive @Rising Edge PRI::gen "$portno WD 41 04"; # CMR4: RCLK is 8.192 MHz PRI::gen "$portno WD 43 04"; # CMR5: TCLK is 8.192 MHz PRI::gen "$portno WD 44 34"; # CMR6: Receive reference clock generated by channel 1, # RCLK is at 8.192 Mhz dejittered, Clock recovered from the line # TCLK is at 8.192 MHz is de-jittered by DCO-R to drive a6.176 MHz # clock on RCLK.*/ PRI::gen "$portno WD 22 00"; # XC0: (Transmit Counter Offset = 497/T=2) PRI::gen "$portno WD 23 04"; # XC1: X=4 => T=4-X=0 offset PRI::gen "$portno WD 24 00"; # RC0: (Receive Counter Offset = 497/T=2) PRI::gen "$portno WD 25 05"; # RC1: Remaining part of RC0 my $sic2 = sprintf("%x", 0x00 | ($portno << 1)); PRI::gen "$portno WD 3F $sic2"; # SIC2: No FFS, no center receive elastic buffer, data active at phase ($sic >> 1) # enable the following interrupt sources PRI::gen "$portno WD 14 F7"; # IMR0 (Interrupt Mask Register2): Enable CASC_E1/RSC_T1 PRI::gen "$portno WD 16 00"; # IMR2 (Interrupt Mask Register2): Enable ALL PRI::gen "$portno WD 17 3F"; # IMR3 ~ES, ~SEC (Enable ES and SEC interrupts) PRI::gen "$portno WD 18 00"; # IMR4: Enable ALL PRI::gen "$portno WD 46 80"; # GCR: (Global Configuration Register) # VIS (Masked Interrupts Visible) PRI::gen "$portno WD 08 04"; # IPC: SYNC is 8 Khz PRI::gen "$portno WD 02 51"; # CMDR (Command Register): RRES, XRES, SRES (Receiver/Transmitter reset) PRI::gen "$portno WD 02 00"; # CMDR PRI::gen "$portno WD 45 00"; # CMR2: External sources for SYPR, SCLKR, SYPX, SCLKX for TX and RX. # Configure ports PRI::gen "$portno WD 85 80"; # GPC1 (Global Port Configuration 1): #PRI::gen "$portno WD 85 00"; # GPC1 (Global Port Configuration 1): # SMM (System Interface Multiplex Mode) PRI::gen "$portno WD 80 00"; # PC1: SYPR/SYPX provided to RPA/XPA inputs PRI::gen "$portno WD 84 31"; # PC5: XMFS active low, SCLKR is input, RCLK is output (unused) PRI::gen "$portno WD 3B 00"; # Clear LCR1 - Loop Code Register 1 # printk("TE110P: Successfully initialized serial bus for card\n"); # Initialize PCM and SIG regs PRI::gen "$portno WD A0 00"; # TSEO (Time Slot Even/Odd Select) PRI::gen "$portno WD A1 FF"; # TSBS (Time Slot Bit Select)- only selected bits are used for HDLC channel 1 # in selected time slots PRI::gen "$portno WD 03 89"; # Mode Register: # MDS (Mode Select) = 100 (No address comparison) # HRAC (Receiver Active - HDLC channel 1) # RFT2 (HDLC Receive FIFO is 64 byte deep) my $ccr1 = 0x18; # CCR1 (Common Configuration Register1) # EITS (Enable Internal Time Slot 0 to 31 Signalling) # ITF (Interframe Time Fill) my $sysfs_pri_protocol; if (defined $pri_protocol) { $sysfs_pri_protocol = $pri_protocol; } else { my $file = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/pri_protocol", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $portno; # The 'open' will fail if the port does not exist. # (or rather: the XPD for it does not exist). While # we only read this file to get the default E1/T1 value, # if it does not exist, it also implies the commands sent would # get nowhere. So we might as well quit now. open(F, $file) || return; $sysfs_pri_protocol = ; close F; chomp $sysfs_pri_protocol; } if($sysfs_pri_protocol eq 'T1') { $ccr1 |= 0x80; # RSCC (Serial CAS Format Selection) } PRI::gen "$portno WD 09 %02X", $ccr1; PRI::gen "$portno WD 0A 04"; # CCR2 (Common Configuration Register2) # RCRC (enable CRC - HDLC channel 1enable CRC - HDLC channel 1) PRI::gen "$portno WD 0C 00"; # RTR1 (Receive Time Slot register 1) PRI::gen "$portno WD 0D 00"; # RTR2 (Receive Time Slot register 2) PRI::gen "$portno WD 0E 00"; # RTR3 (Receive Time Slot register 3), TS16 (Enable time slot 16) PRI::gen "$portno WD 0F 00"; # RTR4 (Receive Time Slot register 4) PRI::gen "$portno WD 10 00"; # TTR1 (Transmit Time Slot register 1) PRI::gen "$portno WD 11 00"; # TTR2 (Transmit Time Slot register 2) PRI::gen "$portno WD 12 00"; # TTR3 (Transmit Time Slot register 3), TS16 (Enable time slot 16) PRI::gen "$portno WD 13 00"; # TTR4 (Transmit Time Slot register 4) # configure the best performance of the Bipolar Violation detection for all four channels PRI::gen "$portno WD BD 00"; # BFR (Bugfix Register): ~BVP (Bipolar Violations), # use Improved Bipolar Violation Detection instead } package main; main::debug "Starting '$0'"; PRI::read_defaults; sub main() { my @ports; my $subunit; main::debug "main(): Initializing chip ($ENV{UNIT_SUBUNITS} ports)"; PRI::init_quad; # Must initialize all 4 ports, regardless how much there are for($subunit = 0; $subunit < 4; $subunit++) { #main::debug "main(): Initializing subunit $subunit"; my $p = PRI::Port->new( 'PORT_NUM' => $subunit, 'EXIST' => ($subunit < $ENV{UNIT_SUBUNITS}) ); $p->port_setup; push(@ports, $p); } PRI::finish_quad; foreach my $p (@ports) { if($p->{EXIST}) { $p->write_pri_info; } } } main; main::debug "Ending '$0'"; close REG; close STDERR; exit 0; dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xbus-core.c0000644000175000017500000013523211611603461021425 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include #include #include #ifdef PROTOCOL_DEBUG #include #endif #include #include #include /* for msleep() to debug */ #include "xpd.h" #include "xpp_dahdi.h" #include "xbus-core.h" #include "card_global.h" #include "dahdi_debug.h" static const char rcsid[] = "$Id: xbus-core.c 10055 2011-07-20 16:49:53Z tzafrir $"; /* Defines */ #define INITIALIZATION_TIMEOUT (90*HZ) /* in jiffies */ #define PROC_XBUSES "xbuses" #define PROC_XBUS_SUMMARY "summary" #ifdef PROTOCOL_DEBUG #ifdef CONFIG_PROC_FS #define PROC_XBUS_COMMAND "command" static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data); #endif #endif /* Command line parameters */ extern int debug; static DEF_PARM(uint, command_queue_length, 1000, 0444, "Maximal command queue length"); static DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply"); static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets"); #ifdef CONFIG_PROC_FS static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); #endif static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); static void transport_destroy(xbus_t *xbus); /* Data structures */ static DEFINE_SPINLOCK(xbuses_lock); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_xbuses = NULL; #endif static struct xbus_desc { xbus_t *xbus; } xbuses_array[MAX_BUSES]; static xbus_t *xbus_byhwid(const char *hwid) { int i; xbus_t *xbus; for (i = 0; i < ARRAY_SIZE(xbuses_array); i++) { xbus = xbuses_array[i].xbus; if (xbus && strcmp(hwid, xbus->label) == 0) return xbus; } return NULL; } int xbus_check_unique(xbus_t *xbus) { if (!xbus) return -ENOENT; if (xbus->label && *(xbus->label)) { xbus_t *xbus_old; XBUS_DBG(DEVICES, xbus, "Checking LABEL='%s'\n", xbus->label); xbus_old = xbus_byhwid(xbus->label); if (xbus_old && xbus_old != xbus) { XBUS_NOTICE(xbus_old, "Duplicate LABEL='%s'. Leave %s unused. refcount_xbus=%d\n", xbus_old->label, xbus->busname, refcount_xbus(xbus_old)); return -EBUSY; } } else { XBUS_NOTICE(xbus, "Missing board label (old Astribank?)\n"); } return 0; } const char *xbus_statename(enum xbus_state st) { switch(st) { case XBUS_STATE_START: return "START"; case XBUS_STATE_IDLE: return "IDLE"; case XBUS_STATE_SENT_REQUEST: return "SENT_REQUEST"; case XBUS_STATE_RECVD_DESC: return "RECVD_DESC"; case XBUS_STATE_READY: return "READY"; case XBUS_STATE_DEACTIVATING: return "DEACTIVATING"; case XBUS_STATE_DEACTIVATED: return "DEACTIVATED"; case XBUS_STATE_FAIL: return "FAIL"; } return NULL; } static void init_xbus(uint num, xbus_t *xbus) { struct xbus_desc *desc; BUG_ON(num >= ARRAY_SIZE(xbuses_array)); desc = &xbuses_array[num]; desc->xbus = xbus; } xbus_t *xbus_num(uint num) { struct xbus_desc *desc; if(num >= ARRAY_SIZE(xbuses_array)) return NULL; desc = &xbuses_array[num]; return desc->xbus; } static void initialize_xbuses_array(void) { int i; for(i = 0; i < ARRAY_SIZE(xbuses_array); i++) init_xbus(i, NULL); } static void finalize_xbuses_array(void) { int i; for(i = 0; i < ARRAY_SIZE(xbuses_array); i++) { if(xbuses_array[i].xbus != NULL) { ERR("%s: xbus #%d is not NULL\n", __FUNCTION__, i); BUG(); } } } /* * Called by put_xbus() when XBUS has no more references. */ static void xbus_destroy(struct kref *kref) { xbus_t *xbus; xbus = kref_to_xbus(kref); XBUS_NOTICE(xbus, "%s\n", __func__); xbus_sysfs_remove(xbus); } xbus_t *get_xbus(const char *msg, uint num) { unsigned long flags; xbus_t *xbus; spin_lock_irqsave(&xbuses_lock, flags); xbus = xbus_num(num); if (xbus != NULL) { kref_get(&xbus->kref); XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg, refcount_xbus(xbus)); } spin_unlock_irqrestore(&xbuses_lock, flags); return xbus; } void put_xbus(const char *msg, xbus_t *xbus) { XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg, refcount_xbus(xbus)); kref_put(&xbus->kref, xbus_destroy); } int refcount_xbus(xbus_t *xbus) { struct kref *kref = &xbus->kref; return atomic_read(&kref->refcount); } /*------------------------- Frame Handling ------------------------*/ void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv) { memset(xframe, 0, sizeof(*xframe)); INIT_LIST_HEAD(&xframe->frame_list); xframe->priv = priv; xframe->xbus = xbus; xframe->packets = xframe->first_free = buf; xframe->frame_maxlen = maxsize; atomic_set(&xframe->frame_len, 0); do_gettimeofday(&xframe->tv_created); xframe->xframe_magic = XFRAME_MAGIC; } /* * Return pointer to next packet slot in the frame * or NULL if the frame is full. * * FIXME: we do not use atomic_add_return() because kernel-2.6.8 * does not have it. This make this code a little racy, * but we currently call xframe_next_packet() only in the * PCM loop (xbus_tick() etc.) */ xpacket_t *xframe_next_packet(xframe_t *frm, int len) { int newlen = XFRAME_LEN(frm); newlen += len; // DBG(GENERAL, "len=%d, newlen=%d, frm->frame_len=%d\n", len, newlen, XFRAME_LEN(frm)); if (newlen > XFRAME_DATASIZE) { return NULL; } atomic_add(len, &frm->frame_len); return (xpacket_t *)(frm->packets + newlen - len); } static DEFINE_SPINLOCK(serialize_dump_xframe); static void do_hexdump(const char msg[], byte *data, uint16_t len) { int i; int debug = DBG_ANY; /* mask global debug */ for(i = 0; i < len; i++) DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]); } void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug) { const uint16_t frm_len = XFRAME_LEN(xframe); xpacket_t *pack; uint16_t pos = 0; uint16_t nextpos; int num = 1; bool do_print; unsigned long flags; if(xframe->xframe_magic != XFRAME_MAGIC) { XBUS_ERR(xbus, "%s: bad xframe_magic %lX\n", __FUNCTION__, xframe->xframe_magic); return; } spin_lock_irqsave(&serialize_dump_xframe, flags); do { if(pos >= xbus->transport.max_send_size) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: xframe overflow (%d bytes)\n", msg, frm_len); do_hexdump(msg, xframe->packets, frm_len); } break; } if(pos > frm_len) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: packet overflow pos=%d frame_len=%d\n", msg, pos, frm_len); do_hexdump(msg, xframe->packets, frm_len); } break; } pack = (xpacket_t *)&xframe->packets[pos]; if(XPACKET_LEN(pack) <= 0) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: xframe -- bad packet_len=%d pos=%d frame_len=%d\n", msg, XPACKET_LEN(pack), pos, frm_len); do_hexdump(msg, xframe->packets, frm_len); } break; } nextpos = pos + XPACKET_LEN(pack); if(nextpos > frm_len) { if(printk_ratelimit()) { XBUS_NOTICE(xbus, "%s: packet overflow nextpos=%d frame_len=%d\n", msg, nextpos, frm_len); do_hexdump(msg, xframe->packets, frm_len); } break; } do_print = 0; if(debug == DBG_ANY) do_print = 1; else if(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ) && XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_WRITE)) do_print = 1; else if(debug & DBG_PCM) { static int rate_limit; if((rate_limit++ % 1003) == 0) do_print = 1; } if(do_print) { if(num == 1) { XBUS_DBG(ANY, xbus, "%s: frame_len=%d. %s\n", msg, frm_len, (XPACKET_IS_PCM(pack)) ? "(IS_PCM)" : ""); } XBUS_DBG(ANY, xbus, " %3d. DATALEN=%d pcm=%d slot=%d OP=0x%02X XPD-%d%d (pos=%d)\n", num, XPACKET_LEN(pack), XPACKET_IS_PCM(pack), XPACKET_PCMSLOT(pack), XPACKET_OP(pack), XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), pos); dump_packet(" ", pack, debug); } num++; pos = nextpos; if(pos >= frm_len) break; } while(1); spin_unlock_irqrestore(&serialize_dump_xframe, flags); } /** * * Frame is freed: * - In case of error, by this function. * - Otherwise, by the underlying sending mechanism */ int send_pcm_frame(xbus_t *xbus, xframe_t *xframe) { struct xbus_ops *ops; int ret = -ENODEV; BUG_ON(!xframe); if(!XBUS_IS(xbus, READY)) { XBUS_ERR(xbus, "Dropped a pcm frame -- hardware is not ready.\n"); ret = -ENODEV; goto error; } ops = transportops_get(xbus); BUG_ON(!ops); ret = ops->xframe_send_pcm(xbus, xframe); transportops_put(xbus); if(ret) XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe); return ret; error: FREE_SEND_XFRAME(xbus, xframe); return ret; } static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe) { struct xbus_ops *ops; int ret; BUG_ON(!xbus); BUG_ON(!xframe); BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_ERR(xbus, "Dropped command before sending -- hardware deactivated.\n"); dump_xframe("Dropped", xbus, xframe, DBG_ANY); FREE_SEND_XFRAME(xbus, xframe); return -ENODEV; } ops = transportops_get(xbus); BUG_ON(!ops); if(debug & DBG_COMMANDS) dump_xframe("TX-CMD", xbus, xframe, DBG_ANY); ret = ops->xframe_send_cmd(xbus, xframe); transportops_put(xbus); if(ret == 0) { XBUS_COUNTER(xbus, TX_CMD)++; XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe); } return ret; } int xbus_command_queue_tick(xbus_t *xbus) { xframe_t *frm; int ret = 0; int packno; xbus->command_tick_counter++; xbus->usec_nosend -= 1000; /* That's our budget */ for(packno = 0; packno < 3; packno++) { if(xbus->usec_nosend > 0) break; frm = xframe_dequeue(&xbus->command_queue); if(!frm) { wake_up(&xbus->command_queue_empty); break; } BUG_ON(frm->xframe_magic != XFRAME_MAGIC); xbus->usec_nosend += frm->usec_towait; ret = really_send_cmd_frame(xbus, frm); if(ret < 0) { XBUS_ERR(xbus, "Failed to send from command_queue (ret=%d)\n", ret); xbus_setstate(xbus, XBUS_STATE_FAIL); } } if(xbus->usec_nosend < 0) xbus->usec_nosend = 0; return ret; } static void xbus_command_queue_clean(xbus_t *xbus) { xframe_t *frm; XBUS_DBG(DEVICES, xbus, "count=%d\n", xbus->command_queue.count); xframe_queue_disable(&xbus->command_queue, 1); while((frm = xframe_dequeue(&xbus->command_queue)) != NULL) { FREE_SEND_XFRAME(xbus, frm); } } static int xbus_command_queue_waitempty(xbus_t *xbus) { int ret; XBUS_DBG(DEVICES, xbus, "Waiting for command_queue to empty\n"); ret = wait_event_interruptible(xbus->command_queue_empty, xframe_queue_count(&xbus->command_queue) == 0); if(ret) { XBUS_ERR(xbus, "waiting for command_queue interrupted!!!\n"); } return ret; } int send_cmd_frame(xbus_t *xbus, xframe_t *xframe) { static int rate_limit; int ret = 0; BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); if(!XBUS_FLAGS(xbus, CONNECTED)) { XBUS_ERR(xbus, "Dropped command before queueing -- hardware deactivated.\n"); ret = -ENODEV; goto err; } if(debug & DBG_COMMANDS) dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY); if(!xframe_enqueue(&xbus->command_queue, xframe)) { if((rate_limit++ % 1003) == 0) { XBUS_ERR(xbus, "Dropped command xframe. Cannot enqueue (%d)\n", rate_limit); dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY); } xbus_setstate(xbus, XBUS_STATE_FAIL); ret = -E2BIG; goto err; } return 0; err: FREE_SEND_XFRAME(xbus, xframe); return ret; } /*------------------------- Receive Tasklet Handling ---------------*/ static void xframe_enqueue_recv(xbus_t *xbus, xframe_t *xframe) { int cpu = smp_processor_id(); BUG_ON(!xbus); xbus->cpu_rcv_intr[cpu]++; if(!xframe_enqueue(&xbus->receive_queue, xframe)) { static int rate_limit; if((rate_limit++ % 1003) == 0) XBUS_ERR(xbus, "Failed to enqueue for receive_tasklet (%d)\n", rate_limit); FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */ return; } tasklet_schedule(&xbus->receive_tasklet); } /* * process frames in the receive_queue in a tasklet */ static void receive_tasklet_func(unsigned long data) { xbus_t *xbus = (xbus_t *)data; xframe_t *xframe = NULL; int cpu = smp_processor_id(); BUG_ON(!xbus); xbus->cpu_rcv_tasklet[cpu]++; while((xframe = xframe_dequeue(&xbus->receive_queue)) != NULL) { xframe_receive(xbus, xframe); } } void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe) { BUG_ON(!xbus); if(rx_tasklet) { xframe_enqueue_recv(xbus, xframe); } else { if(likely(XBUS_FLAGS(xbus, CONNECTED))) xframe_receive(xbus, xframe); else FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */ } } /*------------------------- Bus Management -------------------------*/ xpd_t *xpd_of(const xbus_t *xbus, int xpd_num) { if(!VALID_XPD_NUM(xpd_num)) return NULL; return xbus->xpds[xpd_num]; } xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit) { if(unit > MAX_UNIT || subunit > MAX_SUBUNIT) return NULL; return xbus->xpds[XPD_IDX(unit,subunit)]; } int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit) { unsigned int xpd_num; unsigned long flags; BUG_ON(!xbus); xpd_num = XPD_IDX(unit,subunit); XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num); spin_lock_irqsave(&xbus->lock, flags); if(!VALID_XPD_NUM(xpd_num)) { XBUS_ERR(xbus, "Bad xpd_num = %d\n", xpd_num); BUG(); } if(xbus->xpds[xpd_num] != NULL) { xpd_t *other = xbus->xpds[xpd_num]; XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n", xpd_num, other, other->xpdname); BUG(); } snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit); MKADDR(&xpd->addr, unit, subunit); xpd->xbus_idx = xpd_num; xbus->xpds[xpd_num] = xpd; xpd->xbus = xbus; atomic_inc(&xbus->num_xpds); spin_unlock_irqrestore(&xbus->lock, flags); /* Must be done out of atomic context */ if(xpd_device_register(xbus, xpd) < 0) { XPD_ERR(xpd, "%s: xpd_device_register() failed\n", __FUNCTION__); /* FIXME: What to do? */ } return 0; } int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd) { unsigned int xpd_num = xpd->xbus_idx; unsigned long flags; XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num); if(!VALID_XPD_NUM(xpd_num)) { XBUS_ERR(xbus, "%s: Bad xpd_num = %d\n", __FUNCTION__, xpd_num); BUG(); } if(xbus->xpds[xpd_num] == NULL) { XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __FUNCTION__, xpd_num); BUG(); } if(xbus->xpds[xpd_num] != xpd) { xpd_t *other = xbus->xpds[xpd_num]; XBUS_ERR(xbus, "%s: slot xpd_num=%d is occupied by %p (%s)\n", __FUNCTION__, xpd_num, other, other->xpdname); BUG(); } spin_lock_irqsave(&xbus->lock, flags); xpd->xbus = NULL; xbus->xpds[xpd_num] = NULL; if(atomic_dec_and_test(&xbus->num_xpds)) xbus_setstate(xbus, XBUS_STATE_IDLE); spin_unlock_irqrestore(&xbus->lock, flags); return 0; } static int new_card(xbus_t *xbus, int unit, byte type, byte subtype, byte numchips, byte ports_per_chip, byte ports, byte port_dir) { const xproto_table_t *proto_table; int i; int subunits; int ret = 0; int remaining_ports; const struct echoops *echoops; proto_table = xproto_get(type); if(!proto_table) { XBUS_NOTICE(xbus, "CARD %d: missing protocol table for type %d. Ignored.\n", unit, type); return -EINVAL; } echoops = proto_table->echoops; if (echoops) { XBUS_INFO(xbus, "Detected ECHO Canceler (%d)\n", unit); if (ECHOOPS(xbus)) { XBUS_NOTICE(xbus, "CARD %d: tryies to define echoops (type %d) but we already have one. Ignored.\n", unit, type); return -EINVAL; } xbus->echo_state.echoops = echoops; xbus->echo_state.xpd_idx = XPD_IDX(unit, 0); } remaining_ports = ports; subunits = (ports + proto_table->ports_per_subunit - 1) / proto_table->ports_per_subunit; XBUS_DBG(DEVICES, xbus, "CARD %d type=%d.%d ports=%d (%dx%d), %d subunits, port-dir=0x%02X\n", unit, type, subtype, ports, numchips, ports_per_chip, subunits, port_dir ); if (type == XPD_TYPE_PRI || type == XPD_TYPE_BRI) xbus->quirks.has_digital_span = 1; if (type == XPD_TYPE_FXO) xbus->quirks.has_fxo = 1; xbus->worker.num_units += subunits - 1; for(i = 0; i < subunits; i++) { int subunit_ports = proto_table->ports_per_subunit; if(subunit_ports > remaining_ports) subunit_ports = remaining_ports; remaining_ports -= proto_table->ports_per_subunit; if(subunit_ports <= 0) { XBUS_NOTICE(xbus, "Subunit XPD=%d%d without ports (%d of %d)\n", unit, i, subunit_ports, ports); ret = -ENODEV; goto out; } if(!XBUS_IS(xbus, RECVD_DESC)) { XBUS_NOTICE(xbus, "Cannot create XPD=%d%d in state %s\n", unit, i, xbus_statename(XBUS_STATE(xbus))); ret = -ENODEV; goto out; } XBUS_DBG(DEVICES, xbus, "Creating XPD=%d%d type=%d.%d (%d ports)\n", unit, i, type, subtype, subunit_ports); ret = create_xpd(xbus, proto_table, unit, i, type, subtype, subunits, subunit_ports, port_dir); if(ret < 0) { XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n", unit, i, ret); goto out; } xbus->worker.num_units_initialized++; } out: xproto_put(proto_table); /* ref count is inside the xpds now */ return ret; } static void xbus_release_xpds(xbus_t *xbus) { int i; XBUS_DBG(DEVICES, xbus, "[%s] Release XPDS\n", xbus->label); for(i = 0; i < MAX_XPDS; i++) { xpd_t *xpd = xpd_of(xbus, i); if(xpd) put_xpd(__func__, xpd); } } static int xbus_aquire_xpds(xbus_t *xbus) { unsigned long flags; int i; int ret = 0; xpd_t *xpd; XBUS_DBG(DEVICES, xbus, "[%s] Aquire XPDS\n", xbus->label); spin_lock_irqsave(&xbus->lock, flags); for (i = 0; i < MAX_XPDS; i++) { xpd = xpd_of(xbus, i); if (xpd) { xpd = get_xpd(__func__, xpd); if (!xpd) goto err; } } out: spin_unlock_irqrestore(&xbus->lock, flags); return ret; err: for (--i ; i >= 0; i--) { xpd = xpd_of(xbus, i); if (xpd) put_xpd(__func__, xpd); } ret = -EBUSY; goto out; } static int xpd_initialize(xpd_t *xpd) { int ret = -ENODEV; if(CALL_XMETHOD(card_init, xpd) < 0) { XPD_ERR(xpd, "Card Initialization failed\n"); goto out; } xpd->card_present = 1; if (IS_PHONEDEV(xpd)) { /* * Set echo canceler channels (off) * Asterisk will tell us when/if it's needed. */ CALL_PHONE_METHOD(echocancel_setmask, xpd, 0); CALL_PHONE_METHOD(card_state, xpd, 1); /* Turn on all channels */ } if(!xpd_setstate(xpd, XPD_STATE_READY)) { goto out; } XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name); xpd_post_init(xpd); ret = 0; out: return ret; } static int xbus_echocancel(xbus_t *xbus, int on) { int unit; int subunit; xpd_t *xpd; if (!ECHOOPS(xbus)) return 0; for (unit = 0; unit < MAX_UNIT; unit++) { xpd = xpd_byaddr(xbus, unit, 0); if (!xpd || !IS_PHONEDEV(xpd)) continue; for (subunit = 0; subunit < MAX_SUBUNIT; subunit++) { int ret; xpd = xpd_byaddr(xbus, unit, subunit); if (!xpd || !IS_PHONEDEV(xpd)) continue; ret = echocancel_xpd(xpd, on); if (ret < 0) { XPD_ERR(xpd, "Fail in xbus_echocancel()\n"); return ret; } } } return 0; } static int xbus_initialize(xbus_t *xbus) { int unit; int subunit; xpd_t *xpd; struct timeval time_start; struct timeval time_end; unsigned long timediff; int res = 0; do_gettimeofday(&time_start); XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n", refcount_xbus(xbus)); if (xbus_aquire_xpds(xbus) < 0) /* Until end of initialization */ return -EBUSY; for(unit = 0; unit < MAX_UNIT; unit++) { xpd = xpd_byaddr(xbus, unit, 0); if(!xpd) continue; if (!XBUS_IS(xbus, RECVD_DESC)) { XBUS_NOTICE(xbus, "Cannot initialize UNIT=%d in state %s\n", unit, xbus_statename(XBUS_STATE(xbus))); goto err; } if(run_initialize_registers(xpd) < 0) { XBUS_ERR(xbus, "Register Initialization of card #%d failed\n", unit); goto err; } for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) { int ret; xpd = xpd_byaddr(xbus, unit, subunit); if(!xpd) continue; if (!XBUS_IS(xbus, RECVD_DESC)) { XBUS_ERR(xbus, "XPD-%d%d Not in 'RECVD_DESC' state\n", unit, subunit); goto err; } ret = xpd_initialize(xpd); if(ret < 0) goto err; } } xbus_echocancel(xbus, 1); do_gettimeofday(&time_end); timediff = usec_diff(&time_end, &time_start); timediff /= 1000*100; XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff/10, timediff%10); out: xbus_release_xpds(xbus); /* Initialization done/failed */ return res; err: xbus_setstate(xbus, XBUS_STATE_FAIL); res = -EINVAL; goto out; } /* * This must be called from synchronous (non-interrupt) context * it returns only when all XPD's on the bus are detected and * initialized. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) static void xbus_populate(struct work_struct *work) { struct xbus_workqueue *worker = container_of(work, struct xbus_workqueue, xpds_init_work); #else void xbus_populate(void *data) { struct xbus_workqueue *worker = data; #endif xbus_t *xbus; struct list_head *card; struct list_head *next_card; unsigned long flags; int ret = 0; xbus = container_of(worker, xbus_t, worker); xbus = get_xbus(__func__, xbus->num); /* return in function end */ XBUS_DBG(DEVICES, xbus, "Entering %s\n", __FUNCTION__); spin_lock_irqsave(&worker->worker_lock, flags); list_for_each_safe(card, next_card, &worker->card_list) { struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list); list_del(card); BUG_ON(card_desc->magic != CARD_DESC_MAGIC); /* Release/Reacquire locks around blocking calls */ spin_unlock_irqrestore(&xbus->worker.worker_lock, flags); ret = new_card(xbus, card_desc->xpd_addr.unit, card_desc->type, card_desc->subtype, card_desc->numchips, card_desc->ports_per_chip, card_desc->ports, card_desc->port_dir); spin_lock_irqsave(&xbus->worker.worker_lock, flags); KZFREE(card_desc); if(ret) break; } spin_unlock_irqrestore(&worker->worker_lock, flags); if(xbus_initialize(xbus) < 0) { XBUS_NOTICE(xbus, "Initialization failed. Leave unused. refcount_xbus=%d\n", refcount_xbus(xbus)); goto failed; } if(!xbus_setstate(xbus, XBUS_STATE_READY)) { XBUS_NOTICE(xbus, "Illegal transition. Leave unused. refcount_xbus=%d\n", refcount_xbus(xbus)); goto failed; } worker->xpds_init_done = 1; /* * Now request Astribank to start self_ticking. * This is the last initialization command. So * all others will reach the device before it. */ xbus_request_sync(xbus, SYNC_MODE_PLL); elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */ out: XBUS_DBG(DEVICES, xbus, "Leaving\n"); wake_up_interruptible_all(&worker->wait_for_xpd_initialization); XBUS_DBG(DEVICES, xbus, "populate release\n"); up(&worker->running_initialization); put_xbus(__func__, xbus); /* taken at function entry */ return; failed: xbus_setstate(xbus, XBUS_STATE_FAIL); goto out; } int xbus_process_worker(xbus_t *xbus) { struct xbus_workqueue *worker; if(!xbus) { ERR("%s: xbus gone -- skip initialization\n", __FUNCTION__); return 0; } worker = &xbus->worker; if (down_trylock(&worker->running_initialization)) { ERR("%s: xbus is disconnected -- skip initialization\n", __FUNCTION__); return 0; } XBUS_DBG(DEVICES, xbus, "\n"); /* Initialize the work. (adapt to kernel API changes). */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) INIT_WORK(&worker->xpds_init_work, xbus_populate); #else INIT_WORK(&worker->xpds_init_work, xbus_populate, worker); #endif BUG_ON(!xbus); /* Now send it */ if(!queue_work(worker->wq, &worker->xpds_init_work)) { XBUS_ERR(xbus, "Failed to queue xpd initialization work\n"); up(&worker->running_initialization); return 0; } return 1; } static void worker_reset(xbus_t *xbus) { struct xbus_workqueue *worker; struct list_head *card; struct list_head *next_card; unsigned long flags; char *name; BUG_ON(!xbus); worker = &xbus->worker; name = (xbus) ? xbus->busname : "detached"; DBG(DEVICES, "%s\n", name); if(!worker->xpds_init_done) { NOTICE("%s: worker(%s)->xpds_init_done=%d\n", __FUNCTION__, name, worker->xpds_init_done); } spin_lock_irqsave(&worker->worker_lock, flags); list_for_each_safe(card, next_card, &worker->card_list) { struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list); BUG_ON(card_desc->magic != CARD_DESC_MAGIC); list_del(card); KZFREE(card_desc); } worker->xpds_init_done = 0; worker->num_units = 0; worker->num_units_initialized = 0; wake_up_interruptible_all(&worker->wait_for_xpd_initialization); spin_unlock_irqrestore(&worker->worker_lock, flags); } static void worker_destroy(xbus_t *xbus) { struct xbus_workqueue *worker; BUG_ON(!xbus); worker = &xbus->worker; worker_reset(xbus); XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish...\n"); down(&worker->running_initialization); XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish -- done\n"); if (worker->wq) { XBUS_DBG(DEVICES, xbus, "destroying workqueue...\n"); flush_workqueue(worker->wq); destroy_workqueue(worker->wq); worker->wq = NULL; XBUS_DBG(DEVICES, xbus, "destroying workqueue -- done\n"); } XBUS_DBG(DEVICES, xbus, "detach worker\n"); put_xbus(__func__, xbus); /* got from worker_run() */ } static void worker_init(xbus_t *xbus) { struct xbus_workqueue *worker; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); worker = &xbus->worker; /* poll related variables */ spin_lock_init(&worker->worker_lock); INIT_LIST_HEAD(&worker->card_list); init_waitqueue_head(&worker->wait_for_xpd_initialization); worker->wq = NULL; sema_init(&xbus->worker.running_initialization, 1); } /* * Allocate a worker for the xbus including the nessessary workqueue. * May call blocking operations, but only briefly (as we are called * from xbus_new() which is called from khubd. */ static int worker_run(xbus_t *xbus) { struct xbus_workqueue *worker; xbus = get_xbus(__func__, xbus->num); /* return in worker_destroy() */ BUG_ON(!xbus); BUG_ON(xbus->busname[0] == '\0'); /* No name? */ worker = &xbus->worker; BUG_ON(worker->wq); /* Hmmm... nested workers? */ XBUS_DBG(DEVICES, xbus, "\n"); /* poll related variables */ worker->wq = create_singlethread_workqueue(xbus->busname); if(!worker->wq) { XBUS_ERR(xbus, "Failed to create worker workqueue.\n"); goto err; } return 1; err: worker_destroy(xbus); return 0; } bool xbus_setflags(xbus_t *xbus, int flagbit, bool on) { unsigned long flags; spin_lock_irqsave(&xbus->transport.state_lock, flags); XBUS_DBG(DEVICES, xbus, "%s flag %d\n", (on) ? "Set" : "Clear", flagbit); if(on) set_bit(flagbit, &(xbus->transport.transport_flags)); else clear_bit(flagbit, &(xbus->transport.transport_flags)); spin_unlock_irqrestore(&xbus->transport.state_lock, flags); return 1; } bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate) { unsigned long flags; bool ret = 0; int state_flip = 0; spin_lock_irqsave(&xbus->transport.state_lock, flags); if(newstate == XBUS_STATE(xbus)) { XBUS_DBG(DEVICES, xbus, "stay at %s\n", xbus_statename(newstate)); goto out; } /* Sanity tests */ switch(newstate) { case XBUS_STATE_START: goto bad_state; case XBUS_STATE_IDLE: if(!XBUS_IS(xbus, START) && !XBUS_IS(xbus, DEACTIVATED)) goto bad_state; break; case XBUS_STATE_SENT_REQUEST: if(!XBUS_IS(xbus, IDLE) && !XBUS_IS(xbus, SENT_REQUEST)) goto bad_state; break; case XBUS_STATE_RECVD_DESC: if(!XBUS_IS(xbus, SENT_REQUEST)) goto bad_state; break; case XBUS_STATE_READY: if(!XBUS_IS(xbus, RECVD_DESC)) goto bad_state; state_flip = 1; /* We are good */ break; case XBUS_STATE_DEACTIVATING: if(XBUS_IS(xbus, DEACTIVATING)) goto bad_state; if(XBUS_IS(xbus, DEACTIVATED)) goto bad_state; break; case XBUS_STATE_DEACTIVATED: if(!XBUS_IS(xbus, DEACTIVATING)) goto bad_state; break; case XBUS_STATE_FAIL: if(XBUS_IS(xbus, DEACTIVATING)) goto bad_state; if(XBUS_IS(xbus, DEACTIVATED)) goto bad_state; break; default: XBUS_NOTICE(xbus, "%s: unknown state %d\n", __FUNCTION__, newstate); goto out; } /* All good */ XBUS_DBG(DEVICES, xbus, "%s -> %s\n", xbus_statename(XBUS_STATE(xbus)), xbus_statename(newstate)); if(xbus->transport.xbus_state == XBUS_STATE_READY && newstate != XBUS_STATE_READY) state_flip = -1; /* We became bad */ xbus->transport.xbus_state = newstate; ret = 1; out: spin_unlock_irqrestore(&xbus->transport.state_lock, flags); /* Should be sent out of spinlocks */ if(state_flip > 0) astribank_uevent_send(xbus, KOBJ_ONLINE); else if(state_flip < 0) astribank_uevent_send(xbus, KOBJ_OFFLINE); return ret; bad_state: XBUS_NOTICE(xbus, "Bad state transition %s -> %s ignored.\n", xbus_statename(XBUS_STATE(xbus)), xbus_statename(newstate)); goto out; } int xbus_activate(xbus_t *xbus) { XBUS_INFO(xbus, "[%s] Activating\n", xbus->label); xpp_drift_init(xbus); xbus_set_command_timer(xbus, 1); xframe_queue_disable(&xbus->command_queue, 0); xbus_setstate(xbus, XBUS_STATE_IDLE); /* must be done after transport is valid */ CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL); /* * Make sure Astribank knows not to send us ticks. */ xbus_request_sync(xbus, SYNC_MODE_NONE); return 0; } int xbus_connect(xbus_t *xbus) { struct xbus_ops *ops; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); ops = transportops_get(xbus); BUG_ON(!ops); /* Sanity checks */ BUG_ON(!ops->xframe_send_pcm); BUG_ON(!ops->xframe_send_cmd); BUG_ON(!ops->alloc_xframe); BUG_ON(!ops->free_xframe); xbus_setflags(xbus, XBUS_FLAG_CONNECTED, 1); xbus_activate(xbus); return 0; } void xbus_deactivate(xbus_t *xbus) { BUG_ON(!xbus); XBUS_INFO(xbus, "[%s] Deactivating\n", xbus->label); if(!xbus_setstate(xbus, XBUS_STATE_DEACTIVATING)) return; xbus_request_sync(xbus, SYNC_MODE_NONE); /* no more ticks */ elect_syncer("deactivate"); xbus_echocancel(xbus, 0); xbus_request_removal(xbus); XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label); xbus_command_queue_clean(xbus); xbus_command_queue_waitempty(xbus); xbus_setstate(xbus, XBUS_STATE_DEACTIVATED); worker_reset(xbus); xbus_release_xpds(xbus); /* taken in xpd_alloc() [kref_init] */ } void xbus_disconnect(xbus_t *xbus) { BUG_ON(!xbus); XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label); xbus_setflags(xbus, XBUS_FLAG_CONNECTED, 0); xbus_deactivate(xbus); xbus_command_queue_clean(xbus); xbus_command_queue_waitempty(xbus); tasklet_kill(&xbus->receive_tasklet); xframe_queue_clear(&xbus->receive_queue); xframe_queue_clear(&xbus->send_pool); xframe_queue_clear(&xbus->receive_pool); xframe_queue_clear(&xbus->pcm_tospan); del_timer_sync(&xbus->command_timer); transportops_put(xbus); transport_destroy(xbus); worker_destroy(xbus); XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n", refcount_xbus(xbus)); xbus_sysfs_transport_remove(xbus); /* Device-Model */ put_xbus(__func__, xbus); /* from xbus_new() [kref_init()] */ } static xbus_t *xbus_alloc(void) { unsigned long flags; xbus_t *xbus; int i; xbus = KZALLOC(sizeof(xbus_t), GFP_KERNEL); if(!xbus) { ERR("%s: out of memory\n", __FUNCTION__); return NULL; } spin_lock_irqsave(&xbuses_lock, flags); for(i = 0; i < MAX_BUSES; i++) if(xbuses_array[i].xbus == NULL) break; if(i >= MAX_BUSES) { ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i); KZFREE(xbus); xbus = NULL; goto out; } /* Found empty slot */ xbus->num = i; init_xbus(i, xbus); out: spin_unlock_irqrestore(&xbuses_lock, flags); return xbus; } void xbus_free(xbus_t *xbus) { unsigned long flags; uint num; if(!xbus) return; XBUS_DBG(DEVICES, xbus, "Free\n"); spin_lock_irqsave(&xbuses_lock, flags); num = xbus->num; BUG_ON(!xbuses_array[num].xbus); BUG_ON(xbus != xbuses_array[num].xbus); spin_unlock_irqrestore(&xbuses_lock, flags); #ifdef CONFIG_PROC_FS if(xbus->proc_xbus_dir) { if(xbus->proc_xbus_summary) { XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_SUMMARY); remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir); xbus->proc_xbus_summary = NULL; } #ifdef PROTOCOL_DEBUG if(xbus->proc_xbus_command) { XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_COMMAND); remove_proc_entry(PROC_XBUS_COMMAND, xbus->proc_xbus_dir); xbus->proc_xbus_command = NULL; } #endif XBUS_DBG(PROC, xbus, "Removing proc directory\n"); remove_proc_entry(xbus->busname, xpp_proc_toplevel); xbus->proc_xbus_dir = NULL; } #endif spin_lock_irqsave(&xbuses_lock, flags); XBUS_DBG(DEVICES, xbus, "Going to free...\n"); init_xbus(num, NULL); spin_unlock_irqrestore(&xbuses_lock, flags); KZFREE(xbus); } xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) { int err; xbus_t *xbus = NULL; BUG_ON(!ops); xbus = xbus_alloc(); if(!xbus) { ERR("%s: Failed allocating new xbus\n", __FUNCTION__); module_put(THIS_MODULE); return NULL; } snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num); XBUS_DBG(DEVICES, xbus, "\n"); transport_init(xbus, ops, max_send_size, transport_device, priv); spin_lock_init(&xbus->lock); init_waitqueue_head(&xbus->command_queue_empty); init_timer(&xbus->command_timer); atomic_set(&xbus->pcm_rx_counter, 0); xbus->min_tx_sync = INT_MAX; xbus->min_rx_sync = INT_MAX; kref_init(&xbus->kref); worker_init(xbus); atomic_set(&xbus->num_xpds, 0); xbus->sync_mode = SYNC_MODE_NONE; xbus->sync_mode_default = SYNC_MODE_PLL; err = xbus_sysfs_create(xbus); if(err) { XBUS_ERR(xbus, "SYSFS creation failed: %d\n", err); goto nobus; } err = xbus_sysfs_transport_create(xbus); if (err) { XBUS_ERR(xbus, "SYSFS transport link creation failed: %d\n", err); goto nobus; } xbus_reset_counters(xbus); #ifdef CONFIG_PROC_FS XBUS_DBG(PROC, xbus, "Creating xbus proc directory\n"); xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_proc_toplevel); if(!xbus->proc_xbus_dir) { XBUS_ERR(xbus, "Failed to create proc directory\n"); err = -EIO; goto nobus; } xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir, xbus_read_proc, (void *)((unsigned long)(xbus->num))); if (!xbus->proc_xbus_summary) { XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_SUMMARY); err = -EIO; goto nobus; } SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_summary); #ifdef PROTOCOL_DEBUG xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir); if (!xbus->proc_xbus_command) { XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_COMMAND); err = -EIO; goto nobus; } xbus->proc_xbus_command->write_proc = proc_xbus_command_write; xbus->proc_xbus_command->data = xbus; SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_command); #endif #endif xframe_queue_init(&xbus->command_queue, 10, command_queue_length, "command_queue", xbus); xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus); xframe_queue_init(&xbus->send_pool, 10, 100, "send_pool", xbus); xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus); xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus); tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus); /* * Create worker after /proc/XBUS-?? so the directory exists * before /proc/XBUS-??/waitfor_xpds tries to get created. */ if (!worker_run(xbus)) { ERR("Failed to allocate worker\n"); goto nobus; } return xbus; nobus: xbus_free(xbus); return NULL; } /*------------------------- Proc handling --------------------------*/ void xbus_reset_counters(xbus_t *xbus) { int i; XBUS_DBG(GENERAL, xbus, "Reseting counters\n"); for(i = 0; i < XBUS_COUNTER_MAX; i++) { xbus->counters[i] = 0; } } static bool xpds_done(xbus_t *xbus) { if (XBUS_IS(xbus, FAIL)) return 1; /* Nothing to wait for */ if (!XBUS_IS(xbus, RECVD_DESC)) return 1; /* We are not in the initialization phase */ if (xbus->worker.xpds_init_done) return 1; /* All good */ /* Keep waiting */ return 0; } int waitfor_xpds(xbus_t *xbus, char *buf) { struct xbus_workqueue *worker; unsigned long flags; int ret; int len = 0; /* * FIXME: worker is created before ????? * So by now it exists and initialized. */ /* until end of waitfor_xpds_show(): */ xbus = get_xbus(__func__, xbus->num); if (!xbus) return -ENODEV; worker = &xbus->worker; BUG_ON(!worker); if (!worker->wq) { XBUS_ERR(xbus, "Missing worker thread. Skipping.\n"); len = -ENODEV; goto out; } if (worker->num_units == 0) { XBUS_ERR(xbus, "No cards. Skipping.\n"); goto out; } XBUS_DBG(DEVICES, xbus, "Waiting for card init of %d XPD's max %d seconds (%p)\n", worker->num_units, INITIALIZATION_TIMEOUT/HZ, &worker->wait_for_xpd_initialization); ret = wait_event_interruptible_timeout( worker->wait_for_xpd_initialization, xpds_done(xbus), INITIALIZATION_TIMEOUT); if (ret == 0) { XBUS_ERR(xbus, "Card Initialization Timeout\n"); len = -ETIMEDOUT; goto out; } else if (ret < 0) { XBUS_ERR(xbus, "Card Initialization Interrupted %d\n", ret); len = ret; goto out; } else XBUS_DBG(DEVICES, xbus, "Finished initialization of %d XPD's in %d seconds.\n", worker->num_units_initialized, (INITIALIZATION_TIMEOUT - ret)/HZ); if (XBUS_IS(xbus, FAIL)) { len += sprintf(buf, "FAILED: %s\n", xbus->busname); } else { spin_lock_irqsave(&xbus->lock, flags); len += sprintf(buf, "XPDS_READY: %s: %d/%d\n", xbus->busname, worker->num_units_initialized, worker->num_units); spin_unlock_irqrestore(&xbus->lock, flags); } out: put_xbus(__func__, xbus); /* from start of waitfor_xpds_show() */ return len; } #ifdef CONFIG_PROC_FS static int xbus_fill_proc_queue(char *p, struct xframe_queue *q) { int len; len = sprintf(p, "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", q->name, q->steady_state_count, q->count, q->max_count, q->worst_count, q->overflows, q->worst_lag_usec / 1000, q->worst_lag_usec % 1000); xframe_queue_clearstats(q); return len; } static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { xbus_t *xbus; unsigned long flags; int len = 0; int i = (int)((unsigned long)data); xbus = get_xbus(__func__, i); /* until end of xbus_read_proc */ if(!xbus) goto out; spin_lock_irqsave(&xbus->lock, flags); len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", xbus->busname, xbus->connector, xbus->label, (XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing" ); len += xbus_fill_proc_queue(page + len, &xbus->send_pool); len += xbus_fill_proc_queue(page + len, &xbus->receive_pool); len += xbus_fill_proc_queue(page + len, &xbus->command_queue); len += xbus_fill_proc_queue(page + len, &xbus->receive_queue); len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan); if(rx_tasklet) { len += sprintf(page + len, "\ncpu_rcv_intr: "); for_each_online_cpu(i) len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]); len += sprintf(page + len, "\ncpu_rcv_tasklet: "); for_each_online_cpu(i) len += sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]); len += sprintf(page + len, "\n"); } len += sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n", xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec); len += sprintf(page + len, "command_tick: %d\n", xbus->command_tick_counter); len += sprintf(page + len, "usec_nosend: %d\n", xbus->usec_nosend); len += sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n", atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count); len += sprintf(page + len, "max_rx_process = %2ld.%ld ms\n", xbus->max_rx_process / 1000, xbus->max_rx_process % 1000); xbus->max_rx_process = 0; len += sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n", MAX_SEND_SIZE(xbus), atomic_read(&xbus->transport.transport_refcount) ); len += sprintf(page + len, "PCM Metrices:\n"); len += sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n", xbus->min_tx_sync, xbus->max_tx_sync); len += sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n", xbus->min_rx_sync, xbus->max_rx_sync); len += sprintf(page + len, "COUNTERS:\n"); for(i = 0; i < XBUS_COUNTER_MAX; i++) { len += sprintf(page + len, "\t%-15s = %d\n", xbus_counters[i].name, xbus->counters[i]); } len += sprintf(page + len, "<-- len=%d\n", len); spin_unlock_irqrestore(&xbus->lock, flags); put_xbus(__FUNCTION__, xbus); /* from xbus_read_proc() */ out: if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #ifdef PROTOCOL_DEBUG static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { char *buf; xbus_t *xbus = data; char *p; byte *pack_start; byte *q; xframe_t *xframe; size_t len; const size_t max_len = xbus->transport.max_send_size; const size_t max_text = max_len * 3 + 10; if(count > max_text) { XBUS_ERR(xbus, "%s: line too long (%ld > %zd)\n", __FUNCTION__, count, max_len); return -EFBIG; } /* 3 bytes per hex-digit and space */ buf = kmalloc(max_text, GFP_KERNEL); if(!buf) return -ENOMEM; if(copy_from_user(buf, buffer, count)) { count = -EINVAL; goto out; } buf[count] = '\0'; XBUS_DBG(GENERAL, xbus, "count=%ld\n", count); /* * We replace the content of buf[] from * ascii representation to packet content * as the binary representation is shorter */ q = pack_start = buf; for(p = buf; *p;) { int val; char hexdigit[3]; while(*p && isspace(*p)) // skip whitespace p++; if(!(*p)) break; if(!isxdigit(*p)) { XBUS_ERR(xbus, "%s: bad hex value ASCII='0x%X' at position %ld\n", __FUNCTION__, *p, (long)(p - buf)); count = -EINVAL; goto out; } hexdigit[0] = *p++; hexdigit[1] = '\0'; hexdigit[2] = '\0'; if(isxdigit(*p)) hexdigit[1] = *p++; if(sscanf(hexdigit, "%2X", &val) != 1) { XBUS_ERR(xbus, "%s: bad hex value '%s' at position %ld\n", __FUNCTION__, hexdigit, (long)(p - buf)); count = -EINVAL; goto out; } *q++ = val; XBUS_DBG(GENERAL, xbus, "%3zd> '%s' val=%d\n", q - pack_start, hexdigit, val); } len = q - pack_start; xframe = ALLOC_SEND_XFRAME(xbus); if(!xframe) { count = -ENOMEM; goto out; } if(len > max_len) len = max_len; atomic_set(&xframe->frame_len, len); memcpy(xframe->packets, pack_start, len); /* FIXME: checksum? */ dump_xframe("COMMAND", xbus, xframe, debug); send_cmd_frame(xbus, xframe); out: kfree(buf); return count; } #endif static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; int i; for(i = 0; i < MAX_BUSES; i++) { xbus_t *xbus = get_xbus(__func__, i); if(xbus) { len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", xbus->busname, xbus->connector, xbus->label, (XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing" ); put_xbus(__func__, xbus); } } #if 0 len += sprintf(page + len, "<-- len=%d\n", len); #endif if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) { BUG_ON(!xbus); BUG_ON(!ops); BUG_ON(!ops->xframe_send_pcm); BUG_ON(!ops->xframe_send_cmd); BUG_ON(!ops->alloc_xframe); BUG_ON(!ops->free_xframe); xbus->transport.ops = ops; xbus->transport.max_send_size = max_send_size; xbus->transport.transport_device = transport_device; xbus->transport.priv = priv; xbus->transport.xbus_state = XBUS_STATE_START; spin_lock_init(&xbus->transport.state_lock); spin_lock_init(&xbus->transport.lock); atomic_set(&xbus->transport.transport_refcount, 0); xbus_setflags(xbus, XBUS_FLAG_CONNECTED, 0); init_waitqueue_head(&xbus->transport.transport_unused); } static void transport_destroy(xbus_t *xbus) { int ret; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n", atomic_read(&xbus->transport.transport_refcount)); ret = wait_event_interruptible(xbus->transport.transport_unused, atomic_read(&xbus->transport.transport_refcount) == 0); if(ret) XBUS_ERR(xbus, "Waiting for transport_refcount interrupted!!!\n"); xbus->transport.ops = NULL; xbus->transport.priv = NULL; } struct xbus_ops *transportops_get(xbus_t *xbus) { struct xbus_ops *ops; BUG_ON(!xbus); atomic_inc(&xbus->transport.transport_refcount); ops = xbus->transport.ops; if(!ops) atomic_dec(&xbus->transport.transport_refcount); /* fall through */ return ops; } void transportops_put(xbus_t *xbus) { struct xbus_ops *ops; BUG_ON(!xbus); ops = xbus->transport.ops; BUG_ON(!ops); if(atomic_dec_and_test(&xbus->transport.transport_refcount)) wake_up(&xbus->transport.transport_unused); } /*------------------------- Initialization -------------------------*/ static void xbus_core_cleanup(void) { finalize_xbuses_array(); #ifdef CONFIG_PROC_FS if(proc_xbuses) { DBG(PROC, "Removing " PROC_XBUSES " from proc\n"); remove_proc_entry(PROC_XBUSES, xpp_proc_toplevel); proc_xbuses = NULL; } #endif } int __init xbus_core_init(void) { int ret = 0; initialize_xbuses_array(); #ifdef PROTOCOL_DEBUG INFO("FEATURE: with PROTOCOL_DEBUG\n"); #endif #ifdef CONFIG_PROC_FS proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, NULL); if (!proc_xbuses) { ERR("Failed to create proc file %s\n", PROC_XBUSES); ret = -EFAULT; goto err; } SET_PROC_DIRENTRY_OWNER(proc_xbuses); #endif if((ret = xpp_driver_init()) < 0) goto err; return 0; err: xbus_core_cleanup(); return ret; } void xbus_core_shutdown(void) { int i; for(i = 0; i < MAX_BUSES; i++) BUG_ON(xbus_num(i)); xbus_core_cleanup(); xpp_driver_exit(); } EXPORT_SYMBOL(xpd_of); EXPORT_SYMBOL(xpd_byaddr); EXPORT_SYMBOL(xbus_num); EXPORT_SYMBOL(xbus_setstate); EXPORT_SYMBOL(xbus_statename); EXPORT_SYMBOL(xbus_new); EXPORT_SYMBOL(xbus_free); EXPORT_SYMBOL(xbus_connect); EXPORT_SYMBOL(xbus_activate); EXPORT_SYMBOL(xbus_deactivate); EXPORT_SYMBOL(xbus_disconnect); EXPORT_SYMBOL(xbus_receive_xframe); EXPORT_SYMBOL(xbus_reset_counters); EXPORT_SYMBOL(xframe_next_packet); EXPORT_SYMBOL(dump_xframe); EXPORT_SYMBOL(send_pcm_frame); EXPORT_SYMBOL(send_cmd_frame); EXPORT_SYMBOL(xframe_init); EXPORT_SYMBOL(transportops_get); EXPORT_SYMBOL(transportops_put); EXPORT_SYMBOL(xbus_command_queue_tick); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp_usb.c0000644000175000017500000007676011571765744021232 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include /* for udelay */ #include #include #include #include #include #include #include "xpd.h" #include "xproto.h" #include "xbus-core.h" #include "xframe_queue.h" #ifdef DEBUG #include "card_fxs.h" #include "card_fxo.h" #endif #include "parport_debug.h" static const char rcsid[] = "$Id: xpp_usb.c 9929 2011-06-02 20:00:36Z sruffell $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM(int, usb1, 0, 0644, "Allow using USB 1.1 interfaces"); static DEF_PARM(uint, tx_sluggish, 2000, 0644, "A sluggish transmit (usec)"); static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggish to drop a PCM frame"); #include "dahdi_debug.h" #define XUSB_PRINTK(level, xusb, fmt, ...) \ printk(KERN_ ## level "%s-%s: xusb-%d (%s) [%s]: " fmt, #level, \ THIS_MODULE->name, (xusb)->index, xusb->path, xusb->serial, ## __VA_ARGS__) #define XUSB_DBG(bits, xusb, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && XUSB_PRINTK(DEBUG, xusb, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define XUSB_ERR(xusb, fmt, ...) XUSB_PRINTK(ERR, xusb, fmt, ## __VA_ARGS__) #define XUSB_NOTICE(xusb, fmt, ...) XUSB_PRINTK(NOTICE, xusb, fmt, ## __VA_ARGS__) #define XUSB_INFO(xusb, fmt, ...) XUSB_PRINTK(INFO, xusb, fmt, ## __VA_ARGS__) /* FIXME: A flag that was deprecated at some point, and rather useless */ /* anyway. Only used in the code or-ed to other flags */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) # define URB_ASYNC_UNLINK 0 #endif /* Get a minor range for your devices from the usb maintainer */ #define USB_SKEL_MINOR_BASE 192 #ifdef CONFIG_PROC_FS #define PROC_USBXPP_SUMMARY "xpp_usb" #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) # define usb_alloc_coherent(dev, size, mem_flags, dma) \ usb_buffer_alloc(dev, size, mem_flags, dma) # define usb_free_coherent(dev, size, addr, dma) \ usb_buffer_free(dev, size, addr, dma) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) # undef USB_FIELDS_MISSING #else # define USB_FIELDS_MISSING # define USB_MAX_STRING 128 # define USB_GET_STRING(udev,field,buf) \ do { \ if((udev)->descriptor.field) { \ char tmp[USB_MAX_STRING]; \ if(usb_string((udev), (udev)->descriptor.field, tmp, sizeof(tmp)) > 0) \ snprintf((buf), USB_MAX_STRING, "%s", tmp); \ } \ } while(0); # define USB_GET_IFACE_NAME(udev,iface,buf) \ do { \ if((iface)->desc.iInterface) { \ char tmp[USB_MAX_STRING]; \ if(usb_string((udev), (iface)->desc.iInterface, tmp, sizeof(tmp)) > 0) \ snprintf((buf), USB_MAX_STRING, "%s", tmp); \ } \ } while(0); #endif #ifdef DEBUG_PCM_TIMING static cycles_t stamp_last_pcm_read; static cycles_t accumulate_diff; #endif struct xusb_model_info; struct xusb_endpoint { int ep_addr; int max_size; usb_complete_t callback; }; enum xusb_dir { XUSB_RECV = 0, XUSB_SEND = 1, }; static __must_check int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe); static __must_check int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe); static __must_check xframe_t *alloc_xframe(xbus_t *xbus, gfp_t flags); static void free_xframe(xbus_t *xbus, xframe_t *frm); static struct xbus_ops xusb_ops = { .xframe_send_pcm = xframe_send_pcm, .xframe_send_cmd = xframe_send_cmd, .alloc_xframe = alloc_xframe, .free_xframe = free_xframe, }; enum { XUSB_N_RX_FRAMES, XUSB_N_TX_FRAMES, XUSB_N_RX_ERRORS, XUSB_N_TX_ERRORS, XUSB_N_RCV_ZERO_LEN, }; #define XUSB_COUNTER(xusb, counter) ((xusb)->counters[XUSB_N_ ## counter]) #define C_(x) [ XUSB_N_ ## x ] = { #x } static struct xusb_counters { char *name; } xusb_counters[] = { C_(RX_FRAMES), C_(TX_FRAMES), C_(RX_ERRORS), C_(TX_ERRORS), C_(RCV_ZERO_LEN), }; #undef C_ #define XUSB_COUNTER_MAX ARRAY_SIZE(xusb_counters) #define MAX_PENDING_WRITES 100 static KMEM_CACHE_T *xusb_cache = NULL; typedef struct xusb xusb_t; /* * A uframe is our low level representation of a frame. * * It contains the metadata for the usb stack (a urb) * and the metadata for the xbus-core (an xframe) * as well as pointing to the data (transfer_buffer, transfer_buffer_length) * directionality (send/receive) and ownership (xusb). */ struct uframe { unsigned long uframe_magic; #define UFRAME_MAGIC 654321L struct urb urb; xframe_t xframe; size_t transfer_buffer_length; void *transfer_buffer; /* max XFRAME_DATASIZE */ xusb_t *xusb; }; #define urb_to_uframe(urb) container_of(urb, struct uframe, urb) #define xframe_to_uframe(xframe) container_of(xframe, struct uframe, xframe) #define xusb_of(xbus) ((xusb_t *)((xbus)->transport.priv)) #define USEC_BUCKET 100 /* usec */ #define NUM_BUCKETS 15 #define BUCKET_START (500/USEC_BUCKET) /* skip uninteresting */ /* * USB XPP Bus (a USB Device) */ struct xusb { uint xbus_num; struct usb_device *udev; /* save off the usb device pointer */ struct usb_interface *interface; /* the interface for this device */ unsigned char minor; /* the starting minor number for this device */ uint index; char path[XBUS_DESCLEN]; /* a unique path */ struct xusb_model_info *model_info; struct xusb_endpoint endpoints[2]; /* RECV/SEND endpoints */ int present; /* if the device is not disconnected */ atomic_t pending_writes; /* submited but not out yet */ atomic_t pending_reads; /* submited but not in yet */ struct semaphore sem; /* locks this structure */ int counters[XUSB_COUNTER_MAX]; /* metrics */ struct timeval last_tx; unsigned int max_tx_delay; uint usb_tx_delay[NUM_BUCKETS]; uint sluggish_debounce; bool drop_next_pcm; /* due to sluggishness */ atomic_t pcm_tx_drops; atomic_t usb_sluggish_count; #ifdef USB_FIELDS_MISSING /* storage for missing strings in old kernels */ char manufacturer[USB_MAX_STRING]; char product[USB_MAX_STRING]; char serial[USB_MAX_STRING]; char interface_name[USB_MAX_STRING]; #else const char *manufacturer; const char *product; const char *serial; const char *interface_name; #endif }; static DEFINE_SPINLOCK(xusb_lock); static xusb_t *xusb_array[MAX_BUSES] = {}; static unsigned bus_count = 0; /* prevent races between open() and disconnect() */ static DEFINE_SEMAPHORE(disconnect_sem); /* * AsteriskNow kernel has backported the "lean" callback from 2.6.20 * to 2.6.19 without any macro to notify of this fact -- how lovely. * Debian-Etch and Centos5 are using 2.6.18 for now (lucky for us). * Fedora6 jumped from 2.6.18 to 2.6.20. So far luck is on our side ;-) */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #define USB_PASS_CB(u) struct urb *u, struct pt_regs *regs #else #define USB_PASS_CB(u) struct urb *u #endif static void xpp_send_callback(USB_PASS_CB(urb)); static void xpp_receive_callback(USB_PASS_CB(urb)); static int xusb_probe (struct usb_interface *interface, const struct usb_device_id *id); static void xusb_disconnect (struct usb_interface *interface); #ifdef CONFIG_PROC_FS static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); #endif /*------------------------------------------------------------------*/ /* * Updates the urb+xframe metadata from the uframe information. */ static void uframe_recompute(struct uframe *uframe, enum xusb_dir dir) { struct urb *urb = &uframe->urb; xusb_t *xusb = uframe->xusb; struct usb_device *udev = xusb->udev; struct xusb_endpoint *xusb_ep = &xusb->endpoints[dir]; unsigned int ep_addr = xusb_ep->ep_addr; usb_complete_t urb_cb = xusb_ep->callback; unsigned int epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK; int pipe = usb_pipein(ep_addr) ? usb_rcvbulkpipe(udev, epnum) : usb_sndbulkpipe(udev, epnum); BUG_ON(uframe->uframe_magic != UFRAME_MAGIC); usb_fill_bulk_urb(urb, udev, pipe, uframe->transfer_buffer, uframe->transfer_buffer_length, urb_cb, uframe); urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags) { struct uframe *uframe; xusb_t *xusb; void *p; int size; static int rate_limit; BUG_ON(!xbus); xusb = xusb_of(xbus); BUG_ON(!xusb); if(!xusb->present) { if((rate_limit++ % 1003) == 0) XUSB_ERR(xusb, "abort allocations during device disconnect (%d)\n", rate_limit); return NULL; } size = min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size); uframe = kmem_cache_alloc(xusb_cache, gfp_flags); if(!uframe) { if((rate_limit++ % 1003) == 0) XUSB_ERR(xusb, "frame allocation failed (%d)\n", rate_limit); return NULL; } usb_init_urb(&uframe->urb); p = usb_alloc_coherent(xusb->udev, size, gfp_flags, &uframe->urb.transfer_dma); if(!p) { if((rate_limit++ % 1003) == 0) XUSB_ERR(xusb, "buffer allocation failed (%d)\n", rate_limit); kmem_cache_free(xusb_cache, uframe); return NULL; } uframe->uframe_magic = UFRAME_MAGIC; uframe->transfer_buffer_length = size; uframe->transfer_buffer = p; uframe->xusb = xusb; xframe_init(xbus, &uframe->xframe, uframe->transfer_buffer, uframe->transfer_buffer_length, uframe); return &uframe->xframe; } static void free_xframe(xbus_t *xbus, xframe_t *xframe) { struct uframe *uframe = xframe_to_uframe(xframe); struct urb *urb = &uframe->urb; BUG_ON(xbus->transport.priv != uframe->xusb); //XUSB_INFO(uframe->xusb, "frame_free\n"); usb_free_coherent(urb->dev, uframe->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); memset(uframe, 0, sizeof(*uframe)); kmem_cache_free(xusb_cache, uframe); } /*------------------------------------------------------------------*/ /* * Actuall frame sending -- both PCM and commands. */ static int do_send_xframe(xbus_t *xbus, xframe_t *xframe) { struct urb *urb; xusb_t *xusb; int ret = 0; struct uframe *uframe; BUG_ON(!xframe); BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); xusb = xusb_of(xbus); BUG_ON(!xusb); if(!xusb->present) { static int rate_limit; if((rate_limit++ % 1003) == 0) XUSB_ERR(xusb, "abort do_send_xframe during device disconnect (%d)\n", rate_limit); ret = -ENODEV; goto failure; } /* * If something really bad happend, do not overflow the USB stack */ if(atomic_read(&xusb->pending_writes) > MAX_PENDING_WRITES) { static int rate_limit; if((rate_limit++ % 5000) == 0) XUSB_ERR(xusb, "USB device is totaly stuck. Dropping packets (#%d).\n", rate_limit); ret = -ENODEV; goto failure; } uframe = xframe->priv; BUG_ON(!uframe); BUG_ON(uframe->uframe_magic != UFRAME_MAGIC); uframe_recompute(uframe, XUSB_SEND); urb = &uframe->urb; BUG_ON(!urb); /* update urb length */ urb->transfer_buffer_length = XFRAME_LEN(xframe); do_gettimeofday(&xframe->tv_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); if(ret < 0) { static int rate_limit; if((rate_limit++ % 1000) == 0) XBUS_ERR(xbus, "%s: usb_submit_urb failed: %d\n", __FUNCTION__, ret); ret = -EBADF; goto failure; } // if (debug) // dump_xframe("USB_FRAME_SEND", xbus, xframe, debug); atomic_inc(&xusb->pending_writes); return 0; failure: XUSB_COUNTER(xusb, TX_ERRORS)++; FREE_SEND_XFRAME(xbus, xframe); /* return to pool */ return ret; } /* * PCM wrapper */ static int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe) { xusb_t *xusb; BUG_ON(!xbus); BUG_ON(!xframe); xusb = xusb_of(xbus); BUG_ON(!xusb); if(xusb->drop_next_pcm) { FREE_SEND_XFRAME(xbus, xframe); /* return to pool */ xusb->drop_next_pcm = 0; return -EIO; } return do_send_xframe(xbus, xframe); } /* * commands wrapper */ static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe) { BUG_ON(!xbus); BUG_ON(!xframe); //XBUS_INFO(xbus, "%s:\n", __FUNCTION__); return do_send_xframe(xbus, xframe); } /* * get a urb from the receive_pool and submit it on the read endpoint. */ static bool xusb_listen(xusb_t *xusb) { xbus_t *xbus = xbus_num(xusb->xbus_num); xframe_t *xframe; struct uframe *uframe; int ret = 0; BUG_ON(!xbus); xframe = ALLOC_RECV_XFRAME(xbus); if(!xframe) { XBUS_ERR(xbus, "Empty receive_pool\n"); goto out; } uframe = xframe_to_uframe(xframe); uframe_recompute(uframe, XUSB_RECV); ret = usb_submit_urb(&uframe->urb, GFP_ATOMIC); if(ret < 0) { static int rate_limit; if((rate_limit++ % 1000) == 0) XBUS_ERR(xbus, "%s: usb_submit_urb failed: %d\n", __FUNCTION__, ret); FREE_RECV_XFRAME(xbus, xframe); goto out; } atomic_inc(&xusb->pending_reads); ret = 1; out: return ret; } /*------------------------- XPP USB Bus Handling -------------------*/ enum XUSB_MODELS { MODEL_FPGA_XPD }; static const struct xusb_model_info { const char *desc; int iface_num; struct xusb_endpoint in; struct xusb_endpoint out; } model_table[] = { [MODEL_FPGA_XPD] = { .iface_num = 0, .in = { .ep_addr = 0x86 }, .out = { .ep_addr = 0x02 }, .desc = "FPGA_XPD" }, }; /* table of devices that work with this driver */ static const struct usb_device_id xusb_table [] = { { USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_FXS { USB_DEVICE(0xE4E4, 0x1142), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1141 { USB_DEVICE(0xE4E4, 0x1152), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1151 { USB_DEVICE(0xE4E4, 0x1162), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1161 { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, xusb_table); /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver xusb_driver = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) .owner = THIS_MODULE, #endif .name = "xpp_usb", .probe = xusb_probe, .disconnect = xusb_disconnect, .id_table = xusb_table, }; /* * File operations needed when we register this driver. * This assumes that this driver NEEDS file operations, * of course, which means that the driver is expected * to have a node in the /dev directory. If the USB * device were for a network interface then the driver * would use "struct net_driver" instead, and a serial * device would use "struct tty_driver". */ static struct file_operations xusb_fops = { /* * The owner field is part of the module-locking * mechanism. The idea is that the kernel knows * which module to increment the use-counter of * BEFORE it calls the device's open() function. * This also means that the kernel can decrement * the use-counter again before calling release() * or should the open() function fail. */ .owner = THIS_MODULE, }; /* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with devfs and the driver core */ static struct usb_class_driver xusb_class = { .name = "usb/xpp_usb%d", .fops = &xusb_fops, /* FIXME: The sysfs class interfase seems to have chaged around here */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, #endif .minor_base = USB_SKEL_MINOR_BASE, }; /* * Check that an endpoint's wMaxPacketSize attribute is 512. This * indicates that it is a USB2's high speed end point. * * If it is 64, it means we have a USB1 controller. By default we do not * support it and just fail the probe of the device. However if the user * has set usb1=1, we continue and just put a notice. * * Returns true if all OK, false otherwise. */ static int check_usb1(struct usb_endpoint_descriptor *endpoint) { const char *msg = (usb_pipein(endpoint->bEndpointAddress))?"input":"output"; if(endpoint->wMaxPacketSize >= sizeof(xpacket_t)) return 1; if(usb1) { NOTICE("USB1 endpoint detected: USB %s endpoint 0x%X support only wMaxPacketSize=%d.\n", msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize); return 1; } NOTICE("USB1 endpoint detected. Device disabled. To enable: usb1=1, and read docs. (%s, endpoint %d, size %d).\n", msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize); return 0; } /* * set up the endpoint information * check out the endpoints * FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16] */ static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, struct xusb_model_info *model_info) { struct usb_endpoint_descriptor *endpoint; struct xusb_endpoint *xusb_ep; int ep_addr; int i; #define BULK_ENDPOINT(ep) (((ep)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; ep_addr = endpoint->bEndpointAddress; if(!BULK_ENDPOINT(endpoint)) { DBG(DEVICES, "endpoint 0x%x is not bulk: mbAttributes=0x%X\n", ep_addr, endpoint->bmAttributes); continue; } if(usb_pipein(ep_addr)) { // Input if(ep_addr == model_info->in.ep_addr) { if (!check_usb1(endpoint)) return 0; xusb_ep = &xusb->endpoints[XUSB_RECV]; xusb_ep->ep_addr = ep_addr; xusb_ep->max_size = endpoint->wMaxPacketSize; xusb_ep->callback = xpp_receive_callback; } } else { // Output if(ep_addr == model_info->out.ep_addr) { if (!check_usb1(endpoint)) return 0; xusb_ep = &xusb->endpoints[XUSB_SEND]; xusb_ep->ep_addr = ep_addr; xusb_ep->max_size = endpoint->wMaxPacketSize; xusb_ep->callback = xpp_send_callback; } } } if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) { XUSB_ERR(xusb, "Couldn't find bulk-in or bulk-out endpoints\n"); return 0; } DBG(DEVICES, "in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr); return 1; } /* * The USB stack before 2.6.10 seems to be a bit shoddy. It seems that when * being called from the probe we may already have the lock to udev (the Usb DEVice). * Thus we call the internal __usb_reset_device instead. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) #define DO_USB_RESET_DEVICE(dev) __usb_reset_device(dev) #else #define DO_USB_RESET_DEVICE(dev) usb_reset_device(dev) #endif /** * xusb_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */ static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0); xusb_t *xusb = NULL; struct xusb_model_info *model_info = (struct xusb_model_info*)id->driver_info; #ifdef CONFIG_PROC_FS struct proc_dir_entry *procsummary = NULL; #endif xbus_t *xbus = NULL; unsigned long flags; int retval = -ENOMEM; int i; DBG(DEVICES, "New XUSB device MODEL=%s\n", model_info->desc); if(iface_desc->desc.bInterfaceNumber != model_info->iface_num) { DBG(DEVICES, "Skip interface #%d != #%d\n", iface_desc->desc.bInterfaceNumber, model_info->iface_num); return -ENODEV; } if((retval = DO_USB_RESET_DEVICE(udev)) < 0) { ERR("usb_reset_device failed: %d\n", retval); goto probe_failed; } if (!model_info) { ERR("Missing endpoint setup for this device %d:%d\n", udev->descriptor.idVendor,udev->descriptor.idProduct); retval = -ENODEV; goto probe_failed; } /* allocate memory for our device state and initialize it */ xusb = KZALLOC(sizeof(xusb_t), GFP_KERNEL); if (xusb == NULL) { ERR("xpp_usb: Unable to allocate new xpp usb bus\n"); retval = -ENOMEM; goto probe_failed; } sema_init(&xusb->sem, 1); atomic_set(&xusb->pending_writes, 0); atomic_set(&xusb->pending_reads, 0); atomic_set(&xusb->pcm_tx_drops, 0); atomic_set(&xusb->usb_sluggish_count, 0); xusb->udev = udev; xusb->interface = interface; xusb->model_info = model_info; if(!set_endpoints(xusb, iface_desc, model_info)) { retval = -ENODEV; goto probe_failed; } #ifndef USB_FIELDS_MISSING xusb->serial = udev->serial; xusb->manufacturer = udev->manufacturer; xusb->product = udev->product; xusb->interface_name = iface_desc->string; #else USB_GET_STRING(udev, iSerialNumber, xusb->serial); USB_GET_STRING(udev, iManufacturer, xusb->manufacturer); USB_GET_STRING(udev, iProduct, xusb->product); USB_GET_IFACE_NAME(udev, iface_desc, xusb->interface_name); #endif INFO("XUSB: %s -- %s -- %s\n", xusb->manufacturer, xusb->product, xusb->interface_name); /* allow device read, write and ioctl */ xusb->present = 1; /* we can register the device now, as it is ready */ usb_set_intfdata(interface, xusb); retval = usb_register_dev (interface, &xusb_class); if (retval) { /* something prevented us from registering this driver */ ERR ("Not able to get a minor for this device.\n"); goto probe_failed; } xusb->minor = interface->minor; /* let the user know what node this device is now attached to */ DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor); xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), &udev->dev, xusb); if(!xbus) { retval = -ENOMEM; goto probe_failed; } spin_lock_irqsave(&xusb_lock, flags); for(i = 0; i < MAX_BUSES; i++) { if(xusb_array[i] == NULL) break; } spin_unlock_irqrestore(&xusb_lock, flags); if(i >= MAX_BUSES) { ERR("xpp_usb: Too many XPP USB buses\n"); retval = -ENOMEM; goto probe_failed; } usb_make_path(udev, xusb->path, XBUS_DESCLEN); // May trunacte... ignore snprintf(xbus->connector, XBUS_DESCLEN, "%s", xusb->path); if(xusb->serial && xusb->serial[0]) snprintf(xbus->label, LABEL_SIZE, "usb:%s", xusb->serial); xusb->index = i; xusb_array[i] = xusb; XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->connector); #ifdef CONFIG_PROC_FS DBG(PROC, "Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n"); procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444, xbus->proc_xbus_dir, xusb_read_proc, xusb); if (!procsummary) { XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_USBXPP_SUMMARY); // FIXME: better error handling retval = -EIO; goto probe_failed; } SET_PROC_DIRENTRY_OWNER(procsummary); #endif bus_count++; xusb->xbus_num = xbus->num; /* prepare several pending frames for receive side */ for(i = 0; i < 10; i++) xusb_listen(xusb); xbus_connect(xbus); return retval; probe_failed: ERR("Failed to initialize xpp usb bus: %d\n", retval); usb_set_intfdata(interface, NULL); if(xusb) { if(xusb->minor) { // passed registration phase ERR("Calling usb_deregister_dev()\n"); usb_deregister_dev(interface, &xusb_class); } ERR("Removing failed xusb\n"); KZFREE(xusb); } if(xbus) { #ifdef CONFIG_PROC_FS if(procsummary) { XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n"); remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir); procsummary = NULL; } #endif ERR("Calling xbus_disconnect()\n"); xbus_disconnect(xbus); // Blocking until fully deactivated! } return retval; } /** * xusb_disconnect * * Called by the usb core when the device is removed from the system. * * This routine guarantees that the driver will not submit any more urbs * by clearing dev->udev. It is also supposed to terminate any currently * active urbs. Unfortunately, usb_bulk_msg(), used in xusb_read(), does * not provide any way to do this. But at least we can cancel an active * write. */ static void xusb_disconnect(struct usb_interface *interface) { struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0); xusb_t *xusb; xbus_t *xbus; int i; DBG(DEVICES, "CALLED on interface #%d\n", iface_desc->desc.bInterfaceNumber); /* prevent races with open() */ down (&disconnect_sem); xusb = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); xusb->present = 0; xbus = xbus_num(xusb->xbus_num); /* find our xusb */ for(i = 0; i < MAX_BUSES; i++) { if(xusb_array[i] == xusb) break; } BUG_ON(i >= MAX_BUSES); xusb_array[i] = NULL; #ifdef CONFIG_PROC_FS if(xbus->proc_xbus_dir) { XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n"); remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir); } #endif xbus_disconnect(xbus); // Blocking until fully deactivated! down (&xusb->sem); /* give back our minor */ usb_deregister_dev(interface, &xusb_class); up (&xusb->sem); DBG(DEVICES, "Semaphore released\n"); XUSB_INFO(xusb, "now disconnected\n"); KZFREE(xusb); up (&disconnect_sem); } static void xpp_send_callback(USB_PASS_CB(urb)) { struct uframe *uframe = urb_to_uframe(urb); xframe_t *xframe = &uframe->xframe; xusb_t *xusb = uframe->xusb; xbus_t *xbus = xbus_num(xusb->xbus_num); struct timeval now; long usec; int writes = atomic_read(&xusb->pending_writes); int i; if(!xbus) { XUSB_ERR(xusb, "Sent URB does not belong to a valid xbus anymore...\n"); return; } //flip_parport_bit(6); atomic_dec(&xusb->pending_writes); do_gettimeofday(&now); xusb->last_tx = xframe->tv_submitted; usec = usec_diff(&now, &xframe->tv_submitted); if(usec > xusb->max_tx_delay) xusb->max_tx_delay = usec; i = usec / USEC_BUCKET; if(i >= NUM_BUCKETS) i = NUM_BUCKETS - 1; xusb->usb_tx_delay[i]++; if(unlikely(usec > tx_sluggish)) { atomic_inc(&xusb->usb_sluggish_count); if(xusb->sluggish_debounce++ > drop_pcm_after) { static int rate_limit; if((rate_limit++ % 1003) == 500) /* skip first messages */ XUSB_NOTICE(xusb, "Sluggish USB. Dropping next PCM frame (pending_writes=%d)\n", writes); atomic_inc(&xusb->pcm_tx_drops); xusb->drop_next_pcm = 1; xusb->sluggish_debounce = 0; } } else xusb->sluggish_debounce = 0; /* sync/async unlink faults aren't errors */ if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) { static int rate_limit; if((rate_limit++ % 1000) < 10) { XUSB_ERR(xusb, "nonzero write bulk status received: %d (pending_writes=%d)\n", urb->status, writes); dump_xframe("usb-write-error", xbus, xframe, DBG_ANY); } XUSB_COUNTER(xusb, TX_ERRORS)++; } else XUSB_COUNTER(xusb, TX_FRAMES)++; FREE_SEND_XFRAME(xbus, xframe); if(!xusb->present) XUSB_ERR(xusb, "A urb from non-connected device?\n"); } static void xpp_receive_callback(USB_PASS_CB(urb)) { struct uframe *uframe = urb_to_uframe(urb); xframe_t *xframe = &uframe->xframe; xusb_t *xusb = uframe->xusb; xbus_t *xbus = xbus_num(xusb->xbus_num); size_t size; bool do_resubmit = 1; struct timeval now; do_gettimeofday(&now); atomic_dec(&xusb->pending_reads); if(!xbus) { XUSB_ERR(xusb, "Received URB does not belong to a valid xbus anymore...\n"); return; } if(!xusb->present) { do_resubmit = 0; goto err; } if (urb->status) { DBG(GENERAL, "nonzero read bulk status received: %d\n", urb->status); XUSB_COUNTER(xusb, RX_ERRORS)++; goto err; } size = urb->actual_length; if(size == 0) { static int rate_limit; if((rate_limit++ % 5003) == 0) XUSB_NOTICE(xusb, "Received a zero length URBs (%d)\n", rate_limit); XUSB_COUNTER(xusb, RCV_ZERO_LEN)++; goto err; } atomic_set(&xframe->frame_len, size); xframe->tv_received = now; // if (debug) // dump_xframe("USB_FRAME_RECEIVE", xbus, xframe, debug); XUSB_COUNTER(xusb, RX_FRAMES)++; /* Send UP */ xbus_receive_xframe(xbus, xframe); end: if(do_resubmit) xusb_listen(xusb); return; err: FREE_RECV_XFRAME(xbus, xframe); goto end; } /*------------------------- Initialization -------------------------*/ static void xpp_usb_cleanup(void) { if(xusb_cache) { kmem_cache_destroy(xusb_cache); xusb_cache = NULL; } } static int __init xpp_usb_init(void) { int ret; //xusb_t *xusb; INFO("revision %s\n", XPP_VERSION); xusb_cache = kmem_cache_create("xusb_cache", sizeof(xframe_t) + XFRAME_DATASIZE, #if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,22)) && defined(CONFIG_SLUB) 0, SLAB_STORE_USER, #else 0, 0, #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) NULL, #endif NULL); if(!xusb_cache) { ret = -ENOMEM; goto failure; } /* register this driver with the USB subsystem */ ret = usb_register(&xusb_driver); if (ret) { ERR("usb_register failed. Error number %d\n", ret); goto failure; } return 0; failure: xpp_usb_cleanup(); return ret; } static void __exit xpp_usb_shutdown(void) { DBG(GENERAL, "\n"); /* deregister this driver with the USB subsystem */ usb_deregister(&xusb_driver); xpp_usb_cleanup(); } #ifdef CONFIG_PROC_FS static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; unsigned long flags; int i; //unsigned long stamp = jiffies; xusb_t *xusb = data; uint usb_tx_delay[NUM_BUCKETS]; const int mark_limit = tx_sluggish/USEC_BUCKET; if(!xusb) goto out; // TODO: probably needs a per-xusb lock: spin_lock_irqsave(&xusb_lock, flags); len += sprintf(page + len, "Device: %03d/%03d\n", xusb->udev->bus->busnum, xusb->udev->devnum ); len += sprintf(page + len, "USB: manufacturer=%s\n", xusb->manufacturer); len += sprintf(page + len, "USB: product=%s\n", xusb->product); len += sprintf(page + len, "USB: serial=%s\n", xusb->serial); len += sprintf(page + len, "Minor: %d\nModel Info: %s\n", xusb->minor, xusb->model_info->desc); len += sprintf(page + len, "Endpoints:\n" "\tIn: 0x%02X - Size: %d)\n" "\tOut: 0x%02X - Size: %d)\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_RECV].max_size, xusb->endpoints[XUSB_SEND].ep_addr, xusb->endpoints[XUSB_SEND].max_size ); len += sprintf(page + len, "\npending_writes=%d\n", atomic_read(&xusb->pending_writes)); len += sprintf(page + len, "pending_reads=%d\n", atomic_read(&xusb->pending_reads)); len += sprintf(page + len, "max_tx_delay=%d\n", xusb->max_tx_delay); xusb->max_tx_delay = 0; #ifdef DEBUG_PCM_TIMING len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff); #endif memcpy(usb_tx_delay, xusb->usb_tx_delay, sizeof(usb_tx_delay)); len += sprintf(page + len, "usb_tx_delay[%d,%d,%d]: ", USEC_BUCKET, BUCKET_START, NUM_BUCKETS); for(i = BUCKET_START; i < NUM_BUCKETS; i++) { len += sprintf(page + len, "%6d ", usb_tx_delay[i]); if(i == mark_limit) len += sprintf(page + len, "| "); } len += sprintf(page + len, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n", atomic_read(&xusb->pcm_tx_drops), atomic_read(&xusb->usb_sluggish_count) ); len += sprintf(page + len, "\nCOUNTERS:\n"); for(i = 0; i < XUSB_COUNTER_MAX; i++) { len += sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name, xusb->counters[i]); } #if 0 len += sprintf(page + len, "<-- len=%d\n", len); #endif spin_unlock_irqrestore(&xusb_lock, flags); out: if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif MODULE_DESCRIPTION("XPP USB Transport Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); module_init(xpp_usb_init); module_exit(xpp_usb_shutdown); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/init_card_1_300000755000175000017500000003047611173046264021767 0ustar tzafrirtzafrir#! /usr/bin/perl -w use strict; # Make warnings fatal local $SIG{__WARN__} = sub { die @_ }; # # Written by Oron Peled # Copyright (C) 2006, Xorcom # # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # See the file LICENSE in the top level of this tarball. # # # $Id: init_card_1_30 6407 2009-04-20 10:21:40Z tzafrir $ # # Data format: # - A comment start with ';' or '#' until the end of line # - Blank lines are ignored # - Fields are whitespace separated (spaces or tabs) # # The fields are (in command line order): # 1. SLIC select in decimal (range 0-7). # * is a special value which means ALL SLICS (only some registers # accept settings for ALL SLICS). # 2. Command word: # - RD Read Direct register. # - RS Read Sub-register. # - WD Write Direct register. # - WS Write Sub-register. # 3. Register number in hexadecimal. # 4. Low data byte in hexadecimal. (for WD and WS commands). # 5. High data byte in hexadecimal. (for WS command only). # # package main; use File::Basename; use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; getopts('o:', \%opts); my %settings; $settings{debug} = 0; $settings{fxs_skip_calib} = 0; my $chipregs; sub logit { print STDERR "$unit_id: @_\n"; } sub debug { logit @_ if $settings{debug}; } # Arrange for error logging if (-t STDERR) { $unit_id = 'Interactive'; debug "Interactive startup"; } else { $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}"; open (STDERR, "| logger -t $program -p kern.info") || die; debug "Non Interactive startup"; foreach my $k (qw( XBUS_NAME XBUS_NUMBER UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR XBUS_LABEL)) { unless(defined $ENV{$k}) { logit "Missing ENV{$k}\n"; die; } } $chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}; if(! -f $chipregs) { my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER}); $chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs"; logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc" if -f $chipregs; } } sub set_output() { my $output; if($opts{o}) { $output = $opts{o}; } else { # No subunits in FXS (everything is subunit 0) $output = $chipregs; } open(REG, ">$output") || die "Failed to open '$output': $!\n"; my $oldfh = select REG; main::logit "# Setting output" if $opts{o}; return $oldfh; } sub mysleep($) { my $timeout = shift; select(undef,undef,undef,$timeout); } package FXS; sub gen { my $fmt = shift; $| = 1; printf "$fmt\n", @_; } my @SlicNums = (0 .. 7); sub write_to_slic_file($) { my $write_str = shift; open(SLICS,">$chipregs") or die("Failed writing to chipregs file $chipregs"); print SLICS $write_str; close(SLICS) or die "Failed writing '$write_str' to '$chipregs': $!"; main::mysleep(0.001); } sub read_reg($$$) { my $read_slic = shift; my $read_reg = shift; my $direct = shift; write_to_slic_file( sprintf("%s R%s %02X", $read_slic, $direct, $read_reg)); my $retries = 10; my @reply; # If the command queue is long, we may need to wait... WAIT_RESULTS: { my @results; # The time to sleep is a tradeoff: # - Too long is a waste of time. # - Too short will cause many retries, wastes time. # So the current value (after trial and error) is... main::mysleep(0.013); open(SLICS,$chipregs) or die("Failed reading from chipregs file $chipregs"); while(){ s/#.*//; next unless /\S/; @results = /^\s*(\d+)\s+[RW][DI]\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]*)/; if(@results != 4) { main::logit "Failed reading from '$chipregs' ($read_slic,$read_reg,$direct)"; die; } } close(SLICS); my $reg = hex($results[1]); if($results[0] ne $read_slic || $reg ne $read_reg) { # We read obsolete values, need to wait some more if(--$retries) { main::debug "$read_slic RD $read_reg -- retry ($results[0], $reg)"; redo WAIT_RESULTS; } else { main::logit "Failed: $read_slic RD $read_reg returned $results[0], $reg"; die; } } # Good. @reply = (hex($results[2]), hex($results[3])); } if ($direct eq 'S') { return @reply; } else { return $reply[0]; } } # TODO: rearange arguments sub write_reg{#($$$$$) { my $read_slic = shift; my $read_reg = shift; my $direct = shift; my $reg_val_low = shift; my $reg_val_hi = shift; my $str = sprintf "%s W%s %02X %02X", $read_slic, $direct, $read_reg, $reg_val_low; if ($direct eq 'S') { $str .= sprintf " %02X", $reg_val_hi; } write_to_slic_file($str); } sub log_calib_params() { for my $i (100 .. 107) { my $line="Calib Reg $i: "; for my $slic (@SlicNums) { $line .= " ".read_reg($slic, $i, 'D'); } main::debug($line); } } sub init_indirect_registers() { return write_to_slic_file("# * WS 1E 00 C2 55 * WS 1E 01 E6 51 * WS 1E 02 85 4B * WS 1E 03 37 49 * WS 1E 04 33 33 * WS 1E 05 02 02 * WS 1E 06 02 02 * WS 1E 07 98 01 * WS 1E 08 98 01 * WS 1E 09 11 06 * WS 1E 0A 02 02 * WS 1E 0B E5 00 * WS 1E 0C 1C 0A * WS 1E 0D 30 7B * WS 1E 0E 63 00 * WS 1E 0F 00 00 * WS 1E 10 70 78 * WS 1E 11 7D 00 * WS 1E 12 00 00 * WS 1E 13 00 00 * WS 1E 14 FD 7E * WS 1E 15 77 01 * WS 1E 16 00 00 * WS 1E 17 00 20 * WS 1E 18 00 20 * WS 1E 19 00 00 * WS 1E 1A 00 20 * WS 1E 1B 00 40 * WS 1E 1C 00 10 * WS 1E 1D 00 36 * WS 1E 1E 00 10 * WS 1E 1F 00 02 * WS 1E 20 C0 07 * WS 1E 21 6F 37 * WS 1E 22 80 1B * WS 1E 23 00 80 * WS 1E 24 00 08 * WS 1E 25 00 08 * WS 1E 26 00 08 * WS 1E 27 00 08 * WS 1E 28 00 00 * WS 1E 2B 00 08 # LCRTL = 5.08 mA * WS 1E 63 DA 00 * WS 1E 64 60 6B * WS 1E 65 74 00 * WS 1E 66 C0 79 * WS 1E 67 20 11 * WS 1E 68 E0 3B #"); } sub init_early_direct_regs() { return write_to_slic_file("# * WD 08 00 # Audio Path Loopback Control * WD 6C 01 * WD 4A 3F # High Battery Voltage * WD 4B 10 # Low Battery Voltage * WD 40 00 # Line Feed Control #") } my @FilterParams = (); sub save_indirect_filter_params() { for my $slic (@SlicNums) { for my $reg (35 .. 39) { $FilterParams[$slic][$reg] = [read_reg($slic, $reg, 'S')]; write_reg($slic, $reg, 'S', 0, 0x80); } } } sub restore_indirect_filter_params() { for my $slic (@SlicNums) { for my $reg (35 .. 39) { write_reg($slic, $reg, 'S', @{$FilterParams[$slic][$reg]}); } } } my $ManualCalibrationSleepTime = 0.04; # 40ms sub manual_calibrate_loop($$) { my $write_reg = shift; my $read_reg = shift; my @curr_slics = @SlicNums; # initialize counters my @slic_counters = map { 0x1F } @curr_slics; # wait until all slics have finished calibration, or for timeout while (@curr_slics) { my $debug_calib_str = "ManualCalib:: "; my @next_slics; for my $slic (@curr_slics) { write_reg($slic,$write_reg,'D',$slic_counters[$slic]); } main::mysleep $ManualCalibrationSleepTime; for my $slic (@curr_slics) { my $value = read_reg($slic, $read_reg, 'D'); $debug_calib_str .= sprintf " [%d:%d:%X]", $slic, $slic_counters[$slic], $value; next if $value == 0; # This one is calibrated. if ($slic_counters[$slic] > 0) { $slic_counters[$slic]--; push(@next_slics, $slic); } else { main::logit("ERROR: SLIC $slic reached 0 during manual calibration"); } } @curr_slics = @next_slics; main::debug($debug_calib_str); } main::debug("No more slics to calibrate"); } sub manual_calibrate() { manual_calibrate_loop(98, 88); manual_calibrate_loop(99, 89); } sub auto_calibrate($$) { my $calib_96 = shift; my $calib_97 = shift; #log_calib_params(); # start calibration: for my $slic(@SlicNums) { write_to_slic_file( sprintf "$slic WD 61 %02X\n". "$slic WD 60 %02X\n". "", $calib_97, $calib_96 ); } # wait until all slics have finished calibration, or for timeout # time periods in seconds: my $sleep_time = 0.001; my $timeout_time = 0.600; # Maximum from the spec my @curr_slics = @SlicNums; my $sleep_cnt = 0; CALIB_LOOP: while(1) { main::mysleep($sleep_time); my @next_slics; for my $slic (@curr_slics) { main::debug("checking slic $slic"); my $val = read_reg($slic, 96, 'D'); push(@next_slics, $slic) if $val != 0; } @curr_slics = @next_slics; last unless @curr_slics; if ($sleep_cnt * $sleep_time > $timeout_time) { main::logit("Auto Calibration: Exiting on timeout: $timeout_time."); last CALIB_LOOP; } main::debug("auto_calibrate not done yet($sleep_cnt): @curr_slics"); $sleep_cnt++; } #log_calib_params(); } sub calibrate_slics() { main::debug "Calibrating '$0'"; auto_calibrate(0x40, 0x1E); main::debug "after auto_calibrate"; manual_calibrate(); main::debug "after manul_calibrate"; auto_calibrate(0x40, 0x01); main::debug "after auto_calibrate 2"; main::debug "Continue '$0'"; } sub read_defaults() { if(XppConfig::read_config(\%settings)) { main::logit "Defaults from $settings{xppconf}"; } else { main::logit "No defaults file, use hard-coded defaults."; } } # Try to identify which slics are valid sub check_slics() { my @slics; foreach my $slic (0 .. 7) { my $value = read_reg($slic, 0, 'D'); push(@slics, $slic) if $value != 0xFF; } main::logit "Found " . scalar(@slics) . " SLICS (@slics)"; return @slics; } package main; main::debug "Starting '$0'"; FXS::read_defaults; @SlicNums = FXS::check_slics; main::debug "before init_indirect_registers"; FXS::init_indirect_registers(); main::debug "after init_indirect_registers"; FXS::init_early_direct_regs(); main::debug "after init_early_direct_regs"; if($settings{fxs_skip_calib}) { main::logit "==== WARNING: SKIPPED SLIC CALIBRATION ====="; } else { FXS::calibrate_slics; } set_output; while() { chomp; s/[#;].*$//; # remove comments s/^\s+//; # trim whitespace s/\s+$//; # trim whitespace s/\t+/ /g; # replace tabs with spaces (for logs) next unless /\S/; # Skip empty lines main::debug "writing: '$_'"; print "$_\n"; } close REG; main::debug "Ending '$0'"; close STDERR; exit 0; # ----------------------------------==== 8-channel FXS unit initialization ===----------------------------------------- __DATA__ # Flush out energy accumulators * WS 1E 58 00 00 * WS 1E 59 00 00 * WS 1E 5A 00 00 * WS 1E 5B 00 00 * WS 1E 5C 00 00 * WS 1E 5D 00 00 * WS 1E 5E 00 00 * WS 1E 5F 00 00 * WS 1E 61 00 00 * WS 1E C1 00 00 * WS 1E C2 00 00 * WS 1E C3 00 00 * WS 1E C4 00 00 * WS 1E C5 00 00 * WS 1E C6 00 00 * WS 1E C7 00 00 * WS 1E C8 00 00 * WS 1E C9 00 00 * WS 1E CA 00 00 * WS 1E CB 00 00 * WS 1E CC 00 00 * WS 1E CD 00 00 * WS 1E CE 00 00 * WS 1E CF 00 00 * WS 1E D0 00 00 * WS 1E D1 00 00 * WS 1E D2 00 00 * WS 1E D3 00 00 # Clear and disable interrupts * WD 12 FF * WD 13 FF * WD 14 FF * WD 15 00 * WD 16 00 * WD 17 00 ## Mode(8-bit,u-Law,1 PCLK ) * WD 01 08 # Disable PCM transfers # Setting of SLICs offsets # New card initialization * WD 03 00 * WD 05 00 0 WD 02 00 0 WD 04 00 0 WD 01 28 # Enable PCM transfers 1 WD 02 08 1 WD 04 08 1 WD 01 28 2 WD 02 10 2 WD 04 10 2 WD 01 28 3 WD 02 18 3 WD 04 18 3 WD 01 28 4 WD 02 20 4 WD 04 20 4 WD 01 28 5 WD 02 28 5 WD 04 28 5 WD 01 28 6 WD 02 30 6 WD 04 30 6 WD 01 28 7 WD 02 38 7 WD 04 38 7 WD 01 28 # Audio path. (also initialize 0A and 0B here if necessary) * WD 08 00 * WD 09 00 * WD 0A 08 * WD 0B 33 #------ Metering tone * WD 2C 00 # Timer dL * WD 2D 03 # Timer dH * WS 1E 17 61 15 # Amplitue Ramp-up * WS 1E 18 61 15 # Max Amplitude * WS 1E 19 FB 30 # Frequency # Ring regs are set by driver # Automatic/Manual Control: defaults but: # Cancel AOPN - Power Alarm # Cancel ABAT - Battery Feed Automatic Select * WD 43 16 # Loop Closure Debounce Interval * WD 45 0A # Ring Detect Debounce Interval * WD 46 47 # Battery Feed Control: Battery low (DCSW low) * WD 42 00 # Loop Current Limit * WD 47 00 # On-Hook Line Voltage (VOC) * WD 48 20 # Common Mode Voltage (VCM) * WD 49 03 * WS 1E 23 00 80 * WS 1E 24 20 03 * WS 1E 25 8C 00 * WS 1E 26 00 00 * WS 1E 27 10 00 * WD 0E 00 dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xproto.h0000644000175000017500000002302711602416004021047 0ustar tzafrirtzafrir#ifndef XPROTO_H #define XPROTO_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xdefs.h" #ifdef __KERNEL__ #include #include #include /* * This must match the firmware protocol version */ #define XPP_PROTOCOL_VERSION 30 struct xpd_addr { uint8_t subunit:SUBUNIT_BITS; uint8_t reserved:1; uint8_t unit:UNIT_BITS; uint8_t sync_master:1; } PACKED; #define MKADDR(p, u, s) do { \ (p)->unit = (u); \ (p)->subunit = (s); \ (p)->sync_master = 0; \ } while(0) struct xpacket_header { uint16_t packet_len:10; uint16_t reserved:1; uint16_t is_pcm:1; uint16_t pcmslot:4; uint8_t opcode; struct xpd_addr addr; } PACKED; #define XPACKET_OP(p) ((p)->head.opcode) #define XPACKET_LEN(p) ((p)->head.packet_len) #define XPACKET_IS_PCM(p) ((p)->head.is_pcm) #define XPACKET_PCMSLOT(p) ((p)->head.pcmslot) #define XPACKET_RESERVED(p) ((p)->head.reserved) #define XPACKET_ADDR(p) ((p)->head.addr) #define XPACKET_ADDR_UNIT(p) (XPACKET_ADDR(p).unit) #define XPACKET_ADDR_SUBUNIT(p) (XPACKET_ADDR(p).subunit) #define XPACKET_ADDR_SYNC(p) (XPACKET_ADDR(p).sync_master) #define XPACKET_ADDR_RESERVED(p) (XPACKET_ADDR(p).reserved) #define PROTO_TABLE(n) n ## _protocol_table /* * The LSB of the type number signifies: * 0 - TO_PSTN * 1 - TO_PHONE */ #define XPD_TYPE_FXS 1 // TO_PHONE #define XPD_TYPE_FXO 2 // TO_PSTN #define XPD_TYPE_BRI 3 // TO_PSTN/TO_PHONE (from hardware) #define XPD_TYPE_PRI 4 // TO_PSTN/TO_PHONE (runtime) #define XPD_TYPE_ECHO 5 // Octasic echo canceller #define XPD_TYPE_NOMODULE 7 typedef byte xpd_type_t; #define XPD_TYPE_PREFIX "xpd-type-" #define MODULE_ALIAS_XPD(type) \ MODULE_ALIAS(XPD_TYPE_PREFIX __stringify(type)) #define PCM_CHUNKSIZE (CHANNELS_PERXPD * 8) /* samples of 8 bytes */ bool valid_xpd_addr(const struct xpd_addr *addr); #define XPROTO_NAME(card,op) card ## _ ## op #define XPROTO_HANDLER(card,op) XPROTO_NAME(card,op ## _handler) #define XPROTO_CALLER(card,op) XPROTO_NAME(card,op ## _send) #define HANDLER_DEF(card,op) \ static int XPROTO_HANDLER(card,op) ( \ xbus_t *xbus, \ xpd_t *xpd, \ const xproto_entry_t *cmd, \ xpacket_t *pack) #define CALL_PROTO(card,op, ...) XPROTO_CALLER(card,op)( __VA_ARGS__ ) #define DECLARE_CMD(card,op, ...) \ int CALL_PROTO(card, op, xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ ) #define HOSTCMD(card, op, ...) \ DECLARE_CMD(card, op, ## __VA_ARGS__ ) #define RPACKET_NAME(card,op) XPROTO_NAME(RPACKET_ ## card, op) #define RPACKET_TYPE(card,op) struct RPACKET_NAME(card, op) #define DEF_RPACKET_DATA(card,op, ...) \ RPACKET_TYPE(card,op) { \ struct xpacket_header head; \ __VA_ARGS__ \ } PACKED #define RPACKET_HEADERSIZE sizeof(struct xpacket_header) #define RPACKET_FIELD(p,card,op,field) (((RPACKET_TYPE(card,op) *)(p))->field) #define RPACKET_SIZE(card,op) sizeof(RPACKET_TYPE(card,op)) #define XENTRY(prototab,module,op) \ [ XPROTO_NAME(module,op) ] = { \ .handler = XPROTO_HANDLER(module,op), \ .datalen = RPACKET_SIZE(module,op), \ .name = #op, \ .table = &PROTO_TABLE(prototab) \ } #define XPACKET_INIT(p, card, op, to, pcm, pcmslot) \ do { \ XPACKET_OP(p) = XPROTO_NAME(card,op); \ XPACKET_LEN(p) = RPACKET_SIZE(card,op); \ XPACKET_IS_PCM(p) = (pcm); \ XPACKET_PCMSLOT(p) = (pcmslot); \ XPACKET_RESERVED(p) = 0; \ XPACKET_ADDR_UNIT(p) = XBUS_UNIT(to); \ XPACKET_ADDR_SUBUNIT(p) = XBUS_SUBUNIT(to); \ XPACKET_ADDR_SYNC(p) = 0; \ XPACKET_ADDR_RESERVED(p) = 0; \ } while(0) #define XFRAME_NEW_CMD(frm, p, xbus, card, op, to) \ do { \ int pack_len = RPACKET_SIZE(card,op); \ \ if(!XBUS_FLAGS(xbus, CONNECTED)) \ return -ENODEV; \ (frm) = ALLOC_SEND_XFRAME(xbus); \ if(!(frm)) \ return -ENOMEM; \ (p) = xframe_next_packet(frm, pack_len); \ if(!(p)) \ return -ENOMEM; \ XPACKET_INIT(p, card, op, to, 0, 0); \ (frm)->usec_towait = 0; \ } while(0) #endif /*--------------------------- register handling --------------------------------*/ #define MULTIBYTE_MAX_LEN 5 /* FPGA firmware limitation */ typedef struct reg_cmd { byte bytes:3; /* Length (for Multibyte) */ byte eoframe:1; /* For BRI -- end of frame */ byte portnum:3; /* For port specific registers */ byte is_multibyte:1; union { struct { byte reserved:4; byte do_datah:1; byte do_subreg:1; byte read_request:1; byte all_ports_broadcast:1; byte regnum; byte subreg; byte data_low; byte data_high; } PACKED r; /* For Write-Multibyte commands in BRI */ struct { byte xdata[MULTIBYTE_MAX_LEN]; } PACKED d; } PACKED alt; } PACKED reg_cmd_t; /* Shortcut access macros */ #define REG_FIELD(regptr,member) ((regptr)->alt.r.member) #define REG_XDATA(regptr) ((regptr)->alt.d.xdata) #ifdef __KERNEL__ /*--------------------------- protocol tables ----------------------------------*/ typedef struct xproto_entry xproto_entry_t; typedef struct xproto_table xproto_table_t; typedef int (*xproto_handler_t)( xbus_t *xbus, xpd_t *xpd, const xproto_entry_t *cmd, xpacket_t *pack); const xproto_table_t *xproto_get(xpd_type_t cardtype); void xproto_put(const xproto_table_t *xtable); const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode); xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode); const xproto_entry_t *xproto_global_entry(byte opcode); xproto_handler_t xproto_global_handler(byte opcode); /* * XMETHOD() resolve to method pointer (NULL for optional methods) * CALL_XMETHOD() calls the method, passing mandatory arguments */ #define XMETHOD(name, xpd) ((xpd)->xops->name) #define CALL_XMETHOD(name, xpd, ...) \ (XMETHOD(name, (xpd))((xpd)->xbus, (xpd), ## __VA_ARGS__ )) /* * PHONE_METHOD() resolve to method pointer (NULL for optional methods) * CALL_PHONE_METHOD() calls the method, passing mandatory arguments */ #define PHONE_METHOD(name, xpd) (PHONEDEV(xpd).phoneops->name) #define CALL_PHONE_METHOD(name, xpd, ...) \ (PHONE_METHOD(name, (xpd))((xpd), ## __VA_ARGS__ )) struct phoneops { void (*card_pcm_recompute)(xpd_t *xpd, xpp_line_t pcm_mask); void (*card_pcm_fromspan)(xpd_t *xpd, xpacket_t *pack); void (*card_pcm_tospan)(xpd_t *xpd, xpacket_t *pack); int (*echocancel_timeslot)(xpd_t *xpd, int pos); int (*echocancel_setmask)(xpd_t *xpd, xpp_line_t ec_mask); int (*card_timing_priority)(xpd_t *xpd); int (*card_dahdi_preregistration)(xpd_t *xpd, bool on); int (*card_dahdi_postregistration)(xpd_t *xpd, bool on); int (*card_hooksig)(xpd_t *xpd, int pos, enum dahdi_txsig txsig); int (*card_ioctl)(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg); int (*card_open)(xpd_t *xpd, lineno_t pos); int (*card_close)(xpd_t *xpd, lineno_t pos); int (*card_state)(xpd_t *xpd, bool on); }; struct xops { xpd_t *(*card_new)(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone); int (*card_init)(xbus_t *xbus, xpd_t *xpd); int (*card_remove)(xbus_t *xbus, xpd_t *xpd); int (*card_tick)(xbus_t *xbus, xpd_t *xpd); int (*card_register_reply)(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *reg); }; struct xproto_entry { xproto_handler_t handler; int datalen; const char *name; xproto_table_t *table; }; struct xproto_table { struct module *owner; xproto_entry_t entries[256]; /* Indexed by opcode */ const struct xops *xops; /* Card level operations */ const struct phoneops *phoneops; /* DAHDI operations */ const struct echoops *echoops; /* Echo Canceller operations */ xpd_type_t type; byte ports_per_subunit; const char *name; bool (*packet_is_valid)(xpacket_t *pack); void (*packet_dump)(const char *msg, xpacket_t *pack); }; #include "card_global.h" #include "card_fxs.h" #include "card_fxo.h" #include "card_bri.h" #include "card_pri.h" #define MEMBER(card,op) RPACKET_TYPE(card,op) RPACKET_NAME(card,op) struct xpacket { struct xpacket_header head; union { MEMBER(GLOBAL, NULL_REPLY); MEMBER(GLOBAL, PCM_WRITE); MEMBER(GLOBAL, PCM_READ); MEMBER(GLOBAL, SYNC_REPLY); MEMBER(GLOBAL, ERROR_CODE); MEMBER(FXS, SIG_CHANGED); MEMBER(FXO, SIG_CHANGED); byte data[0]; }; /* Last byte is chksum */ } PACKED; void dump_packet(const char *msg, const xpacket_t *packet, bool debug); void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, byte unit, xportno_t port, const reg_cmd_t *regcmd); int xframe_receive(xbus_t *xbus, xframe_t *xframe); void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg); int xproto_register(const xproto_table_t *proto_table); void xproto_unregister(const xproto_table_t *proto_table); const xproto_entry_t *xproto_global_entry(byte opcode); const char *xproto_name(xpd_type_t xpd_type); #endif /* __KERNEL__ */ #endif /* XPROTO_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/param_doc0000755000175000017500000000172610751714440021231 0ustar tzafrirtzafrir#! /usr/bin/perl -w use strict; # # Extract parameter documentation from *.ko files. # Assumes that parameter description include the default # value in the format we use in our DEF_PARM() macro # @ARGV || die "Usage: $0 module.ko....\n"; my $modinfo = '/sbin/modinfo'; my @mod_params; foreach my $file (glob "@ARGV") { undef @mod_params; print "$file:\n"; open(F, "$modinfo '$file' |") || die; while() { chomp; next unless s/^parm:\s*//; my ($name, $description) = split(/:/, $_, 2); # Extract type $description =~ s/\s*\(([^)]+)\)$//; my $type = $1; # Extract default value $description =~ s/\s*\[default\s+([^]]+)\]$//; my $default = $1; push(@mod_params, { NAME => $name, TYPE => $type, DEFVAL => $default, DESC => $description, }); } # Print sorted list foreach my $p (sort { $a->{NAME} cmp $b->{NAME} } @mod_params) { printf "\t%-8s %-22s = %-20s %s\n", $p->{TYPE}, $p->{NAME}, $p->{DEFVAL}, $p->{DESC}; } close F || die; } dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp_dahdi.h0000644000175000017500000000501011602416004021444 0ustar tzafrirtzafrir#ifndef XPP_DAHDI_H #define XPP_DAHDI_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" #include "xproto.h" int dahdi_register_xpd(xpd_t *xpd); int dahdi_unregister_xpd(xpd_t *xpd); void xbus_request_removal(xbus_t *xbus); int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int unit, int subunit, byte type, byte subtype, int subunits, int subunit_ports, byte port_dir); void xpd_post_init(xpd_t *xpd); xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits, size_t privsize, const xproto_table_t *proto_table, int channels); void xpd_free(xpd_t *xpd); void xpd_remove(xpd_t *xpd); void update_xpd_status(xpd_t *xpd, int alarm_flag); const char *xpp_echocan_name(const struct dahdi_chan *chan); int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); void hookstate_changed(xpd_t *xpd, int pos, bool good); int xpp_open(struct dahdi_chan *chan); int xpp_close(struct dahdi_chan *chan); int xpp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long arg); int xpp_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig); int xpp_maint(struct dahdi_span *span, int cmd); void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd); int total_registered_spans(void); void oht_pcm(xpd_t *xpd, int pos, bool pass); void mark_offhook(xpd_t *xpd, int pos, bool to_offhook); #define IS_OFFHOOK(xpd,pos) IS_SET((xpd)->phonedev.offhook_state, (pos)) void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig); #ifdef CONFIG_PROC_FS #include extern struct proc_dir_entry *xpp_proc_toplevel; #endif #define SPAN_REGISTERED(xpd) atomic_read(&PHONEDEV(xpd).dahdi_registered) #endif /* XPP_DAHDI_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp.rules0000644000175000017500000000076311320417356021240 0ustar tzafrirtzafrir# Load firmware into the Xorcom Astribank device: SUBSYSTEM=="usb", ACTION=="add", \ ENV{PRODUCT}=="e4e4/11[3456][013]/*", ENV{DEVTYPE}!="usb_interface", \ RUN+="/usr/share/dahdi/xpp_fxloader udev $env{PRODUCT}" # Hotplug hook for Astribank up/down # If you need this functionality, copy the astribank_hook.sample # to $XPP_INIT_DIR/astribank_hook # # By default XPP_INIT_DIR="/usr/share/dahdi" KERNEL=="xbus*", RUN+="%E{XPP_INIT_DIR}/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}" dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xframe_queue.c0000644000175000017500000001656211611603356022213 0ustar tzafrirtzafrir#include "xframe_queue.h" #include "xbus-core.h" #include "dahdi_debug.h" extern int debug; static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags); static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe); void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count, unsigned int max_count, const char *name, void *priv) { memset(q, 0, sizeof(*q)); spin_lock_init(&q->lock); INIT_LIST_HEAD(&q->head); q->max_count = XFRAME_QUEUE_MARGIN + max_count; q->steady_state_count = XFRAME_QUEUE_MARGIN + steady_state_count; q->name = name; q->priv = priv; } void xframe_queue_clearstats(struct xframe_queue *q) { q->worst_count = 0; //q->overflows = 0; /* Never clear overflows */ q->worst_lag_usec = 0L; } static void __xframe_dump_queue(struct xframe_queue *q) { xframe_t *xframe; int i = 0; char prefix[30]; struct timeval now; do_gettimeofday(&now); printk(KERN_DEBUG "%s: dump queue '%s' (first packet in each frame)\n", THIS_MODULE->name, q->name); list_for_each_entry_reverse(xframe, &q->head, frame_list) { xpacket_t *pack = (xpacket_t *)&xframe->packets[0]; long usec = usec_diff(&now, &xframe->tv_queued); snprintf(prefix, ARRAY_SIZE(prefix), " %3d> %5ld.%03ld msec", i++, usec / 1000, usec % 1000); dump_packet(prefix, pack, 1); } } static bool __xframe_enqueue(struct xframe_queue *q, xframe_t *xframe) { int ret = 1; static int overflow_cnt = 0; if(unlikely(q->disabled)) { ret = 0; goto out; } if(q->count >= q->max_count) { q->overflows++; if ((overflow_cnt++ % 1000) < 5) { NOTICE("Overflow of %-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", q->name, q->steady_state_count, q->count, q->max_count, q->worst_count, q->overflows, q->worst_lag_usec / 1000, q->worst_lag_usec % 1000); __xframe_dump_queue(q); } ret = 0; goto out; } if(++q->count > q->worst_count) q->worst_count = q->count; list_add_tail(&xframe->frame_list, &q->head); do_gettimeofday(&xframe->tv_queued); out: return ret; } bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe) { unsigned long flags; int ret; spin_lock_irqsave(&q->lock, flags); ret = __xframe_enqueue(q, xframe); spin_unlock_irqrestore(&q->lock, flags); return ret; } static xframe_t *__xframe_dequeue(struct xframe_queue *q) { xframe_t *frm = NULL; struct list_head *h; struct timeval now; unsigned long usec_lag; if(list_empty(&q->head)) goto out; h = q->head.next; list_del_init(h); --q->count; frm = list_entry(h, xframe_t, frame_list); do_gettimeofday(&now); usec_lag = (now.tv_sec - frm->tv_queued.tv_sec)*1000*1000 + (now.tv_usec - frm->tv_queued.tv_usec); if(q->worst_lag_usec < usec_lag) q->worst_lag_usec = usec_lag; out: return frm; } xframe_t *xframe_dequeue(struct xframe_queue *q) { unsigned long flags; xframe_t *frm; spin_lock_irqsave(&q->lock, flags); frm = __xframe_dequeue(q); spin_unlock_irqrestore(&q->lock, flags); return frm; } void xframe_queue_disable(struct xframe_queue *q, bool disabled) { q->disabled = disabled; } void xframe_queue_clear(struct xframe_queue *q) { xframe_t *xframe; xbus_t *xbus = q->priv; int i = 0; xframe_queue_disable(q, 1); while((xframe = xframe_dequeue(q)) != NULL) { transport_free_xframe(xbus, xframe); i++; } XBUS_DBG(DEVICES, xbus, "%s: finished queue clear (%d items)\n", q->name, i); } uint xframe_queue_count(struct xframe_queue *q) { return q->count; } /*------------------------- Frame Alloc/Dealloc --------------------*/ static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags) { struct xbus_ops *ops; xframe_t *xframe; unsigned long flags; BUG_ON(!xbus); ops = transportops_get(xbus); if(unlikely(!ops)) { XBUS_ERR(xbus, "Missing transport\n"); return NULL; } spin_lock_irqsave(&xbus->transport.lock, flags); //XBUS_INFO(xbus, "%s (transport_refcount=%d)\n", __FUNCTION__, atomic_read(&xbus->transport.transport_refcount)); xframe = ops->alloc_xframe(xbus, gfp_flags); if(!xframe) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "Failed xframe allocation from transport (%d)\n", rate_limit); transportops_put(xbus); /* fall through */ } spin_unlock_irqrestore(&xbus->transport.lock, flags); return xframe; } static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe) { struct xbus_ops *ops; unsigned long flags; BUG_ON(!xbus); ops = xbus->transport.ops; BUG_ON(!ops); spin_lock_irqsave(&xbus->transport.lock, flags); //XBUS_INFO(xbus, "%s (transport_refcount=%d)\n", __FUNCTION__, atomic_read(&xbus->transport.transport_refcount)); ops->free_xframe(xbus, xframe); transportops_put(xbus); spin_unlock_irqrestore(&xbus->transport.lock, flags); } static bool xframe_queue_adjust(struct xframe_queue *q) { xbus_t *xbus; xframe_t *xframe; int delta; unsigned long flags; int ret = 0; BUG_ON(!q); xbus = q->priv; BUG_ON(!xbus); spin_lock_irqsave(&q->lock, flags); delta = q->count - q->steady_state_count; if(delta < -XFRAME_QUEUE_MARGIN) { /* Increase pool by one frame */ //XBUS_INFO(xbus, "%s(%d): Allocate one\n", q->name, delta); xframe = transport_alloc_xframe(xbus, GFP_ATOMIC); if(!xframe) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "%s: failed frame allocation\n", q->name); goto out; } if(!__xframe_enqueue(q, xframe)) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "%s: failed enqueueing frame\n", q->name); transport_free_xframe(xbus, xframe); goto out; } } else if(delta > XFRAME_QUEUE_MARGIN) { /* Decrease pool by one frame */ //XBUS_INFO(xbus, "%s(%d): Free one\n", q->name, delta); xframe = __xframe_dequeue(q); if(!xframe) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "%s: failed dequeueing frame\n", q->name); goto out; } transport_free_xframe(xbus, xframe); } ret = 1; out: spin_unlock_irqrestore(&q->lock, flags); return ret; } xframe_t *get_xframe(struct xframe_queue *q) { xframe_t *xframe; xbus_t *xbus; BUG_ON(!q); xbus = (xbus_t *)q->priv; BUG_ON(!xbus); xframe_queue_adjust(q); xframe = xframe_dequeue(q); if(!xframe) { static int rate_limit; if((rate_limit++ % 3001) == 0) XBUS_ERR(xbus, "%s STILL EMPTY (%d)\n", q->name, rate_limit); return NULL; } BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); atomic_set(&xframe->frame_len, 0); xframe->first_free = xframe->packets; do_gettimeofday(&xframe->tv_created); /* * If later parts bother to correctly initialize their * headers, there is no need to memset() the whole data. * * ticket:403 * * memset(xframe->packets, 0, xframe->frame_maxlen); */ //XBUS_INFO(xbus, "%s\n", __FUNCTION__); return xframe; } void put_xframe(struct xframe_queue *q, xframe_t *xframe) { xbus_t *xbus; BUG_ON(!q); xbus = (xbus_t *)q->priv; BUG_ON(!xbus); //XBUS_INFO(xbus, "%s\n", __FUNCTION__); BUG_ON(!TRANSPORT_EXIST(xbus)); if(unlikely(!xframe_enqueue(q, xframe))) { XBUS_ERR(xbus, "Failed returning xframe to %s\n", q->name); transport_free_xframe(xbus, xframe); return; } xframe_queue_adjust(q); } EXPORT_SYMBOL(xframe_queue_init); EXPORT_SYMBOL(xframe_queue_clearstats); EXPORT_SYMBOL(xframe_enqueue); EXPORT_SYMBOL(xframe_dequeue); EXPORT_SYMBOL(xframe_queue_disable); EXPORT_SYMBOL(xframe_queue_clear); EXPORT_SYMBOL(xframe_queue_count); EXPORT_SYMBOL(get_xframe); EXPORT_SYMBOL(put_xframe); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/init_card_2_300000755000175000017500000003065611260427774021776 0ustar tzafrirtzafrir#! /usr/bin/perl -w use strict; # Make warnings fatal local $SIG{__WARN__} = sub { die @_ }; # # Written by Oron Peled # Copyright (C) 2006, Xorcom # # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # See the file LICENSE in the top level of this tarball. # # # $Id: init_card_2_30 7236 2009-09-29 16:04:12Z tzafrir $ # # Data format: # - A comment start with ';' or '#' until the end of line # - Blank lines are ignored # - Fields are whitespace separated (spaces or tabs) # # The fields are (in command line order): # 1. SLIC select in decimal (range 0-7). # * is a special value which means ALL SLICS (only some registers # accept settings for ALL SLICS). # 2. Command word: # - RD Read Direct register. # - RS Read Sub-register. # - WD Write Direct register. # - WS Write Sub-register. # 3. Register number in hexadecimal. # 4. Low data byte in hexadecimal. (for WD and WS commands). # 5. High data byte in hexadecimal. (for WS command only). # # package main; use File::Basename; use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; $Getopt::Std::STANDARD_HELP_VERSION = 1; our $VERSION = '$Id: init_card_2_30 7236 2009-09-29 16:04:12Z tzafrir $'; sub usage() { print <<"EOF"; $0 [-L] [-v verify_file] [-o output_file] -L: List all available opermodes and exit -v: verify opermodes and exit -o: simulate: output to file instead of astribank EOF exit 1; } sub HELP_MESSAGE() { eval {usage}; return 0; } getopts('Lo:v:', \%opts) || usage; my %settings; $settings{debug} = 0; my $chipregs; sub logit { print STDERR "$unit_id: @_\n"; } sub debug { logit @_ if $settings{debug}; } # Arrange for error logging if (-t STDERR || $opts{v}) { $unit_id = 'Interactive'; debug "Interactive startup"; } else { $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}"; open (STDERR, "| logger -t $program -p kern.info") || die; debug "Non Interactive startup"; foreach my $k (qw( XBUS_NAME XBUS_NUMBER UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR XBUS_LABEL)) { unless(defined $ENV{$k}) { logit "Missing ENV{$k}\n"; die; } } $chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}; if(! -f $chipregs) { my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER}); $chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs"; logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc" if -f $chipregs; } } sub set_output() { my $output; if($opts{o}) { $output = $opts{o}; } else { # No subunits in FXS (everything is subunit 0) $output = $chipregs; } open(REG, ">$output") || die "Failed to open '$output': $!\n"; my $oldfh = select REG; main::logit "# Setting output" if $opts{o}; return $oldfh; } package FXO; sub gen { my $fmt = shift; $| = 1; printf "$fmt\n", @_; } my $OPERMODE = 'FCC'; sub turn_off_leds() { # Turning off red LEDs # Warning: do not send WD 31 20 A0 ! foreach my $i (0..7) { FXO::gen "$i WD 20 A0"; } } # This data is manually taken from utils/init_fxo_modes which is generated # during build. # Running this script with a single 'verify' argument, during build, # compare this data to a (possibly updated) utils/init_fxo_modes file. my $OPERMODE_DATA = " FCC reg16=01 reg26=C0 reg30=00 reg31=20 TBR21 reg16=00 reg26=C2 reg30=02 reg31=20 ring_osc=7E6C ring_x=023A ARGENTINA reg16=00 reg26=C0 reg30=00 reg31=20 AUSTRALIA reg16=40 reg26=30 reg30=03 reg31=20 AUSTRIA reg16=00 reg26=C2 reg30=03 reg31=28 BAHRAIN reg16=00 reg26=C2 reg30=02 reg31=20 BELGIUM reg16=00 reg26=C2 reg30=02 reg31=28 BRAZIL reg16=00 reg26=30 reg30=00 reg31=20 BULGARIA reg16=00 reg26=C2 reg30=03 reg31=20 CANADA reg16=00 reg26=C0 reg30=00 reg31=20 CHILE reg16=00 reg26=C0 reg30=00 reg31=20 CHINA reg16=00 reg26=30 reg30=0F reg31=20 COLOMBIA reg16=00 reg26=C0 reg30=00 reg31=20 CROATIA reg16=00 reg26=C2 reg30=02 reg31=20 CYPRUS reg16=00 reg26=C2 reg30=02 reg31=20 CZECH reg16=00 reg26=C2 reg30=02 reg31=20 DENMARK reg16=00 reg26=C2 reg30=02 reg31=28 ECUADOR reg16=00 reg26=C0 reg30=00 reg31=20 EGYPT reg16=00 reg26=30 reg30=00 reg31=20 ELSALVADOR reg16=00 reg26=C0 reg30=00 reg31=20 FINLAND reg16=00 reg26=C2 reg30=02 reg31=28 FRANCE reg16=00 reg26=C2 reg30=02 reg31=28 GERMANY reg16=00 reg26=C2 reg30=03 reg31=28 GREECE reg16=00 reg26=C2 reg30=02 reg31=28 GUAM reg16=00 reg26=C0 reg30=00 reg31=20 HONGKONG reg16=00 reg26=C0 reg30=00 reg31=20 HUNGARY reg16=00 reg26=C0 reg30=00 reg31=20 ICELAND reg16=00 reg26=C2 reg30=02 reg31=28 INDIA reg16=00 reg26=C0 reg30=04 reg31=20 INDONESIA reg16=00 reg26=C0 reg30=00 reg31=20 IRELAND reg16=00 reg26=C2 reg30=02 reg31=28 ISRAEL reg16=00 reg26=C2 reg30=02 reg31=20 ITALY reg16=00 reg26=C2 reg30=02 reg31=28 JAPAN reg16=00 reg26=30 reg30=00 reg31=20 JORDAN reg16=00 reg26=30 reg30=00 reg31=20 KAZAKHSTAN reg16=00 reg26=C0 reg30=00 reg31=20 KUWAIT reg16=00 reg26=C0 reg30=00 reg31=20 LATVIA reg16=00 reg26=C2 reg30=02 reg31=20 LEBANON reg16=00 reg26=C2 reg30=02 reg31=20 LUXEMBOURG reg16=00 reg26=C2 reg30=02 reg31=28 MACAO reg16=00 reg26=C0 reg30=00 reg31=20 MALAYSIA reg16=00 reg26=30 reg30=00 reg31=20 MALTA reg16=00 reg26=C2 reg30=02 reg31=20 MEXICO reg16=00 reg26=C0 reg30=00 reg31=20 MOROCCO reg16=00 reg26=C2 reg30=02 reg31=20 NETHERLANDS reg16=00 reg26=C2 reg30=02 reg31=28 NEWZEALAND reg16=00 reg26=C0 reg30=04 reg31=20 NIGERIA reg16=00 reg26=C2 reg30=02 reg31=20 NORWAY reg16=00 reg26=C2 reg30=02 reg31=28 OMAN reg16=00 reg26=30 reg30=00 reg31=20 PAKISTAN reg16=00 reg26=30 reg30=00 reg31=20 PERU reg16=00 reg26=C0 reg30=00 reg31=20 PHILIPPINES reg16=00 reg26=30 reg30=00 reg31=20 POLAND reg16=03 reg26=C0 reg30=00 reg31=20 PORTUGAL reg16=00 reg26=C2 reg30=02 reg31=28 ROMANIA reg16=00 reg26=C0 reg30=00 reg31=20 RUSSIA reg16=00 reg26=30 reg30=00 reg31=20 SAUDIARABIA reg16=00 reg26=C0 reg30=00 reg31=20 SINGAPORE reg16=00 reg26=C0 reg30=00 reg31=20 SLOVAKIA reg16=00 reg26=C0 reg30=03 reg31=20 SLOVENIA reg16=00 reg26=C0 reg30=02 reg31=20 SOUTHAFRICA reg16=42 reg26=C0 reg30=03 reg31=20 SOUTHKOREA reg16=00 reg26=C0 reg30=00 reg31=20 SPAIN reg16=00 reg26=C2 reg30=02 reg31=28 SWEDEN reg16=00 reg26=C2 reg30=02 reg31=28 SWITZERLAND reg16=00 reg26=C2 reg30=02 reg31=28 SYRIA reg16=00 reg26=30 reg30=00 reg31=20 TAIWAN reg16=00 reg26=30 reg30=00 reg31=20 THAILAND reg16=00 reg26=30 reg30=00 reg31=20 UAE reg16=00 reg26=C0 reg30=00 reg31=20 UK reg16=00 reg26=C2 reg30=05 reg31=28 USA reg16=00 reg26=C0 reg30=00 reg31=20 YEMEN reg16=00 reg26=C0 reg30=00 reg31=20 "; my %opermode_table; sub opermode_setup() { main::logit "Setting OPERMODE=$OPERMODE"; # Several countries (South Africa, UAE, anybody else) # require a shorter delay: if($OPERMODE eq 'SOUTHAFRICA' or $OPERMODE eq 'UAE') { FXO::gen "* WD 17 2B"; } # defaults, based on fxo_modes from wctdm.c . # Decimal register numbers! my %regs = ( 16 => 0, 26 => 0, 30 => 0, 31 => 0x20, ); my $mode = $opermode_table{$OPERMODE}; if(defined $mode) { foreach my $k (keys %regs) { my $fullkey = "reg$k"; $regs{$k} = $mode->{$fullkey}; } } foreach my $k (keys %regs) { # Our values are HEXADECIMAL without a 0x prefix!!! my $cmd = sprintf "* WD %02X %02X", $k, hex($regs{$k}); main::debug " regs: '$cmd'"; FXO::gen "$cmd"; } main::debug "Finished Opermode"; } sub parse_opermode_line($) { my $line = shift or return(); chomp $line; $line =~ s/#.*//; my @params = split(/\s+/, $line); my $location = shift @params; my $entry = {}; foreach my $p (@params) { my ($key, $val) = split(/=/, $p, 2); $entry->{$key} = $val; } return ($location, $entry); } sub opermode_preprocess() { undef %opermode_table; foreach my $line (split(/\n/, $OPERMODE_DATA)) { my ($location, $entry) = parse_opermode_line($line); next unless defined $location; #print "$location\t", ref($entry), "\n"; die "An entry for '$location' already exists\n" if exists $opermode_table{$location}; $opermode_table{$location} = $entry; } } sub opermode_to_string($) { my $mode = shift or die; my @params; foreach my $k (sort keys %{$mode}) { push(@params, "$k=$mode->{$k}"); } return join(" ", @params); } sub opermode_list() { my $l = join("\n", sort keys %opermode_table); print "$l\n"; } sub opermode_verify($) { my $input = shift or die; my %verification_table; my %location_lines; my $mismatches = 0; open(F, $input) or die "$0: Failed opening '$input': $!\n"; while() { chomp; #print "$_\n"; s/#.*//; my @params = split; my $location = shift @params; foreach my $p (@params) { my ($key, $val) = split(/=/, $p, 2); $verification_table{$location}{$key} = $val; } $location_lines{$location} = $.; } close F; # First test: check for missing data in our program foreach my $location (sort keys %verification_table) { my $mode = $opermode_table{$location}; if(! defined $mode) { printf STDERR "Missing from $0: '$location' at $input:$location_lines{$location}\n"; $mismatches++; next; } my $verify_mode = $verification_table{$location}; my $str1 = opermode_to_string($mode); my $str2 = opermode_to_string($verify_mode); if($str1 ne $str2) { print STDERR "DIFF: '$location' at $input:$location_lines{$location}\n"; printf STDERR "\t%-20s: %s\n", "program", $str1; printf STDERR "\t%-20s: %s\n", "verify", $str2; $mismatches++; } } # Second test: check for extra data in our program foreach my $location (sort keys %opermode_table) { my $mode = $verification_table{$location}; if(! defined $mode) { printf STDERR "Extra in $0 '$location'\n"; $mismatches++; next; } } print STDERR "Total $mismatches mismatches\n" if $mismatches; return $mismatches; } sub read_defaults() { if(XppConfig::read_config(\%settings)) { main::logit "Defaults from $settings{xppconf}"; my $o = $settings{opermode}; if(defined($o)) { # Verify $o = uc($o); # Uppercase my $mode = $opermode_table{$o}; if(! defined $mode) { main::logit "Unknown opermode='$o'"; die; } $OPERMODE = $o; main::logit "Set OPERMODE = $o"; } } else { main::logit "No defaults file, use hard-coded defaults."; } } package main; FXO::opermode_preprocess; # Must be first if($opts{v}) { my $verify_file = $opts{v}; usage unless $verify_file; main::debug "$0: opermode verification (input='$verify_file')"; my $mismatches = FXO::opermode_verify($verify_file); die "$0: Verification against $verify_file failed\n" if $mismatches != 0; exit 0; } elsif($opts{L}) { FXO::opermode_list(); exit 0; } main::debug "Starting"; FXO::read_defaults; die "OPERMODE is undefined" unless $OPERMODE; set_output; FXO::turn_off_leds; while() { chomp; s/[#;].*$//; # remove comments s/^\s+//; # trim whitespace s/\s+$//; # trim whitespace s/\t+/ /g; # replace tabs with spaces (for logs) next unless /\S/; # Skip empty lines main::debug "writing: '$_'"; FXO::gen "$_"; } FXO::opermode_setup; close REG; main::debug "Ending '$0'"; close STDERR; exit 0; __DATA__ * WD 21 08 # Disable PCM transfers * WD 18 99 * WD 06 00 # ----------- DAA PCM start offset ---------- * WD 23 00 * WD 25 00 0 WD 22 00 0 WD 24 00 0 WD 21 28 # Enable PCM transfers, when offsets are set 1 WD 22 08 1 WD 24 08 1 WD 21 28 2 WD 22 10 2 WD 24 10 2 WD 21 28 3 WD 22 18 3 WD 24 18 3 WD 21 28 4 WD 22 20 4 WD 24 20 4 WD 21 28 5 WD 22 28 5 WD 24 28 5 WD 21 28 6 WD 22 30 6 WD 24 30 6 WD 21 28 7 WD 22 38 7 WD 24 38 7 WD 21 28 # ----------- DAA ONHOOK -------------------- * WD 05 00 # Set tip to ring voltage to 3.5 volts while off-hook # instead of default of 3.1 * WD 1A C0 dahdi-linux-2.5.0.1/drivers/dahdi/xpp/mmapbus.c0000644000175000017500000000361611204537077021171 0ustar tzafrirtzafrir#include #include #include #include "mmapbus.h" static int mmap_match(struct device *dev, struct device_driver *driver) { return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); } static int mmap_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { envp[0] = buffer; envp[1] = NULL; return 0; } static void mmap_bus_release(struct device *dev) { } static void mmap_dev_release(struct device *dev) { } static struct bus_type mmap_bus_type = { .name = "mmap", .match = mmap_match, .uevent = mmap_uevent, }; static struct device mmap_bus = { .bus_id = "mmap0", .release = mmap_bus_release, }; int register_mmap_device(struct mmap_device *dev) { dev->dev.bus = &mmap_bus_type; dev->dev.parent = &mmap_bus; dev->dev.release = mmap_dev_release; strncpy(dev->dev.bus_id, dev->name, BUS_ID_SIZE); return device_register(&dev->dev); } void unregister_mmap_device(struct mmap_device *dev) { device_unregister(&dev->dev); } EXPORT_SYMBOL(register_mmap_device); EXPORT_SYMBOL(unregister_mmap_device); int register_mmap_driver(struct mmap_driver *driver) { driver->driver.bus = &mmap_bus_type; return driver_register(&driver->driver); } void unregister_mmap_driver(struct mmap_driver *driver) { driver_unregister(&driver->driver); } EXPORT_SYMBOL(register_mmap_driver); EXPORT_SYMBOL(unregister_mmap_driver); int register_mmap_bus(void) { int ret = 0; if ((ret = bus_register(&mmap_bus_type)) < 0) goto bus_type_reg; if ((ret = device_register(&mmap_bus)) < 0) goto bus_reg; return ret; bus_reg: bus_unregister(&mmap_bus_type); bus_type_reg: return ret; } void unregister_mmap_bus(void) { device_unregister(&mmap_bus); bus_unregister(&mmap_bus_type); } EXPORT_SYMBOL(register_mmap_bus); EXPORT_SYMBOL(unregister_mmap_bus); MODULE_AUTHOR("Alexander Landau "); MODULE_LICENSE("GPL"); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_echo.c0000644000175000017500000002156311604344210021422 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2011, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "xpd.h" #include "xproto.h" #include "card_echo.h" #include "xpp_dahdi.h" #include "dahdi_debug.h" #include "xpd.h" #include "xbus-core.h" static const char rcsid[] = "$Id: card_echo.c 10020 2011-07-04 14:04:56Z tzafrir $"; /* must be before dahdi_debug.h: */ static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /*---------------- ECHO Protocol Commands ----------------------------------*/ static bool echo_packet_is_valid(xpacket_t *pack); static void echo_packet_dump(const char *msg, xpacket_t *pack); DEF_RPACKET_DATA(ECHO, SET, byte timeslots[ECHO_TIMESLOTS]; ); DEF_RPACKET_DATA(ECHO, SET_REPLY, byte status; byte reserved; ); struct ECHO_priv_data { }; static xproto_table_t PROTO_TABLE(ECHO); /*---------------- ECHO: Methods -------------------------------------------*/ static xpd_t *ECHO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone) { xpd_t *xpd = NULL; int channels = 0; if (subunit_ports != 1) { XBUS_ERR(xbus, "Bad subunit_ports=%d\n", subunit_ports); return NULL; } XBUS_DBG(GENERAL, xbus, "\n"); xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct ECHO_priv_data), proto_table, channels); if (!xpd) return NULL; xpd->type_name = "ECHO"; return xpd; } static int ECHO_card_init(xbus_t *xbus, xpd_t *xpd) { int ret = 0; BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); xpd->type = XPD_TYPE_ECHO; XPD_DBG(DEVICES, xpd, "%s\n", xpd->type_name); ret = CALL_EC_METHOD(ec_update, xbus, xbus); return ret; } static int ECHO_card_remove(xbus_t *xbus, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); return 0; } static int ECHO_card_tick(xbus_t *xbus, xpd_t *xpd) { struct ECHO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); return 0; } static int ECHO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { unsigned long flags; struct xpd_addr addr; xpd_t *orig_xpd; /* Map UNIT + PORTNUM to XPD */ orig_xpd = xpd; addr.unit = orig_xpd->addr.unit; addr.subunit = info->portnum; xpd = xpd_byaddr(xbus, addr.unit, addr.subunit); if (!xpd) { static int rate_limit; if ((rate_limit++ % 1003) < 5) notify_bad_xpd(__func__, xbus, addr, orig_xpd->xpdname); return -EPROTO; } spin_lock_irqsave(&xpd->lock, flags); /* Update /proc info only if reply related to last reg read request */ if ( REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { xpd->last_reply = *info; } spin_unlock_irqrestore(&xpd->lock, flags); return 0; } /*---------------- ECHO: HOST COMMANDS -------------------------------------*/ static /* 0x39 */ HOSTCMD(ECHO, SET) { struct xbus_echo_state *es; byte *ts; xframe_t *xframe; xpacket_t *pack; int ret; uint16_t frm_len; int xpd_idx; BUG_ON(!xbus); /* * Find echo canceller XPD address */ es = &xbus->echo_state; xpd_idx = es->xpd_idx; XFRAME_NEW_CMD(xframe, pack, xbus, ECHO, SET, xpd_idx); ts = RPACKET_FIELD(pack, ECHO, SET, timeslots); memcpy(ts, es->timeslots, ECHO_TIMESLOTS); frm_len = XFRAME_LEN(xframe); XBUS_DBG(GENERAL, xbus, "ECHO SET: (len = %d)\n", frm_len); ret = send_cmd_frame(xbus, xframe); return ret; } static int ECHO_ec_set(xpd_t *xpd, int pos, bool on) { int ts_number; int ts_mask; byte *ts; ts = xpd->xbus->echo_state.timeslots; /* * ts_number = PCM time slot ("channel number" in the PCM XPP packet) * * Bit 0 is for UNIT=0 * PRI: ts_number * 4 + SUBUNIT * BRI: ts_number * FXS/FXO(all units): UNIT * 32 + ts_number * * Bit 1 is for UNIT=1-3: FXS/FXO * */ ts_mask = (xpd->addr.unit == 0) ? 0x1 : 0x2; /* Which bit? */ ts_number = CALL_PHONE_METHOD(echocancel_timeslot, xpd, pos); if (ts_number >= ECHO_TIMESLOTS || ts_number < 0) { XPD_ERR(xpd, "Bad ts_number=%d\n", ts_number); return -EINVAL; } else { if (on) ts[ts_number] |= ts_mask; else ts[ts_number] &= ~ts_mask; } LINE_DBG(GENERAL, xpd, pos, "%s = %d -- ts_number=%d ts_mask=0x%X\n", __func__, on, ts_number, ts_mask); return 0; } static int ECHO_ec_get(xpd_t *xpd, int pos) { int ts_number; int ts_mask; int is_on; byte *ts; ts = xpd->xbus->echo_state.timeslots; ts_mask = (xpd->addr.unit == 0) ? 0x1 : 0x2; /* Which bit? */ ts_number = CALL_PHONE_METHOD(echocancel_timeslot, xpd, pos); if (ts_number >= ECHO_TIMESLOTS || ts_number < 0) { XPD_ERR(xpd, "Bad ts_number=%d\n", ts_number); return -EINVAL; } else { is_on = ts[ts_number] & ts_mask; } #if 0 LINE_DBG(GENERAL, xpd, pos, "ec_get=%d -- ts_number=%d ts_mask=0x%X\n", is_on, ts_number, ts_mask); #endif return is_on; } static void ECHO_ec_dump(xbus_t *xbus) { byte *ts; int i; ts = xbus->echo_state.timeslots; for (i = 0; i + 15 < ECHO_TIMESLOTS; i += 16) { XBUS_DBG(GENERAL, xbus, "EC-DUMP[%03d]: " "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X " "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", i, ts[i+0], ts[i+1], ts[i+2], ts[i+3], ts[i+4], ts[i+5], ts[i+6], ts[i+7], ts[i+8], ts[i+9], ts[i+10], ts[i+11], ts[i+12], ts[i+13], ts[i+14], ts[i+15] ); } } static int ECHO_ec_update(xbus_t *xbus) { XBUS_DBG(GENERAL, xbus, "%s\n", __func__); //ECHO_ec_dump(xbus); return CALL_PROTO(ECHO, SET, xbus, NULL); } /*---------------- ECHO: Astribank Reply Handlers --------------------------*/ HANDLER_DEF(ECHO, SET_REPLY) { byte status; BUG_ON(!xpd); status = RPACKET_FIELD(pack, ECHO, SET_REPLY, status); XPD_DBG(GENERAL, xpd, "status=0x%X\n", status); return 0; } static const struct xops echo_xops = { .card_new = ECHO_card_new, .card_init = ECHO_card_init, .card_remove = ECHO_card_remove, .card_tick = ECHO_card_tick, .card_register_reply = ECHO_card_register_reply, }; static const struct echoops echoops = { .ec_set = ECHO_ec_set, .ec_get = ECHO_ec_get, .ec_update = ECHO_ec_update, .ec_dump = ECHO_ec_dump, }; static xproto_table_t PROTO_TABLE(ECHO) = { .owner = THIS_MODULE, .entries = { /* Table Card Opcode */ XENTRY(ECHO, ECHO, SET_REPLY), }, .name = "ECHO", .ports_per_subunit = 1, .type = XPD_TYPE_ECHO, .xops = &echo_xops, .echoops = &echoops, .packet_is_valid = echo_packet_is_valid, .packet_dump = echo_packet_dump, }; static bool echo_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe = NULL; // DBG(GENERAL, "\n"); xe = xproto_card_entry(&PROTO_TABLE(ECHO), XPACKET_OP(pack)); return xe != NULL; } static void echo_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } /*------------------------- sysfs stuff --------------------------------*/ static int echo_xpd_probe(struct device *dev) { xpd_t *ec_xpd; int ret = 0; ec_xpd = dev_to_xpd(dev); /* Is it our device? */ if (ec_xpd->type != XPD_TYPE_ECHO) { XPD_ERR(ec_xpd, "drop suggestion for %s (%d)\n", dev_name(dev), ec_xpd->type); return -EINVAL; } XPD_DBG(DEVICES, ec_xpd, "SYSFS\n"); return ret; } static int echo_xpd_remove(struct device *dev) { xpd_t *ec_xpd; ec_xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, ec_xpd, "SYSFS\n"); return 0; } static struct xpd_driver echo_driver = { .type = XPD_TYPE_ECHO, .driver = { .name = "echo", #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE, #endif .probe = echo_xpd_probe, .remove = echo_xpd_remove } }; static int __init card_echo_startup(void) { int ret; ret = xpd_driver_register(&echo_driver.driver); if (ret < 0) return ret; INFO("revision %s\n", XPP_VERSION); INFO("FEATURE: WITH Octasic echo canceller\n"); xproto_register(&PROTO_TABLE(ECHO)); return 0; } static void __exit card_echo_cleanup(void) { DBG(GENERAL, "\n"); xproto_unregister(&PROTO_TABLE(ECHO)); xpd_driver_unregister(&echo_driver.driver); } MODULE_DESCRIPTION("XPP ECHO Card Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_ECHO); module_init(card_echo_startup); module_exit(card_echo_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/parport_debug.h0000644000175000017500000000176010751714440022362 0ustar tzafrirtzafrir#ifndef PARPORT_DEBUG_H #define PARPORT_DEBUG_H /* * Written by Oron Peled * Copyright (C) 2007, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef DEBUG_SYNC_PARPORT void flip_parport_bit(unsigned char bitnum); #else #define flip_parport_bit(bitnum) #endif #endif /* PARPORT_DEBUG_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/Kconfig0000644000175000017500000000377511026460317020664 0ustar tzafrirtzafrir# # XPP configuration # menuconfig DAHDI_XPP tristate "Xorcom Astribank Support" depends on DAHDI default DAHDI ---help--- Infrastructure support for Xorcom Astribank products. To compile this driver as a module, choose M here: the module will be called xpp. If unsure, say Y. config DAHDI_XPP_USB tristate "Astribank USB transport" depends on DAHDI_XPP && USB default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpp_usb. If unsure, say Y. config DAHDI_XPP_MMAP tristate "Astribank Blackfin transport" depends on DAHDI_XPP && BF537 default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpp_mmap. This module can be compiled only on Blackfin architecture (with uClinux). If unsure, say N. config DAHDI_XPD_FXS tristate "FXS port Support" depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpd_fxs. If unsure, say Y. config DAHDI_XPD_FXO tristate "FXO port Support" depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpd_fxo. If unsure, say Y. config DAHDI_XPD_BRI tristate "BRI port Support" depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpd_pri. Note: this driver will be automatically excluded from compilation if dahdi driver does not contain the "bristuff" patch. If unsure, say Y. config DAHDI_XPD_PRI tristate "PRI port Support" depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpd_pri. If unsure, say Y. dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_fxo.h0000644000175000017500000000247011012401471021275 0ustar tzafrirtzafrir#ifndef CARD_FXO_H #define CARD_FXO_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" enum fxo_opcodes { XPROTO_NAME(FXO, SIG_CHANGED) = 0x06, /**/ XPROTO_NAME(FXO, DAA_WRITE) = 0x0F, /* Write to DAA */ XPROTO_NAME(FXO, XPD_STATE) = 0x0F, /* Write to DAA */ XPROTO_NAME(FXO, CHAN_CID) = 0x0F, /* Write to DAA */ XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */ }; DEF_RPACKET_DATA(FXO, SIG_CHANGED, xpp_line_t sig_status; /* channels: lsb=1, msb=8 */ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */ ); #endif /* CARD_FXO_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp_dahdi.c0000644000175000017500000010210711607106652021456 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004, Xorcom * * Derived from ztdummy * * Copyright (C) 2002, Hermes Softlab * Copyright (C) 2004, Digium, Inc. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include #include #include #include #include /* for udelay */ #include #include #include #include "xbus-core.h" #include "xproto.h" #include "xpp_dahdi.h" #include "parport_debug.h" static const char rcsid[] = "$Id: xpp_dahdi.c 10037 2011-07-12 18:08:42Z tzafrir $"; #ifdef CONFIG_PROC_FS struct proc_dir_entry *xpp_proc_toplevel = NULL; #define PROC_DIR "xpp" #define PROC_XPD_SUMMARY "summary" #endif #define MAX_QUEUE_LEN 10000 #define DELAY_UNTIL_DIALTONE 3000 DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); static DEF_PARM_BOOL(dahdi_autoreg, 0, 0644, "Register spans automatically (1) or not (0)"); static DEF_PARM_BOOL(prefmaster, 0, 0644, "Do we want to be dahdi preferred sync master"); // DEF_ARRAY(int, pcmtx, 4, 0, "Forced PCM values to transmit"); #include "dahdi_debug.h" static void phonedev_cleanup(xpd_t *xpd); #ifdef DEBUG_SYNC_PARPORT /* * Use parallel port to sample our PCM sync and diagnose quality and * potential problems. A logic analizer or a scope should be connected * to the data bits of the parallel port. * * Array parameter: Choose the two xbuses Id's to sample. * This can be changed on runtime as well. Example: * echo "3,5" > /sys/module/xpp/parameters/parport_xbuses */ static int parport_xbuses[2] = { 0, 1 }; unsigned int parport_xbuses_num_values; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) module_param_array(parport_xbuses, int, &parport_xbuses_num_values, 0577); #else module_param_array(parport_xbuses, int, parport_xbuses_num_values, 0577); #endif MODULE_PARM_DESC(parport_xbuses, "Id's of xbuses to sample (1-2)"); /* * Flip a single bit in the parallel port: * - The bit number is either bitnum0 or bitnum1 * - Bit is selected by xbus number from parport_xbuses[] */ void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1) { int num = xbus->num; if(num == parport_xbuses[0]) flip_parport_bit(bitnum0); if(num == parport_xbuses[1]) flip_parport_bit(bitnum1); } EXPORT_SYMBOL(xbus_flip_bit); #endif static atomic_t num_registered_spans = ATOMIC_INIT(0); int total_registered_spans(void) { return atomic_read(&num_registered_spans); } #ifdef CONFIG_PROC_FS static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); #endif /*------------------------- XPD Management -------------------------*/ /* * Called by put_xpd() when XPD has no more references. */ static void xpd_destroy(struct kref *kref) { xpd_t *xpd; xpd = kref_to_xpd(kref); XPD_DBG(DEVICES, xpd, "%s\n", __func__); xpd_device_unregister(xpd); } int refcount_xpd(xpd_t *xpd) { struct kref *kref = &xpd->kref; return atomic_read(&kref->refcount); } xpd_t *get_xpd(const char *msg, xpd_t *xpd) { XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", msg, refcount_xpd(xpd)); kref_get(&xpd->kref); return xpd; } void put_xpd(const char *msg, xpd_t *xpd) { XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", msg, refcount_xpd(xpd)); kref_put(&xpd->kref, xpd_destroy); } static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd) { #ifdef CONFIG_PROC_FS if(xpd->proc_xpd_dir) { if(xpd->proc_xpd_summary) { XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_SUMMARY); remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir); xpd->proc_xpd_summary = NULL; } XPD_DBG(PROC, xpd, "Removing %s/%s proc directory\n", xbus->busname, xpd->xpdname); remove_proc_entry(xpd->xpdname, xbus->proc_xbus_dir); xpd->proc_xpd_dir = NULL; } #endif } static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd) { #ifdef CONFIG_PROC_FS XPD_DBG(PROC, xpd, "Creating proc directory\n"); xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir); if(!xpd->proc_xpd_dir) { XPD_ERR(xpd, "Failed to create proc directory\n"); goto err; } xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir, xpd_read_proc, xpd); if(!xpd->proc_xpd_summary) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_SUMMARY); goto err; } SET_PROC_DIRENTRY_OWNER(xpd->proc_xpd_summary); #endif return 0; #ifdef CONFIG_PROC_FS err: xpd_proc_remove(xbus, xpd); return -EFAULT; #endif } void xpd_free(xpd_t *xpd) { xbus_t *xbus = NULL; if(!xpd) return; if(xpd->xproto) xproto_put(xpd->xproto); /* was taken in xpd_alloc() */ xpd->xproto = NULL; xbus = xpd->xbus; if(!xbus) return; XPD_DBG(DEVICES, xpd, "\n"); xpd_proc_remove(xbus, xpd); xbus_xpd_unbind(xbus, xpd); phonedev_cleanup(xpd); KZFREE(xpd); DBG(DEVICES, "refcount_xbus=%d\n", refcount_xbus(xbus)); /* * This must be last, so the xbus cannot be released before the xpd */ put_xbus(__FUNCTION__, xbus); /* was taken in xpd_alloc() */ } /* * Synchronous part of XPD detection. * Called from new_card() */ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int unit, int subunit, byte type, byte subtype, int subunits, int subunit_ports, byte port_dir) { xpd_t *xpd = NULL; bool to_phone; BUG_ON(type == XPD_TYPE_NOMODULE); to_phone = BIT(subunit) & port_dir; BUG_ON(!xbus); xpd = xpd_byaddr(xbus, unit, subunit); if(xpd) { XPD_NOTICE(xpd, "XPD at %d%d already exists\n", unit, subunit); return 0; } if(subunit_ports <= 0 || subunit_ports > CHANNELS_PERXPD) { XBUS_NOTICE(xbus, "Illegal number of ports %d for XPD %d%d\n", subunit_ports, unit, subunit); return 0; } xpd = proto_table->xops->card_new(xbus, unit, subunit, proto_table, subtype, subunits, subunit_ports, to_phone); if(!xpd) { XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n", unit, subunit, proto_table->type, subtype, to_phone); return -EINVAL; } return 0; } void xpd_post_init(xpd_t *xpd) { XPD_DBG(DEVICES, xpd, "\n"); if(dahdi_autoreg) dahdi_register_xpd(xpd); } #ifdef CONFIG_PROC_FS /** * Prints a general procfs entry for the bus, under xpp/BUSNAME/summary * @page TODO: figure out procfs * @start TODO: figure out procfs * @off TODO: figure out procfs * @count TODO: figure out procfs * @eof TODO: figure out procfs * @data an xbus_t pointer with the bus data. */ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; xpd_t *xpd = data; int i; if(!xpd) goto out; len += sprintf(page + len, "%s (%s, card %s, span %d)\n" "timing_priority: %d\n" "timer_count: %d span->mainttimer=%d\n" , xpd->xpdname, xpd->type_name, (xpd->card_present) ? "present" : "missing", (SPAN_REGISTERED(xpd)) ? PHONEDEV(xpd).span.spanno : 0, PHONEDEV(xpd).timing_priority, xpd->timer_count, PHONEDEV(xpd).span.mainttimer ); len += sprintf(page + len, "xpd_state: %s (%d)\n", xpd_statename(xpd->xpd_state), xpd->xpd_state); len += sprintf(page + len, "open_counter=%d refcount=%d\n", atomic_read(&PHONEDEV(xpd).open_counter), refcount_xpd(xpd)); len += sprintf(page + len, "Address: U=%d S=%d\n", xpd->addr.unit, xpd->addr.subunit); len += sprintf(page + len, "Subunits: %d\n", xpd->subunits); len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype); len += sprintf(page + len, "pcm_len=%d\n\n", PHONEDEV(xpd).pcm_len); len += sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n", PHONEDEV(xpd).wanted_pcm_mask); len += sprintf(page + len, "mute_dtmf=0x%04X\n\n", PHONEDEV(xpd).mute_dtmf); len += sprintf(page + len, "STATES:"); len += sprintf(page + len, "\n\t%-17s: ", "output_relays"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).digital_outputs, i)); } len += sprintf(page + len, "\n\t%-17s: ", "input_relays"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).digital_inputs, i)); } len += sprintf(page + len, "\n\t%-17s: ", "offhook"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_OFFHOOK(xpd, i)); } len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).oht_pcm_pass, i)); } len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", PHONEDEV(xpd).msg_waiting[i]); } len += sprintf(page + len, "\n\t%-17s: ", "ringing"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", PHONEDEV(xpd).ringing[i]); } len += sprintf(page + len, "\n\t%-17s: ", "no_pcm"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).no_pcm, i)); } #if 1 if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D"); for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); byte rchunk[DAHDI_CHUNKSIZE]; byte wchunk[DAHDI_CHUNKSIZE]; byte *rp; byte *wp; int j; if(IS_SET(PHONEDEV(xpd).digital_outputs, i)) continue; if(IS_SET(PHONEDEV(xpd).digital_inputs, i)) continue; if(IS_SET(PHONEDEV(xpd).digital_signalling, i)) continue; rp = chan->readchunk; wp = chan->writechunk; memcpy(rchunk, rp, DAHDI_CHUNKSIZE); memcpy(wchunk, wp, DAHDI_CHUNKSIZE); len += sprintf(page + len, "\n port %2d> | ", i); for(j = 0; j < DAHDI_CHUNKSIZE; j++) { len += sprintf(page + len, "%02X ", rchunk[j]); } len += sprintf(page + len, " | "); for(j = 0; j < DAHDI_CHUNKSIZE; j++) { len += sprintf(page + len, "%02X ", wchunk[j]); } len += sprintf(page + len, " | %c", (IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i))?'+':' '); len += sprintf(page + len, " %c", (IS_SET(PHONEDEV(xpd).mute_dtmf, i))?'-':' '); } } #endif #if 0 if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nSignalling:\n"); for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig); } } #endif len += sprintf(page + len, "\nCOUNTERS:\n"); for(i = 0; i < XPD_COUNTER_MAX; i++) { len += sprintf(page + len, "\t\t%-20s = %d\n", xpd_counters[i].name, xpd->counters[i]); } len += sprintf(page + len, "<-- len=%d\n", len); out: if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif const char *xpd_statename(enum xpd_state st) { switch(st) { case XPD_STATE_START: return "START"; case XPD_STATE_INIT_REGS: return "INIT_REGS"; case XPD_STATE_READY: return "READY"; case XPD_STATE_NOHW: return "NOHW"; } return NULL; } bool xpd_setstate(xpd_t *xpd, enum xpd_state newstate) { BUG_ON(!xpd); XPD_DBG(DEVICES, xpd, "%s: %s (%d) -> %s (%d)\n", __FUNCTION__, xpd_statename(xpd->xpd_state), xpd->xpd_state, xpd_statename(newstate), newstate); switch(newstate) { case XPD_STATE_START: goto badstate; case XPD_STATE_INIT_REGS: if(xpd->xpd_state != XPD_STATE_START) goto badstate; if(xpd->addr.subunit != 0) { XPD_NOTICE(xpd, "%s: Moving to %s allowed only for subunit 0\n", __FUNCTION__, xpd_statename(newstate)); goto badstate; } break; case XPD_STATE_READY: if(xpd->addr.subunit == 0) { /* Unit 0 script initialize registers of all subunits */ if(xpd->xpd_state != XPD_STATE_INIT_REGS) goto badstate; } else { if(xpd->xpd_state != XPD_STATE_START) goto badstate; } break; case XPD_STATE_NOHW: break; default: XPD_ERR(xpd, "%s: Unknown newstate=%d\n", __FUNCTION__, newstate); } xpd->xpd_state = newstate; return 1; badstate: XPD_NOTICE(xpd, "%s: cannot transition: %s (%d) -> %s (%d)\n", __FUNCTION__, xpd_statename(xpd->xpd_state), xpd->xpd_state, xpd_statename(newstate), newstate); return 0; } /* * Cleanup/initialize phonedev */ static void phonedev_cleanup(xpd_t *xpd) { struct phonedev *phonedev = &PHONEDEV(xpd); unsigned int x; for (x = 0; x < phonedev->channels; x++) { if (phonedev->chans[x]) { KZFREE(phonedev->chans[x]); } if (phonedev->ec[x]) KZFREE(phonedev->ec[x]); } } __must_check static int phonedev_init(xpd_t *xpd, const xproto_table_t *proto_table, int channels, xpp_line_t no_pcm) { struct phonedev *phonedev = &PHONEDEV(xpd); unsigned int x; spin_lock_init(&phonedev->lock_recompute_pcm); phonedev->channels = channels; phonedev->no_pcm = no_pcm; phonedev->offhook_state = 0x0; /* ONHOOK */ phonedev->phoneops = proto_table->phoneops; phonedev->digital_outputs = 0; phonedev->digital_inputs = 0; atomic_set(&phonedev->dahdi_registered, 0); atomic_set(&phonedev->open_counter, 0); for (x = 0; x < phonedev->channels; x++) { if (!(phonedev->chans[x] = KZALLOC(sizeof(*(phonedev->chans[x])), GFP_KERNEL))) { ERR("%s: Unable to allocate channel %d\n", __FUNCTION__, x); goto err; } phonedev->ec[x] = KZALLOC(sizeof(*(phonedev->ec[x])), GFP_KERNEL); if (!phonedev->ec[x]) { ERR("%s: Unable to allocate ec state %d\n", __func__, x); goto err; } } return 0; err: phonedev_cleanup(xpd); return -ENOMEM; } /* * xpd_alloc - Allocator for new XPD's * */ __must_check xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits, size_t privsize, const xproto_table_t *proto_table, int channels) { xpd_t *xpd = NULL; size_t alloc_size = sizeof(xpd_t) + privsize; int type = proto_table->type; xpp_line_t no_pcm = 0; BUG_ON(!proto_table); XBUS_DBG(DEVICES, xbus, "type=%d channels=%d (alloc_size=%zd)\n", type, channels, alloc_size); if(channels > CHANNELS_PERXPD) { XBUS_ERR(xbus, "%s: type=%d: too many channels %d\n", __FUNCTION__, type, channels); goto err; } if((xpd = KZALLOC(alloc_size, GFP_KERNEL)) == NULL) { XBUS_ERR(xbus, "%s: type=%d: Unable to allocate memory\n", __FUNCTION__, type); goto err; } xpd->priv = (byte *)xpd + sizeof(xpd_t); spin_lock_init(&xpd->lock); xpd->card_present = 0; xpd->type = proto_table->type; xpd->xproto = proto_table; xpd->xops = proto_table->xops; xpd->xpd_state = XPD_STATE_START; xpd->subtype = subtype; xpd->subunits = subunits; kref_init(&xpd->kref); /* For USB-1 disable some channels */ if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) { no_pcm = 0x7F | PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs; XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n", MAX_SEND_SIZE(xbus), PHONEDEV(xpd).no_pcm); } if (phonedev_init(xpd, proto_table, channels, no_pcm) < 0) goto err; xbus_xpd_bind(xbus, xpd, unit, subunit); if(xpd_proc_create(xbus, xpd) < 0) goto err; /* * This makes sure the xbus cannot be removed before this xpd * is removed in xpd_free() */ xbus = get_xbus(__func__, xbus->num); /* returned in xpd_free() */ xproto_get(type); /* will be returned in xpd_free() */ return xpd; err: if(xpd) { xpd_proc_remove(xbus, xpd); phonedev_cleanup(xpd); KZFREE(xpd); } return NULL; } /* * Try our best to make asterisk close all channels related to * this Astribank: * - Set span state to DAHDI_ALARM_NOTOPEN in all relevant spans. * - Notify dahdi afterwards about spans (so it can see all changes at once). * - Also send DAHDI_EVENT_REMOVED on all channels. */ void xbus_request_removal(xbus_t *xbus) { unsigned long flags; int i; for(i = 0; i < MAX_XPDS; i++) { xpd_t *xpd = xpd_of(xbus, i); if(xpd) { XPD_DBG(DEVICES, xpd, "\n"); spin_lock_irqsave(&xpd->lock, flags); xpd->card_present = 0; xpd_setstate(xpd, XPD_STATE_NOHW); PHONEDEV(xpd).span.alarms = DAHDI_ALARM_NOTOPEN; spin_unlock_irqrestore(&xpd->lock, flags); } } /* Now notify dahdi */ for(i = 0; i < MAX_XPDS; i++) { xpd_t *xpd = xpd_of(xbus, i); if(xpd) { if(SPAN_REGISTERED(xpd)) { int j; dahdi_alarm_notify(&PHONEDEV(xpd).span); XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n"); for (j=0; jlast_response = jiffies; break; default: // Nothing break; } if(span->alarms == alarm_flag) return; XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", PHONEDEV(xpd).span.name, alarm_flag); span->alarms = alarm_flag; dahdi_alarm_notify(span); } /* * Used to block/pass PCM during onhook-transfers. E.g: * - Playing FSK after FXS ONHOOK for MWI (non-neon style) * - Playing DTFM/FSK for FXO Caller-ID detection. */ void oht_pcm(xpd_t *xpd, int pos, bool pass) { if(pass) { LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: pass\n"); BIT_SET(PHONEDEV(xpd).oht_pcm_pass, pos); } else { LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: block\n"); BIT_CLR(PHONEDEV(xpd).oht_pcm_pass, pos); } CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); } /* * Update our hookstate -- for PCM block/pass */ void mark_offhook(xpd_t *xpd, int pos, bool to_offhook) { if(to_offhook) { LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK\n"); BIT_SET(PHONEDEV(xpd).offhook_state, pos); } else { LINE_DBG(SIGNAL, xpd, pos, "ONHOOK\n"); BIT_CLR(PHONEDEV(xpd).offhook_state, pos); } CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); } /* * Send a signalling notification to Asterisk */ void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig) { /* * We should not spinlock before calling dahdi_hooksig() as * it may call back into our xpp_hooksig() and cause * a nested spinlock scenario */ LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", rxsig2str(rxsig)); if(SPAN_REGISTERED(xpd)) dahdi_hooksig(XPD_CHAN(xpd, pos), rxsig); } /* * Called when hardware state changed: * - FXS -- the phone was picked up or hanged-up. * - FXO -- we answered the phone or handed-up. */ void hookstate_changed(xpd_t *xpd, int pos, bool to_offhook) { BUG_ON(!xpd); mark_offhook(xpd, pos, to_offhook); if(!to_offhook) { oht_pcm(xpd, pos, 0); /* * To prevent latest PCM to stay in buffers * indefinitely, mark this channel for a * single silence transmittion. * * This bit will be cleared on the next tick. */ BIT_SET(PHONEDEV(xpd).silence_pcm, pos); } notify_rxsig(xpd, pos, (to_offhook) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK); } #define XPP_MAX_LEN 512 /*------------------------- Dahdi Interfaces -----------------------*/ /* * Called from dahdi with spinlock held on chan. Must not call back * dahdi functions. */ int xpp_open(struct dahdi_chan *chan) { xpd_t *xpd; xbus_t *xbus; int pos; unsigned long flags; if (!chan) { NOTICE("open called on a null chan\n"); return -EINVAL; } xpd = chan->pvt; xpd = get_xpd(__FUNCTION__, xpd); /* Returned in xpp_close() */ if (!xpd) { NOTICE("open called on a chan with no pvt (xpd)\n"); BUG(); } xbus = xpd->xbus; if (!xbus) { NOTICE("open called on a chan with no xbus\n"); BUG(); } pos = chan->chanpos - 1; if(!xpd->card_present) { LINE_NOTICE(xpd, pos, "Cannot open -- device not ready\n"); put_xpd(__FUNCTION__, xpd); return -ENODEV; } spin_lock_irqsave(&xbus->lock, flags); atomic_inc(&PHONEDEV(xpd).open_counter); LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm, current->pid, atomic_read(&PHONEDEV(xpd).open_counter)); spin_unlock_irqrestore(&xbus->lock, flags); if(PHONE_METHOD(card_open, xpd)) CALL_PHONE_METHOD(card_open, xpd, pos); return 0; } int xpp_close(struct dahdi_chan *chan) { xpd_t *xpd = chan->pvt; xbus_t *xbus = xpd->xbus; int pos = chan->chanpos - 1; unsigned long flags; spin_lock_irqsave(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags); if(PHONE_METHOD(card_close, xpd)) CALL_PHONE_METHOD(card_close, xpd, pos); LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm, current->pid, atomic_read(&PHONEDEV(xpd).open_counter)); atomic_dec(&PHONEDEV(xpd).open_counter); /* from xpp_open() */ put_xpd(__FUNCTION__, xpd); /* from xpp_open() */ return 0; } void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd) { char *extra_msg = ""; if(_IOC_TYPE(cmd) == 'J') extra_msg = " (for old ZAPTEL)"; XPD_NOTICE(xpd, "%s: Bad ioctl%s\n", msg, extra_msg); XPD_NOTICE(xpd, "ENOTTY: chan=%d cmd=0x%x\n", pos, cmd); XPD_NOTICE(xpd, " IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd)); XPD_NOTICE(xpd, " IOC_DIR=0x%02X\n", _IOC_DIR(cmd)); XPD_NOTICE(xpd, " IOC_NR=%d\n", _IOC_NR(cmd)); XPD_NOTICE(xpd, " IOC_SIZE=0x%02X\n", _IOC_SIZE(cmd)); } int xpp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long arg) { xpd_t *xpd = chan->pvt; int pos = chan->chanpos - 1; if(!xpd) { ERR("%s: channel in pos %d, was already closed. Ignore.\n", __FUNCTION__, pos); return -ENODEV; } switch (cmd) { default: /* Some span-specific commands before we give up: */ if (PHONE_METHOD(card_ioctl, xpd)) { return CALL_PHONE_METHOD(card_ioctl, xpd, pos, cmd, arg); } report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); return -ENOTTY; } return 0; } int xpp_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { xpd_t *xpd = chan->pvt; xbus_t *xbus; int pos = chan->chanpos - 1; if(!xpd) { ERR("%s: channel in pos %d, was already closed. Ignore.\n", __FUNCTION__, pos); return -ENODEV; } if(!PHONE_METHOD(card_hooksig, xpd)) { LINE_ERR(xpd, pos, "%s: No hooksig method for this channel. Ignore.\n", __FUNCTION__); return -ENODEV; } xbus = xpd->xbus; BUG_ON(!xbus); DBG(SIGNAL, "Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig); return CALL_PHONE_METHOD(card_hooksig, xpd, pos, txsig); } EXPORT_SYMBOL(xpp_hooksig); /* Req: Set the requested chunk size. This is the unit in which you must report results for conferencing, etc */ int xpp_setchunksize(struct dahdi_span *span, int chunksize); /* Enable maintenance modes */ int xpp_maint(struct dahdi_span *span, int cmd) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); int ret = 0; #if 0 char loopback_data[] = "THE-QUICK-BROWN-FOX-JUMPED-OVER-THE-LAZY-DOG"; #endif DBG(GENERAL, "span->mainttimer=%d\n", span->mainttimer); switch(cmd) { case DAHDI_MAINT_NONE: INFO("XXX Turn off local and remote loops XXX\n"); break; case DAHDI_MAINT_LOCALLOOP: INFO("XXX Turn on local loopback XXX\n"); break; case DAHDI_MAINT_REMOTELOOP: INFO("XXX Turn on remote loopback XXX\n"); break; case DAHDI_MAINT_LOOPUP: INFO("XXX Send loopup code XXX\n"); break; case DAHDI_MAINT_LOOPDOWN: INFO("XXX Send loopdown code XXX\n"); break; default: ERR("XPP: Unknown maint command: %d\n", cmd); ret = -EINVAL; break; } if (span->mainttimer || span->maintstat) update_xpd_status(xpd, DAHDI_ALARM_LOOPBACK); return ret; } #ifdef CONFIG_DAHDI_WATCHDOG /* * If the watchdog detects no received data, it will call the * watchdog routine */ static int xpp_watchdog(struct dahdi_span *span, int cause) { static int rate_limit = 0; if((rate_limit++ % 1000) == 0) DBG(GENERAL, "\n"); return 0; } #endif /* * Hardware Echo Canceller management */ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { xpd_t *xpd; xbus_t *xbus; int pos = chan->chanpos - 1; const struct echoops *echoops; xpd = chan->pvt; xbus = xpd->xbus; echoops = ECHOOPS(xbus); if (!echoops) return; LINE_DBG(GENERAL, xpd, pos, "mode=0x%X\n", ec->status.mode); CALL_EC_METHOD(ec_set, xbus, xpd, pos, 0); CALL_EC_METHOD(ec_update, xbus, xbus); } static const struct dahdi_echocan_features xpp_ec_features = { }; static const struct dahdi_echocan_ops xpp_ec_ops = { .echocan_free = echocan_free, }; const char *xpp_echocan_name(const struct dahdi_chan *chan) { xpd_t *xpd; xbus_t *xbus; int pos; if (!chan) { NOTICE("%s(NULL)\n", __func__); return "XPP"; } xpd = chan->pvt; xbus = xpd->xbus; pos = chan->chanpos - 1; LINE_DBG(GENERAL, xpd, pos, "%s:\n", __func__); if (!ECHOOPS(xbus)) return NULL; /* * quirks and limitations */ if (xbus->quirks.has_fxo) { if ( xbus->quirks.has_digital_span && xpd->type == XPD_TYPE_FXO) { LINE_NOTICE(xpd, pos, "quirk: give up HWEC on FXO: " "AB has digital span\n"); return NULL; } else if ( xbus->sync_mode != SYNC_MODE_AB && xpd->type == XPD_TYPE_FXS) { LINE_NOTICE(xpd, pos, "quirk: give up HWEC on FXS: " "AB has FXO and is sync slave\n"); return NULL; } } return "XPP"; } EXPORT_SYMBOL(xpp_echocan_name); int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { xpd_t *xpd; xbus_t *xbus; int pos; struct phonedev *phonedev; const struct echoops *echoops; int ret; xpd = chan->pvt; xbus = xpd->xbus; pos = chan->chanpos - 1; echoops = ECHOOPS(xbus); if (!echoops) return -ENODEV; phonedev = &PHONEDEV(xpd); *ec = phonedev->ec[pos]; (*ec)->ops = &xpp_ec_ops; (*ec)->features = xpp_ec_features; LINE_DBG(GENERAL, xpd, pos, "(tap=%d, param_count=%d)\n", ecp->tap_length, ecp->param_count); ret = CALL_EC_METHOD(ec_set, xbus, xpd, pos, 1); CALL_EC_METHOD(ec_update, xbus, xbus); return ret; } EXPORT_SYMBOL(xpp_echocan_create); /** * Unregister an xpd from dahdi and release related resources * @xpd The xpd to be unregistered * @returns 0 on success, errno otherwise * * Checks that nobody holds an open channel. * * Called by: * - User action through /proc * - During xpd_remove() */ int dahdi_unregister_xpd(xpd_t *xpd) { unsigned long flags; BUG_ON(!xpd); spin_lock_irqsave(&xpd->lock, flags); if (!IS_PHONEDEV(xpd)) { XPD_ERR(xpd, "Not a telephony device\n"); spin_unlock_irqrestore(&xpd->lock, flags); return -EBADF; } if(!SPAN_REGISTERED(xpd)) { XPD_NOTICE(xpd, "Already unregistered\n"); spin_unlock_irqrestore(&xpd->lock, flags); return -EIDRM; } update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN); /* We should now have only a ref from the xbus (from create_xpd()) */ if(atomic_read(&PHONEDEV(xpd).open_counter)) { XPD_NOTICE(xpd, "Busy (open_counter=%d). Skipping.\n", atomic_read(&PHONEDEV(xpd).open_counter)); spin_unlock_irqrestore(&xpd->lock, flags); return -EBUSY; } mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish. spin_unlock_irqrestore(&xpd->lock, flags); if(xpd->card_present) CALL_PHONE_METHOD(card_dahdi_preregistration, xpd, 0); atomic_dec(&PHONEDEV(xpd).dahdi_registered); atomic_dec(&num_registered_spans); dahdi_unregister(&PHONEDEV(xpd).span); if(xpd->card_present) CALL_PHONE_METHOD(card_dahdi_postregistration, xpd, 0); return 0; } static const struct dahdi_span_ops xpp_span_ops = { .owner = THIS_MODULE, .open = xpp_open, .close = xpp_close, .ioctl = xpp_ioctl, .maint = xpp_maint, .echocan_create = xpp_echocan_create, .echocan_name = xpp_echocan_name, }; static const struct dahdi_span_ops xpp_rbs_span_ops = { .owner = THIS_MODULE, .hooksig = xpp_hooksig, .open = xpp_open, .close = xpp_close, .ioctl = xpp_ioctl, .maint = xpp_maint, .echocan_create = xpp_echocan_create, .echocan_name = xpp_echocan_name, }; int dahdi_register_xpd(xpd_t *xpd) { struct dahdi_span *span; xbus_t *xbus; int cn; int i; BUG_ON(!xpd); xbus = xpd->xbus; if (!IS_PHONEDEV(xpd)) { XPD_ERR(xpd, "Not a telephony device\n"); return -EBADF; } if (SPAN_REGISTERED(xpd)) { XPD_ERR(xpd, "Already registered\n"); return -EEXIST; } cn = PHONEDEV(xpd).channels; XPD_DBG(DEVICES, xpd, "Initializing span: %d channels.\n", cn); memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span)); for(i = 0; i < cn; i++) { memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan)); } span = &PHONEDEV(xpd).span; snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname); span->deflaw = DAHDI_LAW_MULAW; /* default, may be overriden by card_* drivers */ span->channels = cn; span->chans = PHONEDEV(xpd).chans; span->flags = DAHDI_FLAG_RBS; if(PHONEDEV(xpd).phoneops->card_hooksig) span->ops = &xpp_rbs_span_ops; /* Only with RBS bits */ else span->ops = &xpp_span_ops; /* * This actually describe the dahdi_spaninfo version 3 * A bunch of unrelated data exported via a modified ioctl() * What a bummer... */ span->manufacturer = "Xorcom Inc."; /* OK, that's obvious */ /* span->spantype = "...."; set in card_dahdi_preregistration() */ /* * Yes, this basically duplicates information available * from the description field. If some more is needed * why not add it there? * OK, let's add to the kernel more useless info. */ snprintf(span->devicetype, sizeof(span->devicetype) - 1, "Astribank: Unit %x Subunit %x: %s", XBUS_UNIT(xpd->xbus_idx), XBUS_SUBUNIT(xpd->xbus_idx), xpd->type_name); /* * location is the only usefull new data item. * For our devices it was available for ages via: * - The legacy "/proc/xpp/XBUS-??/summary" (CONNECTOR=...) * - The same info in "/proc/xpp/xbuses" * - The modern "/sys/bus/astribanks/devices/xbus-??/connector" attribute * So let's also export it via the newfangled "location" field. */ snprintf(span->location, sizeof(span->location) - 1, "%s", xbus->connector); /* * Who said a span and irq have 1-1 relationship? * Also exporting this low-level detail isn't too wise. * No irq's for you today! */ span->irq = 0; snprintf(PHONEDEV(xpd).span.desc, MAX_SPANDESC, "Xorcom XPD #%02d/%1d%1d: %s", xbus->num, xpd->addr.unit, xpd->addr.subunit, xpd->type_name); XPD_DBG(GENERAL, xpd, "Registering span '%s'\n", PHONEDEV(xpd).span.desc); CALL_PHONE_METHOD(card_dahdi_preregistration, xpd, 1); if(dahdi_register(&PHONEDEV(xpd).span, prefmaster)) { XPD_ERR(xpd, "Failed to dahdi_register span\n"); return -ENODEV; } atomic_inc(&num_registered_spans); atomic_inc(&PHONEDEV(xpd).dahdi_registered); CALL_PHONE_METHOD(card_dahdi_postregistration, xpd, 1); /* * Update dahdi about our state: * - Since asterisk didn't open the channel yet, * the report is discarded anyway. * - Our FXS driver have another notification mechanism that * is triggered (indirectly) by the open() of the channe. * - The real fix should be in Asterisk (to get the correct state * after open). */ for_each_line(xpd, cn) { if(IS_OFFHOOK(xpd, cn)) notify_rxsig(xpd, cn, DAHDI_RXSIG_OFFHOOK); } return 0; } /*------------------------- Initialization -------------------------*/ static void do_cleanup(void) { #ifdef CONFIG_PROC_FS if(xpp_proc_toplevel) { DBG(GENERAL, "Removing '%s' from proc\n", PROC_DIR); remove_proc_entry(PROC_DIR, NULL); xpp_proc_toplevel = NULL; } #endif } static int __init xpp_dahdi_init(void) { int ret = 0; void *top = NULL; INFO("revision %s MAX_XPDS=%d (%d*%d)\n", XPP_VERSION, MAX_XPDS, MAX_UNIT, MAX_SUBUNIT); #ifdef CONFIG_DAHDI_BRI_DCHANS INFO("FEATURE: with BRISTUFF support\n"); #else INFO("FEATURE: without BRISTUFF support\n"); #endif #ifdef CONFIG_PROC_FS xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL); if(!xpp_proc_toplevel) { ret = -EIO; goto err; } top = xpp_proc_toplevel; #endif ret = xbus_core_init(); if(ret) { ERR("xbus_core_init failed (%d)\n", ret); goto err; } ret = xbus_pcm_init(top); if(ret) { ERR("xbus_pcm_init failed (%d)\n", ret); xbus_core_shutdown(); goto err; } return 0; err: do_cleanup(); return ret; } static void __exit xpp_dahdi_cleanup(void) { xbus_pcm_shutdown(); xbus_core_shutdown(); do_cleanup(); } EXPORT_SYMBOL(debug); EXPORT_SYMBOL(create_xpd); EXPORT_SYMBOL(xpd_post_init); EXPORT_SYMBOL(get_xpd); EXPORT_SYMBOL(put_xpd); EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_free); EXPORT_SYMBOL(xbus_request_removal); EXPORT_SYMBOL(update_xpd_status); EXPORT_SYMBOL(oht_pcm); EXPORT_SYMBOL(mark_offhook); EXPORT_SYMBOL(notify_rxsig); EXPORT_SYMBOL(hookstate_changed); EXPORT_SYMBOL(xpp_open); EXPORT_SYMBOL(xpp_close); EXPORT_SYMBOL(xpp_ioctl); EXPORT_SYMBOL(xpp_maint); EXPORT_SYMBOL(report_bad_ioctl); MODULE_DESCRIPTION("XPP Dahdi Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); module_init(xpp_dahdi_init); module_exit(xpp_dahdi_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_fxo.c0000644000175000017500000011531611602416004021277 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "xpd.h" #include "xproto.h" #include "xpp_dahdi.h" #include "card_fxo.h" #include "dahdi_debug.h" #include "xbus-core.h" static const char rcsid[] = "$Id: card_fxo.c 9993 2011-06-28 18:23:00Z tzafrir $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); static DEF_PARM(uint, poll_battery_interval, 500, 0644, "Poll battery interval in milliseconds (0 - disable)"); #ifdef WITH_METERING static DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval in milliseconds (0 - disable)"); #endif static DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication"); static DEF_PARM(int, caller_id_style, 0, 0444, "Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]"); static DEF_PARM(int, power_denial_safezone, 650, 0644, "msec after offhook to ignore power-denial ( (0 - disable power-denial)"); static DEF_PARM(int, power_denial_minlen, 80, 0644, "Minimal detected power-denial length (msec) (0 - disable power-denial)"); static DEF_PARM(uint, battery_threshold, 3, 0644, "Minimum voltage that shows there is battery"); static DEF_PARM(uint, battery_debounce, 1000, 0644, "Minimum interval (msec) for detection of battery off"); enum cid_style { CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */ CID_STYLE_ETSI_FSK = 1, /* E.g: UK (British Telecom) */ CID_STYLE_ETSI_DTMF = 2, /* E.g: DK, Russia */ }; /* Signaling is opposite (fxs signalling for fxo card) */ #if 1 #define FXO_DEFAULT_SIGCAP (DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS) #else #define FXO_DEFAULT_SIGCAP (DAHDI_SIG_SF) #endif enum fxo_leds { LED_GREEN, LED_RED, }; #define NUM_LEDS 2 #define DELAY_UNTIL_DIALTONE 3000 /* * Minimum duration for polarity reversal detection (in ticks) * Should be longer than the time to detect a ring, so voltage * fluctuation during ring won't trigger false detection. */ #define POLREV_THRESHOLD 200 #define POWER_DENIAL_CURRENT 3 #define POWER_DENIAL_DELAY 2500 /* ticks */ /* Shortcuts */ #define DAA_WRITE 1 #define DAA_READ 0 #define DAA_DIRECT_REQUEST(xbus,xpd,port,writing,reg,dL) \ xpp_register_request((xbus), (xpd), (port), (writing), (reg), 0, 0, (dL), 0, 0, 0) /*---------------- FXO Protocol Commands ----------------------------------*/ static bool fxo_packet_is_valid(xpacket_t *pack); static void fxo_packet_dump(const char *msg, xpacket_t *pack); #ifdef CONFIG_PROC_FS static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); #ifdef WITH_METERING static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data); #endif #endif static void dahdi_report_battery(xpd_t *xpd, lineno_t chan); #define PROC_REGISTER_FNAME "slics" #define PROC_FXO_INFO_FNAME "fxo_info" #ifdef WITH_METERING #define PROC_METERING_FNAME "metering_read" #endif #define REG_DAA_CONTROL1 0x05 /* 5 - DAA Control 1 */ #define REG_DAA_CONTROL1_OH BIT(0) /* Off-Hook. */ #define REG_DAA_CONTROL1_ONHM BIT(3) /* On-Hook Line Monitor */ #define DAA_REG_METERING 0x11 /* 17 */ #define DAA_REG_CURRENT 0x1C /* 28 */ #define DAA_REG_VBAT 0x1D /* 29 */ enum battery_state { BATTERY_UNKNOWN = 0, BATTERY_ON = 1, BATTERY_OFF = -1 }; enum polarity_state { POL_UNKNOWN = 0, POL_POSITIVE = 1, POL_NEGATIVE = -1 }; enum power_state { POWER_UNKNOWN = 0, POWER_ON = 1, POWER_OFF = -1 }; struct FXO_priv_data { #ifdef WITH_METERING struct proc_dir_entry *meteringfile; #endif struct proc_dir_entry *fxo_info; uint poll_counter; signed char battery_voltage[CHANNELS_PERXPD]; signed char battery_current[CHANNELS_PERXPD]; enum battery_state battery[CHANNELS_PERXPD]; ushort nobattery_debounce[CHANNELS_PERXPD]; enum polarity_state polarity[CHANNELS_PERXPD]; ushort polarity_debounce[CHANNELS_PERXPD]; enum power_state power[CHANNELS_PERXPD]; ushort power_denial_delay[CHANNELS_PERXPD]; ushort power_denial_length[CHANNELS_PERXPD]; ushort power_denial_safezone[CHANNELS_PERXPD]; xpp_line_t cidfound; /* 0 - OFF, 1 - ON */ unsigned int cidtimer[CHANNELS_PERXPD]; xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */ int led_counter[NUM_LEDS][CHANNELS_PERXPD]; atomic_t ring_debounce[CHANNELS_PERXPD]; #ifdef WITH_METERING uint metering_count[CHANNELS_PERXPD]; xpp_line_t metering_tone_state; #endif }; /* * LED counter values: * n>1 : BLINK every n'th tick */ #define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos]) #define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0) #define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t)) #define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) #define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) #define LED_BLINK_RING (1000/8) /* in ticks */ /*---------------- FXO: Static functions ----------------------------------*/ static const char *power2str(enum power_state pw) { switch(pw) { case POWER_UNKNOWN: return "UNKNOWN"; case POWER_OFF: return "OFF"; case POWER_ON: return "ON"; } return NULL; } static void power_change(xpd_t *xpd, int portno, enum power_state pw) { struct FXO_priv_data *priv; priv = xpd->priv; LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n", power2str(priv->power[portno]), power2str(pw)); priv->power[portno] = pw; } static void reset_battery_readings(xpd_t *xpd, lineno_t pos) { struct FXO_priv_data *priv = xpd->priv; priv->nobattery_debounce[pos] = 0; priv->power_denial_delay[pos] = 0; power_change(xpd, pos, POWER_UNKNOWN); } static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) }; /* * LED control is done via DAA register 0x20 */ static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on) { int ret = 0; struct FXO_priv_data *priv; xbus_t *xbus; byte value; BUG_ON(!xpd); xbus = xpd->xbus; priv = xpd->priv; which = which % NUM_LEDS; if(IS_SET(PHONEDEV(xpd).digital_outputs, chan) || IS_SET(PHONEDEV(xpd).digital_inputs, chan)) goto out; if(chan == PORT_BROADCAST) { priv->ledstate[which] = (on) ? ~0 : 0; } else { if(on) { BIT_SET(priv->ledstate[which], chan); } else { BIT_CLR(priv->ledstate[which], chan); } } value = 0; value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]); value |= (on) ? BIT(0) : 0; value |= (on) ? BIT(1) : 0; LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off"); ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, value); out: return ret; } static void handle_fxo_leds(xpd_t *xpd) { int i; unsigned long flags; const enum fxo_leds colors[] = { LED_GREEN, LED_RED }; enum fxo_leds color; unsigned int timer_count; struct FXO_priv_data *priv; BUG_ON(!xpd); spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; timer_count = xpd->timer_count; for(color = 0; color < ARRAY_SIZE(colors); color++) { for_each_line(xpd, i) { if(IS_SET(PHONEDEV(xpd).digital_outputs, i) || IS_SET(PHONEDEV(xpd).digital_inputs, i)) continue; if((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking int mod_value = LED_COUNTER(priv, i, color); if(!mod_value) mod_value = DEFAULT_LED_PERIOD; /* safety value */ // led state is toggled if((timer_count % mod_value) == 0) { LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF"); if(!IS_SET(priv->ledstate[color], i)) { do_led(xpd, i, color, 1); } else { do_led(xpd, i, color, 0); } } } else if(IS_SET(priv->ledcontrol[color], i) && !IS_SET(priv->ledstate[color], i)) { do_led(xpd, i, color, 1); } else if(!IS_SET(priv->ledcontrol[color], i) && IS_SET(priv->ledstate[color], i)) { do_led(xpd, i, color, 0); } } } spin_unlock_irqrestore(&xpd->lock, flags); } static void update_dahdi_ring(xpd_t *xpd, int pos, bool on) { BUG_ON(!xpd); if(caller_id_style == CID_STYLE_BELL) oht_pcm(xpd, pos, !on); /* * We should not spinlock before calling dahdi_hooksig() as * it may call back into our xpp_hooksig() and cause * a nested spinlock scenario */ notify_rxsig(xpd, pos, (on) ? DAHDI_RXSIG_RING : DAHDI_RXSIG_OFFHOOK); } static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_dahdi) { struct FXO_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); atomic_set(&priv->ring_debounce[pos], 0); /* Stop debouncing */ /* * We don't want to check battery during ringing * due to voltage fluctuations. */ reset_battery_readings(xpd, pos); if(on && !PHONEDEV(xpd).ringing[pos]) { LINE_DBG(SIGNAL, xpd, pos, "START\n"); PHONEDEV(xpd).ringing[pos] = 1; priv->cidtimer[pos] = xpd->timer_count; MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK_RING); if(update_dahdi) update_dahdi_ring(xpd, pos, on); } else if(!on && PHONEDEV(xpd).ringing[pos]) { LINE_DBG(SIGNAL, xpd, pos, "STOP\n"); PHONEDEV(xpd).ringing[pos] = 0; priv->cidtimer[pos] = xpd->timer_count; if(IS_BLINKING(priv, pos, LED_GREEN)) MARK_BLINK(priv, pos, LED_GREEN, 0); if(update_dahdi) update_dahdi_ring(xpd, pos, on); } } static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) { unsigned long flags; xbus_t *xbus; struct FXO_priv_data *priv; int ret = 0; byte value; BUG_ON(!xpd); BUG_ON(PHONEDEV(xpd).direction == TO_PHONE); // We can SETHOOK state only on PSTN xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!priv); if(priv->battery[pos] != BATTERY_ON && to_offhook) { LINE_NOTICE(xpd, pos, "Cannot take offhook while battery is off!\n"); return -EINVAL; } spin_lock_irqsave(&xpd->lock, flags); mark_ring(xpd, pos, 0, 0); // No more rings value = REG_DAA_CONTROL1_ONHM; /* Bit 3 is for CID */ if(to_offhook) value |= REG_DAA_CONTROL1_OH; LINE_DBG(SIGNAL, xpd, pos, "SETHOOK: value=0x%02X %s\n", value, (to_offhook)?"OFFHOOK":"ONHOOK"); if(to_offhook) MARK_ON(priv, pos, LED_GREEN); else MARK_OFF(priv, pos, LED_GREEN); ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value); mark_offhook(xpd, pos, to_offhook); if(caller_id_style != CID_STYLE_ETSI_DTMF) oht_pcm(xpd, pos, 0); #ifdef WITH_METERING priv->metering_count[pos] = 0; priv->metering_tone_state = 0L; DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D); #endif reset_battery_readings(xpd, pos); /* unstable during hook changes */ if(to_offhook) { priv->power_denial_safezone[pos] = power_denial_safezone; } else { priv->power_denial_length[pos] = 0; priv->power_denial_safezone[pos] = 0; } priv->cidtimer[pos] = xpd->timer_count; spin_unlock_irqrestore(&xpd->lock, flags); return ret; } /*---------------- FXO: Methods -------------------------------------------*/ static void fxo_proc_remove(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; XPD_DBG(PROC, xpd, "\n"); #ifdef CONFIG_PROC_FS #ifdef WITH_METERING if(priv->meteringfile) { XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n"); priv->meteringfile->data = NULL; remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir); priv->meteringfile = NULL; } #endif if(priv->fxo_info) { XPD_DBG(PROC, xpd, "Removing xpd FXO_INFO file\n"); remove_proc_entry(PROC_FXO_INFO_FNAME, xpd->proc_xpd_dir); priv->fxo_info = NULL; } #endif } static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; #ifdef CONFIG_PROC_FS XPD_DBG(PROC, xpd, "Creating FXO_INFO file\n"); priv->fxo_info = create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxo_info_read, xpd); if(!priv->fxo_info) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXO_INFO_FNAME); fxo_proc_remove(xbus, xpd); return -EINVAL; } SET_PROC_DIRENTRY_OWNER(priv->fxo_info); #ifdef WITH_METERING XPD_DBG(PROC, xpd, "Creating Metering tone file\n"); priv->meteringfile = create_proc_read_entry(PROC_METERING_FNAME, 0444, xpd->proc_xpd_dir, proc_xpd_metering_read, xpd); if(!priv->meteringfile) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME); fxo_proc_remove(xbus, xpd); return -EINVAL; } SET_PROC_DIRENTRY_OWNER(priv->meteringfile); #endif #endif return 0; } static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone) { xpd_t *xpd = NULL; int channels; if(to_phone) { XBUS_NOTICE(xbus, "XPD=%d%d: try to instanciate FXO with reverse direction\n", unit, subunit); return NULL; } if(subtype == 2) channels = min(2, subunit_ports); else channels = min(8, subunit_ports); xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct FXO_priv_data), proto_table, channels); if(!xpd) return NULL; PHONEDEV(xpd).direction = TO_PSTN; xpd->type_name = "FXO"; if(fxo_proc_create(xbus, xpd) < 0) goto err; return xpd; err: xpd_free(xpd); return NULL; } static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; int i; BUG_ON(!xpd); priv = xpd->priv; // Hanghup all lines for_each_line(xpd, i) { do_sethook(xpd, i, 0); priv->polarity[i] = POL_UNKNOWN; /* will be updated on next battery sample */ priv->polarity_debounce[i] = 0; priv->battery[i] = BATTERY_UNKNOWN; /* will be updated on next battery sample */ priv->power[i] = POWER_UNKNOWN; /* will be updated on next battery sample */ if(caller_id_style == CID_STYLE_ETSI_DTMF) oht_pcm(xpd, i, 1); } XPD_DBG(GENERAL, xpd, "done\n"); for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 0); } for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 1); msleep(50); } for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 0); msleep(50); } CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); return 0; } static int FXO_card_remove(xbus_t *xbus, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); fxo_proc_remove(xbus, xpd); return 0; } static int FXO_card_dahdi_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct FXO_priv_data *priv; int i; unsigned int timer_count; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); priv = xpd->priv; BUG_ON(!priv); timer_count = xpd->timer_count; XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); PHONEDEV(xpd).span.spantype = "FXO"; for_each_line(xpd, i) { struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting FXO channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d", xbus->num, xpd->addr.unit, xpd->addr.subunit, i); cur_chan->chanpos = i + 1; cur_chan->pvt = xpd; cur_chan->sigcap = FXO_DEFAULT_SIGCAP; } for_each_line(xpd, i) { MARK_ON(priv, i, LED_GREEN); msleep(4); MARK_ON(priv, i, LED_RED); } for_each_line(xpd, i) { priv->cidtimer[i] = timer_count; } return 0; } static int FXO_card_dahdi_postregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct FXO_priv_data *priv; int i; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); for_each_line(xpd, i) { dahdi_report_battery(xpd, i); MARK_OFF(priv, i, LED_GREEN); msleep(2); MARK_OFF(priv, i, LED_RED); msleep(2); } return 0; } static int FXO_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig) { struct FXO_priv_data *priv; int ret = 0; priv = xpd->priv; BUG_ON(!priv); LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig)); BUG_ON(PHONEDEV(xpd).direction != TO_PSTN); /* XXX Enable hooksig for FXO XXX */ switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: ret = do_sethook(xpd, pos, 1); break; case DAHDI_TXSIG_ONHOOK: ret = do_sethook(xpd, pos, 0); break; default: XPD_NOTICE(xpd, "Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig); return -EINVAL; } return ret; } static void dahdi_report_battery(xpd_t *xpd, lineno_t chan) { struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; if(SPAN_REGISTERED(xpd)) { switch(priv->battery[chan]) { case BATTERY_UNKNOWN: /* no-op */ break; case BATTERY_OFF: LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_RED\n"); dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_RED); break; case BATTERY_ON: LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_NONE\n"); dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_NONE); break; } } } static int FXO_card_open(xpd_t *xpd, lineno_t chan) { BUG_ON(!xpd); return 0; } static void poll_battery(xbus_t *xbus, xpd_t *xpd) { int i; for_each_line(xpd, i) { DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_VBAT, 0); } } #ifdef WITH_METERING static void poll_metering(xbus_t *xbus, xpd_t *xpd) { int i; for_each_line(xpd, i) { if (IS_OFFHOOK(xpd, i)) DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0); } } #endif static void handle_fxo_ring(xpd_t *xpd) { struct FXO_priv_data *priv; int i; priv = xpd->priv; for_each_line(xpd, i) { if(atomic_read(&priv->ring_debounce[i]) > 0) { /* Maybe start ring */ if(atomic_dec_and_test(&priv->ring_debounce[i])) mark_ring(xpd, i, 1, 1); } else if (atomic_read(&priv->ring_debounce[i]) < 0) { /* Maybe stop ring */ if(atomic_inc_and_test(&priv->ring_debounce[i])) mark_ring(xpd, i, 0, 1); } } } static void handle_fxo_power_denial(xpd_t *xpd) { struct FXO_priv_data *priv; int i; if(!power_denial_safezone) return; /* Ignore power denials */ priv = xpd->priv; for_each_line(xpd, i) { if(PHONEDEV(xpd).ringing[i] || !IS_OFFHOOK(xpd, i)) { priv->power_denial_delay[i] = 0; continue; } if(priv->power_denial_safezone[i] > 0) { if(--priv->power_denial_safezone[i] == 0) { /* * Poll current, previous answers are meaningless */ DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0); } continue; } if(priv->power_denial_length[i] > 0) { priv->power_denial_length[i]--; if(priv->power_denial_length[i] <= 0) { /* * But maybe the FXS started to ring (and the firmware haven't * detected it yet). This would cause false power denials. * So we just flag it and schedule more ticks to wait. */ LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n"); priv->power_denial_delay[i] = POWER_DENIAL_DELAY; } continue; } if (priv->power_denial_delay[i] > 0) { /* * Ring detection by the firmware takes some time. * Therefore we delay our decision until we are * sure that no ring has started during this time. */ priv->power_denial_delay[i]--; if (priv->power_denial_delay[i] <= 0) { LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n"); priv->power_denial_delay[i] = 0; /* * Let Asterisk decide what to do */ notify_rxsig(xpd, i, DAHDI_RXSIG_ONHOOK); } } } } /* * For caller-id CID_STYLE_ETSI_DTMF: * - No indication is passed before the CID * - We try to detect it and send "fake" polarity reversal. * - The chan_dahdi.conf should have cidstart=polarity * - Based on an idea in http://bugs.digium.com/view.php?id=9096 */ static void check_etsi_dtmf(xpd_t *xpd) { struct FXO_priv_data *priv; int portno; unsigned int timer_count; if(!SPAN_REGISTERED(xpd)) return; priv = xpd->priv; BUG_ON(!priv); timer_count = xpd->timer_count; for_each_line(xpd, portno) { /* Skip offhook and ringing ports */ if(IS_OFFHOOK(xpd, portno) || PHONEDEV(xpd).ringing[portno]) continue; if(IS_SET(priv->cidfound, portno)) { if(timer_count > priv->cidtimer[portno] + 4000) { /* reset flags if it's been a while */ priv->cidtimer[portno] = timer_count; BIT_CLR(priv->cidfound, portno); LINE_DBG(SIGNAL, xpd, portno, "Reset CID flag\n"); } continue; } if(timer_count > priv->cidtimer[portno] + 400) { struct dahdi_chan *chan = XPD_CHAN(xpd, portno); int sample; int i; for(i = 0; i < DAHDI_CHUNKSIZE; i++) { sample = DAHDI_XLAW(chan->readchunk[i], chan); if(sample > 16000 || sample < -16000) { priv->cidtimer[portno] = timer_count; BIT_SET(priv->cidfound, portno); LINE_DBG(SIGNAL, xpd, portno, "Found DTMF CLIP (%d)\n", i); dahdi_qevent_lock(chan, DAHDI_EVENT_POLARITY); break; } } } } } static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) poll_battery(xbus, xpd); #ifdef WITH_METERING if(poll_metering_interval != 0 && (priv->poll_counter % poll_metering_interval) == 0) poll_metering(xbus, xpd); #endif handle_fxo_leds(xpd); handle_fxo_ring(xpd); handle_fxo_power_denial(xpd); if(caller_id_style == CID_STYLE_ETSI_DTMF && likely(xpd->card_present)) check_etsi_dtmf(xpd); priv->poll_counter++; return 0; } #include /* * The first register is the ACIM, the other are coefficient registers. * We define the array size explicitly to track possible inconsistencies * if the struct is modified. */ static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52}; static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) { int i,ret; unsigned char echotune_data[ARRAY_SIZE(echotune_regs)]; BUG_ON(!xpd); if(!XBUS_IS(xpd->xbus, READY)) return -ENODEV; switch (cmd) { case WCTDM_SET_ECHOTUNE: XPD_DBG(GENERAL, xpd, "-- Setting echo registers: \n"); /* first off: check if this span is fxs. If not: -EINVALID */ if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data))) return -EFAULT; for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) { XPD_DBG(REGS, xpd, "Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]); ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]); if (ret < 0) { LINE_NOTICE(xpd, pos, "Couldn't write %0x02X to register %0x02X\n", echotune_data[i], echotune_regs[i]); return ret; } msleep(1); } XPD_DBG(GENERAL, xpd, "-- Set echo registers successfully\n"); break; case DAHDI_TONEDETECT: /* * Asterisk call all span types with this (FXS specific) * call. Silently ignore it. */ LINE_DBG(GENERAL, xpd, pos, "DAHDI_TONEDETECT (FXO: NOTIMPLEMENTED)\n"); return -ENOTTY; default: report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); return -ENOTTY; } return 0; } /*---------------- FXO: HOST COMMANDS -------------------------------------*/ /*---------------- FXO: Astribank Reply Handlers --------------------------*/ HANDLER_DEF(FXO, SIG_CHANGED) { xpp_line_t sig_status = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status); xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles); unsigned long flags; int i; struct FXO_priv_data *priv; if(!xpd) { notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), cmd->name); return -EPROTO; } priv = xpd->priv; BUG_ON(!priv); XPD_DBG(SIGNAL, xpd, "(PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status); spin_lock_irqsave(&xpd->lock, flags); for_each_line(xpd, i) { int debounce; if(IS_SET(sig_toggles, i)) { if(priv->battery[i] == BATTERY_OFF) { /* * With poll_battery_interval==0 we cannot have BATTERY_OFF * so we won't get here */ LINE_NOTICE(xpd, i, "SIG_CHANGED while battery is off. Ignored.\n"); continue; } /* First report false ring alarms */ debounce = atomic_read(&priv->ring_debounce[i]); if(debounce) LINE_NOTICE(xpd, i, "debounced false ring (only %d ticks)\n", debounce); /* * Now set a new ring alarm. * It will be checked in handle_fxo_ring() */ debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce; atomic_set(&priv->ring_debounce[i], debounce); } } spin_unlock_irqrestore(&xpd->lock, flags); return 0; } static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno) { struct FXO_priv_data *priv; enum polarity_state pol; int msec; signed char volts = (signed char)data_low; priv = xpd->priv; BUG_ON(!priv); priv->battery_voltage[portno] = volts; if(PHONEDEV(xpd).ringing[portno]) goto ignore_reading; /* ring voltage create false alarms */ if(abs(volts) < battery_threshold) { /* * Check for battery voltage fluctuations */ if(priv->battery[portno] != BATTERY_OFF) { int milliseconds; milliseconds = priv->nobattery_debounce[portno]++ * poll_battery_interval; if(milliseconds > battery_debounce) { LINE_DBG(SIGNAL, xpd, portno, "BATTERY OFF voltage=%d\n", volts); priv->battery[portno] = BATTERY_OFF; dahdi_report_battery(xpd, portno); /* What's the polarity ? */ priv->polarity[portno] = POL_UNKNOWN; priv->polarity_debounce[portno] = 0; /* What's the current ? */ power_change(xpd, portno, POWER_UNKNOWN); /* * Stop further processing for now */ goto ignore_reading; } } } else { priv->nobattery_debounce[portno] = 0; if(priv->battery[portno] != BATTERY_ON) { LINE_DBG(SIGNAL, xpd, portno, "BATTERY ON voltage=%d\n", volts); priv->battery[portno] = BATTERY_ON; dahdi_report_battery(xpd, portno); } } #if 0 /* * Mark FXO ports without battery! */ if(priv->battery[portno] != BATTERY_ON) MARK_ON(priv, portno, LED_RED); else MARK_OFF(priv, portno, LED_RED); #endif if(priv->battery[portno] != BATTERY_ON) { priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */ return; } /* * Handle reverse polarity */ if(volts == 0) pol = POL_UNKNOWN; else if(volts < 0) pol = POL_NEGATIVE; else pol = POL_POSITIVE; if(priv->polarity[portno] == pol) { /* * Same polarity, reset debounce counter */ priv->polarity_debounce[portno] = 0; return; } /* * Track polarity reversals and debounce spikes. * Only reversals with long duration count. */ msec = priv->polarity_debounce[portno]++ * poll_battery_interval; if (msec >= POLREV_THRESHOLD) { priv->polarity_debounce[portno] = 0; if(pol != POL_UNKNOWN && priv->polarity[portno] != POL_UNKNOWN) { char *polname = NULL; if(pol == POL_POSITIVE) polname = "Positive"; else if(pol == POL_NEGATIVE) polname = "Negative"; else BUG(); LINE_DBG(SIGNAL, xpd, portno, "Polarity changed to %s\n", polname); /* * Inform dahdi/Asterisk: * 1. Maybe used for hangup detection during offhook * 2. In some countries used to report caller-id during onhook * but before first ring. */ if(caller_id_style == CID_STYLE_ETSI_FSK) oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */ if(SPAN_REGISTERED(xpd)) { LINE_DBG(SIGNAL, xpd, portno, "Send DAHDI_EVENT_POLARITY: %s\n", polname); dahdi_qevent_lock(XPD_CHAN(xpd, portno), DAHDI_EVENT_POLARITY); } } priv->polarity[portno] = pol; } return; ignore_reading: /* * Reset debounce counters to prevent false alarms */ reset_battery_readings(xpd, portno); /* unstable during hook changes */ } static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno) { struct FXO_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); priv->battery_current[portno] = data_low; /* * During ringing, current is not stable. * During onhook there should not be current anyway. */ if(PHONEDEV(xpd).ringing[portno] || !IS_OFFHOOK(xpd, portno)) goto ignore_it; /* * Power denial with no battery voltage is meaningless */ if(priv->battery[portno] != BATTERY_ON) goto ignore_it; /* Safe zone after offhook */ if(priv->power_denial_safezone[portno] > 0) goto ignore_it; if(data_low < POWER_DENIAL_CURRENT) { if(priv->power[portno] == POWER_ON) { power_change(xpd, portno, POWER_OFF); priv->power_denial_length[portno] = power_denial_minlen; } } else { if(priv->power[portno] != POWER_ON) { power_change(xpd, portno, POWER_ON); priv->power_denial_length[portno] = 0; /* We are now OFFHOOK */ hookstate_changed(xpd, portno, 1); } } return; ignore_it: priv->power_denial_delay[portno] = 0; } #ifdef WITH_METERING #define BTD_BIT BIT(0) static void update_metering_state(xpd_t *xpd, byte data_low, lineno_t portno) { struct FXO_priv_data *priv; bool metering_tone = data_low & BTD_BIT; bool old_metering_tone; priv = xpd->priv; BUG_ON(!priv); old_metering_tone = IS_SET(priv->metering_tone_state, portno); LINE_DBG(SIGNAL, xpd, portno, "METERING: %s [dL=0x%X] (%d)\n", (metering_tone) ? "ON" : "OFF", data_low, priv->metering_count[portno]); if(metering_tone && !old_metering_tone) { /* Rising edge */ priv->metering_count[portno]++; BIT_SET(priv->metering_tone_state, portno); } else if(!metering_tone && old_metering_tone) BIT_CLR(priv->metering_tone_state, portno); if(metering_tone) { /* Clear the BTD bit */ data_low &= ~BTD_BIT; DAA_DIRECT_REQUEST(xpd->xbus, xpd, portno, DAA_WRITE, DAA_REG_METERING, data_low); } } #endif static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { struct FXO_priv_data *priv; lineno_t portno; priv = xpd->priv; BUG_ON(!priv); portno = info->portnum; switch(REG_FIELD(info, regnum)) { case DAA_REG_VBAT: update_battery_voltage(xpd, REG_FIELD(info, data_low), portno); break; case DAA_REG_CURRENT: update_battery_current(xpd, REG_FIELD(info, data_low), portno); break; #ifdef WITH_METERING case DAA_REG_METERING: update_metering_state(xpd, REG_FIELD(info, data_low), portno); break; #endif } LINE_DBG(REGS, xpd, portno, "%c reg_num=0x%X, dataL=0x%X dataH=0x%X\n", ((info->bytes == 3)?'I':'D'), REG_FIELD(info, regnum), REG_FIELD(info, data_low), REG_FIELD(info, data_high)); /* Update /proc info only if reply relate to the last slic read request */ if( REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { xpd->last_reply = *info; } return 0; } static int FXO_card_state(xpd_t *xpd, bool on) { int ret = 0; struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off"); return ret; } static const struct xops fxo_xops = { .card_new = FXO_card_new, .card_init = FXO_card_init, .card_remove = FXO_card_remove, .card_tick = FXO_card_tick, .card_register_reply = FXO_card_register_reply, }; static const struct phoneops fxo_phoneops = { .card_dahdi_preregistration = FXO_card_dahdi_preregistration, .card_dahdi_postregistration = FXO_card_dahdi_postregistration, .card_hooksig = FXO_card_hooksig, .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = generic_card_pcm_fromspan, .card_pcm_tospan = generic_card_pcm_tospan, .card_timing_priority = generic_timing_priority, .echocancel_timeslot = generic_echocancel_timeslot, .echocancel_setmask = generic_echocancel_setmask, .card_ioctl = FXO_card_ioctl, .card_open = FXO_card_open, .card_state = FXO_card_state, }; static xproto_table_t PROTO_TABLE(FXO) = { .owner = THIS_MODULE, .entries = { /* Prototable Card Opcode */ XENTRY( FXO, FXO, SIG_CHANGED ), }, .name = "FXO", /* protocol name */ .ports_per_subunit = 8, .type = XPD_TYPE_FXO, .xops = &fxo_xops, .phoneops = &fxo_phoneops, .packet_is_valid = fxo_packet_is_valid, .packet_dump = fxo_packet_dump, }; static bool fxo_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe; //DBG(GENERAL, "\n"); xe = xproto_card_entry(&PROTO_TABLE(FXO), XPACKET_OP(pack)); return xe != NULL; } static void fxo_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } /*------------------------- DAA Handling --------------------------*/ #ifdef CONFIG_PROC_FS static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; unsigned long flags; xpd_t *xpd = data; struct FXO_priv_data *priv; int i; if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); len += sprintf(page + len, "\t%-17s: ", "Channel"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, "%4d ", i % 10); } len += sprintf(page + len, "\nLeds:"); len += sprintf(page + len, "\n\t%-17s: ", "state"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, " %d%d ", IS_SET(priv->ledstate[LED_GREEN], i), IS_SET(priv->ledstate[LED_RED], i)); } len += sprintf(page + len, "\n\t%-17s: ", "blinking"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, " %d%d ", IS_BLINKING(priv,i,LED_GREEN), IS_BLINKING(priv,i,LED_RED)); } len += sprintf(page + len, "\nBattery-Data:"); len += sprintf(page + len, "\n\t%-17s: ", "voltage"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->battery_voltage[i]); } len += sprintf(page + len, "\n\t%-17s: ", "current"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->battery_current[i]); } len += sprintf(page + len, "\nBattery:"); len += sprintf(page + len, "\n\t%-17s: ", "on"); for_each_line(xpd, i) { char *bat; if(priv->battery[i] == BATTERY_ON) bat = "+"; else if(priv->battery[i] == BATTERY_OFF) bat = "-"; else bat = "."; len += sprintf(page + len, "%4s ", bat); } len += sprintf(page + len, "\n\t%-17s: ", "debounce"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->nobattery_debounce[i]); } len += sprintf(page + len, "\nPolarity-Reverse:"); len += sprintf(page + len, "\n\t%-17s: ", "polarity"); for_each_line(xpd, i) { char *polname; if(priv->polarity[i] == POL_POSITIVE) polname = "+"; else if(priv->polarity[i] == POL_NEGATIVE) polname = "-"; else polname = "."; len += sprintf(page + len, "%4s ", polname); } len += sprintf(page + len, "\n\t%-17s: ", "debounce"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->polarity_debounce[i]); } len += sprintf(page + len, "\nPower-Denial:"); len += sprintf(page + len, "\n\t%-17s: ", "power"); for_each_line(xpd, i) { char *curr; if(priv->power[i] == POWER_ON) curr = "+"; else if(priv->power[i] == POWER_OFF) curr = "-"; else curr = "."; len += sprintf(page + len, "%4s ", curr); } len += sprintf(page + len, "\n\t%-17s: ", "safezone"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->power_denial_safezone[i]); } len += sprintf(page + len, "\n\t%-17s: ", "delay"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->power_denial_delay[i]); } #ifdef WITH_METERING len += sprintf(page + len, "\nMetering:"); len += sprintf(page + len, "\n\t%-17s: ", "count"); for_each_line(xpd, i) { len += sprintf(page + len, "%4d ", priv->metering_count[i]); } #endif len += sprintf(page + len, "\n"); spin_unlock_irqrestore(&xpd->lock, flags); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif #ifdef WITH_METERING static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; unsigned long flags; xpd_t *xpd = data; struct FXO_priv_data *priv; int i; if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); len += sprintf(page + len, "# Chan\tMeter (since last read)\n"); for_each_line(xpd, i) { len += sprintf(page + len, "%d\t%d\n", i, priv->metering_count[i]); } spin_unlock_irqrestore(&xpd->lock, flags); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; /* Zero meters */ for_each_line(xpd, i) priv->metering_count[i] = 0; return len; } #endif static DEVICE_ATTR_READER(fxo_battery_show, dev, buf) { xpd_t *xpd; struct FXO_priv_data *priv; unsigned long flags; int len = 0; int i; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); for_each_line(xpd, i) { char bat; if(priv->battery[i] == BATTERY_ON) bat = '+'; else if(priv->battery[i] == BATTERY_OFF) bat = '-'; else bat = '.'; len += sprintf(buf + len, "%c ", bat); } len += sprintf(buf + len, "\n"); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(fxo_battery, S_IRUGO, fxo_battery_show, NULL); static int fxo_xpd_probe(struct device *dev) { xpd_t *xpd; int ret; xpd = dev_to_xpd(dev); /* Is it our device? */ if(xpd->type != XPD_TYPE_FXO) { XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev), xpd->type); return -EINVAL; } XPD_DBG(DEVICES, xpd, "SYSFS\n"); ret = device_create_file(dev, &dev_attr_fxo_battery); if(ret) { XPD_ERR(xpd, "%s: device_create_file(fxo_battery) failed: %d\n", __FUNCTION__, ret); goto fail_fxo_battery; } return 0; fail_fxo_battery: return ret; } static int fxo_xpd_remove(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, xpd, "SYSFS\n"); device_remove_file(dev, &dev_attr_fxo_battery); return 0; } static struct xpd_driver fxo_driver = { .type = XPD_TYPE_FXO, .driver = { .name = "fxo", #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE, #endif .probe = fxo_xpd_probe, .remove = fxo_xpd_remove } }; static int __init card_fxo_startup(void) { int ret; if(ring_debounce <= 0) { ERR("ring_debounce=%d. Must be positive number of ticks\n", ring_debounce); return -EINVAL; } if((ret = xpd_driver_register(&fxo_driver.driver)) < 0) return ret; INFO("revision %s\n", XPP_VERSION); #ifdef WITH_METERING INFO("FEATURE: WITH METERING Detection\n"); #else INFO("FEATURE: NO METERING Detection\n"); #endif xproto_register(&PROTO_TABLE(FXO)); return 0; } static void __exit card_fxo_cleanup(void) { xproto_unregister(&PROTO_TABLE(FXO)); xpd_driver_unregister(&fxo_driver.driver); } MODULE_DESCRIPTION("XPP FXO Card Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_FXO); module_init(card_fxo_startup); module_exit(card_fxo_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/mmapbus.h0000644000175000017500000000121411026460317021160 0ustar tzafrirtzafrir#ifndef MMAPBUS_H #define MMAPBUS_H #include struct mmap_device { char *name; struct mmap_driver *driver; struct device dev; }; #define to_mmap_device(x) container_of(x, struct mmap_device, dev) struct mmap_driver { struct module *module; struct device_driver driver; }; #define to_mmap_driver(x) container_of(x, struct mmap_driver, driver) int register_mmap_bus(void); void unregister_mmap_bus(void); int register_mmap_device(struct mmap_device *dev); void unregister_mmap_device(struct mmap_device *dev); int register_mmap_driver(struct mmap_driver *driver); void unregister_mmap_driver(struct mmap_driver *driver); #endif dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_global.h0000644000175000017500000000616511566461444021772 0ustar tzafrirtzafrir#ifndef CARD_GLOBAL_H #define CARD_GLOBAL_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xdefs.h" #include "xbus-pcm.h" enum global_opcodes { XPROTO_NAME(GLOBAL, AB_REQUEST) = 0x07, XPROTO_NAME(GLOBAL, AB_DESCRIPTION) = 0x08, XPROTO_NAME(GLOBAL, REGISTER_REQUEST) = 0x0F, XPROTO_NAME(GLOBAL, REGISTER_REPLY) = 0x10, /**/ XPROTO_NAME(GLOBAL, PCM_WRITE) = 0x11, XPROTO_NAME(GLOBAL, PCM_READ) = 0x12, /**/ XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19, XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A, /**/ XPROTO_NAME(GLOBAL, ERROR_CODE) = 0x22, XPROTO_NAME(GLOBAL, RESET_SYNC_COUNTERS) = 0x23, XPROTO_NAME(GLOBAL, NULL_REPLY) = 0xFE, }; struct unit_descriptor { struct xpd_addr addr; byte subtype:4; byte type:4; byte numchips; byte ports_per_chip; byte port_dir; /* bitmask: 0 - PSTN, 1 - PHONE */ byte reserved[2]; struct xpd_addr ec_addr; }; #define NUM_UNITS 6 DEF_RPACKET_DATA(GLOBAL, NULL_REPLY); DEF_RPACKET_DATA(GLOBAL, AB_REQUEST, byte rev; byte reserved; ); DEF_RPACKET_DATA(GLOBAL, AB_DESCRIPTION, byte rev; byte reserved[3]; struct unit_descriptor unit_descriptor[NUM_UNITS]; ); DEF_RPACKET_DATA(GLOBAL, REGISTER_REQUEST, reg_cmd_t reg_cmd; ); DEF_RPACKET_DATA(GLOBAL, PCM_WRITE, xpp_line_t lines; byte pcm[PCM_CHUNKSIZE]; ); DEF_RPACKET_DATA(GLOBAL, PCM_READ, xpp_line_t lines; byte pcm[PCM_CHUNKSIZE]; ); DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE, byte sync_mode; byte drift; ); DEF_RPACKET_DATA(GLOBAL, SYNC_REPLY, byte sync_mode; byte drift; ); DEF_RPACKET_DATA(GLOBAL, REGISTER_REPLY, reg_cmd_t regcmd; ); DEF_RPACKET_DATA(GLOBAL, RESET_SYNC_COUNTERS, byte mask; ); DEF_RPACKET_DATA(GLOBAL, ERROR_CODE, byte category_code; byte errorbits; byte bad_packet[0]; ); /* 0x07 */ DECLARE_CMD(GLOBAL, AB_REQUEST); /* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift); /* 0x23 */ DECLARE_CMD(GLOBAL, RESET_SYNC_COUNTERS); int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno, bool writing, byte regnum, bool do_subreg, byte subreg, byte data_low, bool do_datah, byte data_high, bool should_reply); int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno, bool eoftx, byte *buf, unsigned len); extern xproto_table_t PROTO_TABLE(GLOBAL); int run_initialize_registers(xpd_t *xpd); int parse_chip_command(xpd_t *xpd, char *cmdline); extern charp initdir; #endif /* CARD_GLOBAL_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xframe_queue.h0000644000175000017500000000176211342005565022213 0ustar tzafrirtzafrir#ifndef XFRAME_QUEUE_H #define XFRAME_QUEUE_H #include #include #include "xdefs.h" #define XFRAME_QUEUE_MARGIN 10 struct xframe_queue { struct list_head head; bool disabled; unsigned int count; unsigned int max_count; unsigned int steady_state_count; spinlock_t lock; const char *name; void *priv; /* statistics */ unsigned int worst_count; unsigned int overflows; unsigned long worst_lag_usec; /* since xframe creation */ }; void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count, unsigned int max_count, const char *name, void *priv); __must_check bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe); __must_check xframe_t *xframe_dequeue(struct xframe_queue *q); void xframe_queue_clearstats(struct xframe_queue *q); void xframe_queue_disable(struct xframe_queue *q, bool disabled); void xframe_queue_clear(struct xframe_queue *q); uint xframe_queue_count(struct xframe_queue *q); #endif /* XFRAME_QUEUE_ */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp.conf0000644000175000017500000000210311260427774021031 0ustar tzafrirtzafrir# /etc/dahdi/xpp.conf # # This file is used to configure the operation # of init_card_* initialization scripts. # # pri_protocol: is an XPP PRI device E1 (default) or T1? #pri_protocol E1 # # Alternatively you can set this on a port by port basis if you have a strange # setup where some of the ports are E1 and some are T1. These specific # settings will override the default set above. #pri_protocol/xbus-00/xpd-02 T1 #pri_protocol/connector:usb-0000:00:1d.7-7/xpd-03 T1 #pri_protocol/label:usb:0000183/xpd-03 T1 # International settings for the XPP FXO module. This is similar to the # 'opermode' kernel module of wctdm and wctdm24xxp . The default value # is 'FCC' (US settings). # # The valid settings can be shown by running the init_card_2_30 script with # the '-L' option. For example: # /usr/share/dahdi/init_card_2_30 -L # #opermode UK # Set this to enable debug mode for the scripts: #debug 1 # # Skip the long calibration of the FXS modules. This saves time, but # makes the units consume much more power and hence highly unreocmmended # and unsupported. #fxs_skip_calib 1 dahdi-linux-2.5.0.1/drivers/dahdi/xpp/Makefile0000644000175000017500000000025510751714440021012 0ustar tzafrirtzafrir# We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. -include $(src)/Kbuild ctags: ctags *.[ch] dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpp_debug0000755000175000017500000000352711602416004021251 0ustar tzafrirtzafrir#! /bin/sh # # xpp_debug: Turn on/off debugging flags via /sys/module/*/parameters/debug # modules="xpp xpp_usb xpd_fxs xpd_fxo xpd_bri xpd_pri xpd_echo" dbg_names="DEFAULT PCM LEDS SYNC SIGNAL PROC REGS DEVICES COMMANDS" usage() { echo 1>&2 "Usage: $0 [module_name] [[-]flags...]" echo 1>&2 " module_name => $modules" echo 1>&2 " flags => NONE $dbg_names ANY" echo 1>&2 "" echo 1>&2 " Example: $0 xpp ANY -PCM -LEDS" echo 1>&2 "" } sysfs_name() { f='' if [ -f "/sys/module/$1/parameters/debug" ]; then f="/sys/module/$1/parameters/debug" elif [ -f "/sys/module/$1/debug" ]; then f="/sys/module/$1/debug" fi echo "$f" } sysfs_value() { f=`sysfs_name "$1"` if [ "$f" != "" ]; then cat "$f" fi } show_debug() { usage for i in $modules do f=`sysfs_name "$i"` if [ -f "$f" ]; then val=`cat $f` j=0 list='' for n in $dbg_names do if (( val & (1 << j) )) then list="$list $n" fi let j++ done if [ "$list" = "" ]; then list=' NONE' fi echo "$i $list" fi done } calc_debug() { val="$1" shift for wanted in $* do j=0 found=0 for n in $dbg_names do if [ "$wanted" = "$n" ]; then (( val |= (1 << j) )) found=1 elif [ "$wanted" = -"$n" ]; then (( val &= ~(1 << j) )) found=1 elif [ "$wanted" = "ANY" ]; then (( val = ~0 )) found=1 elif [ "$wanted" = -"ANY" -o "$wanted" = "NONE" ]; then (( val = 0 )) found=1 fi let j++ done if [ "$found" -eq 0 ]; then echo >&2 "$0: Unknown debug flag '$wanted'" exit 1 fi done echo $val } if [ "$#" = 0 ]; then show_debug exit 0 fi module="$1" shift if ! echo "$modules" | grep -w "$module" > /dev/null; then echo >&2 "$0: Unknown module $module" exit 1 fi oldval=`sysfs_value "$module"` val=`calc_debug "$oldval" $*` file=`sysfs_name $module` echo "$val" > "$file" show_debug dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_bri.c0000644000175000017500000014171011604344237021266 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * Parts derived from Cologne demo driver for the chip. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "xpd.h" #include "xproto.h" #include "xpp_dahdi.h" #include "card_bri.h" #include "dahdi_debug.h" #include "xbus-core.h" static const char rcsid[] = "$Id: card_bri.c 10021 2011-07-04 14:05:19Z tzafrir $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); static DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection"); enum xhfc_states { ST_RESET = 0, /* G/F0 */ /* TE */ ST_TE_SENSING = 2, /* F2 */ ST_TE_DEACTIVATED = 3, /* F3 */ ST_TE_SIGWAIT = 4, /* F4 */ ST_TE_IDENT = 5, /* F5 */ ST_TE_SYNCED = 6, /* F6 */ ST_TE_ACTIVATED = 7, /* F7 */ ST_TE_LOST_FRAMING = 8, /* F8 */ /* NT */ ST_NT_DEACTIVATED = 1, /* G1 */ ST_NT_ACTIVATING = 2, /* G2 */ ST_NT_ACTIVATED = 3, /* G3 */ ST_NT_DEACTIVTING = 4, /* G4 */ }; #ifdef CONFIG_PROC_FS static const char *xhfc_state_name(bool is_nt, enum xhfc_states state) { const char *p; #define _E(x) [ST_ ## x] = #x static const char *te_names[] = { _E(RESET), _E(TE_SENSING), _E(TE_DEACTIVATED), _E(TE_SIGWAIT), _E(TE_IDENT), _E(TE_SYNCED), _E(TE_ACTIVATED), _E(TE_LOST_FRAMING), }; static const char *nt_names[] = { _E(RESET), _E(NT_DEACTIVATED), _E(NT_ACTIVATING), _E(NT_ACTIVATED), _E(NT_DEACTIVTING), }; #undef _E if(is_nt) { if (state > ST_NT_DEACTIVTING) p = "NT ???"; else p = nt_names[state]; } else { if (state > ST_TE_LOST_FRAMING) p = "TE ???"; else p = te_names[state]; } return p; } #endif /* xhfc Layer1 physical commands */ #define HFC_L1_ACTIVATE_TE 0x01 #define HFC_L1_FORCE_DEACTIVATE_TE 0x02 #define HFC_L1_ACTIVATE_NT 0x03 #define HFC_L1_DEACTIVATE_NT 0x04 #define HFC_L1_ACTIVATING 1 #define HFC_L1_ACTIVATED 2 #define HFC_TIMER_T1 2500 #define HFC_TIMER_T3 8000 /* 8s activation timer T3 */ #define HFC_TIMER_OFF -1 /* timer disabled */ #define A_SU_WR_STA 0x30 /* ST/Up state machine register */ #define V_SU_LD_STA 0x10 #define V_SU_ACT 0x60 /* start activation/deactivation */ #define STA_DEACTIVATE 0x40 /* start deactivation in A_SU_WR_STA */ #define STA_ACTIVATE 0x60 /* start activation in A_SU_WR_STA */ #define V_SU_SET_G2_G3 0x80 #define A_SU_RD_STA 0x30 typedef union { struct { byte v_su_sta:4; byte v_su_fr_sync:1; byte v_su_t2_exp:1; byte v_su_info0:1; byte v_g2_g3:1; } bits; byte reg; } su_rd_sta_t; #define REG30_LOST 3 /* in polls */ #define DCHAN_LOST 15000 /* in ticks */ #ifdef CONFIG_DAHDI_BRI_DCHANS #define BRI_DCHAN_SIGCAP ( \ DAHDI_SIG_EM | \ DAHDI_SIG_CLEAR | \ DAHDI_SIG_FXSLS | \ DAHDI_SIG_FXSGS | \ DAHDI_SIG_FXSKS | \ DAHDI_SIG_FXOLS | \ DAHDI_SIG_FXOGS | \ DAHDI_SIG_FXOKS | \ DAHDI_SIG_CAS | \ DAHDI_SIG_SF \ ) #else #define BRI_DCHAN_SIGCAP DAHDI_SIG_HARDHDLC #endif #define BRI_BCHAN_SIGCAP (DAHDI_SIG_CLEAR | DAHDI_SIG_DACS) #define IS_NT(xpd) (PHONEDEV(xpd).direction == TO_PHONE) #define BRI_PORT(xpd) ((xpd)->addr.subunit) /* shift in PCM highway */ #define SUBUNIT_PCM_SHIFT 4 #define PCM_SHIFT(mask, sunit) ((mask) << (SUBUNIT_PCM_SHIFT * (sunit))) /*---------------- BRI Protocol Commands ----------------------------------*/ static int write_state_register(xpd_t *xpd, byte value); static bool bri_packet_is_valid(xpacket_t *pack); static void bri_packet_dump(const char *msg, xpacket_t *pack); #ifdef CONFIG_PROC_FS static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); #endif static int bri_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc); static int bri_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype); static int bri_startup(struct file *file, struct dahdi_span *span); static int bri_shutdown(struct dahdi_span *span); #define PROC_REGISTER_FNAME "slics" #define PROC_BRI_INFO_FNAME "bri_info" enum led_state { BRI_LED_OFF = 0x0, BRI_LED_ON = 0x1, /* * We blink by software from driver, so that * if the driver malfunction that blink would stop. */ // BRI_LED_BLINK_SLOW = 0x2, /* 1/2 a second blink cycle */ // BRI_LED_BLINK_FAST = 0x3 /* 1/4 a second blink cycle */ }; enum bri_led_names { GREEN_LED = 0, RED_LED = 1 }; #define NUM_LEDS 2 #define LED_TICKS 100 struct bri_leds { byte state:2; byte led_sel:1; /* 0 - GREEN, 1 - RED */ byte reserved:5; }; #ifndef MAX_DFRAME_LEN_L1 #define MAX_DFRAME_LEN_L1 300 #endif #define DCHAN_BUFSIZE MAX_DFRAME_LEN_L1 struct BRI_priv_data { struct proc_dir_entry *bri_info; su_rd_sta_t state_register; bool initialized; int t1; /* timer 1 for NT deactivation */ int t3; /* timer 3 for TE activation */ ulong l1_flags; bool reg30_good; uint reg30_ticks; bool layer1_up; /* * D-Chan: buffers + extra state info. */ #ifdef CONFIG_DAHDI_BRI_DCHANS int dchan_r_idx; byte dchan_rbuf[DCHAN_BUFSIZE]; #else atomic_t hdlc_pending; #endif byte dchan_tbuf[DCHAN_BUFSIZE]; bool txframe_begin; uint tick_counter; uint poll_counter; uint dchan_tx_counter; uint dchan_rx_counter; uint dchan_rx_drops; bool dchan_alive; uint dchan_alive_ticks; uint dchan_notx_ticks; uint dchan_norx_ticks; enum led_state ledstate[NUM_LEDS]; }; static xproto_table_t PROTO_TABLE(BRI); DEF_RPACKET_DATA(BRI, SET_LED, /* Set one of the LED's */ struct bri_leds bri_leds; ); static /* 0x33 */ DECLARE_CMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state); #define DO_LED(xpd, which, tostate) \ CALL_PROTO(BRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate)) #define DEBUG_BUF_SIZE (100) static void dump_hex_buf(xpd_t *xpd, char *msg, byte *buf, size_t len) { char debug_buf[DEBUG_BUF_SIZE + 1]; int i; int n = 0; debug_buf[0] = '\0'; for(i = 0; i < len && n < DEBUG_BUF_SIZE; i++) n += snprintf(&debug_buf[n], DEBUG_BUF_SIZE - n, "%02X ", buf[i]); XPD_NOTICE(xpd, "%s[0..%zd]: %s%s\n", msg, len-1, debug_buf, (n >= DEBUG_BUF_SIZE)?"...":""); } static void dump_dchan_packet(xpd_t *xpd, bool transmit, byte *buf, int len) { struct BRI_priv_data *priv; char msgbuf[MAX_PROC_WRITE]; char ftype = '?'; char *direction; int frame_begin; priv = xpd->priv; BUG_ON(!priv); if(transmit) { direction = "TX"; frame_begin = priv->txframe_begin; } else { direction = "RX"; frame_begin = 1; } if(frame_begin) { /* Packet start */ if(!IS_SET(buf[0], 7)) ftype = 'I'; /* Information */ else if(IS_SET(buf[0], 7) && !IS_SET(buf[0], 6)) ftype = 'S'; /* Supervisory */ else if(IS_SET(buf[0], 7) && IS_SET(buf[0], 6)) ftype = 'U'; /* Unnumbered */ else XPD_NOTICE(xpd, "Unknown frame type 0x%X\n", buf[0]); snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = (%c) ", direction, ftype); } else { snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = ", direction); } dump_hex_buf(xpd, msgbuf, buf, len); } static void set_bri_timer(xpd_t *xpd, const char *name, int *bri_timer, int value) { if(value == HFC_TIMER_OFF) XPD_DBG(SIGNAL, xpd, "Timer %s DISABLE\n", name); else XPD_DBG(SIGNAL, xpd, "Timer %s: set to %d\n", name, value); *bri_timer = value; } static void dchan_state(xpd_t *xpd, bool up) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(priv->dchan_alive == up) return; if(up) { XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel RUNNING\n"); priv->dchan_alive = 1; } else { XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); priv->dchan_rx_counter = priv->dchan_tx_counter = priv->dchan_rx_drops = 0; priv->dchan_alive = 0; priv->dchan_alive_ticks = 0; } } static void layer1_state(xpd_t *xpd, bool up) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(priv->layer1_up == up) return; priv->layer1_up = up; XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up)?"UP":"DOWN"); if(!up) dchan_state(xpd, 0); } static void te_activation(xpd_t *xpd, bool on) { struct BRI_priv_data *priv; byte curr_state; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); curr_state = priv->state_register.bits.v_su_sta; XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF"); if(on) { if(curr_state == ST_TE_DEACTIVATED) { XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n"); set_bit(HFC_L1_ACTIVATING, &priv->l1_flags); write_state_register(xpd, STA_ACTIVATE); set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_T3); } else { XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE (state %d, ignored)\n", curr_state); } } else { /* happen only because of T3 expiry */ switch (curr_state) { case ST_TE_DEACTIVATED: /* F3 */ case ST_TE_SYNCED: /* F6 */ case ST_TE_ACTIVATED: /* F7 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE (state %d, ignored)\n", curr_state); break; case ST_TE_SIGWAIT: /* F4 */ case ST_TE_IDENT: /* F5 */ case ST_TE_LOST_FRAMING: /* F8 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE\n"); write_state_register(xpd, STA_DEACTIVATE); break; default: XPD_NOTICE(xpd, "Bad TE state: %d\n", curr_state); break; } } } static void nt_activation(xpd_t *xpd, bool on) { struct BRI_priv_data *priv; byte curr_state; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); curr_state = priv->state_register.bits.v_su_sta; XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF"); if(on) { switch(curr_state) { case ST_RESET: /* F/G 0 */ case ST_NT_DEACTIVATED: /* G1 */ case ST_NT_DEACTIVTING: /* G4 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT\n"); set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_T1); set_bit(HFC_L1_ACTIVATING, &priv->l1_flags); write_state_register(xpd, STA_ACTIVATE); break; case ST_NT_ACTIVATING: /* G2 */ case ST_NT_ACTIVATED: /* G3 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT (in state %d, ignored)\n", curr_state); break; } } else { switch(curr_state) { case ST_RESET: /* F/G 0 */ case ST_NT_DEACTIVATED: /* G1 */ case ST_NT_DEACTIVTING: /* G4 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_DEACTIVATE_NT (in state %d, ignored)\n", curr_state); break; case ST_NT_ACTIVATING: /* G2 */ case ST_NT_ACTIVATED: /* G3 */ XPD_DBG(SIGNAL, xpd, "HFC_L1_DEACTIVATE_NT\n"); write_state_register(xpd, STA_DEACTIVATE); break; default: XPD_NOTICE(xpd, "Bad NT state: %d\n", curr_state); break; } } } /* * D-Chan receive */ static void bri_hdlc_abort(xpd_t *xpd, struct dahdi_chan *dchan, int event) { struct BRI_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); #ifdef CONFIG_DAHDI_BRI_DCHANS if(debug & DBG_COMMANDS) dump_hex_buf(xpd, "D-Chan(abort) RX: dchan_rbuf", priv->dchan_rbuf, priv->dchan_r_idx); priv->dchan_r_idx = 0; #else dahdi_hdlc_abort(dchan, event); #endif } static int bri_check_stat(xpd_t *xpd, struct dahdi_chan *dchan, byte *buf, int len) { struct BRI_priv_data *priv; byte status; priv = xpd->priv; BUG_ON(!priv); #ifdef CONFIG_DAHDI_BRI_DCHANS if(priv->dchan_r_idx < 4) { XPD_NOTICE(xpd, "D-Chan RX short frame (dchan_r_idx=%d)\n", priv->dchan_r_idx); dump_hex_buf(xpd, "D-Chan RX: current packet", buf, len); bri_hdlc_abort(xpd, dchan, DAHDI_EVENT_ABORT); return -EPROTO; } #else if(len <= 0) { XPD_NOTICE(xpd, "D-Chan RX DROP: short frame (len=%d)\n", len); bri_hdlc_abort(xpd, dchan, DAHDI_EVENT_ABORT); return -EPROTO; } #endif status = buf[len-1]; if(status) { int event = DAHDI_EVENT_ABORT; if(status == 0xFF) { XPD_NOTICE(xpd, "D-Chan RX DROP: ABORT: %d\n", status); } else { XPD_NOTICE(xpd, "D-Chan RX DROP: BADFCS: %d\n", status); event = DAHDI_EVENT_BADFCS; } dump_hex_buf(xpd, "D-Chan RX: current packet", buf, len); bri_hdlc_abort(xpd, dchan, event); return -EPROTO; } return 0; } static int bri_hdlc_putbuf(xpd_t *xpd, struct dahdi_chan *dchan, unsigned char *buf, int len) { #ifdef CONFIG_DAHDI_BRI_DCHANS struct BRI_priv_data *priv; byte *dchan_buf; byte *dst; int idx; priv = xpd->priv; BUG_ON(!priv); dchan_buf = dchan->readchunk; idx = priv->dchan_r_idx; if(idx + len >= DCHAN_BUFSIZE) { XPD_ERR(xpd, "D-Chan RX overflow: %d\n", idx); dump_hex_buf(xpd, " current packet", buf, len); dump_hex_buf(xpd, " dchan_buf", dchan_buf, idx); return -ENOSPC; } dst = dchan_buf + idx; idx += len; priv->dchan_r_idx = idx; memcpy(dst, buf, len); #else dahdi_hdlc_putbuf(dchan, buf, len); #endif return 0; } static void bri_hdlc_finish(xpd_t *xpd, struct dahdi_chan *dchan) { struct BRI_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); #ifdef CONFIG_DAHDI_BRI_DCHANS dchan->bytes2receive = priv->dchan_r_idx - 1; dchan->eofrx = 1; #else dahdi_hdlc_finish(dchan); #endif } #ifdef CONFIG_DAHDI_BRI_DCHANS static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd) { struct BRI_priv_data *priv; byte *src; byte *dst; byte *dchan_buf; struct dahdi_chan *dchan; uint len; bool eoframe; int idx; int ret = 0; src = REG_XDATA(regcmd); len = regcmd->bytes; eoframe = regcmd->eoframe; if(len <= 0) return 0; if(!SPAN_REGISTERED(xpd)) /* Nowhere to copy data */ return 0; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); xbus = xpd->xbus; dchan = XPD_CHAN(xpd, 2); if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */ static int rate_limit; if((rate_limit++ % 1000) == 0) XPD_DBG(SIGNAL, xpd, "D-Chan unused\n"); dchan->bytes2receive = 0; dchan->bytes2transmit = 0; goto out; } dchan_buf = dchan->readchunk; idx = priv->dchan_r_idx; if(idx + len >= DCHAN_BUFSIZE) { XPD_ERR(xpd, "D-Chan RX overflow: %d\n", idx); dump_hex_buf(xpd, " current packet", src, len); dump_hex_buf(xpd, " dchan_buf", dchan_buf, idx); ret = -ENOSPC; if(eoframe) goto drop; goto out; } dst = dchan_buf + idx; idx += len; priv->dchan_r_idx = idx; memcpy(dst, src, len); if(!eoframe) goto out; if(idx < 4) { XPD_NOTICE(xpd, "D-Chan RX short frame (idx=%d)\n", idx); dump_hex_buf(xpd, "D-Chan RX: current packet", src, len); dump_hex_buf(xpd, "D-Chan RX: chan_buf", dchan_buf, idx); ret = -EPROTO; goto drop; } if((ret = bri_check_stat(xpd, dchan, dchan_buf, idx)) < 0) goto drop; if(debug) dump_dchan_packet(xpd, 0, dchan_buf, idx /* - 3 */); /* Print checksum? */ /* * Tell Dahdi that we received idx-1 bytes. They include the data and a 2-byte checksum. * The last byte (that we don't pass on) is 0 if the checksum is correct. If it were wrong, * we would drop the packet in the "if(dchan_buf[idx-1])" above. */ dchan->bytes2receive = idx - 1; dchan->eofrx = 1; priv->dchan_rx_counter++; priv->dchan_norx_ticks = 0; drop: priv->dchan_r_idx = 0; out: return ret; } #else static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd) { struct BRI_priv_data *priv; byte *src; struct dahdi_chan *dchan; uint len; bool eoframe; int ret = 0; src = REG_XDATA(regcmd); len = regcmd->bytes; eoframe = regcmd->eoframe; if(len <= 0) return 0; if(!SPAN_REGISTERED(xpd)) /* Nowhere to copy data */ return 0; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); dchan = XPD_CHAN(xpd, 2); if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */ static int rate_limit; if((rate_limit++ % 1000) == 0) XPD_DBG(SIGNAL, xpd, "D-Chan unused\n"); #ifdef CONFIG_DAHDI_BRI_DCHANS dchan->bytes2receive = 0; dchan->bytes2transmit = 0; #endif goto out; } XPD_DBG(GENERAL, xpd, "D-Chan RX: eoframe=%d len=%d\n", eoframe, len); ret = bri_hdlc_putbuf(xpd, dchan, src, (eoframe) ? len - 1 : len); if(ret < 0) goto out; if(!eoframe) goto out; if((ret = bri_check_stat(xpd, dchan, src, len)) < 0) goto out; /* * Tell Dahdi that we received len-1 bytes. They include the data and a 2-byte checksum. * The last byte (that we don't pass on) is 0 if the checksum is correct. If it were wrong, * we would drop the packet in the "if(src[len-1])" above. */ bri_hdlc_finish(xpd, dchan); priv->dchan_rx_counter++; priv->dchan_norx_ticks = 0; out: return ret; } #endif /* * D-Chan transmit */ #ifndef CONFIG_DAHDI_BRI_DCHANS /* DAHDI calls this when it has data it wants to send to the HDLC controller */ static void bri_hdlc_hard_xmit(struct dahdi_chan *chan) { xpd_t *xpd = chan->pvt; struct dahdi_chan *dchan; struct BRI_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); dchan = XPD_CHAN(xpd, 2); if (dchan == chan) { atomic_inc(&priv->hdlc_pending); } } #endif static int bri_hdlc_getbuf(struct dahdi_chan *dchan, unsigned char *buf, unsigned int *size) { int len = *size; int eoframe; #ifdef CONFIG_DAHDI_BRI_DCHANS len = dchan->bytes2transmit; /* dchan's hdlc package len */ if(len > *size) len = *size; /* Silent truncation */ eoframe = dchan->eoftx; /* dchan's end of frame */ dchan->bytes2transmit = 0; dchan->eoftx = 0; dchan->bytes2receive = 0; dchan->eofrx = 0; #else eoframe = dahdi_hdlc_getbuf(dchan, buf, &len); #endif *size = len; return eoframe; } static int tx_dchan(xpd_t *xpd) { struct BRI_priv_data *priv; struct dahdi_chan *dchan; int len; int eoframe; int ret; priv = xpd->priv; BUG_ON(!priv); #ifndef CONFIG_DAHDI_BRI_DCHANS if(atomic_read(&priv->hdlc_pending) == 0) return 0; #endif if(!SPAN_REGISTERED(xpd) || !(PHONEDEV(xpd).span.flags & DAHDI_FLAG_RUNNING)) return 0; dchan = XPD_CHAN(xpd, 2); len = ARRAY_SIZE(priv->dchan_tbuf); if(len > MULTIBYTE_MAX_LEN) len = MULTIBYTE_MAX_LEN; eoframe = bri_hdlc_getbuf(dchan, priv->dchan_tbuf, &len); if(len <= 0) return 0; /* Nothing to transmit on D channel */ if(len > MULTIBYTE_MAX_LEN) { XPD_ERR(xpd, "%s: len=%d. need to split. Unimplemented.\n", __FUNCTION__, len); dump_hex_buf(xpd, "D-Chan TX:", priv->dchan_tbuf, len); return -EINVAL; } if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) { XPD_DBG(SIGNAL, xpd, "Want to transmit: Kick D-Channel transmiter\n"); if(! IS_NT(xpd)) te_activation(xpd, 1); else nt_activation(xpd, 1); } if(debug) dump_dchan_packet(xpd, 1, priv->dchan_tbuf, len); if(eoframe) priv->txframe_begin = 1; else priv->txframe_begin = 0; XPD_DBG(COMMANDS, xpd, "eoframe=%d len=%d\n", eoframe, len); ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, xpd->addr.subunit, eoframe, priv->dchan_tbuf, len); if(ret < 0) XPD_NOTICE(xpd, "%s: failed sending xframe\n", __FUNCTION__); if(eoframe) { #ifndef CONFIG_DAHDI_BRI_DCHANS atomic_dec(&priv->hdlc_pending); #endif priv->dchan_tx_counter++; } priv->dchan_notx_ticks = 0; return ret; } /*---------------- BRI: Methods -------------------------------------------*/ static void bri_proc_remove(xbus_t *xbus, xpd_t *xpd) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; XPD_DBG(PROC, xpd, "\n"); #ifdef CONFIG_PROC_FS if(priv->bri_info) { XPD_DBG(PROC, xpd, "Removing '%s'\n", PROC_BRI_INFO_FNAME); remove_proc_entry(PROC_BRI_INFO_FNAME, xpd->proc_xpd_dir); } #endif } static int bri_proc_create(xbus_t *xbus, xpd_t *xpd) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; XPD_DBG(PROC, xpd, "\n"); #ifdef CONFIG_PROC_FS XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME); priv->bri_info = create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_bri_info_read, xpd); if(!priv->bri_info) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_BRI_INFO_FNAME); bri_proc_remove(xbus, xpd); return -EINVAL; } SET_PROC_DIRENTRY_OWNER(priv->bri_info); #endif return 0; } static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone) { xpd_t *xpd = NULL; int channels = min(3, CHANNELS_PERXPD); if(subunit_ports != 1) { XBUS_ERR(xbus, "Bad subunit_ports=%d\n", subunit_ports); return NULL; } XBUS_DBG(GENERAL, xbus, "\n"); xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct BRI_priv_data), proto_table, channels); if(!xpd) return NULL; PHONEDEV(xpd).direction = (to_phone) ? TO_PHONE : TO_PSTN; xpd->type_name = (to_phone) ? "BRI_NT" : "BRI_TE"; if(bri_proc_create(xbus, xpd) < 0) goto err; return xpd; err: xpd_free(xpd); return NULL; } static int BRI_card_init(xbus_t *xbus, xpd_t *xpd) { struct BRI_priv_data *priv; BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); priv = xpd->priv; DO_LED(xpd, GREEN_LED, BRI_LED_OFF); DO_LED(xpd, RED_LED, BRI_LED_OFF); set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); write_state_register(xpd, 0); /* Enable L1 state machine */ priv->initialized = 1; return 0; } static int BRI_card_remove(xbus_t *xbus, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); bri_proc_remove(xbus, xpd); return 0; } static const struct dahdi_span_ops BRI_span_ops = { .owner = THIS_MODULE, .spanconfig = bri_spanconfig, .chanconfig = bri_chanconfig, .startup = bri_startup, .shutdown = bri_shutdown, #ifndef CONFIG_DAHDI_BRI_DCHANS .hdlc_hard_xmit = bri_hdlc_hard_xmit, #endif .open = xpp_open, .close = xpp_close, .hooksig = xpp_hooksig, /* Only with RBS bits */ .ioctl = xpp_ioctl, .maint = xpp_maint, .echocan_create = xpp_echocan_create, .echocan_name = xpp_echocan_name, #ifdef DAHDI_SYNC_TICK .sync_tick = dahdi_sync_tick, #endif #ifdef CONFIG_DAHDI_WATCHDOG .watchdog = xpp_watchdog, #endif }; static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct BRI_priv_data *priv; int i; BUG_ON(!xpd); xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!xbus); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); if(!on) { /* Nothing to do yet */ return 0; } PHONEDEV(xpd).span.spantype = "BRI"; PHONEDEV(xpd).span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS; PHONEDEV(xpd).span.deflaw = DAHDI_LAW_ALAW; BIT_SET(PHONEDEV(xpd).digital_signalling, 2); /* D-Channel */ for_each_line(xpd, i) { struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d", xpd->type_name, xbus->num, xpd->addr.unit, xpd->addr.subunit, i); cur_chan->chanpos = i + 1; cur_chan->pvt = xpd; if(i == 2) { /* D-CHAN */ cur_chan->sigcap = BRI_DCHAN_SIGCAP; clear_bit(DAHDI_FLAGBIT_HDLC, &cur_chan->flags); priv->txframe_begin = 1; #ifdef CONFIG_DAHDI_BRI_DCHANS priv->dchan_r_idx = 0; set_bit(DAHDI_FLAGBIT_BRIDCHAN, &cur_chan->flags); /* Setup big buffers for D-Channel rx/tx */ cur_chan->readchunk = priv->dchan_rbuf; cur_chan->writechunk = priv->dchan_tbuf; cur_chan->maxbytes2transmit = MULTIBYTE_MAX_LEN; cur_chan->bytes2transmit = 0; cur_chan->bytes2receive = 0; #else atomic_set(&priv->hdlc_pending, 0); #endif } else { cur_chan->sigcap = BRI_BCHAN_SIGCAP; } } CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); PHONEDEV(xpd).span.ops = &BRI_span_ops; return 0; } static int BRI_card_dahdi_postregistration(xpd_t *xpd, bool on) { xbus_t *xbus; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); return(0); } static int BRI_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig) { LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig)); return 0; } /* * LED managment is done by the driver now: * - Turn constant ON RED/GREEN led to indicate NT/TE port * - Very fast "Double Blink" to indicate Layer1 alive (without D-Channel) * - Constant blink (1/2 sec cycle) to indicate D-Channel alive. */ static void handle_leds(xbus_t *xbus, xpd_t *xpd) { struct BRI_priv_data *priv; unsigned int timer_count; int which_led; int other_led; int mod; BUG_ON(!xpd); if(IS_NT(xpd)) { which_led = RED_LED; other_led = GREEN_LED; } else { which_led = GREEN_LED; other_led = RED_LED; } priv = xpd->priv; BUG_ON(!priv); timer_count = xpd->timer_count; if(xpd->blink_mode) { if((timer_count % DEFAULT_LED_PERIOD) == 0) { // led state is toggled if(priv->ledstate[which_led] == BRI_LED_OFF) { DO_LED(xpd, which_led, BRI_LED_ON); DO_LED(xpd, other_led, BRI_LED_ON); } else { DO_LED(xpd, which_led, BRI_LED_OFF); DO_LED(xpd, other_led, BRI_LED_OFF); } } return; } if(priv->ledstate[other_led] != BRI_LED_OFF) DO_LED(xpd, other_led, BRI_LED_OFF); if(priv->dchan_alive) { mod = timer_count % 1000; switch(mod) { case 0: DO_LED(xpd, which_led, BRI_LED_ON); break; case 500: DO_LED(xpd, which_led, BRI_LED_OFF); break; } } else if(priv->layer1_up) { mod = timer_count % 1000; switch(mod) { case 0: case 100: DO_LED(xpd, which_led, BRI_LED_ON); break; case 50: case 150: DO_LED(xpd, which_led, BRI_LED_OFF); break; } } else { if(priv->ledstate[which_led] != BRI_LED_ON) DO_LED(xpd, which_led, BRI_LED_ON); } } static void handle_bri_timers(xpd_t *xpd) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(IS_NT(xpd)) { if (priv->t1 > HFC_TIMER_OFF) { if (--priv->t1 == 0) { set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); if(!nt_keepalive) { if(priv->state_register.bits.v_su_sta == ST_NT_ACTIVATING) { /* G2 */ XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n"); clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); nt_activation(xpd, 0); /* Deactivate NT */ } else XPD_DBG(SIGNAL, xpd, "T1 Expired. (state %d, ignored)\n", priv->state_register.bits.v_su_sta); } } } } else { if (priv->t3 > HFC_TIMER_OFF) { /* timer expired ? */ if (--priv->t3 == 0) { XPD_DBG(SIGNAL, xpd, "T3 expired. Deactivate TE\n"); set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF); clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); te_activation(xpd, 0); /* Deactivate TE */ } } } } /* Poll the register ST/Up-State-machine Register, to see if the cable * if a cable is connected to the port. */ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!priv->initialized || !xbus->self_ticking) return 0; if(poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) { // XPD_DBG(GENERAL, xpd, "%d\n", priv->tick_counter); priv->poll_counter++; xpp_register_request(xbus, xpd, BRI_PORT(xpd), /* portno */ 0, /* writing */ A_SU_RD_STA, /* regnum */ 0, /* do_subreg */ 0, /* subreg */ 0, /* data_low */ 0, /* do_datah */ 0, /* data_high */ 0 /* should_reply */ ); if(IS_NT(xpd) && nt_keepalive && !test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) { XPD_DBG(SIGNAL, xpd, "Kick NT D-Channel\n"); nt_activation(xpd, 1); } } /* Detect D-Channel disconnect heuristic */ priv->dchan_notx_ticks++; priv->dchan_norx_ticks++; priv->dchan_alive_ticks++; if(priv->dchan_alive && (priv->dchan_notx_ticks > DCHAN_LOST || priv->dchan_norx_ticks > DCHAN_LOST)) { /* * No tx_dchan() or rx_dchan() for many ticks * This D-Channel is probabelly dead. */ dchan_state(xpd, 0); } else if(priv->dchan_rx_counter > 1 && priv->dchan_tx_counter > 1) { if(!priv->dchan_alive) dchan_state(xpd, 1); } /* Detect Layer1 disconnect */ if(priv->reg30_good && priv->reg30_ticks > poll_interval * REG30_LOST) { /* No reply for 1/2 a second */ XPD_ERR(xpd, "Lost state tracking for %d ticks\n", priv->reg30_ticks); priv->reg30_good = 0; layer1_state(xpd, 0); } handle_leds(xbus, xpd); handle_bri_timers(xpd); tx_dchan(xpd); priv->tick_counter++; priv->reg30_ticks++; return 0; } static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) { BUG_ON(!xpd); if(!XBUS_IS(xpd->xbus, READY)) return -ENODEV; switch (cmd) { case DAHDI_TONEDETECT: /* * Asterisk call all span types with this (FXS specific) * call. Silently ignore it. */ LINE_DBG(SIGNAL, xpd, pos, "BRI: Starting a call\n"); return -ENOTTY; default: report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); return -ENOTTY; } return 0; } static int BRI_card_open(xpd_t *xpd, lineno_t pos) { BUG_ON(!xpd); if(pos == 2) { LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n"); BIT_SET(PHONEDEV(xpd).offhook_state, 0); BIT_SET(PHONEDEV(xpd).offhook_state, 1); BIT_SET(PHONEDEV(xpd).offhook_state, 2); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); } return 0; } static int BRI_card_close(xpd_t *xpd, lineno_t pos) { /* Clear D-Channel pending data */ #ifdef CONFIG_DAHDI_BRI_DCHANS struct dahdi_chan *chan = XPD_CHAN(xpd, pos); /* Clear D-Channel pending data */ chan->bytes2receive = 0; chan->eofrx = 0; chan->bytes2transmit = 0; chan->eoftx = 0; #endif if(pos == 2) { LINE_DBG(SIGNAL, xpd, pos, "ONHOOK the whole span\n"); BIT_CLR(PHONEDEV(xpd).offhook_state, 0); BIT_CLR(PHONEDEV(xpd).offhook_state, 1); BIT_CLR(PHONEDEV(xpd).offhook_state, 2); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); } return 0; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int bri_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); const char *framingstr = ""; const char *codingstr = ""; const char *crcstr = ""; /* framing first */ if (lc->lineconfig & DAHDI_CONFIG_B8ZS) framingstr = "B8ZS"; else if (lc->lineconfig & DAHDI_CONFIG_AMI) framingstr = "AMI"; else if (lc->lineconfig & DAHDI_CONFIG_HDB3) framingstr = "HDB3"; /* then coding */ if (lc->lineconfig & DAHDI_CONFIG_ESF) codingstr = "ESF"; else if (lc->lineconfig & DAHDI_CONFIG_D4) codingstr = "D4"; else if (lc->lineconfig & DAHDI_CONFIG_CCS) codingstr = "CCS"; /* E1's can enable CRC checking */ if (lc->lineconfig & DAHDI_CONFIG_CRC4) crcstr = "CRC4"; XPD_DBG(GENERAL, xpd, "[%s]: span=%d (%s) lbo=%d lineconfig=%s/%s/%s (0x%X) sync=%d\n", IS_NT(xpd)?"NT":"TE", lc->span, lc->name, lc->lbo, framingstr, codingstr, crcstr, lc->lineconfig, lc->sync); /* * FIXME: validate */ span->lineconfig = lc->lineconfig; return 0; } /* * Set signalling type (if appropriate) * Called from dahdi with spinlock held on chan. Must not call back * dahdi functions. */ static int bri_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype)); // FIXME: sanity checks: // - should be supported (within the sigcap) // - should not replace fxs <->fxo ??? (covered by previous?) return 0; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int bri_startup(struct file *file, struct dahdi_span *span) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct BRI_priv_data *priv; struct dahdi_chan *dchan; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!XBUS_IS(xpd->xbus, READY)) { XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n"); return -ENODEV; } XPD_DBG(GENERAL, xpd, "STARTUP\n"); // Turn on all channels CALL_PHONE_METHOD(card_state, xpd, 1); if(SPAN_REGISTERED(xpd)) { dchan = XPD_CHAN(xpd, 2); span->flags |= DAHDI_FLAG_RUNNING; /* * Dahdi (wrongly) assume that D-Channel need HDLC decoding * and during dahdi registration override our flags. * * Don't Get Mad, Get Even: Now we override dahdi :-) */ #ifdef CONFIG_DAHDI_BRI_DCHANS set_bit(DAHDI_FLAGBIT_BRIDCHAN, &dchan->flags); #endif clear_bit(DAHDI_FLAGBIT_HDLC, &dchan->flags); } return 0; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int bri_shutdown(struct dahdi_span *span) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!XBUS_IS(xpd->xbus, READY)) { XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n"); return -ENODEV; } XPD_DBG(GENERAL, xpd, "SHUTDOWN\n"); // Turn off all channels CALL_PHONE_METHOD(card_state, xpd, 0); return 0; } static void BRI_card_pcm_recompute(xpd_t *xpd, xpp_line_t dont_care) { int i; int line_count; xpp_line_t pcm_mask; uint pcm_len; xpd_t *main_xpd; unsigned long flags; BUG_ON(!xpd); main_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, 0); if(!main_xpd) { XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n"); return; } /* * We calculate all subunits, so use the main lock * as a mutex for the whole operation. */ spin_lock_irqsave(&PHONEDEV(main_xpd).lock_recompute_pcm, flags); line_count = 0; pcm_mask = 0; for(i = 0; i < MAX_SUBUNIT; i++) { xpd_t *sub_xpd = xpd_byaddr(xpd->xbus, main_xpd->addr.unit, i); if(sub_xpd) { xpp_line_t lines = PHONEDEV(sub_xpd).offhook_state & ~(PHONEDEV(sub_xpd).digital_signalling); if(lines) { pcm_mask |= PCM_SHIFT(lines, i); line_count += 2; } /* subunits have fake pcm_len and wanted_pcm_mask */ if(i > 0) { update_wanted_pcm_mask(sub_xpd, lines, 0); } } } /* * FIXME: Workaround a bug in sync code of the Astribank. * Send dummy PCM for sync. */ if(main_xpd->addr.unit == 0 && line_count == 0) { pcm_mask = BIT(0); line_count = 1; } /* * The main unit account for all subunits (pcm_len and wanted_pcm_mask). */ pcm_len = (line_count) ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE : 0L; update_wanted_pcm_mask(main_xpd, pcm_mask, pcm_len); spin_unlock_irqrestore(&PHONEDEV(main_xpd).lock_recompute_pcm, flags); } static void BRI_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack) { byte *pcm; unsigned long flags; int i; int subunit; xpp_line_t pcm_mask = 0; xpp_line_t wanted_lines; BUG_ON(!xpd); BUG_ON(!pack); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) { xpd_t *tmp_xpd; tmp_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, subunit); if(!tmp_xpd || !tmp_xpd->card_present) continue; spin_lock_irqsave(&tmp_xpd->lock, flags); wanted_lines = PHONEDEV(tmp_xpd).wanted_pcm_mask; for_each_line(tmp_xpd, i) { struct dahdi_chan *chan = XPD_CHAN(tmp_xpd, i); if(IS_SET(wanted_lines, i)) { if(SPAN_REGISTERED(tmp_xpd)) { #ifdef DEBUG_PCMTX int channo = chan->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); else #endif memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); } else memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } } pcm_mask |= PCM_SHIFT(wanted_lines, subunit); XPD_COUNTER(tmp_xpd, PCM_WRITE)++; spin_unlock_irqrestore(&tmp_xpd->lock, flags); } RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = pcm_mask; } static void BRI_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack) { byte *pcm; xpp_line_t pcm_mask; unsigned long flags; int subunit; int i; /* * Subunit 0 handle all other subunits */ if(xpd->addr.subunit != 0) return; if(!SPAN_REGISTERED(xpd)) return; pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); for(subunit = 0; subunit < MAX_SUBUNIT; subunit++, pcm_mask >>= SUBUNIT_PCM_SHIFT) { xpd_t *tmp_xpd; if(!pcm_mask) break; /* optimize */ tmp_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, subunit); if(!tmp_xpd || !tmp_xpd->card_present || !SPAN_REGISTERED(tmp_xpd)) continue; spin_lock_irqsave(&tmp_xpd->lock, flags); for (i = 0; i < 2; i++) { xpp_line_t tmp_mask = pcm_mask & (BIT(0) | BIT(1)); volatile u_char *r; if(IS_SET(tmp_mask, i)) { r = XPD_CHAN(tmp_xpd, i)->readchunk; // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } } XPD_COUNTER(tmp_xpd, PCM_READ)++; spin_unlock_irqrestore(&tmp_xpd->lock, flags); } } int BRI_echocancel_timeslot(xpd_t *xpd, int pos) { return xpd->addr.subunit * 4 + pos; } static int BRI_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask) { struct BRI_priv_data *priv; int i; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "0x%8X\n", ec_mask); if (!ECHOOPS(xpd->xbus)) { XPD_DBG(GENERAL, xpd, "No echo canceller in XBUS: Doing nothing.\n"); return -EINVAL; } for (i = 0; i < PHONEDEV(xpd).channels - 1; i++) { int on = BIT(i) & ec_mask; CALL_EC_METHOD(ec_set, xpd->xbus, xpd, i, on); } CALL_EC_METHOD(ec_update, xpd->xbus, xpd->xbus); return 0; } /*---------------- BRI: HOST COMMANDS -------------------------------------*/ static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state) { int ret = 0; xframe_t *xframe; xpacket_t *pack; struct bri_leds *bri_leds; struct BRI_priv_data *priv; BUG_ON(!xbus); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(LEDS, xpd, "%s -> %d\n", (which_led)?"RED":"GREEN", to_led_state); XFRAME_NEW_CMD(xframe, pack, xbus, BRI, SET_LED, xpd->xbus_idx); bri_leds = &RPACKET_FIELD(pack, BRI, SET_LED, bri_leds); bri_leds->state = to_led_state; bri_leds->led_sel = which_led; XPACKET_LEN(pack) = RPACKET_SIZE(BRI, SET_LED); ret = send_cmd_frame(xbus, xframe); priv->ledstate[which_led] = to_led_state; return ret; } static int write_state_register(xpd_t *xpd, byte value) { int ret; XPD_DBG(REGS, xpd, "value = 0x%02X\n", value); ret = xpp_register_request(xpd->xbus, xpd, BRI_PORT(xpd), /* portno */ 1, /* writing */ A_SU_WR_STA, /* regnum */ 0, /* do_subreg */ 0, /* subreg */ value, /* data_low */ 0, /* do_datah */ 0, /* data_high */ 0 /* should_reply */ ); return ret; } /*---------------- BRI: Astribank Reply Handlers --------------------------*/ static void su_new_state(xpd_t *xpd, byte reg_x30) { struct BRI_priv_data *priv; su_rd_sta_t new_state; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!priv->initialized) { XPD_ERR(xpd, "%s called on uninitialized AB\n", __FUNCTION__); return; } new_state.reg = reg_x30; if(new_state.bits.v_su_t2_exp) { XPD_NOTICE(xpd, "T2 Expired\n"); } priv->reg30_ticks = 0; priv->reg30_good = 1; if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta) return; /* same same */ XPD_DBG(SIGNAL, xpd, "%02X ---> %02X (info0=%d) (%s%i)\n", priv->state_register.reg, reg_x30, new_state.bits.v_su_info0, IS_NT(xpd)?"G":"F", new_state.bits.v_su_sta); if(!IS_NT(xpd)) { switch (new_state.bits.v_su_sta) { case ST_TE_DEACTIVATED: /* F3 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_DEACTIVATED (F3)\n"); clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags); layer1_state(xpd, 0); break; case ST_TE_SIGWAIT: /* F4 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_SIGWAIT (F4)\n"); layer1_state(xpd, 0); break; case ST_TE_IDENT: /* F5 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_IDENT (F5)\n"); layer1_state(xpd, 0); break; case ST_TE_SYNCED: /* F6 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_SYNCED (F6)\n"); layer1_state(xpd, 0); break; case ST_TE_ACTIVATED: /* F7 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_ACTIVATED (F7)\n"); set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF); clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); set_bit(HFC_L1_ACTIVATED, &priv->l1_flags); layer1_state(xpd, 1); update_xpd_status(xpd, DAHDI_ALARM_NONE); break; case ST_TE_LOST_FRAMING: /* F8 */ XPD_DBG(SIGNAL, xpd, "State ST_TE_LOST_FRAMING (F8)\n"); layer1_state(xpd, 0); break; default: XPD_NOTICE(xpd, "Bad TE state: %d\n", new_state.bits.v_su_sta); break; } } else { switch (new_state.bits.v_su_sta) { case ST_NT_DEACTIVATED: /* G1 */ XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVATED (G1)\n"); clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags); set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); layer1_state(xpd, 0); break; case ST_NT_ACTIVATING: /* G2 */ XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATING (G2)\n"); layer1_state(xpd, 0); if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) nt_activation(xpd, 1); break; case ST_NT_ACTIVATED: /* G3 */ XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATED (G3)\n"); clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); set_bit(HFC_L1_ACTIVATED, &priv->l1_flags); set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); layer1_state(xpd, 1); update_xpd_status(xpd, DAHDI_ALARM_NONE); break; case ST_NT_DEACTIVTING: /* G4 */ XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVTING (G4)\n"); set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); layer1_state(xpd, 0); break; default: XPD_NOTICE(xpd, "Bad NT state: %d\n", new_state.bits.v_su_sta); break; } } priv->state_register.reg = new_state.reg; } static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { unsigned long flags; struct BRI_priv_data *priv; struct xpd_addr addr; xpd_t *orig_xpd; int ret; /* Map UNIT + PORTNUM to XPD */ orig_xpd = xpd; addr.unit = orig_xpd->addr.unit; addr.subunit = info->portnum; xpd = xpd_byaddr(xbus, addr.unit, addr.subunit); if(!xpd) { static int rate_limit; if((rate_limit++ % 1003) < 5) notify_bad_xpd(__FUNCTION__, xbus, addr , orig_xpd->xpdname); return -EPROTO; } spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); if(REG_FIELD(info, do_subreg)) { XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n", REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low)); } else { if (REG_FIELD(info, regnum) != A_SU_RD_STA) XPD_DBG(REGS, xpd, "RD %02X %02X\n", REG_FIELD(info, regnum), REG_FIELD(info, data_low)); else XPD_DBG(REGS, xpd, "Got SU_RD_STA=%02X\n", REG_FIELD(info, data_low)); } if(info->is_multibyte) { XPD_DBG(REGS, xpd, "Got Multibyte: %d bytes, eoframe: %d\n", info->bytes, info->eoframe); ret = rx_dchan(xpd, info); if (ret < 0) { priv->dchan_rx_drops++; if(atomic_read(&PHONEDEV(xpd).open_counter) > 0) XPD_NOTICE(xpd, "Multibyte Drop: errno=%d\n", ret); } goto end; } if(REG_FIELD(info, regnum) == A_SU_RD_STA) { su_new_state(xpd, REG_FIELD(info, data_low)); } /* Update /proc info only if reply relate to the last slic read request */ if( REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { xpd->last_reply = *info; } end: spin_unlock_irqrestore(&xpd->lock, flags); return 0; } static int BRI_card_state(xpd_t *xpd, bool on) { struct BRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); if(on) { if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) { if( ! IS_NT(xpd)) te_activation(xpd, 1); else nt_activation(xpd, 1); } } else if(IS_NT(xpd)) nt_activation(xpd, 0); return 0; } static const struct xops bri_xops = { .card_new = BRI_card_new, .card_init = BRI_card_init, .card_remove = BRI_card_remove, .card_tick = BRI_card_tick, .card_register_reply = BRI_card_register_reply, }; static const struct phoneops bri_phoneops = { .card_dahdi_preregistration = BRI_card_dahdi_preregistration, .card_dahdi_postregistration = BRI_card_dahdi_postregistration, .card_hooksig = BRI_card_hooksig, .card_pcm_recompute = BRI_card_pcm_recompute, .card_pcm_fromspan = BRI_card_pcm_fromspan, .card_pcm_tospan = BRI_card_pcm_tospan, .card_timing_priority = generic_timing_priority, .echocancel_timeslot = BRI_echocancel_timeslot, .echocancel_setmask = BRI_echocancel_setmask, .card_ioctl = BRI_card_ioctl, .card_open = BRI_card_open, .card_close = BRI_card_close, .card_state = BRI_card_state, }; static xproto_table_t PROTO_TABLE(BRI) = { .owner = THIS_MODULE, .entries = { /* Table Card Opcode */ }, .name = "BRI", /* protocol name */ .ports_per_subunit = 1, .type = XPD_TYPE_BRI, .xops = &bri_xops, .phoneops = &bri_phoneops, .packet_is_valid = bri_packet_is_valid, .packet_dump = bri_packet_dump, }; static bool bri_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe = NULL; // DBG(GENERAL, "\n"); xe = xproto_card_entry(&PROTO_TABLE(BRI), XPACKET_OP(pack)); return xe != NULL; } static void bri_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } /*------------------------- REGISTER Handling --------------------------*/ #ifdef CONFIG_PROC_FS static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; unsigned long flags; xpd_t *xpd = data; struct BRI_priv_data *priv; DBG(PROC, "\n"); if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter); if(priv->reg30_good) { len += sprintf(page + len, "%-5s ", (priv->layer1_up) ? "UP" : "DOWN"); len += sprintf(page + len, "%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n", IS_NT(xpd)?'G':'F', priv->state_register.bits.v_su_sta, xhfc_state_name(IS_NT(xpd), priv->state_register.bits.v_su_sta), priv->state_register.bits.v_su_fr_sync, priv->state_register.bits.v_su_t2_exp, priv->state_register.bits.v_su_info0, priv->state_register.bits.v_g2_g3); } else len += sprintf(page + len, "Unknown\n"); if(IS_NT(xpd)) { len += sprintf(page + len, "T1 Timer: %d\n", priv->t1); } else { len += sprintf(page + len, "T3 Timer: %d\n", priv->t3); } len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter); len += sprintf(page + len, "Last Poll Reply: %d ticks ago\n", priv->reg30_ticks); len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good); len += sprintf(page + len, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ", priv->dchan_tx_counter, priv->dchan_rx_counter, priv->dchan_rx_drops); if(priv->dchan_alive) { len += sprintf(page + len, "(alive %d K-ticks)\n", priv->dchan_alive_ticks/1000); } else { len += sprintf(page + len, "(dead)\n"); } #ifndef CONFIG_DAHDI_BRI_DCHANS len += sprintf(page + len, "hdlc_pending=%d\n", atomic_read(&priv->hdlc_pending)); #endif len += sprintf(page + len, "dchan_notx_ticks: %d\n", priv->dchan_notx_ticks); len += sprintf(page + len, "dchan_norx_ticks: %d\n", priv->dchan_norx_ticks); len += sprintf(page + len, "LED: %-10s = %d\n", "GREEN", priv->ledstate[GREEN_LED]); len += sprintf(page + len, "LED: %-10s = %d\n", "RED", priv->ledstate[RED_LED]); len += sprintf(page + len, "\nDCHAN:\n"); len += sprintf(page + len, "\n"); spin_unlock_irqrestore(&xpd->lock, flags); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif static DRIVER_ATTR_READER(dchan_hardhdlc_show, drv,buf) { int len = 0; #if defined(CONFIG_DAHDI_BRI_DCHANS) len += sprintf(buf + len, "0\n"); #elif defined(DAHDI_SIG_HARDHDLC) len += sprintf(buf + len, "1\n"); #else #error Cannot build BRI without BRISTUFF or HARDHDLC supprt #endif return len; } static DRIVER_ATTR(dchan_hardhdlc,S_IRUGO,dchan_hardhdlc_show,NULL); static int bri_xpd_probe(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); /* Is it our device? */ if(xpd->type != XPD_TYPE_BRI) { XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev), xpd->type); return -EINVAL; } XPD_DBG(DEVICES, xpd, "SYSFS\n"); return 0; } static int bri_xpd_remove(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, xpd, "SYSFS\n"); return 0; } static struct xpd_driver bri_driver = { .type = XPD_TYPE_BRI, .driver = { .name = "bri", #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE, #endif .probe = bri_xpd_probe, .remove = bri_xpd_remove } }; static int __init card_bri_startup(void) { int ret; if((ret = xpd_driver_register(&bri_driver.driver)) < 0) return ret; ret = driver_create_file(&bri_driver.driver, &driver_attr_dchan_hardhdlc); if(ret < 0) return ret; INFO("revision %s\n", XPP_VERSION); #if defined(CONFIG_DAHDI_BRI_DCHANS) INFO("FEATURE: WITH BRISTUFF\n"); #elif defined(DAHDI_SIG_HARDHDLC) INFO("FEATURE: WITH HARDHDLC\n"); #else #error Cannot build BRI without BRISTUFF or HARDHDLC supprt #endif xproto_register(&PROTO_TABLE(BRI)); return 0; } static void __exit card_bri_cleanup(void) { DBG(GENERAL, "\n"); xproto_unregister(&PROTO_TABLE(BRI)); driver_remove_file(&bri_driver.driver, &driver_attr_dchan_hardhdlc); xpd_driver_unregister(&bri_driver.driver); } MODULE_DESCRIPTION("XPP BRI Card Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_BRI); module_init(card_bri_startup); module_exit(card_bri_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xdefs.h0000644000175000017500000001156011521270645020635 0ustar tzafrirtzafrir#ifndef XDEFS_H #define XDEFS_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpp_version.h" #ifdef __KERNEL__ #include #include #else /* This is to enable user-space programs to include this. */ #include typedef uint8_t __u8; typedef uint32_t __u32; #include #define DBG(fmt, ...) printf("DBG: %s: " fmt, __FUNCTION__, ## __VA_ARGS__) #define INFO(fmt, ...) printf("INFO: " fmt, ## __VA_ARGS__) #define NOTICE(fmt, ...) printf("NOTICE: " fmt, ## __VA_ARGS__) #define ERR(fmt, ...) printf("ERR: " fmt, ## __VA_ARGS__) #define __user struct list_head { struct list_head *next; struct list_head *prev; }; #endif #define PACKED __attribute__((packed)) #define ALL_LINES ((lineno_t)-1) #ifndef BIT /* added in 2.6.24 */ #define BIT(i) (1UL << (i)) #endif #define BIT_SET(x,i) ((x) |= BIT(i)) #define BIT_CLR(x,i) ((x) &= ~BIT(i)) #define IS_SET(x,i) (((x) & BIT(i)) != 0) #define BITMASK(i) (((u64)1 << (i)) - 1) #define MAX_PROC_WRITE 100 /* Largest buffer we allow writing our /proc files */ #define CHANNELS_PERXPD 32 /* Depends on xpp_line_t and protocol fields */ #define MAX_SPANNAME 20 /* From dahdi/kernel.h */ #define MAX_SPANDESC 40 /* From dahdi/kernel.h */ #define MAX_CHANNAME 40 /* From dahdi/kernel.h */ #define XPD_NAMELEN 10 /* must be <= from maximal workqueue name */ #define XPD_DESCLEN 20 #define XBUS_NAMELEN 20 /* must be <= from maximal workqueue name */ #define XBUS_DESCLEN 40 #define LABEL_SIZE 20 #define UNIT_BITS 3 /* Bit for Astribank unit number */ #define SUBUNIT_BITS 3 /* Bit for Astribank subunit number */ #define MAX_UNIT (1 << UNIT_BITS) /* 1 FXS + 3 FXS/FXO | 1 BRI + 3 FXS/FXO */ #define MAX_SUBUNIT (1 << SUBUNIT_BITS) /* 8 port BRI */ /* * Compile time sanity checks */ #if MAX_UNIT > BIT(UNIT_BITS) #error "MAX_UNIT too large" #endif #if MAX_SUBUNIT > BIT(SUBUNIT_BITS) #error "MAX_SUBUNIT too large" #endif #define MAX_XPDS (MAX_UNIT*MAX_SUBUNIT) #define VALID_XPD_NUM(x) ((x) < MAX_XPDS && (x) >= 0) #define CHAN_BITS 5 /* 0-31 for E1 */ typedef char *charp; typedef unsigned char byte; #ifdef __KERNEL__ /* Kernel versions... */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) #define KMEM_CACHE_T kmem_cache_t #else #define KMEM_CACHE_T struct kmem_cache #endif #define KZALLOC(size, gfp) my_kzalloc(size, gfp) #define KZFREE(p) do { \ memset((p), 0, sizeof(*(p))); \ kfree(p); \ } while(0); /* * Hotplug replaced with uevent in 2.6.16 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) #define OLD_HOTPLUG_SUPPORT // for older kernels #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) #define OLD_HOTPLUG_SUPPORT_269// for way older kernels #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) #define DEVICE_ATTR_READER(name,dev,buf) \ ssize_t name(struct device *dev, struct device_attribute *attr, char *buf) #define DEVICE_ATTR_WRITER(name,dev,buf, count) \ ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) #else #define DEVICE_ATTR_READER(name,dev,buf) \ ssize_t name(struct device *dev, char *buf) #define DEVICE_ATTR_WRITER(name,dev,buf, count) \ ssize_t name(struct device *dev, const char *buf, size_t count) #endif #define DRIVER_ATTR_READER(name,drv,buf) \ ssize_t name(struct device_driver *drv, char * buf) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) #define SET_PROC_DIRENTRY_OWNER(p) do { (p)->owner = THIS_MODULE; } while(0); #else #define SET_PROC_DIRENTRY_OWNER(p) do { } while(0); #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) /* Also don't define this for later RHEL >= 5.2 . hex_asc is from the * same linux-2.6-net-infrastructure-updates-to-mac80211-iwl4965.patch * as is the bool typedef. */ #if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18) || ! defined(hex_asc) typedef int bool; #endif #endif #else typedef int bool; #endif typedef struct xbus xbus_t; typedef struct xpd xpd_t; typedef struct xframe xframe_t; typedef struct xpacket xpacket_t; typedef __u32 xpp_line_t; /* at most 31 lines for E1 */ typedef byte lineno_t; typedef byte xportno_t; #define PORT_BROADCAST 255 #endif /* XDEFS_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/parport_debug.c0000644000175000017500000000605411447224745022365 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2007, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include #include "parport_debug.h" static struct parport *debug_sync_parport = NULL; static int parport_toggles[8]; /* 8 bit flip-flop */ void flip_parport_bit(unsigned char bitnum) { static unsigned char last_value; DEFINE_SPINLOCK(lock); unsigned long flags; unsigned char mask; unsigned char value; if(!debug_sync_parport) { if(printk_ratelimit()) { printk(KERN_NOTICE "%s: no debug parallel port\n", THIS_MODULE->name); } return; } BUG_ON(bitnum > 7); mask = 1 << bitnum; spin_lock_irqsave(&lock, flags); value = last_value & ~mask; if(parport_toggles[bitnum] % 2) /* square wave */ value |= mask; last_value = value; parport_toggles[bitnum]++; spin_unlock_irqrestore(&lock, flags); parport_write_data(debug_sync_parport, value); } EXPORT_SYMBOL(flip_parport_bit); static void parport_attach(struct parport *port) { printk(KERN_INFO "%s: Using %s for debugging\n", THIS_MODULE->name, port->name); if(debug_sync_parport) { printk(KERN_ERR "%s: Using %s, ignore new attachment %s\n", THIS_MODULE->name, debug_sync_parport->name, port->name); return; } parport_get_port(port); debug_sync_parport = port; } static void parport_detach(struct parport *port) { printk(KERN_INFO "%s: Releasing %s\n", THIS_MODULE->name, port->name); if(debug_sync_parport != port) { printk(KERN_ERR "%s: Using %s, ignore new detachment %s\n", THIS_MODULE->name, debug_sync_parport->name, port->name); return; } parport_put_port(debug_sync_parport); debug_sync_parport = NULL; } static struct parport_driver debug_parport_driver = { .name = "parport_debug", .attach = parport_attach, .detach = parport_detach, }; int __init parallel_dbg_init(void) { int ret; ret = parport_register_driver(&debug_parport_driver); return ret; } void __exit parallel_dbg_cleanup(void) { parport_unregister_driver(&debug_parport_driver); } MODULE_DESCRIPTION("Use parallel port to debug drivers"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION("$Id:"); module_init(parallel_dbg_init); module_exit(parallel_dbg_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/Kbuild0000644000175000017500000000613211602416004020476 0ustar tzafrirtzafrirEXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \ -DDEBUG \ -DPOLL_DIGITAL_INPUTS \ -DDEBUG_PCMTX \ -DPROTOCOL_DEBUG \ -g # WITH_BRISTUFF := $(shell grep -c '^[[:space:]]*\#[[:space:]]*define[[:space:]]\+CONFIG_DAHDI_BRI_DCHANS\>' $(src)/../../../include/dahdi/dahdi_config.h) obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPP) += xpp.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_FXS) += xpd_fxs.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_FXO) += xpd_fxo.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_PRI) += xpd_pri.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_BRI) += xpd_bri.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_ECHO) += xpd_echo.o # Build only supported modules ifneq (,$(filter y m,$(CONFIG_USB))) obj-$(DAHDI_BUILD_ALL)$(CONFIG_XPP_USB) += xpp_usb.o endif ifneq (,$(filter y m,$(CONFIG_BF537))) obj-$(DAHDI_BUILD_ALL)$(CONFIG_XPP_MMAP) += xpp_mmap.o endif xpp-objs += xbus-core.o xbus-sysfs.o xbus-pcm.o xframe_queue.o xpp_dahdi.o xproto.o card_global.o dahdi_debug.o xpd_fxs-objs += card_fxs.o xpd_fxo-objs += card_fxo.o xpd_bri-objs += card_bri.o xpd_pri-objs += card_pri.o xpd_echo-objs += card_echo.o xpp_mmap-objs += mmapbus.o mmapdrv.o ifeq (y,$(PARPORT_DEBUG)) EXTRA_CFLAGS += -DDEBUG_SYNC_PARPORT obj-m += parport_debug.o endif # Handle versioning XPP_VERSION_STR ?= $(shell if [ -r $(obj)/.version ]; then echo "\"`cat $(obj)/.version`\""; else echo '"Unknown"'; fi) clean-files += xpp_version.h $(obj)/card_fxs.o $(obj)/card_fxo.o $(obj)/card_bri.o $(obj)/card_pri.o $(obj)/xpp_usb.o $(obj)/xpp.o: $(obj)/xpp_version.h $(obj)/xpp_version.h: FORCE @echo ' VERSION $@' $(Q)echo '#define XPP_VERSION $(XPP_VERSION_STR)' > $@.tmp $(Q)if cmp -s $@.tmp $@ ; then echo; else \ mv $@.tmp $@ ; \ fi $(Q)rm -f $@.tmp # Validations: # - Syntactic verification of perl scripts # - Handle country table validation for init_card_2_* XPP_PROTOCOL_VERSION := $(shell grep XPP_PROTOCOL_VERSION $(src)/xproto.h | sed -e 's/^.*XPP_PROTOCOL_VERSION[ \t]*//') xpp_verifications = \ init_card_1_$(XPP_PROTOCOL_VERSION) \ init_card_2_$(XPP_PROTOCOL_VERSION) \ init_card_3_$(XPP_PROTOCOL_VERSION) \ init_card_4_$(XPP_PROTOCOL_VERSION) \ init_fxo_modes xpp_verified = $(foreach file, $(xpp_verifications), $(file).verified) FXO_MODES = $(src)/../fxo_modes.h FXO_VERIFY = $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION) -v $(obj)/init_fxo_modes hostprogs-y := print_fxo_modes always := $(xpp_verified) xpp_version.h print_fxo_modes-objs := print_fxo_modes.o HOSTCFLAGS_print_fxo_modes.o += -include $(FXO_MODES) clean-files += print_fxo_modes init_fxo_modes $(xpp_verified) $(obj)/init_fxo_modes: $(obj)/print_fxo_modes @echo ' GEN $@' $(Q)$(obj)/print_fxo_modes >$@ || (rm -f $@; exit 1) $(obj)/init_fxo_modes.verified: $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION) $(obj)/init_fxo_modes @echo ' CHECK $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION)' $(Q)$(FXO_VERIFY) || (rm -f $@; exit 1) $(Q)touch $@ $(obj)/init_card_%_$(XPP_PROTOCOL_VERSION).verified: $(src)/init_card_%_$(XPP_PROTOCOL_VERSION) @echo ' VERIFY $<' $(Q)perl -c $< 2> $@ || (cat $@; rm -f $@; exit 1) .PHONY: FORCE FORCE: dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xbus-pcm.h0000644000175000017500000000772211602416004021256 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2007, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * This source module contains all the PCM and SYNC handling code. */ #ifndef XBUS_PCM_H #define XBUS_PCM_H #include "xdefs.h" #include #include #ifdef __KERNEL__ enum sync_mode { SYNC_MODE_NONE = 0x00, SYNC_MODE_AB = 0x01, /* Astribank sync */ SYNC_MODE_PLL = 0x03, /* Adjust XPD's PLL according to HOST */ SYNC_MODE_QUERY = 0x80, }; /* * Abstract representation of timestamp. * It would (eventually) replace the hard-coded * timeval structs so we can migrate to better * time representations. */ struct xpp_timestamp { struct timeval tv; }; /* * A ticker encapsulates the timing information of some * abstract tick source. The following tickers are used: * - Each xbus has an embedded ticker. * - There is one global dahdi_ticker to represent ticks * of external dahdi card (in case we want to sync * from other dahdi devices). */ struct xpp_ticker { /* for rate calculation */ int count; int cycle; struct xpp_timestamp first_sample; struct xpp_timestamp last_sample; int tick_period; /* usec/tick */ spinlock_t lock; }; /* * xpp_drift represent the measurements of the offset between an * xbus ticker to a reference ticker. */ struct xpp_drift { int delta_tick; /* from ref_ticker */ int lost_ticks; /* occurances */ int lost_tick_count; int sync_inaccuracy; struct xpp_timestamp last_lost_tick; long delta_sum; int offset_prev; int offset_range; int offset_min; int offset_max; int min_speed; int max_speed; spinlock_t lock; }; void xpp_drift_init(xbus_t *xbus); static inline long usec_diff(const struct timeval *tv1, const struct timeval *tv2) { long diff_sec; long diff_usec; diff_sec = tv1->tv_sec - tv2->tv_sec; diff_usec = tv1->tv_usec - tv2->tv_usec; return diff_sec * 1000000 + diff_usec; } int xbus_pcm_init(void *top); void xbus_pcm_shutdown(void); int send_pcm_frame(xbus_t *xbus, xframe_t *xframe); void pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe); void update_wanted_pcm_mask(xpd_t *xpd, xpp_line_t new_mask, uint new_pcm_len); void generic_card_pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask); void generic_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack); void generic_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack); int generic_timing_priority(xpd_t *xpd); int generic_echocancel_timeslot(xpd_t *xpd, int pos); int generic_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask); void fill_beep(u_char *buf, int num, int duration); const char *sync_mode_name(enum sync_mode mode); void xbus_set_command_timer(xbus_t *xbus, bool on); void xbus_request_sync(xbus_t *xbus, enum sync_mode mode); void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift); int xbus_command_queue_tick(xbus_t *xbus); void xbus_reset_counters(xbus_t *xbus); void elect_syncer(const char *msg); int exec_sync_command(const char *buf, size_t count); int fill_sync_string(char *buf, size_t count); #ifdef DAHDI_SYNC_TICK void dahdi_sync_tick(struct dahdi_span *span, int is_master); #endif #ifdef DEBUG_PCMTX extern int pcmtx; extern int pcmtx_chan; #endif #endif /* __KERNEL__ */ #endif /* XBUS_PCM_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_fxs.c0000644000175000017500000013754611626407053021326 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "xpd.h" #include "xproto.h" #include "xpp_dahdi.h" #include "card_fxo.h" #include "dahdi_debug.h" #include "xbus-core.h" static const char rcsid[] = "$Id: card_fxs.c 10157 2011-08-28 09:45:15Z tzafrir $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity"); static DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware"); #ifdef POLL_DIGITAL_INPUTS static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs"); #endif static DEF_PARM_BOOL(vmwi_ioctl, 1, 0644, "Asterisk support VMWI notification via ioctl"); static DEF_PARM_BOOL(ring_trapez, 0, 0664, "Use trapezoid ring type"); /* Signaling is opposite (fxo signalling for fxs card) */ #if 1 #define FXS_DEFAULT_SIGCAP (DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS) #else #define FXS_DEFAULT_SIGCAP (DAHDI_SIG_SF | DAHDI_SIG_EM) #endif #define VMWI_TYPE(priv, pos, type) \ ((priv)->vmwisetting[pos].vmwi_type & DAHDI_VMWI_ ## type) #define VMWI_NEON(priv, pos) VMWI_TYPE(priv, pos, HVAC) #define LINES_DIGI_OUT 2 #define LINES_DIGI_INP 4 enum fxs_leds { LED_GREEN, LED_RED, OUTPUT_RELAY, }; #define NUM_LEDS 2 /* Shortcuts */ #define SLIC_WRITE 1 #define SLIC_READ 0 #define SLIC_DIRECT_REQUEST(xbus,xpd,port,writing,reg,dL) \ xpp_register_request((xbus), (xpd), (port), (writing), (reg), 0, 0, (dL), 0, 0, 0) #define SLIC_INDIRECT_REQUEST(xbus,xpd,port,writing,reg,dL,dH) \ xpp_register_request((xbus), (xpd), (port), (writing), 0x1E, 1, (reg), (dL), 1, (dH), 0) #define VALID_PORT(port) (((port) >= 0 && (port) <= 7) || (port) == PORT_BROADCAST) #define REG_DIGITAL_IOCTRL 0x06 /* LED and RELAY control */ /* Values of SLIC linefeed control register (0x40) */ enum fxs_state { FXS_LINE_OPEN = 0x00, /* Open */ FXS_LINE_ACTIVE = 0x01, /* Forward active */ FXS_LINE_OHTRANS = 0x02, /* Forward on-hook transmission */ FXS_LINE_TIPOPEN = 0x03, /* TIP open */ FXS_LINE_RING = 0x04, /* Ringing */ FXS_LINE_REV_ACTIVE = 0x05, /* Reverse active */ FXS_LINE_REV_OHTRANS = 0x06, /* Reverse on-hook transmission */ FXS_LINE_RING_OPEN = 0x07 /* RING open */ }; #define FXS_LINE_POL_ACTIVE ((reversepolarity) ? FXS_LINE_REV_ACTIVE : FXS_LINE_ACTIVE) #define FXS_LINE_POL_OHTRANS ((reversepolarity) ? FXS_LINE_REV_OHTRANS : FXS_LINE_OHTRANS) /* * DTMF detection */ #define REG_DTMF_DECODE 0x18 /* 24 - DTMF Decode Status */ #define REG_BATTERY 0x42 /* 66 - Battery Feed Control */ #define REG_BATTERY_BATSL BIT(1) /* Battery Feed Select */ #define REG_LOOPCLOSURE 0x44 /* 68 - Loop Closure/Ring Trip Detect Status */ #define REG_LOOPCLOSURE_ZERO 0xF8 /* Loop Closure zero bits. */ #define REG_LOOPCLOSURE_LCR BIT(0) /* Loop Closure Detect Indicator. */ /*---------------- FXS Protocol Commands ----------------------------------*/ static bool fxs_packet_is_valid(xpacket_t *pack); static void fxs_packet_dump(const char *msg, xpacket_t *pack); #ifdef CONFIG_PROC_FS static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); #ifdef WITH_METERING static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data); #endif #endif static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos); #define PROC_REGISTER_FNAME "slics" #define PROC_FXS_INFO_FNAME "fxs_info" #ifdef WITH_METERING #define PROC_METERING_FNAME "metering_gen" #endif struct FXS_priv_data { #ifdef WITH_METERING struct proc_dir_entry *meteringfile; #endif struct proc_dir_entry *fxs_info; xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */ xpp_line_t search_fsk_pattern; xpp_line_t found_fsk_pattern; xpp_line_t update_offhook_state; xpp_line_t want_dtmf_events; /* what dahdi want */ xpp_line_t want_dtmf_mute; /* what dahdi want */ xpp_line_t prev_key_down; /* DTMF down sets the bit */ struct timeval prev_key_time[CHANNELS_PERXPD]; int led_counter[NUM_LEDS][CHANNELS_PERXPD]; int ohttimer[CHANNELS_PERXPD]; #define OHT_TIMER 6000 /* How long after RING to retain OHT */ enum fxs_state idletxhookstate[CHANNELS_PERXPD]; /* IDLE changing hook state */ enum fxs_state lasttxhook[CHANNELS_PERXPD]; struct dahdi_vmwi_info vmwisetting[CHANNELS_PERXPD]; }; /* * LED counter values: * n>1 : BLINK every n'th tick */ #define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos]) #define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0) #define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t)) #define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) #define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) #define LED_BLINK_RING (1000/8) /* in ticks */ /*---------------- FXS: Static functions ----------------------------------*/ static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan, enum fxs_state value) { struct FXS_priv_data *priv; priv = xpd->priv; LINE_DBG(SIGNAL, xpd, chan, "value=0x%02X\n", value); priv->lasttxhook[chan] = value; return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value); } static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on) { int value = (on) ? REG_BATTERY_BATSL : 0x00; BUG_ON(!xbus); BUG_ON(!xpd); LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down"); return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value); } static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on) { struct FXS_priv_data *priv; priv = xpd->priv; BUG_ON(!xpd); if (VMWI_NEON(priv, pos) && on) { LINE_DBG(SIGNAL, xpd, pos, "START\n"); BIT_SET(priv->search_fsk_pattern, pos); } else { LINE_DBG(SIGNAL, xpd, pos, "STOP\n"); BIT_CLR(priv->search_fsk_pattern, pos); } } /* * LED and RELAY control is done via SLIC register 0x06: * 7 6 5 4 3 2 1 0 * +-----+-----+-----+-----+-----+-----+-----+-----+ * | M2 | M1 | M3 | C2 | O1 | O3 | C1 | C3 | * +-----+-----+-----+-----+-----+-----+-----+-----+ * * Cn - Control bit (control one digital line) * On - Output bit (program a digital line for output) * Mn - Mask bit (only the matching output control bit is affected) * * C3 - OUTPUT RELAY (0 - OFF, 1 - ON) * C1 - GREEN LED (0 - OFF, 1 - ON) * O3 - Output RELAY (this line is output) * O1 - Output GREEN (this line is output) * C2 - RED LED (0 - OFF, 1 - ON) * M3 - Mask RELAY. (1 - C3 effect the OUTPUT RELAY) * M2 - Mask RED. (1 - C2 effect the RED LED) * M1 - Mask GREEN. (1 - C1 effect the GREEN LED) * * The OUTPUT RELAY (actually a relay out) is connected to line 0 and 4 only. */ // GREEN RED OUTPUT RELAY static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) }; static const int led_register_vals[] = { BIT(4), BIT(1), BIT(0) }; /* * pos can be: * - A line number * - ALL_LINES. This is not valid anymore since 8-Jan-2007. */ static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on) { int ret = 0; struct FXS_priv_data *priv; int value; xbus_t *xbus; BUG_ON(!xpd); BUG_ON(chan == ALL_LINES); xbus = xpd->xbus; priv = xpd->priv; which = which % NUM_LEDS; if(IS_SET(PHONEDEV(xpd).digital_outputs, chan) || IS_SET(PHONEDEV(xpd).digital_inputs, chan)) goto out; if(chan == PORT_BROADCAST) { priv->ledstate[which] = (on) ? ~0 : 0; } else { if(on) { BIT_SET(priv->ledstate[which], chan); } else { BIT_CLR(priv->ledstate[which], chan); } } LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off"); value = BIT(2) | BIT(3); value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]); if(on) value |= led_register_vals[which]; ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_DIGITAL_IOCTRL, value); out: return ret; } static void handle_fxs_leds(xpd_t *xpd) { int i; const enum fxs_leds colors[] = { LED_GREEN, LED_RED }; enum fxs_leds color; unsigned int timer_count; struct FXS_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; timer_count = xpd->timer_count; for(color = 0; color < ARRAY_SIZE(colors); color++) { for_each_line(xpd, i) { if(IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, i)) continue; if((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking int mod_value = LED_COUNTER(priv, i, color); if(!mod_value) mod_value = DEFAULT_LED_PERIOD; /* safety value */ // led state is toggled if((timer_count % mod_value) == 0) { LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF"); if(!IS_SET(priv->ledstate[color], i)) { do_led(xpd, i, color, 1); } else { do_led(xpd, i, color, 0); } } } else if(IS_SET(priv->ledcontrol[color] & ~priv->ledstate[color], i)) { do_led(xpd, i, color, 1); } else if(IS_SET(~priv->ledcontrol[color] & priv->ledstate[color], i)) { do_led(xpd, i, color, 0); } } } } static void restore_leds(xpd_t *xpd) { struct FXS_priv_data *priv; int i; priv = xpd->priv; for_each_line(xpd, i) { if(IS_OFFHOOK(xpd, i)) MARK_ON(priv, i, LED_GREEN); else MARK_OFF(priv, i, LED_GREEN); } } #ifdef WITH_METERING static int metering_gen(xpd_t *xpd, lineno_t chan, bool on) { byte value = (on) ? 0x94 : 0x00; LINE_DBG(SIGNAL, xpd, chan, "METERING Generate: %s\n", (on)?"ON":"OFF"); return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, chan, SLIC_WRITE, 0x23, value); } #endif /*---------------- FXS: Methods -------------------------------------------*/ static void fxs_proc_remove(xbus_t *xbus, xpd_t *xpd) { struct FXS_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; #ifdef CONFIG_PROC_FS #ifdef WITH_METERING if(priv->meteringfile) { XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n"); priv->meteringfile->data = NULL; remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir); priv->meteringfile = NULL; } #endif if(priv->fxs_info) { XPD_DBG(PROC, xpd, "Removing xpd FXS_INFO file\n"); remove_proc_entry(PROC_FXS_INFO_FNAME, xpd->proc_xpd_dir); priv->fxs_info = NULL; } #endif } static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd) { struct FXS_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; #ifdef CONFIG_PROC_FS XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n"); priv->fxs_info = create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxs_info_read, xpd); if(!priv->fxs_info) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXS_INFO_FNAME); fxs_proc_remove(xbus, xpd); return -EINVAL; } SET_PROC_DIRENTRY_OWNER(priv->fxs_info); #ifdef WITH_METERING XPD_DBG(PROC, xpd, "Creating Metering tone file\n"); priv->meteringfile = create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir); if(!priv->meteringfile) { XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME); fxs_proc_remove(xbus, xpd); return -EINVAL; } SET_PROC_DIRENTRY_OWNER(priv->meteringfile); priv->meteringfile->write_proc = proc_xpd_metering_write; priv->meteringfile->read_proc = NULL; priv->meteringfile->data = xpd; #endif #endif return 0; } static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone) { xpd_t *xpd = NULL; int channels; int regular_channels; struct FXS_priv_data *priv; int i; if(!to_phone) { XBUS_NOTICE(xbus, "XPD=%d%d: try to instanciate FXS with reverse direction\n", unit, subunit); return NULL; } if(subtype == 2) regular_channels = min(6, subunit_ports); else regular_channels = min(8, subunit_ports); channels = regular_channels; if(unit == 0 && subtype != 4) channels += 6; /* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct FXS_priv_data), proto_table, channels); if(!xpd) return NULL; if(unit == 0) { XBUS_DBG(GENERAL, xbus, "First XPD detected. Initialize digital outputs/inputs\n"); PHONEDEV(xpd).digital_outputs = BITMASK(LINES_DIGI_OUT) << regular_channels; PHONEDEV(xpd).digital_inputs = BITMASK(LINES_DIGI_INP) << (regular_channels + LINES_DIGI_OUT); } PHONEDEV(xpd).direction = TO_PHONE; xpd->type_name = "FXS"; if(fxs_proc_create(xbus, xpd) < 0) goto err; priv = xpd->priv; for_each_line(xpd, i) { priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE; } return xpd; err: xpd_free(xpd); return NULL; } static int FXS_card_init(xbus_t *xbus, xpd_t *xpd) { int ret = 0; int i; BUG_ON(!xpd); /* * Setup ring timers */ /* Software controled ringing (for CID) */ ret = SLIC_DIRECT_REQUEST(xbus, xpd, PORT_BROADCAST, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */ if(ret < 0) goto err; for_each_line(xpd, i) { linefeed_control(xbus, xpd, i, FXS_LINE_POL_ACTIVE); } XPD_DBG(GENERAL, xpd, "done\n"); for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 0); do_led(xpd, i, LED_RED, 0); } for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 1); msleep(50); } for_each_line(xpd, i) { do_led(xpd, i, LED_GREEN, 0); msleep(50); } restore_leds(xpd); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); /* * We should query our offhook state long enough time after we * set the linefeed_control() * So we do this after the LEDs */ for_each_line(xpd, i) { if(IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, i)) continue; SLIC_DIRECT_REQUEST(xbus, xpd, i, SLIC_READ, REG_LOOPCLOSURE, 0); } return 0; err: fxs_proc_remove(xbus, xpd); XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret); return ret; } static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); fxs_proc_remove(xbus, xpd); return 0; } static int FXS_card_dahdi_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct FXS_priv_data *priv; int i; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); PHONEDEV(xpd).span.spantype = "FXS"; for_each_line(xpd, i) { struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i); if(IS_SET(PHONEDEV(xpd).digital_outputs, i)) { snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%02d/%1d%1d/%d", xbus->num, xpd->addr.unit, xpd->addr.subunit, i); } else if(IS_SET(PHONEDEV(xpd).digital_inputs, i)) { snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%02d/%1d%1d/%d", xbus->num, xpd->addr.unit, xpd->addr.subunit, i); } else { snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%02d/%1d%1d/%d", xbus->num, xpd->addr.unit, xpd->addr.subunit, i); } cur_chan->chanpos = i + 1; cur_chan->pvt = xpd; cur_chan->sigcap = FXS_DEFAULT_SIGCAP; if (!vmwi_ioctl) { /* Old asterisk, assume default VMWI type */ priv->vmwisetting[i].vmwi_type = DAHDI_VMWI_HVAC; } } for_each_line(xpd, i) { MARK_ON(priv, i, LED_GREEN); msleep(4); MARK_ON(priv, i, LED_RED); } return 0; } static int FXS_card_dahdi_postregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct FXS_priv_data *priv; int i; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); for_each_line(xpd, i) { MARK_OFF(priv, i, LED_GREEN); msleep(2); MARK_OFF(priv, i, LED_RED); msleep(2); } restore_leds(xpd); return 0; } /* * Called with XPD spinlocked */ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit) { LINE_DBG(SIGNAL, xpd, pos, "%s\n", (muteit) ? "MUTE" : "UNMUTE"); if(muteit) BIT_SET(PHONEDEV(xpd).mute_dtmf, pos); else BIT_CLR(PHONEDEV(xpd).mute_dtmf, pos); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); /* already spinlocked */ } static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, unsigned int msg_waiting) { int ret = 0; struct FXS_priv_data *priv; BUG_ON(!xbus); BUG_ON(!xpd); priv = xpd->priv; if (VMWI_NEON(priv, pos) && msg_waiting) { /* A write to register 0x40 will now turn on/off the VM led */ LINE_DBG(SIGNAL, xpd, pos, "NEON\n"); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46); } else if (ring_trapez) { LINE_DBG(SIGNAL, xpd, pos, "RINGER: Trapez ring\n"); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xC8, 0x00); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xAB, 0x5E); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x8C, 0x01); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x01); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36); } else { /* A write to register 0x40 will now turn on/off the ringer */ LINE_DBG(SIGNAL, xpd, pos, "RINGER\n"); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x77, 0x01); ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xFD, 0x7E); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00); ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);/* High Vbat~ -82V[Dc] */ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36); } return (ret ? -EPROTO : 0); } static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos) { struct FXS_priv_data *priv; unsigned int msgs; BUG_ON(!xpd); if (IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, pos)) return; priv = xpd->priv; msgs = PHONEDEV(xpd).msg_waiting[pos]; LINE_DBG(SIGNAL, xpd, pos, "%s\n", (msgs) ? "ON" : "OFF"); set_vm_led_mode(xbus, xpd, pos, msgs); do_chan_power(xbus, xpd, pos, msgs > 0); linefeed_control(xbus, xpd, pos, (msgs > 0) ? FXS_LINE_RING : priv->idletxhookstate[pos]); } static int relay_out(xpd_t *xpd, int pos, bool on) { int value; int which = pos; int relay_channels[] = { 0, 4 }; BUG_ON(!xpd); /* map logical position to output port number (0/1) */ which -= (xpd->subtype == 2) ? 6 : 8; LINE_DBG(SIGNAL, xpd, pos, "which=%d -- %s\n", which, (on) ? "on" : "off"); which = which % ARRAY_SIZE(relay_channels); value = BIT(2) | BIT(3); value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]); if(on) value |= led_register_vals[OUTPUT_RELAY]; return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, relay_channels[which], SLIC_WRITE, REG_DIGITAL_IOCTRL, value); } static int send_ring(xpd_t *xpd, lineno_t chan, bool on) { int ret = 0; xbus_t *xbus; struct FXS_priv_data *priv; enum fxs_state value = (on) ? FXS_LINE_RING : FXS_LINE_POL_ACTIVE; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on)?"on":"off"); priv = xpd->priv; set_vm_led_mode(xbus, xpd, chan, 0); do_chan_power(xbus, xpd, chan, on); // Power up (for ring) ret = linefeed_control(xbus, xpd, chan, value); if(on) { MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING); } else { if(IS_BLINKING(priv, chan, LED_GREEN)) MARK_BLINK(priv, chan, LED_GREEN, 0); } return ret; } static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig) { struct FXS_priv_data *priv; int ret = 0; struct dahdi_chan *chan = NULL; enum fxs_state txhook; unsigned long flags; LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig)); priv = xpd->priv; BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); if (IS_SET(PHONEDEV(xpd).digital_inputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "Ignoring signal sent to digital input line\n"); return 0; } if(SPAN_REGISTERED(xpd)) chan = XPD_CHAN(xpd, pos); switch(txsig) { case DAHDI_TXSIG_ONHOOK: spin_lock_irqsave(&xpd->lock, flags); PHONEDEV(xpd).ringing[pos] = 0; oht_pcm(xpd, pos, 0); vmwi_search(xpd, pos, 0); BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); spin_unlock_irqrestore(&xpd->lock, flags); if(IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig)); ret = relay_out(xpd, pos, 0); return ret; } if (priv->lasttxhook[pos] == FXS_LINE_OPEN) { /* * Restore state after KEWL hangup. */ LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n"); linefeed_control(xpd->xbus, xpd, pos, FXS_LINE_POL_ACTIVE); if(IS_OFFHOOK(xpd, pos)) MARK_ON(priv, pos, LED_GREEN); } ret = send_ring(xpd, pos, 0); // RING off if (!IS_OFFHOOK(xpd, pos)) start_stop_vm_led(xpd->xbus, xpd, pos); txhook = priv->lasttxhook[pos]; if(chan) { switch(chan->sig) { case DAHDI_SIG_EM: case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: txhook = priv->idletxhookstate[pos]; break; case DAHDI_SIG_FXOGS: txhook = FXS_LINE_TIPOPEN; break; } } ret = linefeed_control(xpd->xbus, xpd, pos, txhook); break; case DAHDI_TXSIG_OFFHOOK: if(IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { LINE_NOTICE(xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig)); return -EINVAL; } txhook = priv->lasttxhook[pos]; if(PHONEDEV(xpd).ringing[pos]) { oht_pcm(xpd, pos, 1); txhook = FXS_LINE_OHTRANS; } PHONEDEV(xpd).ringing[pos] = 0; if(chan) { switch(chan->sig) { case DAHDI_SIG_EM: txhook = FXS_LINE_POL_ACTIVE; break; default: txhook = priv->idletxhookstate[pos]; break; } } ret = linefeed_control(xpd->xbus, xpd, pos, txhook); break; case DAHDI_TXSIG_START: PHONEDEV(xpd).ringing[pos] = 1; oht_pcm(xpd, pos, 0); vmwi_search(xpd, pos, 0); if(IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig)); ret = relay_out(xpd, pos, 1); return ret; } ret = send_ring(xpd, pos, 1); // RING on break; case DAHDI_TXSIG_KEWL: if(IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { LINE_DBG(SIGNAL, xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig)); return -EINVAL; } linefeed_control(xpd->xbus, xpd, pos, FXS_LINE_OPEN); MARK_OFF(priv, pos, LED_GREEN); break; default: XPD_NOTICE(xpd, "%s: Can't set tx state to %s (%d)\n", __FUNCTION__, txsig2str(txsig), txsig); ret = -EINVAL; } return ret; } static int set_vmwi(xpd_t *xpd, int pos, unsigned long arg) { struct FXS_priv_data *priv; struct dahdi_vmwi_info vmwisetting; const int vmwi_flags = DAHDI_VMWI_LREV | DAHDI_VMWI_HVDC | DAHDI_VMWI_HVAC; priv = xpd->priv; BUG_ON(!priv); if (copy_from_user(&vmwisetting, (__user void *)arg, sizeof(vmwisetting))) return -EFAULT; if ((vmwisetting.vmwi_type & ~vmwi_flags) != 0) { LINE_NOTICE(xpd, pos, "Bad DAHDI_VMWI_CONFIG: 0x%X\n", vmwisetting.vmwi_type); return -EINVAL; } LINE_DBG(SIGNAL, xpd, pos, "DAHDI_VMWI_CONFIG: 0x%X\n", vmwisetting.vmwi_type); if (VMWI_TYPE(priv, pos, LREV)) { LINE_NOTICE(xpd, pos, "%s: VMWI(lrev) is not implemented yet. Ignored.\n", __func__); } if (VMWI_TYPE(priv, pos, HVDC)) { LINE_NOTICE(xpd, pos, "%s: VMWI(hvdc) is not implemented yet. Ignored.\n", __func__); } if (VMWI_TYPE(priv, pos, HVAC)) { ; /* VMWI_NEON */ } if (priv->vmwisetting[pos].vmwi_type == 0) { ; /* Disable VMWI */ } priv->vmwisetting[pos] = vmwisetting; set_vm_led_mode(xpd->xbus, xpd, pos, PHONEDEV(xpd).msg_waiting[pos]); return 0; } /* * Private ioctl() * We don't need it now, since we detect vmwi via FSK patterns */ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) { struct FXS_priv_data *priv; xbus_t *xbus; int val; unsigned long flags; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); xbus = xpd->xbus; BUG_ON(!xbus); if(!XBUS_IS(xbus, READY)) return -ENODEV; if (pos < 0 || pos >= PHONEDEV(xpd).channels) { XPD_NOTICE(xpd, "Bad channel number %d in %s(), cmd=%u\n", pos, __FUNCTION__, cmd); return -EINVAL; } switch (cmd) { case DAHDI_ONHOOKTRANSFER: if (get_user(val, (int __user *)arg)) return -EFAULT; LINE_DBG(SIGNAL, xpd, pos, "DAHDI_ONHOOKTRANSFER (%d millis)\n", val); if (IS_SET(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs, pos)) return 0; /* Nothing to do */ oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */ if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) { priv->ohttimer[pos] = val; priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS; vmwi_search(xpd, pos, 1); CALL_PHONE_METHOD(card_pcm_recompute, xpd, priv->search_fsk_pattern); LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", PHONEDEV(xpd).wanted_pcm_mask); } if (VMWI_NEON(priv, pos) && !IS_OFFHOOK(xpd, pos)) start_stop_vm_led(xbus, xpd, pos); return 0; case DAHDI_TONEDETECT: if (get_user(val, (int __user *)arg)) return -EFAULT; LINE_DBG(SIGNAL, xpd, pos, "DAHDI_TONEDETECT: %s %s (dtmf_detection=%s)\n", (val & DAHDI_TONEDETECT_ON) ? "ON" : "OFF", (val & DAHDI_TONEDETECT_MUTE) ? "MUTE" : "NO-MUTE", (dtmf_detection ? "YES" : "NO")); if(!dtmf_detection) { spin_lock_irqsave(&xpd->lock, flags); if(IS_SET(priv->want_dtmf_events, pos)) { /* Detection mode changed: Disable DTMF interrupts */ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0); } BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); spin_unlock_irqrestore(&xpd->lock, flags); return -ENOTTY; } /* * During natively bridged calls, Asterisk * will request one of the sides to stop sending * dtmf events. Check the requested state. */ spin_lock_irqsave(&xpd->lock, flags); if(val & DAHDI_TONEDETECT_ON) { if(!IS_SET(priv->want_dtmf_events, pos)) { /* Detection mode changed: Enable DTMF interrupts */ LINE_DBG(SIGNAL, xpd, pos, "DAHDI_TONEDETECT: Enable Hardware DTMF\n"); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 1); } BIT_SET(priv->want_dtmf_events, pos); } else { if(IS_SET(priv->want_dtmf_events, pos)) { /* Detection mode changed: Disable DTMF interrupts */ LINE_DBG(SIGNAL, xpd, pos, "DAHDI_TONEDETECT: Disable Hardware DTMF\n"); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0); } BIT_CLR(priv->want_dtmf_events, pos); } if(val & DAHDI_TONEDETECT_MUTE) { BIT_SET(priv->want_dtmf_mute, pos); } else { BIT_CLR(priv->want_dtmf_mute, pos); __do_mute_dtmf(xpd, pos, 0); } spin_unlock_irqrestore(&xpd->lock, flags); return 0; case DAHDI_SETPOLARITY: if (get_user(val, (int __user *)arg)) return -EFAULT; /* Can't change polarity while ringing or when open */ if (priv->lasttxhook[pos] == FXS_LINE_RING || priv->lasttxhook[pos] == FXS_LINE_OPEN) { LINE_ERR(xpd, pos, "DAHDI_SETPOLARITY: %s Cannot change when lasttxhook=0x%X\n", (val)?"ON":"OFF", priv->lasttxhook[pos]); return -EINVAL; } LINE_DBG(SIGNAL, xpd, pos, "DAHDI_SETPOLARITY: %s\n", (val)?"ON":"OFF"); if ((val && !reversepolarity) || (!val && reversepolarity)) priv->lasttxhook[pos] |= FXS_LINE_RING; else priv->lasttxhook[pos] &= ~FXS_LINE_RING; linefeed_control(xbus, xpd, pos, priv->lasttxhook[pos]); return 0; case DAHDI_VMWI_CONFIG: if (set_vmwi(xpd, pos, arg) < 0) return -EINVAL; return 0; case DAHDI_VMWI: /* message-waiting led control */ if (get_user(val, (int __user *)arg)) return -EFAULT; if(!vmwi_ioctl) { static bool notified = 0; if(!notified++) LINE_NOTICE(xpd, pos, "Got DAHDI_VMWI notification but vmwi_ioctl parameter is off. Ignoring.\n"); return 0; } /* Digital inputs/outputs don't have VM leds */ if (IS_SET(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs, pos)) return 0; PHONEDEV(xpd).msg_waiting[pos] = val; LINE_DBG(SIGNAL, xpd, pos, "DAHDI_VMWI: %s\n", (val) ? "yes" : "no"); return 0; default: report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); } return -ENOTTY; } static int FXS_card_open(xpd_t *xpd, lineno_t chan) { struct FXS_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; if(IS_OFFHOOK(xpd, chan)) LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n"); else LINE_DBG(SIGNAL, xpd, chan, "is onhook\n"); /* * Delegate updating dahdi to FXS_card_tick(): * The problem is that dahdi_hooksig() is spinlocking the channel and * we are called by dahdi with the spinlock already held on the * same channel. */ BIT_SET(priv->update_offhook_state, chan); return 0; } static int FXS_card_close(xpd_t *xpd, lineno_t chan) { struct FXS_priv_data *priv; BUG_ON(!xpd); LINE_DBG(GENERAL, xpd, chan, "\n"); priv = xpd->priv; priv->idletxhookstate[chan] = FXS_LINE_POL_ACTIVE; return 0; } #ifdef POLL_DIGITAL_INPUTS /* * INPUT polling is done via SLIC register 0x06 (same as LEDS): * 7 6 5 4 3 2 1 0 * +-----+-----+-----+-----+-----+-----+-----+-----+ * | I1 | I3 | | | I2 | I4 | | | * +-----+-----+-----+-----+-----+-----+-----+-----+ * */ static int input_channels[] = { 6, 7, 2, 3 }; // Slic numbers of input relays static void poll_inputs(xpd_t *xpd) { int i; BUG_ON(xpd->xbus_idx != 0); // Only unit #0 has digital inputs for(i = 0; i < ARRAY_SIZE(input_channels); i++) { byte pos = input_channels[i]; SLIC_DIRECT_REQUEST(xpd->xbus, xpd, pos, SLIC_READ, 0x06, 0); } } #endif static void handle_linefeed(xpd_t *xpd) { struct FXS_priv_data *priv; int i; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); for_each_line(xpd, i) { if (priv->lasttxhook[i] == FXS_LINE_RING) { /* RINGing, prepare for OHT */ priv->ohttimer[i] = OHT_TIMER; priv->idletxhookstate[i] = FXS_LINE_POL_OHTRANS; } else { if (priv->ohttimer[i]) { priv->ohttimer[i]--; if (!priv->ohttimer[i]) { LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n"); priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE; oht_pcm(xpd, i, 0); vmwi_search(xpd, i, 0); if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) { /* Apply the change if appropriate */ linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE); } } } } } } /* * Optimized memcmp() like function. Only test for equality (true/false). * This optimization reduced the detect_vmwi() runtime by a factor of 3. */ static inline bool mem_equal(const char a[], const char b[], size_t len) { int i; for(i = 0; i < len; i++) if(a[i] != b[i]) return 0; return 1; } /* * Detect Voice Mail Waiting Indication */ static void detect_vmwi(xpd_t *xpd) { struct FXS_priv_data *priv; xbus_t *xbus; static const byte FSK_COMMON_PATTERN[] = { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB }; static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF }; static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F }; int i; xpp_line_t ignore_mask; BUG_ON(!xpd); xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!priv); ignore_mask = PHONEDEV(xpd).offhook_state | ~(PHONEDEV(xpd).oht_pcm_pass) | ~(priv->search_fsk_pattern) | PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs; for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); byte *writechunk = chan->writechunk; if(IS_SET(ignore_mask, i)) continue; #if 0 if(writechunk[0] != 0x7F && writechunk[0] != 0) { int j; LINE_DBG(GENERAL, xpd, pos, "MSG:"); for(j = 0; j < DAHDI_CHUNKSIZE; j++) { if(debug) printk(" %02X", writechunk[j]); } if(debug) printk("\n"); } #endif if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) { LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n"); BIT_SET(priv->found_fsk_pattern, i); } else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) { BIT_CLR(priv->found_fsk_pattern, i); oht_pcm(xpd, i, 0); if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, DAHDI_CHUNKSIZE))) { LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n"); PHONEDEV(xpd).msg_waiting[i] = 1; start_stop_vm_led(xbus, xpd, i); } else if(unlikely(mem_equal(writechunk, FSK_OFF_PATTERN, DAHDI_CHUNKSIZE))) { LINE_DBG(SIGNAL, xpd, i, "MSG WAITING OFF\n"); PHONEDEV(xpd).msg_waiting[i] = 0; start_stop_vm_led(xbus, xpd, i); } else { int j; LINE_NOTICE(xpd, i, "MSG WAITING Unexpected:"); for(j = 0; j < DAHDI_CHUNKSIZE; j++) { printk(" %02X", writechunk[j]); } printk("\n"); } } } } static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd) { struct FXS_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); #ifdef POLL_DIGITAL_INPUTS if(poll_digital_inputs && xpd->xbus_idx == 0) { if((xpd->timer_count % poll_digital_inputs) == 0) poll_inputs(xpd); } #endif handle_fxs_leds(xpd); handle_linefeed(xpd); /* * Hack alert (FIXME): * Asterisk did FXS_card_open() and we wanted to report * offhook state. However, the channel is spinlocked by dahdi * so we marked it in the priv->update_offhook_state mask and * now we take care of notification to dahdi and Asterisk */ if(priv->update_offhook_state) { enum dahdi_rxsig rxsig; int i; for_each_line(xpd, i) { if(!IS_SET(priv->update_offhook_state, i)) continue; rxsig = IS_OFFHOOK(xpd, i) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK; notify_rxsig(xpd, i, rxsig); /* Notify after open() */ BIT_CLR(priv->update_offhook_state, i); } } if(SPAN_REGISTERED(xpd)) { if (!vmwi_ioctl && priv->search_fsk_pattern) detect_vmwi(xpd); /* Detect via FSK modulation */ } return 0; } /*---------------- FXS: HOST COMMANDS -------------------------------------*/ /*---------------- FXS: Astribank Reply Handlers --------------------------*/ /* * Should be called with spinlocked XPD */ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_mask) { xbus_t *xbus; struct FXS_priv_data *priv; int i; BUG_ON(!xpd); BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); xbus = xpd->xbus; priv = xpd->priv; XPD_DBG(SIGNAL, xpd, "offhook=0x%X change_mask=0x%X\n", offhook, change_mask); for_each_line(xpd, i) { if(IS_SET(PHONEDEV(xpd).digital_outputs, i) || IS_SET(PHONEDEV(xpd).digital_inputs, i)) continue; if(IS_SET(change_mask, i)) { PHONEDEV(xpd).ringing[i] = 0; /* No more ringing... */ #ifdef WITH_METERING metering_gen(xpd, i, 0); /* Stop metering... */ #endif MARK_BLINK(priv, i, LED_GREEN, 0); /* * Reset our previous DTMF memories... */ BIT_CLR(priv->prev_key_down, i); priv->prev_key_time[i].tv_sec = priv->prev_key_time[i].tv_usec = 0L; if(IS_SET(offhook, i)) { LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n"); MARK_ON(priv, i, LED_GREEN); hookstate_changed(xpd, i, 1); } else { LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n"); MARK_OFF(priv, i, LED_GREEN); hookstate_changed(xpd, i, 0); } /* * Must switch to low power. In high power, an ONHOOK * won't be detected. */ do_chan_power(xbus, xpd, i, 0); } } } HANDLER_DEF(FXS, SIG_CHANGED) { xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status); xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles); unsigned long flags; BUG_ON(!xpd); BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status); #if 0 Is this needed? for_each_line(xpd, i) { if(IS_SET(sig_toggles, i)) do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!) } #endif spin_lock_irqsave(&xpd->lock, flags); process_hookstate(xpd, sig_status, sig_toggles); spin_unlock_irqrestore(&xpd->lock, flags); return 0; } #ifdef POLL_DIGITAL_INPUTS static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info) { int i; bool offhook = (REG_FIELD(info, data_low) & 0x1) == 0; xpp_line_t lines = BIT(info->portnum); /* Map SLIC number into line number */ for(i = 0; i < ARRAY_SIZE(input_channels); i++) { int channo = input_channels[i]; int newchanno; if(IS_SET(lines, channo)) { newchanno = PHONEDEV(xpd).channels - LINES_DIGI_INP + i; BIT_CLR(lines, channo); BIT_SET(lines, newchanno); PHONEDEV(xpd).ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs. if(offhook && !IS_OFFHOOK(xpd, newchanno)) { // OFFHOOK LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n"); hookstate_changed(xpd, newchanno, 1); } else if(!offhook && IS_OFFHOOK(xpd, newchanno)) { // ONHOOK LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n"); hookstate_changed(xpd, newchanno, 0); } } } } #endif static const char dtmf_digits[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#', 'A', 'B', 'C', 'D' }; /* * This function is called with spinlocked XPD */ static void process_dtmf(xpd_t *xpd, uint portnum, byte val) { byte digit; bool key_down = val & 0x10; bool want_mute; bool want_event; struct FXS_priv_data *priv; struct timeval now; int msec = 0; if(!dtmf_detection) return; if(!SPAN_REGISTERED(xpd)) return; priv = xpd->priv; val &= 0xF; if(val <= 0) { if(key_down) XPD_NOTICE(xpd, "Bad DTMF value %d. Ignored\n", val); return; } val--; digit = dtmf_digits[val]; want_mute = IS_SET(priv->want_dtmf_mute, portnum); want_event = IS_SET(priv->want_dtmf_events, portnum); if(!IS_SET(priv->prev_key_down, portnum) && !key_down) { LINE_NOTICE(xpd, portnum, "DTMF: duplicate UP (%c)\n", digit); } if(key_down) BIT_SET(priv->prev_key_down, portnum); else BIT_CLR(priv->prev_key_down, portnum); do_gettimeofday(&now); if(priv->prev_key_time[portnum].tv_sec != 0) msec = usec_diff(&now, &priv->prev_key_time[portnum]) / 1000; priv->prev_key_time[portnum] = now; LINE_DBG(SIGNAL, xpd, portnum, "[%lu.%06lu] DTMF digit %-4s '%c' (val=%d, want_mute=%s want_event=%s, delta=%d msec)\n", now.tv_sec, now.tv_usec, (key_down)?"DOWN":"UP", digit, val, (want_mute) ? "yes" : "no", (want_event) ? "yes" : "no", msec); /* * FIXME: we currently don't use the want_dtmf_mute until * we are sure about the logic in Asterisk native bridging. * Meanwhile, simply mute it on button press. */ if(key_down && want_mute) __do_mute_dtmf(xpd, portnum, 1); else __do_mute_dtmf(xpd, portnum, 0); if(want_event) { int event = (key_down) ? DAHDI_EVENT_DTMFDOWN : DAHDI_EVENT_DTMFUP; dahdi_qevent_lock(XPD_CHAN(xpd, portnum), event | digit); } } static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { unsigned long flags; struct FXS_priv_data *priv; byte regnum; bool indirect; spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); indirect = (REG_FIELD(info, regnum) == 0x1E); regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum); XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", (indirect)?"I":"D", regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); if(!indirect && regnum == REG_DTMF_DECODE) { byte val = REG_FIELD(info, data_low); process_dtmf(xpd, info->portnum, val); } #ifdef POLL_DIGITAL_INPUTS /* * Process digital inputs polling results */ else if(xpd->xbus_idx == 0 && !indirect && regnum == REG_DIGITAL_IOCTRL) { process_digital_inputs(xpd, info); } #endif else if(!indirect && regnum == REG_LOOPCLOSURE) { /* OFFHOOK ? */ byte val = REG_FIELD(info, data_low); xpp_line_t mask = BIT(info->portnum); xpp_line_t offhook; /* * Validate reply. Non-existing/disabled ports * will reply with 0xFF. Ignore these. */ if((val & REG_LOOPCLOSURE_ZERO) == 0) { offhook = (val & REG_LOOPCLOSURE_LCR) ? mask : 0; LINE_DBG(SIGNAL, xpd, info->portnum, "REG_LOOPCLOSURE: dataL=0x%X (offhook=0x%X mask=0x%X\n", val, offhook, mask); process_hookstate(xpd, offhook, mask); } } else { #if 0 XPD_NOTICE(xpd, "Spurious register reply(ignored): %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", (indirect)?"I":"D", regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); #endif } /* Update /proc info only if reply relate to the last slic read request */ if( REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { xpd->last_reply = *info; } spin_unlock_irqrestore(&xpd->lock, flags); return 0; } static int FXS_card_state(xpd_t *xpd, bool on) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); return 0; } static const struct xops fxs_xops = { .card_new = FXS_card_new, .card_init = FXS_card_init, .card_remove = FXS_card_remove, .card_tick = FXS_card_tick, .card_register_reply = FXS_card_register_reply, }; static const struct phoneops fxs_phoneops = { .card_dahdi_preregistration = FXS_card_dahdi_preregistration, .card_dahdi_postregistration = FXS_card_dahdi_postregistration, .card_hooksig = FXS_card_hooksig, .card_pcm_recompute = generic_card_pcm_recompute, .card_pcm_fromspan = generic_card_pcm_fromspan, .card_pcm_tospan = generic_card_pcm_tospan, .card_timing_priority = generic_timing_priority, .echocancel_timeslot = generic_echocancel_timeslot, .echocancel_setmask = generic_echocancel_setmask, .card_open = FXS_card_open, .card_close = FXS_card_close, .card_ioctl = FXS_card_ioctl, .card_state = FXS_card_state, }; static xproto_table_t PROTO_TABLE(FXS) = { .owner = THIS_MODULE, .entries = { /* Prototable Card Opcode */ XENTRY( FXS, FXS, SIG_CHANGED ), }, .name = "FXS", /* protocol name */ .ports_per_subunit = 8, .type = XPD_TYPE_FXS, .xops = &fxs_xops, .phoneops = &fxs_phoneops, .packet_is_valid = fxs_packet_is_valid, .packet_dump = fxs_packet_dump, }; static bool fxs_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe; // DBG(GENERAL, "\n"); xe = xproto_card_entry(&PROTO_TABLE(FXS), XPACKET_OP(pack)); return xe != NULL; } static void fxs_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } /*------------------------- SLIC Handling --------------------------*/ #ifdef CONFIG_PROC_FS static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; unsigned long flags; xpd_t *xpd = data; struct FXS_priv_data *priv; int i; int led; if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); len += sprintf(page + len, "%-8s %-10s %-10s %-10s\n", "Channel", "idletxhookstate", "lasttxhook", "ohttimer" ); for_each_line(xpd, i) { char pref; if(IS_SET(PHONEDEV(xpd).digital_outputs, i)) pref = 'O'; else if(IS_SET(PHONEDEV(xpd).digital_inputs, i)) pref = 'I'; else pref = ' '; len += sprintf(page + len, "%c%7d %10d %10d %10d\n", pref, i, priv->idletxhookstate[i], priv->lasttxhook[i], priv->ohttimer[i] ); } len += sprintf(page + len, "\n"); for(led = 0; led < NUM_LEDS; led++) { len += sprintf(page + len, "LED #%d", led); len += sprintf(page + len, "\n\t%-17s: ", "ledstate"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, "%d ", IS_SET(priv->ledstate[led], i)); } len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i)); } len += sprintf(page + len, "\n\t%-17s: ", "led_counter"); for_each_line(xpd, i) { if(!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) len += sprintf(page + len, "%d ", LED_COUNTER(priv,i,led)); } len += sprintf(page + len, "\n"); } spin_unlock_irqrestore(&xpd->lock, flags); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } #endif #ifdef WITH_METERING static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { xpd_t *xpd = data; char buf[MAX_PROC_WRITE]; lineno_t chan; int num; int ret; if(!xpd) return -ENODEV; if(count >= MAX_PROC_WRITE - 1) { XPD_ERR(xpd, "Metering string too long (%lu)\n", count); return -EINVAL; } if(copy_from_user(&buf, buffer, count)) return -EFAULT; buf[count] = '\0'; ret = sscanf(buf, "%d", &num); if(ret != 1) { XPD_ERR(xpd, "Metering value should be number. Got '%s'\n", buf); return -EINVAL; } chan = num; if(chan != PORT_BROADCAST && chan > xpd->channels) { XPD_ERR(xpd, "Metering tone: bad channel number %d\n", chan); return -EINVAL; } if((ret = metering_gen(xpd, chan, 1)) < 0) { XPD_ERR(xpd, "Failed sending metering tone\n"); return ret; } return count; } #endif static int fxs_xpd_probe(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); /* Is it our device? */ if(xpd->type != XPD_TYPE_FXS) { XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev), xpd->type); return -EINVAL; } XPD_DBG(DEVICES, xpd, "SYSFS\n"); return 0; } static int fxs_xpd_remove(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, xpd, "SYSFS\n"); return 0; } static struct xpd_driver fxs_driver = { .type = XPD_TYPE_FXS, .driver = { .name = "fxs", #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE, #endif .probe = fxs_xpd_probe, .remove = fxs_xpd_remove } }; static int __init card_fxs_startup(void) { int ret; if((ret = xpd_driver_register(&fxs_driver.driver)) < 0) return ret; INFO("revision %s\n", XPP_VERSION); #ifdef POLL_DIGITAL_INPUTS INFO("FEATURE: with DIGITAL INPUTS support (polled every %d msec)\n", poll_digital_inputs); #else INFO("FEATURE: without DIGITAL INPUTS support\n"); #endif INFO("FEATURE: DAHDI_VMWI (HVAC only)\n"); #ifdef WITH_METERING INFO("FEATURE: WITH METERING Generation\n"); #else INFO("FEATURE: NO METERING Generation\n"); #endif xproto_register(&PROTO_TABLE(FXS)); return 0; } static void __exit card_fxs_cleanup(void) { xproto_unregister(&PROTO_TABLE(FXS)); xpd_driver_unregister(&fxs_driver.driver); } MODULE_DESCRIPTION("XPP FXS Card Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_FXS); module_init(card_fxs_startup); module_exit(card_fxs_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/dahdi_debug.h0000644000175000017500000001706711045355753021760 0ustar tzafrirtzafrir#ifndef DAHDI_DEBUG_H #define DAHDI_DEBUG_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include /* for dahdi_* defs */ /* Debugging Macros */ #define PRINTK(level, category, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: " fmt, #level, category, THIS_MODULE->name, ## __VA_ARGS__) #define XBUS_PRINTK(level, category, xbus, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: %s: " fmt, #level, \ category, THIS_MODULE->name, (xbus)->busname, ## __VA_ARGS__) #define XPD_PRINTK(level, category, xpd, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: %s/%s: " fmt, #level, \ category, THIS_MODULE->name, (xpd)->xbus->busname, (xpd)->xpdname, ## __VA_ARGS__) #define LINE_PRINTK(level, category, xpd, pos, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: %s/%s/%d: " fmt, #level, \ category, THIS_MODULE->name, (xpd)->xbus->busname, (xpd)->xpdname, (pos), ## __VA_ARGS__) #define PORT_PRINTK(level, category, xbus, unit, port, fmt, ...) \ printk(KERN_ ## level "%s%s-%s: %s UNIT=%d PORT=%d: " fmt, #level, \ category, THIS_MODULE->name, (xbus)->busname, (unit), (port), ## __VA_ARGS__) #define DBG(bits, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && PRINTK(DEBUG, "-" #bits, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define INFO(fmt, ...) PRINTK(INFO, "", fmt, ## __VA_ARGS__) #define NOTICE(fmt, ...) PRINTK(NOTICE, "", fmt, ## __VA_ARGS__) #define WARNING(fmt, ...) PRINTK(WARNING, "", fmt, ## __VA_ARGS__) #define ERR(fmt, ...) PRINTK(ERR, "", fmt, ## __VA_ARGS__) #define XBUS_DBG(bits, xbus, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && XBUS_PRINTK(DEBUG, "-" #bits, xbus, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define XBUS_INFO(xbus, fmt, ...) XBUS_PRINTK(INFO, "", xbus, fmt, ## __VA_ARGS__) #define XBUS_NOTICE(xbus, fmt, ...) XBUS_PRINTK(NOTICE, "", xbus, fmt, ## __VA_ARGS__) #define XBUS_ERR(xbus, fmt, ...) XBUS_PRINTK(ERR, "", xbus, fmt, ## __VA_ARGS__) #define XPD_DBG(bits, xpd, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && XPD_PRINTK(DEBUG, "-" #bits, xpd, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define XPD_INFO(xpd, fmt, ...) XPD_PRINTK(INFO, "", xpd, fmt, ## __VA_ARGS__) #define XPD_NOTICE(xpd, fmt, ...) XPD_PRINTK(NOTICE, "", xpd, fmt, ## __VA_ARGS__) #define XPD_WARNING(xpd, fmt, ...) XPD_PRINTK(WARNING, "", xpd, fmt, ## __VA_ARGS__) #define XPD_ERR(xpd, fmt, ...) XPD_PRINTK(ERR, "", xpd, fmt, ## __VA_ARGS__) #define LINE_DBG(bits, xpd, pos, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && LINE_PRINTK(DEBUG, "-" #bits, xpd, pos, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define LINE_NOTICE(xpd, pos, fmt, ...) LINE_PRINTK(NOTICE, "", xpd, pos, fmt, ## __VA_ARGS__) #define LINE_ERR(xpd, pos, fmt, ...) LINE_PRINTK(ERR, "", xpd, pos, fmt, ## __VA_ARGS__) #define PORT_DBG(bits, xbus, unit, port, fmt, ...) \ ((void)((debug & (DBG_ ## bits)) && PORT_PRINTK(DEBUG, "-" #bits, \ xbus, unit, port, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__))) #define PORT_NOTICE(xbus, unit, port, fmt, ...) PORT_PRINTK(NOTICE, "", xbus, unit, port, fmt, ## __VA_ARGS__) #define PORT_ERR(xbus, unit, port, fmt, ...) PORT_PRINTK(ERR, "", xbus, unit, port, fmt, ## __VA_ARGS__) /* * Bits for debug */ #define DBG_GENERAL BIT(0) #define DBG_PCM BIT(1) #define DBG_LEDS BIT(2) #define DBG_SYNC BIT(3) #define DBG_SIGNAL BIT(4) #define DBG_PROC BIT(5) #define DBG_REGS BIT(6) #define DBG_DEVICES BIT(7) /* instantiation/destruction etc. */ #define DBG_COMMANDS BIT(8) /* All commands */ #define DBG_ANY (~0) void dump_poll(int debug, const char *msg, int poll); static inline char *rxsig2str(enum dahdi_rxsig sig) { switch(sig) { case DAHDI_RXSIG_ONHOOK: return "ONHOOK"; case DAHDI_RXSIG_OFFHOOK: return "OFFHOOK"; case DAHDI_RXSIG_START: return "START"; case DAHDI_RXSIG_RING: return "RING"; case DAHDI_RXSIG_INITIAL: return "INITIAL"; } return "Unknown rxsig"; } static inline char *txsig2str(enum dahdi_txsig sig) { switch(sig) { case DAHDI_TXSIG_ONHOOK: return "TXSIG_ONHOOK"; case DAHDI_TXSIG_OFFHOOK: return "TXSIG_OFFHOOK"; case DAHDI_TXSIG_START: return "TXSIG_START"; case DAHDI_TXSIG_KEWL: return "TXSIG_KEWL"; /* Drop battery if possible */ case DAHDI_TXSIG_TOTAL: break; } return "Unknown txsig"; } static inline char *event2str(int event) { switch(event) { case DAHDI_EVENT_NONE: return "NONE"; case DAHDI_EVENT_ONHOOK: return "ONHOOK"; case DAHDI_EVENT_RINGOFFHOOK: return "RINGOFFHOOK"; case DAHDI_EVENT_WINKFLASH: return "WINKFLASH"; case DAHDI_EVENT_ALARM: return "ALARM"; case DAHDI_EVENT_NOALARM: return "NOALARM"; case DAHDI_EVENT_ABORT: return "ABORT"; case DAHDI_EVENT_OVERRUN: return "OVERRUN"; case DAHDI_EVENT_BADFCS: return "BADFCS"; case DAHDI_EVENT_DIALCOMPLETE: return "DIALCOMPLETE"; case DAHDI_EVENT_RINGERON: return "RINGERON"; case DAHDI_EVENT_RINGEROFF: return "RINGEROFF"; case DAHDI_EVENT_HOOKCOMPLETE: return "HOOKCOMPLETE"; case DAHDI_EVENT_BITSCHANGED: return "BITSCHANGED"; case DAHDI_EVENT_PULSE_START: return "PULSE_START"; case DAHDI_EVENT_TIMER_EXPIRED: return "TIMER_EXPIRED"; case DAHDI_EVENT_TIMER_PING: return "TIMER_PING"; case DAHDI_EVENT_POLARITY: return "POLARITY"; } return "Unknown event"; } static inline char *hookstate2str(int hookstate) { switch(hookstate) { case DAHDI_ONHOOK: return "DAHDI_ONHOOK"; case DAHDI_START: return "DAHDI_START"; case DAHDI_OFFHOOK: return "DAHDI_OFFHOOK"; case DAHDI_WINK: return "DAHDI_WINK"; case DAHDI_FLASH: return "DAHDI_FLASH"; case DAHDI_RING: return "DAHDI_RING"; case DAHDI_RINGOFF: return "DAHDI_RINGOFF"; } return "Unknown hookstate"; } /* From dahdi-base.c */ static inline char *sig2str(int sig) { switch (sig) { case DAHDI_SIG_FXSLS: return "FXSLS"; case DAHDI_SIG_FXSKS: return "FXSKS"; case DAHDI_SIG_FXSGS: return "FXSGS"; case DAHDI_SIG_FXOLS: return "FXOLS"; case DAHDI_SIG_FXOKS: return "FXOKS"; case DAHDI_SIG_FXOGS: return "FXOGS"; case DAHDI_SIG_EM: return "E&M"; case DAHDI_SIG_EM_E1: return "E&M-E1"; case DAHDI_SIG_CLEAR: return "Clear"; case DAHDI_SIG_HDLCRAW: return "HDLCRAW"; case DAHDI_SIG_HDLCFCS: return "HDLCFCS"; case DAHDI_SIG_HDLCNET: return "HDLCNET"; case DAHDI_SIG_SLAVE: return "Slave"; case DAHDI_SIG_CAS: return "CAS"; case DAHDI_SIG_DACS: return "DACS"; case DAHDI_SIG_DACS_RBS: return "DACS+RBS"; case DAHDI_SIG_SF: return "SF (ToneOnly)"; case DAHDI_SIG_NONE: break; } return "Unconfigured"; } static inline char *alarmbit2str(int alarmbit) { /* from dahdi/kernel.h */ switch(1 << alarmbit) { case DAHDI_ALARM_NONE: return "NONE"; case DAHDI_ALARM_RECOVER: return "RECOVER"; case DAHDI_ALARM_LOOPBACK: return "LOOPBACK"; case DAHDI_ALARM_YELLOW: return "YELLOW"; case DAHDI_ALARM_RED: return "RED"; case DAHDI_ALARM_BLUE: return "BLUE"; case DAHDI_ALARM_NOTOPEN: return "NOTOPEN"; } return "UNKNOWN"; } void alarm2str(int alarm, char *buf, int buflen); #endif /* DAHDI_DEBUG_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xbus-core.h0000644000175000017500000002315111611603433021425 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifndef XBUS_CORE_H #define XBUS_CORE_H #include #include /* for tasklets */ #include #include "xpd.h" #include "xframe_queue.h" #include "xbus-pcm.h" #define MAX_BUSES 32 #define XFRAME_DATASIZE 512 /* forward declarations */ struct xbus_workqueue; #ifdef __KERNEL__ struct xbus_ops { int (*xframe_send_pcm)(xbus_t *xbus, xframe_t *xframe); int (*xframe_send_cmd)(xbus_t *xbus, xframe_t *xframe); xframe_t *(*alloc_xframe)(xbus_t *xbus, gfp_t gfp_flags); void (*free_xframe)(xbus_t *xbus, xframe_t *xframe); }; /* * XBUS statistics counters */ enum { XBUS_N_UNITS, XBUS_N_TX_XFRAME_PCM, XBUS_N_RX_XFRAME_PCM, XBUS_N_TX_PACK_PCM, XBUS_N_RX_PACK_PCM, XBUS_N_TX_BYTES, XBUS_N_RX_BYTES, XBUS_N_TX_PCM_FRAG, XBUS_N_RX_CMD, XBUS_N_TX_CMD, }; #define XBUS_COUNTER(xbus, counter) ((xbus)->counters[XBUS_N_ ## counter]) #define C_(x) [ XBUS_N_ ## x ] = { #x } /* yucky, make an instance so we can size it... */ static struct xbus_counters { char *name; } xbus_counters[] = { C_(UNITS), C_(TX_XFRAME_PCM), C_(RX_XFRAME_PCM), C_(TX_PACK_PCM), C_(RX_PACK_PCM), C_(TX_BYTES), C_(RX_BYTES), C_(TX_PCM_FRAG), C_(RX_CMD), C_(TX_CMD), }; #undef C_ #define XBUS_COUNTER_MAX ARRAY_SIZE(xbus_counters) enum xbus_state { XBUS_STATE_START, XBUS_STATE_IDLE, XBUS_STATE_SENT_REQUEST, XBUS_STATE_RECVD_DESC, XBUS_STATE_READY, XBUS_STATE_DEACTIVATING, XBUS_STATE_DEACTIVATED, XBUS_STATE_FAIL, }; const char *xbus_statename(enum xbus_state st); struct xbus_transport { struct xbus_ops *ops; void *priv; struct device *transport_device; ushort max_send_size; enum xbus_state xbus_state; unsigned long transport_flags; spinlock_t state_lock; atomic_t transport_refcount; wait_queue_head_t transport_unused; spinlock_t lock; }; #define MAX_SEND_SIZE(xbus) ((xbus)->transport.max_send_size) #define XBUS_STATE(xbus) ((xbus)->transport.xbus_state) #define XBUS_IS(xbus, st) (XBUS_STATE(xbus) == XBUS_STATE_ ## st) #define TRANSPORT_EXIST(xbus) ((xbus)->transport.ops != NULL) #define XBUS_FLAG_CONNECTED 0 #define XBUS_FLAGS(xbus, flg) test_bit(XBUS_FLAG_ ## flg, &((xbus)->transport.transport_flags)) struct xbus_ops *transportops_get(xbus_t *xbus); void transportops_put(xbus_t *xbus); /* * Encapsulate all poll related data of a single xbus. */ struct xbus_workqueue { struct workqueue_struct *wq; struct work_struct xpds_init_work; bool xpds_init_done; struct list_head card_list; int num_units; int num_units_initialized; wait_queue_head_t wait_for_xpd_initialization; spinlock_t worker_lock; struct semaphore running_initialization; }; /* * Allocate/Free an xframe from pools of empty xframes. * Calls to {get,put}_xframe are wrapped in * the macros bellow, so we take/return it * to the correct pool. */ xframe_t *get_xframe(struct xframe_queue *q); void put_xframe(struct xframe_queue *q, xframe_t *xframe); #define ALLOC_SEND_XFRAME(xbus) get_xframe(&(xbus)->send_pool) #define ALLOC_RECV_XFRAME(xbus) get_xframe(&(xbus)->receive_pool) #define FREE_SEND_XFRAME(xbus, xframe) put_xframe(&(xbus)->send_pool, (xframe)) #define FREE_RECV_XFRAME(xbus, xframe) put_xframe(&(xbus)->receive_pool, (xframe)) xbus_t *xbus_num(uint num); xbus_t *get_xbus(const char *msg, uint num); void put_xbus(const char *msg, xbus_t *xbus); int refcount_xbus(xbus_t *xbus); /* * Echo canceller related data */ #define ECHO_TIMESLOTS 128 struct echoops { int (*ec_set)(xpd_t *xpd, int pos, bool on); int (*ec_get)(xpd_t *xpd, int pos); int (*ec_update)(xbus_t *xbus); void (*ec_dump)(xbus_t *xbus); }; struct xbus_echo_state { const struct echoops *echoops; byte timeslots[ECHO_TIMESLOTS]; int xpd_idx; struct device_attribute *da[MAX_XPDS]; }; #define ECHOOPS(xbus) ((xbus)->echo_state.echoops) #define EC_METHOD(name, xbus) (ECHOOPS(xbus)->name) #define CALL_EC_METHOD(name, xbus, ...) (EC_METHOD(name, (xbus))(__VA_ARGS__)) /* * An xbus is a transport layer for Xorcom Protocol commands */ struct xbus { char busname[XBUS_NAMELEN]; /* set by xbus_new() */ /* low-level bus drivers set these 2 fields */ char connector[XBUS_DESCLEN]; char label[LABEL_SIZE]; byte revision; /* Protocol revision */ struct xbus_transport transport; int num; struct xpd *xpds[MAX_XPDS]; struct xbus_echo_state echo_state; int command_tick_counter; int usec_nosend; /* Firmware flow control */ struct xframe_queue command_queue; wait_queue_head_t command_queue_empty; struct xframe_queue send_pool; /* empty xframes for send */ struct xframe_queue receive_pool; /* empty xframes for receive */ /* tasklet processing */ struct xframe_queue receive_queue; struct tasklet_struct receive_tasklet; int cpu_rcv_intr[NR_CPUS]; int cpu_rcv_tasklet[NR_CPUS]; struct quirks { unsigned int has_fxo:1; unsigned int has_digital_span:1; } quirks; bool self_ticking; enum sync_mode sync_mode; /* Managed by low-level drivers: */ enum sync_mode sync_mode_default; struct timer_list command_timer; unsigned int xbus_frag_count; struct xframe_queue pcm_tospan; struct xpp_ticker ticker; /* for tick rate */ struct xpp_drift drift; /* for tick offset */ atomic_t pcm_rx_counter; unsigned int global_counter; /* Device-Model */ struct device astribank; #define dev_to_xbus(dev) container_of(dev, struct xbus, astribank) struct kref kref; #define kref_to_xbus(k) container_of(k, struct xbus, kref) spinlock_t lock; /* PCM metrics */ struct timeval last_tx_sync; struct timeval last_rx_sync; unsigned long max_tx_sync; unsigned long min_tx_sync; unsigned long max_rx_sync; unsigned long min_rx_sync; unsigned long max_rx_process; /* packet processing time (usec) */ #ifdef SAMPLE_TICKS #define SAMPLE_SIZE 1000 int sample_ticks[SAMPLE_SIZE]; bool sample_running; int sample_pos; #endif struct xbus_workqueue worker; /* * Sync adjustment */ int sync_adjustment; int sync_adjustment_offset; long pll_updated_at; atomic_t num_xpds; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_xbus_dir; struct proc_dir_entry *proc_xbus_summary; #ifdef PROTOCOL_DEBUG struct proc_dir_entry *proc_xbus_command; #endif #endif /* statistics */ int counters[XBUS_COUNTER_MAX]; }; #endif #define XFRAME_MAGIC 123456L struct xframe { unsigned long xframe_magic; struct list_head frame_list; atomic_t frame_len; xbus_t *xbus; struct timeval tv_created; struct timeval tv_queued; struct timeval tv_submitted; struct timeval tv_received; /* filled by transport layer */ size_t frame_maxlen; byte *packets; /* max XFRAME_DATASIZE */ byte *first_free; int usec_towait; /* prevent overflowing AB */ void *priv; }; void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv); #define XFRAME_LEN(frame) atomic_read(&(frame)->frame_len) int xbus_core_init(void); /* Initializer */ void xbus_core_shutdown(void); /* Terminator */ /* Frame handling */ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug); int send_cmd_frame(xbus_t *xbus, xframe_t *xframe); /* * Return pointer to next packet slot in the frame * or NULL if the frame is full. */ xpacket_t *xframe_next_packet(xframe_t *xframe, int len); /* XBUS handling */ /* * Map: unit+subunit <--> index in xbus->xpds[] */ #define XPD_IDX(unit,subunit) ((unit) * MAX_SUBUNIT + (subunit)) #define XBUS_UNIT(idx) ((idx) / MAX_SUBUNIT) #define XBUS_SUBUNIT(idx) ((idx) % MAX_SUBUNIT) xpd_t *xpd_of(const xbus_t *xbus, int xpd_num); xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit); int xbus_check_unique(xbus_t *xbus); bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate); bool xbus_setflags(xbus_t *xbus, int flagbit, bool on); xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); void xbus_free(xbus_t *xbus); int xbus_connect(xbus_t *xbus); int xbus_activate(xbus_t *xbus); void xbus_deactivate(xbus_t *xbus); void xbus_disconnect(xbus_t *xbus); void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe); int xbus_process_worker(xbus_t *xbus); int waitfor_xpds(xbus_t *xbus, char *buf); int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit); int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd); /* sysfs */ int xpd_device_register(xbus_t *xbus, xpd_t *xpd); void xpd_device_unregister(xpd_t *xpd); int echocancel_xpd(xpd_t *xpd, int on); int xpp_driver_init(void); void xpp_driver_exit(void); int xbus_sysfs_transport_create(xbus_t *xbus); void xbus_sysfs_transport_remove(xbus_t *xbus); int xbus_sysfs_create(xbus_t *xbus); void xbus_sysfs_remove(xbus_t *xbus); #ifdef OLD_HOTPLUG_SUPPORT_269 /* Copy from new kernels lib/kobject_uevent.c */ enum kobject_action { KOBJ_ADD, KOBJ_REMOVE, KOBJ_CHANGE, KOBJ_MOUNT, KOBJ_UMOUNT, KOBJ_OFFLINE, KOBJ_ONLINE, }; #endif void astribank_uevent_send(xbus_t *xbus, enum kobject_action act); #endif /* XBUS_CORE_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xpd.h0000644000175000017500000001622411602416004020310 0ustar tzafrirtzafrir#ifndef XPD_H #define XPD_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xdefs.h" #include "xproto.h" #ifdef __KERNEL__ #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #include #else #include #endif #include #endif /* __KERNEL__ */ #include #ifdef __KERNEL__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* also added in RHEL kernels with the OpenInfiniband backport: */ #if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,9) || !defined(DEFINE_SPINLOCK) typedef unsigned gfp_t; /* Added in 2.6.14 */ #endif #endif /* * FIXME: Kludge for 2.6.19 * bool is now defined as a proper boolean type (gcc _Bool) * but the command line parsing framework handles it as int. */ #define DEF_PARM_BOOL(name,init,perm,desc) \ int name = init; \ module_param(name, bool, perm); \ MODULE_PARM_DESC(name, desc " [default " #init "]") #define DEF_PARM(type,name,init,perm,desc) \ type name = init; \ module_param(name, type, perm); \ MODULE_PARM_DESC(name, desc " [default " #init "]") #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) /* * Old 2.6 kernels had module_param_array() macro that receive the counter * by value. */ #define DEF_ARRAY(type,name,count,init,desc) \ unsigned int name ## _num_values; \ type name[count] = { [0 ... ((count)-1)] = (init) }; \ module_param_array(name, type, name ## _num_values, 0644); \ MODULE_PARM_DESC(name, desc " ( 1-" __MODULE_STRING(count) ")") #else #define DEF_ARRAY(type,name,count,init,desc) \ unsigned int name ## _num_values; \ type name[count] = {[0 ... ((count)-1)] = init}; \ module_param_array(name, type, &name ## _num_values, 0644); \ MODULE_PARM_DESC(name, desc " ( 1-" __MODULE_STRING(count) ")") #endif #endif // __KERNEL__ #define CARD_DESC_MAGIC 0xca9dde5c struct card_desc_struct { struct list_head card_list; u32 magic; byte type; /* LSB: 1 - to_phone, 0 - to_line */ byte subtype; struct xpd_addr xpd_addr; byte numchips; byte ports_per_chip; byte ports; byte port_dir; struct xpd_addr ec_addr; /* echo canceler address */ }; typedef enum xpd_direction { TO_PSTN = 0, TO_PHONE = 1, } xpd_direction_t; #ifdef __KERNEL__ /* * XPD statistics counters */ enum { XPD_N_PCM_READ, XPD_N_PCM_WRITE, XPD_N_RECV_ERRORS, }; #define XPD_COUNTER(xpd, counter) ((xpd)->counters[XPD_N_ ## counter]) #define C_(x) [ XPD_N_ ## x ] = { #x } /* yucky, make an instance so we can size it... */ static struct xpd_counters { char *name; } xpd_counters[] = { C_(PCM_READ), C_(PCM_WRITE), C_(RECV_ERRORS), }; #undef C_ #define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0])) enum xpd_state { XPD_STATE_START, XPD_STATE_INIT_REGS, XPD_STATE_READY, XPD_STATE_NOHW, }; bool xpd_setstate(xpd_t *xpd, enum xpd_state newstate); const char *xpd_statename(enum xpd_state st); #define PHONEDEV(xpd) ((xpd)->phonedev) #define IS_PHONEDEV(xpd) (PHONEDEV(xpd).phoneops) struct phonedev { const struct phoneops *phoneops; /* Card level operations */ struct dahdi_span span; struct dahdi_chan *chans[32]; #define XPD_CHAN(xpd,chan) (PHONEDEV(xpd).chans[(chan)]) struct dahdi_echocan_state *ec[32]; int channels; xpd_direction_t direction; /* TO_PHONE, TO_PSTN */ xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */ xpp_line_t offhook_state; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */ xpp_line_t oht_pcm_pass; /* Transfer on-hook PCM */ /* Voice Mail Waiting Indication: */ unsigned int msg_waiting[CHANNELS_PERXPD]; xpp_line_t digital_outputs; /* 0 - no, 1 - yes */ xpp_line_t digital_inputs; /* 0 - no, 1 - yes */ xpp_line_t digital_signalling; /* BRI signalling channels */ uint timing_priority; /* from 'span' directives in chan_dahdi.conf */ /* Assure atomicity of changes to pcm_len and wanted_pcm_mask */ spinlock_t lock_recompute_pcm; /* maintained by card drivers */ uint pcm_len; /* allocation length of PCM packet (dynamic) */ xpp_line_t wanted_pcm_mask; xpp_line_t silence_pcm; /* inject silence during next tick */ xpp_line_t mute_dtmf; bool ringing[CHANNELS_PERXPD]; atomic_t dahdi_registered; /* Am I fully registered with dahdi */ atomic_t open_counter; /* Number of open channels */ /* Echo cancelation */ u_char ec_chunk1[CHANNELS_PERXPD][DAHDI_CHUNKSIZE]; u_char ec_chunk2[CHANNELS_PERXPD][DAHDI_CHUNKSIZE]; }; /* * An XPD is a single Xorcom Protocol Device */ struct xpd { char xpdname[XPD_NAMELEN]; struct phonedev phonedev; const struct xops *xops; xpd_type_t type; const char *type_name; byte subtype; int subunits; /* all siblings */ enum xpd_state xpd_state; struct device xpd_dev; #define dev_to_xpd(dev) container_of(dev, struct xpd, xpd_dev) struct kref kref; #define kref_to_xpd(k) container_of(k, struct xpd, kref) xbus_t *xbus; /* The XBUS we are connected to */ struct device *echocancel; spinlock_t lock; int flags; unsigned long blink_mode; /* bitmask of blinking ports */ #define DEFAULT_LED_PERIOD (1000/8) /* in tick */ #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_xpd_dir; struct proc_dir_entry *proc_xpd_summary; #endif int counters[XPD_COUNTER_MAX]; const xproto_table_t *xproto; /* Card level protocol table */ void *priv; /* Card level private data */ bool card_present; reg_cmd_t requested_reply; reg_cmd_t last_reply; unsigned long last_response; /* in jiffies */ unsigned xbus_idx; /* index in xbus->xpds[] */ struct xpd_addr addr; struct list_head xpd_list; unsigned int timer_count; }; #define for_each_line(xpd,i) for((i) = 0; (i) < PHONEDEV(xpd).channels; (i)++) #define IS_BRI(xpd) ((xpd)->type == XPD_TYPE_BRI) #define TICK_TOLERANCE 500 /* usec */ #ifdef DEBUG_SYNC_PARPORT void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1); #else #define xbus_flip_bit(xbus, bitnum0, bitnum1) #endif static inline void *my_kzalloc(size_t size, gfp_t flags) { void *p; p = kmalloc(size, flags); if(p) memset(p, 0, size); return p; } struct xpd_driver { xpd_type_t type; struct device_driver driver; #define driver_to_xpd_driver(driver) container_of(driver, struct xpd_driver, driver) }; int xpd_driver_register(struct device_driver *driver); void xpd_driver_unregister(struct device_driver *driver); xpd_t *get_xpd(const char *msg, xpd_t *xpd); void put_xpd(const char *msg, xpd_t *xpd); int refcount_xpd(xpd_t *xpd); #endif #endif /* XPD_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/Changelog_xpp0000644000175000017500000000270411152512007022043 0ustar tzafrirtzafrirSun Mar 1 2009 Oron Peled - xpp.r6795 * Fix cases where the command_queue overflowed during initialization. - Also add a 'command_queue_length' parameter to xpp.ko * More migrations to sysfs: - Add a 'transport' attribute to our astribank devices which points to the usb device we use. E.g: /sys/bus/astribanks/devices/xbus-00/transport is symlinked to ../../../../../../devices/pci0000:00/0000:00:10.4/usb5/5-4 - Move /proc/xpp/XBUS-??/XPD-??/span to /sys/bus/xpds/devices/??:?:?/span - Migrate from /proc/xpp/sync to: /sys/bus/astribanks/drivers/xppdrv/sync - New 'offhook' attribute in: /sys/bus/xpds/devices/??:?:?/offhook * PRI: change the "timing" priority to match the convention used by other PRI cards -- I.e: lower numbers (not 0) have higher priority. * FXO: - Power denial: create two module parameters instead of hard-coded constants (power_denial_safezone, power_denial_minlen). For sites that get non-standard power-denial signals from central office on offhook. - Don't hangup on power-denial, just notify Dahdi and wait for - Fix caller-id detection for the case central office sends it before first ring without any indication before. Asterisk's desicion. * USB_FW.hex: - Fixes cases where firmware loading would fail. Thu, Aug 14 2008 Oron Peled - xpp.r6056 * First DAHDI-linux release. dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_pri.c0000644000175000017500000021076411611603403021301 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * Parts derived from Cologne demo driver for the chip. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include "xpd.h" #include "xproto.h" #include "xpp_dahdi.h" #include "card_pri.h" #include "dahdi_debug.h" #include "xbus-core.h" static const char rcsid[] = "$Id: card_pri.c 10053 2011-07-20 16:49:07Z tzafrir $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); #define PRI_LINES_BITMASK BITMASK(31) #define PRI_SIGCAP ( \ DAHDI_SIG_EM | \ DAHDI_SIG_CLEAR | \ DAHDI_SIG_FXSLS | \ DAHDI_SIG_FXSGS | \ DAHDI_SIG_FXSKS | \ DAHDI_SIG_HARDHDLC | \ DAHDI_SIG_MTP2 | \ DAHDI_SIG_FXOLS | \ DAHDI_SIG_FXOGS | \ DAHDI_SIG_FXOKS | \ DAHDI_SIG_CAS | \ DAHDI_SIG_EM_E1 | \ DAHDI_SIG_DACS_RBS \ ) static bool is_sigtype_dchan(int sigtype) { if((sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW) return 1; if((sigtype & DAHDI_SIG_HDLCFCS) == DAHDI_SIG_HDLCFCS) return 1; if((sigtype & DAHDI_SIG_HARDHDLC) == DAHDI_SIG_HARDHDLC) return 1; return 0; } #define MAX_SLAVES 4 /* we have MUX of 4 clocks */ #define PRI_PORT(xpd) ((xpd)->addr.subunit) #define CHAN_PER_REGS(p) (((p)->is_esf) ? 2 : 4) /*---------------- PRI Protocol Commands ----------------------------------*/ static bool pri_packet_is_valid(xpacket_t *pack); static void pri_packet_dump(const char *msg, xpacket_t *pack); static int pri_startup(struct file *file, struct dahdi_span *span); static int pri_shutdown(struct dahdi_span *span); static int pri_rbsbits(struct dahdi_chan *chan, int bits); static int pri_lineconfig(xpd_t *xpd, int lineconfig); static void send_idlebits(xpd_t *xpd, bool saveold); #define PROC_REGISTER_FNAME "slics" enum pri_protocol { PRI_PROTO_0 = 0, PRI_PROTO_E1 = 1, PRI_PROTO_T1 = 2, PRI_PROTO_J1 = 3 }; static const char *pri_protocol_name(enum pri_protocol pri_protocol) { static const char *protocol_names[] = { [PRI_PROTO_0] = "??", /* unknown */ [PRI_PROTO_E1] = "E1", [PRI_PROTO_T1] = "T1", [PRI_PROTO_J1] = "J1" }; return protocol_names[pri_protocol]; } static int pri_num_channels(enum pri_protocol pri_protocol) { static int num_channels[] = { [PRI_PROTO_0] = 0, [PRI_PROTO_E1] = 31, [PRI_PROTO_T1] = 24, [PRI_PROTO_J1] = 0 }; return num_channels[pri_protocol]; } static const char *type_name(enum pri_protocol pri_protocol) { static const char *names[4] = { [PRI_PROTO_0] = "PRI-Unknown", [PRI_PROTO_E1] = "E1", [PRI_PROTO_T1] = "T1", [PRI_PROTO_J1] = "J1" }; return names[pri_protocol]; } static int pri_linecompat(enum pri_protocol pri_protocol) { static const int linecompat[] = { [PRI_PROTO_0] = 0, [PRI_PROTO_E1] = /* coding */ DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4 | /* framing */ DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3, [PRI_PROTO_T1] = /* coding */ DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF | /* framing */ DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS, [PRI_PROTO_J1] = 0 }; DBG(GENERAL, "pri_linecompat: pri_protocol=%d\n", pri_protocol); return linecompat[pri_protocol]; } #define PRI_DCHAN_IDX(priv) ((priv)->dchan_num - 1) enum pri_led_state { PRI_LED_OFF = 0x0, PRI_LED_ON = 0x1, /* * We blink by software from driver, so that * if the driver malfunction that blink would stop. */ // PRI_LED_BLINK_SLOW = 0x2, /* 1/2 a second blink cycle */ // PRI_LED_BLINK_FAST = 0x3 /* 1/4 a second blink cycle */ }; enum pri_led_selectors { BOTTOM_RED_LED = 0, BOTTOM_GREEN_LED = 1, TOP_RED_LED = 2, TOP_GREEN_LED = 3, }; #define NUM_LEDS 4 struct pri_leds { byte state:2; /* enum pri_led_state */ byte led_sel:2; /* enum pri_led_selectors */ byte reserved:4; }; #define REG_CCB1_T 0x2F /* Clear Channel Register 1 */ #define REG_FRS0 0x4C /* Framer Receive Status Register 0 */ #define REG_FRS0_T1_FSR BIT(0) /* T1 - Frame Search Restart Flag */ #define REG_FRS0_LMFA BIT(1) /* Loss of Multiframe Alignment */ #define REG_FRS0_E1_NMF BIT(2) /* E1 - No Multiframe Alignment Found */ #define REG_FRS0_RRA BIT(4) /* Receive Remote Alarm: T1-YELLOW-Alarm */ #define REG_FRS0_LFA BIT(5) /* Loss of Frame Alignment */ #define REG_FRS0_AIS BIT(6) /* Alarm Indication Signal: T1-BLUE-Alarm */ #define REG_FRS0_LOS BIT(7) /* Los Of Signal: T1-RED-Alarm */ #define REG_FRS1 0x4D /* Framer Receive Status Register 1 */ #define REG_LIM0 0x36 #define REG_LIM0_MAS BIT(0) /* Master Mode, DCO-R circuitry is frequency synchronized to the clock supplied by SYNC */ #define REG_LIM0_RTRS BIT(5) /* * Receive Termination Resistance Selection: * integrated resistor to create 75 Ohm termination (100 || 300 = 75) * 0 = 100 Ohm * 1 = 75 Ohm */ #define REG_LIM0_LL BIT(1) /* LL (Local Loopback) */ #define REG_FMR0 0x1C #define REG_FMR0_E_RC0 BIT(4) /* Receive Code - LSB */ #define REG_FMR0_E_RC1 BIT(5) /* Receive Code - MSB */ #define REG_FMR0_E_XC0 BIT(6) /* Transmit Code - LSB */ #define REG_FMR0_E_XC1 BIT(7) /* Transmit Code - MSB */ #define REG_FMR1 0x1D #define REG_FMR1_XAIS BIT(0) /* Transmit AIS toward transmit end */ #define REG_FMR1_SSD0 BIT(1) #define REG_FMR1_ECM BIT(2) #define REG_FMR1_T_CRC BIT(3) /* Enable CRC6 */ #define REG_FMR1_E_XFS BIT(3) /* Transmit Framing Select */ #define REG_FMR1_PMOD BIT(4) /* E1 = 0, T1/J1 = 1 */ #define REG_FMR1_EDL BIT(5) #define REG_FMR1_AFR BIT(6) #define REG_FMR2 0x1E #define REG_FMR2_E_ALMF BIT(0) /* Automatic Loss of Multiframe */ #define REG_FMR2_T_EXZE BIT(0) /* Excessive Zeros Detection Enable */ #define REG_FMR2_E_AXRA BIT(1) /* Automatic Transmit Remote Alarm */ #define REG_FMR2_T_AXRA BIT(1) /* Automatic Transmit Remote Alarm */ #define REG_FMR2_E_PLB BIT(2) /* Payload Loop-Back */ #define REG_FMR2_E_RFS0 BIT(6) /* Receive Framing Select - LSB */ #define REG_FMR2_E_RFS1 BIT(7) /* Receive Framing Select - MSB */ #define REG_FMR2_T_SSP BIT(5) /* Select Synchronization/Resynchronization Procedure */ #define REG_FMR2_T_MCSP BIT(6) /* Multiple Candidates Synchronization Procedure */ #define REG_FMR2_T_AFRS BIT(7) /* Automatic Force Resynchronization */ #define REG_FMR3 0x31 #define REG_FMR3_EXTIW BIT(0) /* Extended CRC4 to Non-CRC4 Interworking */ #define REG_FMR4 0x20 #define REG_FMR4_FM0 BIT(0) #define REG_FMR4_FM1 BIT(1) #define REG_FMR4_AUTO BIT(2) #define REG_FMR4_SSC0 BIT(3) #define REG_FMR4_SSC1 BIT(4) #define REG_FMR4_XRA BIT(5) /* Transmit Remote Alarm (Yellow Alarm) */ #define REG_FMR4_TM BIT(6) #define REG_FMR4_AIS3 BIT(7) #define REG_XSW_E 0x20 #define REG_XSW_E_XY4 BIT(0) #define REG_XSW_E_XY3 BIT(1) #define REG_XSW_E_XY2 BIT(2) #define REG_XSW_E_XY1 BIT(3) #define REG_XSW_E_XY0 BIT(4) #define REG_XSW_E_XRA BIT(5) /* Transmit Remote Alarm (Yellow Alarm) */ #define REG_XSW_E_XTM BIT(6) #define REG_XSW_E_XSIS BIT(7) #define REG_XSP_E 0x21 #define REG_FMR5_T 0x21 #define REG_XSP_E_XSIF BIT(2) /* Transmit Spare Bit For International Use (FAS Word) */ #define REG_FMR5_T_XTM BIT(2) /* Transmit Transparent Mode */ #define REG_XSP_E_AXS BIT(3) /* Automatic Transmission of Submultiframe Status */ #define REG_XSP_E_EBP BIT(4) /* E-Bit Polarity, Si-bit position of every outgoing CRC multiframe */ #define REG_XSP_E_CASEN BIT(6) /* CAS: Channel Associated Signaling Enable */ #define REG_FMR5_T_EIBR BIT(6) /* CAS: Enable Internal Bit Robbing Access */ #define REG_XC0_T 0x22 /* Transmit Control 0 */ #define REG_XC0_BRIF BIT(5) /* Bit Robbing Idle Function */ #define REG_CMDR_E 0x02 /* Command Register */ #define REG_CMDR_RRES BIT(6) /* Receiver reset */ #define REG_CMDR_XRES BIT(4) /* Transmitter reset */ #define REG_RC0 0x24 #define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */ #define REG_CMR1 0x44 #define REG_CMR1_DRSS (BIT(7) | BIT(6)) #define REG_CMR1_RS (BIT(5) | BIT(4)) #define REG_CMR1_STF BIT(2) #define REG_RS1_E 0x70 /* Receive CAS Register 1 */ #define REG_RS2_E 0x71 /* Receive CAS Register 2 */ #define REG_RS3_E 0x72 /* Receive CAS Register 3 */ #define REG_RS4_E 0x73 /* Receive CAS Register 4 */ #define REG_RS5_E 0x74 /* Receive CAS Register 5 */ #define REG_RS6_E 0x75 /* Receive CAS Register 6 */ #define REG_RS7_E 0x76 /* Receive CAS Register 7 */ #define REG_RS8_E 0x77 /* Receive CAS Register 8 */ #define REG_RS9_E 0x78 /* Receive CAS Register 9 */ #define REG_RS10_E 0x79 /* Receive CAS Register 10 */ #define REG_RS11_E 0x7A /* Receive CAS Register 11 */ #define REG_RS12_E 0x7B /* Receive CAS Register 12 */ #define REG_RS13_E 0x7C /* Receive CAS Register 13 */ #define REG_RS14_E 0x7D /* Receive CAS Register 14 */ #define REG_RS15_E 0x7E /* Receive CAS Register 15 */ #define REG_RS16_E 0x7F /* Receive CAS Register 16 */ #define REG_PC2 0x81 /* Port Configuration 2 */ #define REG_PC3 0x82 /* Port Configuration 3 */ #define REG_PC4 0x83 /* Port Configuration 4 */ #define REG_XPM2 0x28 /* Transmit Pulse Mask 2 */ #define VAL_PC_SYPR 0x00 /* Synchronous Pulse Receive (Input, low active) */ #define VAL_PC_GPI 0x90 /* General purpose input */ #define VAL_PC_GPOH 0x0A /* General Purpose Output, high level */ #define VAL_PC_GPOL 0x0B /* General Purpose Output, low level */ #define NUM_CAS_RS_E (REG_RS16_E - REG_RS2_E + 1) /* and of those, the ones used in T1: */ #define NUM_CAS_RS_T (REG_RS12_E - REG_RS1_E + 1) struct PRI_priv_data { bool clock_source; enum pri_protocol pri_protocol; xpp_line_t rbslines; int deflaw; unsigned int dchan_num; bool initialized; int is_cas; unsigned int chanconfig_dchan; #define NO_DCHAN (0) #define DCHAN(p) ((p)->chanconfig_dchan) #define VALID_DCHAN(p) (DCHAN(p) != NO_DCHAN) #define SET_DCHAN(p,d) do { DCHAN(p) = (d); } while(0); byte cas_rs_e[NUM_CAS_RS_E]; byte cas_ts_e[NUM_CAS_RS_E]; uint cas_replies; bool is_esf; bool local_loopback; uint poll_noreplies; uint layer1_replies; byte reg_frs0; byte reg_frs1; bool layer1_up; int alarms; byte dchan_tx_sample; byte dchan_rx_sample; uint dchan_tx_counter; uint dchan_rx_counter; bool dchan_alive; uint dchan_alive_ticks; enum pri_led_state ledstate[NUM_LEDS]; }; static xproto_table_t PROTO_TABLE(PRI); DEF_RPACKET_DATA(PRI, SET_LED, /* Set one of the LED's */ struct pri_leds pri_leds; ); static /* 0x33 */ DECLARE_CMD(PRI, SET_LED, enum pri_led_selectors led_sel, enum pri_led_state to_led_state); #define DO_LED(xpd, which, tostate) \ CALL_PROTO(PRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate)) /*---------------- PRI: Methods -------------------------------------------*/ static int query_subunit(xpd_t *xpd, byte regnum) { XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X\n", xpd->addr.unit, xpd->addr.subunit, regnum); return xpp_register_request( xpd->xbus, xpd, PRI_PORT(xpd), /* portno */ 0, /* writing */ regnum, 0, /* do_subreg */ 0, /* subreg */ 0, /* data_L */ 0, /* do_datah */ 0, /* data_H */ 0 /* should_reply */ ); } static int write_subunit(xpd_t *xpd, byte regnum, byte val) { XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X dataL=0x%02X\n", xpd->addr.unit, xpd->addr.subunit, regnum, val); return xpp_register_request( xpd->xbus, xpd, PRI_PORT(xpd), /* portno */ 1, /* writing */ regnum, 0, /* do_subreg */ 0, /* subreg */ val, /* data_L */ 0, /* do_datah */ 0, /* data_H */ 0 /* should_reply */ ); } static int pri_write_reg(xpd_t *xpd, int regnum, byte val) { XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X dataL=0x%02X\n", xpd->addr.unit, xpd->addr.subunit, regnum, val); return xpp_register_request( xpd->xbus, xpd, 0, /* portno=0 */ 1, /* writing */ regnum, 0, /* do_subreg */ 0, /* subreg */ val, /* data_L */ 0, /* do_datah */ 0, /* data_H */ 0 /* should_reply */ ); } static int cas_regbase(xpd_t *xpd) { struct PRI_priv_data *priv; priv = xpd->priv; switch (priv->pri_protocol) { case PRI_PROTO_E1: return REG_RS2_E; case PRI_PROTO_T1: /* fall-through */ case PRI_PROTO_J1: return REG_RS1_E; case PRI_PROTO_0: /* fall-through */ ; } BUG(); return 0; } static int cas_numregs(xpd_t *xpd) { struct PRI_priv_data *priv; priv = xpd->priv; switch (priv->pri_protocol) { case PRI_PROTO_E1: return NUM_CAS_RS_E; case PRI_PROTO_T1: /* fall-through */ case PRI_PROTO_J1: return NUM_CAS_RS_T; case PRI_PROTO_0: /* fall-through */ ; } BUG(); return 0; } static int write_cas_reg(xpd_t *xpd, int rsnum, byte val) { struct PRI_priv_data *priv; int regbase = cas_regbase(xpd); int num_cas_rs = cas_numregs(xpd); int regnum; bool is_d4 = 0; BUG_ON(!xpd); priv = xpd->priv; if ((priv->pri_protocol == PRI_PROTO_T1) && !priv->is_esf) { /* same data should be copied to RS7..12 in D4 only */ is_d4 = 1; } if (rsnum < 0 || rsnum >= num_cas_rs) { XPD_ERR(xpd, "RBS(TX): rsnum=%d\n", rsnum); BUG(); } regnum = regbase + rsnum; priv->cas_ts_e[rsnum] = val; XPD_DBG(SIGNAL, xpd, "RBS(TX): reg=0x%X val=0x%02X\n", regnum, val); write_subunit(xpd, regbase + rsnum, val); if (is_d4) { /* same data should be copied to RS7..12 in D4 only */ regnum = REG_RS7_E + rsnum; XPD_DBG(SIGNAL, xpd, "RBS(TX): reg=0x%X val=0x%02X\n", regnum, val); write_subunit(xpd, regnum, val); } return 0; } static bool valid_pri_modes(const xpd_t *xpd) { struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; if( priv->pri_protocol != PRI_PROTO_E1 && priv->pri_protocol != PRI_PROTO_T1 && priv->pri_protocol != PRI_PROTO_J1) return 0; return 1; } static void PRI_card_pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask) { struct PRI_priv_data *priv; int i; int line_count = 0; unsigned long flags; uint pcm_len; BUG_ON(!xpd); priv = xpd->priv; spin_lock_irqsave(&PHONEDEV(xpd).lock_recompute_pcm, flags); //XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask); /* Add/remove all the trivial cases */ pcm_mask |= PHONEDEV(xpd).offhook_state; for_each_line(xpd, i) if (IS_SET(pcm_mask, i)) line_count++; if(priv->is_cas) { if(priv->pri_protocol == PRI_PROTO_E1) { /* CAS: Don't send PCM to D-Channel */ line_count--; pcm_mask &= ~BIT(PRI_DCHAN_IDX(priv)); } } /* * FIXME: Workaround a bug in sync code of the Astribank. * Send dummy PCM for sync. */ if (xpd->addr.unit == 0 && pcm_mask == 0) { pcm_mask = BIT(0); line_count = 1; } pcm_len = (line_count) ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE : 0L; update_wanted_pcm_mask(xpd, pcm_mask, pcm_len); spin_unlock_irqrestore(&PHONEDEV(xpd).lock_recompute_pcm, flags); } /* * Set E1/T1/J1 * May only be called on unregistered xpd's * (the span and channel description are set according to this) */ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) { struct PRI_priv_data *priv; int deflaw; unsigned int dchan_num; int default_lineconfig = 0; int ret; BUG_ON(!xpd); priv = xpd->priv; if(SPAN_REGISTERED(xpd)) { XPD_NOTICE(xpd, "Registered as span %d. Cannot do setup pri protocol (%s)\n", PHONEDEV(xpd).span.spanno, __FUNCTION__); return -EBUSY; } if(priv->pri_protocol != PRI_PROTO_0) { if(priv->pri_protocol == set_proto) { XPD_NOTICE(xpd, "Already in protocol %s. Ignored\n", pri_protocol_name(set_proto)); return 0; } else { XPD_INFO(xpd, "Switching from %s to %s\n", pri_protocol_name(priv->pri_protocol), pri_protocol_name(set_proto)); } } switch(set_proto) { case PRI_PROTO_E1: deflaw = DAHDI_LAW_ALAW; dchan_num = 16; default_lineconfig = DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4 | DAHDI_CONFIG_HDB3; break; case PRI_PROTO_T1: deflaw = DAHDI_LAW_MULAW; dchan_num = 24; default_lineconfig = DAHDI_CONFIG_ESF | DAHDI_CONFIG_B8ZS; break; case PRI_PROTO_J1: /* * Check all assumptions */ deflaw = DAHDI_LAW_MULAW; dchan_num = 24; default_lineconfig = 0; /* FIXME: J1??? */ XPD_NOTICE(xpd, "J1 is not supported yet\n"); return -ENOSYS; default: XPD_ERR(xpd, "%s: Unknown pri protocol = %d\n", __FUNCTION__, set_proto); return -EINVAL; } priv->pri_protocol = set_proto; priv->is_cas = -1; PHONEDEV(xpd).channels = pri_num_channels(set_proto); PHONEDEV(xpd).offhook_state = BITMASK(PHONEDEV(xpd).channels); CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); priv->deflaw = deflaw; priv->dchan_num = dchan_num; priv->local_loopback = 0; xpd->type_name = type_name(priv->pri_protocol); XPD_DBG(GENERAL, xpd, "%s, channels=%d, dchan_num=%d, deflaw=%d\n", pri_protocol_name(set_proto), PHONEDEV(xpd).channels, priv->dchan_num, priv->deflaw ); /* * Must set default now, so layer1 polling (Register REG_FRS0) would * give reliable results. */ ret = pri_lineconfig(xpd, default_lineconfig); if(ret) { XPD_NOTICE(xpd, "Failed setting PRI default line config\n"); return ret; } return 0; } static void dahdi_update_syncsrc(xpd_t *xpd) { struct PRI_priv_data *priv; xpd_t *subxpd; int best_spanno = 0; int i; if(!SPAN_REGISTERED(xpd)) return; for(i = 0; i < MAX_SLAVES; i++) { subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i); if(!subxpd) continue; priv = subxpd->priv; if(priv->clock_source && priv->alarms == 0) { if(best_spanno) XPD_ERR(xpd, "Duplicate XPD's with clock_source=1\n"); best_spanno = PHONEDEV(subxpd).span.spanno; } } for(i = 0; i < MAX_SLAVES; i++) { subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i); if(!subxpd) continue; if(PHONEDEV(subxpd).span.syncsrc == best_spanno) XPD_DBG(SYNC, xpd, "Setting SyncSource to span %d\n", best_spanno); else XPD_DBG(SYNC, xpd, "Slaving to span %d\n", best_spanno); PHONEDEV(subxpd).span.syncsrc = best_spanno; } } /* * Called from: * - set_master_mode() -- * As a result of dahdi_cfg * - layer1_state() -- * As a result of an alarm. */ static void set_clocking(xpd_t *xpd) { xbus_t *xbus; xpd_t *best_xpd = NULL; int best_subunit = -1; /* invalid */ unsigned int best_subunit_prio = INT_MAX; int i; xbus = xpd->xbus; /* Find subunit with best timing priority */ for(i = 0; i < MAX_SLAVES; i++) { struct PRI_priv_data *priv; xpd_t *subxpd; subxpd = xpd_byaddr(xbus, xpd->addr.unit, i); if(!subxpd) continue; priv = subxpd->priv; if(priv->alarms != 0) continue; if(PHONEDEV(subxpd).timing_priority > 0 && PHONEDEV(subxpd).timing_priority < best_subunit_prio) { best_xpd = subxpd; best_subunit = i; best_subunit_prio = PHONEDEV(subxpd).timing_priority; } } /* Now set it */ if(best_xpd && ((struct PRI_priv_data *)(best_xpd->priv))->clock_source == 0) { byte reg_pc_init[] = { VAL_PC_GPI, VAL_PC_GPI, VAL_PC_GPI }; for(i = 0; i < ARRAY_SIZE(reg_pc_init); i++) { byte reg_pc = reg_pc_init[i]; reg_pc |= (best_subunit & (1 << i)) ? VAL_PC_GPOH : VAL_PC_GPOL; XPD_DBG(SYNC, best_xpd, "ClockSource Set: PC%d=0x%02X\n", 2+i, reg_pc); pri_write_reg(xpd, REG_PC2 + i, reg_pc); } ((struct PRI_priv_data *)(best_xpd->priv))->clock_source = 1; } /* clear old clock sources */ for(i = 0; i < MAX_SLAVES; i++) { struct PRI_priv_data *priv; xpd_t *subxpd; subxpd = xpd_byaddr(xbus, xpd->addr.unit, i); if(subxpd && subxpd != best_xpd) { XPD_DBG(SYNC, subxpd, "Clearing clock source\n"); priv = subxpd->priv; priv->clock_source = 0; } } dahdi_update_syncsrc(xpd); } static void set_reg_lim0(const char *msg, xpd_t *xpd) { struct PRI_priv_data *priv; bool is_master_mode; bool localloop; byte lim0 = 0; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); is_master_mode = PHONEDEV(xpd).timing_priority == 0; localloop = priv->local_loopback; lim0 |= (localloop) ? REG_LIM0_LL : 0; if(is_master_mode) lim0 |= REG_LIM0_MAS; else lim0 &= ~REG_LIM0_MAS; XPD_DBG(SIGNAL, xpd, "%s(%s): %s, %s\n", __FUNCTION__, msg, (is_master_mode) ? "MASTER" : "SLAVE", (localloop) ? "LOCALLOOP" : "NO_LOCALLOOP"); write_subunit(xpd, REG_LIM0 , lim0); } /* * Normally set by the timing parameter in /etc/dahdi/system.conf * If this is called by dahdi_cfg, than it's too late to change * dahdi sync priority (we are already registered) * * Also called from set_localloop() */ static int set_master_mode(const char *msg, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(SIGNAL, xpd, "\n"); set_reg_lim0(__FUNCTION__, xpd); set_clocking(xpd); return 0; } static int set_localloop(xpd_t *xpd, bool localloop) { struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; if(SPAN_REGISTERED(xpd)) { XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s\n", PHONEDEV(xpd).span.spanno, __FUNCTION__); return -EBUSY; } priv->local_loopback = localloop; XPD_DBG(SIGNAL, xpd, "%s: %s\n", __FUNCTION__, (localloop) ? "LOCALLOOP" : "NO"); set_master_mode(__FUNCTION__, xpd); return 0; } #define VALID_CONFIG(bit,flg,str) [bit] = { .flags = flg, .name = str } static const struct { const char *name; const int flags; } valid_spanconfigs[sizeof(unsigned int)*8] = { /* These apply to T1 */ VALID_CONFIG(4, DAHDI_CONFIG_D4, "D4"), VALID_CONFIG(5, DAHDI_CONFIG_ESF, "ESF"), VALID_CONFIG(6, DAHDI_CONFIG_AMI, "AMI"), VALID_CONFIG(7, DAHDI_CONFIG_B8ZS, "B8ZS"), /* These apply to E1 */ VALID_CONFIG(8, DAHDI_CONFIG_CCS, "CCS"), VALID_CONFIG(9, DAHDI_CONFIG_HDB3, "HDB3"), VALID_CONFIG(10, DAHDI_CONFIG_CRC4, "CRC4"), }; /* * Mark the lines as CLEAR or RBS signalling. * With T1, we need to mark the CLEAR lines on the REG_CCB1_T registers * Should be called only when we are registered to DAHDI * The channo parameter: * channo == 0: set lines for the whole span * channo != 0: only set modified lines */ static void set_rbslines(xpd_t *xpd, int channo) { struct PRI_priv_data *priv; xpp_line_t new_rbslines = 0; xpp_line_t modified_lines; int i; priv = xpd->priv; for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); if(chan->flags & DAHDI_FLAG_CLEAR) BIT_CLR(new_rbslines, i); else BIT_SET(new_rbslines, i); } new_rbslines &= BITMASK(PHONEDEV(xpd).channels); modified_lines = priv->rbslines ^ new_rbslines; XPD_DBG(DEVICES, xpd, "RBSLINES-%d(%s): 0x%X\n", channo, pri_protocol_name(priv->pri_protocol), new_rbslines); if((priv->pri_protocol == PRI_PROTO_T1) || (priv->pri_protocol == PRI_PROTO_J1)) { byte clear_lines = 0; /* Mark clear lines */ bool reg_changed = 0; for_each_line(xpd, i) { int bytenum = i / 8; int bitnum = i % 8; if(!IS_SET(new_rbslines, i)) { BIT_SET(clear_lines, (7 - bitnum)); } if(IS_SET(modified_lines, i)) reg_changed = 1; if(bitnum == 7) { if(channo == 0 || reg_changed) { bytenum += REG_CCB1_T; XPD_DBG(DEVICES, xpd, "RBS(%s): modified=0x%X rbslines=0x%X reg=0x%X clear_lines=0x%X\n", pri_protocol_name(priv->pri_protocol), modified_lines, new_rbslines, bytenum, clear_lines); write_subunit(xpd, bytenum, clear_lines); } clear_lines = 0; reg_changed = 0; } } } priv->rbslines = new_rbslines; } static int set_mode_cas(xpd_t *xpd, bool want_cas) { struct PRI_priv_data *priv; priv = xpd->priv; XPD_INFO(xpd, "Setting TDM to %s\n", (want_cas) ? "CAS" : "PRI"); if(want_cas) { priv->is_cas = 1; priv->dchan_alive = 0; } else { priv->is_cas = 0; } return 0; } static int pri_lineconfig(xpd_t *xpd, int lineconfig) { struct PRI_priv_data *priv; const char *framingstr = ""; const char *codingstr = ""; const char *crcstr = ""; #ifdef JAPANEZE_SUPPORT byte rc0 = 0; /* FIXME: PCM offsets */ #endif byte fmr0 = 0; byte fmr1 = REG_FMR1_ECM; byte fmr2 = 0; byte fmr3 = 0; /* write only for CRC4 */ byte fmr4 = 0; byte cmdr = REG_CMDR_RRES | REG_CMDR_XRES; byte xsp = 0; unsigned int bad_bits; bool force_cas = 0; int i; BUG_ON(!xpd); priv = xpd->priv; /* * validate */ bad_bits = lineconfig & pri_linecompat(priv->pri_protocol); bad_bits = bad_bits ^ lineconfig; for(i = 0; i < ARRAY_SIZE(valid_spanconfigs); i++) { unsigned int flags = valid_spanconfigs[i].flags; if(bad_bits & BIT(i)) { if(flags) { XPD_ERR(xpd, "Bad config item '%s' for %s. Ignore\n", valid_spanconfigs[i].name, pri_protocol_name(priv->pri_protocol)); } else { /* we got real garbage */ XPD_ERR(xpd, "Unknown config item 0x%lX for %s. Ignore\n", BIT(i), pri_protocol_name(priv->pri_protocol)); } } if(flags && flags != BIT(i)) { ERR("%s: BUG: i=%d flags=0x%X\n", __FUNCTION__, i, flags); // BUG(); } } if(bad_bits) goto bad_lineconfig; if(priv->pri_protocol == PRI_PROTO_E1) { fmr1 |= REG_FMR1_AFR; fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */ fmr4 = 0x9F; /* E1.XSW: All spare bits = 1*/ xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF; } else if(priv->pri_protocol == PRI_PROTO_T1) { fmr1 |= REG_FMR1_PMOD | REG_FMR1_T_CRC; fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */ fmr4 = 0x0C; xsp &= ~REG_FMR5_T_XTM; force_cas = 1; /* T1 - Chip always in CAS mode */ } else if(priv->pri_protocol == PRI_PROTO_J1) { fmr1 |= REG_FMR1_PMOD; fmr4 = 0x1C; xsp &= ~REG_FMR5_T_XTM; force_cas = 1; /* T1 - Chip always in CAS mode */ XPD_ERR(xpd, "J1 unsupported yet\n"); return -ENOSYS; } if(priv->local_loopback) fmr2 |= REG_FMR2_E_PLB; /* framing first */ if (lineconfig & DAHDI_CONFIG_B8ZS) { framingstr = "B8ZS"; fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0; } else if (lineconfig & DAHDI_CONFIG_AMI) { framingstr = "AMI"; fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1; /* * From Infineon Errata Sheet: PEF 22554, Version 3.1 * Problem: Incorrect CAS Receiption when * using AMI receive line code * Workaround: For E1, * "...The receive line coding HDB3 is * recommended instead." * For T1, * "...in T1 mode it is recommended to * configure the Rx side to B8ZS coding" * For both cases this is the same bit in FMR0 */ if(priv->pri_protocol == PRI_PROTO_J1) XPD_NOTICE(xpd, "J1 is not supported yet\n"); else fmr0 |= REG_FMR0_E_RC0; } else if (lineconfig & DAHDI_CONFIG_HDB3) { framingstr = "HDB3"; fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0; } else { XPD_NOTICE(xpd, "Bad lineconfig. Not (B8ZS|AMI|HDB3). Ignored.\n"); return -EINVAL; } /* then coding */ priv->is_esf = 0; if (lineconfig & DAHDI_CONFIG_ESF) { codingstr = "ESF"; fmr4 |= REG_FMR4_FM1; fmr2 |= REG_FMR2_T_AXRA | REG_FMR2_T_MCSP | REG_FMR2_T_SSP; priv->is_esf = 1; } else if (lineconfig & DAHDI_CONFIG_D4) { codingstr = "D4"; } else if (lineconfig & DAHDI_CONFIG_CCS) { codingstr = "CCS"; set_mode_cas(xpd, 0); /* In E1 we know right from the span statement. */ } else { codingstr = "CAS"; /* In E1 we know right from the span statement. */ force_cas = 1; set_mode_cas(xpd, 1); } CALL_PHONE_METHOD(card_pcm_recompute, xpd, 0); /* * E1's can enable CRC checking * CRC4 is legal only for E1, and it is checked by pri_linecompat() * in the beginning of the function. */ if (lineconfig & DAHDI_CONFIG_CRC4) { crcstr = "CRC4"; fmr1 |= REG_FMR1_E_XFS; fmr2 |= REG_FMR2_E_RFS1; fmr3 |= REG_FMR3_EXTIW; } XPD_DBG(GENERAL, xpd, "[%s] lineconfig=%s/%s/%s %s (0x%X)\n", (priv->clock_source)?"MASTER":"SLAVE", framingstr, codingstr, crcstr, (lineconfig & DAHDI_CONFIG_NOTOPEN)?"YELLOW":"", lineconfig); set_reg_lim0(__FUNCTION__, xpd); XPD_DBG(GENERAL, xpd, "%s: fmr1(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR1, fmr1); write_subunit(xpd, REG_FMR1, fmr1); XPD_DBG(GENERAL, xpd, "%s: fmr2(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR2, fmr2); write_subunit(xpd, REG_FMR2, fmr2); XPD_DBG(GENERAL, xpd, "%s: fmr0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR0, fmr0); write_subunit(xpd, REG_FMR0, fmr0); XPD_DBG(GENERAL, xpd, "%s: fmr4(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR4, fmr4); write_subunit(xpd, REG_FMR4, fmr4); if(fmr3) { XPD_DBG(GENERAL, xpd, "%s: fmr3(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR3, fmr3); write_subunit(xpd, REG_FMR3, fmr3); } XPD_DBG(GENERAL, xpd, "%s: cmdr(0x%02X) = 0x%02X\n", __FUNCTION__, REG_CMDR_E, cmdr); write_subunit(xpd, REG_CMDR_E, cmdr); #ifdef JAPANEZE_SUPPORT if(rc0) { XPD_DBG(GENERAL, xpd, "%s: rc0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_RC0, rc0); write_subunit(xpd, REG_RC0, rc0); } #endif if(force_cas) { xsp |= REG_XSP_E_CASEN; /* Same as REG_FMR5_T_EIBR for T1 */ } XPD_DBG(GENERAL, xpd, "%s: xsp(0x%02X) = 0x%02X\n", __FUNCTION__, REG_XSP_E, xsp); write_subunit(xpd, REG_XSP_E, xsp); return 0; bad_lineconfig: XPD_ERR(xpd, "Bad lineconfig. Abort\n"); return -EINVAL; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int pri_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct PRI_priv_data *priv; int ret; BUG_ON(!xpd); priv = xpd->priv; if(lc->span != PHONEDEV(xpd).span.spanno) { XPD_ERR(xpd, "I am span %d but got spanconfig for span %d\n", PHONEDEV(xpd).span.spanno, lc->span); return -EINVAL; } /* * FIXME: lc->name is unused by dahdi_cfg and dahdi... * We currently ignore it also. */ XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=0x%X sync=%d\n", (priv->clock_source)?"MASTER":"SLAVE", lc->lbo, lc->lineconfig, lc->sync); ret = pri_lineconfig(xpd, lc->lineconfig); if(!ret) { span->lineconfig = lc->lineconfig; PHONEDEV(xpd).timing_priority = lc->sync; set_master_mode("spanconfig", xpd); elect_syncer("PRI-master_mode"); } return ret; } /* * Set signalling type (if appropriate) * Called from dahdi with spinlock held on chan. Must not call back * dahdi functions. */ static int pri_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { struct phonedev *phonedev = container_of(chan->span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype)); /* * Some bookkeeping to check if we have DChan defined or not * FIXME: actually use this to prevent duplicate DChan definitions * and prevent DChan definitions with CAS. */ if(is_sigtype_dchan(sigtype)) { if (VALID_DCHAN(priv) && DCHAN(priv) != chan->channo) { ERR("channel %d (%s) marked DChan but also channel %d.\n", chan->channo, chan->name, DCHAN(priv)); return -EINVAL; } XPD_DBG(GENERAL, xpd, "channel %d (%s) marked as DChan\n", chan->channo, chan->name); SET_DCHAN(priv, chan->channo); /* In T1, we don't know before-hand */ if(priv->pri_protocol != PRI_PROTO_E1 && priv->is_cas != 0) { set_mode_cas(xpd, 0); } } else { if(chan->channo == 1) { XPD_DBG(GENERAL, xpd, "channel %d (%s) marked a not DChan\n", chan->channo, chan->name); SET_DCHAN(priv, NO_DCHAN); } /* In T1, we don't know before-hand */ if(priv->pri_protocol != PRI_PROTO_E1 && priv->is_cas != 1) set_mode_cas(xpd, 1); } if(PHONEDEV(xpd).span.flags & DAHDI_FLAG_RUNNING) { XPD_DBG(DEVICES, xpd, "Span is RUNNING. Updating rbslines.\n"); set_rbslines(xpd, chan->channo); } // FIXME: sanity checks: // - should be supported (within the sigcap) // - should not replace fxs <->fxo ??? (covered by previous?) return 0; } static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, int subunit_ports, bool to_phone) { xpd_t *xpd = NULL; struct PRI_priv_data *priv; int channels = min(31, CHANNELS_PERXPD); /* worst case */ if(subunit_ports != 1) { XBUS_ERR(xbus, "Bad subunit_ports=%d\n", subunit_ports); return NULL; } XBUS_DBG(GENERAL, xbus, "\n"); xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct PRI_priv_data), proto_table, channels); if(!xpd) return NULL; priv = xpd->priv; priv->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */ priv->deflaw = DAHDI_LAW_DEFAULT; /* Default, changes in set_pri_proto() */ xpd->type_name = type_name(priv->pri_protocol); xbus->sync_mode_default = SYNC_MODE_AB; return xpd; } static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) { struct PRI_priv_data *priv; int ret = 0; BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); xpd->type = XPD_TYPE_PRI; priv = xpd->priv; if(priv->pri_protocol == PRI_PROTO_0) { /* * init_card_* script didn't set pri protocol * Let's have a default E1 */ ret = set_pri_proto(xpd, PRI_PROTO_E1); if(ret < 0) goto err; } SET_DCHAN(priv, NO_DCHAN); /* * initialization script should have set correct * operating modes. */ if(!valid_pri_modes(xpd)) { XPD_NOTICE(xpd, "PRI protocol not set\n"); goto err; } xpd->type_name = type_name(priv->pri_protocol); PHONEDEV(xpd).direction = TO_PSTN; XPD_DBG(DEVICES, xpd, "%s\n", xpd->type_name); PHONEDEV(xpd).timing_priority = 1; /* High priority SLAVE */ set_master_mode(__FUNCTION__, xpd); for(ret = 0; ret < NUM_LEDS; ret++) { DO_LED(xpd, ret, PRI_LED_ON); msleep(20); DO_LED(xpd, ret, PRI_LED_OFF); } priv->initialized = 1; return 0; err: XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret); return ret; } static int PRI_card_remove(xbus_t *xbus, xpd_t *xpd) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "\n"); return 0; } #ifdef DAHDI_AUDIO_NOTIFY static int pri_audio_notify(struct dahdi_chan *chan, int on) { xpd_t *xpd = chan->pvt; int pos = chan->chanpos - 1; BUG_ON(!xpd); LINE_DBG(SIGNAL, xpd, pos, "PRI-AUDIO: %s\n", (on) ? "on" : "off"); mark_offhook(xpd, pos, on); return 0; } #endif static const struct dahdi_span_ops PRI_span_ops = { .owner = THIS_MODULE, .spanconfig = pri_spanconfig, .chanconfig = pri_chanconfig, .startup = pri_startup, .shutdown = pri_shutdown, .rbsbits = pri_rbsbits, .open = xpp_open, .close = xpp_close, .ioctl = xpp_ioctl, .maint = xpp_maint, .echocan_create = xpp_echocan_create, .echocan_name = xpp_echocan_name, #ifdef DAHDI_SYNC_TICK .sync_tick = dahdi_sync_tick, #endif #ifdef CONFIG_DAHDI_WATCHDOG .watchdog = xpp_watchdog, #endif #ifdef DAHDI_AUDIO_NOTIFY .audio_notify = pri_audio_notify, #endif }; static int PRI_card_dahdi_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct PRI_priv_data *priv; int i; BUG_ON(!xpd); xbus = xpd->xbus; priv = xpd->priv; BUG_ON(!xbus); XPD_DBG(GENERAL, xpd, "%s (proto=%s, channels=%d, deflaw=%d)\n", (on)?"on":"off", pri_protocol_name(priv->pri_protocol), PHONEDEV(xpd).channels, priv->deflaw); if(!on) { /* Nothing to do yet */ return 0; } PHONEDEV(xpd).span.spantype = pri_protocol_name(priv->pri_protocol); PHONEDEV(xpd).span.linecompat = pri_linecompat(priv->pri_protocol); PHONEDEV(xpd).span.deflaw = priv->deflaw; PHONEDEV(xpd).span.alarms = DAHDI_ALARM_NONE; for_each_line(xpd, i) { struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); bool is_dchan = i == PRI_DCHAN_IDX(priv); XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i, (is_dchan)?"DCHAN":"CLEAR"); snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d", xpd->type_name, xbus->num, xpd->addr.unit, xpd->addr.subunit, i); cur_chan->chanpos = i + 1; cur_chan->pvt = xpd; cur_chan->sigcap = PRI_SIGCAP; if(is_dchan && !priv->is_cas) { /* D-CHAN */ //FIXME: cur_chan->flags |= DAHDI_FLAG_PRIDCHAN; cur_chan->flags &= ~DAHDI_FLAG_HDLC; } } PHONEDEV(xpd).offhook_state = PHONEDEV(xpd).wanted_pcm_mask; PHONEDEV(xpd).span.ops = &PRI_span_ops; return 0; } static int PRI_card_dahdi_postregistration(xpd_t *xpd, bool on) { xbus_t *xbus; BUG_ON(!xpd); xbus = xpd->xbus; BUG_ON(!xbus); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); dahdi_update_syncsrc(xpd); return(0); } static void dchan_state(xpd_t *xpd, bool up) { struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(priv->is_cas) { return; } if(priv->dchan_alive == up) return; if(!priv->layer1_up) /* No layer1, kill dchan */ up = 0; if(up) { XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel RUNNING\n"); priv->dchan_alive = 1; } else { int d = PRI_DCHAN_IDX(priv); if(SPAN_REGISTERED(xpd) && d >= 0 && d < PHONEDEV(xpd).channels) { byte *pcm; pcm = (byte *)XPD_CHAN(xpd, d)->readchunk; pcm[0] = 0x00; pcm = (byte *)XPD_CHAN(xpd, d)->writechunk; pcm[0] = 0x00; } XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); priv->dchan_rx_counter = priv->dchan_tx_counter = 0; priv->dchan_alive = 0; priv->dchan_alive_ticks = 0; priv->dchan_rx_sample = priv->dchan_tx_sample = 0x00; } } /* * LED managment is done by the driver now: * - Turn constant ON RED/GREEN led to indicate MASTER/SLAVE port * - Very fast "Double Blink" to indicate Layer1 alive (without D-Channel) * - Constant blink (1/2 sec cycle) to indicate D-Channel alive. */ static void handle_leds(xbus_t *xbus, xpd_t *xpd) { struct PRI_priv_data *priv; unsigned int timer_count; int which_led; int other_led; enum pri_led_state ledstate; int mod; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(PHONEDEV(xpd).timing_priority == 0) { which_led = TOP_RED_LED; other_led = BOTTOM_GREEN_LED; } else { which_led = BOTTOM_GREEN_LED; other_led = TOP_RED_LED; } ledstate = priv->ledstate[which_led]; timer_count = xpd->timer_count; if(xpd->blink_mode) { if((timer_count % DEFAULT_LED_PERIOD) == 0) { // led state is toggled if(ledstate == PRI_LED_OFF) { DO_LED(xpd, which_led, PRI_LED_ON); DO_LED(xpd, other_led, PRI_LED_ON); } else { DO_LED(xpd, which_led, PRI_LED_OFF); DO_LED(xpd, other_led, PRI_LED_OFF); } } return; } if(priv->ledstate[other_led] != PRI_LED_OFF) DO_LED(xpd, other_led, PRI_LED_OFF); if(priv->dchan_alive) { mod = timer_count % 1000; switch(mod) { case 0: DO_LED(xpd, which_led, PRI_LED_ON); break; case 500: DO_LED(xpd, which_led, PRI_LED_OFF); break; } } else if(priv->layer1_up) { mod = timer_count % 1000; switch(mod) { case 0: case 100: DO_LED(xpd, which_led, PRI_LED_ON); break; case 50: case 150: DO_LED(xpd, which_led, PRI_LED_OFF); break; } } else { if(priv->ledstate[which_led] != PRI_LED_ON) DO_LED(xpd, which_led, PRI_LED_ON); } } static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd) { struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!priv->initialized || !xbus->self_ticking) return 0; /* * Poll layer1 status (cascade subunits) */ if(poll_interval != 0 && ((xpd->timer_count % poll_interval) == 0)) { priv->poll_noreplies++; query_subunit(xpd, REG_FRS0); //query_subunit(xpd, REG_FRS1); } if(priv->dchan_tx_counter >= 1 && priv->dchan_rx_counter > 1) { dchan_state(xpd, 1); priv->dchan_alive_ticks++; } handle_leds(xbus, xpd); return 0; } static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) { struct dahdi_chan *chan; BUG_ON(!xpd); if(!XBUS_IS(xpd->xbus, READY)) return -ENODEV; chan = XPD_CHAN(xpd, pos); switch (cmd) { case DAHDI_TONEDETECT: /* * Asterisk call all span types with this (FXS specific) * call. Silently ignore it. */ LINE_DBG(SIGNAL, xpd, pos, "PRI: TONEDETECT (%s)\n", (chan->flags & DAHDI_FLAG_AUDIO) ? "AUDIO" : "SILENCE"); return -ENOTTY; case DAHDI_ONHOOKTRANSFER: LINE_DBG(SIGNAL, xpd, pos, "PRI: ONHOOKTRANSFER\n"); return -ENOTTY; case DAHDI_VMWI: LINE_DBG(SIGNAL, xpd, pos, "PRI: VMWI\n"); return -ENOTTY; case DAHDI_VMWI_CONFIG: LINE_DBG(SIGNAL, xpd, pos, "PRI: VMWI_CONFIG\n"); return -ENOTTY; default: report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); return -ENOTTY; } return 0; } static int PRI_card_close(xpd_t *xpd, lineno_t pos) { //struct dahdi_chan *chan = XPD_CHAN(xpd, pos); dchan_state(xpd, 0); return 0; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int pri_startup(struct file *file, struct dahdi_span *span) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!XBUS_IS(xpd->xbus, READY)) { XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n"); return -ENODEV; } XPD_DBG(GENERAL, xpd, "STARTUP\n"); // Turn on all channels CALL_PHONE_METHOD(card_state, xpd, 1); set_rbslines(xpd, 0); write_subunit(xpd, REG_XPM2, 0x00); return 0; } /* * Called only for 'span' keyword in /etc/dahdi/system.conf */ static int pri_shutdown(struct dahdi_span *span) { struct phonedev *phonedev = container_of(span, struct phonedev, span); xpd_t *xpd = container_of(phonedev, struct xpd, phonedev); struct PRI_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); if(!XBUS_IS(xpd->xbus, READY)) { XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n"); return -ENODEV; } XPD_DBG(GENERAL, xpd, "SHUTDOWN\n"); // Turn off all channels CALL_PHONE_METHOD(card_state, xpd, 0); return 0; } static int encode_rbsbits_e1(xpd_t *xpd, int pos, int bits) { struct PRI_priv_data *priv; byte val; int rsnum; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); BUG_ON(priv->pri_protocol != PRI_PROTO_E1); if(pos == 15) return 0; /* Don't write dchan in CAS */ if(pos < 0 || pos > 31) { XPD_NOTICE(xpd, "%s: pos=%d out of range. Ignore\n", __FUNCTION__, pos); return 0; } if(pos >= 16) { /* Low nibble */ rsnum = pos - 16; val = (priv->cas_ts_e[rsnum] & 0xF0) | (bits & 0x0F); } else { /* High nibble */ rsnum = pos; val = (priv->cas_ts_e[rsnum] & 0x0F) | ((bits << 4) & 0xF0); } LINE_DBG(SIGNAL, xpd, pos, "RBS: TX: bits=0x%X\n", bits); write_cas_reg(xpd, rsnum, val); return 0; } static int encode_rbsbits_t1(xpd_t *xpd, int pos, int bits) { struct PRI_priv_data *priv; int rsnum; int chan_per_reg; int offset; int width; uint tx_bits = bits; uint mask; byte val; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); BUG_ON(priv->pri_protocol != PRI_PROTO_T1); if(pos < 0 || pos >= PHONEDEV(xpd).channels) { XPD_ERR(xpd, "%s: Bad pos=%d\n", __FUNCTION__, pos); return 0; } chan_per_reg = CHAN_PER_REGS(priv); width = 8 / chan_per_reg; rsnum = pos / chan_per_reg; offset = pos % chan_per_reg; mask = BITMASK(width) << (chan_per_reg - offset - 1) * width; if (!priv->is_esf) tx_bits >>= 2; tx_bits &= BITMASK(width); tx_bits <<= (chan_per_reg - offset - 1) * width; val = priv->cas_ts_e[rsnum]; val &= ~mask; val |= tx_bits; LINE_DBG(SIGNAL, xpd, pos, "bits=0x%02X RS%02d(%s) offset=%d tx_bits=0x%02X\n", bits, rsnum+1, (priv->is_esf) ? "esf" : "d4", offset, tx_bits); write_cas_reg(xpd, rsnum , val); priv->dchan_tx_counter++; return 0; } static void send_idlebits(xpd_t *xpd, bool saveold) { struct PRI_priv_data *priv; byte save_rs[NUM_CAS_RS_E]; int i; if (!SPAN_REGISTERED(xpd)) return; priv = xpd->priv; BUG_ON(!priv); XPD_DBG(SIGNAL, xpd, "saveold=%d\n", saveold); if (saveold) memcpy(save_rs, priv->cas_ts_e, sizeof(save_rs)); for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); pri_rbsbits(chan, chan->idlebits); } if (saveold) memcpy(priv->cas_ts_e, save_rs, sizeof(save_rs)); } static void send_oldbits(xpd_t *xpd) { struct PRI_priv_data *priv; int i; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(SIGNAL, xpd, "\n"); for (i = 0; i < cas_numregs(xpd); i++) write_cas_reg(xpd, i , priv->cas_ts_e[i]); } static int pri_rbsbits(struct dahdi_chan *chan, int bits) { xpd_t *xpd; struct PRI_priv_data *priv; int pos; xpd = chan->pvt; BUG_ON(!xpd); pos = chan->chanpos - 1; priv = xpd->priv; BUG_ON(!priv); if(!priv->is_cas) { XPD_DBG(SIGNAL, xpd, "RBS: TX: not in CAS mode. Ignore.\n"); return 0; } if (chan->sig == DAHDI_SIG_NONE) { LINE_DBG(SIGNAL, xpd, pos, "RBS: TX: sigtyp=%s. , bits=0x%X. Ignore.\n", sig2str(chan->sig), bits); return 0; } if(!priv->layer1_up) { XPD_DBG(SIGNAL, xpd, "RBS: TX: No layer1 yet. Keep going.\n"); } if(priv->pri_protocol == PRI_PROTO_E1) { if(encode_rbsbits_e1(xpd, pos, bits) < 0) return -EINVAL; } else if(priv->pri_protocol == PRI_PROTO_T1) { if(encode_rbsbits_t1(xpd, pos, bits) < 0) return -EINVAL; } else { XPD_NOTICE(xpd, "%s: protocol %s is not supported yet with CAS\n", __FUNCTION__, pri_protocol_name(priv->pri_protocol)); return -EINVAL; } return 0; } /*! Copy PCM chunks from the buffers of the xpd to a new packet * \param xbus xbus of source xpd. * \param xpd source xpd. * \param lines a bitmask of the active channels that need to be copied. * \param pack packet to be filled. * * On PRI this function is should also shift the lines mask one bit, as * channel 0 on the wire is an internal chip control channel. We only * send 31 channels to the device, but they should be called 1-31 rather * than 0-30 . */ static void PRI_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; unsigned long flags; int i; xpp_line_t wanted_lines; int physical_chan; int physical_mask = 0; BUG_ON(!xpd); BUG_ON(!pack); priv = xpd->priv; BUG_ON(!priv); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); spin_lock_irqsave(&xpd->lock, flags); wanted_lines = PHONEDEV(xpd).wanted_pcm_mask; physical_chan = 0; for_each_line(xpd, i) { struct dahdi_chan *chan = XPD_CHAN(xpd, i); if(priv->pri_protocol == PRI_PROTO_E1) { /* In E1 - Only 0'th channel is unused */ if(i == 0) { physical_chan++; } } else if(priv->pri_protocol == PRI_PROTO_T1) { /* In T1 - Every 4'th channel is unused */ if((i % 3) == 0) { physical_chan++; } } if(IS_SET(wanted_lines, i)) { physical_mask |= BIT(physical_chan); if(SPAN_REGISTERED(xpd)) { #ifdef DEBUG_PCMTX int channo = XPD_CHAN(xpd, i)->channo; if(pcmtx >= 0 && pcmtx_chan == channo) memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); else #endif memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); if(i == PRI_DCHAN_IDX(priv)) { if(priv->dchan_tx_sample != chan->writechunk[0]) { priv->dchan_tx_sample = chan->writechunk[0]; priv->dchan_tx_counter++; } else if(chan->writechunk[0] == 0xFF) dchan_state(xpd, 0); else chan->writechunk[0] = 0xFF; /* Clobber for next tick */ } } else memset((u_char *)pcm, DAHDI_XLAW(0, chan), DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } physical_chan++; } RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = physical_mask; XPD_COUNTER(xpd, PCM_WRITE)++; spin_unlock_irqrestore(&xpd->lock, flags); } /*! Copy PCM chunks from the packet we received to the xpd struct. * \param xbus xbus of target xpd. * \param xpd target xpd. * \param pack Source packet. * * On PRI this function is should also shift the lines back mask one bit, as * channel 0 on the wire is an internal chip control channel. * * \see PRI_card_pcm_fromspan */ static void PRI_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack) { struct PRI_priv_data *priv; byte *pcm; xpp_line_t physical_mask; unsigned long flags; int i; int logical_chan; if(!SPAN_REGISTERED(xpd)) return; priv = xpd->priv; BUG_ON(!priv); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); spin_lock_irqsave(&xpd->lock, flags); logical_chan = 0; for (i = 0; i < CHANNELS_PERXPD; i++) { volatile u_char *r; if(priv->pri_protocol == PRI_PROTO_E1) { /* In E1 - Only 0'th channel is unused */ if(i == 0) continue; } else if(priv->pri_protocol == PRI_PROTO_T1) { /* In T1 - Every 4'th channel is unused */ if((i % 4) == 0) continue; } if(logical_chan == PRI_DCHAN_IDX(priv) && !priv->is_cas) { if(priv->dchan_rx_sample != pcm[0]) { if(debug & DBG_PCM) { XPD_INFO(xpd, "RX-D-Chan: prev=0x%X now=0x%X\n", priv->dchan_rx_sample, pcm[0]); dump_packet("RX-D-Chan", pack, 1); } priv->dchan_rx_sample = pcm[0]; priv->dchan_rx_counter++; } else if(pcm[0] == 0xFF) dchan_state(xpd, 0); } if(IS_SET(physical_mask, i)) { r = XPD_CHAN(xpd, logical_chan)->readchunk; // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); pcm += DAHDI_CHUNKSIZE; } logical_chan++; } XPD_COUNTER(xpd, PCM_READ)++; spin_unlock_irqrestore(&xpd->lock, flags); } static int PRI_timing_priority(xpd_t *xpd) { struct PRI_priv_data *priv; priv = xpd->priv; BUG_ON(!priv); if (priv->layer1_up) return PHONEDEV(xpd).timing_priority; XPD_DBG(SYNC, xpd, "No timing priority (no layer1)\n"); return -ENOENT; } static int PRI_echocancel_timeslot(xpd_t *xpd, int pos) { /* * Skip ts=0 (used for PRI sync) */ return (1 + pos) * 4 + xpd->addr.subunit; } static int PRI_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask) { struct PRI_priv_data *priv; int i; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(GENERAL, xpd, "0x%8X\n", ec_mask); if (!ECHOOPS(xpd->xbus)) { XPD_DBG(GENERAL, xpd, "No echo canceller in XBUS: Doing nothing.\n"); return -EINVAL; } for (i = 0; i < PHONEDEV(xpd).channels; i++) { int on = BIT(i) & ec_mask; if (i == PRI_DCHAN_IDX(priv)) on = 0; CALL_EC_METHOD(ec_set, xpd->xbus, xpd, i, on); } CALL_EC_METHOD(ec_update, xpd->xbus, xpd->xbus); return 0; } /*---------------- PRI: HOST COMMANDS -------------------------------------*/ static /* 0x33 */ HOSTCMD(PRI, SET_LED, enum pri_led_selectors led_sel, enum pri_led_state to_led_state) { int ret = 0; xframe_t *xframe; xpacket_t *pack; struct pri_leds *pri_leds; struct PRI_priv_data *priv; BUG_ON(!xbus); BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); XPD_DBG(LEDS, xpd, "led_sel=%d to_state=%d\n", led_sel, to_led_state); XFRAME_NEW_CMD(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx); pri_leds = &RPACKET_FIELD(pack, PRI, SET_LED, pri_leds); pri_leds->state = to_led_state; pri_leds->led_sel = led_sel; pri_leds->reserved = 0; XPACKET_LEN(pack) = RPACKET_SIZE(PRI, SET_LED); ret = send_cmd_frame(xbus, xframe); priv->ledstate[led_sel] = to_led_state; return ret; } /*---------------- PRI: Astribank Reply Handlers --------------------------*/ static void layer1_state(xpd_t *xpd, byte data_low) { struct PRI_priv_data *priv; int alarms = DAHDI_ALARM_NONE; int layer1_up_prev; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); priv->poll_noreplies = 0; if(data_low & REG_FRS0_LOS) alarms |= DAHDI_ALARM_RED; if(data_low & REG_FRS0_AIS) alarms |= DAHDI_ALARM_BLUE; if(data_low & REG_FRS0_RRA) alarms |= DAHDI_ALARM_YELLOW; layer1_up_prev = priv->layer1_up; priv->layer1_up = alarms == DAHDI_ALARM_NONE; #if 0 /* * Some bad bits (e.g: LMFA and NMF have no alarm "colors" * associated. However, layer1 is still not working if they are set. * FIXME: These behave differently in E1/T1, so ignore them for while. */ if(data_low & (REG_FRS0_LMFA | REG_FRS0_E1_NMF)) priv->layer1_up = 0; #endif priv->alarms = alarms; if(!priv->layer1_up) { dchan_state(xpd, 0); } else if (priv->is_cas && !layer1_up_prev) { int regbase = cas_regbase(xpd); int i; XPD_DBG(SIGNAL , xpd, "Returning From Alarm Refreshing Rx register data \n"); for (i = 0; i < cas_numregs(xpd); i++) query_subunit(xpd, regbase + i); } if(SPAN_REGISTERED(xpd) && PHONEDEV(xpd).span.alarms != alarms) { char str1[MAX_PROC_WRITE]; char str2[MAX_PROC_WRITE]; alarm2str(PHONEDEV(xpd).span.alarms, str1, sizeof(str1)); alarm2str(alarms, str2, sizeof(str2)); XPD_NOTICE(xpd, "Alarms: 0x%X (%s) => 0x%X (%s)\n", PHONEDEV(xpd).span.alarms, str1, alarms, str2); if (priv->is_cas) { if (alarms == DAHDI_ALARM_NONE) send_oldbits(xpd); else if (PHONEDEV(xpd).span.alarms == DAHDI_ALARM_NONE) send_idlebits(xpd, 1); } PHONEDEV(xpd).span.alarms = alarms; elect_syncer("LAYER1"); dahdi_alarm_notify(&PHONEDEV(xpd).span); set_clocking(xpd); } priv->reg_frs0 = data_low; priv->layer1_replies++; XPD_DBG(REGS, xpd, "subunit=%d data_low=0x%02X\n", xpd->addr.subunit, data_low); } static int decode_cas_e1(xpd_t *xpd, byte regnum, byte data_low) { struct PRI_priv_data *priv; uint pos = regnum - REG_RS2_E; int rsnum = pos + 2; int chan1 = pos; int chan2 = pos + 16; int val1 = (data_low >> 4) & 0xF; int val2 = data_low & 0xF; priv = xpd->priv; BUG_ON(!priv->is_cas); BUG_ON(priv->pri_protocol != PRI_PROTO_E1); XPD_DBG(SIGNAL, xpd, "RBS: RX: data_low=0x%02X\n", data_low); if(pos >= NUM_CAS_RS_E) { XPD_ERR(xpd, "%s: got bad pos=%d [0-%d]\n", __FUNCTION__, pos, NUM_CAS_RS_E); return -EINVAL; } if(chan1 < 0 || chan1 > PHONEDEV(xpd).channels) { XPD_NOTICE(xpd, "%s: %s CAS: Bad chan1 number (%d)\n", __FUNCTION__, pri_protocol_name(priv->pri_protocol), chan1); return -EINVAL; } if(chan2 < 0 || chan2 > PHONEDEV(xpd).channels) { XPD_NOTICE(xpd, "%s: %s CAS: Bad chan2 number (%d)\n", __FUNCTION__, pri_protocol_name(priv->pri_protocol), chan2); return -EINVAL; } XPD_DBG(SIGNAL, xpd, "RBS: RX: RS%02d (channel %2d, channel %2d): 0x%02X -> 0x%02X\n", rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low); if(SPAN_REGISTERED(xpd)) { dahdi_rbsbits(XPD_CHAN(xpd, chan1), val1); dahdi_rbsbits(XPD_CHAN(xpd, chan2), val2); } priv->dchan_rx_counter++; priv->cas_rs_e[pos] = data_low; return 0; } static int decode_cas_t1(xpd_t *xpd, byte regnum, byte data_low) { struct PRI_priv_data *priv; uint rsnum; uint chan_per_reg; uint width; int i; priv = xpd->priv; BUG_ON(!priv->is_cas); BUG_ON(priv->pri_protocol != PRI_PROTO_T1); rsnum = regnum - REG_RS1_E; if(rsnum >= 12) { XPD_ERR(xpd, "Bad rsnum=%d\n", rsnum); return 0; } if(!priv->is_esf) rsnum = rsnum % 6; /* 2 identical banks of 6 registers */ chan_per_reg = CHAN_PER_REGS(priv); width = 8 / chan_per_reg; XPD_DBG(SIGNAL, xpd, "RBS: RX(%s,%d): RS%02d data_low=0x%02X\n", (priv->is_esf) ? "esf" : "d4", chan_per_reg, rsnum+1, data_low); for(i = 0; i < chan_per_reg; i++) { uint rxsig = (data_low >> (i * width)) & BITMASK(width); int pos; struct dahdi_chan *chan; if (!priv->is_esf) rxsig <<= 2; pos = rsnum * chan_per_reg + chan_per_reg - i - 1; if(pos < 0 || pos >= PHONEDEV(xpd).channels) { XPD_ERR(xpd, "%s: Bad pos=%d\n", __FUNCTION__, pos); continue; } chan = XPD_CHAN(xpd, pos); if(!chan) { XPD_ERR(xpd, "%s: Null channel in pos=%d\n", __FUNCTION__, pos); continue; } if(chan->rxsig != rxsig) { LINE_DBG(SIGNAL, xpd, pos, "i=%d rxsig=0x%02X\n", i, rxsig); dahdi_rbsbits(chan, rxsig); } } priv->cas_rs_e[rsnum] = data_low; return 0; } static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low) { struct PRI_priv_data *priv; priv = xpd->priv; if(!priv->is_cas) { static int rate_limit; if((rate_limit++ % 10003) == 0) XPD_NOTICE(xpd, "RBS: RX: not in CAS mode. Ignore.\n"); return; } if(!priv->layer1_up) { static int rate_limit; if((rate_limit++ % 10003) == 0) XPD_DBG(SIGNAL, xpd, "RBS: RX: No layer1.\n"); } if(!SPAN_REGISTERED(xpd)) { static int rate_limit; if((rate_limit++ % 10003) == 0) XPD_DBG(SIGNAL, xpd, "RBS: RX: Span not registered. Ignore.\n"); return; } if(priv->pri_protocol == PRI_PROTO_E1) { if(regnum == REG_RS1_E) return; /* Time slot 0: Ignored for E1 */ if(regnum < REG_RS2_E) { /* Should not happen, but harmless. Ignore */ if (regnum == REG_RS1_E) return; XPD_NOTICE(xpd, "%s: received register 0x%X in protocol %s. Ignore\n", __FUNCTION__, regnum, pri_protocol_name(priv->pri_protocol)); return; } if(decode_cas_e1(xpd, regnum, data_low) < 0) return; } else if(priv->pri_protocol == PRI_PROTO_T1) { if(regnum > REG_RS12_E) { XPD_NOTICE(xpd, "%s: received register 0x%X in protocol %s. Ignore\n", __FUNCTION__, regnum, pri_protocol_name(priv->pri_protocol)); return; } if(decode_cas_t1(xpd, regnum, data_low) < 0) return; } else { XPD_NOTICE(xpd, "%s: protocol %s is not supported yet with CAS\n", __FUNCTION__, pri_protocol_name(priv->pri_protocol)); } priv->cas_replies++; } static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { unsigned long flags; struct PRI_priv_data *priv; struct xpd_addr addr; xpd_t *orig_xpd; byte regnum; byte data_low; /* Map UNIT + PORTNUM to XPD */ orig_xpd = xpd; addr.unit = orig_xpd->addr.unit; addr.subunit = info->portnum; regnum = REG_FIELD(info, regnum); data_low = REG_FIELD(info, data_low); xpd = xpd_byaddr(xbus, addr.unit, addr.subunit); if(!xpd) { static int rate_limit; if((rate_limit++ % 1003) < 5) notify_bad_xpd(__FUNCTION__, xbus, addr , orig_xpd->xpdname); return -EPROTO; } spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); if(info->is_multibyte) { XPD_NOTICE(xpd, "Got Multibyte: %d bytes, eoframe: %d\n", info->bytes, info->eoframe); goto end; } if(regnum == REG_FRS0 && !REG_FIELD(info, do_subreg)) layer1_state(xpd, data_low); else if(regnum == REG_FRS1 && !REG_FIELD(info, do_subreg)) priv->reg_frs1 = data_low; if(priv->is_cas && !REG_FIELD(info, do_subreg)) { if(regnum >= REG_RS1_E && regnum <= REG_RS16_E) { process_cas_dchan(xpd, regnum, data_low); } } /* Update /proc info only if reply relate to the last slic read request */ if( REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { xpd->last_reply = *info; } end: spin_unlock_irqrestore(&xpd->lock, flags); return 0; } static int PRI_card_state(xpd_t *xpd, bool on) { BUG_ON(!xpd); XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); return 0; } static const struct xops pri_xops = { .card_new = PRI_card_new, .card_init = PRI_card_init, .card_remove = PRI_card_remove, .card_tick = PRI_card_tick, .card_register_reply = PRI_card_register_reply, }; static const struct phoneops pri_phoneops = { .card_dahdi_preregistration = PRI_card_dahdi_preregistration, .card_dahdi_postregistration = PRI_card_dahdi_postregistration, .card_pcm_recompute = PRI_card_pcm_recompute, .card_pcm_fromspan = PRI_card_pcm_fromspan, .card_pcm_tospan = PRI_card_pcm_tospan, .echocancel_timeslot = PRI_echocancel_timeslot, .echocancel_setmask = PRI_echocancel_setmask, .card_timing_priority = PRI_timing_priority, .card_ioctl = PRI_card_ioctl, .card_close = PRI_card_close, .card_state = PRI_card_state, }; static xproto_table_t PROTO_TABLE(PRI) = { .owner = THIS_MODULE, .entries = { /* Table Card Opcode */ }, .name = "PRI", /* protocol name */ .ports_per_subunit = 1, .type = XPD_TYPE_PRI, .xops = &pri_xops, .phoneops = &pri_phoneops, .packet_is_valid = pri_packet_is_valid, .packet_dump = pri_packet_dump, }; static bool pri_packet_is_valid(xpacket_t *pack) { const xproto_entry_t *xe = NULL; // DBG(GENERAL, "\n"); xe = xproto_card_entry(&PROTO_TABLE(PRI), XPACKET_OP(pack)); return xe != NULL; } static void pri_packet_dump(const char *msg, xpacket_t *pack) { DBG(GENERAL, "%s\n", msg); } /*------------------------- REGISTER Handling --------------------------*/ /*------------------------- sysfs stuff --------------------------------*/ static DEVICE_ATTR_READER(pri_protocol_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf, "%s\n", pri_protocol_name(priv->pri_protocol)); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(pri_protocol_store, dev, buf, count) { xpd_t *xpd; enum pri_protocol new_protocol = PRI_PROTO_0; int i; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); XPD_DBG(GENERAL, xpd, "%s\n", buf); if(!xpd) return -ENODEV; if((i = strcspn(buf, " \r\n")) != 2) { XPD_NOTICE(xpd, "Protocol name '%s' has %d characters (should be 2). Ignored.\n", buf, i); return -EINVAL; } if(strnicmp(buf, "E1", 2) == 0) new_protocol = PRI_PROTO_E1; else if(strnicmp(buf, "T1", 2) == 0) new_protocol = PRI_PROTO_T1; else if(strnicmp(buf, "J1", 2) == 0) new_protocol = PRI_PROTO_J1; else { XPD_NOTICE(xpd, "Unknown PRI protocol '%s' (should be E1|T1|J1). Ignored.\n", buf); return -EINVAL; } ret = set_pri_proto(xpd, new_protocol); return (ret < 0) ? ret : count; } static DEVICE_ATTR(pri_protocol, S_IRUGO | S_IWUSR, pri_protocol_show, pri_protocol_store); static DEVICE_ATTR_READER(pri_localloop_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf, "%c\n", (priv->local_loopback) ? 'Y' : 'N'); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(pri_localloop_store, dev, buf, count) { xpd_t *xpd; bool ll = 0; int i; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); XPD_DBG(GENERAL, xpd, "%s\n", buf); if(!xpd) return -ENODEV; if((i = strcspn(buf, " \r\n")) != 1) { XPD_NOTICE(xpd, "Value '%s' has %d characters (should be 1). Ignored.\n", buf, i); return -EINVAL; } if(strchr("1Yy", buf[0]) != NULL) ll = 1; else if(strchr("0Nn", buf[0]) != NULL) ll = 0; else { XPD_NOTICE(xpd, "Unknown value '%s' (should be [1Yy]|[0Nn]). Ignored.\n", buf); return -EINVAL; } ret = set_localloop(xpd, ll); return (ret < 0) ? ret : count; } static DEVICE_ATTR(pri_localloop, S_IRUGO | S_IWUSR, pri_localloop_show, pri_localloop_store); static DEVICE_ATTR_READER(pri_layer1_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); if(priv->poll_noreplies > 1) len += sprintf(buf + len, "Unknown[%d]", priv->poll_noreplies); else len += sprintf(buf + len, "%-10s", ((priv->layer1_up) ? "UP" : "DOWN")); len += sprintf(buf + len, "%d\n", priv->layer1_replies); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(pri_layer1, S_IRUGO, pri_layer1_show, NULL); static DEVICE_ATTR_READER(pri_alarms_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; static const struct { byte bits; const char *name; } alarm_types[] = { { REG_FRS0_LOS, "RED" }, { REG_FRS0_AIS, "BLUE" }, { REG_FRS0_RRA, "YELLOW" }, }; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); if(priv->poll_noreplies > 1) len += sprintf(buf + len, "Unknown[%d]", priv->poll_noreplies); else { int i; for(i = 0; i < ARRAY_SIZE(alarm_types); i++) { if(priv->reg_frs0 & alarm_types[i].bits) len += sprintf(buf + len, "%s ", alarm_types[i].name); } } len += sprintf(buf + len, "\n"); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(pri_alarms, S_IRUGO, pri_alarms_show, NULL); static DEVICE_ATTR_READER(pri_cas_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); if(priv->is_cas) { int i; len += sprintf(buf + len, "CAS: replies=%d\n", priv->cas_replies); len += sprintf(buf + len, " CAS-TS: "); for(i = 0; i < NUM_CAS_RS_E; i++) { len += sprintf(buf + len, " %02X", priv->cas_ts_e[i]); } len += sprintf(buf + len, "\n"); len += sprintf(buf + len, " CAS-RS: "); for(i = 0; i < NUM_CAS_RS_E; i++) { len += sprintf(buf + len, " %02X", priv->cas_rs_e[i]); } len += sprintf(buf + len, "\n"); } spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(pri_cas, S_IRUGO, pri_cas_show, NULL); static DEVICE_ATTR_READER(pri_dchan_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf + len, "D-Channel: TX=[%5d] (0x%02X) RX=[%5d] (0x%02X) ", priv->dchan_tx_counter, priv->dchan_tx_sample, priv->dchan_rx_counter, priv->dchan_rx_sample); if(priv->dchan_alive) { len += sprintf(buf + len, "(alive %d K-ticks)\n", priv->dchan_alive_ticks/1000); } else { len += sprintf(buf + len, "(dead)\n"); } spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(pri_dchan, S_IRUGO, pri_dchan_show, NULL); static DEVICE_ATTR_READER(pri_clocking_show, dev, buf) { xpd_t *xpd; struct PRI_priv_data *priv; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; priv = xpd->priv; BUG_ON(!priv); spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf + len, "%s\n", (priv->clock_source) ? "MASTER" : "SLAVE"); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR(pri_clocking, S_IRUGO, pri_clocking_show, NULL); static int pri_xpd_probe(struct device *dev) { xpd_t *xpd; int ret = 0; xpd = dev_to_xpd(dev); /* Is it our device? */ if(xpd->type != XPD_TYPE_PRI) { XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev), xpd->type); return -EINVAL; } XPD_DBG(DEVICES, xpd, "SYSFS\n"); ret = device_create_file(dev, &dev_attr_pri_protocol); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_protocol) failed: %d\n", __FUNCTION__, ret); goto fail_pri_protocol; } ret = device_create_file(dev, &dev_attr_pri_localloop); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_localloop) failed: %d\n", __FUNCTION__, ret); goto fail_pri_localloop; } ret = device_create_file(dev, &dev_attr_pri_layer1); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_layer1) failed: %d\n", __FUNCTION__, ret); goto fail_pri_layer1; } ret = device_create_file(dev, &dev_attr_pri_alarms); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_alarms) failed: %d\n", __FUNCTION__, ret); goto fail_pri_alarms; } ret = device_create_file(dev, &dev_attr_pri_cas); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_cas) failed: %d\n", __FUNCTION__, ret); goto fail_pri_cas; } ret = device_create_file(dev, &dev_attr_pri_dchan); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_dchan) failed: %d\n", __FUNCTION__, ret); goto fail_pri_dchan; } ret = device_create_file(dev, &dev_attr_pri_clocking); if(ret) { XPD_ERR(xpd, "%s: device_create_file(pri_clocking) failed: %d\n", __FUNCTION__, ret); goto fail_pri_clocking; } return 0; fail_pri_clocking: device_remove_file(dev, &dev_attr_pri_dchan); fail_pri_dchan: device_remove_file(dev, &dev_attr_pri_cas); fail_pri_cas: device_remove_file(dev, &dev_attr_pri_alarms); fail_pri_alarms: device_remove_file(dev, &dev_attr_pri_layer1); fail_pri_layer1: device_remove_file(dev, &dev_attr_pri_localloop); fail_pri_localloop: device_remove_file(dev, &dev_attr_pri_protocol); fail_pri_protocol: return ret; } static int pri_xpd_remove(struct device *dev) { xpd_t *xpd; xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, xpd, "SYSFS\n"); device_remove_file(dev, &dev_attr_pri_clocking); device_remove_file(dev, &dev_attr_pri_dchan); device_remove_file(dev, &dev_attr_pri_cas); device_remove_file(dev, &dev_attr_pri_alarms); device_remove_file(dev, &dev_attr_pri_layer1); device_remove_file(dev, &dev_attr_pri_localloop); device_remove_file(dev, &dev_attr_pri_protocol); return 0; } static struct xpd_driver pri_driver = { .type = XPD_TYPE_PRI, .driver = { .name = "pri", #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE, #endif .probe = pri_xpd_probe, .remove = pri_xpd_remove } }; static int __init card_pri_startup(void) { int ret; if((ret = xpd_driver_register(&pri_driver.driver)) < 0) return ret; INFO("revision %s\n", XPP_VERSION); #ifdef DAHDI_AUDIO_NOTIFY INFO("FEATURE: WITH DAHDI_AUDIO_NOTIFY\n"); #else INFO("FEATURE: WITHOUT DAHDI_AUDIO_NOTIFY\n"); #endif xproto_register(&PROTO_TABLE(PRI)); return 0; } static void __exit card_pri_cleanup(void) { DBG(GENERAL, "\n"); xproto_unregister(&PROTO_TABLE(PRI)); xpd_driver_unregister(&pri_driver.driver); } MODULE_DESCRIPTION("XPP PRI Card Driver"); MODULE_AUTHOR("Oron Peled "); MODULE_LICENSE("GPL"); MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_PRI); module_init(card_pri_startup); module_exit(card_pri_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/card_fxs.h0000644000175000017500000000247511012401471021306 0ustar tzafrirtzafrir#ifndef CARD_FXS_H #define CARD_FXS_H /* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "xpd.h" enum fxs_opcodes { XPROTO_NAME(FXS, SIG_CHANGED) = 0x06, /**/ XPROTO_NAME(FXS, XPD_STATE) = 0x0F, /* Write to SLIC */ XPROTO_NAME(FXS, CHAN_POWER) = 0x0F, /* Write to SLIC */ XPROTO_NAME(FXS, CHAN_CID) = 0x0F, /* Write to SLIC */ XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */ }; DEF_RPACKET_DATA(FXS, SIG_CHANGED, xpp_line_t sig_status; /* channels: lsb=1, msb=8 */ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */ ); #endif /* CARD_FXS_H */ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/init_card_3_300000755000175000017500000003327411156223162021763 0ustar tzafrirtzafrir#! /usr/bin/perl -w use strict; # Make warnings fatal local $SIG{__WARN__} = sub { die @_ }; # # $Id: init_card_3_30 6135 2009-03-12 15:12:50Z tzafrir $ # # # Written by Oron Peled # Copyright (C) 2006, Xorcom # # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # See the file LICENSE in the top level of this tarball. # # This script is run from the xpp kernel module upon detection # of a new XPD. # # Expects the following environment variables to be set: # XBUS_NAME - bus name # UNIT_NUMBER - xpd unit number # UNIT_SUBUNITS - number of subunits in this xpd # UNIT_TYPE - xpd type number (from protocol reply): # 1 - FXS # 2 - FXO # 3 - BRI # 4 - PRI # XBUS_REVISION - xbus revision number # XBUS_CONNECTOR - xbus connector string # # Output data format: # - An optional comment start with ';' or '#' until the end of line # - Optional Blank lines are ignored # - Fields are whitespace separated (spaces or tabs) # # The fields are (in command line order): # 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number) # 2. Command word: # - RD Read Direct register. # - RS Read Sub-register. # - WD Write Direct register. # - WS Write Sub-register. # 3. Register number in hexadecimal. # 4. Subregister number in hexadecimal. (for RS and WS commands). # 5. Data byte in hexadecimal. (for WD and WS commands only). # package main; use File::Basename; use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); } use XppConfig $init_dir; my $unit_id; my %opts; getopts('o:', \%opts); my %settings; sub logit { print STDERR "$unit_id: @_\n"; } sub debug { logit @_ if $settings{debug}; } # Arrange for error logging if (-t STDERR) { $unit_id = 'Interactive'; debug "Interactive startup"; } else { $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}"; open (STDERR, "| logger -t $program -p kern.info") || die; debug "Non Interactive startup"; foreach my $k (qw( XBUS_NAME XBUS_NUMBER UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR XBUS_LABEL)) { unless(defined $ENV{$k}) { logit "Missing ENV{$k}\n"; die; } } } sub select_subunit($) { my $subunit = shift; die unless defined $subunit; my $output; if($opts{o}) { $output = $opts{o}; } else { $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs", $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit; if(! -f $output) { my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit); $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs"; logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc" if -f $output; } } open(REG, ">$output") || die "Failed to open '$output': $!\n"; my $oldfh = select REG; print "# Selecting subunit $subunit\n" if $opts{o}; return $oldfh; } package BRI; sub gen { my $fmt = shift; $| = 1; printf "$fmt\n", @_; } # Turning on/off multi-byte packet reception. sub multibyte($) { my $active = (shift) ? 'M' : 'm'; for my $subunit (0 .. $ENV{UNIT_SUBUNITS} - 1) { #main::logit "multibyte(): $subunit -> $active"; main::select_subunit($subunit); BRI::gen "$subunit W$active"; } } sub read_defaults() { if(XppConfig::read_config(\%settings)) { main::logit "Defaults from $settings{xppconf}"; } else { main::logit "No defaults file, use hard-coded defaults."; } } package BRI::Port; sub new { my $pack = shift; my $port = { @_ }; bless $port, $pack; } # zap_xhfc_su.c:995 sub init_su { my $port = shift; my $portnum = $port->{PORT_NUM}; my $port_mode_up = $port->{PORT_MODE_UP}; my $port_mode_exch = $port->{PORT_MODE_EXCH}; my $bri_nt = $port->{BRI_NT}; #main::logit "init_su(portnum=$portnum, port_mode_up=$port_mode_up, bri_nt=$bri_nt)"; # Setting PLL # R_PLL_CTRL = 0 (V_PLL_M = 0, Reset PLL, Disable PLL_ # R_CLK_CFG = 05 (PLL clock as system clock, output it to CLK_OUT pin) # R_PLL_P = 1 # R_PLL_N = 6 # R_PLL_S = 1 # R_PLL_CTRL = 1 (V_PLL_M) BRI::gen "#--------------------------- init_su($portnum, $bri_nt, $port_mode_up, $port_mode_exch)"; BRI::gen "$portnum WD 02 04"; BRI::gen "$portnum WD 50 00"; # disable PLL BRI::gen "$portnum WD 51 02"; BRI::gen "$portnum WD 52 06"; BRI::gen "$portnum WD 53 04"; BRI::gen "$portnum WD 50 01"; # Enable PLL BRI::gen "$portnum WD 02 05"; # Enable PLL su_sel($portnum); # select port if ("$port_mode_up" == 1) { $port->{CTRL3} = 0x01; # A_ST_CTRL3: V_ST_SEL = 1 $port->{CTRL0} = 0x10; # A_SU_CTRL0: V_ST_SQ_EN = 1 BRI::gen "$portnum WD 34 0F"; # A_MS_TX: # (multiframe/superframe transmit register) } else { $port->{CTRL3} = 0x00; # A_ST_CTRL3: V_ST_SEL = 0 $port->{CTRL0} = 0x00; # A_SU_CTRL0: V_ST_SQ_EN = 0 } if ("$bri_nt" == 1) { $port->{CTRL0} |= 0x04; # V_SU_MD } # ((V_SU_EXCH)?0x80:00) (change polarity) if($port_mode_exch) { $port->{CTRL2} = 0x80; } else { $port->{CTRL2} = 0x00; } BRI::gen "$portnum WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3 BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0 BRI::gen "$portnum WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8 BRI::gen "$portnum WD 32 09"; # A_SU_CTRL1 = Ignore E-channel data, Force automatic transition from G2 to G3 BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2 # zap_xhfc_su.c:1030 in init_su() # A_SU_CLK_DLY my $clk_dly; if ("$bri_nt" == 1) { $clk_dly = 0x6C; } else { $clk_dly = 0x0E; } #main::logit "clk_dly=$clk_dly"; BRI::gen "$portnum WD 37 %02X", "$clk_dly"; } sub su_sel { if (@_ != 1 ) { main::logit "ERROR: su_sel() called with " . scalar(@_) . " parameters"; exit 1; } my $portnum = shift; BRI::gen "$portnum WD 16 %02X", $portnum; # R_SU_SEL } # zap_xhfc_su.c:281 sub xhfc_selfifo { my $port = shift; my $portnum = $port->{PORT_NUM}; if (@_ != 1 ) { main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters"; exit 1; } my $fifonum = shift; #main::logit "xhfc_selfifo($fifonum)"; BRI::gen "$portnum WD 0F %02X", $fifonum; # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0 } # zap_xhfc_su.c:295 sub xhfc_resetfifo() { my $port = shift; my $portnum = $port->{PORT_NUM}; #main::logit "xhfc_resetfifo()"; # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR BRI::gen "$portnum WD 0E 0A"; # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0 } # zap_xhfc_su.c:1040 # Initialize fifo (called for each portnum, channel, direction) sub setup_fifo { my $port = shift; my $chan = shift; my $direction = shift; my $conhdlc = shift; my $subcfg = shift; my $fifoctrl = shift; my $portnum = $port->{PORT_NUM}; my $port_mode_up = $port->{PORT_MODE_UP}; my $port_mode_exch = $port->{PORT_MODE_EXCH}; my $bri_nt = $port->{BRI_NT}; BRI::gen "#--------------------------- setup_fifo($portnum, $chan, $direction)"; # my $fifonum = 0x80 | ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first my $fifonum = ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first my $r_slot = ($portnum << 3) | ($chan << 1) | ($direction); # channel order workaround, swap odd and even portnums in $r_slot for PCM (chan 0, 1) only if ("$chan" == 0 || "$chan" == 1) { $r_slot = $r_slot ^ 0x08; } my $short_portnum = $portnum & 0x03; my $a_sl_cfg = (0x80 | ($short_portnum << 3) | ($chan << 1) | ($direction)); # receive data from STIO2, transmit to STIO1 #main::logit "setup_fifo($fifonum)"; $port->xhfc_selfifo($fifonum); # A_CON_HDLC: transparent mode selection BRI::gen "$portnum WD FA %02X", $conhdlc; # A_SUBCH_CFG: subchnl params BRI::gen "$portnum WD FB %02X", $subcfg; # A_FIFO_CTRL: FIFO Control Register BRI::gen "$portnum WD FF %02X", $fifoctrl; $port->xhfc_resetfifo(); $port->xhfc_selfifo($fifonum); # wait for busy is builtin in this command BRI::gen "$portnum WD 10 %02X", $r_slot; # R_SLOT BRI::gen "$portnum WD D0 %02X", $a_sl_cfg; # A_SL_CFG #system("/bin/echo \"----=====TE\" \"short_portnum=\"$short_portnum \"portnum=\" $portnum \"chan=\" $chan\"======----\n\" >>/root/xortel/test_init"); } # zap_xhfc_su.c:1071 sub setup_su { my $port = shift; my $bchan = shift; my $portnum = $port->{PORT_NUM}; my $port_mode_exch = $port->{PORT_MODE_EXCH}; my $bri_nt = $port->{BRI_NT}; BRI::gen "#--------------------------- setup_su($portnum, $bchan)"; #main::logit "setup_su(portnum=$portnum, bchan=$bchan, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)"; $port->{CTRL0} |= (1 << $bchan) | $bri_nt; $port->{CTRL2} |= ($port_mode_exch << 7) | (1 << $bchan); su_sel($portnum); # Select port BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE) BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2: V_B1_RX_EN } sub xhfc_ph_command { my $port = shift; my $cmd = shift; my $portnum = $port->{PORT_NUM}; #main::logit "xhfc_ph_command(portnum=$portnum)"; if ("$cmd" eq "HFC_L1_ACTIVATE_TE") { su_sel($portnum); # Select port BRI::gen "$portnum WD 30 60"; # A_SU_WR_STA = (M_SU_ACT & 0x03) # (set activation) } elsif ("$cmd" eq "HFC_L1_FORCE_DEACTIVATE_TE") { su_sel($portnum); # Select port BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02) # (set deactivation) } elsif ("$cmd" eq "HFC_L1_ACTIVATE_NT") { su_sel($portnum); # Select port BRI::gen "$portnum WD 30 E0"; # A_SU_WR_STA = (M_SU_ACT & 0x03) | 0x80 # (set activation + NT) } elsif ("$cmd" eq "HFC_L1_DEACTIVATE_NT") { su_sel($portnum); # Select port BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02) # (set deactivation) } } sub zthfc_startup { my $port = shift; my $portnum = $port->{PORT_NUM}; my $port_mode_exch = $port->{PORT_MODE_EXCH}; my $bri_nt = $port->{BRI_NT}; #main::logit "zthfc_startup(portnum=$portnum, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)"; # PCM <-> ST/Up Configuration foreach my $chan ( 0, 1 ) { $port->setup_fifo($chan, 0, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM $port->setup_fifo($chan, 1, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM $port->setup_su($chan); # zap_xhfc_su.c:194 } # Dahdi chan 2 used as HDLC D-Channel $port->setup_fifo(2, 0, 0x05, 2, 0); # D-TX: zap_xhfc_su.c:205 $port->setup_fifo(2, 1, 0x05, 2, 0); # D-RX: zap_xhfc_su.c:206 # E-chan, Echo channel is ignored # enable this port's state machine su_sel($portnum); # Select port # A_SU_WR_STA: reset port state machine BRI::gen "$portnum WD 30 00"; if ("$bri_nt" == 0) { $port->xhfc_ph_command("HFC_L1_ACTIVATE_TE"); } else { $port->xhfc_ph_command("HFC_L1_ACTIVATE_NT"); } } package main; debug "Starting '$0'"; BRI::read_defaults; #------------------------------------------- Instance detection # zap_xhfc_su.c:895 sub init_xhfc($) { my $portnum = shift; main::debug "init_xhfc($portnum)"; BRI::gen "#--------------------------- init_xhfc"; BRI::gen "$portnum WD 0D 00"; # r_FIFO_MD: 16 fifos, # 64 bytes for TX and RX each (FIFO mode config) # software reset to enable R_FIFO_MD setting BRI::gen "$portnum WD 00 08"; # R_CIRM = M_SRES (soft reset) # --> WAIT 5u BRI::gen "$portnum WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset) # amplitude BRI::gen "$portnum WD 46 80"; # R_PWM_MD: (PWM output mode register) # PWM push to zero only BRI::gen "$portnum WD 39 18"; # R_PWM1: (modulator register for PWM1) # set duty cycle BRI::gen "$portnum WD 0C 11"; # R_FIFO_THRES: (FIFO fill lvl control register) # RX/TX threshold = 16 bytes # set PCM bus mode to slave by default BRI::gen "$portnum WD 14 08"; # R_PCM_MD0 = PCM slave mode, F0IO duration is 2 HFC_PCLK's # (C4IO, F0IO are inputs) BRI::gen "$portnum WD 14 98"; # R_PCM_MD0: Index value to select # the register at address 15 BRI::gen "$portnum WD 15 20"; # R_PCM_MD1: V_PLL_ADJ (DPLL adjust speed), # in the last slot of PCM frame # V_PCM_DR, C4IO is 16.384MHz(128 time slots) BRI::gen "$portnum WD 4C 07"; # GPIOGPIO function (not PWM) on GPIO0, GPIO1 and GPIO2 pins BRI::gen "$portnum WD 4A 07"; # Output enable for GPIO0, GPIO1 and GPIO2 pins BRI::gen "$portnum WD 48 01"; # GPIO output data bits } my @port_type = ( { 'BRI_NT' => 1 }, { 'BRI_NT' => 0 } ); # zap_xhfc_su.c:175 sub main() { my $subunit; my $subunits_mask = pack("C", $ENV{UNIT_SUBUNITS_DIR}); my @direction = split(//, unpack("b*", $subunits_mask)); #logit "main(): UNIT_TYPE=$ENV{UNIT_TYPE} UNIT_SUBUNITS_DIR=[@direction]"; if(!$opts{o}) { foreach my $var (qw(XBUS_NAME UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR)) { die "Missing mandatory '$var' environment variable" unless defined $var; } } # Turn off multi-byte packet reception before initialization started # Otherwise we mess with registers while the FPGA firmware tries to # send us packets. BRI::multibyte(0); # Port initialization for($subunit = 0; $subunit < $ENV{UNIT_SUBUNITS}; $subunit++) { my $is_nt = $direction[$subunit]; main::select_subunit($subunit); if(($subunit % 4) == 0) { # A new xhfc chip #logit "main(): Initializing chip"; init_xhfc($subunit); # zap_xhfc_su.c:1173 in setup_instance() } #logit "main(): Initializing subunit $subunit is_nt=$is_nt"; my $p = BRI::Port->new( 'PORT_NUM' => $subunit, 'BRI_NT' => $is_nt, 'PORT_MODE_UP' => 0, 'PORT_MODE_EXCH' => 0 ); # zap_XHfc_su.c:1186 in setup_instance() $p->init_su; $p->zthfc_startup; } # Turn on multi-byte packet reception when ports initialization finished BRI::multibyte(1); } main; debug "Ending '$0'"; close REG; close STDERR; exit 0; dahdi-linux-2.5.0.1/drivers/dahdi/xpp/xbus-sysfs.c0000644000175000017500000006115111602416004021635 0ustar tzafrirtzafrir/* * Written by Oron Peled * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) # warning "This module is tested only with 2.6 kernels" #endif #include #include #include #include #ifdef PROTOCOL_DEBUG #include #endif #include #include #include /* for msleep() to debug */ #include "xpd.h" #include "xpp_dahdi.h" #include "xbus-core.h" #include "dahdi_debug.h" static const char rcsid[] = "$Id: xbus-sysfs.c 9993 2011-06-28 18:23:00Z tzafrir $"; /* Command line parameters */ extern int debug; /*--------- xpp driver attributes -*/ static ssize_t sync_show(struct device_driver *driver, char *buf) { DBG(SYNC, "\n"); return fill_sync_string(buf, PAGE_SIZE); } static ssize_t sync_store(struct device_driver *driver, const char *buf, size_t count) { /* DBG(SYNC, "%s\n", buf); */ return exec_sync_command(buf, count); } static struct driver_attribute xpp_attrs[] = { __ATTR(sync, S_IRUGO | S_IWUSR, sync_show, sync_store), __ATTR_NULL, }; /*--------- Sysfs Bus handling ----*/ static DEVICE_ATTR_READER(xbus_state_show, dev, buf) { xbus_t *xbus; int ret; xbus = dev_to_xbus(dev); ret = XBUS_STATE(xbus); ret = snprintf(buf, PAGE_SIZE, "%s (%d)\n", xbus_statename(ret), ret); return ret; } static DEVICE_ATTR_WRITER(xbus_state_store, dev, buf, count) { xbus_t *xbus; xbus = dev_to_xbus(dev); XBUS_DBG(GENERAL, xbus, "%s\n", buf); if(strncmp(buf, "stop", 4) == 0) xbus_deactivate(xbus); else if(XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0) xbus_activate(xbus); else { XBUS_NOTICE(xbus, "%s: Illegal action %s in state %s. Ignored.\n", __FUNCTION__, buf, xbus_statename(XBUS_STATE(xbus))); return -EINVAL; } return count; } static DEVICE_ATTR_READER(status_show, dev, buf) { xbus_t *xbus; int ret; xbus = dev_to_xbus(dev); ret = snprintf(buf, PAGE_SIZE, "%s\n", (XBUS_FLAGS(xbus, CONNECTED))?"connected":"missing"); return ret; } static DEVICE_ATTR_READER(timing_show, dev, buf) { xbus_t *xbus; struct xpp_drift *driftinfo; int len = 0; struct timeval now; do_gettimeofday(&now); xbus = dev_to_xbus(dev); driftinfo = &xbus->drift; len += snprintf(buf + len, PAGE_SIZE - len, "%-3s", sync_mode_name(xbus->sync_mode)); if(xbus->sync_mode == SYNC_MODE_PLL) { len += snprintf(buf + len, PAGE_SIZE - len, " %5d: lost (%4d,%4d) : ", xbus->ticker.cycle, driftinfo->lost_ticks, driftinfo->lost_tick_count); len += snprintf(buf + len, PAGE_SIZE - len, "DRIFT %3d %ld sec ago", xbus->sync_adjustment, (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at); } len += snprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } #ifdef SAMPLE_TICKS /* * tick sampling: Measure offset from reference ticker: * - Recording start when writing to: * /sys/bus/astribanks/devices/xbus-??/samples * - Recording ends when filling SAMPLE_SIZE ticks * - Results are read from the same sysfs file. * - Trying to read/write during recording, returns -EBUSY. */ static DEVICE_ATTR_READER(samples_show, dev, buf) { xbus_t *xbus; int len = 0; int i; xbus = dev_to_xbus(dev); if(xbus->sample_running) return -EBUSY; for(i = 0; i < SAMPLE_SIZE; i++) { if(len > PAGE_SIZE - 20) break; len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", xbus->sample_ticks[i]); } return len; } static DEVICE_ATTR_WRITER(samples_store, dev, buf, count) { xbus_t *xbus; xbus = dev_to_xbus(dev); if(xbus->sample_running) return -EBUSY; memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks)); xbus->sample_pos = 0; xbus->sample_running = 1; return count; } #endif /* * Clear statistics */ static DEVICE_ATTR_WRITER(cls_store, dev, buf, count) { xbus_t *xbus; struct xpp_drift *driftinfo; xbus = dev_to_xbus(dev); driftinfo = &xbus->drift; driftinfo->lost_ticks = 0; driftinfo->lost_tick_count = 0; xbus->min_tx_sync = INT_MAX; xbus->max_tx_sync = 0; xbus->min_rx_sync = INT_MAX; xbus->max_rx_sync = 0; #ifdef SAMPLE_TICKS memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks)); #endif return count; } static DEVICE_ATTR_READER(waitfor_xpds_show, dev, buf) { xbus_t *xbus; int len; xbus = dev_to_xbus(dev); len = waitfor_xpds(xbus, buf); return len; } static DEVICE_ATTR_READER(refcount_xbus_show, dev, buf) { xbus_t *xbus; int len; xbus = dev_to_xbus(dev); len = sprintf(buf, "%d\n", refcount_xbus(xbus)); return len; } static DEVICE_ATTR_READER(driftinfo_show, dev, buf) { xbus_t *xbus; struct xpp_drift *di; struct xpp_ticker *ticker; struct timeval now; int len = 0; int hours; int minutes; int seconds; int speed_range; int uframes_inaccuracy; int i; xbus = dev_to_xbus(dev); di = &xbus->drift; ticker = &xbus->ticker; /* * Calculate lost ticks time */ do_gettimeofday(&now); seconds = now.tv_sec - di->last_lost_tick.tv.tv_sec; minutes = seconds / 60; seconds = seconds % 60; hours = minutes / 60; minutes = minutes % 60; #define SHOW(ptr,item) len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", #item, (ptr)->item) len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d (was %d:%02d:%02d ago)\n", "lost_ticks", di->lost_ticks, hours, minutes, seconds); speed_range = abs(di->max_speed - di->min_speed); uframes_inaccuracy = di->sync_inaccuracy / 125; len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d ", "instability", speed_range + uframes_inaccuracy); if(xbus->sync_mode == SYNC_MODE_AB) { buf[len++] = '-'; } else { for(i = 0; len < PAGE_SIZE - 1 && i < speed_range + uframes_inaccuracy; i++) buf[len++] = '#'; } buf[len++] = '\n'; len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d (uframes)\n", "inaccuracy", uframes_inaccuracy); len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "speed_range", speed_range); SHOW(xbus, sync_adjustment); len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "offset (usec)", di->offset_prev); SHOW(di, offset_range); len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "best_speed", (di->max_speed + di->min_speed) / 2); SHOW(di, min_speed); SHOW(di, max_speed); SHOW(ticker, cycle); SHOW(ticker, tick_period); SHOW(ticker, count); #undef SHOW return len; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) #define xbus_attr(field, format_string) \ static ssize_t \ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ xbus_t *xbus; \ \ xbus = dev_to_xbus(dev); \ return sprintf (buf, format_string, xbus->field); \ } #else #define xbus_attr(field, format_string) \ static ssize_t \ field##_show(struct device *dev, char *buf) \ { \ xbus_t *xbus; \ \ xbus = dev_to_xbus(dev); \ return sprintf (buf, format_string, xbus->field); \ } #endif xbus_attr(connector, "%s\n"); xbus_attr(label, "%s\n"); static struct device_attribute xbus_dev_attrs[] = { __ATTR_RO(connector), __ATTR_RO(label), __ATTR_RO(status), __ATTR_RO(timing), __ATTR_RO(refcount_xbus), __ATTR_RO(waitfor_xpds), __ATTR_RO(driftinfo), __ATTR(cls, S_IWUSR, NULL, cls_store), __ATTR(xbus_state, S_IRUGO | S_IWUSR, xbus_state_show, xbus_state_store), #ifdef SAMPLE_TICKS __ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store), #endif __ATTR_NULL, }; static int astribank_match(struct device *dev, struct device_driver *driver) { DBG(DEVICES, "SYSFS MATCH: dev->bus_id = %s, driver->name = %s\n", dev_name(dev), driver->name); return 1; } #ifdef OLD_HOTPLUG_SUPPORT static int astribank_hotplug(struct device *dev, char **envp, int envnum, char *buff, int bufsize) { xbus_t *xbus; if(!dev) return -ENODEV; xbus = dev_to_xbus(dev); envp[0] = buff; if(snprintf(buff, bufsize, "XBUS_NAME=%s", xbus->busname) >= bufsize) return -ENOMEM; envp[1] = NULL; return 0; } #else #define XBUS_VAR_BLOCK \ do { \ XBUS_ADD_UEVENT_VAR("XPP_INIT_DIR=%s", initdir); \ XBUS_ADD_UEVENT_VAR("XBUS_NUM=%02d", xbus->num); \ XBUS_ADD_UEVENT_VAR("XBUS_NAME=%s", xbus->busname); \ } while(0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) #define XBUS_ADD_UEVENT_VAR(fmt, val...) \ do { \ int err = add_uevent_var(envp, num_envp, &i, \ buffer, buffer_size, &len, \ fmt, val); \ if (err) \ return err; \ } while (0) static int astribank_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { xbus_t *xbus; int i = 0; int len = 0; extern char *initdir; if(!dev) return -ENODEV; xbus = dev_to_xbus(dev); DBG(GENERAL, "SYFS bus_id=%s xbus=%s\n", dev_name(dev), xbus->busname); XBUS_VAR_BLOCK; envp[i] = NULL; return 0; } #else #define XBUS_ADD_UEVENT_VAR(fmt, val...) \ do { \ int err = add_uevent_var(kenv, fmt, val); \ if (err) \ return err; \ } while (0) static int astribank_uevent(struct device *dev, struct kobj_uevent_env *kenv) { xbus_t *xbus; extern char *initdir; if(!dev) return -ENODEV; xbus = dev_to_xbus(dev); DBG(GENERAL, "SYFS bus_id=%s xbus=%s\n", dev_name(dev), xbus->busname); XBUS_VAR_BLOCK; return 0; } #endif #endif /* OLD_HOTPLUG_SUPPORT */ void astribank_uevent_send(xbus_t *xbus, enum kobject_action act) { struct kobject *kobj; kobj = &xbus->astribank.kobj; XBUS_DBG(DEVICES, xbus, "SYFS bus_id=%s action=%d\n", dev_name(&xbus->astribank), act); #if defined(OLD_HOTPLUG_SUPPORT_269) { /* Copy from new kernels lib/kobject_uevent.c */ static const char *str[] = { [KOBJ_ADD] "add", [KOBJ_REMOVE] "remove", [KOBJ_CHANGE] "change", [KOBJ_MOUNT] "mount", [KOBJ_UMOUNT] "umount", [KOBJ_OFFLINE] "offline", [KOBJ_ONLINE] "online" }; kobject_hotplug(str[act], kobj); } #elif defined(OLD_HOTPLUG_SUPPORT) kobject_hotplug(kobj, act); #else kobject_uevent(kobj, act); #endif } static void astribank_release(struct device *dev) { xbus_t *xbus; BUG_ON(!dev); xbus = dev_to_xbus(dev); if(XBUS_FLAGS(xbus, CONNECTED)) { XBUS_ERR(xbus, "Try to release CONNECTED device.\n"); BUG(); } if(!XBUS_IS(xbus, IDLE) && !XBUS_IS(xbus, FAIL) && !XBUS_IS(xbus, DEACTIVATED)) { XBUS_ERR(xbus, "Try to release in state %s\n", xbus_statename(XBUS_STATE(xbus))); BUG(); } XBUS_INFO(xbus, "[%s] Astribank Release\n", xbus->label); xbus_free(xbus); } static void toplevel_release(struct device *dev) { NOTICE("%s\n", __func__); } static struct device toplevel_device = { .release = toplevel_release, /* No Parent */ }; static struct bus_type toplevel_bus_type = { .name = "astribanks", .match = astribank_match, #ifdef OLD_HOTPLUG_SUPPORT .hotplug = astribank_hotplug, #else .uevent = astribank_uevent, #endif .dev_attrs = xbus_dev_attrs, .drv_attrs = xpp_attrs, }; static int astribank_probe(struct device *dev) { xbus_t *xbus; xbus = dev_to_xbus(dev); XBUS_DBG(DEVICES, xbus, "SYSFS\n"); return 0; } static int astribank_remove(struct device *dev) { xbus_t *xbus; xbus = dev_to_xbus(dev); XBUS_INFO(xbus, "[%s] Atribank Remove\n", xbus->label); return 0; } static struct device_driver xpp_driver = { .name = "xppdrv", .bus = &toplevel_bus_type, .probe = astribank_probe, .remove = astribank_remove, #ifndef OLD_HOTPLUG_SUPPORT .owner = THIS_MODULE #endif }; /*--------- Sysfs XPD handling ----*/ static DEVICE_ATTR_READER(chipregs_show, dev, buf) { xpd_t *xpd; unsigned long flags; reg_cmd_t *regs; bool do_datah; char datah_str[50]; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); regs = &xpd->last_reply; len += sprintf(buf + len, "# Writing bad data into this file may damage your hardware!\n"); len += sprintf(buf + len, "# Consult firmware docs first\n"); len += sprintf(buf + len, "#\n"); do_datah = REG_FIELD(regs, do_datah) ? 1 : 0; if(do_datah) { snprintf(datah_str, ARRAY_SIZE(datah_str), "\t%02X", REG_FIELD(regs, data_high)); } else datah_str[0] = '\0'; if(REG_FIELD(regs, do_subreg)) { len += sprintf(buf + len, "#CH\tOP\tReg.\tSub\tDL%s\n", (do_datah) ? "\tDH" : ""); len += sprintf(buf + len, "%2d\tRS\t%02X\t%02X\t%02X%s\n", regs->portnum, REG_FIELD(regs, regnum), REG_FIELD(regs, subreg), REG_FIELD(regs, data_low), datah_str); } else { len += sprintf(buf + len, "#CH\tOP\tReg.\tDL%s\n", (do_datah) ? "\tDH" : ""); len += sprintf(buf + len, "%2d\tRD\t%02X\t%02X%s\n", regs->portnum, REG_FIELD(regs, regnum), REG_FIELD(regs, data_low), datah_str); } spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(chipregs_store, dev, buf, count) { xpd_t *xpd; const char *p; char tmp[MAX_PROC_WRITE]; int i; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); //XPD_DBG(GENERAL, xpd, "%s\n", buf); if(!xpd) return -ENODEV; p = buf; while((p - buf) < count) { i = strcspn(p, "\r\n"); if(i > 0) { if(i >= MAX_PROC_WRITE) { XPD_NOTICE(xpd, "Command too long (%d chars)\n", i); return -E2BIG; } memcpy(tmp, p, i); tmp[i] = '\0'; ret = parse_chip_command(xpd, tmp); if(ret < 0) { XPD_NOTICE(xpd, "Failed writing command: '%s'\n", tmp); return ret; } } p += i + 1; /* Don't flood command_queue */ if(xframe_queue_count(&xpd->xbus->command_queue) > 5) msleep(6); } return count; } static DEVICE_ATTR_READER(blink_show, dev, buf) { xpd_t *xpd; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf, "0x%lX\n", xpd->blink_mode); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(blink_store, dev, buf, count) { xpd_t *xpd; char *endp; unsigned long blink; BUG_ON(!dev); xpd = dev_to_xpd(dev); //XPD_DBG(GENERAL, xpd, "%s\n", buf); if(!xpd) return -ENODEV; blink = simple_strtoul(buf, &endp, 0); if(*endp != '\0' && *endp != '\n' && *endp != '\r') return -EINVAL; if(blink > 0xFFFF) return -EINVAL; XPD_DBG(GENERAL, xpd, "BLINK channels: 0x%lX\n", blink); xpd->blink_mode = blink; return count; } static DEVICE_ATTR_READER(span_show, dev, buf) { xpd_t *xpd; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf, "%d\n", SPAN_REGISTERED(xpd) ? PHONEDEV(xpd).span.spanno : 0); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(span_store, dev, buf, count) { xpd_t *xpd; int dahdi_reg; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; ret = sscanf(buf, "%d", &dahdi_reg); if(ret != 1) return -EINVAL; if(!XBUS_IS(xpd->xbus, READY)) return -ENODEV; XPD_DBG(GENERAL, xpd, "%s\n", (dahdi_reg) ? "register" : "unregister"); if(dahdi_reg) ret = dahdi_register_xpd(xpd); else ret = dahdi_unregister_xpd(xpd); return (ret < 0) ? ret : count; } static DEVICE_ATTR_READER(type_show, dev, buf) { xpd_t *xpd; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; len += sprintf(buf, "%s\n", xpd->type_name); return len; } static DEVICE_ATTR_READER(offhook_show, dev, buf) { xpd_t *xpd; int len = 0; int i; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; for_each_line(xpd, i) { len += sprintf(buf + len, "%d ", IS_OFFHOOK(xpd, i)); } if(len) { len--; /* backout last space */ } len += sprintf(buf + len, "\n"); return len; } static DEVICE_ATTR_READER(timing_priority_show, dev, buf) { xpd_t *xpd; unsigned long flags; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if(!xpd) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); len += sprintf(buf + len, "%d\n", PHONEDEV(xpd).timing_priority); spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_READER(refcount_xpd_show, dev, buf) { xpd_t *xpd; int len = 0; BUG_ON(!dev); xpd = dev_to_xpd(dev); if (!xpd) return -ENODEV; len += sprintf(buf + len, "%d\n", refcount_xpd(xpd)); return len; } static int xpd_match(struct device *dev, struct device_driver *driver) { struct xpd_driver *xpd_driver; xpd_t *xpd; xpd_driver = driver_to_xpd_driver(driver); xpd = dev_to_xpd(dev); if(xpd_driver->type != xpd->type) { XPD_DBG(DEVICES, xpd, "SYSFS match fail: xpd->type = %d, xpd_driver->type = %d\n", xpd->type, xpd_driver->type); return 0; } XPD_DBG(DEVICES, xpd, "SYSFS MATCH: type=%d dev->bus_id = %s, driver->name = %s\n", xpd->type, dev_name(dev), driver->name); return 1; } static struct device_attribute xpd_dev_attrs[] = { __ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store), __ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store), __ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store), __ATTR_RO(type), __ATTR_RO(offhook), __ATTR_RO(timing_priority), __ATTR_RO(refcount_xpd), __ATTR_NULL, }; static struct bus_type xpd_type = { .name = "xpds", .match = xpd_match, .dev_attrs = xpd_dev_attrs, }; int xpd_driver_register(struct device_driver *driver) { int ret; DBG(DEVICES, "%s\n", driver->name); driver->bus = &xpd_type; if((ret = driver_register(driver)) < 0) { ERR("%s: driver_register(%s) failed. Error number %d", __FUNCTION__, driver->name, ret); } return ret; } void xpd_driver_unregister(struct device_driver *driver) { DBG(DEVICES, "%s\n", driver->name); driver_unregister(driver); } static void xpd_release(struct device *dev) { xpd_t *xpd; BUG_ON(!dev); xpd = dev_to_xpd(dev); XPD_DBG(DEVICES, xpd, "SYSFS\n"); xpd_remove(xpd); } int xpd_device_register(xbus_t *xbus, xpd_t *xpd) { struct device *dev = &xpd->xpd_dev; int ret; XPD_DBG(DEVICES, xpd, "SYSFS\n"); dev->bus = &xpd_type; dev->parent = &xbus->astribank; dev_set_name(dev, "%02d:%1x:%1x", xbus->num, xpd->addr.unit, xpd->addr.subunit); dev_set_drvdata(dev, xpd); dev->release = xpd_release; ret = device_register(dev); if(ret) { XPD_ERR(xpd, "%s: device_register failed: %d\n", __FUNCTION__, ret); return ret; } return 0; } void xpd_device_unregister(xpd_t *xpd) { xbus_t *xbus; struct device *dev; xbus = xpd->xbus; BUG_ON(!xbus); XPD_DBG(DEVICES, xpd, "SYSFS\n"); dev = &xpd->xpd_dev; if(!dev_get_drvdata(dev)) return; BUG_ON(dev_get_drvdata(dev) != xpd); device_unregister(dev); dev_set_drvdata(dev, NULL); } static DEVICE_ATTR_READER(echocancel_show, dev, buf) { xpd_t *xpd; unsigned long flags; int len = 0; xpp_line_t ec_mask = 0; int i; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); if (!xpd) return -ENODEV; if (!ECHOOPS(xpd->xbus)) return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); for (i = 0; i < PHONEDEV(xpd).channels; i++) { ret = CALL_EC_METHOD(ec_get, xpd->xbus, xpd, i); if (ret < 0) { LINE_ERR(xpd, i, "ec_get failed\n"); len = -ENODEV; goto out; } if (ret) ec_mask |= (1 << i); } len += sprintf(buf, "0x%08X\n", ec_mask); out: spin_unlock_irqrestore(&xpd->lock, flags); return len; } static DEVICE_ATTR_WRITER(echocancel_store, dev, buf, count) { xpd_t *xpd; char *endp; unsigned long mask; int channels; int ret; BUG_ON(!dev); xpd = dev_to_xpd(dev); XPD_DBG(GENERAL, xpd, "%s\n", buf); if (!xpd) return -ENODEV; if (!ECHOOPS(xpd->xbus)) { XPD_ERR(xpd, "No echo canceller in this XBUS\n"); return -ENODEV; } if (!IS_PHONEDEV(xpd)) { XPD_ERR(xpd, "Not a phone device\n"); return -ENODEV; } channels = PHONEDEV(xpd).channels; mask = simple_strtoul(buf, &endp, 0); if (*endp != '\0' && *endp != '\n' && *endp != '\r') { XPD_ERR(xpd, "Too many channels: %d\n", channels); return -EINVAL; } if (mask != 0 && __ffs(mask) > channels) { XPD_ERR(xpd, "Channel mask (0x%lX) larger than available channels (%d)\n", mask, channels); return -EINVAL; } XPD_DBG(GENERAL, xpd, "ECHOCANCEL channels: 0x%lX\n", mask); ret = CALL_PHONE_METHOD(echocancel_setmask, xpd, mask); if (ret < 0) { XPD_ERR(xpd, "echocancel_setmask failed\n"); return ret; } return count; } static DEVICE_ATTR(echocancel, S_IRUGO | S_IWUSR, echocancel_show, echocancel_store); int echocancel_xpd(xpd_t *xpd, int on) { int ret; XPD_DBG(GENERAL, xpd, "echocancel_xpd(%s)\n", (on) ? "on" : "off"); if (!on) { device_remove_file(xpd->echocancel, &dev_attr_echocancel); return 0; } ret = device_create_file(&xpd->xpd_dev, &dev_attr_echocancel); if (ret) XPD_ERR(xpd, "%s: device_create_file(echocancel) failed: %d\n", __func__, ret); return ret; } EXPORT_SYMBOL(echocancel_xpd); /*--------- Sysfs Device handling ----*/ void xbus_sysfs_transport_remove(xbus_t *xbus) { struct device *astribank; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); astribank = &xbus->astribank; sysfs_remove_link(&astribank->kobj, "transport"); } int xbus_sysfs_transport_create(xbus_t *xbus) { struct device *astribank; struct device *transport_device; int ret = 0; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); astribank = &xbus->astribank; BUG_ON(!astribank); transport_device = xbus->transport.transport_device; if (!transport_device) { XBUS_ERR(xbus, "%s: Missing transport_device\n", __func__); return -ENODEV; } ret = sysfs_create_link(&astribank->kobj, &transport_device->kobj, "transport"); if (ret < 0) { XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", __func__, ret); dev_set_drvdata(astribank, NULL); } return ret; } void xbus_sysfs_remove(xbus_t *xbus) { struct device *astribank; BUG_ON(!xbus); XBUS_DBG(DEVICES, xbus, "\n"); astribank = &xbus->astribank; if(!dev_get_drvdata(astribank)) return; BUG_ON(dev_get_drvdata(astribank) != xbus); device_unregister(astribank); dev_set_drvdata(astribank, NULL); } int xbus_sysfs_create(xbus_t *xbus) { struct device *astribank; int ret = 0; BUG_ON(!xbus); astribank = &xbus->astribank; XBUS_DBG(DEVICES, xbus, "\n"); astribank->bus = &toplevel_bus_type; astribank->parent = &toplevel_device; dev_set_name(astribank, "xbus-%02d", xbus->num); dev_set_drvdata(astribank, xbus); astribank->release = astribank_release; ret = device_register(astribank); if(ret) { XBUS_ERR(xbus, "%s: device_register failed: %d\n", __FUNCTION__, ret); dev_set_drvdata(astribank, NULL); } return ret; } int __init xpp_driver_init(void) { int ret; DBG(DEVICES, "SYSFS\n"); dev_set_name(&toplevel_device, "astribanks"); ret = device_register(&toplevel_device); if (ret) { ERR("%s: toplevel device_register failed: %d\n", __func__, ret); goto failed_toplevel; } if((ret = bus_register(&toplevel_bus_type)) < 0) { ERR("%s: bus_register(%s) failed. Error number %d", __FUNCTION__, toplevel_bus_type.name, ret); goto failed_bus; } if((ret = driver_register(&xpp_driver)) < 0) { ERR("%s: driver_register(%s) failed. Error number %d", __FUNCTION__, xpp_driver.name, ret); goto failed_xpp_driver; } if((ret = bus_register(&xpd_type)) < 0) { ERR("%s: bus_register(%s) failed. Error number %d", __FUNCTION__, xpd_type.name, ret); goto failed_xpd_bus; } return 0; failed_xpd_bus: driver_unregister(&xpp_driver); failed_xpp_driver: bus_unregister(&toplevel_bus_type); failed_bus: device_unregister(&toplevel_device); failed_toplevel: return ret; } void xpp_driver_exit(void) { DBG(DEVICES, "SYSFS\n"); bus_unregister(&xpd_type); driver_unregister(&xpp_driver); bus_unregister(&toplevel_bus_type); device_unregister(&toplevel_device); } EXPORT_SYMBOL(xpd_driver_register); EXPORT_SYMBOL(xpd_driver_unregister); dahdi-linux-2.5.0.1/drivers/dahdi/xpp/firmwares/0000755000175000017500000000000011632333706021350 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/xpp/firmwares/LICENSE.firmware0000644000175000017500000000525610751714440024177 0ustar tzafrirtzafrirThe firmware files (*.hex) in this directory are software for the Astribank itself and not intended to run on the Linux system itself. They are generally freely distriributable (see exact terms below). /****************************************************************************/ /* Copyright (c) 2004-2006 Xorcom Inc. All Rights Reserved. */ /* Redistribution and use of the microcode software ( Firmware ) is */ /* permitted provided that the following conditions are met: */ /* */ /* 1. Firmware is redistributed verbatim without any modification; */ /* 2. Any reproduction of Firmware must contain the above */ /* copyright notice, this list of conditions and the below */ /* disclaimer in the documentation and/or other materials */ /* provided with the distribution; and */ /* 3. The name of Xorcom may not be used to endorse or promote */ /* products derived from this Firmware without specific prior */ /* written consent. */ /* */ /* Disclaimer: Xorcom provides this firmware "as is" with no warranties */ /* or indemnities whatsoever. Xorcom expressly disclaims any express, */ /* statutory or implied warranties, including, but not limited to, the */ /* implied warranties of merchantability, fitness for a particular */ /* purpose and non-infringement. In no event shall Xorcom be liable for */ /* any direct, indirect, incidental, special, exemplary, or consequential */ /* damages (including, but not limited to, procurement of substitute */ /* goods or services; loss of use, data, or profits; or business */ /* interruption) however caused and on any theory of liability, whether */ /* in contract, strict liability, or tort (including negligence or */ /* otherwise) arising in any way out of the use of this firmware, even */ /* if advised of the possibility of such damage. User acknowledges and */ /* agrees that the purchase or use of the firmware will not create or */ /* give grounds for a license by implication, estoppel, or otherwise in */ /* any intellectual property rights (patent, copyright, trade secret, */ /* mask work, or other proprietary right) embodied in any other Xorcom */ /* hardware or firmware either solely or in combination with the firmware. */ /****************************************************************************/ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/firmwares/README0000644000175000017500000000117010751714440022226 0ustar tzafrirtzafrirThis distribution includes the firmware files required by the Xorcom[tm] Astribank[tm]. This distribution inlcudes just the firmware files. Be sure to use a zaptel distribution/package of a matching version. INSTALLATION """""""""""" run "make install" as root. (which will simply copy all the *.hex files to /usr/share/zaptel ) USAGE """"" When the firmware files are in place everything should work automagically. Consult the xpp documentation included in the package zaptel (or the debian package zaptel) that you use for further information. For further information contact support@xorcom.com http://xorcom.com dahdi-linux-2.5.0.1/drivers/dahdi/xpp/firmwares/Makefile0000644000175000017500000000111611607107447023012 0ustar tzafrirtzafrir# Install firmwares and initialization scripts for the Astribank # drivers FPGA_FW = FPGA_FXS.hex FPGA_1141.hex FPGA_1151.hex FPGA_1161.hex PIC_FW = PIC_TYPE_1.hex PIC_TYPE_2.hex PIC_TYPE_3.hex PIC_TYPE_4.hex OCT_FW = $(wildcard OCT6104E-256D.ima) FIRMWARES = USB_FW.hex $(FPGA_FW) $(PIC_FW) $(OCT_FW) PROTO_VER = 30 SCRIPTS_BASE = $(patsubst %,init_card_%_$(PROTO_VER),1 2 3 4 5) SCRIPTS = $(SCRIPTS_BASE:%=../%) TARGET = $(DESTDIR)/usr/share/dahdi all: clean: install: mkdir -p $(TARGET) install $(SCRIPTS) $(TARGET)/ install -m 644 ../XppConfig.pm $(FIRMWARES) $(TARGET)/ dahdi-linux-2.5.0.1/drivers/dahdi/xpp/mmapdrv.c0000644000175000017500000004004411447224745021173 0ustar tzafrirtzafrir#include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmapbus.h" #include "xbus-core.h" #include "dahdi_debug.h" #include "xdefs.h" #include "xproto.h" #include "xframe_queue.h" /* Check at compile time that sizeof(xframe_t) is a multiple of 4 */ typedef char sizeof_xframe_t_should_be_divisible_by_4[((sizeof(xframe_t) % 4) == 0) * 2 - 1]; #define ssync() __builtin_bfin_ssync() //#define AB_IN_BUF PF5 /* firmware pins */ #define DATA PG8 #define NCONFIG PG9 #define CONF_DONE PG10 #define DCLK PG11 #define NSTATUS PG12 #ifdef DEBUG_VIA_GPIO /* * For debugging we can use the following two pins. * These two pins are not used *after initialization* */ #define DEBUG_GPIO1 CONF_DONE #define DEBUG_GPIO2 NSTATUS static int rx_intr_counter; #endif #define FPGA_RX_IRQ IRQ_PF7 #define FPGA_TX_IRQ IRQ_PF4 #define FPGA_BASE_ADDR ((volatile char __iomem *)0x203FA800) #define END_OF_FRAME 0x0001 #define GET_LEN 0x0002 #define START_RD_BURST 0x0008 #define AS_BF_MODE 0x0010 //stand alone Astribank without USB (Asterisk BlackFin Mode) #define EC_BF_MODE 0x0020 //all data between Astribank and USB routed thru BF(EchoCanceler BlackFin Mode) #define NO_BF_MODE 0x0040 //Astribank worke with USB only (no BlackFin Mode) #define SET_XA_DIR 0x0080 #define GET_XPD_STS 0x0100 #define GET_CHECKSUM 0x0200 static const char rcsid[] = "$Id: mmapdrv.c 9411 2010-09-24 22:44:53Z sruffell $"; static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); static DEF_PARM(int, notxrx, 0, 0644, "Don't send or receive anything"); struct counter { long intr_min, intr_max; long intr_avg, intr_count; }; static xbus_t *global_xbus; static bool tx_ready = 1; static DEFINE_SPINLOCK(tx_ready_lock); static struct xframe_queue txpool; static unsigned int pcm_in_pool_count; static bool disconnecting; static struct kmem_cache *xframe_cache; static struct counter tx_counter, rx_counter; static unsigned long pcm_dropped; static void print_buffer(const char *msg, const char *buf, int len) { int i; printk(KERN_ERR "%s", msg); for (i = 0; i < len; i++) { printk("%02X ", (unsigned char)buf[i]); } printk("\n"); } static void update_counter(struct counter *c, struct timeval *tv1) { struct timeval tv2; long diff; do_gettimeofday(&tv2); diff = usec_diff(&tv2, tv1); if (c->intr_min > diff) c->intr_min = diff; if (c->intr_max < diff) c->intr_max = diff; c->intr_avg = (c->intr_avg*c->intr_count + diff) / (c->intr_count+1); c->intr_count++; } static irqreturn_t xpp_mmap_rx_irq(int irq, void *dev_id) { unsigned short rxcnt; xbus_t *xbus; xframe_t *xframe; byte *buf; bool in_use = 0; struct timeval tv1; do_gettimeofday(&tv1); if (unlikely(disconnecting)) return IRQ_HANDLED; xbus = xbus_num(global_xbus->num); BUG_ON(!xbus); if(!XBUS_GET(xbus)) { if (printk_ratelimit()) XBUS_ERR(xbus, "Dropping packet. Is shutting down.\n"); goto out; } in_use = 1; outw(GET_LEN, FPGA_BASE_ADDR + 4); rxcnt = inw(FPGA_BASE_ADDR); if (rxcnt < 3) { if (printk_ratelimit()) NOTICE("Got %d bytes\n", rxcnt); goto out; } if(rxcnt >= XFRAME_DATASIZE) { if (printk_ratelimit()) ERR("Bad rxcnt=%d\n", rxcnt); goto out; } xframe = ALLOC_RECV_XFRAME(xbus); if (!xframe) { if (printk_ratelimit()) XBUS_ERR(xbus, "Empty receive_pool\n"); goto out; } buf = xframe->packets; atomic_set(&xframe->frame_len, rxcnt); do_gettimeofday(&xframe->tv_received); #ifdef DEBUG_VIA_GPIO if (rx_intr_counter & 1) bfin_write_PORTGIO_SET(DEBUG_GPIO1); else bfin_write_PORTGIO_CLEAR(DEBUG_GPIO1); #endif outw(START_RD_BURST, FPGA_BASE_ADDR + 4); insw((unsigned long)FPGA_BASE_ADDR, buf, rxcnt / 2); #if 0 for (count = 0; count < rxcnt; count+=2) { unsigned short v = inw(FPGA_BASE_ADDR); buf[count] = v & 0xFF; buf[count+1] = v >> 8; } #endif if (rxcnt & 1) buf[rxcnt-1] = inw(FPGA_BASE_ADDR); /* Sanity check: length of first packet in frame should be no more than the frame length */ if (((buf[0] | (buf[1]<<8)) & 0x3FF) > rxcnt) { if (printk_ratelimit()) { ERR("Packet len=%d, frame len=%d\n", (buf[0] | (buf[1]<<8)) & 0x3FF, rxcnt); print_buffer("16 bytes of packet: ", buf, 16); } goto free; } if (debug && buf[2] != 0x12) print_buffer("Received: ", buf, rxcnt); if (!notxrx) { xbus_receive_xframe(xbus, xframe); #ifdef DEBUG_VIA_GPIO if (rx_intr_counter & 1) bfin_write_PORTGIO_SET(DEBUG_GPIO2); else bfin_write_PORTGIO_CLEAR(DEBUG_GPIO2); #endif goto out; } free: FREE_RECV_XFRAME(xbus, xframe); out: if (in_use) XBUS_PUT(xbus); #ifdef DEBUG_VIA_GPIO rx_intr_counter++; #endif update_counter(&rx_counter, &tv1); return IRQ_HANDLED; } static void send_buffer(unsigned char *buf, unsigned long len) { if (debug && len >= 3 && buf[2] != 0x11) print_buffer("Sent: ", buf, len); outsw((unsigned long)FPGA_BASE_ADDR, buf, len / 2); if (len & 1) outw((unsigned short)buf[len-1], FPGA_BASE_ADDR); outw(END_OF_FRAME, FPGA_BASE_ADDR + 4); } static irqreturn_t xpp_mmap_tx_irq(int irq, void *dev_id) { unsigned long flags; xbus_t *xbus; xframe_t *xframe; struct timeval tv1; do_gettimeofday(&tv1); if (unlikely(disconnecting)) { update_counter(&tx_counter, &tv1); return IRQ_HANDLED; } spin_lock_irqsave(&tx_ready_lock, flags); xframe = xframe_dequeue(&txpool); if (!xframe) { tx_ready = 1; spin_unlock_irqrestore(&tx_ready_lock, flags); update_counter(&tx_counter, &tv1); return IRQ_HANDLED; } tx_ready = 0; if (XPACKET_IS_PCM((xpacket_t *)xframe->packets)) pcm_in_pool_count--; spin_unlock_irqrestore(&tx_ready_lock, flags); xbus = (xbus_t *)xframe->priv; BUG_ON(!xbus); xbus = xbus_num(xbus->num); BUG_ON(!xbus); send_buffer(xframe->packets, XFRAME_LEN(xframe)); FREE_SEND_XFRAME(xbus, xframe); update_counter(&tx_counter, &tv1); return IRQ_HANDLED; } static int xframe_send_common(xbus_t *xbus, xframe_t *xframe, bool pcm) { unsigned long flags; if (unlikely(disconnecting)) { FREE_SEND_XFRAME(xbus, xframe); return -ENODEV; } if (unlikely(notxrx)) { FREE_SEND_XFRAME(xbus, xframe); return 0; } spin_lock_irqsave(&tx_ready_lock, flags); if (tx_ready) { tx_ready = 0; send_buffer(xframe->packets, XFRAME_LEN(xframe)); spin_unlock_irqrestore(&tx_ready_lock, flags); FREE_SEND_XFRAME(xbus, xframe); } else { if (pcm && pcm_in_pool_count >= 1) { static int rate_limit; if ((rate_limit++ % 1000) == 0) XBUS_ERR(xbus, "Dropped PCM xframe (pcm_in_pool_count=%d).\n", pcm_in_pool_count); FREE_SEND_XFRAME(xbus, xframe); pcm_dropped++; } else { if (!xframe_enqueue(&txpool, xframe)) { static int rate_limit; spin_unlock_irqrestore(&tx_ready_lock, flags); if ((rate_limit++ % 1000) == 0) XBUS_ERR(xbus, "Dropped xframe. Cannot enqueue.\n"); FREE_SEND_XFRAME(xbus, xframe); return -E2BIG; } if (pcm) pcm_in_pool_count++; } spin_unlock_irqrestore(&tx_ready_lock, flags); } return 0; } static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags) { xframe_t *xframe = kmem_cache_alloc(xframe_cache, gfp_flags); if (!xframe) { static int rate_limit; if ((rate_limit++ % 1000) < 5) XBUS_ERR(xbus, "frame allocation failed (%d)\n", rate_limit); return NULL; } xframe_init(xbus, xframe, ((byte*)xframe) + sizeof(xframe_t), XFRAME_DATASIZE, xbus); return xframe; } static void free_xframe(xbus_t *xbus, xframe_t *xframe) { memset(xframe, 0, sizeof(*xframe)); kmem_cache_free(xframe_cache, xframe); } static int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe) { return xframe_send_common(xbus, xframe, 1); } static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe) { return xframe_send_common(xbus, xframe, 0); } static struct xbus_ops xmmap_ops = { .xframe_send_pcm = xframe_send_pcm, .xframe_send_cmd = xframe_send_cmd, .alloc_xframe = alloc_xframe, .free_xframe = free_xframe, }; static int fill_proc_queue(char *p, struct xframe_queue *q) { int len; len = sprintf(p, "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", q->name, q->steady_state_count, q->count, q->max_count, q->worst_count, q->overflows, q->worst_lag_usec / 1000, q->worst_lag_usec % 1000); xframe_queue_clearstats(q); return len; } static int fill_proc_counter(char *p, struct counter *c) { return sprintf(p, "min=%ld\nmax=%ld\navg=%ld\ncount=%ld\n", c->intr_min, c->intr_max, c->intr_avg, c->intr_count); } static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; len += fill_proc_queue(page + len, &txpool); len += sprintf(page + len, "pcm_in_pool_count=%d\n", pcm_in_pool_count); len += sprintf(page + len, "pcm_dropped=%lu\n", pcm_dropped); len += sprintf(page + len, "\nrx_counter:\n"); len += fill_proc_counter(page + len, &rx_counter); len += sprintf(page + len, "\ntx_counter:\n"); len += fill_proc_counter(page + len, &tx_counter); if (len <= off+count) { *eof = 1; tx_counter.intr_min = rx_counter.intr_min = INT_MAX; tx_counter.intr_max = rx_counter.intr_max = 0; tx_counter.intr_avg = rx_counter.intr_avg = 0; tx_counter.intr_count = rx_counter.intr_count = 0; } *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len; } static int xpp_mmap_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { int i = 0; char *txchunk, *p, *endp; if (count >= XFRAME_DATASIZE*3+10) return -EINVAL; p = txchunk = kmalloc(count+1, GFP_KERNEL); if (copy_from_user(txchunk, buffer, count)) { count = -EFAULT; goto out; } txchunk[count] = '\0'; while (*p) { unsigned long value; while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; if (*p == '\0') break; value = simple_strtoul(p, &endp, 16); if (endp == p || value > 0xFF) { INFO("%s: Bad input\n", __FUNCTION__); count = -EINVAL; goto out; } p = endp; txchunk[i++] = (char)value; } send_buffer(txchunk, i); out: kfree(txchunk); return count; } static struct mmap_driver astribank_driver = { .module = THIS_MODULE, .driver = { .name = "xpp_mmap", }, }; static struct mmap_device astribank_dev = { .name = "astribank0", .driver = &astribank_driver, }; static int __init xpp_mmap_load_fpga(u8 *data, size_t size) { size_t i; bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DATA | NCONFIG | DCLK); //set data, nconfig and dclk to port out bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DATA | NCONFIG | DCLK)); bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~(CONF_DONE | NSTATUS));//set conf_done and nstatus to port in bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DATA | NCONFIG | DCLK)); bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() | CONF_DONE | NSTATUS); bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low udelay(40); //Tcfg ~40us delay bfin_write_PORTGIO_SET(NCONFIG); //transition nCONFIG to high - reset end. udelay(40); //Tcf2ck ~40us delay if (!(bfin_read_PORTGIO() & NSTATUS)) return -EIO; //report reset faill - Tcf2st1 pass #if 0 if (!(bfin_read_PORTGIO() & CONF_DONE)) return -EIO; #endif bfin_write_PORTGIO_CLEAR(DCLK); for (i=0; i>= 1; bfin_write_PORTGIO_SET(DCLK); bfin_write_PORTGIO_CLEAR(DCLK); } if (!(bfin_read_PORTGIO() & NSTATUS)) return -EIO; //check the nSTATUS } bfin_write_PORTGIO_CLEAR(DATA); udelay(1); if (!(bfin_read_PORTGIO() & CONF_DONE)) return -EIO; #ifdef DEBUG_VIA_GPIO /* * Normal initialization is done. Now we can reuse * some pins that were used only during initialization * to be used for debugging from now on. */ bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DEBUG_GPIO1 | DEBUG_GPIO2); //set to port out bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); #endif udelay(40); //tCD2UM - CONF_DONE high to user mode return 0; } static void __exit xpp_mmap_unload_fpga(void) { bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low udelay(40); //Tcfg ~40us delay bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~( DATA | NCONFIG | DCLK)); //disable output pin bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~( CONF_DONE | NSTATUS));//disable input buffer INFO("FPGA Firmware unloaded\n"); } static int __init xpp_mmap_load_firmware(void) { const struct firmware *fw; int ret; if ((ret = request_firmware(&fw, "astribank.bin", &astribank_dev.dev)) < 0) return ret; xpp_mmap_load_fpga(fw->data, fw->size); release_firmware(fw); return ret; } static int __init xpp_mmap_init(void) { int ret; struct proc_dir_entry *proc_entry; if ((ret = register_mmap_bus()) < 0) goto bus_reg; if ((ret = register_mmap_driver(&astribank_driver)) < 0) goto driver_reg; if ((ret = register_mmap_device(&astribank_dev)) < 0) goto dev_reg; if ((ret = xpp_mmap_load_firmware()) < 0) { ERR("xpp_mmap_load_firmware() failed, errno=%d\n", ret); goto fail_fw; } if ((ret = request_irq(FPGA_RX_IRQ, xpp_mmap_rx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_rx", NULL)) < 0) { ERR("Unable to attach to RX interrupt %d\n", FPGA_RX_IRQ); goto fail_irq_rx; } if ((ret = request_irq(FPGA_TX_IRQ, xpp_mmap_tx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_tx", NULL)) < 0) { ERR("Unable to attach to TX interrupt %d\n", FPGA_TX_IRQ); goto fail_irq_tx; } if (!request_region((resource_size_t)FPGA_BASE_ADDR, 8, "xpp_mmap")) { ERR("Unable to request memory region at %p\n", FPGA_BASE_ADDR); goto fail_region; } outw(AS_BF_MODE, FPGA_BASE_ADDR + 4); xframe_cache = kmem_cache_create("xframe_cache", sizeof(xframe_t) + XFRAME_DATASIZE, 0, 0, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) NULL, #endif NULL); if(!xframe_cache) { ret = -ENOMEM; goto fail_cache; } /* interface with Dahdi */ global_xbus = xbus_new(&xmmap_ops, XFRAME_DATASIZE, NULL); if (!global_xbus) { ret = -ENOMEM; goto fail_xbus; } strncpy(global_xbus->connector, "mmap", XBUS_DESCLEN); strncpy(global_xbus->label, "mmap:0", LABEL_SIZE); xframe_queue_init(&txpool, 10, 200, "mmap_txpool", global_xbus); if (!(proc_entry = create_proc_entry("xpp_mmap", 0, global_xbus->proc_xbus_dir))) { ERR("create_proc_entry() failed\n"); ret = -EINVAL; goto fail_proc; } proc_entry->write_proc = xpp_mmap_proc_write; proc_entry->read_proc = xpp_mmap_proc_read; /* Go xbus, go! */ xbus_connect(global_xbus); INFO("xpp_mmap module loaded\n"); return 0; fail_proc: xbus_disconnect(global_xbus); fail_xbus: kmem_cache_destroy(xframe_cache); fail_cache: release_region((resource_size_t)FPGA_BASE_ADDR, 8); fail_region: free_irq(FPGA_TX_IRQ, NULL); fail_irq_tx: free_irq(FPGA_RX_IRQ, NULL); fail_irq_rx: fail_fw: unregister_mmap_device(&astribank_dev); dev_reg: unregister_mmap_driver(&astribank_driver); driver_reg: unregister_mmap_bus(); bus_reg: return ret; } static void __exit xpp_mmap_exit(void) { xbus_t *xbus; DBG(GENERAL, "\n"); disconnecting = 1; xbus = xbus_num(global_xbus->num); remove_proc_entry("xpp_mmap", xbus->proc_xbus_dir); xframe_queue_clear(&txpool); xbus_disconnect(xbus); kmem_cache_destroy(xframe_cache); release_region((resource_size_t)FPGA_BASE_ADDR, 8); free_irq(FPGA_RX_IRQ, NULL); free_irq(FPGA_TX_IRQ, NULL); unregister_mmap_device(&astribank_dev); unregister_mmap_driver(&astribank_driver); unregister_mmap_bus(); xpp_mmap_unload_fpga(); INFO("xpp_mmap module unloaded\n"); } module_init(xpp_mmap_init); module_exit(xpp_mmap_exit); MODULE_AUTHOR("Alexander Landau "); MODULE_LICENSE("GPL"); dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/0000755000175000017500000000000011631523354020360 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/voicebus/GpakCust.h0000644000175000017500000002116611571766210022263 0ustar tzafrirtzafrir/* * Copyright (c) 2005, Adaptive Digital Technologies, Inc. * * File Name: GpakCust.h * * Description: * This file contains host system dependent definitions and prototypes of * functions to support generic G.PAK API functions. The file is used when * integrating G.PAK API functions in a specific host processor environment. * * Note: This file may need to be modified by the G.PAK system integrator. * * Version: 1.0 * * Revision History: * 06/15/05 - Initial release. * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _GPAKCUST_H /* prevent multiple inclusion */ #define _GPAKCUST_H #include #include #include #include #include #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) #include #endif #include "gpakenum.h" #include "adt_lec.h" #define DEBUG_VPMADT032_ECHOCAN (1 << 4) /* Host and DSP system dependent related definitions. */ #define MAX_DSP_CORES 128 /* maximum number of DSP cores */ #define MAX_CHANNELS 32 /* maximum number of channels */ #define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */ #define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */ #define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */ #define VPM150M_MAX_COMMANDS 8 #define __VPM150M_RWPAGE (1 << 4) #define __VPM150M_RD (1 << 3) #define __VPM150M_WR (1 << 2) #define __VPM150M_FIN (1 << 1) #define __VPM150M_TX (1 << 0) #define __VPM150M_RWPAGE (1 << 4) #define __VPM150M_RD (1 << 3) #define __VPM150M_WR (1 << 2) #define __VPM150M_FIN (1 << 1) #define __VPM150M_TX (1 << 0) /* Some Bit ops for different operations */ #define VPM150M_HPIRESET 1 #define VPM150M_SWRESET 2 #define VPM150M_ACTIVE 4 #define NLPTYPE_NONE 0 #define NLPTYPE_MUTE 1 #define NLPTYPE_RANDOM_NOISE 2 #define HOTH_NOISE_NLPTYPE 3 #define NLPTYPE_SUPPRESS 4 #define NLPTYPE_RESERVED 5 #define NLPTYPE_AUTOSUPPRESS 6 #define DEFAULT_NLPTYPE NLPTYPE_AUTOSUPPRESS /* This is the threshold (in dB) for enabling and disabling of the NLP */ #define DEFAULT_NLPTHRESH 22 #define DEFAULT_NLPMAXSUPP 10 struct vpmadt032_cmd { struct list_head node; __le32 address; __le16 data; u8 desc; u8 txident; struct completion complete; }; /* Contains the options used when initializing the vpmadt032 module */ struct vpmadt032_options { int vpmnlptype; int vpmnlpthresh; int vpmnlpmaxsupp; u32 debug; u32 channels; }; struct GpakChannelConfig; struct vpmadt032 { struct voicebus *vb; struct work_struct work; struct workqueue_struct *wq; int dspid; struct semaphore sem; unsigned long control; unsigned char curpage; unsigned short version; struct adt_lec_params curecstate[MAX_CHANNELS]; spinlock_t change_list_lock; struct list_head change_list; spinlock_t list_lock; /* Commands that are waiting to be processed. */ struct list_head pending_cmds; /* Commands that are currently in progress by the VPM module */ struct list_head active_cmds; struct vpmadt032_options options; void (*setchanconfig_from_state)(struct vpmadt032 *vpm, int channel, struct GpakChannelConfig *chanconfig); }; struct voicebus; struct dahdi_chan; struct dahdi_echocanparams; struct dahdi_echocanparam; struct dahdi_echocan_state; char vpmadt032tone_to_zaptone(GpakToneCodes_t tone); int vpmadt032_test(struct vpmadt032 *vpm, struct voicebus *vb); int vpmadt032_init(struct vpmadt032 *vpm); int vpmadt032_reset(struct vpmadt032 *vpm); struct vpmadt032 *vpmadt032_alloc(struct vpmadt032_options *options); void vpmadt032_free(struct vpmadt032 *vpm); int vpmadt032_echocan_create(struct vpmadt032 *vpm, int channo, enum adt_companding companding, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p); void vpmadt032_echocan_free(struct vpmadt032 *vpm, int channo, struct dahdi_echocan_state *ec); struct GpakEcanParms; void vpmadt032_get_default_parameters(struct GpakEcanParms *p); /* If there is a command ready to go to the VPMADT032, return it, otherwise * NULL. Call with local interrupts disabled. */ static inline struct vpmadt032_cmd *vpmadt032_get_ready_cmd(struct vpmadt032 *vpm) { struct vpmadt032_cmd *cmd; spin_lock(&vpm->list_lock); if (list_empty(&vpm->pending_cmds)) { spin_unlock(&vpm->list_lock); return NULL; } cmd = list_entry(vpm->pending_cmds.next, struct vpmadt032_cmd, node); list_move_tail(&cmd->node, &vpm->active_cmds); spin_unlock(&vpm->list_lock); return cmd; } /** * call with local interrupts disabled. */ static inline void vpmadt032_resend(struct vpmadt032 *vpm) { struct vpmadt032_cmd *cmd, *temp; /* By moving the commands back to the pending list, they will be * transmitted when room is available */ spin_lock(&vpm->list_lock); list_for_each_entry_safe(cmd, temp, &vpm->active_cmds, node) { cmd->desc &= ~(__VPM150M_TX); list_move_tail(&cmd->node, &vpm->pending_cmds); } spin_unlock(&vpm->list_lock); } typedef __u16 DSP_WORD; /* 16 bit DSP word */ typedef __u32 DSP_ADDRESS; /* 32 bit DSP address */ typedef __u32 GPAK_FILE_ID; /* G.PAK Download file identifier */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadDspMemory - Read DSP memory. * * FUNCTION * This function reads a contiguous block of words from DSP memory starting at * the specified address. * * RETURNS * nothing * */ extern void gpakReadDspMemory( unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ unsigned int NumWords, /* number of contiguous words to read */ DSP_WORD *pWordValues /* pointer to array of word values variable */ ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakWriteDspMemory - Write DSP memory. * * FUNCTION * This function writes a contiguous block of words to DSP memory starting at * the specified address. * * RETURNS * nothing * */ extern void gpakWriteDspMemory( unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ unsigned int NumWords, /* number of contiguous words to write */ DSP_WORD *pWordValues /* pointer to array of word values to write */ ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakHostDelay - Delay for a fixed time interval. * * FUNCTION * This function delays for a fixed time interval before returning. The time * interval is the Host Port Interface sampling period when polling a DSP for * replies to command messages. * * RETURNS * nothing * */ extern void gpakHostDelay(void); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakLockAccess - Lock access to the specified DSP. * * FUNCTION * This function aquires exclusive access to the specified DSP. * * RETURNS * nothing * */ extern void gpakLockAccess( unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakUnlockAccess - Unlock access to the specified DSP. * * FUNCTION * This function releases exclusive access to the specified DSP. * * RETURNS * nothing * */ extern void gpakUnlockAccess( unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadFile - Read a block of bytes from a G.PAK Download file. * * FUNCTION * This function reads a contiguous block of bytes from a G.PAK Download file * starting at the current file position. * * RETURNS * The number of bytes read from the file. * -1 indicates an error occurred. * 0 indicates all bytes have been read (end of file) * */ extern int gpakReadFile( GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ unsigned char *pBuffer, /* pointer to buffer for storing bytes */ unsigned int NumBytes /* number of bytes to read */ ); #endif /* prevent multiple inclusion */ dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/vpmoct.c0000644000175000017500000004754411602452654022054 0ustar tzafrirtzafrir/* * VPMOCT Driver. * * Written by Russ Meyerriecks * * Copyright (C) 2010-2011 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include "voicebus/vpmoct.h" #include "linux/firmware.h" struct vpmoct_header { u8 header[6]; __le32 chksum; u8 pad[20]; u8 major; u8 minor; } __packed; static int _vpmoct_read(struct vpmoct *vpm, u8 address, void *data, size_t size, u8 *new_command, u8 *new_address) { struct vpmoct_cmd *cmd; unsigned long flags; if (unlikely(size >= ARRAY_SIZE(cmd->data))) { memset(data, -1, size); return -1; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { dev_info(vpm->dev, "Unable to allocate memory for vpmoct_cmd\n"); return 0; } init_completion(&cmd->complete); cmd->command = 0x60 + size; cmd->address = address; cmd->chunksize = size; spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_list); spin_unlock_irqrestore(&vpm->list_lock, flags); /* Wait for receiveprep to process our result */ if (!wait_for_completion_timeout(&cmd->complete, HZ/5)) { spin_lock_irqsave(&vpm->list_lock, flags); list_del(&cmd->node); spin_unlock_irqrestore(&vpm->list_lock, flags); kfree(cmd); dev_err(vpm->dev, "vpmoct_read_byte cmd timed out :O(\n"); return 0; } memcpy(data, &cmd->data[0], size); if (new_command) *new_command = cmd->command; if (new_address) *new_address = cmd->address; kfree(cmd); return 0; } static u8 vpmoct_read_byte(struct vpmoct *vpm, u8 address) { u8 val; _vpmoct_read(vpm, address, &val, sizeof(val), NULL, NULL); return val; } static u32 vpmoct_read_dword(struct vpmoct *vpm, u8 address) { __le32 val; _vpmoct_read(vpm, address, &val, sizeof(val), NULL, NULL); return le32_to_cpu(val); } static void vpmoct_write_byte(struct vpmoct *vpm, u8 address, u8 data) { struct vpmoct_cmd *cmd; unsigned long flags; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { dev_info(vpm->dev, "Unable to allocate memory for vpmoct_cmd\n"); return; } cmd->command = 0x21; cmd->address = address; cmd->data[0] = data; cmd->chunksize = 1; spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_list); spin_unlock_irqrestore(&vpm->list_lock, flags); } static void vpmoct_write_dword(struct vpmoct *vpm, u8 address, u32 data) { struct vpmoct_cmd *cmd; unsigned long flags; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { dev_info(vpm->dev, "Unable to allocate memory for vpmoct_cmd\n"); return; } cmd->command = 0x20 + sizeof(data); cmd->address = address; *(__le32 *)(&cmd->data[0]) = cpu_to_le32(data); cmd->chunksize = sizeof(data); spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_list); spin_unlock_irqrestore(&vpm->list_lock, flags); } static void vpmoct_write_chunk(struct vpmoct *vpm, u8 address, const u8 *data, u8 chunksize) { struct vpmoct_cmd *cmd; unsigned long flags; if (unlikely(chunksize > ARRAY_SIZE(cmd->data))) return; cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); if (unlikely(!cmd)) { dev_info(vpm->dev, "Unable to allocate memory for vpmoct_cmd\n"); return; } cmd->command = 0x20 + chunksize; cmd->address = address; cmd->chunksize = chunksize; memcpy(cmd->data, data, chunksize); spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_list); spin_unlock_irqrestore(&vpm->list_lock, flags); } static u8 vpmoct_resync(struct vpmoct *vpm) { unsigned long time; u8 status = 0xff; u8 address; u8 command; /* Poll the status register until it returns valid values * This is because we have to wait on the bootloader to do * its thing. * Timeout after 3 seconds */ time = jiffies + 3*HZ; while (time_after(time, jiffies) && (0xff == status)) { status = _vpmoct_read(vpm, VPMOCT_BOOT_STATUS, &status, sizeof(status), &command, &address); /* Throw out invalid statuses */ if ((0x55 != command) || (0xaa != address)) status = 0xff; } if ((status != 0xff) && status) dev_info(vpm->dev, "Resync with status %x\n", status); return status; } static inline short vpmoct_erase_flash(struct vpmoct *vpm) { short res; vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_FLASH_ERASE); res = vpmoct_resync(vpm); if (res) dev_info(vpm->dev, "Unable to erase flash\n"); return res; } static inline short vpmoct_send_firmware_header(struct vpmoct *vpm, const struct firmware *fw) { unsigned short i; short res; /* Send the encrypted firmware header */ for (i = 0; i < VPMOCT_FIRM_HEADER_LEN; i++) { vpmoct_write_byte(vpm, VPMOCT_BOOT_RAM+i, fw->data[i + sizeof(struct vpmoct_header)]); } /* Decrypt header */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_DECRYPT); res = vpmoct_resync(vpm); if (res) dev_info(vpm->dev, "Unable to send firmware header\n"); return res; } static inline short vpmoct_send_firmware_body(struct vpmoct *vpm, const struct firmware *fw) { unsigned int i, ram_index, flash_index, flash_address; const u8 *buf; u8 chunksize; /* Load the body of the firmware */ ram_index = 0; flash_index = 0; flash_address = 0; for (i = VPMOCT_FIRM_HEADER_LEN*2; i < fw->size;) { if (ram_index >= VPMOCT_BOOT_RAM_LEN) { /* Tell bootloader to load ram buffer into buffer */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, 0x10 + flash_index); /* Assuming the memory load doesn't take longer than 1 * eframe just insert a blank eframe before continuing * the firmware load */ vpmoct_read_byte(vpm, VPMOCT_BOOT_STATUS); ram_index = 0; flash_index++; } if (flash_index >= VPMOCT_FLASH_BUF_SECTIONS) { /* Tell the bootloader the memory address for load */ vpmoct_write_dword(vpm, VPMOCT_BOOT_ADDRESS1, flash_address); /* Tell the bootloader to load from flash buffer */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_FLASH_COPY); if (vpmoct_resync(vpm)) goto error; flash_index = 0; flash_address = i-VPMOCT_FIRM_HEADER_LEN*2; } /* Try to buffer for batch writes if possible */ chunksize = VPMOCT_BOOT_RAM_LEN - ram_index; if (chunksize > VPMOCT_MAX_CHUNK) chunksize = VPMOCT_MAX_CHUNK; buf = &fw->data[i]; vpmoct_write_chunk(vpm, VPMOCT_BOOT_RAM+ram_index, buf, chunksize); ram_index += chunksize; i += chunksize; } /* Flush remaining ram buffer to flash buffer */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_FLASHLOAD + flash_index); if (vpmoct_resync(vpm)) goto error; /* Tell boot loader the memory address to flash load */ vpmoct_write_dword(vpm, VPMOCT_BOOT_ADDRESS1, flash_address); /* Tell the bootloader to load flash from flash buffer */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_FLASH_COPY); if (vpmoct_resync(vpm)) goto error; return 0; error: dev_info(vpm->dev, "Unable to load firmware body\n"); return -1; } /** * vpmoct_get_mode - Return the current operating mode of the VPMOCT032. * @vpm: The vpm to query. * * Will be either BOOTLOADER, APPLICATION, or UNKNOWN. * */ static enum vpmoct_mode vpmoct_get_mode(struct vpmoct *vpm) { int i; enum vpmoct_mode ret = UNKNOWN; char identifier[11] = {0}; for (i = 0; i < ARRAY_SIZE(identifier) - 1; i++) identifier[i] = vpmoct_read_byte(vpm, VPMOCT_IDENT+i); if (!memcmp(identifier, "bootloader", sizeof(identifier) - 1)) ret = BOOTLOADER; else if (!memcmp(identifier, "VPMOCT032\0", sizeof(identifier) - 1)) ret = APPLICATION; dev_dbg(vpm->dev, "vpmoct identifier: %s\n", identifier); return ret; } static inline short vpmoct_check_firmware_crc(struct vpmoct *vpm, size_t size, u8 major, u8 minor) { short ret = 0; u8 status; /* Load firmware size */ vpmoct_write_dword(vpm, VPMOCT_BOOT_RAM, size); /* Load firmware version */ vpmoct_write_byte(vpm, VPMOCT_BOOT_RAM+8, major); vpmoct_write_byte(vpm, VPMOCT_BOOT_RAM+9, minor); /* Validate the firmware load */ vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_IMAGE_VALIDATE); status = vpmoct_resync(vpm); if (status) { dev_info(vpm->dev, "vpmoct firmware CRC check failed: %x\n", status); /* TODO: Try the load again */ ret = -1; } else { /* Switch to application code */ vpmoct_write_dword(vpm, VPMOCT_BOOT_ADDRESS2, 0xDEADBEEF); vpmoct_write_byte(vpm, VPMOCT_BOOT_CMD, VPMOCT_BOOT_REBOOT); msleep(250); status = vpmoct_resync(vpm); if (APPLICATION != vpmoct_get_mode(vpm)) { dev_info(vpm->dev, "vpmoct firmware failed to switch to " "application. (%x)\n", status); ret = -1; } else { vpm->mode = APPLICATION; dev_info(vpm->dev, "vpmoct firmware uploaded successfully\n"); } } return ret; } static inline short vpmoct_switch_to_boot(struct vpmoct *vpm) { vpmoct_write_dword(vpm, 0x74, 0x00009876); vpmoct_write_byte(vpm, 0x71, 0x02); if (vpmoct_resync(vpm)) { dev_info(vpm->dev, "Failed to switch to bootloader\n"); return -1; } vpm->mode = BOOTLOADER; return 0; } struct vpmoct_load_work { struct vpmoct *vpm; struct work_struct work; struct workqueue_struct *wq; load_complete_func_t load_complete; bool operational; }; /** * vpmoct_load_complete_fn - * * This function should run in the context of one of the system workqueues so * that it can destroy any workqueues that may have been created to setup a * long running firmware load. * */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void vpmoct_load_complete_fn(void *data) { struct vpmoct_load_work *work = data; #else static void vpmoct_load_complete_fn(struct work_struct *data) { struct vpmoct_load_work *work = container_of(data, struct vpmoct_load_work, work); #endif /* Do not touch work->vpm after calling load complete. It may have * been freed in the function by the board driver. */ work->load_complete(work->vpm->dev, work->operational); destroy_workqueue(work->wq); kfree(work); } /** * vpmoct_load_complete - Call the load_complete function in a system workqueue. * @work: * @operational: Whether the VPM is functioning or not. * */ static void vpmoct_load_complete(struct vpmoct_load_work *work, bool operational) { work->operational = operational; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&work->work, vpmoct_load_complete_fn, work); #else INIT_WORK(&work->work, vpmoct_load_complete_fn); #endif schedule_work(&work->work); } static bool is_valid_vpmoct_firmware(const struct firmware *fw) { const struct vpmoct_header *header = (const struct vpmoct_header *)fw->data; u32 crc = crc32(~0, &fw->data[10], fw->size - 10) ^ ~0; return (!memcmp("DIGIUM", header->header, sizeof(header->header)) && (le32_to_cpu(header->chksum) == crc)); } static void vpmoct_set_defaults(struct vpmoct *vpm) { vpmoct_write_dword(vpm, 0x40, 0); vpmoct_write_dword(vpm, 0x30, 0); } /** * vpmoct_load_flash - Check the current flash version and possibly load. * @vpm: The VPMOCT032 module to check / load. * */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void vpmoct_load_flash(void *data) { struct vpmoct_load_work *work = data; #else static void vpmoct_load_flash(struct work_struct *data) { struct vpmoct_load_work *work = container_of(data, struct vpmoct_load_work, work); #endif int res; struct vpmoct *const vpm = work->vpm; const struct firmware *fw; const struct vpmoct_header *header; char serial[VPMOCT_SERIAL_SIZE+1]; const char *const FIRMWARE_NAME = "dahdi-fw-vpmoct032.bin"; int i; res = request_firmware(&fw, FIRMWARE_NAME, vpm->dev); if (res) { dev_warn(vpm->dev, "vpmoct: Failed to load firmware from userspace! %d\n", res); header = NULL; fw = NULL; } else { header = (const struct vpmoct_header *)fw->data; } if (vpm->mode == APPLICATION) { /* Check the running application firmware * for the proper version */ vpm->major = vpmoct_read_byte(vpm, VPMOCT_MAJOR); vpm->minor = vpmoct_read_byte(vpm, VPMOCT_MINOR); for (i = 0; i < VPMOCT_SERIAL_SIZE; i++) serial[i] = vpmoct_read_byte(vpm, VPMOCT_SERIAL+i); serial[VPMOCT_SERIAL_SIZE] = '\0'; dev_info(vpm->dev, "vpmoct: Detected firmware v%d.%d Serial: %s\n", vpm->major, vpm->minor, (serial[0] != -1) ? serial : "(None)"); if (!fw) { /* Again, we'll use the existing loaded firmware. */ vpmoct_set_defaults(vpm); vpmoct_load_complete(work, true); return; } if (!is_valid_vpmoct_firmware(fw)) { dev_warn(vpm->dev, "%s is invalid. Please reinstall.\n", FIRMWARE_NAME); /* Just use the old version of the fimware. */ release_firmware(fw); vpmoct_set_defaults(vpm); vpmoct_load_complete(work, true); return; } if (vpm->minor == header->minor && vpm->major == header->major) { /* Proper version is running */ release_firmware(fw); vpmoct_set_defaults(vpm); vpmoct_load_complete(work, true); return; } else { /* Incorrect version of application code is * loaded. Reset to bootloader mode */ if (vpmoct_switch_to_boot(vpm)) goto error; } } if (!fw) { vpmoct_load_complete(work, false); return; } else if (!is_valid_vpmoct_firmware(fw)) { dev_warn(vpm->dev, "%s is invalid. Please reinstall.\n", FIRMWARE_NAME); goto error; } dev_info(vpm->dev, "vpmoct: Uploading firmware, v%d.%d. This can "\ "take up to 1 minute\n", header->major, header->minor); if (vpmoct_erase_flash(vpm)) goto error; if (vpmoct_send_firmware_header(vpm, fw)) goto error; if (vpmoct_send_firmware_body(vpm, fw)) goto error; if (vpmoct_check_firmware_crc(vpm, fw->size-VPMOCT_FIRM_HEADER_LEN*2, header->major, header->minor)) goto error; release_firmware(fw); vpmoct_set_defaults(vpm); vpmoct_load_complete(work, true); return; error: dev_info(vpm->dev, "Unable to load firmware\n"); release_firmware(fw); /* TODO: Should we disable module if the firmware doesn't load? */ vpmoct_load_complete(work, false); return; } struct vpmoct *vpmoct_alloc(void) { struct vpmoct *vpm; vpm = kzalloc(sizeof(*vpm), GFP_KERNEL); if (!vpm) return NULL; spin_lock_init(&vpm->list_lock); INIT_LIST_HEAD(&vpm->pending_list); INIT_LIST_HEAD(&vpm->active_list); mutex_init(&vpm->mutex); return vpm; } EXPORT_SYMBOL(vpmoct_alloc); void vpmoct_free(struct vpmoct *vpm) { unsigned long flags; struct vpmoct_cmd *cmd; LIST_HEAD(list); if (!vpm) return; spin_lock_irqsave(&vpm->list_lock, flags); list_splice(&vpm->active_list, &list); list_splice(&vpm->pending_list, &list); spin_unlock_irqrestore(&vpm->list_lock, flags); while (!list_empty(&list)) { cmd = list_entry(list.next, struct vpmoct_cmd, node); list_del(&cmd->node); kfree(cmd); } kfree(vpm); } EXPORT_SYMBOL(vpmoct_free); /** * vpmoct_init - Check for / initialize VPMOCT032 module. * @vpm: struct vpmoct allocated with vpmoct_alloc * @load_complete_fn: Function to call when the load is complete. * * Check to see if there is a VPMOCT module installed. If there appears to be * one return 0 and perform any necessary setup in the background. The * load_complete function will be called in a system global workqueue when the * initialization is complete. * * Must be called in process context. */ int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete) { struct vpmoct_load_work *work; if (!vpm || !vpm->dev || !load_complete) return -EINVAL; if (vpmoct_resync(vpm)) { load_complete(vpm->dev, false); return -ENODEV; } vpm->mode = vpmoct_get_mode(vpm); if (UNKNOWN == vpm->mode) { load_complete(vpm->dev, false); return -ENODEV; } work = kzalloc(sizeof(*work), GFP_KERNEL); if (!work) { load_complete(vpm->dev, false); return -ENOMEM; } work->wq = create_singlethread_workqueue("vpmoct"); if (!work->wq) { kfree(work); load_complete(vpm->dev, false); return -ENOMEM; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&work->work, vpmoct_load_flash, work); #else INIT_WORK(&work->work, vpmoct_load_flash); #endif work->vpm = vpm; work->load_complete = load_complete; queue_work(work->wq, &work->work); return 0; } EXPORT_SYMBOL(vpmoct_init); static void vpmoct_set_companding(struct vpmoct *vpm, int channo, int companding) { u32 new_companding; bool do_update = false; mutex_lock(&vpm->mutex); new_companding = (DAHDI_LAW_MULAW == companding) ? (vpm->companding & ~(1 << channo)) : (vpm->companding | (1 << channo)); if (vpm->companding != new_companding) { vpm->companding = new_companding; if (!vpm->companding_update_active) { do_update = true; vpm->companding_update_active = 1; } } mutex_unlock(&vpm->mutex); while (do_update) { u32 update; vpmoct_write_dword(vpm, 0x40, new_companding); update = vpmoct_read_dword(vpm, 0x40); WARN_ON(new_companding != update); mutex_lock(&vpm->mutex); if (vpm->companding != new_companding) { new_companding = vpm->companding; } else { vpm->companding_update_active = 0; do_update = false; } mutex_unlock(&vpm->mutex); } } /** * vpmoct_echo_update - Enable / Disable the VPMOCT032 echocan state * @vpm: The echocan to operate on. * @channo: Which echocan timeslot to enable / disable. * @echo_on: Whether we're turning the echocan on or off. * * When this function returns, the echocan is scheduled to be enabled or * disabled at some point in the near future. * * Must be called in process context. * */ static void vpmoct_echo_update(struct vpmoct *vpm, int channo, bool echo_on) { u32 echo; unsigned long timeout; bool do_update = false; mutex_lock(&vpm->mutex); echo = (echo_on) ? (vpm->echo | (1 << channo)) : (vpm->echo & ~(1 << channo)); if (vpm->echo != echo) { vpm->echo = echo; if (!vpm->echo_update_active) { do_update = true; vpm->echo_update_active = 1; } } mutex_unlock(&vpm->mutex); timeout = jiffies + 2*HZ; while (do_update) { u32 new; vpmoct_write_dword(vpm, 0x30, echo); new = vpmoct_read_dword(vpm, 0x10); mutex_lock(&vpm->mutex); if (((vpm->echo != echo) || (new != echo)) && time_before(jiffies, timeout)) { echo = vpm->echo; } else { vpm->echo_update_active = 0; do_update = false; } mutex_unlock(&vpm->mutex); } if (!time_before(jiffies, timeout)) dev_warn(vpm->dev, "vpmoct: Updating echo state timed out.\n"); } int vpmoct_echocan_create(struct vpmoct *vpm, int channo, int companding) { vpmoct_set_companding(vpm, channo, companding); vpmoct_echo_update(vpm, channo, true); return 0; } EXPORT_SYMBOL(vpmoct_echocan_create); void vpmoct_echocan_free(struct vpmoct *vpm, int channo) { vpmoct_echo_update(vpm, channo, false); } EXPORT_SYMBOL(vpmoct_echocan_free); /* Enable a vpm debugging mode where the pre-echo-canceled audio * stream is physically output on timeslot 24. */ int vpmoct_preecho_enable(struct vpmoct *vpm, const int channo) { int ret; mutex_lock(&vpm->mutex); if (!vpm->preecho_enabled) { vpm->preecho_enabled = 1; vpm->preecho_timeslot = channo; vpmoct_write_dword(vpm, 0x74, channo); /* Begin pre-echo stream on timeslot 24 */ vpmoct_write_byte(vpm, 0x71, 0x0a); ret = 0; } else { ret = -EBUSY; } mutex_unlock(&vpm->mutex); return ret; } EXPORT_SYMBOL(vpmoct_preecho_enable); int vpmoct_preecho_disable(struct vpmoct *vpm, const int channo) { int ret; mutex_lock(&vpm->mutex); if (!vpm->preecho_enabled) { ret = 0; } else if (channo == vpm->preecho_timeslot) { vpm->preecho_enabled = 0; /* Disable pre-echo stream by loading in a non-existing * channel number */ vpmoct_write_byte(vpm, 0x74, 0xff); /* Stop pre-echo stream on timeslot 24 */ vpmoct_write_byte(vpm, 0x71, 0x0a); ret = 0; } else { ret = -EINVAL; } mutex_unlock(&vpm->mutex); return ret; } EXPORT_SYMBOL(vpmoct_preecho_disable); dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/GpakHpi.h0000644000175000017500000000665311176111367022067 0ustar tzafrirtzafrir/* * Copyright (c) 2001, Adaptive Digital Technologies, Inc. * * File Name: GpakHpi.h * * Description: * This file contains common definitions related to the G.PAK interface * between a host processor and a DSP processor via the Host Port Interface. * * Version: 1.0 * * Revision History: * 10/17/01 - Initial release. * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _GPAKHPI_H /* prevent multiple inclusion */ #define _GPAKHPI_H /* Definition of G.PAK Command/Reply message type codes. */ #define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */ #define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */ #define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */ #define MSG_READ_SYS_PARMS 3 /* Read System Parameters */ #define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */ #define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */ #define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */ #define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */ #define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */ #define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */ #define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */ #define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */ #define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */ #define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */ #define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */ #define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */ #define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */ #define MSG_ALG_CONTROL 27 /* algorithm control */ #define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */ #define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */ #define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */ #define MSG_PING 35 /* ping command */ #define MSG_PING_REPLY 36 /* ping command reply */ #define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */ #define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */ #define MSG_TDM_LOOPBACK 39 /* tdm loopback control */ #define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */ #define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */ #define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */ #define MSG_RESET_FRAME_STATS 47 /* reset framing stats */ #define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */ #define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */ #define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */ #define MSG_ACCESSGPIO 51 #define MSG_ACCESSGPIO_REPLY 52 #endif /* prevent multiple inclusion */ dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/voicebus.c0000644000175000017500000015025311621247604022351 0ustar tzafrirtzafrir/* * VoiceBus(tm) Interface Library. * * Written by Shaun Ruffell * and based on previous work by Mark Spencer , * Matthew Fredrickson , and * Michael Spiceland * * Copyright (C) 2007-2010 Digium, Inc. * * All rights reserved. * VoiceBus is a registered trademark of Digium. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include "voicebus.h" #include "voicebus_net.h" #include "vpmadtreg.h" #include "GpakCust.h" #if VOICEBUS_DEFERRED == TIMER #if HZ < 1000 /* \todo Put an error message here. */ #endif #endif /* Interrupt status' reported in SR_CSR5 */ #define TX_COMPLETE_INTERRUPT 0x00000001 #define TX_STOPPED_INTERRUPT 0x00000002 #define TX_UNAVAILABLE_INTERRUPT 0x00000004 #define TX_JABBER_TIMEOUT_INTERRUPT 0x00000008 #define TX_UNDERFLOW_INTERRUPT 0x00000020 #define RX_COMPLETE_INTERRUPT 0x00000040 #define RX_UNAVAILABLE_INTERRUPT 0x00000080 #define RX_STOPPED_INTERRUPT 0x00000100 #define RX_WATCHDOG_TIMEOUT_INTERRUPT 0x00000200 #define TIMER_INTERRUPT 0x00000800 #define FATAL_BUS_ERROR_INTERRUPT 0x00002000 #define ABNORMAL_INTERRUPT_SUMMARY 0x00008000 #define NORMAL_INTERRUPT_SUMMARY 0x00010000 #define SR_CSR5 0x0028 #define NAR_CSR6 0x0030 #define IER_CSR7 0x0038 #define CSR7_TCIE 0x00000001 /* tx complete */ #define CSR7_TPSIE 0x00000002 /* tx processor stopped */ #define CSR7_TDUIE 0x00000004 /* tx desc unavailable */ #define CSR7_TUIE 0x00000020 /* tx underflow */ #define CSR7_RCIE 0x00000040 /* rx complete */ #define CSR7_RUIE 0x00000080 /* rx desc unavailable */ #define CSR7_RSIE 0x00000100 /* rx processor stopped */ #define CSR7_FBEIE 0x00002000 /* fatal bus error */ #define CSR7_AIE 0x00008000 /* abnormal enable */ #define CSR7_NIE 0x00010000 /* normal enable */ #define DEFAULT_COMMON_INTERRUPTS (CSR7_TCIE|CSR7_TPSIE|CSR7_RUIE|CSR7_RSIE|\ CSR7_FBEIE|CSR7_AIE|CSR7_NIE) #define DEFAULT_NORMAL_INTERRUPTS (DEFAULT_COMMON_INTERRUPTS|CSR7_TDUIE) #define DEFAULT_NO_IDLE_INTERRUPTS (DEFAULT_COMMON_INTERRUPTS|CSR7_RCIE) #define CSR9 0x0048 #define CSR9_MDC 0x00010000 #define CSR9_MDO 0x00020000 #define CSR9_MMC 0x00040000 #define CSR9_MDI 0x00080000 #define OWN_BIT cpu_to_le32(1 << 31) #ifdef CONFIG_VOICEBUS_ECREFERENCE /* * These dahdi_fifo_xxx functions are currently only used by the voicebus * drivers, but are named more generally to facilitate moving out in the * future. They probably also could stand to be changed in order to use a * kfifo implementation from the kernel if one is available. * */ struct dahdi_fifo { size_t total_size; u32 start; u32 end; u8 data[0]; }; static unsigned int dahdi_fifo_used_space(struct dahdi_fifo *fifo) { return (fifo->end >= fifo->start) ? fifo->end - fifo->start : fifo->total_size - fifo->start + fifo->end; } unsigned int __dahdi_fifo_put(struct dahdi_fifo *fifo, u8 *data, size_t size) { int newinsertposition; int cpy_one_len, cpy_two_len; if ((size + dahdi_fifo_used_space(fifo)) > (fifo->total_size - 1)) return -1; if ((fifo->end + size) >= fifo->total_size) { cpy_one_len = fifo->total_size - fifo->end; cpy_two_len = fifo->end + size - fifo->total_size; newinsertposition = cpy_two_len; } else { cpy_one_len = size; cpy_two_len = 0; newinsertposition = fifo->end + size; } memcpy(&fifo->data[fifo->end], data, cpy_one_len); if (cpy_two_len) memcpy(&fifo->data[0], &data[cpy_one_len], cpy_two_len); fifo->end = newinsertposition; return size; } EXPORT_SYMBOL(__dahdi_fifo_put); unsigned int __dahdi_fifo_get(struct dahdi_fifo *fifo, u8 *data, size_t size) { int newbegin; int cpy_one_len, cpy_two_len; if (size > dahdi_fifo_used_space(fifo)) return 0; if ((fifo->start + size) >= fifo->total_size) { cpy_one_len = fifo->total_size - fifo->start; cpy_two_len = fifo->start + size - fifo->total_size; newbegin = cpy_two_len; } else { cpy_one_len = size; cpy_two_len = 0; newbegin = fifo->start + size; } memcpy(&data[0], &fifo->data[fifo->start], cpy_one_len); if (cpy_two_len) memcpy(&data[cpy_one_len], &fifo->data[0], cpy_two_len); fifo->start = newbegin; return size; } EXPORT_SYMBOL(__dahdi_fifo_get); void dahdi_fifo_free(struct dahdi_fifo *fifo) { kfree(fifo); } EXPORT_SYMBOL(dahdi_fifo_free); struct dahdi_fifo *dahdi_fifo_alloc(u32 maxsize, gfp_t alloc_flags) { struct dahdi_fifo *fifo; fifo = kmalloc(maxsize + sizeof(*fifo) + 1, alloc_flags); if (!fifo) return NULL; fifo->start = fifo->end = 0; fifo->total_size = maxsize + 1; return fifo; } EXPORT_SYMBOL(dahdi_fifo_alloc); #endif /* CONFIG_VOICEBUS_ECREFERENCE */ /* In memory structure shared by the host and the adapter. */ struct voicebus_descriptor { volatile __le32 des0; volatile __le32 des1; volatile __le32 buffer1; volatile __le32 container; /* Unused */ } __attribute__((packed)); static inline void handle_transmit(struct voicebus *vb, struct list_head *buffers) { vb->ops->handle_transmit(vb, buffers); } static inline void handle_receive(struct voicebus *vb, struct list_head *buffers) { vb->ops->handle_receive(vb, buffers); } static inline struct voicebus_descriptor * vb_descriptor(const struct voicebus_descriptor_list *dl, const unsigned int index) { struct voicebus_descriptor *d; d = (struct voicebus_descriptor *)((u8*)dl->desc + ((sizeof(*d) + dl->padding) * index)); return d; } static int vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl, u32 des1, unsigned int direction) { int i; struct voicebus_descriptor *d; const u32 END_OF_RING = 0x02000000; u8 cacheline_size; BUG_ON(!dl); /* * Add some padding to each descriptor to ensure that they are * aligned on host system cache-line boundaries, but only for the * cache-line sizes that we support. * */ if (pci_read_config_byte(vb->pdev, PCI_CACHE_LINE_SIZE, &cacheline_size)) { dev_err(&vb->pdev->dev, "Failed read of cache line " "size from PCI configuration space.\n"); return -EIO; } if ((0x08 == cacheline_size) || (0x10 == cacheline_size) || (0x20 == cacheline_size)) { dl->padding = (cacheline_size*sizeof(u32)) - sizeof(*d); } else { dl->padding = 0; } dl->desc = pci_alloc_consistent(vb->pdev, (sizeof(*d) + dl->padding) * DRING_SIZE, &dl->desc_dma); if (!dl->desc) return -ENOMEM; memset(dl->desc, 0, (sizeof(*d) + dl->padding) * DRING_SIZE); for (i = 0; i < DRING_SIZE; ++i) { d = vb_descriptor(dl, i); d->des1 = cpu_to_le32(des1); } d->des1 |= cpu_to_le32(END_OF_RING); dl->count = 0; return 0; } #define OWNED(_d_) (((_d_)->des0)&OWN_BIT) #define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0) static int vb_initialize_tx_descriptors(struct voicebus *vb) { int i; int des1 = 0xe4800000 | VOICEBUS_SFRAME_SIZE; struct voicebus_descriptor *d; struct voicebus_descriptor_list *dl = &vb->txd; const u32 END_OF_RING = 0x02000000; u8 cacheline_size; WARN_ON(!dl); WARN_ON((NULL == vb->idle_vbb) || (0 == vb->idle_vbb_dma_addr)); /* * Add some padding to each descriptor to ensure that they are * aligned on host system cache-line boundaries, but only for the * cache-line sizes that we support. * */ if (pci_read_config_byte(vb->pdev, PCI_CACHE_LINE_SIZE, &cacheline_size)) { dev_err(&vb->pdev->dev, "Failed read of cache line " "size from PCI configuration space.\n"); return -EIO; } if ((0x08 == cacheline_size) || (0x10 == cacheline_size) || (0x20 == cacheline_size)) { dl->padding = (cacheline_size*sizeof(u32)) - sizeof(*d); } else { dl->padding = 0; } dl->desc = pci_alloc_consistent(vb->pdev, (sizeof(*d) + dl->padding) * DRING_SIZE, &dl->desc_dma); if (!dl->desc) return -ENOMEM; memset(dl->desc, 0, (sizeof(*d) + dl->padding) * DRING_SIZE); for (i = 0; i < DRING_SIZE; ++i) { d = vb_descriptor(dl, i); d->des1 = cpu_to_le32(des1); dl->pending[i] = NULL; d->buffer1 = 0; } d->des1 |= cpu_to_le32(END_OF_RING); dl->count = 0; return 0; } static int vb_initialize_rx_descriptors(struct voicebus *vb) { return vb_initialize_descriptors( vb, &vb->rxd, VOICEBUS_SFRAME_SIZE, DMA_FROM_DEVICE); } /*! \brief Use to set the minimum number of buffers queued to the hardware * before enabling interrupts. */ int voicebus_set_minlatency(struct voicebus *vb, unsigned int ms) { unsigned long flags; /* * One millisecond of latency means that we have 3 buffers pending, * since two are always going to be waiting in the TX fifo on the * interface chip. * */ #define MESSAGE "%d ms is an invalid value for minumum latency. Setting to %d ms.\n" if (DRING_SIZE < ms) { dev_warn(&vb->pdev->dev, MESSAGE, ms, DRING_SIZE); return -EINVAL; } else if (VOICEBUS_DEFAULT_LATENCY > ms) { dev_warn(&vb->pdev->dev, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY); return -EINVAL; } spin_lock_irqsave(&vb->lock, flags); vb->min_tx_buffer_count = ms; spin_unlock_irqrestore(&vb->lock, flags); return 0; } EXPORT_SYMBOL(voicebus_set_minlatency); /*! \brief Returns the number of buffers currently on the transmit queue. */ int voicebus_current_latency(struct voicebus *vb) { int latency; unsigned long flags; spin_lock_irqsave(&vb->lock, flags); latency = vb->min_tx_buffer_count; spin_unlock_irqrestore(&vb->lock, flags); return latency; } EXPORT_SYMBOL(voicebus_current_latency); /*! * \brief Read one of the hardware control registers without acquiring locks. */ static inline u32 __vb_getctl(struct voicebus *vb, u32 addr) { u32 ret; ret = readl(vb->iobase + addr); rmb(); return ret; } /*! * \brief Read one of the hardware control registers with locks held. */ static inline u32 vb_getctl(struct voicebus *vb, u32 addr) { unsigned long flags; u32 val; spin_lock_irqsave(&vb->lock, flags); val = __vb_getctl(vb, addr); spin_unlock_irqrestore(&vb->lock, flags); return val; } static int __vb_is_stopped(struct voicebus *vb) { u32 reg; reg = __vb_getctl(vb, SR_CSR5); reg = (reg >> 17) & 0x3f; return ((0 == reg) || (3 == reg)) ? 1 : 0; } /*! * \brief Returns whether or not the interface is running. * * NOTE: Running in this case means whether or not the hardware reports the * transmit processor in any state but stopped. * * \return 1 of the process is stopped, 0 if running. */ static int vb_is_stopped(struct voicebus *vb) { int ret; unsigned long flags; spin_lock_irqsave(&vb->lock, flags); ret = __vb_is_stopped(vb); spin_unlock_irqrestore(&vb->lock, flags); return ret; } #if defined(CONFIG_VOICEBUS_INTERRUPT) static inline void vb_disable_deferred(struct voicebus *vb) { if (atomic_inc_return(&vb->deferred_disabled_count) == 1) disable_irq(vb->pdev->irq); } static inline void vb_enable_deferred(struct voicebus *vb) { if (atomic_dec_return(&vb->deferred_disabled_count) == 0) enable_irq(vb->pdev->irq); } #else static inline void vb_disable_deferred(struct voicebus *vb) { tasklet_disable(&vb->tasklet); } static inline void vb_enable_deferred(struct voicebus *vb) { tasklet_enable(&vb-tasklet); } #endif static void vb_cleanup_tx_descriptors(struct voicebus *vb) { unsigned int i; struct voicebus_descriptor_list *dl = &vb->txd; struct voicebus_descriptor *d; struct vbb *vbb; vb_disable_deferred(vb); while (!list_empty(&vb->tx_complete)) { vbb = list_entry(vb->tx_complete.next, struct vbb, entry); list_del(&vbb->entry); dma_pool_free(vb->pool, vbb, vbb->dma_addr); } for (i = 0; i < DRING_SIZE; ++i) { d = vb_descriptor(dl, i); if (d->buffer1 && (d->buffer1 != le32_to_cpu(vb->idle_vbb_dma_addr))) { WARN_ON(!dl->pending[i]); vbb = dl->pending[i]; dma_pool_free(vb->pool, vbb, vbb->dma_addr); } if (NORMAL == vb->mode) { d->des1 |= cpu_to_le32(0x80000000); d->buffer1 = cpu_to_le32(vb->idle_vbb_dma_addr); dl->pending[i] = vb->idle_vbb; SET_OWNED(d); } else { d->buffer1 = 0; dl->pending[i] = NULL; d->des0 &= ~OWN_BIT; } } dl->head = dl->tail = 0; dl->count = 0; vb_enable_deferred(vb); } static void vb_cleanup_rx_descriptors(struct voicebus *vb) { unsigned int i; struct voicebus_descriptor_list *dl = &vb->rxd; struct voicebus_descriptor *d; struct vbb *vbb; vb_disable_deferred(vb); for (i = 0; i < DRING_SIZE; ++i) { d = vb_descriptor(dl, i); if (d->buffer1) { d->buffer1 = 0; BUG_ON(!dl->pending[i]); vbb = dl->pending[i]; list_add_tail(&vbb->entry, &vb->free_rx); dl->pending[i] = NULL; } d->des0 &= ~OWN_BIT; } dl->head = 0; dl->tail = 0; dl->count = 0; vb_enable_deferred(vb); } static void vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl) { if (dl == &vb->txd) vb_cleanup_tx_descriptors(vb); else vb_cleanup_rx_descriptors(vb); } static void vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl) { struct vbb *vbb; if (NULL == dl->desc) { WARN_ON(1); return; } vb_cleanup_descriptors(vb, dl); pci_free_consistent( vb->pdev, (sizeof(struct voicebus_descriptor)+dl->padding)*DRING_SIZE, dl->desc, dl->desc_dma); while (!list_empty(&vb->free_rx)) { vbb = list_entry(vb->free_rx.next, struct vbb, entry); list_del(&vbb->entry); dma_pool_free(vb->pool, vbb, vbb->dma_addr); } } /*! * \brief Write one of the hardware control registers without acquiring locks. */ static inline void __vb_setctl(struct voicebus *vb, u32 addr, u32 val) { wmb(); writel(val, vb->iobase + addr); readl(vb->iobase + addr); } /*! * \brief Write one of the hardware control registers with locks held. */ static inline void vb_setctl(struct voicebus *vb, u32 addr, u32 val) { unsigned long flags; spin_lock_irqsave(&vb->lock, flags); __vb_setctl(vb, addr, val); spin_unlock_irqrestore(&vb->lock, flags); } static int __vb_sdi_clk(struct voicebus *vb, u32 *sdi) { unsigned int ret; *sdi &= ~CSR9_MDC; __vb_setctl(vb, 0x0048, *sdi); ret = __vb_getctl(vb, 0x0048); *sdi |= CSR9_MDC; __vb_setctl(vb, 0x0048, *sdi); return (ret & CSR9_MDI) ? 1 : 0; } static void __vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count, u32 *sdi) { *sdi &= ~CSR9_MMC; __vb_setctl(vb, 0x0048, *sdi); while (count--) { if (bits & (1 << count)) *sdi |= CSR9_MDO; else *sdi &= ~CSR9_MDO; __vb_sdi_clk(vb, sdi); } } static void vb_setsdi(struct voicebus *vb, int addr, u16 val) { u32 bits; u32 sdi = 0; unsigned long flags; /* Send preamble */ bits = 0xffffffff; spin_lock_irqsave(&vb->lock, flags); __vb_sdi_sendbits(vb, bits, 32, &sdi); bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2; __vb_sdi_sendbits(vb, bits, 16, &sdi); __vb_sdi_sendbits(vb, val, 16, &sdi); spin_unlock_irqrestore(&vb->lock, flags); } /*! \brief Resets the voicebus hardware interface. */ static int vb_reset_interface(struct voicebus *vb) { unsigned long timeout; u32 reg; u32 pci_access; enum { /* Software Reset */ SWR = (1 << 0), /* Bus Arbitration (1 for priority transmit) */ BAR = (1 << 1), /* Memory Write Invalidate */ MWI = (1 << 24), /* Memory Read Line */ MRL = (1 << 23), /* Descriptor Skip Length */ DSLShift = 2, /* Cache Alignment */ CALShift = 14, /* Transmit Auto Pollling */ TAPShift = 17, }; const u32 DEFAULT_PCI_ACCESS = MWI | MRL | (0x2 << TAPShift) | BAR; u8 cacheline_size; BUG_ON(in_interrupt()); if (pci_read_config_byte(vb->pdev, PCI_CACHE_LINE_SIZE, &cacheline_size)) { dev_err(&vb->pdev->dev, "Failed read of cache line " "size from PCI configuration space.\n"); return -EIO; } switch (cacheline_size) { case 0x08: pci_access = DEFAULT_PCI_ACCESS | (0x1 << CALShift); break; case 0x10: pci_access = DEFAULT_PCI_ACCESS | (0x2 << CALShift); break; case 0x20: pci_access = DEFAULT_PCI_ACCESS | (0x3 << CALShift); break; default: if (*vb->debug) { dev_warn(&vb->pdev->dev, "Host system set a cache " "size of %d which is not supported. " "Disabling memory write line and memory " "read line.\n", cacheline_size); } pci_access = 0xfe584202; break; } /* The transmit and receive descriptors will have the same padding. */ pci_access |= ((vb->txd.padding / sizeof(u32)) << DSLShift) & 0x7c; vb_setctl(vb, 0x0000, pci_access | SWR); timeout = jiffies + HZ/10; /* 100ms interval */ do { reg = vb_getctl(vb, 0x0000); } while ((reg & SWR) && time_before(jiffies, timeout)); if (reg & SWR) { if (-1 == reg) { dev_err(&vb->pdev->dev, "Unable to read I/O registers.\n"); } else { dev_err(&vb->pdev->dev, "Did not come out of reset " "within 100ms\n"); } return -EIO; } vb_setctl(vb, 0x0000, pci_access); return 0; } /*! * \brief Give a frame to the hardware to use for receiving. * */ static inline int vb_submit_rxb(struct voicebus *vb, struct vbb *vbb) { struct voicebus_descriptor *d; struct voicebus_descriptor_list *dl = &vb->rxd; unsigned int tail = dl->tail; d = vb_descriptor(dl, tail); if (unlikely(d->buffer1)) { /* Do not overwrite a buffer that is still in progress. */ WARN_ON(1); list_add_tail(&vbb->entry, &vb->free_rx); return -EBUSY; } dl->pending[tail] = vbb; dl->tail = (++tail) & DRING_MASK; d->buffer1 = cpu_to_le32(vbb->dma_addr); SET_OWNED(d); /* That's it until the hardware is done with it. */ ++dl->count; return 0; } static int __voicebus_transmit(struct voicebus *vb, struct vbb *vbb) { struct voicebus_descriptor *d; struct voicebus_descriptor_list *dl = &vb->txd; d = vb_descriptor(dl, dl->tail); if (unlikely((le32_to_cpu(d->buffer1) != vb->idle_vbb_dma_addr) && d->buffer1)) { if (printk_ratelimit()) dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n"); dma_pool_free(vb->pool, vbb, vbb->dma_addr); /* Schedule the underrun handler to run here, since we'll need * to cleanup as best we can. */ schedule_work(&vb->underrun_work); return -EFAULT; } dl->pending[dl->tail] = vbb; d->buffer1 = cpu_to_le32(vbb->dma_addr); dl->tail = (dl->tail + 1) & DRING_MASK; SET_OWNED(d); /* That's it until the hardware is done with it. */ ++dl->count; return 0; } /** * voicebus_transmit - Queue a buffer on the hardware descriptor ring. * */ int voicebus_transmit(struct voicebus *vb, struct vbb *vbb) { int res = __voicebus_transmit(vb, vbb); __vb_setctl(vb, 0x0008, 0x00000000); return res; } EXPORT_SYMBOL(voicebus_transmit); /*! * \brief Instruct the hardware to check for a new tx descriptor. */ static inline void __vb_tx_demand_poll(struct voicebus *vb) { u32 status = __vb_getctl(vb, 0x0028); if ((status & 0x00700000) == 0x00600000) __vb_setctl(vb, 0x0008, 0x00000000); } static void setup_descriptors(struct voicebus *vb) { int i; struct vbb *vbb; dma_addr_t dma_addr; LIST_HEAD(buffers); unsigned long flags; might_sleep(); vb_cleanup_tx_descriptors(vb); vb_cleanup_rx_descriptors(vb); /* Tell the card where the descriptors are in host memory. */ vb_setctl(vb, 0x0020, (u32)vb->txd.desc_dma); vb_setctl(vb, 0x0018, (u32)vb->rxd.desc_dma); for (i = 0; i < DRING_SIZE; ++i) { if (list_empty(&vb->free_rx)) { vbb = dma_pool_alloc(vb->pool, GFP_KERNEL, &dma_addr); if (vbb) vbb->dma_addr = dma_addr; } else { vbb = list_entry(vb->free_rx.next, struct vbb, entry); list_del(&vbb->entry); } if (unlikely(NULL == vbb)) BUG_ON(1); list_add_tail(&vbb->entry, &buffers); } vb_disable_deferred(vb); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); vb_submit_rxb(vb, vbb); } vb_enable_deferred(vb); if (BOOT != vb->mode) { for (i = 0; i < vb->min_tx_buffer_count; ++i) { vbb = dma_pool_alloc(vb->pool, GFP_KERNEL, &dma_addr); if (unlikely(NULL == vbb)) BUG_ON(1); vbb->dma_addr = dma_addr; list_add_tail(&vbb->entry, &buffers); } local_irq_save(flags); handle_transmit(vb, &buffers); local_irq_restore(flags); vb_disable_deferred(vb); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del_init(&vbb->entry); __voicebus_transmit(vb, vbb); } __vb_setctl(vb, 0x0008, 0x00000000); vb_enable_deferred(vb); } } static void __vb_set_control_defaults(struct voicebus *vb) { /* Pass bad packets, runt packets, disable SQE function, * store-and-forward */ vb_setctl(vb, 0x0030, 0x00280048); /* ...disable jabber and the receive watchdog. */ vb_setctl(vb, 0x0078, 0x00000013); vb_getctl(vb, 0x0078); } static void __vb_set_mac_only_mode(struct voicebus *vb) { u32 reg; reg = __vb_getctl(vb, 0x00fc); __vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x4); __vb_getctl(vb, 0x00fc); } static int vb_initialize_interface(struct voicebus *vb) { u32 reg; setup_descriptors(vb); __vb_set_control_defaults(vb); reg = vb_getctl(vb, 0x00fc); vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x7); vb_setsdi(vb, 0x00, 0x0100); vb_setsdi(vb, 0x16, 0x2100); __vb_set_mac_only_mode(vb); vb_setsdi(vb, 0x00, 0x0100); vb_setsdi(vb, 0x16, 0x2100); reg = vb_getctl(vb, 0x00fc); /* * The calls to setsdi above toggle the reset line of the CPLD. Wait * here to give the CPLD time to stabilize after reset. */ msleep(10); return ((reg&0x7) == 0x4) ? 0 : -EIO; } #ifdef DBG static void dump_descriptor(struct voicebus *vb, struct voicebus_descriptor *d) { VB_PRINTK(vb, DEBUG, "Displaying descriptor at address %08x\n", (unsigned int)d); VB_PRINTK(vb, DEBUG, " des0: %08x\n", le32_to_cpu(d->des0)); VB_PRINTK(vb, DEBUG, " des1: %08x\n", le32_to_cpu(d->des1)); VB_PRINTK(vb, DEBUG, " buffer1: %08x\n", le32_to_cpu(d->buffer1)); VB_PRINTK(vb, DEBUG, " container: %08x\n", le32_to_cpu(d->container)); } static void show_buffer(struct voicebus *vb, struct vbb *vbb) { int x; unsigned char *c; c = vbb; printk(KERN_DEBUG "Packet %d\n", count); printk(KERN_DEBUG ""); for (x = 1; x <= VOICEBUS_SFRAME_SIZE; ++x) { printk("%02x ", c[x]); if (x % 16 == 0) printk("\n"); } printk(KERN_DEBUG "\n\n"); } #endif /*! * \brief Remove the next completed transmit buffer (txb) from the tx * descriptor ring. * * NOTE: This function doesn't need any locking because only one instance is * ever running on the deferred processing routine and it only looks at * the head pointer. The deferred routine should only ever be running * on one processor at a time (no multithreaded workqueues allowed!) * * Context: Must be called from the voicebus deferred workqueue. * * \return Pointer to buffer, or NULL if not available. */ static void * vb_get_completed_txb(struct voicebus *vb) { struct voicebus_descriptor_list *dl = &vb->txd; struct voicebus_descriptor *d; struct vbb *vbb; unsigned int head = dl->head; d = vb_descriptor(dl, head); if (OWNED(d) || !d->buffer1 || (le32_to_cpu(d->buffer1) == vb->idle_vbb_dma_addr)) return NULL; vbb = dl->pending[head]; if (NORMAL == vb->mode) { d->buffer1 = cpu_to_le32(vb->idle_vbb_dma_addr); dl->pending[head] = vb->idle_vbb; SET_OWNED(d); } else { d->buffer1 = 0; dl->pending[head] = NULL; } dl->head = (++head) & DRING_MASK; --dl->count; vb_net_capture_vbb(vb, vbb, 1, d->des0, d->container); return vbb; } static void * vb_get_completed_rxb(struct voicebus *vb, u32 *des0) { struct voicebus_descriptor *d; struct voicebus_descriptor_list *dl = &vb->rxd; unsigned int head = dl->head; struct vbb *vbb; d = vb_descriptor(dl, head); if ((0 == d->buffer1) || OWNED(d)) return NULL; vbb = dl->pending[head]; dl->head = (++head) & DRING_MASK; d->buffer1 = 0; --dl->count; # ifdef VOICEBUS_NET_DEBUG vb_net_capture_vbb(vb, vbb, 0, d->des0, d->container); # endif *des0 = le32_to_cpu(d->des0); return vbb; } /*! * \brief Command the hardware to check if it owns the next receive * descriptor. */ static inline void __vb_rx_demand_poll(struct voicebus *vb) { if (((__vb_getctl(vb, 0x0028) >> 17) & 0x7) == 0x4) __vb_setctl(vb, 0x0010, 0x00000000); } static void __vb_enable_interrupts(struct voicebus *vb) { if (BOOT == vb->mode) __vb_setctl(vb, IER_CSR7, DEFAULT_NO_IDLE_INTERRUPTS); else __vb_setctl(vb, IER_CSR7, DEFAULT_NORMAL_INTERRUPTS); } static void __vb_disable_interrupts(struct voicebus *vb) { __vb_setctl(vb, IER_CSR7, 0); } static void vb_disable_interrupts(struct voicebus *vb) { unsigned long flags; spin_lock_irqsave(&vb->lock, flags); __vb_disable_interrupts(vb); spin_unlock_irqrestore(&vb->lock, flags); } static void start_packet_processing(struct voicebus *vb) { u32 reg; unsigned long flags; spin_lock_irqsave(&vb->lock, flags); clear_bit(VOICEBUS_STOP, &vb->flags); clear_bit(VOICEBUS_STOPPED, &vb->flags); #if defined(CONFIG_VOICEBUS_TIMER) vb->timer.expires = jiffies + HZ/1000; add_timer(&vb->timer); #else /* Clear the interrupt status register. */ __vb_setctl(vb, SR_CSR5, 0xffffffff); __vb_enable_interrupts(vb); #endif /* Start the transmit and receive processors. */ reg = __vb_getctl(vb, 0x0030); __vb_setctl(vb, 0x0030, reg|0x00002002); __vb_getctl(vb, 0x0030); __vb_rx_demand_poll(vb); __vb_tx_demand_poll(vb); __vb_getctl(vb, 0x0030); spin_unlock_irqrestore(&vb->lock, flags); } static void vb_tasklet_boot(unsigned long data); static void vb_tasklet_hx8(unsigned long data); static void vb_tasklet_normal(unsigned long data); /*! * \brief Starts the VoiceBus interface. * * When the VoiceBus interface is started, it is actively transferring * frames to and from the backend of the card. This means the card will * generate interrupts. * * This function should only be called from process context, with interrupts * enabled, since it can sleep while running the self checks. * * \return zero on success. -EBUSY if device is already running. */ int voicebus_start(struct voicebus *vb) { int ret; if (!vb_is_stopped(vb)) return -EBUSY; if (NORMAL == vb->mode) { tasklet_init(&vb->tasklet, vb_tasklet_normal, (unsigned long)vb); } else if (BOOT == vb->mode) { tasklet_init(&vb->tasklet, vb_tasklet_boot, (unsigned long)vb); } else if (HX8 == vb->mode) { tasklet_init(&vb->tasklet, vb_tasklet_hx8, (unsigned long)vb); } else { return -EINVAL; } ret = vb_reset_interface(vb); if (ret) return ret; ret = vb_initialize_interface(vb); if (ret) return ret; start_packet_processing(vb); BUG_ON(vb_is_stopped(vb)); return 0; } EXPORT_SYMBOL(voicebus_start); static void vb_stop_txrx_processors(struct voicebus *vb) { unsigned long flags; u32 reg; int i; spin_lock_irqsave(&vb->lock, flags); reg = __vb_getctl(vb, NAR_CSR6); reg &= ~(0x2002); __vb_setctl(vb, NAR_CSR6, reg); spin_unlock_irqrestore(&vb->lock, flags); barrier(); i = 150; while (--i && (__vb_getctl(vb, SR_CSR5) & (0x007e0000))) udelay(100); } /*! * \brief Stops the VoiceBus interface. * * Stops the VoiceBus interface and waits for any outstanding DMA transactions * to complete. When this functions returns the VoiceBus interface tx and rx * states will both be suspended. * * Only call this function from process context, with interrupt enabled, * without any locks held since it sleeps. * * \return zero on success, -1 on error. */ void voicebus_stop(struct voicebus *vb) { static DEFINE_SEMAPHORE(stop); down(&stop); if (test_bit(VOICEBUS_STOP, &vb->flags) || vb_is_stopped(vb)) { up(&stop); return; } set_bit(VOICEBUS_STOP, &vb->flags); vb_stop_txrx_processors(vb); WARN_ON(!vb_is_stopped(vb)); set_bit(VOICEBUS_STOPPED, &vb->flags); #if defined(CONFIG_VOICEBUS_TIMER) del_timer_sync(&vb->timer); #endif vb_disable_interrupts(vb); up(&stop); } EXPORT_SYMBOL(voicebus_stop); /** * voicebus_quiesce - Halt the voicebus interface. * @vb: The voicebus structure to quiet * * This ensures that the device is not engaged in any DMA transactions or * interrupting. It does not grab any locks since it may be called by a dying * kernel. */ void voicebus_quiesce(struct voicebus *vb) { if (!vb) return; /* Reset the device */ __vb_disable_interrupts(vb); __vb_setctl(vb, 0x0000, 0x1); __vb_getctl(vb, 0x0000); } EXPORT_SYMBOL(voicebus_quiesce); /*! * \brief Prepare the interface for module unload. * * Stop the interface and free all the resources allocated by the driver. The * caller should have returned all VoiceBus buffers to the VoiceBus layer * before calling this function. * * context: !in_interrupt() */ void voicebus_release(struct voicebus *vb) { set_bit(VOICEBUS_SHUTDOWN, &vb->flags); #ifdef VOICEBUS_NET_DEBUG vb_net_unregister(vb); #endif /* Make sure the underrun_work isn't running or going to run. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) flush_scheduled_work(); #else cancel_work_sync(&vb->underrun_work); #endif /* quiesce the hardware */ voicebus_stop(vb); vb_reset_interface(vb); tasklet_kill(&vb->tasklet); #if !defined(CONFIG_VOICEBUS_TIMER) free_irq(vb->pdev->irq, vb); #endif /* Cleanup memory and software resources. */ vb_free_descriptors(vb, &vb->txd); vb_free_descriptors(vb, &vb->rxd); if (vb->idle_vbb_dma_addr) { dma_free_coherent(&vb->pdev->dev, VOICEBUS_SFRAME_SIZE, vb->idle_vbb, vb->idle_vbb_dma_addr); } release_mem_region(pci_resource_start(vb->pdev, 1), pci_resource_len(vb->pdev, 1)); pci_iounmap(vb->pdev, vb->iobase); pci_clear_mwi(vb->pdev); pci_disable_device(vb->pdev); dma_pool_destroy(vb->pool); } EXPORT_SYMBOL(voicebus_release); static void vb_increase_latency(struct voicebus *vb, unsigned int increase, struct list_head *buffers) { struct vbb *vbb; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) struct vbb *n; #endif int i; LIST_HEAD(local); if (0 == increase) return; if (test_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags)) return; if (unlikely(increase > VOICEBUS_MAXLATENCY_BUMP)) increase = VOICEBUS_MAXLATENCY_BUMP; if ((increase + vb->min_tx_buffer_count) > vb->max_latency) increase = vb->max_latency - vb->min_tx_buffer_count; /* Because there are 2 buffers in the transmit FIFO on the hardware, * setting 3 ms of latency means that the host needs to be able to * service the cards within 1ms. This is because the interface will * load up 2 buffers into the TX FIFO then attempt to read the 3rd * descriptor. If the OWN bit isn't set, then the hardware will set the * TX descriptor not available interrupt. */ /* Set the minimum latency in case we're restarted...we don't want to * wait for the buffer to grow to this depth again in that case. */ for (i = 0; i < increase; ++i) { dma_addr_t dma_addr; vbb = dma_pool_alloc(vb->pool, GFP_ATOMIC, &dma_addr); WARN_ON(NULL == vbb); if (likely(NULL != vbb)) { vbb->dma_addr = dma_addr; list_add_tail(&vbb->entry, &local); } } handle_transmit(vb, &local); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) list_for_each_entry_safe(vbb, n, &local, entry) list_move_tail(&vbb->entry, buffers); #else list_splice_tail(&local, buffers); #endif /* Set the new latency (but we want to ensure that there aren't any * printks to the console, so we don't call the function) */ vb->min_tx_buffer_count += increase; } static void vb_schedule_deferred(struct voicebus *vb) { #if !defined(CONFIG_VOICEBUS_INTERRUPT) tasklet_hi_schedule(&vb->tasklet); #else vb->tasklet.func(vb->tasklet.data); #endif } /** * vb_tasklet_boot() - When vb->mode == BOOT * * This deferred processing routine is for hx8 boards during initialization. It * simply services any completed tx / rx packets without any concerns about what * the current latency is. */ static void vb_tasklet_boot(unsigned long data) { struct voicebus *vb = (struct voicebus *)data; LIST_HEAD(buffers); struct vbb *vbb; const int DEFAULT_COUNT = 5; int count = DEFAULT_COUNT; u32 des0 = 0; /* First, temporarily store any non-idle buffers that the hardware has * indicated it's finished transmitting. Non idle buffers are those * buffers that contain actual data and was filled out by the client * driver (as of this writing, the wcte12xp or wctdm24xxp drivers) when * passed up through the handle_transmit callback. * * On the other hand, idle buffers are "dummy" buffers that solely exist * to in order to prevent the transmit descriptor ring from ever * completely draining. */ while ((vbb = vb_get_completed_txb(vb))) list_add_tail(&vbb->entry, &vb->tx_complete); while (--count && !list_empty(&vb->tx_complete)) list_move_tail(vb->tx_complete.next, &buffers); /* Prep all the new buffers for transmit before actually sending any * of them. */ handle_transmit(vb, &buffers); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); __voicebus_transmit(vb, vbb); } __vb_setctl(vb, 0x0008, 0x00000000); /* If there may still be buffers in the descriptor rings, reschedule * ourself to run again. We essentially yield here to allow any other * cards a chance to run. */ #if !defined(CONFIG_VOICEBUS_INTERRUPT) if (unlikely(!count && !test_bit(VOICEBUS_STOP, &vb->flags))) vb_schedule_deferred(vb); #endif /* And finally, pass up any receive buffers. */ count = DEFAULT_COUNT; while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) { if (likely((des0 & (0x7fff << 16)) == (VOICEBUS_SFRAME_SIZE << 16))) list_add_tail(&vbb->entry, &buffers); else vb_submit_rxb(vb, vbb); } handle_receive(vb, &buffers); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); vb_submit_rxb(vb, vbb); } return; } /** * vb_tasklet_hx8() - When vb->mode == HX8 * * The normal deferred processing routine for the Hx8 boards. This deferred * processing routine doesn't configure any idle buffers and increases the * latency when there is a hard underrun. There are not any softunderruns here, * unlike in vb_tasklet_normal. */ static void vb_tasklet_hx8(unsigned long data) { struct voicebus *vb = (struct voicebus *)data; int hardunderrun; LIST_HEAD(buffers); struct vbb *vbb; const int DEFAULT_COUNT = 5; int count = DEFAULT_COUNT; u32 des0 = 0; hardunderrun = test_and_clear_bit(VOICEBUS_HARD_UNDERRUN, &vb->flags); /* First, temporarily store any non-idle buffers that the hardware has * indicated it's finished transmitting. Non idle buffers are those * buffers that contain actual data and was filled out by the client * driver (as of this writing, the wcte12xp or wctdm24xxp drivers) when * passed up through the handle_transmit callback. * * On the other hand, idle buffers are "dummy" buffers that solely exist * to in order to prevent the transmit descriptor ring from ever * completely draining. */ while ((vbb = vb_get_completed_txb(vb))) list_add_tail(&vbb->entry, &vb->tx_complete); while (--count && !list_empty(&vb->tx_complete)) list_move_tail(vb->tx_complete.next, &buffers); /* Prep all the new buffers for transmit before actually sending any * of them. */ handle_transmit(vb, &buffers); if (unlikely(hardunderrun)) vb_increase_latency(vb, 1, &buffers); /* Now we can send all our buffers together in a group. */ while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); __voicebus_transmit(vb, vbb); } __vb_setctl(vb, 0x0008, 0x00000000); /* Print any messages about soft latency bumps after we fix the transmit * descriptor ring. Otherwise it's possible to take so much time * printing the dmesg output that we lose the lead that we got on the * hardware, resulting in a hard underrun condition. */ if (unlikely(hardunderrun)) { #if !defined(CONFIG_VOICEBUS_SYSFS) if (!test_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags) && printk_ratelimit()) { if (vb->max_latency != vb->min_tx_buffer_count) { dev_info(&vb->pdev->dev, "Missed interrupt. " "Increasing latency to %d ms in " "order to compensate.\n", vb->min_tx_buffer_count); } else { dev_info(&vb->pdev->dev, "ERROR: Unable to " "service card within %d ms and " "unable to further increase " "latency.\n", vb->max_latency); } } #endif } #if !defined(CONFIG_VOICEBUS_INTERRUPT) /* If there may still be buffers in the descriptor rings, reschedule * ourself to run again. We essentially yield here to allow any other * cards a chance to run. */ if (unlikely(!count && !test_bit(VOICEBUS_STOP, &vb->flags))) vb_schedule_deferred(vb); #endif /* And finally, pass up any receive buffers. */ count = DEFAULT_COUNT; while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) { if (((des0 >> 16) & 0x7fff) == VOICEBUS_SFRAME_SIZE) list_add_tail(&vbb->entry, &buffers); else vb_submit_rxb(vb, vbb); } handle_receive(vb, &buffers); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); vb_submit_rxb(vb, vbb); } return; } /** * vb_tasklet_relaxed() - When vb->mode == NORMAL * * This is the standard deferred processing routine for CPLD based cards * (essentially the non-hx8 cards). */ static void vb_tasklet_normal(unsigned long data) { struct voicebus *vb = (struct voicebus *)data; int softunderrun; LIST_HEAD(buffers); struct vbb *vbb; struct voicebus_descriptor_list *const dl = &vb->txd; struct voicebus_descriptor *d; int behind = 0; const int DEFAULT_COUNT = 5; int count = DEFAULT_COUNT; u32 des0 = 0; BUG_ON(NORMAL != vb->mode); /* First, temporarily store any non-idle buffers that the hardware has * indicated it's finished transmitting. Non idle buffers are those * buffers that contain actual data and was filled out by the client * driver (as of this writing, the wcte12xp or wctdm24xxp drivers) when * passed up through the handle_transmit callback. * * On the other hand, idle buffers are "dummy" buffers that solely exist * to in order to prevent the transmit descriptor ring from ever * completely draining. */ while ((vbb = vb_get_completed_txb(vb))) list_add_tail(&vbb->entry, &vb->tx_complete); if (unlikely(dl->count < 2)) { softunderrun = 1; d = vb_descriptor(dl, dl->head); if (1 == dl->count) return; behind = 2; while (!OWNED(d)) { if (le32_to_cpu(d->buffer1) != vb->idle_vbb_dma_addr) goto tx_error_exit; SET_OWNED(d); dl->head = (dl->head + 1) & DRING_MASK; d = vb_descriptor(dl, dl->head); ++behind; } } else { softunderrun = 0; } while (--count && !list_empty(&vb->tx_complete)) list_move_tail(vb->tx_complete.next, &buffers); /* Prep all the new buffers for transmit before actually sending any * of them. */ handle_transmit(vb, &buffers); if (unlikely(softunderrun)) { int i; unsigned long flags; /* Disable interrupts on the local processor. We don't want * the following process interrupted. We're 'racing' against * the hardware here.... */ local_irq_save(flags); vb_increase_latency(vb, behind, &buffers); d = vb_descriptor(dl, dl->head); while (!OWNED(d)) { if (le32_to_cpu(d->buffer1) != vb->idle_vbb_dma_addr) { local_irq_restore(flags); goto tx_error_exit; } SET_OWNED(d); dl->head = (dl->head + 1) & DRING_MASK; d = vb_descriptor(dl, dl->head); ++behind; } /* Now we'll get a little further ahead of the hardware. */ for (i = 0; i < 5; ++i) { d = vb_descriptor(dl, dl->head); d->buffer1 = cpu_to_le32(vb->idle_vbb_dma_addr); dl->pending[dl->head] = vb->idle_vbb; d->des0 |= OWN_BIT; dl->head = (dl->head + 1) & DRING_MASK; } dl->tail = dl->head; local_irq_restore(flags); } d = vb_descriptor(dl, dl->tail); if (le32_to_cpu(d->buffer1) != vb->idle_vbb_dma_addr) goto tx_error_exit; /* Now we can send all our buffers together in a group. */ while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); __voicebus_transmit(vb, vbb); } writel(0, vb->iobase + 0x8); /* Print any messages about soft latency bumps after we fix the transmit * descriptor ring. Otherwise it's possible to take so much time * printing the dmesg output that we lose the lead that we got on the * hardware, resulting in a hard underrun condition. */ if (unlikely(softunderrun)) { #if !defined(CONFIG_VOICEBUS_SYSFS) if (!test_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags) && printk_ratelimit()) { if (vb->max_latency != vb->min_tx_buffer_count) { dev_info(&vb->pdev->dev, "Missed interrupt. " "Increasing latency to %d ms in " "order to compensate.\n", vb->min_tx_buffer_count); } else { dev_info(&vb->pdev->dev, "ERROR: Unable to " "service card within %d ms and " "unable to further increase " "latency.\n", vb->max_latency); } } #endif } #if !defined(CONFIG_VOICEBUS_INTERRUPT) /* If there may still be buffers in the descriptor rings, reschedule * ourself to run again. We essentially yield here to allow any other * cards a chance to run. */ if (unlikely(!count && !test_bit(VOICEBUS_STOP, &vb->flags))) vb_schedule_deferred(vb); #endif /* And finally, pass up any receive buffers. */ count = DEFAULT_COUNT; while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) { if (((des0 >> 16) & 0x7fff) == VOICEBUS_SFRAME_SIZE) list_add_tail(&vbb->entry, &buffers); else vb_submit_rxb(vb, vbb); } handle_receive(vb, &buffers); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); vb_submit_rxb(vb, vbb); } return; tx_error_exit: vb_disable_interrupts(vb); schedule_work(&vb->underrun_work); while (!list_empty(&buffers)) { vbb = list_entry(buffers.next, struct vbb, entry); list_del(&vbb->entry); dma_pool_free(vb->pool, vbb, vbb->dma_addr); } return; } /** * handle_hardunderrun() - reset the AN983 after experiencing a hardunderrun. * @work: The work_struct used to queue this function. * */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void handle_hardunderrun(void *data) { struct voicebus *vb = data; #else static void handle_hardunderrun(struct work_struct *work) { struct voicebus *vb = container_of(work, struct voicebus, underrun_work); #endif if (test_bit(VOICEBUS_STOP, &vb->flags) || test_bit(VOICEBUS_STOPPED, &vb->flags)) return; voicebus_stop(vb); if (!test_bit(VOICEBUS_SHUTDOWN, &vb->flags)) { if (printk_ratelimit()) { dev_info(&vb->pdev->dev, "Host failed to service " "card interrupt within %d ms which is a " "hardunderun.\n", DRING_SIZE); } if (vb->ops->handle_error) vb->ops->handle_error(vb); vb_disable_deferred(vb); setup_descriptors(vb); start_packet_processing(vb); vb_enable_deferred(vb); } } /*! * \brief Interrupt handler for VoiceBus interface. * * NOTE: This handler is optimized for the case where only a single interrupt * condition will be generated at a time. * * ALSO NOTE: Only access the interrupt status register from this function * since it doesn't employ any locking on the voicebus interface. */ static irqreturn_t #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) vb_isr(int irq, void *dev_id, struct pt_regs *regs) #else vb_isr(int irq, void *dev_id) #endif { struct voicebus *vb = dev_id; unsigned long flags; u32 int_status; int_status = __vb_getctl(vb, SR_CSR5); /* Mask out the reserved bits. */ int_status &= ~(0xfc004010); int_status &= 0x7fff; if (!int_status) return IRQ_NONE; local_irq_save(flags); if (unlikely((int_status & (TX_UNAVAILABLE_INTERRUPT|RX_UNAVAILABLE_INTERRUPT)) && !test_bit(VOICEBUS_STOP, &vb->flags) && (BOOT != vb->mode))) { if (NORMAL == vb->mode) { __vb_disable_interrupts(vb); __vb_setctl(vb, SR_CSR5, int_status); schedule_work(&vb->underrun_work); } else if (HX8 == vb->mode) { set_bit(VOICEBUS_HARD_UNDERRUN, &vb->flags); vb_schedule_deferred(vb); __vb_setctl(vb, SR_CSR5, int_status); } } else if (likely(int_status & (TX_COMPLETE_INTERRUPT|RX_COMPLETE_INTERRUPT))) { /* ******************************************************** */ /* NORMAL INTERRUPT CASE */ /* ******************************************************** */ vb_schedule_deferred(vb); __vb_setctl(vb, SR_CSR5, TX_COMPLETE_INTERRUPT|RX_COMPLETE_INTERRUPT); } else { if (int_status & FATAL_BUS_ERROR_INTERRUPT) dev_err(&vb->pdev->dev, "Fatal Bus Error detected!\n"); if (int_status & TX_STOPPED_INTERRUPT) { BUG_ON(!test_bit(VOICEBUS_STOP, &vb->flags)); if (__vb_is_stopped(vb)) { __vb_disable_interrupts(vb); } } if (int_status & RX_STOPPED_INTERRUPT) { BUG_ON(!test_bit(VOICEBUS_STOP, &vb->flags)); if (__vb_is_stopped(vb)) { __vb_disable_interrupts(vb); } } /* Clear the interrupt(s) */ __vb_setctl(vb, SR_CSR5, int_status); } local_irq_restore(flags); return IRQ_HANDLED; } #if defined(CONFIG_VOICEBUS_TIMER) /*! \brief Called if the deferred processing is to happen in the context of * the timer. */ static void vb_timer(unsigned long data) { unsigned long start = jiffies; struct voicebus *vb = (struct voicebus *)data; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) vb_isr(0, vb, 0); #else vb_isr(0, vb); #endif if (!test_bit(VOICEBUS_STOPPED, &vb->flags)) { vb->timer.expires = start + HZ/1000; add_timer(&vb->timer); } } #endif /*! * \brief Initalize the voicebus interface. * * This function must be called in process context since it may sleep. * \todo Complete this description. */ int __voicebus_init(struct voicebus *vb, const char *board_name, enum voicebus_mode mode) { int retval = 0; int reserved_iomem = 0; BUG_ON(NULL == vb); BUG_ON(NULL == board_name); BUG_ON(NULL == vb->ops); BUG_ON(NULL == vb->pdev); BUG_ON(NULL == vb->debug); /* ---------------------------------------------------------------- Initialize the pure software constructs. ---------------------------------------------------------------- */ vb->max_latency = VOICEBUS_DEFAULT_MAXLATENCY; spin_lock_init(&vb->lock); set_bit(VOICEBUS_STOP, &vb->flags); if ((NORMAL != mode) && (BOOT != mode) && (HX8 != mode)) return -EINVAL; vb->mode = mode; vb->min_tx_buffer_count = VOICEBUS_DEFAULT_LATENCY; INIT_LIST_HEAD(&vb->tx_complete); INIT_LIST_HEAD(&vb->free_rx); #if defined(CONFIG_VOICEBUS_TIMER) init_timer(&vb->timer); vb->timer.function = vb_timer; vb->timer.data = (unsigned long)vb; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&vb->underrun_work, handle_hardunderrun, vb); #else INIT_WORK(&vb->underrun_work, handle_hardunderrun); #endif /* ---------------------------------------------------------------- Configure the hardware / kernel module interfaces. ---------------------------------------------------------------- */ if (pci_set_dma_mask(vb->pdev, DMA_BIT_MASK(32))) { dev_err(&vb->pdev->dev, "No suitable DMA available.\n"); goto cleanup; } if (pci_enable_device(vb->pdev)) { dev_err(&vb->pdev->dev, "Failed call to pci_enable_device.\n"); retval = -EIO; goto cleanup; } if (0 == (pci_resource_flags(vb->pdev, 0)&IORESOURCE_IO)) { dev_err(&vb->pdev->dev, "BAR0 is not IO Memory.\n"); retval = -EIO; goto cleanup; } vb->iobase = pci_iomap(vb->pdev, 1, 0); if (request_mem_region(pci_resource_start(vb->pdev, 1), pci_resource_len(vb->pdev, 1), board_name)) { reserved_iomem = 1; } else { dev_err(&vb->pdev->dev, "IO Registers are in use by another " "module.\n"); if (!(*vb->debug)) { retval = -EIO; goto cleanup; } } vb->pool = dma_pool_create(board_name, &vb->pdev->dev, sizeof(struct vbb), 64, 0); if (!vb->pool) { retval = -ENOMEM; goto cleanup; } vb->idle_vbb = dma_alloc_coherent(&vb->pdev->dev, VOICEBUS_SFRAME_SIZE, &vb->idle_vbb_dma_addr, GFP_KERNEL); /* ---------------------------------------------------------------- Configure the hardware interface. ---------------------------------------------------------------- */ if (pci_set_dma_mask(vb->pdev, DMA_BIT_MASK(32))) { dev_warn(&vb->pdev->dev, "No suitable DMA available.\n"); goto cleanup; } retval = pci_set_mwi(vb->pdev); if (retval) { dev_warn(&vb->pdev->dev, "Failed to set Memory-Write " \ "Invalidate Command Bit..\n"); } pci_set_master(vb->pdev); if (vb_reset_interface(vb)) { retval = -EIO; dev_warn(&vb->pdev->dev, "Failed reset.\n"); goto cleanup; } retval = vb_initialize_tx_descriptors(vb); if (retval) goto cleanup; retval = vb_initialize_rx_descriptors(vb); if (retval) goto cleanup; #if !defined(CONFIG_VOICEBUS_TIMER) retval = request_irq(vb->pdev->irq, vb_isr, DAHDI_IRQ_SHARED, board_name, vb); if (retval) { dev_warn(&vb->pdev->dev, "Failed to request interrupt line.\n"); goto cleanup; } #endif #ifdef VOICEBUS_NET_DEBUG vb_net_register(vb, board_name); #endif return retval; cleanup: tasklet_kill(&vb->tasklet); if (vb->pool) dma_pool_destroy(vb->pool); /* Cleanup memory and software resources. */ if (vb->txd.desc) vb_free_descriptors(vb, &vb->txd); if (vb->rxd.desc) vb_free_descriptors(vb, &vb->rxd); dma_free_coherent(&vb->pdev->dev, VOICEBUS_SFRAME_SIZE, vb->idle_vbb, vb->idle_vbb_dma_addr); if (vb->iobase) pci_iounmap(vb->pdev, vb->iobase); if (vb->pdev) pci_disable_device(vb->pdev); if (reserved_iomem) { release_mem_region(pci_resource_start(vb->pdev, 1), pci_resource_len(vb->pdev, 1)); } if (0 == retval) retval = -EIO; return retval; } EXPORT_SYMBOL(__voicebus_init); static spinlock_t loader_list_lock; static LIST_HEAD(binary_loader_list); /** * vpmadtreg_loadfirmware - Load the vpmadt032 firmware. * @vb: The voicebus device to load. */ int vpmadtreg_loadfirmware(struct voicebus *vb) { struct vpmadt_loader *loader; int ret = 0; int loader_present = 0; unsigned long stop; might_sleep(); /* First check to see if a loader is already loaded into memory. */ spin_lock(&loader_list_lock); loader_present = !(list_empty(&binary_loader_list)); spin_unlock(&loader_list_lock); if (!loader_present) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) ret = request_module("dahdi_vpmadt032_loader"); #else /* If we use the blocking 'request_module' here and we are * loading the client boards with async_schedule we will hang * here. The module loader will wait for our asynchronous tasks * to finish, but we can't because we're waiting for the load * the finish. */ ret = request_module_nowait("dahdi_vpmadt032_loader"); #endif if (ret) return ret; stop = jiffies + HZ; while (time_after(stop, jiffies)) { spin_lock(&loader_list_lock); loader_present = !(list_empty(&binary_loader_list)); spin_unlock(&loader_list_lock); if (loader_present) break; msleep(10); } } spin_lock(&loader_list_lock); if (!list_empty(&binary_loader_list)) { loader = list_entry(binary_loader_list.next, struct vpmadt_loader, node); if (try_module_get(loader->owner)) { spin_unlock(&loader_list_lock); ret = loader->load(vb); module_put(loader->owner); } else { spin_unlock(&loader_list_lock); dev_info(&vb->pdev->dev, "Failed to find a " "registered loader after loading module.\n"); ret = -ENODEV; } } else { spin_unlock(&loader_list_lock); dev_info(&vb->pdev->dev, "Failed to find a registered " "loader after loading module.\n"); ret = -ENODEV; } return ret; } /* Called by the binary loader module when it is ready to start loading * firmware. */ int vpmadtreg_register(struct vpmadt_loader *loader) { spin_lock(&loader_list_lock); list_add_tail(&loader->node, &binary_loader_list); spin_unlock(&loader_list_lock); return 0; } EXPORT_SYMBOL(vpmadtreg_register); int vpmadtreg_unregister(struct vpmadt_loader *loader) { int removed = 0; struct vpmadt_loader *cur, *temp; list_for_each_entry_safe(cur, temp, &binary_loader_list, node) { if (loader == cur) { list_del_init(&cur->node); removed = 1; break; } } WARN_ON(!removed); return 0; } EXPORT_SYMBOL(vpmadtreg_unregister); static int __init voicebus_module_init(void) { /* This registration with dahdi.ko will fail since the span is not * defined, but it will make sure that this module is a dependency of * dahdi.ko, so that when it is being unloded, this module will be * unloaded as well. */ dahdi_register(NULL, 0); spin_lock_init(&loader_list_lock); return 0; } static void __exit voicebus_module_cleanup(void) { WARN_ON(!list_empty(&binary_loader_list)); } MODULE_DESCRIPTION("Voicebus Interface w/VPMADT032 support"); MODULE_AUTHOR("Digium Incorporated "); MODULE_LICENSE("GPL"); module_init(voicebus_module_init); module_exit(voicebus_module_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/vpmadtreg.c0000644000175000017500000000162211176111367022517 0ustar tzafrirtzafrir/* * vpmadtreg.c - Registration utility for firmware loaders. * * Allows drivers for boards that host VPMAD032 modules to initiate firmware * loads. * * Written by Digium Incorporated * * Copyright (C) 2008-2009 Digium, Inc. All rights reserved. * * See http://www.asterisk.org for more information about the Asterisk * project. Please do not directly contact any of the maintainers of this * project for assistance; the project provides a web site, mailing lists and * IRC channels for your use. * * This program is free software, distributed under the terms of the GNU * General Public License Version 2 as published by the Free Software * Foundation. See the LICENSE file included with this program for more * details. */ #include #include #include #include "voicebus.h" #include "GpakCust.h" #include "vpmadtreg.h" dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/gpakenum.h0000644000175000017500000001337111423153456022346 0ustar tzafrirtzafrir/* * Copyright (c) 2005, Adaptive Digital Technologies, Inc. * * File Name: gpakenum.h * * Description: * This file contains common enumerations related to G.PAK application * software. * * Version: 1.0 * * Revision History: * 06/15/05 - Initial release. * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _GPAKENUM_H /* prevent multiple inclusion */ #define _GPAKENUM_H /* G.PAK Serial Port Word Size */ typedef enum { SerWordSize8 = 0, // 8-bit seial word SerWordSize16 = 1 // 16-bit serial word } GpakSerWordSize_t; /* G.PAK Serial Port FrameSync Polarity */ typedef enum { FrameSyncActLow = 0, // active low frame sync signal FrameSyncActHigh = 1 // active high frame sync signal } GpakSerFrameSyncPol_t; /* G.PAK Serial Port Clock Polarity */ typedef enum { SerClockActLow = 0, // active low serial clock SerClockActHigh = 1 // active high serial clock } GpakSerClockPol_t; /* G.PAK Serial Port Data Delay */ typedef enum { DataDelay0 = 0, // no data delay DataDelay1 = 1, // 1-bit data delay DataDelay2 = 2 // 2-bit data delay } GpakSerDataDelay_t; /* G.PAK Serial Port Ids. */ typedef enum { SerialPortNull = 0, // null serial port SerialPort1 = 1, // first PCM serial stream port (McBSP0) SerialPort2 = 2, // second PCM serial stream port (McBSP1) SerialPort3 = 3 // third PCM serial stream port (McBSP2) } GpakSerialPort_t; /* G.PAK serial port Slot Configuration selection codes. */ typedef enum { SlotCfgNone = 0, // no time slots used SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system SlotCfg8Groups = 8 // 8-partition mode for 128-channel system } GpakSlotCfg_t; /* G.PAK serial port Companding Mode codes. */ typedef enum { cmpPCMU=0, // u-Law cmpPCMA=1, // A-Law cmpNone=2 // none } GpakCompandModes; /* G.PAK Active/Inactive selection codes. */ typedef enum { Disabled=0, // Inactive Enabled=1 // Active } GpakActivation; /* G.PAK Channel Type codes. */ typedef enum { inactive=0, // channel inactive tdmToTdm = 1, /* tdmToTdm */ tdmToTdmDebug = 2 /* tdmToTdm */ } GpakChanType; /* G.PAK Algorithm control commands */ typedef enum { EnableEcanA = 0, // Enable A side echo canceller BypassEcanA = 1, // Bypass A side echo canceller ResetEcanA = 2, // Reset A side echo canceller EnableEcanB = 3, // Enable B side echo canceller BypassEcanB = 4, // Bypass B side echo canceller ResetEcanB = 5, // Reset B side echo canceller EnableMuLawSwCompanding = 6,// Enable Mu-law Software companding EnableALawSwCompanding = 7, // Enable Mu-law Software companding BypassSwCompanding = 8, // Bypass Software companding EnableDTMFMuteA = 9, // Mute A side Dtmf digit after tone detected DisableDTMFMuteA = 10, // Do not mute A side Dtmf digit once tone detected EnableDTMFMuteB = 11, // Mute B side Dtmf digit after tone detected DisableDTMFMuteB = 12, // Do not mute B side Dtmf digit once tone detected EnableFaxCngDetectA = 13, // Enable A side Fax CNG detector, channel must be configed already DisableFaxCngDetectA = 14, // Disable A side Fax CNG detector, channel must be configed already EnableFaxCngDetectB = 15, // Enable B side Fax CNG detector, channel must be configed already DisableFaxCngDetectB = 16 // Disable B side Fax CNG detector, channel must be configed already } GpakAlgCtrl_t; /* G.PAK Tone types. */ typedef enum { Null_tone = 0, // no tone detection DTMF_tone = 1 // DTMF tone } GpakToneTypes; /* G.PAK direction. */ typedef enum { TDMAToB = 0, // A to B TDMBToA = 1 // B to A } GpakTdmDirection; typedef enum { rate1ms=0, rate2ms=1, rate10ms=2 } GpakRate_t; /* G.PAK Asynchronous Event Codes */ typedef enum { EventToneDetect = 0, // Tone detection event EventDSPDebug = 7 // DSP debug data event } GpakAsyncEventCode_t; /* G.PAK MF Tone Code Indices */ typedef enum { DtmfDigit1 = 0, // DTMF Digit 1 DtmfDigit2 = 1, // DTMF Digit 2 DtmfDigit3 = 2, // DTMF Digit 3 DtmfDigitA = 3, // DTMF Digit A DtmfDigit4 = 4, // DTMF Digit 4 DtmfDigit5 = 5, // DTMF Digit 5 DtmfDigit6 = 6, // DTMF Digit 6 DtmfDigitB = 7, // DTMF Digit B DtmfDigit7 = 8, // DTMF Digit 7 DtmfDigit8 = 9, // DTMF Digit 8 DtmfDigit9 = 10, // DTMF Digit 9 DtmfDigitC = 11, // DTMF Digit C DtmfDigitSt = 12, // DTMF Digit * DtmfDigit0 = 13, // DTMF Digit 0 DtmfDigitPnd = 14, // DTMF Digit # DtmfDigitD = 15, // DTMF Digit D FaxCngDigit = 90, // Fax Calling Tone (1100 Hz) EndofMFDigit = 100, // End of MF digit EndofCngDigit = 101 // End of Cng Digit } GpakToneCodes_t; /* GPIO control code*/ typedef enum { GPIO_READ = 0, GPIO_WRITE = 1, GPIO_DIR = 2 } GpakGPIOCotrol_t; #endif // end multiple inclusion dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/voicebus.h0000644000175000017500000001460511546370413022357 0ustar tzafrirtzafrir/* * VoiceBus(tm) Interface Library. * * Written by Shaun Ruffell * and based on previous work by Mark Spencer , * Matthew Fredrickson , and * Michael Spiceland * * Copyright (C) 2007-2010 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef __VOICEBUS_H__ #define __VOICEBUS_H__ #include #define VOICEBUS_DEFAULT_LATENCY 3U #define VOICEBUS_DEFAULT_MAXLATENCY 25U #define VOICEBUS_MAXLATENCY_BUMP 6U #define VOICEBUS_SFRAME_SIZE 1004U /*! The number of descriptors in both the tx and rx descriptor ring. */ #define DRING_SIZE (1 << 7) /* Must be a power of 2 */ #define DRING_MASK (DRING_SIZE-1) /* Define CONFIG_VOICEBUS_SYSFS to create some attributes under the pci device. * This is disabled by default because it hasn't been tested on the full range * of supported kernels. */ #undef CONFIG_VOICEBUS_SYSFS /* Do not generate interrupts on this interface, but instead just poll it */ #undef CONFIG_VOICEBUS_TIMER /* Define this in order to create a debugging network interface. */ #undef VOICEBUS_NET_DEBUG /* Define this to only run the processing in an interrupt handler * (and not tasklet). */ #define CONFIG_VOICEBUS_INTERRUPT /* Define this to use a FIFO for the software echocan reference. * (experimental) */ #undef CONFIG_VOICEBUS_ECREFERENCE #ifdef CONFIG_VOICEBUS_ECREFERENCE struct dahdi_fifo; unsigned int __dahdi_fifo_put(struct dahdi_fifo *fifo, u8 *data, size_t size); unsigned int __dahdi_fifo_get(struct dahdi_fifo *fifo, u8 *data, size_t size); void dahdi_fifo_free(struct dahdi_fifo *fifo); struct dahdi_fifo *dahdi_fifo_alloc(size_t maxsize, gfp_t alloc_flags); #endif #ifdef VOICEBUS_NET_DEBUG #include #include #include #endif struct voicebus; struct vbb { u8 data[VOICEBUS_SFRAME_SIZE]; struct list_head entry; dma_addr_t dma_addr; }; struct voicebus_operations { void (*handle_receive)(struct voicebus *vb, struct list_head *buffers); void (*handle_transmit)(struct voicebus *vb, struct list_head *buffers); void (*handle_error)(struct voicebus *vb); }; /** * struct voicebus_descriptor_list - A single descriptor list. */ struct voicebus_descriptor_list { struct voicebus_descriptor *desc; unsigned int head; unsigned int tail; void *pending[DRING_SIZE]; dma_addr_t desc_dma; unsigned long count; unsigned int padding; }; /* Bit definitions for struct voicebus.flags */ #define VOICEBUS_SHUTDOWN 0 #define VOICEBUS_STOP 1 #define VOICEBUS_STOPPED 2 #define VOICEBUS_LATENCY_LOCKED 3 #define VOICEBUS_HARD_UNDERRUN 4 /** * voicebus_mode * * NORMAL: For non-hx8 boards. Uses idle_buffers. * BOOT: For hx8 boards. For sending single packets at a time. * HX8: Normal operating mode for Hx8 Boards. Does not use * idle_buffers. */ enum voicebus_mode { NORMAL = 0, BOOT = 1, HX8 = 2, }; /** * struct voicebus - Represents physical interface to voicebus card. * * @tx_complete: only used in the tasklet to temporarily hold complete tx * buffers. */ struct voicebus { struct pci_dev *pdev; spinlock_t lock; struct voicebus_descriptor_list rxd; struct voicebus_descriptor_list txd; u8 *idle_vbb; dma_addr_t idle_vbb_dma_addr; const int *debug; void __iomem *iobase; struct tasklet_struct tasklet; enum voicebus_mode mode; #if defined(CONFIG_VOICEBUS_INTERRUPT) atomic_t deferred_disabled_count; #endif #if defined(CONFIG_VOICEBUS_TIMER) struct timer_list timer; #endif struct work_struct underrun_work; const struct voicebus_operations *ops; unsigned long flags; unsigned int min_tx_buffer_count; unsigned int max_latency; struct list_head tx_complete; struct list_head free_rx; struct dma_pool *pool; #ifdef VOICEBUS_NET_DEBUG struct sk_buff_head captured_packets; struct net_device *netdev; struct net_device_stats net_stats; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) struct napi_struct napi; #endif atomic_t tx_seqnum; atomic_t rx_seqnum; #endif }; int __voicebus_init(struct voicebus *vb, const char *board_name, enum voicebus_mode mode); void voicebus_release(struct voicebus *vb); int voicebus_start(struct voicebus *vb); void voicebus_stop(struct voicebus *vb); void voicebus_quiesce(struct voicebus *vb); int voicebus_transmit(struct voicebus *vb, struct vbb *vbb); int voicebus_set_minlatency(struct voicebus *vb, unsigned int milliseconds); int voicebus_current_latency(struct voicebus *vb); static inline int voicebus_init(struct voicebus *vb, const char *board_name) { return __voicebus_init(vb, board_name, NORMAL); } static inline int voicebus_boot_init(struct voicebus *vb, const char *board_name) { return __voicebus_init(vb, board_name, BOOT); } /** * voicebus_lock_latency() - Do not increase the latency during underruns. * */ static inline void voicebus_lock_latency(struct voicebus *vb) { set_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags); } /** * voicebus_unlock_latency() - Bump up the latency during underruns. * */ static inline void voicebus_unlock_latency(struct voicebus *vb) { clear_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags); } /** * voicebus_is_latency_locked() - Return 1 if latency is currently locked. * */ static inline int voicebus_is_latency_locked(const struct voicebus *vb) { return test_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags); } static inline void voicebus_set_normal_mode(struct voicebus *vb) { vb->mode = NORMAL; } static inline void voicebus_set_hx8_mode(struct voicebus *vb) { vb->mode = HX8; } /** * voicebus_set_max_latency() - Set the maximum number of milliseconds the latency will be able to grow to. */ static inline void voicebus_set_maxlatency(struct voicebus *vb, unsigned int max_latency) { unsigned long flags; spin_lock_irqsave(&vb->lock, flags); vb->max_latency = clamp(max_latency, vb->min_tx_buffer_count, VOICEBUS_DEFAULT_MAXLATENCY); spin_unlock_irqrestore(&vb->lock, flags); } #endif /* __VOICEBUS_H__ */ dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/GpakApi.h0000644000175000017500000006155711423153456022064 0ustar tzafrirtzafrir/* * Copyright (c) 2005 , Adaptive Digital Technologies, Inc. * * File Name: GpakApi.h * * Description: * This file contains the function prototypes and data types for the user * API functions that communicate with DSPs executing G.PAK software. The * file is used by application software in the host processor connected to * C55X G.PAK DSPs via a Host Port Interface. * * Version: 1.0 * * Revision History: * 06/15/05 - Initial release. * 11/15/2006 - 24 TDM-TDM Channels EC release */ #ifndef _GPAKAPI_H /* prevent multiple inclusion */ #define _GPAKAPI_H #include "gpakErrs.h" #include "gpakenum.h" // Bit masks to select which algorithm's parameters to update: Or-together the // desired masks into the UpdateBits function parameter. #define DTMF_UPDATE_MASK 0x0010 // update DTMF params, MinLevel, SNRFlag and Freq #define DTMF_TWIST_UPDATE_MASK 0x0020 // update DTMF TWIST system params #define DTMF_VALID_MASK 0x0080 // update DTMF ValidMask params #define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words /* Definition of an Asynchronous Event Data Structure */ typedef union { struct { GpakToneCodes_t ToneCode; // detected tone code unsigned short int ToneDuration; // tone duration GpakTdmDirection Direction; // detected on A r B side short int DebugToneStatus;// reserved for debug info } toneEvent; } GpakAsyncEventData_t; /* Definition of an Echo Canceller Parameters information structure. */ typedef struct GpakEcanParms { short int EcanTapLength; // Echo Can Num Taps (tail length) short int EcanNlpType; // Echo Can NLP Type short int EcanAdaptEnable; // Echo Can Adapt Enable flag short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag short int EcanDblTalkThresh; // Echo Can Double Talk threshold short int EcanMaxDoubleTalkThres; // Maximum double-talk threshold short int EcanNlpThreshold; // Echo Can NLP threshold short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged short int EcanNlpUnConv;// Dynamic NLP control, NLP limit when EC not converged yet short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode short int EcanCngThreshold; // Echo Can CNG Noise threshold short int EcanAdaptLimit; // Echo Can Max Adapts per frame short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit short int EcanNumFirSegments; // Echo Can Num FIR Segments short int EcanFirSegmentLen; // Echo Can FIR Segment Length short int EcanTandemOperationEnable; //Enable tandem operation short int EcanMixedFourWireMode; // Handle possible 4-wire (echo-free) lines short int EcanReconvergenceCheckEnable; // Handle possible 4-wire (echo-free) lines short int EcanSaturationLevel; /* Far end input level above which significant saturation/nonlinearity may be expected. */ short int EcanNLPSaturationThreshold; /* NLP threshold under conditions of possible saturation */ } GpakEcanParms_t; /* Definition of a Channel Configuration information structure. */ typedef struct GpakChannelConfig { GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id unsigned short int PcmInSlotA; // A side PCM Input Time Slot GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id unsigned short int PcmOutSlotA; // A side PCM Output Time Slot GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id unsigned short int PcmInSlotB; // B side PCM Input Time Slot GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id unsigned short int PcmOutSlotB; // B side PCM Output Time Slot GpakToneTypes ToneTypesA; // A side Tone Detect Types GpakToneTypes ToneTypesB; // B side Tone Detect Types GpakActivation EcanEnableA; // Echo Cancel A Enabled GpakActivation EcanEnableB; // Echo Cancel B Enabled GpakEcanParms_t EcanParametersA; // Echo Cancel parameters GpakEcanParms_t EcanParametersB; // Echo Cancel parameters GpakCompandModes SoftwareCompand; // software companding GpakRate_t FrameRate; // Gpak Frame Rate GpakActivation MuteToneA; // A side mute DTMF Enabled GpakActivation MuteToneB; // B side mute DTMF Enabled GpakActivation FaxCngDetA; // A side FaxCng Tone Detector Enabled GpakActivation FaxCngDetB; // B side FaxCng Tone Detector Enabled unsigned short int ChannelId_tobe_Debug; /* Channel Id of the channel that we'd like to debug */ /* (0 to MaxChannels-1), only used for tdmToTdmDebug */ } GpakChannelConfig_t; /* Definition of a Serial Port Configuration Structure */ typedef struct GpakPortConfig { GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection unsigned short int FirstBlockNum1; // port 1 first group Block Number unsigned short int FirstSlotMask1; // port 1 first group Slot Mask unsigned short int SecBlockNum1; // port 1 second group Block Number unsigned short int SecSlotMask1; // port 1 second group Slot Mask GpakSerWordSize_t SerialWordSize1; // port 1 serial word size GpakCompandModes CompandingMode1; // port 1 companding mode GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay GpakActivation DxDelay1; // port 1 DX Delay unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask unsigned short int EightSlotMask1; // port 1 8th group Slot Mask GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection unsigned short int FirstBlockNum2; // port 2 first group Block Number unsigned short int FirstSlotMask2; // port 2 first group Slot Mask unsigned short int SecBlockNum2; // port 2 second group Block Number unsigned short int SecSlotMask2; // port 2 second group Slot Mask GpakSerWordSize_t SerialWordSize2; // port 2 serial word size GpakCompandModes CompandingMode2; // port 2 companding mode GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay GpakActivation DxDelay2; // port 2 DX Delay unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask unsigned short int EightSlotMask2; // port 2 8th group Slot Mask GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection unsigned short int FirstBlockNum3; // port 3 first group Block Number unsigned short int FirstSlotMask3; // port 3 first group Slot Mask unsigned short int SecBlockNum3; // port 3 second group Block Number unsigned short int SecSlotMask3; // port 3 second group Slot Mask GpakSerWordSize_t SerialWordSize3; // port 3 serial word size GpakCompandModes CompandingMode3; // port 3 companding mode GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay GpakActivation DxDelay3; // port 3 DX Delay unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask unsigned short int EightSlotMask3; // port 3 8th group Slot Mask } GpakPortConfig_t; /* Definition of a Tone Generation Parameter Structure */ /* typedef struct { GpakToneGenType_t ToneType; // Tone Type unsigned short int Frequency[4]; // Frequency (Hz) short int Level[4]; // Frequency's Level (1 dBm) unsigned short int OnTime[4]; // On Times (msecs) unsigned short int OffTime[4]; // Off Times (msecs) } GpakToneGenParms_t; */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakConfigureChannel return status. */ typedef enum { CcsSuccess = 0, /* Channel Configured successfully */ CcsParmError = 1, /* Channel Config Parameter error */ CcsInvalidChannel = 2, /* invalid channel */ CcsInvalidDsp = 3, /* invalid DSP */ CcsDspCommFailure = 4 /* failed to communicate with DSP */ } gpakConfigChanStatus_t; /* * gpakConfigureChannel - Configure a DSP's Channel. * * FUNCTION * This function configures a DSP's Channel. * * RETURNS * Status code indicating success or a specific error. * */ extern gpakConfigChanStatus_t gpakConfigureChannel( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GpakChanType ChannelType, // channel type GpakChannelConfig_t *pChanConfig, // pointer to channel config info GPAK_ChannelConfigStat_t *pStatus // pointer to Channel Config Status ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakTearDownChannel return status. */ typedef enum { TdsSuccess = 0, /* Channel Tear Down successful */ TdsError = 1, /* Channel Tear Down error */ TdsInvalidChannel = 2, /* invalid channel */ TdsInvalidDsp = 3, /* invalid DSP */ TdsDspCommFailure = 4 /* failed to communicate with DSP */ } gpakTearDownStatus_t; /* * gpakTearDownChannel - Tear Down a DSP's Channel. * * FUNCTION * This function tears down a DSP's Channel. * * RETURNS * Status code indicating success or a specific error. * */ extern gpakTearDownStatus_t gpakTearDownChannel( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GPAK_TearDownChanStat_t *pStatus // pointer to Tear Down Status ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakAlgControl return status. */ typedef enum { AcSuccess = 0, /* control successful */ AcInvalidChannel = 1, /* invalid channel identifier */ AcInvalidDsp = 2, /* invalid DSP */ AcParmError = 3, /* invalid control parameter */ AcDspCommFailure = 4 /* failed to communicate with DSP */ } gpakAlgControlStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakAlgControl - Control an Algorithm. * * FUNCTION * This function controls an Algorithm * * RETURNS * Status code indicating success or a specific error. * */ extern gpakAlgControlStat_t gpakAlgControl( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GpakAlgCtrl_t ControlCode, // algorithm control code GPAK_AlgControlStat_t *pStatus // pointer to return status ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakConfigurePorts return status. */ typedef enum { CpsSuccess = 0, /* Serial Ports configured successfully */ CpsParmError = 1, /* Configure Ports Parameter error */ CpsInvalidDsp = 2, /* invalid DSP */ CpsDspCommFailure = 3 /* failed to communicate with DSP */ } gpakConfigPortStatus_t; /* * gpakConfigurePorts - Configure a DSP's serial ports. * * FUNCTION * This function configures a DSP's serial ports. * * RETURNS * Status code indicating success or a specific error. * */ extern gpakConfigPortStatus_t gpakConfigurePorts( unsigned short int DspId, // DSP identifier const GpakPortConfig_t *pPortConfig, // pointer to Port Config info GPAK_PortConfigStat_t *pStatus // pointer to Port Config Status ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakDownloadDsp return status. */ typedef enum { GdlSuccess = 0, /* DSP download successful */ GdlFileReadError = 1, /* error reading Download file */ GdlInvalidFile = 2, /* invalid Download file content */ GdlInvalidDsp = 3 /* invalid DSP */ } gpakDownloadStatus_t; /* * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. * * FUNCTION * This function reads a DSP's Program and Data memory image from the * specified file and writes the image to the DSP's memory. * * RETURNS * Status code indicating success or a specific error. * */ extern gpakDownloadStatus_t gpakDownloadDsp( unsigned short int DspId, // DSP identifier GPAK_FILE_ID FileId // G.PAK download file identifier ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* gpakReadEventFIFOMessage return status */ typedef enum { RefEventAvail = 0, /* an event was successfully read from the fifo */ RefNoEventAvail = 1, /* no event was in the fifo */ RefInvalidDsp = 2, /* invalid DSP identifier */ RefInvalidEvent = 3, /* invalid event */ RefDspCommFailure = 4 /* error communicating with DSP */ } gpakReadEventFIFOMessageStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadEventFIFOMessage - read from the event fifo * * FUNCTION * This function reads a single event from the event fifo if one is available * * RETURNS * Status code indicating success or a specific error. * * Note: This function should be called in a loop until the return status * indicates that the fifo is empty. */ extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage( unsigned short int DspId, // DSP identifier unsigned short int *pChannelId, // pointer to channel identifier GpakAsyncEventCode_t *pEventCode, // pointer to Event Code GpakAsyncEventData_t *pEventData // pointer to Event Data Struct ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakPingDsp return status values */ typedef enum { PngSuccess = 0, /* DSP responded successfully */ PngInvalidDsp = 1, /* invalid DSP identifier */ PngDspCommFailure = 2 /* error communicating with DSP */ } gpakPingDspStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakPingDsp - ping the DSP to see if it's alive * * FUNCTION * This function checks if the DSP is still communicating with the host * * RETURNS * Status code indicating success or a specific error. */ extern gpakPingDspStat_t gpakPingDsp( unsigned short int DspId, // DSP identifier unsigned short int *pDspSwVersion // DSP software version ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakSerialTxFixedValue return status values */ typedef enum { TfvSuccess = 0, /* operation successful */ TfvInvalidChannel = 1, /* invalid channel identifier */ TfvInvalidDsp = 2, /* invalid DSP identifier */ TfvDspCommFailure = 3 /* failed to communicate with DSP */ } gpakSerialTxFixedValueStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakSerialTxFixedValue - transmit a fixed value on a timeslot * * FUNCTION * This function controls transmission of a fixed value out onto a serial * port's timeslot. * * RETURNS * Status code indicating success or a specific error. */ extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id unsigned short int PcmOutSlot, // PCM Output Time Slot unsigned short int Value, // 16-bit value GpakActivation State // activation state ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakControlTdmLoopBack return status values */ typedef enum { ClbSuccess = 0, /* operation successful */ ClbSerPortInactive = 1, /* serial port is inactive */ ClbInvalidDsp = 2, /* invalid DSP identifier */ ClbDspCommFailure = 3 /* failed to communicate with DSP */ } gpakControlTdmLoopBackStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakControlTdmLoopBack - control a serial port's loopback state * * FUNCTION * This function enables/disables the tdm input to output looback mode on a * serial port * * RETURNS * Status code indicating success or a specific error. */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack( unsigned short int DspId, // DSP identifier GpakSerialPort_t SerialPort, // Serial Port Id GpakActivation LoopBackState // Loopback State ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakReadCpuUsage return status values */ typedef enum { RcuSuccess = 0, /* operation successful */ RcuInvalidDsp = 1, /* invalid DSP identifier */ RcuDspCommFailure = 2 /* communication failure */ } gpakReadCpuUsageStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadCpuUsage - read the cpu usage statistics * * FUNCTION * This function reads cpu utilization from the DSP. * * RETURNS * Status code indicating success or a specific error. */ extern gpakReadCpuUsageStat_t gpakReadCpuUsage( unsigned short int DspId, // DSP identifier unsigned short int *pPeakUsage, // pointer to peak usage variable unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakResetCpuUsageStats return status values */ typedef enum { RstcSuccess = 0, /* operation successful */ RstcInvalidDsp = 1, /* invalid DSP identifier */ RstcDspCommFailure = 2 /* communication failure */ } gpakResetCpuUsageStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakResetCpuUsageStats - reset the cpu usage statistics * * FUNCTION * This function resets the cpu utilization statistics * * RETURNS * Status code indicating success or a specific error. */ extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats( unsigned short int DspId // DSP identifier ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakReadFramingStats return status values */ typedef enum { RfsSuccess = 0, /* operation successful */ RfsInvalidDsp = 1, /* invalid DSP identifier */ RfsDspCommFailure = 2 /* communication failure */ } gpakReadFramingStatsStatus_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadFramingStats * * FUNCTION * This function reads a DSP's framing interrupt statistics * * RETURNS * Status code indicating success or a specific error. */ extern gpakReadFramingStatsStatus_t gpakReadFramingStats( unsigned short int DspId, // DSP identifier unsigned short int *pFramingError1Count, // port 1 Framing error count unsigned short int *pFramingError2Count, // port 2 Framing error count unsigned short int *pFramingError3Count, // port 3 Framing error count unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count unsigned short int *pDmaSlipStatsBuffer // DMA slips count ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* gpakResetFramingStats return values */ typedef enum { RstfSuccess = 0, /* operation successful */ RstfInvalidDsp = 1, /* invalid DSP identifier */ RstfDspCommFailure = 2 /* communication failure */ } gpakResetFramingStatsStatus_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakResetFramingStats - reset a DSP's framing interrupt statistics * * FUNCTION * This function resets a DSP's framing interrupt statistics * * RETURNS * Status code indicating success or a specific error. */ extern gpakResetFramingStatsStatus_t gpakResetFramingStats( unsigned short int DspId // DSP identifier ); typedef enum { RmmSuccess =0, RmmInvalidDsp = 1, RmmSizeTooBig = 2, RmmFailure = 3, RmmInvalidAddress = 4 } gpakReadDSPMemoryStat_t; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakResetFramingStats - read a section of DSP memory * to get access DSP registers, since 0x00--0x60 not HPI-accessable * * FUNCTION * This function resets a DSP's framing interrupt statistics * * RETURNS * Status code indicating success or a specific error. */ extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap( unsigned short int DspId, // Dsp Identifier unsigned short int *pDest, // Buffer on host to hold DSP memory map DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word ); typedef enum { GPIOSuccess =0, GPIOInvalidDsp = 1, GPIODspCommFailure = 2 }gpakAccessGPIOStat_t; extern gpakAccessGPIOStat_t gpakAccessGPIO( unsigned short int DspId, // DSP identifier GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read unsigned short int *pGPIOValue // pointer for the read/write value or DIR mask ); /* gpakWriteSystemParms return status. */ typedef enum { WspSuccess = 0, /* System Parameters written successfully */ WspParmError = 1, /* Write System Parms's Parameter error */ WspInvalidDsp = 2, /* invalid DSP */ WspDspCommFailure = 3 /* failed to communicate with DSP */ } gpakWriteSysParmsStatus_t; /* Definition of a System Parameters information structure. */ typedef struct { /* DTMF Parameters */ short int MinSigLevel; /* 0 = Disabled, Min Sig Power Level for detection */ short int SNRFlag; /* 0 = Disabled, relax SNR tolerances */ short int FreqDeviation; /* 0 = Disabled, X Percent Deviation times 10 (e.g. 1.7% is entered as 17) */ short int DtmfFwdTwist; /* 0 to 8 db */ short int DtmfRevTwist; /* 0 to 8 db */ short int DtmfValidityMask; /* This flag allows users to relax the trailing conditions of the tone */ } GpakSystemParms_t; /* gpakReadSystemParms return status. */ typedef enum { RspSuccess = 0, /* System Parameters read successfully */ RspInvalidDsp = 1, /* invalid DSP */ RspDspCommFailure = 2 /* failed to communicate with DSP */ } gpakReadSysParmsStatus_t; extern gpakReadSysParmsStatus_t gpakReadSystemParms( unsigned short int DspId, // DSP identifier GpakSystemParms_t *pSysParms /* pointer to System Parms info var */ ); extern gpakWriteSysParmsStatus_t gpakWriteSystemParms( unsigned short int DspId, // DSP identifier GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */ unsigned short int UpdateBits, /* input: flags indicating which parms to update */ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */ ); #endif // end multiple inclusion dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/voicebus_net.c0000644000175000017500000002162311621031736023212 0ustar tzafrirtzafrir/* * Voicebus network debug interface * * Written by Shaun Ruffell * * Copyright (C) 2010-2011 Digium, Inc. * * All rights reserved. * VoiceBus is a registered trademark of Digium. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include "voicebus.h" #include "voicebus_net.h" #ifdef VOICEBUS_NET_DEBUG struct voicebus_netdev_priv { struct voicebus *vb; }; static inline struct voicebus * voicebus_from_netdev(struct net_device *netdev) { struct voicebus_netdev_priv *priv; priv = netdev_priv(netdev); return priv->vb; } static void * skb_to_vbb(struct voicebus *vb, struct sk_buff *skb) { int res; struct vbb *vbb; const int COMMON_HEADER = 30; dma_addr_t dma_addr; if (skb->len != (VOICEBUS_SFRAME_SIZE + COMMON_HEADER)) { dev_warn(&vb->pdev->dev, "Packet of length %d is not the " "required %d.\n", skb->len, VOICEBUS_SFRAME_SIZE + COMMON_HEADER); return NULL; } vbb = dma_pool_alloc(vb->pool, GFP_KERNEL, &dma_addr); if (!vbb) return NULL; vbb->dma_addr = dma_addr; res = skb_copy_bits(skb, COMMON_HEADER, vbb, VOICEBUS_SFRAME_SIZE); if (res) { dev_warn(&vb->pdev->dev, "Failed call to skb_copy_bits.\n"); dma_pool_free(vb->pool, vbb, vbb->dma_addr); return NULL; } return vbb; } static int vb_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct voicebus *vb = voicebus_from_netdev(netdev); void *vbb; vbb = skb_to_vbb(vb, skb); if (vbb) voicebus_transmit(vb, vbb); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } static int vb_net_receive(struct voicebus *vb, int max) { int count = 0; struct sk_buff *skb; WARN_ON(0 == max); while ((skb = skb_dequeue(&vb->captured_packets))) { netif_receive_skb(skb); if (++count >= max) break; } return count; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) static int vb_net_poll(struct net_device *netdev, int *budget) { struct voicebus *vb = voicebus_from_netdev(netdev); int count = 0; int quota = min(netdev->quota, *budget); count = vb_net_receive(vb, quota); *budget -= count; netdev->quota -= count; if (!skb_queue_len(&vb->captured_packets)) { netif_rx_complete(netdev); return 0; } else { return -1; } } #else static int vb_net_poll(struct napi_struct *napi, int budget) { struct voicebus *vb = container_of(napi, struct voicebus, napi); int count; count = vb_net_receive(vb, budget); if (!skb_queue_len(&vb->captured_packets)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_complete(vb->netdev, &vb->napi); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) netif_rx_complete(&vb->napi); #else napi_complete(&vb->napi); #endif } return count; } #endif static void vb_net_set_multi(struct net_device *netdev) { struct voicebus *vb = voicebus_from_netdev(netdev); dev_dbg(&vb->pdev->dev, "%s promiscuity:%d\n", __func__, netdev->promiscuity); } static int vb_net_up(struct net_device *netdev) { struct voicebus *vb = voicebus_from_netdev(netdev); dev_dbg(&vb->pdev->dev, "%s\n", __func__); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_enable(netdev); #else napi_enable(&vb->napi); #endif return 0; } static int vb_net_down(struct net_device *netdev) { struct voicebus *vb = voicebus_from_netdev(netdev); dev_dbg(&vb->pdev->dev, "%s\n", __func__); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_disable(netdev); #else napi_disable(&vb->napi); #endif return 0; } static struct net_device_stats * vb_net_get_stats(struct net_device *netdev) { struct voicebus *vb = voicebus_from_netdev(netdev); return &vb->net_stats; } #ifdef HAVE_NET_DEVICE_OPS static const struct net_device_ops vb_netdev_ops = { .ndo_set_multicast_list = &vb_net_set_multi, .ndo_open = &vb_net_up, .ndo_stop = &vb_net_down, .ndo_start_xmit = &vb_net_hard_start_xmit, .ndo_get_stats = &vb_net_get_stats, }; #endif /** * vb_net_register - Register a new network interface. * @vb: voicebus card to register the interface for. * * The network interface is primarily used for debugging in order to watch the * traffic between the transcoder and the host. * */ int vb_net_register(struct voicebus *vb, const char *board_name) { int res; struct net_device *netdev; struct voicebus_netdev_priv *priv; const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; netdev = alloc_netdev(sizeof(*priv), board_name, ether_setup); if (!netdev) return -ENOMEM; priv = netdev_priv(netdev); priv->vb = vb; memcpy(netdev->dev_addr, our_mac, sizeof(our_mac)); # ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &vb_netdev_ops; # else netdev->set_multicast_list = vb_net_set_multi; netdev->open = vb_net_up; netdev->stop = vb_net_down; netdev->hard_start_xmit = vb_net_hard_start_xmit; netdev->get_stats = vb_net_get_stats; # endif netdev->promiscuity = 0; netdev->flags |= IFF_NOARP; # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netdev->poll = vb_net_poll; netdev->weight = 64; # else netif_napi_add(netdev, &vb->napi, vb_net_poll, 64); # endif skb_queue_head_init(&vb->captured_packets); res = register_netdev(netdev); if (res) { dev_warn(&vb->pdev->dev, "Failed to register network device %s.\n", board_name); goto error_sw; } vb->netdev = netdev; dev_dbg(&vb->pdev->dev, "Created network device %s for debug.\n", board_name); return 0; error_sw: if (netdev) free_netdev(netdev); return res; } void vb_net_unregister(struct voicebus *wc) { struct sk_buff *skb; if (!wc->netdev) return; unregister_netdev(wc->netdev); while ((skb = skb_dequeue(&wc->captured_packets))) kfree_skb(skb); free_netdev(wc->netdev); wc->netdev = NULL; } /* Header format for the voicebus network interface. */ struct voicebus_net_hdr { struct ethhdr ethhdr; __be16 seq_num; __be32 des0; __be16 tag; __be16 filler[4]; } __attribute__((packed)); static struct sk_buff * vbb_to_skb(struct net_device *netdev, const void *vbb, const int tx, const u32 des0, const u16 tag) { struct voicebus *vb = voicebus_from_netdev(netdev); struct sk_buff *skb; struct voicebus_net_hdr *hdr; /* 0x88B5 is the local experimental ethertype */ const u16 VOICEBUS_ETHTYPE = 0x88b5; const u8 BOARD_MAC[6] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; const u8 HOST_MAC[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; skb = netdev_alloc_skb(vb->netdev, VOICEBUS_SFRAME_SIZE + sizeof(*hdr) + NET_IP_ALIGN); if (!skb) return NULL; skb_reserve(skb, NET_IP_ALIGN); skb->dev = netdev; hdr = (struct voicebus_net_hdr *)skb_put(skb, VOICEBUS_SFRAME_SIZE + sizeof(*hdr)); /* Fill in the source and destination mac addresses appropriately * depending on whether this is a packet we are transmitting or a packet * that we have received. */ if (tx) { memcpy(hdr->ethhdr.h_dest, BOARD_MAC, sizeof(BOARD_MAC)); memcpy(hdr->ethhdr.h_source, HOST_MAC, sizeof(HOST_MAC)); hdr->seq_num = cpu_to_be16(atomic_inc_return( &vb->tx_seqnum)); } else { memcpy(hdr->ethhdr.h_dest, HOST_MAC, sizeof(HOST_MAC)); memcpy(hdr->ethhdr.h_source, BOARD_MAC, sizeof(BOARD_MAC)); hdr->seq_num = cpu_to_be16(atomic_inc_return( &vb->rx_seqnum)); } memset(hdr->filler, 0, sizeof(hdr->filler)); hdr->des0 = cpu_to_be32(des0); hdr->tag = cpu_to_be16(tag); hdr->ethhdr.h_proto = htons(VOICEBUS_ETHTYPE); /* copy the rest of the packet. */ memcpy(skb->data + sizeof(*hdr), vbb, VOICEBUS_SFRAME_SIZE); skb->protocol = eth_type_trans(skb, netdev); return skb; } /** * vb_net_capture_cmd - Send a vbb to the network stack. * @vb: Interface card received the command. * @vbb: Voicebus buffer to pass up.. * @tx: 1 if this is a vbb that the driver is sending to the card. * */ void vb_net_capture_vbb(struct voicebus *vb, const void *vbb, const int tx, const u32 des0, const u16 tag) { struct sk_buff *skb; struct net_device *netdev = vb->netdev; const int MAX_CAPTURED_PACKETS = 5000; if (!netdev) return; /* If the interface isn't up, we don't need to capture the packet. */ if (!(netdev->flags & IFF_UP)) return; if (skb_queue_len(&vb->captured_packets) > MAX_CAPTURED_PACKETS) { WARN_ON_ONCE(1); return; } skb = vbb_to_skb(netdev, vbb, tx, des0, tag); if (!skb) return; skb_queue_tail(&vb->captured_packets, skb); # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_rx_schedule(netdev); # elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_schedule(netdev, &vb->napi); # elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) netif_rx_schedule(&vb->napi); # else napi_schedule(&vb->napi); # endif return; } #endif dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/vpmadtreg.h0000644000175000017500000000210011334112400022475 0ustar tzafrirtzafrir/* * vpmadtreg.h - Registration utility for firmware loaders. * * Allows drivers for boards that host VPMAD032 modules to initiate firmware * loads. * * Written by Digium Incorporated * * Copyright (C) 2008-2010 Digium, Inc. All rights reserved. * * See http://www.asterisk.org for more information about the Asterisk * project. Please do not directly contact any of the maintainers of this * project for assistance; the project provides a web site, mailing lists and * IRC channels for your use. * * This program is free software, distributed under the terms of the GNU * General Public License Version 2 as published by the Free Software * Foundation. See the LICENSE file included with this program for more * details. */ #ifndef __VPMADTREG_H__ #define __VPMADTREG_H__ struct vpmadt_loader { struct module *owner; struct list_head node; int (*load)(struct voicebus *); }; int vpmadtreg_register(struct vpmadt_loader *loader); int vpmadtreg_unregister(struct vpmadt_loader *loader); int vpmadtreg_loadfirmware(struct voicebus *vb); #endif dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/GpakCust.c0000644000175000017500000006236711571766124022272 0ustar tzafrirtzafrir/* * Copyright (c) 2005, Adaptive Digital Technologies, Inc. * Copyright (c) 2005-2010, Digium Incorporated * * File Name: GpakCust.c * * Description: * This file contains host system dependent functions to support generic * G.PAK API functions. The file is integrated into the host processor * connected to C55x G.PAK DSPs via a Host Port Interface. * * Note: This file is supplied by Adaptive Digital Technologies and * modified by Digium in order to support the VPMADT032 modules. * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #include #else #include #endif #include #include #include "GpakCust.h" #include "GpakApi.h" #include "adt_lec.h" #include "voicebus.h" #include "vpmadtreg.h" static DEFINE_SPINLOCK(ifacelock); static struct vpmadt032 *ifaces[MAX_DSP_CORES]; #define vpm_info(vpm, format, arg...) \ dev_info(&vpm->vb->pdev->dev , format , ## arg) static inline struct vpmadt032 *find_iface(const unsigned short dspid) { struct vpmadt032 *ret; spin_lock(&ifacelock); if (ifaces[dspid]) { ret = ifaces[dspid]; } else { ret = NULL; } spin_unlock(&ifacelock); return ret; } static struct vpmadt032_cmd *vpmadt032_get_free_cmd(struct vpmadt032 *vpm) { struct vpmadt032_cmd *cmd; might_sleep(); cmd = kmalloc(sizeof(struct vpmadt032_cmd), GFP_KERNEL); if (unlikely(!cmd)) return NULL; memset(cmd, 0, sizeof(*cmd)); init_completion(&cmd->complete); return cmd; } /* Wait for any outstanding commands to the VPMADT032 to complete */ static inline int vpmadt032_io_wait(struct vpmadt032 *vpm) { unsigned long flags; int empty; while (1) { spin_lock_irqsave(&vpm->list_lock, flags); empty = list_empty(&vpm->pending_cmds) && list_empty(&vpm->active_cmds); spin_unlock_irqrestore(&vpm->list_lock, flags); if (empty) { break; } else { msleep(1); } } return 0; } /* Issue a read command to a register on the VPMADT032. We'll get the results * later. */ static struct vpmadt032_cmd *vpmadt032_getreg_full_async(struct vpmadt032 *vpm, int pagechange, unsigned short addr) { unsigned long flags; struct vpmadt032_cmd *cmd; cmd = vpmadt032_get_free_cmd(vpm); if (!cmd) return NULL; cmd->desc = (pagechange) ? __VPM150M_RWPAGE | __VPM150M_RD : __VPM150M_RD; cmd->address = addr; cmd->data = 0; spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_cmds); spin_unlock_irqrestore(&vpm->list_lock, flags); return cmd; } /* Get the results from a previous call to vpmadt032_getreg_full_async. */ static int vpmadt032_getreg_full_return(struct vpmadt032 *vpm, int pagechange, u16 addr, u16 *outbuf, struct vpmadt032_cmd *cmd) { unsigned long flags; unsigned long ret; BUG_ON(!cmd); /* We'll wait for 200ms */ ret = wait_for_completion_timeout(&cmd->complete, HZ/5); if (unlikely(!ret)) { spin_lock_irqsave(&vpm->list_lock, flags); list_del(&cmd->node); spin_unlock_irqrestore(&vpm->list_lock, flags); kfree(cmd); return -EIO; } if (cmd->desc & __VPM150M_FIN) { *outbuf = cmd->data; cmd->desc = 0; ret = 0; } list_del(&cmd->node); kfree(cmd); return 0; } /* Read one of the registers on the VPMADT032 */ static int vpmadt032_getreg_full(struct vpmadt032 *vpm, int pagechange, u16 addr, u16 *outbuf) { struct vpmadt032_cmd *cmd; cmd = vpmadt032_getreg_full_async(vpm, pagechange, addr); if (unlikely(!cmd)) { return -ENOMEM; } return vpmadt032_getreg_full_return(vpm, pagechange, addr, outbuf, cmd); } static int vpmadt032_setreg_full(struct vpmadt032 *vpm, int pagechange, unsigned int addr, u16 data) { unsigned long flags; struct vpmadt032_cmd *cmd; cmd = vpmadt032_get_free_cmd(vpm); if (!cmd) return -ENOMEM; cmd->desc = cpu_to_le16((pagechange) ? (__VPM150M_WR|__VPM150M_RWPAGE) : __VPM150M_WR); cmd->address = cpu_to_le16(addr); cmd->data = cpu_to_le16(data); spin_lock_irqsave(&vpm->list_lock, flags); list_add_tail(&cmd->node, &vpm->pending_cmds); spin_unlock_irqrestore(&vpm->list_lock, flags); return 0; } static int vpmadt032_setpage(struct vpmadt032 *vpm, u16 addr) { addr &= 0xf; /* We do not need to set the page if we're already on the page we're * interested in. */ if (vpm->curpage == addr) return 0; else vpm->curpage = addr; return vpmadt032_setreg_full(vpm, 1, 0, addr); } static unsigned char vpmadt032_getpage(struct vpmadt032 *vpm) { unsigned short res; const int pagechange = 1; vpmadt032_getreg_full(vpm, pagechange, 0, &res); return res; } static int vpmadt032_getreg(struct vpmadt032 *vpm, unsigned int addr, u16 *data) { unsigned short res; vpmadt032_setpage(vpm, addr >> 16); res = vpmadt032_getreg_full(vpm, 0, addr & 0xffff, data); return res; } static int vpmadt032_setreg(struct vpmadt032 *vpm, unsigned int addr, u16 data) { int res; vpmadt032_setpage(vpm, addr >> 16); res = vpmadt032_setreg_full(vpm, 0, addr & 0xffff, data); return res; } struct change_order { struct list_head node; unsigned int channel; struct adt_lec_params params; }; static struct change_order *alloc_change_order(void) { return kzalloc(sizeof(struct change_order), GFP_ATOMIC); } static void free_change_order(struct change_order *order) { kfree(order); } static int vpmadt032_control(struct vpmadt032 *vpm, unsigned short int channel, GpakAlgCtrl_t control_code, GPAK_AlgControlStat_t *pstatus) { gpakAlgControlStat_t stat; int retry = 4; while (retry--) { stat = gpakAlgControl(vpm->dspid, channel, control_code, pstatus); if (AcDspCommFailure == stat) msleep(5); else break; } return stat; } static int vpmadt032_enable_ec(struct vpmadt032 *vpm, int channel, enum adt_companding companding) { int res; GPAK_AlgControlStat_t pstatus; GpakAlgCtrl_t control; control = (ADT_COMP_ALAW == companding) ? EnableALawSwCompanding : EnableMuLawSwCompanding; if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) { const char *law; law = (control == EnableMuLawSwCompanding) ? "MuLaw" : "ALaw"; vpm_info(vpm, "Enabling ecan on channel: %d (%s)\n", channel, law); } res = vpmadt032_control(vpm, channel, control, &pstatus); if (res) { vpm_info(vpm, "Unable to set SW Companding on " "channel %d (reason %d)\n", channel, res); } res = vpmadt032_control(vpm, channel, EnableEcanA, &pstatus); return res; } static int vpmadt032_disable_ec(struct vpmadt032 *vpm, int channel) { int res; GPAK_AlgControlStat_t pstatus; if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) vpm_info(vpm, "Disabling ecan on channel: %d\n", channel); res = vpmadt032_control(vpm, channel, BypassSwCompanding, &pstatus); if (res) { vpm_info(vpm, "Unable to disable sw companding on " "echo cancellation channel %d (reason %d)\n", channel, res); } res = vpmadt032_control(vpm, channel, BypassEcanA, &pstatus); return res; } static struct change_order *get_next_order(struct vpmadt032 *vpm) { struct change_order *order; spin_lock(&vpm->change_list_lock); if (!list_empty(&vpm->change_list)) { order = list_entry(vpm->change_list.next, struct change_order, node); list_del(&order->node); } else { order = NULL; } spin_unlock(&vpm->change_list_lock); return order; } static int nlp_settings_changed(const struct adt_lec_params *a, const struct adt_lec_params *b) { return ((a->nlp_type != b->nlp_type) || (a->nlp_threshold != b->nlp_threshold) || (a->nlp_max_suppress != b->nlp_max_suppress)); } static int echocan_on(const struct adt_lec_params *new, const struct adt_lec_params *old) { return ((new->tap_length != old->tap_length) && (new->tap_length > 0)); } static int echocan_off(const struct adt_lec_params *new, const struct adt_lec_params *old) { return ((new->tap_length != old->tap_length) && (0 == new->tap_length)); } static void update_channel_config(struct vpmadt032 *vpm, unsigned int channel, struct adt_lec_params *desired) { int res; GPAK_AlgControlStat_t pstatus; GPAK_ChannelConfigStat_t cstatus; GPAK_TearDownChanStat_t tstatus; GpakChannelConfig_t chanconfig; if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) { vpm_info(vpm, "Reconfiguring chan %d for nlp %d, " "nlp_thresh %d, and max_supp %d\n", channel + 1, desired->nlp_type, desired->nlp_threshold, desired->nlp_max_suppress); } vpm->setchanconfig_from_state(vpm, channel, &chanconfig); res = gpakTearDownChannel(vpm->dspid, channel, &tstatus); if (res) return; res = gpakConfigureChannel(vpm->dspid, channel, tdmToTdm, &chanconfig, &cstatus); if (res) return; if (!desired->tap_length) { res = vpmadt032_control(vpm, channel, BypassSwCompanding, &pstatus); if (res) { vpm_info(vpm, "Unable to disable sw companding on " "echo cancellation channel %d (reason %d)\n", channel, res); } vpmadt032_control(vpm, channel, BypassEcanA, &pstatus); } return; } /** * vpmadt032_bh - Changes the echocan parameters on the vpmadt032 module. * * This function is typically scheduled to run in the workqueue by the * vpmadt032_echocan_with_params function. This is because communicating with * the hardware can take some time while messages are sent to the VPMADT032 * module and the driver waits for the responses. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void vpmadt032_bh(void *data) { struct vpmadt032 *vpm = data; #else static void vpmadt032_bh(struct work_struct *data) { struct vpmadt032 *vpm = container_of(data, struct vpmadt032, work); #endif struct change_order *order; while ((order = get_next_order(vpm))) { struct adt_lec_params *old; struct adt_lec_params *new; unsigned int channel; channel = order->channel; BUG_ON(channel >= ARRAY_SIZE(vpm->curecstate)); old = &vpm->curecstate[channel]; new = &order->params; if (nlp_settings_changed(new, old)) update_channel_config(vpm, channel, new); else if (echocan_on(new, old)) vpmadt032_enable_ec(vpm, channel, new->companding); else if (echocan_off(new, old)) vpmadt032_disable_ec(vpm, channel); *old = order->params; free_change_order(order); } } #include "adt_lec.c" static void vpmadt032_check_and_schedule_update(struct vpmadt032 *vpm, struct change_order *order) { struct change_order *cur; struct change_order *n; INIT_LIST_HEAD(&order->node); spin_lock(&vpm->change_list_lock); list_for_each_entry_safe(cur, n, &vpm->change_list, node) { if (cur->channel == order->channel) { list_replace(&cur->node, &order->node); free_change_order(cur); break; } } if (list_empty(&order->node)) list_add_tail(&order->node, &vpm->change_list); spin_unlock(&vpm->change_list_lock); queue_work(vpm->wq, &vpm->work); } int vpmadt032_echocan_create(struct vpmadt032 *vpm, int channo, enum adt_companding companding, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p) { unsigned int ret; struct change_order *order = alloc_change_order(); if (!order) return -ENOMEM; memcpy(&order->params, &vpm->curecstate[channo], sizeof(order->params)); ret = adt_lec_parse_params(&order->params, ecp, p); if (ret) { free_change_order(order); return ret; } if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) { vpm_info(vpm, "Channel is %d length %d\n", channo, ecp->tap_length); } /* The driver cannot control the number of taps on the VPMADT032 * module. Instead, it uses tap_length to enable or disable the echo * cancellation. */ order->params.tap_length = (ecp->tap_length) ? 1 : 0; order->params.companding = companding; order->channel = channo; vpmadt032_check_and_schedule_update(vpm, order); return 0; } EXPORT_SYMBOL(vpmadt032_echocan_create); void vpmadt032_echocan_free(struct vpmadt032 *vpm, int channo, struct dahdi_echocan_state *ec) { struct change_order *order; order = alloc_change_order(); WARN_ON(!order); if (!order) return; adt_lec_init_defaults(&order->params, 0); order->params.nlp_type = vpm->options.vpmnlptype; order->params.nlp_threshold = vpm->options.vpmnlpthresh; order->params.nlp_max_suppress = vpm->options.vpmnlpmaxsupp; order->channel = channo; if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) vpm_info(vpm, "Channel is %d length 0\n", channo); vpmadt032_check_and_schedule_update(vpm, order); } EXPORT_SYMBOL(vpmadt032_echocan_free); struct vpmadt032 * vpmadt032_alloc(struct vpmadt032_options *options) { struct vpmadt032 *vpm; int i; might_sleep(); vpm = kzalloc(sizeof(*vpm), GFP_KERNEL); if (!vpm) return NULL; /* Init our vpmadt032 struct */ memcpy(&vpm->options, options, sizeof(*options)); spin_lock_init(&vpm->list_lock); spin_lock_init(&vpm->change_list_lock); INIT_LIST_HEAD(&vpm->change_list); INIT_LIST_HEAD(&vpm->pending_cmds); INIT_LIST_HEAD(&vpm->active_cmds); sema_init(&vpm->sem, 1); vpm->curpage = 0x80; vpm->dspid = -1; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&vpm->work, vpmadt032_bh, vpm); #else INIT_WORK(&vpm->work, vpmadt032_bh); #endif /* Do not use the global workqueue for processing these events. Some of * the operations can take 100s of ms, most of that time spent sleeping. * On single CPU systems, this unduly serializes operations accross * multiple vpmadt032 instances. */ vpm->wq = create_singlethread_workqueue("vpmadt032"); if (!vpm->wq) { kfree(vpm); return NULL; } /* Place this structure in the ifaces array so that the DspId from the * Gpak Library can be used to locate it. */ spin_lock(&ifacelock); for (i=0; idspid = i; break; } } spin_unlock(&ifacelock); if (-1 == vpm->dspid) { kfree(vpm); dev_notice(&vpm->vb->pdev->dev, "Unable to initialize another vpmadt032 modules\n"); vpm = NULL; } return vpm; } EXPORT_SYMBOL(vpmadt032_alloc); int vpmadt032_reset(struct vpmadt032 *vpm) { int res; gpakPingDspStat_t pingstatus; u16 version; unsigned long stoptime; struct device *const dev = &vpm->vb->pdev->dev; might_sleep(); set_bit(VPM150M_HPIRESET, &vpm->control); msleep(2000); /* It should never take longer than 5 seconds. */ stoptime = jiffies + 3*HZ; while (test_bit(VPM150M_HPIRESET, &vpm->control) && time_before(jiffies, stoptime)) msleep(1); if (time_after(jiffies, stoptime)) { dev_dbg(dev, "Detected failure to clear HPIRESET.\n"); return -EIO; } /* Set us up to page 0 */ vpmadt032_setpage(vpm, 0); res = vpmadtreg_loadfirmware(vpm->vb); if (res) { dev_err(dev, "Failed to load VPMADT032 firmware.\n"); return res; } vpm->curpage = -1; stoptime = jiffies + 3*HZ; set_bit(VPM150M_SWRESET, &vpm->control); while (test_bit(VPM150M_SWRESET, &vpm->control) && time_before(jiffies, stoptime)) msleep(1); if (time_after(jiffies, stoptime)) { dev_dbg(dev, "Detected failure to clear SWRESET.\n"); return -EIO; } /* Set us up to page 0 */ pingstatus = gpakPingDsp(vpm->dspid, &version); if (!pingstatus) { vpm_info(vpm, "VPM present and operational " "(Firmware version %x)\n", version); vpm->version = version; res = 0; } else { res = -EIO; } return res; } EXPORT_SYMBOL(vpmadt032_reset); /** * vpmadt032_test - Check if there is a VPMADT032 present on voicebus device. * @vpm: Allocated with vpmadt032_alloc previously. * @vb: Voicebus structure to test on. * * Returns 0 if there is a device, otherwise -ENODEV. * */ int vpmadt032_test(struct vpmadt032 *vpm, struct voicebus *vb) { u8 reg; int i, x; struct device *dev = &vb->pdev->dev; vpm->vb = vb; if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) dev_info(dev, "VPMADT032 Testing page access: "); for (i = 0; i < 0xf; i++) { for (x = 0; x < 3; x++) { vpmadt032_setpage(vpm, i); reg = vpmadt032_getpage(vpm); if (reg != i) { if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) { dev_err(dev, "Failed: Sent %x != %x " \ "VPMADT032 Failed HI page " \ "test\n", i, reg); } return -ENODEV; } } } if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) dev_info(dev, "Passed\n"); return 0; } EXPORT_SYMBOL(vpmadt032_test); /** * vpmadt032_init - Initialize and load VPMADT032 firmware. * @vpm: Allocated with vpmadt032_alloc previously. * * Returns 0 on success. This must be called after vpmadt032_test already * checked if there appears to be a VPMADT032 installed on the board. * */ int vpmadt032_init(struct vpmadt032 *vpm) { int i; u16 reg; int res = -EFAULT; unsigned long stoptime; struct device *dev; gpakPingDspStat_t pingstatus; BUG_ON(!vpm->setchanconfig_from_state); BUG_ON(!vpm->wq); BUG_ON(!vpm->vb); might_sleep(); dev = &vpm->vb->pdev->dev; stoptime = jiffies + 3*HZ; set_bit(VPM150M_HPIRESET, &vpm->control); while (test_bit(VPM150M_HPIRESET, &vpm->control) && time_before(jiffies, stoptime)) msleep(1); if (time_after(jiffies, stoptime)) { dev_dbg(dev, "Detected failure to clear HPIRESET.\n"); res = -EIO; goto failed_exit; } msleep(250); /* Set us up to page 0 */ vpmadt032_setpage(vpm, 0); if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) dev_info(&vpm->vb->pdev->dev, "VPMADT032 now doing address test: "); for (i = 0; i < 16; i++) { int x; for (x = 0; x < 2; x++) { vpmadt032_setreg(vpm, 0x1000, i); vpmadt032_getreg(vpm, 0x1000, ®); if (reg != i) { printk(KERN_CONT "VPMADT032 Failed address test\n"); res = -EIO; } } } if (vpm->options.debug & DEBUG_VPMADT032_ECHOCAN) printk(KERN_CONT "Passed\n"); stoptime = jiffies + 3*HZ; set_bit(VPM150M_HPIRESET, &vpm->control); while (test_bit(VPM150M_HPIRESET, &vpm->control) && time_before(jiffies, stoptime)) msleep(1); if (time_after(jiffies, stoptime)) { dev_dbg(dev, "Detected failure to clear SWRESET.\n"); res = -EIO; goto failed_exit; } res = vpmadtreg_loadfirmware(vpm->vb); if (res) { dev_info(&vpm->vb->pdev->dev, "Failed to load the firmware.\n"); return res; } vpm->curpage = -1; dev_info(&vpm->vb->pdev->dev, "Booting VPMADT032\n"); stoptime = jiffies + 3*HZ; set_bit(VPM150M_SWRESET, &vpm->control); while (test_bit(VPM150M_SWRESET, &vpm->control) && time_before(jiffies, stoptime)) msleep(1); if (time_after(jiffies, stoptime)) { dev_dbg(dev, "Detected failure to clear SWRESET.\n"); res = -EIO; goto failed_exit; } pingstatus = gpakPingDsp(vpm->dspid, &vpm->version); if (!pingstatus) { dev_info(&vpm->vb->pdev->dev, "VPM present and operational " "(Firmware version %x)\n", vpm->version); } else { dev_notice(&vpm->vb->pdev->dev, "VPMADT032 Failed! Unable to ping the DSP (%d)!\n", pingstatus); res = -EIO; goto failed_exit; } return 0; failed_exit: return res; } EXPORT_SYMBOL(vpmadt032_init); void vpmadt032_get_default_parameters(struct GpakEcanParms *p) { memset(p, 0, sizeof(*p)); p->EcanTapLength = 1024; p->EcanNlpType = DEFAULT_NLPTYPE; p->EcanAdaptEnable = 1; #ifdef CONFIG_DAHDI_NO_ECHOCAN_DISABLE p->EcanG165DetEnable = 0; #else p->EcanG165DetEnable = 1; #endif p->EcanDblTalkThresh = 6; p->EcanMaxDoubleTalkThres = 40; p->EcanNlpThreshold = DEFAULT_NLPTHRESH; p->EcanNlpConv = 18; p->EcanNlpUnConv = 12; p->EcanNlpMaxSuppress = DEFAULT_NLPMAXSUPP; p->EcanCngThreshold = 43; p->EcanAdaptLimit = 25; p->EcanCrossCorrLimit = 15; p->EcanNumFirSegments = 3; p->EcanFirSegmentLen = 48; p->EcanReconvergenceCheckEnable = 1; p->EcanTandemOperationEnable = 0; p->EcanMixedFourWireMode = 0; p->EcanSaturationLevel = 3; p->EcanNLPSaturationThreshold = 6; } EXPORT_SYMBOL(vpmadt032_get_default_parameters); void vpmadt032_free(struct vpmadt032 *vpm) { unsigned long flags; struct vpmadt032_cmd *cmd; struct change_order *order; LIST_HEAD(local_list); if (!vpm) return; BUG_ON(!vpm->wq); destroy_workqueue(vpm->wq); /* Move all the commands onto the local list protected by the locks */ spin_lock_irqsave(&vpm->list_lock, flags); list_splice(&vpm->pending_cmds, &local_list); list_splice(&vpm->active_cmds, &local_list); spin_unlock_irqrestore(&vpm->list_lock, flags); while (!list_empty(&local_list)) { cmd = list_entry(local_list.next, struct vpmadt032_cmd, node); list_del(&cmd->node); kfree(cmd); } spin_lock(&vpm->change_list_lock); list_splice(&vpm->change_list, &local_list); spin_unlock(&vpm->change_list_lock); while (!list_empty(&local_list)) { order = list_entry(local_list.next, struct change_order, node); list_del(&order->node); kfree(order); } BUG_ON(ifaces[vpm->dspid] != vpm); spin_lock(&ifacelock); ifaces[vpm->dspid] = NULL; spin_unlock(&ifacelock); kfree(vpm); } EXPORT_SYMBOL(vpmadt032_free); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadDspMemory - Read DSP memory. * * FUNCTION * This function reads a contiguous block of words from DSP memory starting at * the specified address. * * RETURNS * nothing * */ void gpakReadDspMemory( unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ unsigned int NumWords, /* number of contiguous words to read */ DSP_WORD *pWordValues /* pointer to array of word values variable */ ) { struct vpmadt032 *vpm = find_iface(DspId); int i; int ret; vpmadt032_io_wait(vpm); if ( NumWords < VPM150M_MAX_COMMANDS ) { struct vpmadt032_cmd *cmds[VPM150M_MAX_COMMANDS]; memset(cmds, 0, sizeof(cmds)); vpmadt032_setpage(vpm, DspAddress >> 16); DspAddress &= 0xffff; for (i=0; i < NumWords; ++i) { if (!(cmds[i] = vpmadt032_getreg_full_async(vpm,0,DspAddress+i))) { return; } } for (i=NumWords-1; i >=0; --i) { ret = vpmadt032_getreg_full_return(vpm,0,DspAddress+i,&pWordValues[i], cmds[i]); if (0 != ret) { return; } } } else { for (i=0; ivb->pdev->dev, "Writing %d words to memory\n", NumWords); if (vpm) { for (i = 0; i < NumWords; ++i) { vpmadt032_setreg(vpm, DspAddress + i, pWordValues[i]); } #if 0 for (i = 0; i < NumWords; i++) { if (wctdm_vpmadt032_getreg(wc, DspAddress + i) != pWordValues[i]) { dev_notice(&vpm->vb->pdev->dev, "Error in write. Address %x is not %x\n", DspAddress + i, pWordValues[i]); } } #endif } return; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakHostDelay - Delay for a fixed time interval. * * FUNCTION * This function delays for a fixed time interval before returning. The time * interval is the Host Port Interface sampling period when polling a DSP for * replies to command messages. * * RETURNS * nothing * */ void gpakHostDelay(void) { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakLockAccess - Lock access to the specified DSP. * * FUNCTION * This function aquires exclusive access to the specified DSP. * * RETURNS * nothing * */ void gpakLockAccess(unsigned short DspId) { struct vpmadt032 *vpm; vpm = find_iface(DspId); if (!vpm) return; down(&vpm->sem); return; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakUnlockAccess - Unlock access to the specified DSP. * * FUNCTION * This function releases exclusive access to the specified DSP. * * RETURNS * nothing * */ void gpakUnlockAccess(unsigned short DspId) { struct vpmadt032 *vpm; vpm = find_iface(DspId); if (vpm) { up(&vpm->sem); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadFile - Read a block of bytes from a G.PAK Download file. * * FUNCTION * This function reads a contiguous block of bytes from a G.PAK Download file * starting at the current file position. * * RETURNS * The number of bytes read from the file. * -1 indicates an error occurred. * 0 indicates all bytes have been read (end of file) * */ int gpakReadFile( GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ unsigned char *pBuffer, /* pointer to buffer for storing bytes */ unsigned int NumBytes /* number of bytes to read */ ) { /* The firmware is loaded into the part by a closed-source firmware * loader, and therefore this function should never be called. */ WARN_ON(1); return -1; } dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/GpakApi.c0000644000175000017500000017540611424046571022056 0ustar tzafrirtzafrir/* * Copyright (c) 2005, Adaptive Digital Technologies, Inc. * * File Name: GpakApi.c * * Description: * This file contains user API functions to communicate with DSPs executing * G.PAK software. The file is integrated into the host processor connected * to C55X G.PAK DSPs via a Host Port Interface. * * Version: 1.0 * * Revision History: * 06/15/05 - Initial release. * 11/15/2006 - 24 TDM-TDM Channels EC release * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include "GpakHpi.h" #include "GpakCust.h" #include "GpakApi.h" #include "gpakenum.h" /* DSP to Host interface block offsets. */ #define REPLY_MSG_PNTR_OFFSET 0 /* I/F blk offset to Reply Msg Pointer */ #define CMD_MSG_PNTR_OFFSET 2 /* I/F blk offset to Command Msg Pointer */ #define EVENT_MSG_PNTR_OFFSET 4 /* I/F blk offset to Event Msg Pointer */ #define PKT_BUFR_MEM_OFFSET 6 /* I/F blk offset to Packet Buffer memory */ #define DSP_STATUS_OFFSET 8 /* I/F blk offset to DSP Status */ #define VERSION_ID_OFFSET 9 /* I/F blk offset to G.PAK Version Id */ #define MAX_CMD_MSG_LEN_OFFSET 10 /* I/F blk offset to Max Cmd Msg Length */ #define CMD_MSG_LEN_OFFSET 11 /* I/F blk offset to Command Msg Length */ #define REPLY_MSG_LEN_OFFSET 12 /* I/F blk offset to Reply Msg Length */ #define NUM_CHANNELS_OFFSET 13 /* I/F blk offset to Num Built Channels */ #define NUM_PKT_CHANNELS_OFFSET 14 /* I/F blk offset to Num Pkt Channels */ #define NUM_CONFERENCES_OFFSET 15 /* I/F blk offset to Num Conferences */ //#define CPU_USAGE_OFFSET_1MS 16 /* I/F blk offset to CPU Usage statistics */ #define CPU_USAGE_OFFSET 18 /* I/F blk offset to CPU Usage statistics */ //#define CPU_USAGE_OFFSET_10MS 20 /* I/F blk offset to CPU Usage statistics */ #define FRAMING_STATS_OFFSET 22 /* I/F blk offset to Framing statistics */ //#define GPAK_RELEASE_Rate rate10ms // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Macro to reconstruct a 32-bit value from two 16-bit values. // Parameter p32: 32-bit-wide destination // Parameter p16: 16-bit-wide source array of length 2 words #define RECONSTRUCT_LONGWORD(p32, p16) p32 = (DSP_ADDRESS)p16[0]<<16; \ p32 |= (unsigned long)p16[1] // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = /* DSP Status value definitions. */ #define DSP_INIT_STATUS 0x5555 /* DSP Initialized status value */ #define HOST_INIT_STATUS 0xAAAA /* Host Initialized status value */ /* Circular packet buffer information structure offsets. */ #define CB_BUFR_BASE 0 /* pointer to base of circular buffer */ #define CB_BUFR_SIZE 2 /* size of buffer (words) */ #define CB_BUFR_PUT_INDEX 3 /* offset in buffer for next write */ #define CB_BUFR_TAKE_INDEX 4 /* offset in buffer for next read */ #define CIRC_BUFFER_INFO_STRUCT_SIZE 6 /* Miscellaneous definitions. */ #define MSG_BUFFER_SIZE 100 /* size (words) of Host msg buffer */ #define WORD_BUFFER_SIZE 84 /* size of DSP Word buffer (words) */ #ifdef __TMS320C55XX__ // debug sections if not on host #pragma DATA_SECTION(pDspIfBlk,"GPAKAPIDEBUG_SECT") #pragma DATA_SECTION(MaxCmdMsgLen,"GPAKAPIDEBUG_SECT") #pragma DATA_SECTION(MaxChannels,"GPAKAPIDEBUG_SECT") #pragma DATA_SECTION(DlByteBufr,"GPAKAPIDEBUG_SECT") #pragma DATA_SECTION(DlWordBufr,"GPAKAPIDEBUG_SECT") #pragma DATA_SECTION(pEventFifoAddress,"GPAKAPIDEBUG_SECT") #endif /* Host variables related to Host to DSP interface. */ static DSP_ADDRESS pDspIfBlk[MAX_DSP_CORES]; /* DSP address of I/F block */ static DSP_WORD MaxCmdMsgLen[MAX_DSP_CORES]; /* max Cmd msg length (octets) */ static unsigned short int MaxChannels[MAX_DSP_CORES]; /* max num channels */ //static unsigned short int MaxPktChannels[MAX_DSP_CORES]; /* max num pkt channels */ //static unsigned short int MaxConfs[MAX_DSP_CORES]; /* max num conferences */ //static DSP_ADDRESS pPktInBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt In buffer */ //static DSP_ADDRESS pPktOutBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt Out buffer */ static DSP_ADDRESS pEventFifoAddress[MAX_DSP_CORES]; /* event fifo */ static unsigned char DlByteBufr[DOWNLOAD_BLOCK_SIZE * 2]; /* Dowload byte buf */ static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE]; /* Dowload word buffer */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * CheckDspReset - Check if the DSP was reset. * * FUNCTION * This function determines if the DSP was reset and is ready. If reset * occurred, it reads interface parameters and calculates DSP addresses. * * RETURNS * -1 = DSP is not ready. * 0 = Reset did not occur. * 1 = Reset occurred. * */ static int __CheckDspReset( int DspId /* DSP Identifier (0 to MaxDSPCores-1) */ ) { DSP_ADDRESS IfBlockPntr; /* Interface Block pointer */ DSP_WORD DspStatus; /* DSP Status */ DSP_WORD DspChannels; /* number of DSP channels */ DSP_WORD Temp[2]; /* Read the pointer to the Interface Block. */ gpakReadDspMemory(DspId, DSP_IFBLK_ADDRESS, 2, Temp); RECONSTRUCT_LONGWORD(IfBlockPntr, Temp); /* If the pointer is zero, return with an indication the DSP is not ready. */ if (IfBlockPntr == 0) return (-1); /* Read the DSP's Status. */ gpakReadDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus); /* If status indicates the DSP was reset, read the DSP's interface parameters and calculate DSP addresses. */ if (DspStatus == DSP_INIT_STATUS || ((DspStatus == HOST_INIT_STATUS) && (pDspIfBlk[DspId] == 0))) { /* Save the address of the DSP's Interface Block. */ pDspIfBlk[DspId] = IfBlockPntr; /* Read the DSP's interface parameters. */ gpakReadDspMemory(DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1, &(MaxCmdMsgLen[DspId])); /* read the number of configured DSP channels */ gpakReadDspMemory(DspId, IfBlockPntr + NUM_CHANNELS_OFFSET, 1, &DspChannels); if (DspChannels > MAX_CHANNELS) MaxChannels[DspId] = MAX_CHANNELS; else MaxChannels[DspId] = (unsigned short int) DspChannels; /* read the pointer to the event fifo info struct */ gpakReadDspMemory(DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, Temp); RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp); /* Set the DSP Status to indicate the host recognized the reset. */ DspStatus = HOST_INIT_STATUS; gpakWriteDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus); /* Return with an indication that a reset occurred. */ return (1); } /* If status doesn't indicate the host recognized a reset, return with an indication the DSP is not ready. */ if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0)) return (-1); /* Return with an indication that a reset did not occur. */ return (0); } static int CheckDspReset( int DspId /* DSP Identifier (0 to MaxDSPCores-1) */ ) { int ret; int retries = 20; while (--retries) { ret = __CheckDspReset(DspId); if (-1 != ret) return ret; msleep(5); } return ret; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * WriteDspCmdMessage - Write a Host Command/Request message to DSP. * * FUNCTION * This function writes a Host Command/Request message into DSP memory and * informs the DSP of the presence of the message. * * RETURNS * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) * 0 = Temporarily unable to write message (previous Cmd Msg busy) * 1 = Message written successfully * */ static int WriteDspCmdMessage( int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ DSP_WORD *pMessage, /* pointer to Command message */ DSP_WORD MsgLength /* length of message (octets) */ ) { DSP_WORD CmdMsgLength; /* current Cmd message length */ DSP_WORD Temp[2]; DSP_ADDRESS BufferPointer; /* message buffer pointer */ /* Check if the DSP was reset and is ready. */ if (CheckDspReset(DspId) == -1) return (-1); /* Make sure the message length is valid. */ if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId])) return (-1); /* Make sure a previous Command message is not in use by the DSP. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, &CmdMsgLength); if (CmdMsgLength != 0) return (0); /* Purge any previous Reply message that wasn't read. */ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, &CmdMsgLength); /* Copy the Command message into DSP memory. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp); RECONSTRUCT_LONGWORD(BufferPointer, Temp); gpakWriteDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); /* Store the message length in DSP's Command message length (flags DSP that a Command message is ready). */ CmdMsgLength = MsgLength; gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, &CmdMsgLength); /* Return with an indication the message was written. */ return (1); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * ReadDspReplyMessage - Read a DSP Reply message from DSP. * * FUNCTION * This function reads a DSP Reply message from DSP memory. * * RETURNS * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) * 0 = No message available (DSP Reply message empty) * 1 = Message read successfully (message and length stored in variables) * */ static int ReadDspReplyMessage( int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ DSP_WORD *pMessage, /* pointer to Reply message buffer */ DSP_WORD *pMsgLength /* pointer to msg length var (octets) */ ) { DSP_WORD MsgLength; /* message length */ DSP_ADDRESS BufferPointer; /* message buffer pointer */ DSP_WORD Temp[2]; /* Check if the DSP was reset and is ready. */ if (CheckDspReset(DspId) == -1) return (-1); /* Check if a Reply message is ready. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, &MsgLength); if (MsgLength == 0) return (0); /* Make sure the message length is valid. */ if (MsgLength > *pMsgLength) return (-1); /* Copy the Reply message from DSP memory. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp); RECONSTRUCT_LONGWORD(BufferPointer, Temp); gpakReadDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); /* Store the message length in the message length variable. */ *pMsgLength = MsgLength; /* Indicate a Reply message is not ready. */ MsgLength = 0; gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, &MsgLength); /* Return with an indication the message was read. */ return (1); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * ReadCircBuffer - Read from a DSP circular buffer. * * FUNCTION * This function reads a block of words from a DSP circular buffer. The Take * address is incremented by the number of words read adjusting for buffer * wrap. * * RETURNS * nothing * */ static void ReadCircBuffer( int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */ DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */ DSP_ADDRESS *TakeAddress, /* pointer to address in buffer for read */ DSP_WORD *pWordBuffer, /* pointer to buffer for words read */ DSP_WORD NumWords /* number of words to read */ ) { DSP_WORD WordsTillEnd; /* number of words until end of buffer */ /* Determine the number of words from the start address until the end of the buffer. */ WordsTillEnd = BufrLastAddress - *TakeAddress + 1; /* If a buffer wrap will occur, read the first part at the end of the buffer followed by the second part at the beginning of the buffer. */ if (NumWords > WordsTillEnd) { gpakReadDspMemory(DspId, *TakeAddress, WordsTillEnd, pWordBuffer); gpakReadDspMemory(DspId, BufrBaseAddress, NumWords - WordsTillEnd, &(pWordBuffer[WordsTillEnd])); *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd; } /* If a buffer wrap will not occur, read all words starting at the current take address in the buffer. */ else { gpakReadDspMemory(DspId, *TakeAddress, NumWords, pWordBuffer); if (NumWords == WordsTillEnd) *TakeAddress = BufrBaseAddress; else *TakeAddress = *TakeAddress + NumWords; } return; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * VerifyReply - Verify the reply message is correct for the command sent. * * FUNCTION * This function verifies correct reply message content for the command that * was just sent. * * RETURNS * 0 = Incorrect * 1 = Correct * */ static int VerifyReply( DSP_WORD *pMsgBufr, /* pointer to Reply message buffer */ int CheckType, /* reply check type */ DSP_WORD CheckValue /* reply check value */ ) { /* Verify Channel or Conference Id. */ if (CheckType == 1) { if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue) return (0); } /* Verify Test Mode Id. */ else if (CheckType == 2) { if (pMsgBufr[1] != CheckValue) return (0); } /* Return with an indication of correct reply. */ return (1); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * TransactCmd - Send a command to the DSP and receive it's reply. * * FUNCTION * This function sends the specified command to the DSP and receives the DSP's * reply. * * RETURNS * Length of reply message (0 = Failure) * */ static unsigned int TransactCmd( int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ DSP_WORD *pMsgBufr, /* pointer to Cmd/Reply message buffer */ DSP_WORD CmdLength, /* length of command message (octets) */ DSP_WORD ReplyType, /* required type of reply message */ DSP_WORD ReplyLength, /* required length of reply message (octets) */ int ReplyCheckType, /* reply check type */ DSP_WORD ReplyCheckValue /* reply check value */ ) { int FuncStatus; /* function status */ int LoopCount; /* wait loop counter */ DSP_WORD RcvReplyLength; /* received Reply message length */ DSP_WORD RcvReplyType; /* received Reply message type code */ DSP_WORD RetValue; /* return value */ /* Default the return value to indicate a failure. */ RetValue = 0; /* Lock access to the DSP. */ gpakLockAccess(DspId); /* Attempt to write the command message to the DSP. */ LoopCount = 0; while ((FuncStatus = WriteDspCmdMessage(DspId, pMsgBufr, CmdLength)) != 1) { if (FuncStatus == -1) break; if (++LoopCount > MAX_WAIT_LOOPS) break; gpakHostDelay(); } /* Attempt to read the reply message from the DSP if the command message was sent successfully. */ if (FuncStatus == 1) { for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++) { RcvReplyLength = MSG_BUFFER_SIZE * 2; FuncStatus = ReadDspReplyMessage(DspId, pMsgBufr, &RcvReplyLength); if (FuncStatus == 1) { RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF; if ((RcvReplyLength >= ReplyLength) && (RcvReplyType == ReplyType) && VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue)) { RetValue = RcvReplyLength; break; } else if (RcvReplyType == MSG_NULL_REPLY) break; } else if (FuncStatus == -1) break; gpakHostDelay(); } } /* Unlock access to the DSP. */ gpakUnlockAccess(DspId); /* Return the length of the reply message (0 = failure). */ return (RetValue); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakConfigurePorts - Configure a DSP's serial ports. * * FUNCTION * This function configures a DSP's serial ports. * * RETURNS * Status code indicating success or a specific error. * */ gpakConfigPortStatus_t gpakConfigurePorts( unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ const GpakPortConfig_t *pPortConfig, /* pointer to Port Config info */ GPAK_PortConfigStat_t *pStatus /* pointer to Port Config Status */ ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (CpsInvalidDsp); /* Build the Configure Serial Ports message. */ MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8; MsgBuffer[1] = (DSP_WORD) ((pPortConfig->SlotsSelect1 << 12) | ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) | ((pPortConfig->SecBlockNum1 << 4) & 0x00F0)); MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1; MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1; MsgBuffer[4] = (DSP_WORD) ((pPortConfig->SlotsSelect2 << 12) | ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) | ((pPortConfig->SecBlockNum2 << 4) & 0x00F0)); MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2; MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2; MsgBuffer[7] = (DSP_WORD) ((pPortConfig->SlotsSelect3 << 12) | ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) | ((pPortConfig->SecBlockNum3 << 4) & 0x00F0)); MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3; MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3; MsgBuffer[10] = (DSP_WORD) (((pPortConfig->DxDelay1 << 11) & 0x0800) | ((pPortConfig->RxDataDelay1 << 9) & 0x0600) | ((pPortConfig->TxDataDelay1 << 7) & 0x0180) | ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) | ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) | ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) | ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) | ((pPortConfig->CompandingMode1 << 1) & 0x0006) | (pPortConfig->SerialWordSize1 & 0x0001)); MsgBuffer[11] = (DSP_WORD) (((pPortConfig->DxDelay2 << 11) & 0x0800) | ((pPortConfig->RxDataDelay2 << 9) & 0x0600) | ((pPortConfig->TxDataDelay2 << 7) & 0x0180) | ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) | ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) | ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) | ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) | ((pPortConfig->CompandingMode2 << 1) & 0x0006) | (pPortConfig->SerialWordSize2 & 0x0001)); MsgBuffer[12] = (DSP_WORD) (((pPortConfig->DxDelay3 << 11) & 0x0800) | ((pPortConfig->RxDataDelay3 << 9) & 0x0600) | ((pPortConfig->TxDataDelay3 << 7) & 0x0180) | ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) | ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) | ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) | ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) | ((pPortConfig->CompandingMode3 << 1) & 0x0006) | (pPortConfig->SerialWordSize3 & 0x0001)); MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1; MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1; MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1; MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1; MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1; MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1; MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;; MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2; MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;; MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2; MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;; MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2; MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;; MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3; MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;; MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3; MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;; MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3; /* Attempt to send the Configure Serial Ports message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) return (CpsDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF); if (*pStatus == Pc_Success) return (CpsSuccess); else return (CpsParmError); } EXPORT_SYMBOL(gpakConfigurePorts); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakConfigureChannel - Configure a DSP's Channel. * * FUNCTION * This function configures a DSP's Channel. * * RETURNS * Status code indicating success or a specific error. * */ gpakConfigChanStatus_t gpakConfigureChannel( unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ GpakChanType ChannelType, /* Channel Type */ GpakChannelConfig_t *pChanConfig, /* pointer to Channel Config info */ GPAK_ChannelConfigStat_t *pStatus /* pointer to Channel Config Status */ ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD MsgLength; /* message length */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (CcsInvalidDsp); /* Make sure the Channel Id is valid. */ if (ChannelId >= MaxChannels[DspId]) return (CcsInvalidChannel); /* Build the Configure Channel message based on the Channel Type. */ switch (ChannelType) { /* PCM to Packet channel type. */ case tdmToTdm: MsgBuffer[2] = (DSP_WORD) ((pChanConfig->PcmInPortA << 8) | (pChanConfig->PcmInSlotA & 0xFF)); MsgBuffer[3] = (DSP_WORD) ((pChanConfig->PcmOutPortA << 8) | (pChanConfig->PcmOutSlotA & 0xFF)); MsgBuffer[4] = (DSP_WORD) ((pChanConfig->PcmInPortB << 8) | (pChanConfig->PcmInSlotB & 0xFF)); MsgBuffer[5] = (DSP_WORD) ((pChanConfig->PcmOutPortB << 8) | (pChanConfig->PcmOutSlotB & 0xFF)); MsgBuffer[6] = (DSP_WORD) ( ((pChanConfig->FaxCngDetB <<11) & 0x0800) | ((pChanConfig->FaxCngDetA <<10) & 0x0400) | ((pChanConfig->MuteToneB << 9) & 0x0200) | ((pChanConfig->MuteToneA << 8) & 0x0100) | ((pChanConfig->FrameRate << 6) & 0x00C0) | ((pChanConfig->ToneTypesB << 5) & 0x0020) | ((pChanConfig->ToneTypesA << 4) & 0x0010) | ((pChanConfig->SoftwareCompand & 3) << 2) | (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1) ); MsgBuffer[7] = (DSP_WORD) pChanConfig->EcanParametersA.EcanTapLength; MsgBuffer[8] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpType; MsgBuffer[9] = (DSP_WORD) pChanConfig->EcanParametersA.EcanAdaptEnable; MsgBuffer[10] = (DSP_WORD) pChanConfig->EcanParametersA.EcanG165DetEnable; MsgBuffer[11] = (DSP_WORD) pChanConfig->EcanParametersA.EcanDblTalkThresh; MsgBuffer[12] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpThreshold; MsgBuffer[13] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpConv; MsgBuffer[14] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpUnConv; MsgBuffer[15] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpMaxSuppress; MsgBuffer[16] = (DSP_WORD) pChanConfig->EcanParametersA.EcanCngThreshold; MsgBuffer[17] = (DSP_WORD) pChanConfig->EcanParametersA.EcanAdaptLimit; MsgBuffer[18] = (DSP_WORD) pChanConfig->EcanParametersA.EcanCrossCorrLimit; MsgBuffer[19] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNumFirSegments; MsgBuffer[20] = (DSP_WORD) pChanConfig->EcanParametersA.EcanFirSegmentLen; MsgBuffer[21] = (DSP_WORD) pChanConfig->EcanParametersB.EcanTapLength; MsgBuffer[22] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpType; MsgBuffer[23] = (DSP_WORD) pChanConfig->EcanParametersB.EcanAdaptEnable; MsgBuffer[24] = (DSP_WORD) pChanConfig->EcanParametersB.EcanG165DetEnable; MsgBuffer[25] = (DSP_WORD) pChanConfig->EcanParametersB.EcanDblTalkThresh; MsgBuffer[26] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpThreshold; MsgBuffer[27] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpConv; MsgBuffer[28] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpUnConv; MsgBuffer[29] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpMaxSuppress; MsgBuffer[30] = (DSP_WORD) pChanConfig->EcanParametersB.EcanCngThreshold; MsgBuffer[31] = (DSP_WORD) pChanConfig->EcanParametersB.EcanAdaptLimit; MsgBuffer[32] = (DSP_WORD) pChanConfig->EcanParametersB.EcanCrossCorrLimit; MsgBuffer[33] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNumFirSegments; MsgBuffer[34] = (DSP_WORD) pChanConfig->EcanParametersB.EcanFirSegmentLen; MsgBuffer[35] = (DSP_WORD) ( ((pChanConfig->EcanParametersB.EcanReconvergenceCheckEnable <<5) & 0x20) | ((pChanConfig->EcanParametersA.EcanReconvergenceCheckEnable <<4) & 0x10) | ((pChanConfig->EcanParametersB.EcanTandemOperationEnable <<3) & 0x8) | ((pChanConfig->EcanParametersA.EcanTandemOperationEnable <<2) & 0x4) | ((pChanConfig->EcanParametersB.EcanMixedFourWireMode << 1) & 0x2) | (pChanConfig->EcanParametersA.EcanMixedFourWireMode & 1) ); MsgBuffer[36] = (DSP_WORD) pChanConfig->EcanParametersA.EcanMaxDoubleTalkThres; MsgBuffer[37] = (DSP_WORD) pChanConfig->EcanParametersB.EcanMaxDoubleTalkThres; MsgBuffer[38] = (DSP_WORD) pChanConfig->EcanParametersA.EcanSaturationLevel; MsgBuffer[39] = (DSP_WORD) pChanConfig->EcanParametersB.EcanSaturationLevel; MsgBuffer[40] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNLPSaturationThreshold; MsgBuffer[41] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNLPSaturationThreshold; MsgLength = 84; /* byte number == 42*2 */ break; /* PCM to Packet channel type. */ case tdmToTdmDebug: MsgBuffer[2] = (DSP_WORD) ((pChanConfig->PcmInPortA << 8) | (pChanConfig->PcmInSlotA & 0xFF)); MsgBuffer[3] = (DSP_WORD) ((pChanConfig->PcmOutPortA << 8) | (pChanConfig->PcmOutSlotA & 0xFF)); MsgBuffer[4] = (DSP_WORD) ((pChanConfig->PcmInPortB << 8) | (pChanConfig->PcmInSlotB & 0xFF)); MsgBuffer[5] = (DSP_WORD) ((pChanConfig->PcmOutPortB << 8) | (pChanConfig->PcmOutSlotB & 0xFF)); MsgBuffer[6] = (DSP_WORD) ( ((pChanConfig->FaxCngDetB << 11) & 0x0800) | ((pChanConfig->FaxCngDetA << 10) & 0x0400) | ((pChanConfig->MuteToneB << 9) & 0x0200) | ((pChanConfig->MuteToneA << 8) & 0x0100) | ((pChanConfig->FrameRate << 6) & 0x00C0) | ((pChanConfig->ToneTypesB << 5) & 0x0020) | ((pChanConfig->ToneTypesA << 4) & 0x0010) | ((pChanConfig->SoftwareCompand & 3) << 2) | (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1) ); MsgBuffer[7] = (DSP_WORD) pChanConfig->EcanParametersA.EcanTapLength; MsgBuffer[8] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpType; MsgBuffer[9] = (DSP_WORD) pChanConfig->EcanParametersA.EcanAdaptEnable; MsgBuffer[10] = (DSP_WORD) pChanConfig->EcanParametersA.EcanG165DetEnable; MsgBuffer[11] = (DSP_WORD) pChanConfig->EcanParametersA.EcanDblTalkThresh; MsgBuffer[12] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpThreshold; MsgBuffer[13] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpConv; MsgBuffer[14] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpUnConv; MsgBuffer[15] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNlpMaxSuppress; MsgBuffer[16] = (DSP_WORD) pChanConfig->EcanParametersA.EcanCngThreshold; MsgBuffer[17] = (DSP_WORD) pChanConfig->EcanParametersA.EcanAdaptLimit; MsgBuffer[18] = (DSP_WORD) pChanConfig->EcanParametersA.EcanCrossCorrLimit; MsgBuffer[19] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNumFirSegments; MsgBuffer[20] = (DSP_WORD) pChanConfig->EcanParametersA.EcanFirSegmentLen; MsgBuffer[21] = (DSP_WORD) pChanConfig->EcanParametersB.EcanTapLength; MsgBuffer[22] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpType; MsgBuffer[23] = (DSP_WORD) pChanConfig->EcanParametersB.EcanAdaptEnable; MsgBuffer[24] = (DSP_WORD) pChanConfig->EcanParametersB.EcanG165DetEnable; MsgBuffer[25] = (DSP_WORD) pChanConfig->EcanParametersB.EcanDblTalkThresh; MsgBuffer[26] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpThreshold; MsgBuffer[27] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpConv; MsgBuffer[28] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpUnConv; MsgBuffer[29] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNlpMaxSuppress; MsgBuffer[30] = (DSP_WORD) pChanConfig->EcanParametersB.EcanCngThreshold; MsgBuffer[31] = (DSP_WORD) pChanConfig->EcanParametersB.EcanAdaptLimit; MsgBuffer[32] = (DSP_WORD) pChanConfig->EcanParametersB.EcanCrossCorrLimit; MsgBuffer[33] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNumFirSegments; MsgBuffer[34] = (DSP_WORD) pChanConfig->EcanParametersB.EcanFirSegmentLen; MsgBuffer[35] = (DSP_WORD) ( ((pChanConfig->EcanParametersB.EcanReconvergenceCheckEnable << 5) & 0x20) | ((pChanConfig->EcanParametersA.EcanReconvergenceCheckEnable << 4) & 0x10) | ((pChanConfig->EcanParametersB.EcanTandemOperationEnable << 3) & 0x8) | ((pChanConfig->EcanParametersA.EcanTandemOperationEnable << 2) & 0x4) | ((pChanConfig->EcanParametersB.EcanMixedFourWireMode << 1) & 0x2) | (pChanConfig->EcanParametersA.EcanMixedFourWireMode & 1) ); MsgBuffer[36] = (DSP_WORD) pChanConfig->EcanParametersA.EcanMaxDoubleTalkThres; MsgBuffer[37] = (DSP_WORD) pChanConfig->EcanParametersB.EcanMaxDoubleTalkThres; MsgBuffer[38] = (DSP_WORD) pChanConfig->EcanParametersA.EcanSaturationLevel; MsgBuffer[39] = (DSP_WORD) pChanConfig->EcanParametersB.EcanSaturationLevel; MsgBuffer[40] = (DSP_WORD) pChanConfig->EcanParametersA.EcanNLPSaturationThreshold; MsgBuffer[41] = (DSP_WORD) pChanConfig->EcanParametersB.EcanNLPSaturationThreshold; MsgBuffer[42] = (DSP_WORD) pChanConfig->ChannelId_tobe_Debug; MsgLength = 86; /* byte number == 43*2 */ break; /* Unknown (invalid) channel type. */ default: *pStatus = Cc_InvalidChannelType; return (CcsParmError); } MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8; MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF)); /* Attempt to send the Configure Channel message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1, (DSP_WORD) ChannelId)) return (CcsDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF); if (*pStatus == Cc_Success) return (CcsSuccess); else return (CcsParmError); } EXPORT_SYMBOL(gpakConfigureChannel); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakTearDownChannel - Tear Down a DSP's Channel. * * FUNCTION * This function tears down a DSP's Channel. * * RETURNS * Status code indicating success or a specific error. * */ gpakTearDownStatus_t gpakTearDownChannel( unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ GPAK_TearDownChanStat_t *pStatus /* pointer to Tear Down Status */ ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (TdsInvalidDsp); /* Make sure the Channel Id is valid. */ if (ChannelId >= MaxChannels[DspId]) return (TdsInvalidChannel); /* Build the Tear Down Channel message. */ MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8; MsgBuffer[1] = (DSP_WORD) (ChannelId << 8); /* Attempt to send the Tear Down Channel message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1, (DSP_WORD) ChannelId)) return (TdsDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF); if (*pStatus == Td_Success) return (TdsSuccess); else return (TdsError); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakAlgControl - Control an Algorithm. * * FUNCTION * This function controls an Algorithm * * RETURNS * Status code indicating success or a specific error. * */ gpakAlgControlStat_t gpakAlgControl( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GpakAlgCtrl_t ControlCode, // algorithm control code GPAK_AlgControlStat_t *pStatus // pointer to return status ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (AcInvalidDsp); /* Make sure the Channel Id is valid. */ if (ChannelId >= MaxChannels[DspId]) return (AcInvalidChannel); MsgBuffer[0] = MSG_ALG_CONTROL << 8; MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF)); /* Attempt to send the Tear Down Channel message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1, (DSP_WORD) ChannelId)) return (AcDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF); if (*pStatus == Ac_Success) return (AcSuccess); else return (AcParmError); } EXPORT_SYMBOL(gpakAlgControl); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadEventFIFOMessage - read from the event fifo * * FUNCTION * This function reads a single event from the event fifo if one is available * * RETURNS * Status code indicating success or a specific error. * * Notes: This function should be called in a loop until the return status * indicates that the fifo is empty. * * If the event code equals "EventLoopbackTeardownComplete", then the * contents of *pChannelId hold the coderBlockId that was assigned to * the loopback coder that was torn down. */ gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage( unsigned short int DspId, // DSP identifier unsigned short int *pChannelId, // pointer to channel identifier GpakAsyncEventCode_t *pEventCode, // pointer to Event Code GpakAsyncEventData_t *pEventData // pointer to Event Data Struct ) { DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */ GpakAsyncEventCode_t EventCode; /* DSP's event code */ DSP_WORD EventDataLength; /* Length of event to read */ DSP_WORD ChannelId; /* DSP's channel Id */ DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */ DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */ DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */ DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */ DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */ DSP_WORD PutIndex; /* event fifo put index */ DSP_WORD TakeIndex; /* event fifo take index */ DSP_WORD WordsReady; /* number words ready for read out of event fifo */ DSP_WORD EventError; /* flag indicating error with event fifo msg */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RefInvalidDsp); /* Lock access to the DSP. */ gpakLockAccess(DspId); /* Check if the DSP was reset and is ready. */ if (CheckDspReset(DspId) == -1) { gpakUnlockAccess(DspId); return (RefDspCommFailure); } /* Check if an event message is ready in the DSP. */ EventInfoAddress = pEventFifoAddress[DspId]; gpakReadDspMemory(DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE, WordBuffer); RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *)&WordBuffer[CB_BUFR_BASE])); BufrSize = WordBuffer[CB_BUFR_SIZE]; PutIndex = WordBuffer[CB_BUFR_PUT_INDEX]; TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX]; if (PutIndex >= TakeIndex) WordsReady = PutIndex - TakeIndex; else WordsReady = PutIndex + BufrSize - TakeIndex; if (WordsReady < 2) { gpakUnlockAccess(DspId); return (RefNoEventAvail); } /* Read the event header from the DSP's Event FIFO. */ TakeAddress = BufrBaseAddress + TakeIndex; BufrLastAddress = BufrBaseAddress + BufrSize - 1; ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, WordBuffer, 2); TakeIndex += 2; if (TakeIndex >= BufrSize) TakeIndex -= BufrSize; ChannelId = (WordBuffer[0] >> 8) & 0xFF; EventCode = (GpakAsyncEventCode_t)(WordBuffer[0] & 0xFF); EventDataLength = WordBuffer[1]; EventError = 0; switch (EventCode) { case EventToneDetect: if (EventDataLength > WORD_BUFFER_SIZE) { gpakUnlockAccess(DspId); return (RefInvalidEvent); } ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, WordBuffer, EventDataLength); pEventData->toneEvent.ToneCode = (GpakToneCodes_t) (WordBuffer[0] & 0xFF); pEventData->toneEvent.ToneDuration = WordBuffer[1]; pEventData->toneEvent.Direction = WordBuffer[2]; pEventData->toneEvent.DebugToneStatus = WordBuffer[3]; TakeIndex += EventDataLength; if (TakeIndex >= BufrSize) TakeIndex -= BufrSize; if (EventDataLength != 4) EventError = 1; break; default: EventError = 1; break; }; /* Update the Take index in the DSP's Packet Out buffer information. */ gpakWriteDspMemory(DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1, &TakeIndex); /* Unlock access to the DSP. */ gpakUnlockAccess(DspId); if (EventError) return(RefInvalidEvent); *pChannelId = ChannelId; *pEventCode = EventCode; return(RefEventAvail); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakPingDsp - ping the DSP to see if it's alive * * FUNCTION * This function checks if the DSP is still communicating with the host * and returns the DSP SW version * * RETURNS * Status code indicating success or a specific error. */ gpakPingDspStat_t gpakPingDsp( unsigned short int DspId, // DSP identifier unsigned short int *pDspSwVersion // DSP software version ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (PngInvalidDsp); /* send value of 1, DSP increments it */ MsgBuffer[0] = (MSG_PING << 8); /* Attempt to send the ping message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0)) return (PngDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) { *pDspSwVersion = MsgBuffer[2]; return (PngSuccess); } else return (PngDspCommFailure); } EXPORT_SYMBOL(gpakPingDsp); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakSerialTxFixedValue - transmit a fixed value on a timeslot * * FUNCTION * This function controls transmission of a fixed value out onto a serial * port's timeslot. * * RETURNS * Status code indicating success or a specific error. */ gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue( unsigned short int DspId, // DSP identifier unsigned short int ChannelId, // channel identifier GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id unsigned short int PcmOutSlot, // PCM Output Time Slot unsigned short int Value, // 16-bit value GpakActivation State // activation state ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (TfvInvalidDsp); /* Make sure the Channel Id is valid. */ if (ChannelId >= MaxChannels[DspId]) return (TfvInvalidChannel); /* Build the message. */ MsgBuffer[0] = MSG_SERIAL_TXVAL << 8; MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF)); MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF)); MsgBuffer[3] = (DSP_WORD) Value; /* Attempt to send the message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4, 1, ChannelId)) return (TfvDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) return (TfvSuccess); else return (TfvDspCommFailure); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakControlTdmLoopBack - control a serial port's loopback state * * FUNCTION * This function enables/disables the tdm input to output looback mode on a * serial port * * RETURNS * Status code indicating success or a specific error. */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack( unsigned short int DspId, // DSP identifier GpakSerialPort_t SerialPort, // Serial Port Id GpakActivation LoopBackState // Loopback State ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (ClbInvalidDsp); /* Build the message. */ MsgBuffer[0] = MSG_TDM_LOOPBACK << 8; MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF)); /* Attempt to send the message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0)) return (ClbDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) return (ClbSuccess); else return (ClbDspCommFailure); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadCpuUsage - Read CPU usage statistics from a DSP. * * FUNCTION * This function reads the CPU usage statistics from a DSP's memory. The * average CPU usage in units of .1 percent are obtained for each of the frame * rates. * * RETURNS * Status code indicating success or a specific error. * */ gpakReadCpuUsageStat_t gpakReadCpuUsage( unsigned short int DspId, // Dsp Identifier unsigned short int *pPeakUsage, // pointer to peak usage variable unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second ) { DSP_WORD ReadBuffer[2]; /* DSP read buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RcuInvalidDsp); /* Lock access to the DSP. */ gpakLockAccess(DspId); /* Check if the DSP was reset and is ready. */ if (CheckDspReset(DspId) == -1) return (RcuDspCommFailure); /* Read the CPU Usage statistics from the DSP. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2, ReadBuffer); /* Unlock access to the DSP. */ gpakUnlockAccess(DspId); /* Store the usage statistics in the specified variables. */ *pPrev1SecPeakUsage = ReadBuffer[0]; *pPeakUsage = ReadBuffer[1]; /* Return with an indication the usage staistics were read successfully. */ return (RcuSuccess); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakResetCpuUsageStats - reset the cpu usage statistics * * FUNCTION * This function resets the cpu utilization statistics * * RETURNS * Status code indicating success or a specific error. */ gpakResetCpuUsageStat_t gpakResetCpuUsageStats( unsigned short int DspId // DSP identifier ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RstcInvalidDsp); MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8); /* Attempt to send the message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0)) return (RstcDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) return (RstcSuccess); else return (RstcDspCommFailure); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadFramingStats * * FUNCTION * This function reads a DSP's framing interrupt statistics * * RETURNS * Status code indicating success or a specific error. */ gpakReadFramingStatsStatus_t gpakReadFramingStats( unsigned short int DspId, // DSP identifier unsigned short int *pFramingError1Count, // port 1 Framing error count unsigned short int *pFramingError2Count, // port 2 Framing error count unsigned short int *pFramingError3Count, // port 3 Framing error count unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count unsigned short int *pDmaSlipStatsBuffer // DMA slips count ) { DSP_WORD ReadBuffer[10]; /* DSP read buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RfsInvalidDsp); /* Lock access to the DSP. */ gpakLockAccess(DspId); /* Check if the DSP was reset and is ready. */ if (CheckDspReset(DspId) == -1) return (RfsDspCommFailure); /* Read the framing interrupt statistics from the DSP. */ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10, ReadBuffer); /* Unlock access to the DSP. */ gpakUnlockAccess(DspId); /* Store the framing statistics in the specified variables. */ *pFramingError1Count = ReadBuffer[0]; *pFramingError2Count = ReadBuffer[1]; *pFramingError3Count = ReadBuffer[2]; *pDmaStopErrorCount = ReadBuffer[3]; if (pDmaSlipStatsBuffer != NULL) { /* If users want to get the DMA slips count */ pDmaSlipStatsBuffer[0] = ReadBuffer[4]; pDmaSlipStatsBuffer[1] = ReadBuffer[5]; pDmaSlipStatsBuffer[2] = ReadBuffer[6]; pDmaSlipStatsBuffer[3] = ReadBuffer[7]; pDmaSlipStatsBuffer[4] = ReadBuffer[8]; pDmaSlipStatsBuffer[5] = ReadBuffer[9]; } /* Return with an indication the statistics were read successfully. */ return (RfsSuccess); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakResetFramingStats - reset a DSP's framing interrupt statistics * * FUNCTION * This function resets a DSP's framing interrupt statistics * * RETURNS * Status code indicating success or a specific error. */ gpakResetFramingStatsStatus_t gpakResetFramingStats( unsigned short int DspId // DSP identifier ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RstfInvalidDsp); MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8); /* Attempt to send the message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0)) return (RstfDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) return (RstfSuccess); else return (RstfDspCommFailure); } /* * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. * * FUNCTION * This function reads a DSP's Program and Data memory image from the * specified file and writes the image to the DSP's memory. * * RETURNS * Status code indicating success or a specific error. * */ gpakDownloadStatus_t gpakDownloadDsp( unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ GPAK_FILE_ID FileId /* G.PAK Download File Identifier */ ) { gpakDownloadStatus_t RetStatus; /* function return status */ int NumRead; /* number of file bytes read */ DSP_ADDRESS Address; /* DSP address */ unsigned int WordCount; /* number of words in record */ unsigned int NumWords; /* number of words to read/write */ unsigned int i; /* loop index / counter */ unsigned int j; /* loop index */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (GdlInvalidDsp); /* Lock access to the DSP. */ gpakLockAccess(DspId); RetStatus = GdlSuccess; while (RetStatus == GdlSuccess) { /* Read a record header from the file. */ NumRead = gpakReadFile(FileId, DlByteBufr, 6); if (NumRead == -1) { RetStatus = GdlFileReadError; break; } if (NumRead != 6) { RetStatus = GdlInvalidFile; break; } Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); WordCount = (((unsigned int) DlByteBufr[4]) << 8) | ((unsigned int) DlByteBufr[5]); /* Check for the End Of File record. */ if (DlByteBufr[0] == 0xFF) break; /* Verify the record is for a valid memory type. */ if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01)) { RetStatus = GdlInvalidFile; break; } /* Read a block of words at a time from the file and write to the DSP's memory .*/ while (WordCount != 0) { if (WordCount < DOWNLOAD_BLOCK_SIZE) NumWords = WordCount; else NumWords = DOWNLOAD_BLOCK_SIZE; WordCount -= NumWords; NumRead = gpakReadFile(FileId, DlByteBufr, NumWords * 2); if (NumRead == -1) { RetStatus = GdlFileReadError; break; } if (NumRead != (NumWords * 2)) { RetStatus = GdlInvalidFile; break; } for (i = 0, j = 0; i < NumWords; i++, j += 2) DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | ((DSP_WORD) DlByteBufr[j + 1]); gpakWriteDspMemory(DspId, Address, NumWords, DlWordBufr); Address += ((DSP_ADDRESS) NumWords); } } /* Unlock access to the DSP. */ gpakUnlockAccess(DspId); /* Return with an indication of success or failure. */ return (RetStatus); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadCpuUsage - Read CPU usage statistics from a DSP. * * FUNCTION * This function reads the memory map register section of DSP memory. * * RETURNS * Status code indicating success or a specific error. * */ gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap( unsigned short int DspId, // Dsp Identifier unsigned short int *pDest, // Buffer on host to hold DSP memory map DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP reply's status */ int i; /* loop index / counter */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RmmInvalidDsp); /* Verify the message buffer is large enough */ if (MSG_BUFFER_SIZE < MemoryLength_Word16 ) return (RmmSizeTooBig); MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8; MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF); MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF); MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16; /* Attempt to send the Read memory section message to the DSP and receive it's reply. */ //need_reply_len; if (!TransactCmd(DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY, (MemoryLength_Word16+2)*2, 0, 0) ) return (RmmInvalidAddress); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus != 0) return (RmmFailure); for (i = 0; i < MemoryLength_Word16; i++) pDest[i] = (short int) MsgBuffer[2 + i]; return (RmmSuccess); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakAccessGPIO - change Direction/read/write the GPIO on DSP * * FUNCTION * This function read/write GPIO and change the GPIO direction * * * RETURNS * Status code indicating success or a specific error. */ gpakAccessGPIOStat_t gpakAccessGPIO( unsigned short int DspId, // DSP identifier GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read unsigned short int *pGPIOValue // DSP software version ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (GPIOInvalidDsp); /* send value of 1, DSP increments it */ MsgBuffer[0] = (MSG_ACCESSGPIO << 8); MsgBuffer[1] = (DSP_WORD) ((gpakControlGPIO << 8) | (*pGPIOValue & 0xFF) ); /* Attempt to send the ping message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ACCESSGPIO_REPLY, 6, 0, 0)) return (GPIODspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) { *pGPIOValue = MsgBuffer[2]; return (GPIOSuccess); } else return (GPIODspCommFailure); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakWriteSystemParms - Write a DSP's System Parameters. * * FUNCTION * This function writes a DSP's System Parameters information. * * Note: * Or-together the desired bit-mask #defines that are listed below. Only * those algorithm parameters whose bit-mask is selected in the UpdateBits * function parameter will be updated. * * RETURNS * Status code indicating success or a specific error. * */ gpakWriteSysParmsStatus_t gpakWriteSystemParms( unsigned short int DspId, // DSP identifier GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */ unsigned short int UpdateBits, /* input: flags indicating which parms to update */ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */ ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ DSP_WORD DspStatus; /* DSP's reply status */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (WspInvalidDsp); /* Build the Write System Parameters message. */ MsgBuffer[0] = MSG_WRITE_SYS_PARMS << 8; if (UpdateBits & DTMF_UPDATE_MASK) { MsgBuffer[1] |= DTMF_UPDATE_MASK; MsgBuffer[8] = (DSP_WORD) pSysParms->MinSigLevel; MsgBuffer[9] = (DSP_WORD) (pSysParms->FreqDeviation & 0xff); if (pSysParms->SNRFlag) MsgBuffer[9] |= (1<<8); } MsgBuffer[10] = (DSP_WORD) 0; if (UpdateBits & DTMF_TWIST_UPDATE_MASK) { MsgBuffer[1] |= DTMF_TWIST_UPDATE_MASK; MsgBuffer[10] |= (DSP_WORD) (pSysParms->DtmfFwdTwist & 0x000f); MsgBuffer[10] |= (DSP_WORD) ((pSysParms->DtmfRevTwist << 4) & 0x00f0); } if (UpdateBits & DTMF_VALID_MASK) { MsgBuffer[1] |= DTMF_VALID_MASK; MsgBuffer[11] = (DSP_WORD) (pSysParms->DtmfValidityMask & 0x00ff); } /* Attempt to send the ping message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 24, MSG_WRITE_SYS_PARMS_REPLY, 6, 0, 0)) return (WspDspCommFailure); /* Return with an indication of success or failure based on the return status in the reply message. */ *pStatus = (GPAK_SysParmsStat_t) (MsgBuffer[2] ); DspStatus = (MsgBuffer[1] & 0xFF); if (DspStatus == 0) return (WspSuccess); else return (WspDspCommFailure); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * gpakReadSystemParms - Read a DSP's System Parameters. * * FUNCTION * This function reads a DSP's System Parameters information. * * RETURNS * Status code indicating success or a specific error. * */ gpakReadSysParmsStatus_t gpakReadSystemParms( unsigned short int DspId, // DSP identifier GpakSystemParms_t *pSysParms /* pointer to System Parms info var */ ) { DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ /* Make sure the DSP Id is valid. */ if (DspId >= MAX_DSP_CORES) return (RspInvalidDsp); /* Build the Read System Parameters message. */ MsgBuffer[0] = MSG_READ_SYS_PARMS << 8; /* Attempt to send the ping message to the DSP and receive it's reply. */ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_READ_SYS_PARMS_REPLY, 22, 0, 0)) return (RspDspCommFailure); /* Extract the System Parameters information from the message. */ pSysParms->DtmfValidityMask = (short int)(MsgBuffer[7]) ; pSysParms->MinSigLevel = (short int)MsgBuffer[8]; pSysParms->SNRFlag = (short int)((MsgBuffer[9]>>8) & 0x1); pSysParms->FreqDeviation = (short int)(MsgBuffer[9] & 0xff); pSysParms->DtmfFwdTwist = (short int)MsgBuffer[10] & 0x000f; pSysParms->DtmfRevTwist = (short int)(MsgBuffer[10] >> 4) & 0x000f; /* Return with an indication that System Parameters info was obtained. */ return (RspSuccess); } dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/gpakErrs.h0000644000175000017500000001450211423153456022312 0ustar tzafrirtzafrir/* * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc. * * File Name: GpakErrs.h * * Description: * This file contains DSP reply status codes used by G.PAK API functions to * indicate specific errors. * * Version: 1.0 * * Revision History: * 10/17/01 - Initial release. * 07/03/02 - Updates for conferencing. * 06/15/04 - Tone type updates. * * This program has been released under the terms of the GPL version 2 by * permission of Adaptive Digital Technologies, Inc. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _GPAKERRS_H /* prevent multiple inclusion */ #define _GPAKERRS_H /* Configure Serial Ports reply status codes. */ typedef enum { Pc_Success = 0, /* serial ports configured successfully */ Pc_ChannelsActive = 1, /* unable to configure while channels active */ Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */ Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */ Pc_NoSlots1 = 4, /* no slots selected for port 1 */ Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */ Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */ Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */ Pc_NoSlots2 = 8, /* no slots selected for port 2 */ Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */ Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */ Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */ Pc_NoSlots3 = 12, /* no slots selected for port 3 */ Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */ } GPAK_PortConfigStat_t; /* Configure Channel reply status codes. */ typedef enum { Cc_Success = 0, /* channel configured successfully */ Cc_InvalidChannelType = 1, /* invalid Channel Type */ Cc_InvalidChannel = 2, /* invalid Channel A Id */ Cc_ChannelActiveA = 3, /* Channel A is currently active */ Cc_InvalidInputPortA = 4, /* invalid Input A Port */ Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */ Cc_BusyInputSlotA = 6, /* busy Input A Slot */ Cc_InvalidOutputPortA = 7, /* invalid Output A Port */ Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */ Cc_BusyOutputSlotA = 9, /* busy Output A Slot */ Cc_InvalidInputPortB = 10, /* invalid Input B Port */ Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */ Cc_BusyInputSlotB = 12, /* busy Input B Slot */ Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */ Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */ Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */ Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */ Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */ Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */ Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */ Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */ Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */ Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */ Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */ Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */ Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */ Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */ Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */ Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */ Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */ Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */ /*Cc_InvalidNumEcsEnabled = 48, */ /* more than 1 Ec enabled on channel */ Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */ Cc_InvalidSoftCompand = 50, /* invalid softCompanding type */ Cc_InvalidMuteToneA = 51, /* invalid MuteToneA set, no detector */ Cc_InvalidMuteToneB = 52, /* invalid MuteToneB set, no detector */ Cc_InsuffFaxCngDetResources = 53, /* insufficient tdm block resources avail. */ Cc_PortDmaNotStarted = 54, /* SerialPort not ready */ Cc_ChannelDebugActive = 55, /* Debug Channel is not active */ Cc_ChannelDebugEnabled = 56 /* Channel already been debugged */ } GPAK_ChannelConfigStat_t; /* Tear Down Channel reply status codes. */ typedef enum { Td_Success = 0, /* channel torn down successfully */ Td_InvalidChannel = 1, /* invalid Channel Id */ Td_ChannelNotActive = 2 /* channel is not active */ } GPAK_TearDownChanStat_t; typedef enum { Ac_Success = 0, /* algorithm control is successfull */ Ac_InvalidChannel = 1, /* invalid channel identifier */ Ac_InvalidCode = 2, /* invalid algorithm control code */ Ac_ECNotEnabled = 3, /* echo canceller was not allocated */ Ac_InvalidSoftComp = 4, /* invalid softcompanding, 'cause serial port not in companding mode */ Ac_InvalidDTMFMuteA = 5, /* A side invalid Mute, since no dtmf detector */ Ac_InvalidDTMFMuteB = 6, /* B side invalid Mute, since no dtmf detector */ Ac_InvalidFaxCngA = 7, /* A side FAXCNG detector not available */ Ac_InvalidFaxCngB = 8, /* B side FAXCNG detector not available */ Ac_InvalidSysConfig = 9 /* No new system parameters (DTMF config) wrriten yet */ } GPAK_AlgControlStat_t; /* Write System Parameters reply status codes. */ typedef enum { Sp_Success = 0, /* System Parameters written successfully */ Sp_BadTwistThresh = 29 /* invalid twist threshold */ } GPAK_SysParmsStat_t; #endif /* prevent multiple inclusion */ dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/vpmoct.h0000644000175000017500000000535111602452654022047 0ustar tzafrirtzafrir/* * VPMOCT Driver. * * Written by Russ Meyerriecks * * Copyright (C) 2010-2011 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _VPMOCT_H #define _VPMOCT_H #include #include #include #include "dahdi/kernel.h" #include #define VPMOCT_FIRM_HEADER_LEN 32 #define VPMOCT_BOOT_RAM_LEN 128 #define VPMOCT_FLASH_BUF_SECTIONS 4 #define VPMOCT_MAX_CHUNK 7 /* Bootloader commands */ #define VPMOCT_BOOT_FLASH_ERASE 0x01 #define VPMOCT_BOOT_FLASH_COPY 0x02 #define VPMOCT_BOOT_IMAGE_VALIDATE 0x06 #define VPMOCT_BOOT_REBOOT 0x07 #define VPMOCT_BOOT_DECRYPT 0x08 #define VPMOCT_BOOT_FLASHLOAD 0x10 /* Dual use registers */ #define VPMOCT_IDENT 0x00 #define VPMOCT_MAJOR 0x0a #define VPMOCT_MINOR 0x0b #define VPMOCT_SERIAL 0x90 #define VPMOCT_SERIAL_SIZE 32 /* Bootloader registers */ #define VPMOCT_BOOT_ERROR 0x0c #define VPMOCT_BOOT_STATUS 0x10 #define VPMOCT_BOOT_CMD 0x11 #define VPMOCT_BOOT_LEN 0x14 #define VPMOCT_BOOT_ADDRESS1 0x18 #define VPMOCT_BOOT_ADDRESS2 0x1c #define VPMOCT_BOOT_RAM 0x20 enum vpmoct_mode { UNKNOWN = 0, APPLICATION, BOOTLOADER }; struct vpmoct { struct list_head pending_list; struct list_head active_list; spinlock_t list_lock; struct mutex mutex; enum vpmoct_mode mode; struct device *dev; u32 companding; u32 echo; unsigned int preecho_enabled:1; unsigned int echo_update_active:1; unsigned int companding_update_active:1; u8 preecho_timeslot; u8 preecho_buf[8]; u8 major; u8 minor; }; struct vpmoct_cmd { struct list_head node; u8 address; u8 data[VPMOCT_MAX_CHUNK]; u8 command; u8 chunksize; u8 txident; struct completion complete; }; static inline bool is_vpmoct_cmd_read(const struct vpmoct_cmd *cmd) { return (0x60 == (cmd->command & 0xf0)); } struct vpmoct *vpmoct_alloc(void); void vpmoct_free(struct vpmoct *vpm); typedef void (*load_complete_func_t)(struct device *dev, bool operational); int vpmoct_init(struct vpmoct *vpm, load_complete_func_t load_complete); int vpmoct_echocan_create(struct vpmoct *vpm, int channo, int companding); void vpmoct_echocan_free(struct vpmoct *vpm, int channo); int vpmoct_preecho_enable(struct vpmoct *vpm, int channo); int vpmoct_preecho_disable(struct vpmoct *vpm, int channo); #endif dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/Makefile0000644000175000017500000000026011176623226022021 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild endif dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/Kbuild0000644000175000017500000000027311602452645021521 0ustar tzafrirtzafrirobj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VOICEBUS) += dahdi_voicebus.o dahdi_voicebus-objs := voicebus.o GpakCust.o GpakApi.o voicebus_net.o vpmoct.o EXTRA_CFLAGS := -I$(src)/.. -Wno-undef dahdi-linux-2.5.0.1/drivers/dahdi/voicebus/voicebus_net.h0000644000175000017500000000060411341774611023220 0ustar tzafrirtzafrir#ifdef VOICEBUS_NET_DEBUG int vb_net_register(struct voicebus *, const char *); void vb_net_unregister(struct voicebus *); void vb_net_capture_vbb(struct voicebus *, const void *, const int, const u32, const u16); #else #define vb_net_register(a, b) do { ; } while (0) #define vb_net_unregister(a) do { ; } while (0) #define vb_net_capture_vbb(a, b, c, d, e) do { ; } while (0) #endif dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_sec.c0000644000175000017500000002523511500234716022273 0ustar tzafrirtzafrir/* * SpanDSP - a series of DSP components for telephony * * echo.c - An echo cancellor, suitable for electrical and acoustic * cancellation. This code does not currently comply with * any relevant standards (e.g. G.164/5/7/8). One day.... * * Written by Steve Underwood * Various optimizations and improvements by Mark Spencer * * Copyright (C) 2001 Steve Underwood * * Based on a bit from here, a bit from there, eye of toad, * ear of bat, etc - plus, of course, my own 2 cents. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /* TODO: Finish the echo suppressor option, however nasty suppression may be Add an option to reintroduce side tone at -24dB under appropriate conditions. Improve double talk detector (iterative!) */ #include #include #include #include #include #include #include #include static int debug; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk(KERN_DEBUG "%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) #include "arith.h" #ifndef NULL #define NULL 0 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!FALSE) #endif #define USE_SHORTS #define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */ /* Original parameters : #define MIN_TX_POWER_FOR_ADAPTION 256 #define MIN_RX_POWER_FOR_ADAPTION 128 */ #define MIN_TX_POWER_FOR_ADAPTION 256 #define MIN_RX_POWER_FOR_ADAPTION 64 /* Better ones found by Jim #define MIN_TX_POWER_FOR_ADAPTION 128 #define MIN_RX_POWER_FOR_ADAPTION 64 */ static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable); static const char *name = "SEC"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_features my_features = { .NLP_toggle = 1, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, .echocan_NLP_toggle = echocan_NLP_toggle, }; struct ec_pvt { struct dahdi_echocan_state dahdi; int tx_power; int rx_power; int clean_rx_power; int rx_power_threshold; int nonupdate_dwell; int16_t *tx_history; /* Last N tx samples */ int32_t *fir_taps; /* Echo FIR taps */ int16_t *fir_taps_short; /* Echo FIR taps, shorts instead of ints */ int curr_pos; int taps; int tap_mask; int use_nlp; int use_suppressor; int32_t supp_test1; int32_t supp_test2; int32_t supp1; int32_t supp2; int32_t latest_correction; /* Indication of the magnitude of the latest adaption, or a code to indicate why adaption was skipped, for test purposes */ }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct ec_pvt *pvt; size_t size; if (ecp->param_count > 0) { printk(KERN_WARNING "SEC does not support parameters; failing request\n"); return -EINVAL; } size = sizeof(*pvt) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t); pvt = kzalloc(size, GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; pvt->dahdi.features = my_features; pvt->taps = ecp->tap_length; pvt->tap_mask = ecp->tap_length - 1; pvt->tx_history = (int16_t *) (pvt + sizeof(*pvt)); pvt->fir_taps = (int32_t *) (pvt + sizeof(*pvt) + ecp->tap_length * 2 * sizeof(int16_t)); pvt->fir_taps_short = (int16_t *) (pvt + sizeof(*pvt) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 2 * sizeof(int16_t)); pvt->rx_power_threshold = 10000000; pvt->use_suppressor = FALSE; /* Non-linear processor - a fancy way to say "zap small signals, to avoid accumulating noise". */ pvt->use_nlp = TRUE; *ec = &pvt->dahdi; return 0; } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); kfree(pvt); } static inline int16_t sample_update(struct ec_pvt *pvt, int16_t tx, int16_t rx) { int32_t echo_value; int clean_rx; int nsuppr; pvt->tx_history[pvt->curr_pos] = tx; pvt->tx_history[pvt->curr_pos + pvt->taps] = tx; /* Evaluate the echo - i.e. apply the FIR filter */ /* Assume the gain of the FIR does not exceed unity. Exceeding unity would seem like a rather poor thing for an echo cancellor to do :) This means we can compute the result with a total disregard for overflows. 16bits x 16bits -> 31bits, so no overflow can occur in any multiply. While accumulating we may overflow and underflow the 32 bit scale often. However, if the gain does not exceed unity, everything should work itself out, and the final result will be OK, without any saturation logic. */ /* Overflow is very much possible here, and we do nothing about it because of the compute costs */ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems best */ #ifdef USE_SHORTS echo_value = CONVOLVE2(pvt->fir_taps_short, pvt->tx_history + pvt->curr_pos, pvt->taps); #else echo_value = CONVOLVE(pvt->fir_taps, pvt->tx_history + pvt->curr_pos, pvt->taps); #endif echo_value >>= 16; /* And the answer is..... */ clean_rx = rx - echo_value; /* That was the easy part. Now we need to adapt! */ if (pvt->nonupdate_dwell > 0) pvt->nonupdate_dwell--; /* If there is very little being transmitted, any attempt to train is futile. We would either be training on the far end's noise or signal, the channel's own noise, or our noise. Either way, this is hardly good training, so don't do it (avoid trouble). */ /* If the received power is very low, either we are sending very little or we are already well adapted. There is little point in trying to improve the adaption under these circumstanceson, so don't do it (reduce the compute load). */ if (pvt->tx_power > MIN_TX_POWER_FOR_ADAPTION && pvt->rx_power > MIN_RX_POWER_FOR_ADAPTION) { /* This is a really crude piece of decision logic, but it does OK for now. */ if (pvt->tx_power > pvt->rx_power << 1) { /* There is no far-end speech detected */ if (pvt->nonupdate_dwell == 0) { /* ... and we are not in the dwell time from previous speech. */ /* nsuppr = saturate((clean_rx << 16)/pvt->tx_power); */ nsuppr = (clean_rx << 16) / pvt->tx_power; nsuppr >>= 4; if (nsuppr > 512) nsuppr = 512; if (nsuppr < -512) nsuppr = -512; /* Update the FIR taps */ pvt->latest_correction = 0; #ifdef USE_SHORTS UPDATE2(pvt->fir_taps, pvt->fir_taps_short, pvt->tx_history + pvt->curr_pos, nsuppr, pvt->taps); #else UPDATE(pvt->fir_taps, pvt->fir_taps_short, pvt->tx_history + pvt->curr_pos, nsuppr, pvt->taps); #endif } else { pvt->latest_correction = -3; } } else { pvt->nonupdate_dwell = NONUPDATE_DWELL_TIME; pvt->latest_correction = -2; } } else { pvt->nonupdate_dwell = 0; pvt->latest_correction = -1; } /* Calculate short term power levels using very simple single pole IIRs */ /* TODO: Is the nasty modulus approach the fastest, or would a real tx*tx power calculation actually be faster? */ pvt->tx_power += ((abs(tx) - pvt->tx_power) >> 5); pvt->rx_power += ((abs(rx) - pvt->rx_power) >> 5); pvt->clean_rx_power += ((abs(clean_rx) - pvt->clean_rx_power) >> 5); #if defined(XYZZY) if (pvt->use_suppressor) { pvt->supp_test1 += (pvt->tx_history[pvt->curr_pos] - pvt->tx_history[(pvt->curr_pos - 7) & pvt->tap_mask]); pvt->supp_test2 += (pvt->tx_history[(pvt->curr_pos - 24) & pvt->tap_mask] - pvt->tx_history[(pvt->curr_pos - 31) & pvt->tap_mask]); if (pvt->supp_test1 > 42 && pvt->supp_test2 > 42) supp_change = 25; else supp_change = 50; supp = supp_change + k1*pvt->supp1 + k2*pvt->supp2; pvt->supp2 = pvt->supp1; pvt->supp1 = supp; clean_rx *= (1 - supp); } #endif if (pvt->use_nlp && pvt->rx_power < 32) clean_rx = 0; /* Roll around the rolling buffer */ pvt->curr_pos = (pvt->curr_pos - 1) & pvt->tap_mask; return clean_rx; } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 x; short result; for (x = 0; x < size; x++) { result = sample_update(pvt, *iref, *isig); *isig++ = result; ++iref; } } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { struct ec_pvt *pvt = dahdi_to_pvt(ec); /* Reset hang counter to avoid adjustments after initial forced training */ pvt->nonupdate_dwell = pvt->taps << 1; if (pos >= pvt->taps) return 1; pvt->fir_taps[pos] = val << 17; pvt->fir_taps_short[pos] = val << 1; if (++pos >= pvt->taps) return 1; else return 0; } static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable) { struct ec_pvt *pvt = dahdi_to_pvt(ec); pvt->use_nlp = enable ? 1 : 0; } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI 'SEC' Echo Canceler"); MODULE_AUTHOR("Steve Underwood "); MODULE_LICENSE("GPL"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/wctc4xxp/0000755000175000017500000000000011631523355020326 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/wctc4xxp/base.c0000644000175000017500000030111711622312745021406 0ustar tzafrirtzafrir/* Wildcard TC400B Driver * * Copyright (C) 2006-2010, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dahdi/kernel.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #include #else #include #endif /* COMPILE TIME OPTIONS =================================================== */ #define INTERRUPT 0 #define WORKQUEUE 1 #define TASKLET 2 #ifndef DEFERRED_PROCESSING # define DEFERRED_PROCESSING WORKQUEUE #endif #if DEFERRED_PROCESSING == INTERRUPT # define ALLOC_FLAGS GFP_ATOMIC #elif DEFERRED_PROCESSING == TASKLET # define ALLOC_FLAGS GFP_ATOMIC #else # define ALLOC_FLAGS GFP_KERNEL #endif #define WARN_ALWAYS() WARN_ON(1) #define DTE_DEBUG(_dbgmask, _fmt, _args...) \ if ((debug & _dbgmask) == (_dbgmask)) { \ dev_info(&(wc)->pdev->dev, _fmt, ## _args); \ } \ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #ifndef WARN_ON_ONCE #define WARN_ON_ONCE(__condition) do { \ static int __once = 1; \ if (unlikely(__condition)) { \ if (__once) { \ __once = 0; \ WARN_ON(0); \ } \ } \ } while (0) #endif #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) /* also added in RHEL kernels with the OpenInfiniband backport: */ #if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9) || !defined(DEFINE_SPINLOCK) typedef unsigned gfp_t; /* Added in 2.6.14 */ #endif #endif /* define CONFIG_WCTC4XXP_POLLING to operate in a pure polling mode. This is * was placed in as a debugging tool for a particluar system that wasn't * routing the interrupt properly. Therefore it is off by default and the * driver must be recompiled to enable it. */ #undef CONFIG_WCTC4XXP_POLLING /* The total number of active channels over which the driver will start polling * the card every 10 ms. */ #define POLLING_CALL_THRESHOLD 40 #define INVALID 999 /* Used to mark invalid channels, commands, etc.. */ #define MAX_CHANNEL_PACKETS 5 #define G729_LENGTH 20 #define G723_LENGTH 30 #define G729_SAMPLES 160 /* G.729 */ #define G723_SAMPLES 240 /* G.723.1 */ #define G729_BYTES 20 /* G.729 */ #define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */ #define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */ #define G723_SID_BYTES 4 /* G.723.1 SID frame */ #define MAX_CAPTURED_PACKETS 5000 /* The following bit fields are used to set the various debug levels. */ #define DTE_DEBUG_GENERAL (1 << 0) /* 1 */ #define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */ #define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */ #define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */ #define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */ #define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */ #define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */ static int debug; static char *mode; static spinlock_t wctc4xxp_list_lock; static struct list_head wctc4xxp_list; #define ETH_P_CSM_ENCAPS 0x889B struct rtphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 csrc_count:4; __u8 extension:1; __u8 padding:1; __u8 ver:2; __u8 type:7; __u8 marker:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u8 ver:2; __u8 padding:1; __u8 extension:1; __u8 csrc_count:4; __u8 marker:1; __u8 type:7; #else #error "Please fix " #endif __be16 seqno; __be32 timestamp; __be32 ssrc; } __attribute__((packed)); struct rtp_packet { struct ethhdr ethhdr; struct iphdr iphdr; struct udphdr udphdr; struct rtphdr rtphdr; __u8 payload[0]; } __attribute__((packed)); /* Ethernet packet type for communication control information to the DTE. */ struct csm_encaps_hdr { struct ethhdr ethhdr; /* CSM_ENCAPS HEADER */ __be16 op_code; __u8 seq_num; __u8 control; __be16 channel; /* COMMON PART OF PAYLOAD HEADER */ __u8 length; __u8 index; __u8 type; __u8 class; __le16 function; __le16 reserved; __le16 params[0]; } __attribute__((packed)); #define CONTROL_PACKET_OPCODE 0x0001 /* Control bits */ #define LITTLE_ENDIAN 0x01 #define SUPPRESS_ACK 0x40 #define MESSAGE_PACKET 0x80 #define SUPERVISOR_CHANNEL 0xffff /* Supervisor function codes */ #define SUPVSR_CREATE_CHANNEL 0x0010 #define MONITOR_LIVE_INDICATION_TYPE 0x75 #define CONFIG_CHANGE_TYPE 0x00 #define CONFIG_CHANNEL_CLASS 0x02 #define CONFIG_DEVICE_CLASS 0x06 /* Individual channel config commands */ #define MAX_FRAME_SIZE 1518 #define SFRAME_SIZE MAX_FRAME_SIZE #define DRING_SIZE (1 << 7) /* Must be a power of two */ #define DRING_MASK (DRING_SIZE-1) #define MIN_PACKET_LEN 64 /* Transcoder buffer (tcb) */ struct tcb { void *data; struct list_head node; unsigned long timeout; unsigned long retries; /* NOTE: these flags aren't bit fields because some of the flags are * combinations of the other ones. */ #define DO_NOT_AUTO_FREE (1 << 0) #define TX_COMPLETE (1 << 1) #define DO_NOT_CAPTURE (1 << 2) #define __WAIT_FOR_ACK (1 << 3) #define __WAIT_FOR_RESPONSE (1 << 4) #define DTE_CMD_TIMEOUT (1 << 5) #define WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE) #define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE) unsigned long flags; struct tcb *response; struct completion complete; struct timer_list timer; /* The number of bytes available in data. */ int data_len; spinlock_t lock; }; static inline const struct csm_encaps_hdr * response_header(struct tcb *cmd) { BUG_ON(!cmd->response); return (const struct csm_encaps_hdr *)(cmd)->response->data; } static inline void initialize_cmd(struct tcb *cmd, unsigned long cmd_flags) { INIT_LIST_HEAD(&cmd->node); init_completion(&cmd->complete); cmd->flags = cmd_flags; spin_lock_init(&cmd->lock); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) /*! Used to allocate commands to submit to the dte. */ kmem_cache_t *cmd_cache; #else /*! Used to allocate commands to submit to the dte. */ static struct kmem_cache *cmd_cache; #endif static inline struct tcb * __alloc_cmd(size_t size, gfp_t alloc_flags, unsigned long cmd_flags) { struct tcb *cmd; if (unlikely(size > SFRAME_SIZE)) return NULL; if (size < MIN_PACKET_LEN) size = MIN_PACKET_LEN; cmd = kmem_cache_alloc(cmd_cache, alloc_flags); if (likely(cmd)) { memset(cmd, 0, sizeof(*cmd)); cmd->data = kzalloc(size, alloc_flags); if (unlikely(!cmd->data)) { kmem_cache_free(cmd_cache, cmd); return NULL; } cmd->data_len = size; initialize_cmd(cmd, cmd_flags); } return cmd; } static struct tcb * alloc_cmd(size_t size) { return __alloc_cmd(size, GFP_KERNEL, 0); } static void __free_cmd(struct tcb *cmd) { if (cmd) kfree(cmd->data); kmem_cache_free(cmd_cache, cmd); return; } static void free_cmd(struct tcb *cmd) { if (cmd->response) __free_cmd(cmd->response); __free_cmd(cmd); } struct channel_stats { atomic_t packets_sent; atomic_t packets_received; }; struct channel_pvt { spinlock_t lock; /* Lock for this structure */ struct wcdte *wc; u16 seqno; u8 cmd_seqno; u8 ssrc; u16 timeslot_in_num; /* DTE timeslot to receive from */ u16 timeslot_out_num; /* DTE timeslot to send data to */ u16 chan_in_num; /* DTE channel to receive from */ u16 chan_out_num; /* DTE channel to send data to */ u32 timestamp; struct { u8 encoder:1; /* If we're an encoder */ }; struct channel_stats stats; struct list_head rx_queue; /* Transcoded packets for this channel. */ }; struct wcdte { char board_name[40]; const char *variety; int pos; struct list_head node; spinlock_t reglock; wait_queue_head_t waitq; struct semaphore chansem; #define DTE_READY 1 #define DTE_SHUTDOWN 2 #define DTE_POLLING 3 unsigned long flags; /* This is a device-global list of commands that are waiting to be * transmited (and did not fit on the transmit descriptor ring) */ spinlock_t cmd_list_lock; struct list_head cmd_list; struct list_head waiting_for_response_list; spinlock_t rx_list_lock; struct list_head rx_list; spinlock_t rx_lock; unsigned int seq_num; int last_rx_seq_num; unsigned char numchannels; unsigned char complexname[40]; /* This section contains the members necessary to communicate with the * physical interface to the transcoding engine. */ struct pci_dev *pdev; unsigned int intmask; void __iomem *iobase; struct wctc4xxp_descriptor_ring *txd; struct wctc4xxp_descriptor_ring *rxd; struct dahdi_transcoder *uencode; struct dahdi_transcoder *udecode; struct channel_pvt *encoders; struct channel_pvt *decoders; #if DEFERRED_PROCESSING == WORKQUEUE struct work_struct deferred_work; #endif /* * This section contains the members necessary for exporting the * network interface to the host system. This is only used for * debugging purposes. * */ struct sk_buff_head captured_packets; struct net_device *netdev; struct net_device_stats net_stats; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) struct napi_struct napi; #endif struct timer_list watchdog; atomic_t open_channels; struct timer_list polling; #if HZ > 100 unsigned long jiffies_at_last_poll; #endif }; struct wcdte_netdev_priv { struct wcdte *wc; }; static inline struct wcdte * wcdte_from_netdev(struct net_device *netdev) { struct wcdte_netdev_priv *priv; priv = netdev_priv(netdev); return priv->wc; } static inline void wctc4xxp_set_ready(struct wcdte *wc) { set_bit(DTE_READY, &wc->flags); } static inline int wctc4xxp_is_ready(struct wcdte *wc) { return test_bit(DTE_READY, &wc->flags); } #define DTE_FORMAT_ULAW 0x00 #define DTE_FORMAT_G723_1 0x04 #define DTE_FORMAT_ALAW 0x08 #define DTE_FORMAT_G729A 0x12 #define DTE_FORMAT_UNDEF 0xFF static inline u8 wctc4xxp_dahdifmt_to_dtefmt(unsigned int fmt) { u8 pt; switch (fmt) { case DAHDI_FORMAT_G723_1: pt = DTE_FORMAT_G723_1; break; case DAHDI_FORMAT_ULAW: pt = DTE_FORMAT_ULAW; break; case DAHDI_FORMAT_ALAW: pt = DTE_FORMAT_ALAW; break; case DAHDI_FORMAT_G729A: pt = DTE_FORMAT_G729A; break; default: pt = DTE_FORMAT_UNDEF; break; } return pt; } static struct sk_buff * tcb_to_skb(struct net_device *netdev, const struct tcb *cmd) { struct sk_buff *skb; skb = alloc_skb(cmd->data_len, in_atomic() ? GFP_ATOMIC : GFP_KERNEL); if (skb) { skb->dev = netdev; skb_put(skb, cmd->data_len); memcpy(skb->data, cmd->data, cmd->data_len); skb->protocol = eth_type_trans(skb, netdev); } return skb; } /** * wctc4xxp_skb_to_cmd - Convert a socket buffer (skb) to a tcb * @wc: The transcoder that we're going to send this command to. * @skb: socket buffer to convert. * */ static struct tcb * wctc4xxp_skb_to_cmd(struct wcdte *wc, const struct sk_buff *skb) { const gfp_t alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct tcb *cmd; cmd = __alloc_cmd(skb->len, alloc_flags, 0); if (cmd) { int res; cmd->data_len = skb->len; res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len); if (res) { dev_warn(&wc->pdev->dev, "Failed call to skb_copy_bits.\n"); free_cmd(cmd); cmd = NULL; } } return cmd; } static void wctc4xxp_net_set_multi(struct net_device *netdev) { struct wcdte *wc = wcdte_from_netdev(netdev); DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n", __func__, netdev->promiscuity); } static int wctc4xxp_net_up(struct net_device *netdev) { struct wcdte *wc = wcdte_from_netdev(netdev); DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_enable(netdev); #else napi_enable(&wc->napi); #endif return 0; } static int wctc4xxp_net_down(struct net_device *netdev) { struct wcdte *wc = wcdte_from_netdev(netdev); DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_disable(netdev); #else napi_disable(&wc->napi); #endif return 0; } static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *); static int wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct wcdte *wc = wcdte_from_netdev(netdev); struct tcb *cmd; /* We set DO_NOT_CAPTURE because this packet was already captured by * in code higher up in the networking stack. We don't want to * capture it twice. */ cmd = wctc4xxp_skb_to_cmd(wc, skb); if (cmd) { cmd->flags |= DO_NOT_CAPTURE; wctc4xxp_transmit_cmd(wc, cmd); } dev_kfree_skb_any(skb); return NETDEV_TX_OK; } static int wctc4xxp_net_receive(struct wcdte *wc, int max) { int count = 0; struct sk_buff *skb; WARN_ON(0 == max); while ((skb = skb_dequeue(&wc->captured_packets))) { netif_receive_skb(skb); if (++count >= max) break; } return count; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) static int wctc4xxp_poll(struct net_device *netdev, int *budget) { struct wcdte *wc = wcdte_from_netdev(netdev); int count = 0; int quota = min(netdev->quota, *budget); count = wctc4xxp_net_receive(wc, quota); *budget -= count; netdev->quota -= count; if (!skb_queue_len(&wc->captured_packets)) { netif_rx_complete(netdev); return 0; } else { return -1; } } #else static int wctc4xxp_poll(struct napi_struct *napi, int budget) { struct wcdte *wc = container_of(napi, struct wcdte, napi); int count; count = wctc4xxp_net_receive(wc, budget); if (!skb_queue_len(&wc->captured_packets)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_complete(wc->netdev, &wc->napi); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) netif_rx_complete(&wc->napi); #else napi_complete(&wc->napi); #endif } return count; } #endif static struct net_device_stats * wctc4xxp_net_get_stats(struct net_device *netdev) { struct wcdte *wc = wcdte_from_netdev(netdev); return &wc->net_stats; } /* Wait until this device is put into promiscuous mode, or we timeout. */ static void wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc) { unsigned int seconds = 15; unsigned long start = jiffies; struct net_device *netdev = wc->netdev; dev_info(&wc->pdev->dev, "Waiting %d seconds for adapter to be placed in " \ "promiscuous mode for early trace.\n", seconds); while (!netdev->promiscuity) { if (signal_pending(current)) { dev_info(&wc->pdev->dev, "Aborting wait due to signal.\n"); break; } msleep(100); if (time_after(jiffies, start + (seconds * HZ))) { dev_info(&wc->pdev->dev, "Aborting wait due to timeout.\n"); break; } } } static int wctc4xxp_turn_off_booted_led(struct wcdte *wc); static void wctc4xxp_turn_on_booted_led(struct wcdte *wc); static int wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { struct wcdte *wc = wcdte_from_netdev(netdev); switch (cmd) { case 0x89f0: down(&wc->chansem); wctc4xxp_turn_off_booted_led(wc); break; case 0x89f1: wctc4xxp_turn_on_booted_led(wc); up(&wc->chansem); break; default: return -EOPNOTSUPP; }; return 0; } #ifdef HAVE_NET_DEVICE_OPS static const struct net_device_ops wctc4xxp_netdev_ops = { .ndo_set_multicast_list = &wctc4xxp_net_set_multi, .ndo_open = &wctc4xxp_net_up, .ndo_stop = &wctc4xxp_net_down, .ndo_start_xmit = &wctc4xxp_net_hard_start_xmit, .ndo_get_stats = &wctc4xxp_net_get_stats, .ndo_do_ioctl = &wctc4xxp_net_ioctl, }; #endif /** * wctc4xxp_net_register - Register a new network interface. * @wc: transcoder card to register the interface for. * * The network interface is primarily used for debugging in order to watch the * traffic between the transcoder and the host. * */ static int wctc4xxp_net_register(struct wcdte *wc) { int res; struct net_device *netdev; struct wcdte_netdev_priv *priv; const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; netdev = alloc_netdev(sizeof(*priv), wc->board_name, ether_setup); if (!netdev) return -ENOMEM; priv = netdev_priv(netdev); priv->wc = wc; memcpy(netdev->dev_addr, our_mac, sizeof(our_mac)); # ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &wctc4xxp_netdev_ops; # else netdev->set_multicast_list = &wctc4xxp_net_set_multi; netdev->open = &wctc4xxp_net_up; netdev->stop = &wctc4xxp_net_down; netdev->hard_start_xmit = &wctc4xxp_net_hard_start_xmit; netdev->get_stats = &wctc4xxp_net_get_stats; netdev->do_ioctl = &wctc4xxp_net_ioctl; # endif netdev->promiscuity = 0; netdev->flags |= IFF_NOARP; # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netdev->poll = &wctc4xxp_poll; netdev->weight = 64; # else netif_napi_add(netdev, &wc->napi, &wctc4xxp_poll, 64); # endif res = register_netdev(netdev); if (res) { dev_warn(&wc->pdev->dev, "Failed to register network device %s.\n", wc->board_name); goto error_sw; } wc->netdev = netdev; skb_queue_head_init(&wc->captured_packets); if (debug & DTE_DEBUG_NETWORK_EARLY) wctc4xxp_net_waitfor_promiscuous(wc); dev_info(&wc->pdev->dev, "Created network device %s for debug.\n", wc->board_name); return 0; error_sw: if (netdev) free_netdev(netdev); return res; } static void wctc4xxp_net_unregister(struct wcdte *wc) { struct sk_buff *skb; if (!wc->netdev) return; unregister_netdev(wc->netdev); while ((skb = skb_dequeue(&wc->captured_packets))) kfree_skb(skb); free_netdev(wc->netdev); wc->netdev = NULL; } /** * wctc4xxp_net_capture_cmd - Send a tcb to the network stack. * @wc: transcoder that received the command. * @cmd: command to send to network stack. * */ static void wctc4xxp_net_capture_cmd(struct wcdte *wc, const struct tcb *cmd) { struct sk_buff *skb; struct net_device *netdev = wc->netdev; if (!netdev) return; /* No need to capture if there isn't anyone listening. */ if (!(netdev->flags & IFF_UP)) return; if (skb_queue_len(&wc->captured_packets) > MAX_CAPTURED_PACKETS) { WARN_ON_ONCE(1); return; } skb = tcb_to_skb(netdev, cmd); if (!skb) return; skb_queue_tail(&wc->captured_packets, skb); # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_rx_schedule(netdev); # elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_schedule(netdev, &wc->napi); # elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) netif_rx_schedule(&wc->napi); # else napi_schedule(&wc->napi); # endif return; } /*! In-memory structure shared by the host and the adapter. */ struct wctc4xxp_descriptor { __le32 des0; __le32 des1; __le32 buffer1; __le32 container; /* Unused */ } __attribute__((packed)); struct wctc4xxp_descriptor_ring { /* Pointer to an array of descriptors to give to hardware. */ struct wctc4xxp_descriptor *desc; /* Read completed buffers from the head. */ unsigned int head; /* Write ready buffers to the tail. */ unsigned int tail; /* Array to save the kernel virtual address of pending commands. */ struct tcb *pending[DRING_SIZE]; /* PCI Bus address of the descriptor list. */ dma_addr_t desc_dma; /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */ unsigned int direction; /*! The number of buffers currently submitted to the hardware. */ unsigned int count; /*! The number of bytes to pad each descriptor for cache alignment. */ unsigned int padding; /*! Protects this structure from concurrent access. */ spinlock_t lock; /*! PCI device for the card associated with this ring. */ struct pci_dev *pdev; }; /** * wctc4xxp_descriptor - Returns the desriptor at index. * @dr: The descriptor ring we're using. * @index: index of the descriptor we want. * * We need this function because we do not know what the padding on the * descriptors will be. Otherwise, we would just use an array. */ static inline struct wctc4xxp_descriptor * wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index) { return (struct wctc4xxp_descriptor *)((u8 *)dr->desc + ((sizeof(*dr->desc) + dr->padding) * index)); } static int wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descriptor_ring *dr, u32 des1, unsigned int direction) { int i; const u32 END_OF_RING = 0x02000000; u8 cache_line_size = 0; struct wctc4xxp_descriptor *d; int add_padding; BUG_ON(!pdev); BUG_ON(!dr); if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) return -EIO; memset(dr, 0, sizeof(*dr)); /* * Add some padding to each descriptor to ensure that they are * aligned on host system cache-line boundaries, but only for the * cache-line sizes that we support. * */ add_padding = (0x08 == cache_line_size) || (0x10 == cache_line_size) || (0x20 == cache_line_size); if (add_padding) dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d); dr->desc = pci_alloc_consistent(pdev, (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma); if (!dr->desc) return -ENOMEM; memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE); for (i = 0; i < DRING_SIZE; ++i) { d = wctc4xxp_descriptor(dr, i); d->des1 = cpu_to_le32(des1); } d->des1 |= cpu_to_le32(END_OF_RING); dr->direction = direction; spin_lock_init(&dr->lock); dr->pdev = pdev; return 0; } #define OWN_BIT cpu_to_le32(0x80000000) #define OWNED(_d_) (((_d_)->des0)&OWN_BIT) #define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0) static const unsigned int BUFFER1_SIZE_MASK = 0x7ff; static int wctc4xxp_submit(struct wctc4xxp_descriptor_ring *dr, struct tcb *c) { volatile struct wctc4xxp_descriptor *d; unsigned int len; unsigned long flags; WARN_ON(!c); len = (c->data_len < MIN_PACKET_LEN) ? MIN_PACKET_LEN : c->data_len; if (c->data_len > MAX_FRAME_SIZE) { WARN_ON_ONCE(!"Invalid command length passed\n"); c->data_len = MAX_FRAME_SIZE; } spin_lock_irqsave(&dr->lock, flags); d = wctc4xxp_descriptor(dr, dr->tail); WARN_ON(!d); if (d->buffer1) { spin_unlock_irqrestore(&dr->lock, flags); /* Do not overwrite a buffer that is still in progress. */ return -EBUSY; } d->des1 &= cpu_to_le32(~(BUFFER1_SIZE_MASK)); d->des1 |= cpu_to_le32(len & BUFFER1_SIZE_MASK); d->buffer1 = cpu_to_le32(pci_map_single(dr->pdev, c->data, SFRAME_SIZE, dr->direction)); SET_OWNED(d); /* That's it until the hardware is done with it. */ dr->pending[dr->tail] = c; dr->tail = (dr->tail + 1) & DRING_MASK; ++dr->count; spin_unlock_irqrestore(&dr->lock, flags); return 0; } static inline struct tcb* wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr) { volatile struct wctc4xxp_descriptor *d; struct tcb *c; unsigned int head = dr->head; unsigned long flags; spin_lock_irqsave(&dr->lock, flags); d = wctc4xxp_descriptor(dr, head); if (d->buffer1 && !OWNED(d)) { pci_unmap_single(dr->pdev, le32_to_cpu(d->buffer1), SFRAME_SIZE, dr->direction); c = dr->pending[head]; WARN_ON(!c); dr->head = (++head) & DRING_MASK; d->buffer1 = 0; --dr->count; WARN_ON(!c); c->data_len = (le32_to_cpu(d->des0) >> 16) & BUFFER1_SIZE_MASK; WARN_ON(c->data_len > SFRAME_SIZE); } else { c = NULL; } spin_unlock_irqrestore(&dr->lock, flags); return c; } static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr) { int count; unsigned long flags; spin_lock_irqsave(&dr->lock, flags); count = dr->count; spin_unlock_irqrestore(&dr->lock, flags); return count; } static inline void __wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { writel(val, wc->iobase + addr); readl(wc->iobase + addr); } static inline unsigned int __wctc4xxp_getctl(struct wcdte *wc, unsigned int addr) { return readl(wc->iobase + addr); } static inline void wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __wctc4xxp_setctl(wc, addr, val); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void wctc4xxp_receive_demand_poll(struct wcdte *wc) { __wctc4xxp_setctl(wc, 0x0010, 0x00000000); } static inline void wctc4xxp_transmit_demand_poll(struct wcdte *wc) { return; # if 0 __wctc4xxp_setctl(wc, 0x0008, 0x00000000); /* \todo Investigate why this register needs to be written twice in * order to get it to poll reliably. So far, most of the problems * I've seen with timeouts had more to do with an untransmitted * packet sitting in the outbound descriptor list as opposed to any * problem with the dte firmware. */ __wctc4xxp_setctl(wc, 0x0008, 0x00000000); #endif } /* Returns the size, in bytes, of a CSM_ENCAPS packet, given the number of * parameters used. */ #define SIZE_WITH_N_PARAMETERS(__n) (sizeof(struct csm_encaps_hdr) + \ ((__n) * (sizeof(u16)))) /* There are 20 bytes in the ethernet header and the common CSM_ENCAPS header * that we don't want in the length of the actual CSM_ENCAPS command */ #define LENGTH_WITH_N_PARAMETERS(__n) (SIZE_WITH_N_PARAMETERS(__n) - 20) static const u8 dst_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; static const u8 src_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; static int wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd); static void setup_common_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) { memcpy(hdr->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); memcpy(hdr->ethhdr.h_source, src_mac, sizeof(src_mac)); hdr->ethhdr.h_proto = cpu_to_be16(ETH_P_CSM_ENCAPS); } static void setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) { setup_common_header(wc, hdr); hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE); hdr->control = LITTLE_ENDIAN; hdr->seq_num = (wc->seq_num++)&0xf; hdr->channel = cpu_to_be16(SUPERVISOR_CHANNEL); } static void setup_channel_header(struct channel_pvt *pvt, struct csm_encaps_hdr *hdr) { setup_common_header(pvt->wc, hdr); hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE); hdr->seq_num = (pvt->cmd_seqno++)&0xf; hdr->channel = cpu_to_be16(pvt->chan_in_num); } static void create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class, u16 function, const u16 *parameters, const int num_parameters) { struct csm_encaps_hdr *hdr = cmd->data; int i; if (cmd->response) { free_cmd(cmd->response); cmd->response = NULL; } setup_supervisor_header(wc, hdr); hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); hdr->index = 0; hdr->type = type; hdr->class = class; hdr->function = cpu_to_le16(function); hdr->reserved = 0; for (i = 0; i < num_parameters; ++i) hdr->params[i] = cpu_to_le16(parameters[i]); cmd->flags = WAIT_FOR_RESPONSE; cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); } static void create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class, u16 function, const u16 *parameters, int num_parameters) { int i; struct csm_encaps_hdr *hdr = cmd->data; if (cmd->response) { free_cmd(cmd->response); cmd->response = NULL; } setup_channel_header(pvt, hdr); hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); hdr->index = 0; hdr->type = type; hdr->class = class; hdr->function = cpu_to_le16(function); hdr->reserved = 0; for (i = 0; i < num_parameters; ++i) hdr->params[i] = cpu_to_le16(parameters[i]); cmd->flags = WAIT_FOR_RESPONSE; cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); } static int send_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot, u16 *channel_number) { int res; const u16 parameters[] = {0x0002, timeslot}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, SUPVSR_CREATE_CHANNEL, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; if (0x0000 != response_header(cmd)->params[0]) { if (printk_ratelimit()) { dev_warn(&wc->pdev->dev, "Failed to create channel in timeslot " \ "%d. Response from DTE was (%04x).\n", timeslot, response_header(cmd)->params[0]); } free_cmd(cmd->response); cmd->response = NULL; return -EIO; } *channel_number = le16_to_cpu(response_header(cmd)->params[1]); free_cmd(cmd->response); cmd->response = NULL; return 0; } static int send_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x012c, 0x0000}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0411, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_set_spu_clk_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x012c, 0x0000}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0412, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_tdm_select_bus_mode_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0004}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0417, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_set_eth_header_cmd(struct wcdte *wc, struct tcb *cmd, const u8 *host_mac, const u8 *assigned_mac) { u16 parameters[8]; u16 *part; parameters[0] = 0x0001; part = (u16 *)host_mac; parameters[1] = part[0]; parameters[2] = part[1]; parameters[3] = part[2]; part = (u16 *)assigned_mac; parameters[4] = part[0]; parameters[5] = part[1]; parameters[6] = part[2]; parameters[7] = 0x0008; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0100, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_supvsr_setup_tdm_parms(struct wcdte *wc, struct tcb *cmd, u8 bus_number) { const u16 parameters[] = {0x8380, 0x0c00, 0, (bus_number << 2)&0xc}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0407, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_ip_service_config_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0200}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0302, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_arp_service_config_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0001}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0105, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_icmp_service_config_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0xff01}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0304, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_device_set_country_code_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0000}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x041b, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_spu_features_control_cmd(struct wcdte *wc, struct tcb *cmd, u16 options) { const u16 parameters[] = {options}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0013, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_tdm_opt_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0000}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0435, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int send_destroy_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 channel) { int res; u16 result; const u16 parameters[] = {channel}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0011, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ result = le16_to_cpu(response_header(cmd)->params[0]); if (0x0000 != result) { dev_err(&wc->pdev->dev, "Failed to destroy channel %04d (%04x)\n", channel, result); return -EIO; } return 0; } static int send_set_ip_hdr_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd) { int res; u16 result; struct wcdte *wc = pvt->wc; const u16 parameters[] = {0, 0x0045, 0, 0, 0x0040, 0x1180, 0, 0xa8c0, 0x0309, 0xa8c0, 0x0309, swab16(pvt->timeslot_out_num + 0x5000), swab16(pvt->timeslot_in_num + 0x5000), 0, 0}; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x9000, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ result = le16_to_cpu(response_header(cmd)->params[0]); if (0x0000 != result) { dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n", __func__, result); return -EIO; } return 0; } static int send_voip_vceopt_cmd(struct channel_pvt *pvt, struct tcb *cmd, u16 length) { int res; u16 result; const u16 parameters[] = {((length << 8)|0x21), 0x1c00, 0x0004, 0, 0}; struct wcdte *wc = pvt->wc; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x8001, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ result = le16_to_cpu(response_header(cmd)->params[0]); if (0x0000 != result) { dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n", __func__, result); return -EIO; } return 0; } static int send_voip_tonectl_cmd(struct channel_pvt *pvt, struct tcb *cmd) { int res; u16 result; const u16 parameters[] = {0}; struct wcdte *wc = pvt->wc; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x805b, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ result = le16_to_cpu(response_header(cmd)->params[0]); if (0x0000 != result) { dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n", __func__, result); return -EIO; } return 0; } static int send_voip_dtmfopt_cmd(struct channel_pvt *pvt, struct tcb *cmd) { const u16 parameters[] = {0x0008}; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x8002, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); } static int send_voip_indctrl_cmd(struct channel_pvt *pvt, struct tcb *cmd) { const u16 parameters[] = {0x0007}; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x8084, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); } static int send_voip_vopena_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 format) { const u16 parameters[] = {1, ((format<<8)|0x80), 0, 0, 0, 0x3412, 0x7856}; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x8000, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); } static int send_voip_vopena_close_cmd(struct channel_pvt *pvt, struct tcb *cmd) { int res; const u16 parameters[] = {0}; create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, 0x8000, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ if (0x0000 != response_header(cmd)->params[0]) { WARN_ON(1); return -EIO; } return 0; } static int send_ip_options_cmd(struct wcdte *wc, struct tcb *cmd) { const u16 parameters[] = {0x0002}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x0306, parameters, ARRAY_SIZE(parameters)); return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } static int _send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, u16 enable, u16 encoder_channel, u16 decoder_channel, u16 encoder_format, u16 decoder_format) { int res; const u16 parameters[] = {enable, encoder_channel, encoder_format, decoder_channel, decoder_format}; create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, CONFIG_DEVICE_CLASS, 0x9322, parameters, ARRAY_SIZE(parameters)); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); if (res) return res; /* Let's check the response for any error codes.... */ if (0x0000 != response_header(cmd)->params[0]) { WARN_ON(1); return -EIO; } return 0; } static int send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, const u16 encoder_channel, const u16 decoder_channel, const u16 encoder_format, const u16 decoder_format) { return _send_trans_connect_cmd(wc, cmd, 1, encoder_channel, decoder_channel, encoder_format, decoder_format); } static int send_trans_disconnect_cmd(struct wcdte *wc, struct tcb *cmd, const u16 encoder_channel, const u16 decoder_channel, const u16 encoder_format, const u16 decoder_format) { return _send_trans_connect_cmd(wc, cmd, 0, encoder_channel, decoder_channel, encoder_format, decoder_format); } static struct tcb * wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc, size_t inbytes) { const struct channel_pvt *cpvt = dtc->pvt; struct rtp_packet *packet; struct tcb *cmd; cmd = alloc_cmd(sizeof(*packet) + inbytes); if (!cmd) return NULL; packet = cmd->data; BUG_ON(cmd->data_len < sizeof(*packet)); /* setup the ethernet header */ memcpy(packet->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); memcpy(packet->ethhdr.h_source, src_mac, sizeof(src_mac)); packet->ethhdr.h_proto = cpu_to_be16(ETH_P_IP); /* setup the IP header */ packet->iphdr.ihl = 5; packet->iphdr.version = 4; packet->iphdr.tos = 0; packet->iphdr.tot_len = cpu_to_be16(inbytes+40); packet->iphdr.id = 0; packet->iphdr.frag_off = cpu_to_be16(0x4000); packet->iphdr.ttl = 64; packet->iphdr.protocol = 0x11; /* UDP */ packet->iphdr.check = 0; packet->iphdr.saddr = cpu_to_be32(0xc0a80903); packet->iphdr.daddr = cpu_to_be32(0xc0a80903); packet->iphdr.check = ip_fast_csum((void *)&packet->iphdr, packet->iphdr.ihl); /* setup the UDP header */ packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000); packet->udphdr.dest = cpu_to_be16(cpvt->timeslot_in_num + 0x5000); packet->udphdr.len = cpu_to_be16(inbytes + sizeof(struct rtphdr) + sizeof(struct udphdr)); packet->udphdr.check = 0; /* Setup the RTP header */ packet->rtphdr.ver = 2; packet->rtphdr.padding = 0; packet->rtphdr.extension = 0; packet->rtphdr.csrc_count = 0; packet->rtphdr.marker = 0; packet->rtphdr.type = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt); packet->rtphdr.seqno = cpu_to_be16(cpvt->seqno); packet->rtphdr.timestamp = cpu_to_be32(cpvt->timestamp); packet->rtphdr.ssrc = cpu_to_be32(cpvt->ssrc); WARN_ON(cmd->data_len > SFRAME_SIZE); return cmd; } static void wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr) { int i; struct wctc4xxp_descriptor *d; if (!dr || !dr->desc) return; for (i = 0; i < DRING_SIZE; ++i) { d = wctc4xxp_descriptor(dr, i); if (d->buffer1) { pci_unmap_single(dr->pdev, d->buffer1, SFRAME_SIZE, dr->direction); d->buffer1 = 0; /* Commands will also be sitting on the waiting for * response list, so we want to make sure to delete * them from that list as well. */ list_del_init(&(dr->pending[i])->node); free_cmd(dr->pending[i]); dr->pending[i] = NULL; } } dr->head = 0; dr->tail = 0; dr->count = 0; pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE, dr->desc, dr->desc_dma); } static void wctc4xxp_cleanup_command_list(struct wcdte *wc) { struct tcb *cmd; unsigned long flags; LIST_HEAD(local_list); spin_lock_irqsave(&wc->cmd_list_lock, flags); list_splice_init(&wc->cmd_list, &local_list); list_splice_init(&wc->waiting_for_response_list, &local_list); list_splice_init(&wc->rx_list, &local_list); spin_unlock_irqrestore(&wc->cmd_list_lock, flags); while (!list_empty(&local_list)) { cmd = list_entry(local_list.next, struct tcb, node); list_del_init(&cmd->node); free_cmd(cmd); } } /** * The command list is used to store commands that couldn't fit in the tx * descriptor list when they were requested. */ static void wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd) { unsigned long flags; spin_lock_irqsave(&wc->cmd_list_lock, flags); list_add_tail(&cmd->node, &wc->cmd_list); spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } static void wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd) { unsigned long flags; spin_lock_irqsave(&wc->cmd_list_lock, flags); list_add_tail(&cmd->node, &wc->waiting_for_response_list); spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } static void wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd) { unsigned long flags; spin_lock_irqsave(&wc->cmd_list_lock, flags); list_del_init(&cmd->node); spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } static void wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd) { int res; /* If we're shutdown all commands will timeout. Just complete the * command here with the timeout flag */ if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { if (cmd->flags & DO_NOT_AUTO_FREE) { cmd->flags |= DTE_CMD_TIMEOUT; list_del_init(&cmd->node); complete(&cmd->complete); } else { list_del(&cmd->node); free_cmd(cmd); } return; } if (cmd->data_len < MIN_PACKET_LEN) { memset((u8 *)(cmd->data) + cmd->data_len, 0, MIN_PACKET_LEN-cmd->data_len); cmd->data_len = MIN_PACKET_LEN; } WARN_ON(cmd->response); WARN_ON(cmd->flags & TX_COMPLETE); cmd->timeout = jiffies + HZ/4; if (cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE)) { if (cmd->flags & __WAIT_FOR_RESPONSE) { /* We don't need both an ACK and a response. Let's * tell the DTE not to generate an ACK, and we'll just * retry if we do not get the response within the * timeout period. */ struct csm_encaps_hdr *hdr = cmd->data; hdr->control |= SUPPRESS_ACK; } WARN_ON(!list_empty(&cmd->node)); wctc4xxp_add_to_response_list(wc, cmd); mod_timer(&wc->watchdog, jiffies + HZ/2); } if (!(cmd->flags & DO_NOT_CAPTURE)) wctc4xxp_net_capture_cmd(wc, cmd); res = wctc4xxp_submit(wc->txd, cmd); if (-EBUSY == res) { /* Looks like we're out of room in the descriptor * ring. We'll add this command to the pending list * and the interrupt service routine will pull from * this list as it clears up room in the descriptor * ring. */ wctc4xxp_remove_from_response_list(wc, cmd); wctc4xxp_add_to_command_list(wc, cmd); } else if (0 == res) { wctc4xxp_transmit_demand_poll(wc); } else { /* Unknown return value... */ WARN_ON(1); } } static int wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd) { cmd->flags |= DO_NOT_AUTO_FREE; wctc4xxp_transmit_cmd(wc, cmd); wait_for_completion(&cmd->complete); if (cmd->flags & DTE_CMD_TIMEOUT) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n"); return -EIO; } return 0; } static int wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, u8 simple, u8 complicated); static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt); static int __wctc4xxp_setup_channels(struct wcdte *wc); static void wctc4xxp_init_state(struct channel_pvt *cpvt, int encoder, unsigned int channel, struct wcdte *wc) { memset(cpvt, 0, sizeof(*cpvt)); cpvt->encoder = encoder; cpvt->wc = wc; cpvt->chan_in_num = INVALID; cpvt->chan_out_num = INVALID; cpvt->ssrc = 0x78; cpvt->timeslot_in_num = channel*2; cpvt->timeslot_out_num = channel*2; if (encoder) ++cpvt->timeslot_out_num; else ++cpvt->timeslot_in_num; spin_lock_init(&cpvt->lock); INIT_LIST_HEAD(&cpvt->rx_queue); } static unsigned int wctc4xxp_getctl(struct wcdte *wc, unsigned int addr) { unsigned int val; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); val = __wctc4xxp_getctl(wc, addr); spin_unlock_irqrestore(&wc->reglock, flags); return val; } static void wctc4xxp_cleanup_channel_private(struct wcdte *wc, struct dahdi_transcoder_channel *dtc) { struct tcb *cmd, *temp; struct channel_pvt *cpvt = dtc->pvt; unsigned long flags; LIST_HEAD(local_list); spin_lock_irqsave(&cpvt->lock, flags); list_splice_init(&cpvt->rx_queue, &local_list); dahdi_tc_clear_data_waiting(dtc); spin_unlock_irqrestore(&cpvt->lock, flags); memset(&cpvt->stats, 0, sizeof(cpvt->stats)); list_for_each_entry_safe(cmd, temp, &local_list, node) { list_del(&cmd->node); free_cmd(cmd); } } static int wctc4xxp_mark_channel_complement_built(struct wcdte *wc, struct dahdi_transcoder_channel *dtc) { int index; struct channel_pvt *cpvt = dtc->pvt; struct dahdi_transcoder_channel *compl_dtc; struct channel_pvt *compl_cpvt; BUG_ON(!cpvt); index = cpvt->timeslot_in_num/2; BUG_ON(index >= wc->numchannels); if (cpvt->encoder) compl_dtc = &(wc->udecode->channels[index]); else compl_dtc = &(wc->uencode->channels[index]); /* It shouldn't already have been built... */ WARN_ON(dahdi_tc_is_built(compl_dtc)); compl_dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; compl_cpvt = compl_dtc->pvt; DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "dtc: %p is the complement to %p\n", compl_dtc, dtc); compl_cpvt->chan_in_num = cpvt->chan_out_num; compl_cpvt->chan_out_num = cpvt->chan_in_num; dahdi_tc_set_built(compl_dtc); wctc4xxp_cleanup_channel_private(wc, dtc); return 0; } static int do_channel_allocate(struct dahdi_transcoder_channel *dtc) { struct channel_pvt *cpvt = dtc->pvt; struct wcdte *wc = cpvt->wc; u8 wctc4xxp_srcfmt; /* Digium Transcoder Engine Source Format */ u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */ int res; #ifndef DEBUG_WCTC4XXP down(&wc->chansem); #else if (down_interruptible(&wc->chansem)) return -EINTR; #endif /* Check again to see if the channel was built after grabbing the * channel semaphore, in case the previous holder of the semaphore * built this channel as a complement to itself. */ if (dahdi_tc_is_built(dtc)) { up(&wc->chansem); DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating channel %p which is already built.\n", dtc); return 0; } DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Entering %s for channel %p.\n", __func__, dtc); /* Anything on the rx queue now is old news... */ wctc4xxp_cleanup_channel_private(wc, dtc); DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating a new channel: %p.\n", dtc); wctc4xxp_srcfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt); wctc4xxp_dstfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->dstfmt); res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt, wctc4xxp_dstfmt); if (res) { /* There was a problem creating the channel.... */ up(&wc->chansem); return res; } /* Mark this channel as built */ dahdi_tc_set_built(dtc); dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Channel %p has dstfmt=%x and srcfmt=%x\n", dtc, dtc->dstfmt, dtc->srcfmt); /* Mark the channel complement (other half of encoder/decoder pair) as * built */ res = wctc4xxp_mark_channel_complement_built(wc, dtc); up(&wc->chansem); dahdi_transcoder_alert(dtc); return res; } static void wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask) { wc->intmask = intmask; wctc4xxp_setctl(wc, 0x0038, intmask); } static void wctc4xxp_enable_interrupts(struct wcdte *wc) { wctc4xxp_setintmask(wc, 0x000180c0); } static void wctc4xxp_disable_interrupts(struct wcdte *wc) { /* Disable interrupts */ wctc4xxp_setintmask(wc, 0x00000000); wctc4xxp_setctl(wc, 0x0084, 0x00000000); } static void wctc4xxp_enable_polling(struct wcdte *wc) { set_bit(DTE_POLLING, &wc->flags); mod_timer(&wc->polling, jiffies + 1); wctc4xxp_disable_interrupts(wc); } static int wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc) { struct wcdte *wc = ((struct channel_pvt *)(dtc->pvt))->wc; if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { /* The shudown flags can also be set if there is a * catastrophic failure. */ return -EIO; } atomic_inc(&wc->open_channels); if (atomic_read(&wc->open_channels) > POLLING_CALL_THRESHOLD) { if (!test_bit(DTE_POLLING, &wc->flags)) wctc4xxp_enable_polling(wc); } if (dahdi_tc_is_built(dtc)) { DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating channel %p which is already built.\n", dtc); return 0; } return do_channel_allocate(dtc); } static void wctc4xxp_disable_polling(struct wcdte *wc) { clear_bit(DTE_POLLING, &wc->flags); wctc4xxp_enable_interrupts(wc); } static int wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc) { int res; int index; /* This is the 'complimentary channel' to dtc. I.e., if dtc is an * encoder, compl_dtc is the decoder and vice-versa */ struct dahdi_transcoder_channel *compl_dtc; struct channel_pvt *compl_cpvt; struct channel_pvt *cpvt = dtc->pvt; struct wcdte *wc = cpvt->wc; int packets_received, packets_sent; BUG_ON(!cpvt); BUG_ON(!wc); if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { /* The shudown flags can also be set if there is a * catastrophic failure. */ return -EIO; } #ifndef DEBUG_WCTC4XXP down(&wc->chansem); #else if (down_interruptible(&wc->chansem)) return -EINTR; #endif atomic_dec(&wc->open_channels); #if !defined(CONFIG_WCTC4XXP_POLLING) if (atomic_read(&wc->open_channels) < POLLING_CALL_THRESHOLD) { if (test_bit(DTE_POLLING, &wc->flags)) wctc4xxp_disable_polling(wc); } #endif packets_received = atomic_read(&cpvt->stats.packets_received); packets_sent = atomic_read(&cpvt->stats.packets_sent); if ((packets_sent - packets_received) > 5) { DTE_DEBUG(DTE_DEBUG_GENERAL, "%s channel %d sent %d packets " "and received %d packets.\n", (cpvt->encoder) ? "encoder" : "decoder", cpvt->chan_out_num, packets_sent, packets_received); } /* Remove any packets that are waiting on the outbound queue. */ wctc4xxp_cleanup_channel_private(wc, dtc); index = cpvt->timeslot_in_num/2; BUG_ON(index >= wc->numchannels); if (cpvt->encoder) compl_dtc = &(wc->udecode->channels[index]); else compl_dtc = &(wc->uencode->channels[index]); BUG_ON(!compl_dtc); if (!dahdi_tc_is_built(compl_dtc)) { DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing a channel that was never built.\n"); res = 0; goto error_exit; } /* If the channel complement (other half of the encoder/decoder pair) is * being used. */ if (dahdi_tc_is_busy(compl_dtc)) { res = 0; goto error_exit; } res = wctc4xxp_destroy_channel_pair(wc, cpvt); if (res) goto error_exit; DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %p\n", dtc); /* Mark this channel as not built */ dahdi_tc_clear_built(dtc); dtc->built_fmts = 0; cpvt->chan_in_num = INVALID; cpvt->chan_out_num = INVALID; /* Mark the channel complement as not built */ dahdi_tc_clear_built(compl_dtc); compl_dtc->built_fmts = 0; compl_cpvt = compl_dtc->pvt; compl_cpvt->chan_in_num = INVALID; compl_cpvt->chan_out_num = INVALID; error_exit: up(&wc->chansem); return res; } static inline struct tcb* get_ready_cmd(struct dahdi_transcoder_channel *dtc) { struct channel_pvt *cpvt = dtc->pvt; struct tcb *cmd; unsigned long flags; spin_lock_irqsave(&cpvt->lock, flags); if (!list_empty(&cpvt->rx_queue)) { WARN_ON(!dahdi_tc_is_data_waiting(dtc)); cmd = list_entry(cpvt->rx_queue.next, struct tcb, node); list_del_init(&cmd->node); } else { cmd = NULL; } if (list_empty(&cpvt->rx_queue)) dahdi_tc_clear_data_waiting(dtc); spin_unlock_irqrestore(&cpvt->lock, flags); return cmd; } static int wctc4xxp_handle_receive_ring(struct wcdte *wc) { struct tcb *cmd; unsigned long flags; unsigned int count = 0; /* If we can't grab this lock, another thread must already be checking * the receive ring...so we should just finish up, and we'll try again * later. */ #if defined(spin_trylock_irqsave) if (!spin_trylock_irqsave(&wc->rx_lock, flags)) return 0; #else if (spin_is_locked(&wc->rx_lock)) return 0; spin_lock_irqsave(&wc->rx_lock, flags); #endif while ((cmd = wctc4xxp_retrieve(wc->rxd))) { ++count; spin_lock(&wc->rx_list_lock); list_add_tail(&cmd->node, &wc->rx_list); spin_unlock(&wc->rx_list_lock); cmd = __alloc_cmd(SFRAME_SIZE, GFP_ATOMIC, 0); if (!cmd) { dev_err(&wc->pdev->dev, "Out of memory in %s.\n", __func__); } else { if (wctc4xxp_submit(wc->rxd, cmd)) { dev_err(&wc->pdev->dev, "Failed submit in %s\n", __func__); free_cmd(cmd); } } } spin_unlock_irqrestore(&wc->rx_lock, flags); return count; } static void __wctc4xxp_polling(struct wcdte *wc) { if (wctc4xxp_handle_receive_ring(wc)) schedule_work(&wc->deferred_work); } static void wctc4xxp_polling(unsigned long data) { struct wcdte *wc = (struct wcdte *)data; __wctc4xxp_polling(wc); if (test_bit(DTE_POLLING, &wc->flags)) mod_timer(&wc->polling, jiffies + 1); } /* Called with a buffer in which to copy a transcoded frame. */ static ssize_t wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) { ssize_t ret; struct dahdi_transcoder_channel *dtc = file->private_data; struct channel_pvt *cpvt = dtc->pvt; struct wcdte *wc = cpvt->wc; struct tcb *cmd; struct rtp_packet *packet; ssize_t payload_bytes; ssize_t returned_bytes = 0; unsigned long flags; BUG_ON(!dtc); BUG_ON(!cpvt); if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { /* The shudown flags can also be set if there is a * catastrophic failure. */ return -EIO; } cmd = get_ready_cmd(dtc); if (!cmd) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; ret = wait_event_interruptible(dtc->ready, dahdi_tc_is_data_waiting(dtc)); if (-ERESTARTSYS == ret) return -EINTR; /* List went not empty. */ cmd = get_ready_cmd(dtc); } do { BUG_ON(!cmd); packet = cmd->data; payload_bytes = be16_to_cpu(packet->udphdr.len) - sizeof(struct rtphdr) - sizeof(struct udphdr); if (count < (payload_bytes + returned_bytes)) { if (returned_bytes) { /* If we have already returned at least one * packets worth of data, we'll add this next * packet to the head of the receive queue so * it will be picked up next time. */ spin_lock_irqsave(&cpvt->lock, flags); list_add(&cmd->node, &cpvt->rx_queue); dahdi_tc_set_data_waiting(dtc); spin_unlock_irqrestore(&cpvt->lock, flags); return returned_bytes; } if (printk_ratelimit()) { dev_err(&wc->pdev->dev, "Cannot copy %zd bytes into %zd byte user " \ "buffer.\n", payload_bytes, count); } free_cmd(cmd); return -EFBIG; } atomic_inc(&cpvt->stats.packets_received); ret = copy_to_user(&frame[returned_bytes], &packet->payload[0], payload_bytes); if (unlikely(ret)) { dev_err(&wc->pdev->dev, "Failed to copy data in %s\n", __func__); free_cmd(cmd); return -EFAULT; } returned_bytes += payload_bytes; free_cmd(cmd); } while ((cmd = get_ready_cmd(dtc))); return returned_bytes; } /* Called with a frame in the srcfmt to be transcoded into the dstfmt. */ static ssize_t wctc4xxp_write(struct file *file, const char __user *frame, size_t count, loff_t *ppos) { struct dahdi_transcoder_channel *dtc = file->private_data; struct channel_pvt *cpvt = dtc->pvt; struct wcdte *wc = cpvt->wc; struct tcb *cmd; BUG_ON(!cpvt); BUG_ON(!wc); if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) return -EIO; if (!test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags)) return -EAGAIN; if (count < 2) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Cannot request to transcode a packet that is less than " \ "2 bytes.\n"); return -EINVAL; } if (unlikely(count > SFRAME_SIZE - sizeof(struct rtp_packet))) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Cannot transcode packet of %Zu bytes. This exceeds the " \ "maximum size of %Zu bytes.\n", count, SFRAME_SIZE - sizeof(struct rtp_packet)); return -EINVAL; } if (DAHDI_FORMAT_G723_1 == dtc->srcfmt) { if ((G723_5K_BYTES != count) && (G723_6K_BYTES != count)) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Trying to transcode packet into G723 format " \ "that is %Zu bytes instead of the expected " \ "%d/%d bytes.\n", count, G723_5K_BYTES, G723_6K_BYTES); return -EINVAL; } cpvt->timestamp += G723_SAMPLES; } else if (DAHDI_FORMAT_G723_1 == dtc->dstfmt) { cpvt->timestamp = G723_SAMPLES; } else { /* Same for ulaw and alaw */ cpvt->timestamp += G729_SAMPLES; } cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count); if (!cmd) return -ENOMEM; /* Copy the data directly from user space into the command buffer. */ if (copy_from_user(&((struct rtp_packet *)(cmd->data))->payload[0], frame, count)) { dev_err(&wc->pdev->dev, "Failed to copy packet from userspace.\n"); free_cmd(cmd); return -EFAULT; } cpvt->seqno += 1; DTE_DEBUG(DTE_DEBUG_RTP_TX, "Sending packet of %Zu byte on channel (%p).\n", count, dtc); atomic_inc(&cpvt->stats.packets_sent); wctc4xxp_transmit_cmd(wc, cmd); if (test_bit(DTE_POLLING, &wc->flags)) { #if HZ == 100 __wctc4xxp_polling(wc); #else if (jiffies != wc->jiffies_at_last_poll) { wc->jiffies_at_last_poll = jiffies; __wctc4xxp_polling(wc); } #endif } return count; } static void wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel) { struct tcb *cmd; struct csm_encaps_hdr *hdr; cmd = __alloc_cmd(sizeof(*hdr), ALLOC_FLAGS, 0); if (!cmd) { WARN_ON(1); return; } hdr = cmd->data; BUG_ON(sizeof(*hdr) > cmd->data_len); setup_common_header(wc, hdr); hdr->op_code = cpu_to_be16(0x0001); hdr->seq_num = seqno; hdr->control = 0xe0; hdr->channel = channel; wctc4xxp_transmit_cmd(wc, cmd); } static bool do_rx_response_packet(struct wcdte *wc, struct tcb *cmd) { const struct csm_encaps_hdr *listhdr, *rxhdr; struct tcb *pos, *temp; unsigned long flags; bool handled = false; rxhdr = cmd->data; if (SUPERVISOR_CHANNEL == rxhdr->channel) { /* We received a duplicate response. */ if (rxhdr->seq_num == wc->last_rx_seq_num) { free_cmd(cmd); return false; } wc->last_rx_seq_num = rxhdr->seq_num; } spin_lock_irqsave(&wc->cmd_list_lock, flags); list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { listhdr = pos->data; if ((listhdr->function == rxhdr->function) && (listhdr->channel == rxhdr->channel)) { spin_lock(&pos->lock); list_del_init(&pos->node); pos->flags &= ~(__WAIT_FOR_RESPONSE); pos->response = cmd; /* If this isn't TX_COMPLETE yet, then this packet will * be completed in service_tx_ring. */ if (pos->flags & TX_COMPLETE) complete(&pos->complete); spin_unlock(&pos->lock); handled = true; break; } } spin_unlock_irqrestore(&wc->cmd_list_lock, flags); if (!handled) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Freeing unhandled response ch:(%04x)\n", be16_to_cpu(rxhdr->channel)); free_cmd(cmd); return false; } return true; } static void do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd) { const struct csm_encaps_hdr *listhdr, *rxhdr; struct tcb *pos, *temp; unsigned long flags; rxhdr = cmd->data; spin_lock_irqsave(&wc->cmd_list_lock, flags); list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { listhdr = pos->data; if (cpu_to_be16(0xefed) == listhdr->ethhdr.h_proto) { wc->seq_num = (rxhdr->seq_num + 1) & 0xff; WARN_ON(!(pos->flags & DO_NOT_AUTO_FREE)); WARN_ON(!(pos->flags & TX_COMPLETE)); list_del_init(&pos->node); WARN_ON(!(pos->flags & TX_COMPLETE)); complete(&pos->complete); } else if ((listhdr->seq_num == rxhdr->seq_num) && (listhdr->channel == rxhdr->channel)) { spin_lock(&pos->lock); if (pos->flags & __WAIT_FOR_RESPONSE) { pos->flags &= ~(__WAIT_FOR_ACK); spin_unlock(&pos->lock); } else { list_del_init(&pos->node); if (pos->flags & DO_NOT_AUTO_FREE) { WARN_ON(!(pos->flags & TX_COMPLETE)); complete(&pos->complete); spin_unlock(&pos->lock); } else { spin_unlock(&pos->lock); free_cmd(pos); } } break; } } spin_unlock_irqrestore(&wc->cmd_list_lock, flags); /* There is never a reason to store up the ack packets. */ free_cmd(cmd); } static inline int is_response(const struct csm_encaps_hdr *hdr) { return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0; } static void print_command(struct wcdte *wc, const struct tcb *cmd) { int i, curlength; const struct csm_encaps_hdr *hdr = cmd->data; char *buffer; const int BUFFER_SIZE = 1024; int parameters = ((hdr->length - 8)/sizeof(__le16)); buffer = kzalloc(BUFFER_SIZE + 1, GFP_ATOMIC); if (!buffer) { dev_info(&wc->pdev->dev, "Failed print_command\n"); return; } curlength = snprintf(buffer, BUFFER_SIZE, "opcode: %04x seq: %02x control: %02x " "channel: %04x ", be16_to_cpu(hdr->op_code), hdr->seq_num, hdr->control, be16_to_cpu(hdr->channel)); curlength += snprintf(buffer + curlength, BUFFER_SIZE - curlength, "length: %02x index: %02x type: %02x " "class: %02x function: %04x", hdr->length, hdr->index, hdr->type, hdr->class, le16_to_cpu(hdr->function)); for (i = 0; i < parameters; ++i) { curlength += snprintf(buffer + curlength, BUFFER_SIZE - curlength, " %04x", le16_to_cpu(hdr->params[i])); } dev_info(&wc->pdev->dev, "%s\n", buffer); kfree(buffer); } static void receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) { const struct csm_encaps_hdr *hdr = cmd->data; if (!(hdr->control & MESSAGE_PACKET)) { const bool suppress_ack = ((hdr->control & SUPPRESS_ACK) > 0); if (is_response(hdr)) { u8 seq_num = hdr->seq_num; __be16 channel = hdr->channel; if (do_rx_response_packet(wc, cmd) && !suppress_ack) wctc4xxp_send_ack(wc, seq_num, channel); } else if (0xc1 == hdr->type) { if (!suppress_ack) { wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); } if (0x75 == hdr->class) { dev_warn(&wc->pdev->dev, "Received alert (0x%04x) from dsp\n", le16_to_cpu(hdr->params[0])); } free_cmd(cmd); } else if (0xd4 == hdr->type) { if (!suppress_ack) { wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); } if (hdr->params[0] != le16_to_cpu(0xffff)) { dev_warn(&wc->pdev->dev, "DTE Failed self test (%04x).\n", le16_to_cpu(hdr->params[0])); } else if ((hdr->params[1] != le16_to_cpu(0x000c)) && (hdr->params[1] != le16_to_cpu(0x010c))) { dev_warn(&wc->pdev->dev, "Unexpected ERAM status (%04x).\n", le16_to_cpu(hdr->params[1])); } else { wctc4xxp_set_ready(wc); wake_up(&wc->waitq); } free_cmd(cmd); } else if (MONITOR_LIVE_INDICATION_TYPE == hdr->type) { if (!suppress_ack) { wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); } dev_warn(&wc->pdev->dev, "Received diagnostic message:\n"); print_command(wc, cmd); free_cmd(cmd); } else { if (!suppress_ack) { wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); } dev_warn(&wc->pdev->dev, "Unknown command type received. %02x\n", hdr->type); free_cmd(cmd); } } else { do_rx_ack_packet(wc, cmd); } } static void queue_rtp_packet(struct wcdte *wc, struct tcb *cmd) { unsigned index; struct dahdi_transcoder_channel *dtc; struct channel_pvt *cpvt; struct rtp_packet *packet = cmd->data; unsigned long flags; if (unlikely(ip_fast_csum((void *)(&packet->iphdr), packet->iphdr.ihl))) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Invalid checksum in RTP packet %04x\n", ip_fast_csum((void *)(&packet->iphdr), packet->iphdr.ihl)); free_cmd(cmd); return; } index = (be16_to_cpu(packet->udphdr.dest) - 0x5000) / 2; if (unlikely(!(index < wc->numchannels))) { dev_err(&wc->pdev->dev, "Invalid channel number in response from DTE.\n"); free_cmd(cmd); return; } switch (packet->rtphdr.type) { case 0x00: case 0x08: dtc = &(wc->udecode->channels[index]); break; case 0x04: case 0x12: dtc = &(wc->uencode->channels[index]); break; default: dev_err(&wc->pdev->dev, "Unknown codec in packet (0x%02x).\n",\ packet->rtphdr.type); free_cmd(cmd); return; } cpvt = dtc->pvt; spin_lock_irqsave(&cpvt->lock, flags); list_add_tail(&cmd->node, &cpvt->rx_queue); dahdi_tc_set_data_waiting(dtc); spin_unlock_irqrestore(&cpvt->lock, flags); dahdi_transcoder_alert(dtc); return; } static inline void wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd) { const struct ethhdr *ethhdr = (const struct ethhdr *)(cmd->data); if (cpu_to_be16(ETH_P_IP) == ethhdr->h_proto) { queue_rtp_packet(wc, cmd); } else if (cpu_to_be16(ETH_P_CSM_ENCAPS) == ethhdr->h_proto) { receive_csm_encaps_packet(wc, cmd); } else { DTE_DEBUG(DTE_DEBUG_GENERAL, "Unknown packet protocol received: %04x.\n", be16_to_cpu(ethhdr->h_proto)); free_cmd(cmd); } } static void service_tx_ring(struct wcdte *wc) { struct tcb *cmd; unsigned long flags; while ((cmd = wctc4xxp_retrieve(wc->txd))) { spin_lock_irqsave(&cmd->lock, flags); cmd->flags |= TX_COMPLETE; if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) { /* If we're not waiting for an ACK or Response from * the DTE, this message should not be sitting on any * lists. */ WARN_ON(!list_empty(&cmd->node)); if (DO_NOT_AUTO_FREE & cmd->flags) { spin_unlock_irqrestore(&cmd->lock, flags); WARN_ON(!(cmd->flags & TX_COMPLETE)); complete(&cmd->complete); } else { spin_unlock_irqrestore(&cmd->lock, flags); free_cmd(cmd); } } else { spin_unlock_irqrestore(&cmd->lock, flags); } /* We've freed up a spot in the hardware ring buffer. If * another packet is queued up, let's submit it to the * hardware. */ spin_lock_irqsave(&wc->cmd_list_lock, flags); if (!list_empty(&wc->cmd_list)) { cmd = list_entry(wc->cmd_list.next, struct tcb, node); list_del_init(&cmd->node); } else { cmd = NULL; } spin_unlock_irqrestore(&wc->cmd_list_lock, flags); if (cmd) wctc4xxp_transmit_cmd(wc, cmd); } } static void service_rx_ring(struct wcdte *wc) { struct tcb *cmd; unsigned long flags; LIST_HEAD(local_list); spin_lock_irqsave(&wc->rx_list_lock, flags); list_splice_init(&wc->rx_list, &local_list); spin_unlock_irqrestore(&wc->rx_list_lock, flags); /* * Process the received packets */ while (!list_empty(&local_list)) { cmd = container_of(local_list.next, struct tcb, node); list_del_init(&cmd->node); wctc4xxp_net_capture_cmd(wc, cmd); wctc4xxp_receiveprep(wc, cmd); } wctc4xxp_receive_demand_poll(wc); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void deferred_work_func(void *param) { struct wcdte *wc = param; #else static void deferred_work_func(struct work_struct *work) { struct wcdte *wc = container_of(work, struct wcdte, deferred_work); #endif service_tx_ring(wc); service_rx_ring(wc); } DAHDI_IRQ_HANDLER(wctc4xxp_interrupt) { struct wcdte *wc = dev_id; u32 ints; u32 reg; #define TX_COMPLETE_INTERRUPT 0x00000001 #define RX_COMPLETE_INTERRUPT 0x00000040 #define NORMAL_INTERRUPTS (TX_COMPLETE_INTERRUPT | RX_COMPLETE_INTERRUPT) /* Read and clear interrupts */ ints = __wctc4xxp_getctl(wc, 0x0028); ints &= wc->intmask; if (!ints) return IRQ_NONE; if (likely(ints & NORMAL_INTERRUPTS)) { reg = 0; if (ints & TX_COMPLETE_INTERRUPT) reg |= TX_COMPLETE_INTERRUPT; if (ints & RX_COMPLETE_INTERRUPT) { wctc4xxp_handle_receive_ring(wc); reg |= RX_COMPLETE_INTERRUPT; } #if DEFERRED_PROCESSING == WORKQUEUE schedule_work(&wc->deferred_work); #elif DEFERRED_PROCESSING == INTERRUPT #error "You will need to change the locks if you want to run the processing " \ "in the interrupt handler." #else #error "Define a deferred processing function in kernel/wctc4xxp/wctc4xxp.h" #endif __wctc4xxp_setctl(wc, 0x0028, reg); } else { if ((ints & 0x00008000) && debug) dev_info(&wc->pdev->dev, "Abnormal Interrupt.\n"); if ((ints & 0x00002000) && debug) dev_info(&wc->pdev->dev, "Fatal Bus Error INT\n"); if ((ints & 0x00000100) && debug) dev_info(&wc->pdev->dev, "Receive Stopped INT\n"); if ((ints & 0x00000080) && debug) { dev_info(&wc->pdev->dev, "Receive Desciptor Unavailable INT " \ "(%d)\n", wctc4xxp_getcount(wc->rxd)); } if ((ints & 0x00000020) && debug) dev_info(&wc->pdev->dev, "Transmit Under-flow INT\n"); if ((ints & 0x00000008) && debug) dev_info(&wc->pdev->dev, "Jabber Timer Time-out INT\n"); if ((ints & 0x00000002) && debug) { dev_info(&wc->pdev->dev, "Transmit Processor Stopped INT\n"); } /* Clear all the pending interrupts. */ __wctc4xxp_setctl(wc, 0x0028, ints); } return IRQ_HANDLED; } static int wctc4xxp_hardware_init(struct wcdte *wc) { /* Hardware stuff */ u32 reg; unsigned long newjiffies; u8 cache_line_size; const u32 DEFAULT_PCI_ACCESS = 0xfff80000; /* Enable I/O Access */ pci_read_config_dword(wc->pdev, 0x0004, ®); reg |= 0x00000007; pci_write_config_dword(wc->pdev, 0x0004, reg); if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size)) return -EIO; switch (cache_line_size) { case 0x08: reg = DEFAULT_PCI_ACCESS | (0x1 << 14); break; case 0x10: reg = DEFAULT_PCI_ACCESS | (0x2 << 14); break; case 0x20: reg = DEFAULT_PCI_ACCESS | (0x3 << 14); break; default: reg = 0xfe584202; break; } reg |= ((wc->txd->padding / sizeof(u32)) << 2) & 0x7c; /* Reset the DTE... */ wctc4xxp_setctl(wc, 0x0000, reg | 1); newjiffies = jiffies + HZ; /* One second timeout */ /* ...and wait for it to come out of reset. */ while (((wctc4xxp_getctl(wc, 0x0000)) & 0x00000001) && (newjiffies > jiffies)) msleep(1); wctc4xxp_setctl(wc, 0x0000, reg | 0x60000); /* Configure watchdogs, access, etc */ wctc4xxp_setctl(wc, 0x0030, 0x00280040); wctc4xxp_setctl(wc, 0x0078, 0x00000013); reg = wctc4xxp_getctl(wc, 0x00fc); wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); reg = wctc4xxp_getctl(wc, 0x00fc); return 0; } static void wctc4xxp_start_dma(struct wcdte *wc) { int res; int i; u32 reg; struct tcb *cmd; for (i = 0; i < DRING_SIZE; ++i) { cmd = alloc_cmd(SFRAME_SIZE); if (!cmd) { WARN_ALWAYS(); return; } WARN_ON(SFRAME_SIZE != cmd->data_len); res = wctc4xxp_submit(wc->rxd, cmd); if (res) { /* When we're starting the DMA, we should always be * able to fill the ring....so something is wrong * here. */ WARN_ALWAYS(); free_cmd(cmd); break; } } wmb(); wctc4xxp_setctl(wc, 0x0020, wc->txd->desc_dma); wctc4xxp_setctl(wc, 0x0018, wc->rxd->desc_dma); /* Start receiver/transmitter */ reg = wctc4xxp_getctl(wc, 0x0030); wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002); wctc4xxp_receive_demand_poll(wc); reg = wctc4xxp_getctl(wc, 0x0028); wctc4xxp_setctl(wc, 0x0028, reg); } static void _wctc4xxp_stop_dma(struct wcdte *wc) { /* Disable interrupts and reset */ unsigned int reg; /* Disable interrupts */ wctc4xxp_setintmask(wc, 0x00000000); wctc4xxp_setctl(wc, 0x0084, 0x00000000); wctc4xxp_setctl(wc, 0x0048, 0x00000000); /* Reset the part to be on the safe side */ reg = wctc4xxp_getctl(wc, 0x0000); reg |= 0x00000001; wctc4xxp_setctl(wc, 0x0000, reg); } static void wctc4xxp_stop_dma(struct wcdte *wc) { unsigned long newjiffies; _wctc4xxp_stop_dma(wc); newjiffies = jiffies + HZ; /* One second timeout */ /* We'll wait here for the part to come out of reset */ while (((wctc4xxp_getctl(wc, 0x0000)) & 0x00000001) && (newjiffies > jiffies)) msleep(1); } #define MDIO_SHIFT_CLK 0x10000 #define MDIO_DATA_WRITE1 0x20000 #define MDIO_ENB 0x00000 #define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 static int wctc4xxp_read_phy(struct wcdte *wc, int location) { int i; long mdio_addr = 0x0048; int read_cmd = (0xf6 << 10) | (1 << 5) | location; int retval = 0; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Shift the read command bits out. */ for (i = 17; i >= 0; --i) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); wctc4xxp_getctl(wc, mdio_addr); retval = (retval << 1) | ((wctc4xxp_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } retval = (retval>>1) & 0xffff; return retval; } static void wctc4xxp_write_phy(struct wcdte *wc, int location, int value) { int i; int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value; long mdio_addr = 0x0048; /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Shift the command bits out. */ for (i = 31; i >= 0; --i) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } return; } static int wctc4xxp_wait_for_link(struct wcdte *wc) { int reg; unsigned int delay_count = 0; do { reg = wctc4xxp_getctl(wc, 0x00fc); msleep(2); delay_count++; if (delay_count >= 5000) { dev_err(&wc->pdev->dev, "Failed to link to DTE processor!\n"); return -EIO; } } while ((reg & 0xE0000000) != 0xE0000000); return 0; } static int wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware) { unsigned int byteloc; unsigned int length; struct tcb *cmd; byteloc = 17; cmd = alloc_cmd(SFRAME_SIZE); if (!cmd) return -ENOMEM; #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_enable_polling(wc); #endif while (byteloc < (firmware->size-20)) { length = (firmware->data[byteloc] << 8) | firmware->data[byteloc+1]; byteloc += 2; cmd->data_len = length; BUG_ON(length > cmd->data_len); memcpy(cmd->data, &firmware->data[byteloc], length); byteloc += length; cmd->flags = WAIT_FOR_ACK; wctc4xxp_transmit_cmd(wc, cmd); wait_for_completion(&cmd->complete); if (cmd->flags & DTE_CMD_TIMEOUT) { free_cmd(cmd); dev_err(&wc->pdev->dev, "Failed to load firmware.\n"); #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_disable_polling(wc); #endif return -EIO; } } free_cmd(cmd); if (!wait_event_timeout(wc->waitq, wctc4xxp_is_ready(wc), 15*HZ)) { dev_err(&wc->pdev->dev, "Failed to boot firmware.\n"); #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_disable_polling(wc); #endif return -EIO; } #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_disable_polling(wc); #endif return 0; } static int wctc4xxp_turn_off_booted_led(struct wcdte *wc) { int ret = 0; int reg; /* Turn off auto negotiation */ wctc4xxp_write_phy(wc, 0, 0x2100); DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n", wctc4xxp_read_phy(wc, 0)); /* Set reset */ wctc4xxp_setctl(wc, 0x00A0, 0x04000000); /* Wait 4 ms to ensure processor reset */ msleep(4); /* Clear reset */ wctc4xxp_setctl(wc, 0x00A0, 0x04080000); /* Wait for the ethernet link */ ret = wctc4xxp_wait_for_link(wc); if (ret) return ret; /* Turn off booted LED */ wctc4xxp_setctl(wc, 0x00A0, 0x04084000); reg = wctc4xxp_getctl(wc, 0x00fc); DTE_DEBUG(DTE_DEBUG_GENERAL, "LINK STATUS: reg(0xfc) = %X\n", reg); reg = wctc4xxp_getctl(wc, 0x00A0); return ret; } static void wctc4xxp_turn_on_booted_led(struct wcdte *wc) { wctc4xxp_setctl(wc, 0x00A0, 0x04080000); } static int wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware) { int ret; wctc4xxp_turn_off_booted_led(wc); ret = wctc4xxp_load_firmware(wc, firmware); if (ret) return ret; wctc4xxp_turn_on_booted_led(wc); DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n"); return 0; } static int setup_half_channel(struct channel_pvt *pvt, struct tcb *cmd, u16 length) { if (send_set_ip_hdr_channel_cmd(pvt, cmd)) return -EIO; if (send_voip_vceopt_cmd(pvt, cmd, length)) return -EIO; if (send_voip_tonectl_cmd(pvt, cmd)) return -EIO; if (send_voip_dtmfopt_cmd(pvt, cmd)) return -EIO; if (send_voip_indctrl_cmd(pvt, cmd)) return -EIO; return 0; } static int wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, u8 simple, u8 complicated) { struct channel_pvt *encoder_pvt, *decoder_pvt; u16 encoder_timeslot, decoder_timeslot; u16 encoder_channel, decoder_channel; u16 length; struct tcb *cmd; cmd = alloc_cmd(SFRAME_SIZE); if (!cmd) return -ENOMEM; BUG_ON(!wc || !cpvt); if (cpvt->encoder) { encoder_timeslot = cpvt->timeslot_in_num; decoder_timeslot = cpvt->timeslot_out_num; } else { u8 temp; encoder_timeslot = cpvt->timeslot_out_num; decoder_timeslot = cpvt->timeslot_in_num; temp = simple; simple = complicated; complicated = temp; } BUG_ON(encoder_timeslot/2 >= wc->numchannels); BUG_ON(decoder_timeslot/2 >= wc->numchannels); encoder_pvt = wc->uencode->channels[encoder_timeslot/2].pvt; decoder_pvt = wc->udecode->channels[decoder_timeslot/2].pvt; BUG_ON(!encoder_pvt); BUG_ON(!decoder_pvt); WARN_ON(encoder_timeslot == decoder_timeslot); /* First, let's create two channels, one for the simple -> complex * encoder and another for the complex->simple decoder. */ if (send_create_channel_cmd(wc, cmd, encoder_timeslot, &encoder_channel)) goto error_exit; if (send_create_channel_cmd(wc, cmd, decoder_timeslot, &decoder_channel)) goto error_exit; DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "DTE is using the following channels encoder_channel: " \ "%d decoder_channel: %d\n", encoder_channel, decoder_channel); length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH : (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0; WARN_ON(encoder_channel == decoder_channel); /* Now set all the default parameters for the encoder. */ encoder_pvt->chan_in_num = encoder_channel; encoder_pvt->chan_out_num = decoder_channel; if (setup_half_channel(encoder_pvt, cmd, length)) goto error_exit; /* And likewise for the decoder. */ decoder_pvt->chan_in_num = decoder_channel; decoder_pvt->chan_out_num = encoder_channel; if (setup_half_channel(decoder_pvt, cmd, length)) goto error_exit; if (send_trans_connect_cmd(wc, cmd, encoder_channel, decoder_channel, complicated, simple)) goto error_exit; if (send_voip_vopena_cmd(encoder_pvt, cmd, complicated)) goto error_exit; if (send_voip_vopena_cmd(decoder_pvt, cmd, simple)) goto error_exit; DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "DTE has completed setup and connected the " \ "two channels together.\n"); free_cmd(cmd); return 0; error_exit: free_cmd(cmd); return -EIO; } static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt) { struct dahdi_transcoder_channel *dtc1, *dtc2; struct channel_pvt *encoder_pvt, *decoder_pvt; int chan1, chan2, timeslot1, timeslot2; struct tcb *cmd; cmd = alloc_cmd(SFRAME_SIZE); if (!cmd) return -ENOMEM; if (cpvt->encoder) { chan1 = cpvt->chan_in_num; timeslot1 = cpvt->timeslot_in_num; chan2 = cpvt->chan_out_num; timeslot2 = cpvt->timeslot_out_num; } else { chan1 = cpvt->chan_out_num; timeslot1 = cpvt->timeslot_out_num; chan2 = cpvt->chan_in_num; timeslot2 = cpvt->timeslot_in_num; } if (timeslot1/2 >= wc->numchannels || timeslot2/2 >= wc->numchannels) { dev_warn(&wc->pdev->dev, "Invalid channel numbers in %s. chan1:%d chan2: %d\n", __func__, timeslot1/2, timeslot2/2); return 0; } dtc1 = &(wc->uencode->channels[timeslot1/2]); dtc2 = &(wc->udecode->channels[timeslot2/2]); encoder_pvt = dtc1->pvt; decoder_pvt = dtc2->pvt; if (send_voip_vopena_close_cmd(encoder_pvt, cmd)) goto error_exit; if (send_voip_vopena_close_cmd(decoder_pvt, cmd)) goto error_exit; if (send_trans_disconnect_cmd(wc, cmd, chan1, chan2, 0, 0)) goto error_exit; if (send_destroy_channel_cmd(wc, cmd, chan1)) goto error_exit; if (send_destroy_channel_cmd(wc, cmd, chan2)) goto error_exit; free_cmd(cmd); return 0; error_exit: free_cmd(cmd); return -1; } static int __wctc4xxp_setup_channels(struct wcdte *wc) { struct tcb *cmd; int tdm_bus; cmd = alloc_cmd(SFRAME_SIZE); if (!cmd) return -ENOMEM; if (send_set_arm_clk_cmd(wc, cmd)) goto error_exit; if (send_set_spu_clk_cmd(wc, cmd)) goto error_exit; if (send_tdm_select_bus_mode_cmd(wc, cmd)) goto error_exit; for (tdm_bus = 0; tdm_bus < 4; ++tdm_bus) { if (send_supvsr_setup_tdm_parms(wc, cmd, tdm_bus)) goto error_exit; } if (send_set_eth_header_cmd(wc, cmd, src_mac, dst_mac)) goto error_exit; if (send_ip_service_config_cmd(wc, cmd)) goto error_exit; if (send_arp_service_config_cmd(wc, cmd)) goto error_exit; if (send_icmp_service_config_cmd(wc, cmd)) goto error_exit; if (send_device_set_country_code_cmd(wc, cmd)) goto error_exit; if (send_spu_features_control_cmd(wc, cmd, 0x02)) goto error_exit; if (send_ip_options_cmd(wc, cmd)) goto error_exit; if (send_spu_features_control_cmd(wc, cmd, 0x04)) goto error_exit; if (send_tdm_opt_cmd(wc, cmd)) goto error_exit; free_cmd(cmd); return 0; error_exit: free_cmd(cmd); return -1; } static int wctc4xxp_setup_channels(struct wcdte *wc) { int ret; #ifndef DEBUG_WCTC4XXP down(&wc->chansem); #else if (down_interruptible(&wc->chansem)) return -EINTR; #endif ret = __wctc4xxp_setup_channels(wc); up(&wc->chansem); return ret; } static void wctc4xxp_setup_file_operations(struct file_operations *fops) { fops->owner = THIS_MODULE; fops->read = wctc4xxp_read; fops->write = wctc4xxp_write; } static int initialize_channel_pvt(struct wcdte *wc, int encoder, struct channel_pvt **cpvt) { int chan; *cpvt = kmalloc(sizeof(struct channel_pvt) * wc->numchannels, GFP_KERNEL); if (!(*cpvt)) return -ENOMEM; for (chan = 0; chan < wc->numchannels; ++chan) wctc4xxp_init_state((*cpvt) + chan, encoder, chan, wc); return 0; } static int initialize_transcoder(struct wcdte *wc, unsigned int srcfmts, unsigned int dstfmts, struct channel_pvt *pvts, struct dahdi_transcoder **zt) { int chan; *zt = dahdi_transcoder_alloc(wc->numchannels); if (!(*zt)) return -ENOMEM; (*zt)->srcfmts = srcfmts; (*zt)->dstfmts = dstfmts; (*zt)->allocate = wctc4xxp_operation_allocate; (*zt)->release = wctc4xxp_operation_release; wctc4xxp_setup_file_operations(&((*zt)->fops)); for (chan = 0; chan < wc->numchannels; ++chan) (*zt)->channels[chan].pvt = &pvts[chan]; return 0; } static int initialize_encoders(struct wcdte *wc, unsigned int complexfmts) { int res; res = initialize_channel_pvt(wc, 1, &wc->encoders); if (res) return res; res = initialize_transcoder(wc, DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW, complexfmts, wc->encoders, &wc->uencode); if (res) return res; sprintf(wc->uencode->name, "DTE Encoder"); return res; } static int initialize_decoders(struct wcdte *wc, unsigned int complexfmts) { int res; res = initialize_channel_pvt(wc, 0, &wc->decoders); if (res) return res; res = initialize_transcoder(wc, complexfmts, DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW, wc->decoders, &wc->udecode); if (res) return res; sprintf(wc->udecode->name, "DTE Decoder"); return res; } static void wctc4xxp_send_commands(struct wcdte *wc, struct list_head *to_send) { struct tcb *cmd; while (!list_empty(to_send)) { cmd = container_of(to_send->next, struct tcb, node); list_del_init(&cmd->node); wctc4xxp_transmit_cmd(wc, cmd); } } static void wctc4xxp_watchdog(unsigned long data) { struct wcdte *wc = (struct wcdte *)data; struct tcb *cmd, *temp; LIST_HEAD(cmds_to_retry); const int MAX_RETRIES = 5; int reschedule_timer = 0; service_tx_ring(wc); spin_lock(&wc->cmd_list_lock); /* Go through the list of messages that are waiting for responses from * the DTE, and complete or retry any that have timed out. */ list_for_each_entry_safe(cmd, temp, &wc->waiting_for_response_list, node) { if (time_after(jiffies, cmd->timeout)) { if (++cmd->retries > MAX_RETRIES) { if (!(cmd->flags & TX_COMPLETE)) { cmd->flags |= DTE_CMD_TIMEOUT; list_del_init(&cmd->node); complete(&cmd->complete); set_bit(DTE_SHUTDOWN, &wc->flags); spin_unlock(&wc->cmd_list_lock); _wctc4xxp_stop_dma(wc); dev_err(&wc->pdev->dev, "Board malfunctioning. " \ "Halting operation.\n"); reschedule_timer = 0; spin_lock(&wc->cmd_list_lock); break; } /* ERROR: We've retried the command and * haven't received the ACK or the response. */ cmd->flags |= DTE_CMD_TIMEOUT; list_del_init(&cmd->node); complete(&cmd->complete); } else if (cmd->flags & TX_COMPLETE) { /* Move this to the local list because we're * going to resend it once we free the locks */ list_move_tail(&cmd->node, &cmds_to_retry); cmd->flags &= ~(TX_COMPLETE); } else { /* The command is still sitting on the tx * descriptor ring. We don't want to move it * off any lists, lets just reset the timeout * and tell the hardware to look for another * command . */ dev_warn(&wc->pdev->dev, "Retrying command that was " \ "still on descriptor list.\n"); cmd->timeout = jiffies + HZ/4; wctc4xxp_transmit_demand_poll(wc); reschedule_timer = 1; } } } spin_unlock(&wc->cmd_list_lock); if (list_empty(&cmds_to_retry) && reschedule_timer) mod_timer(&wc->watchdog, jiffies + HZ/2); else if (!list_empty(&cmds_to_retry)) wctc4xxp_send_commands(wc, &cmds_to_retry); } /** * Insert an struct wcdte on the global list in sorted order * */ static int __devinit wctc4xxp_add_to_device_list(struct wcdte *wc) { struct wcdte *cur; int pos = 0; INIT_LIST_HEAD(&wc->node); spin_lock(&wctc4xxp_list_lock); list_for_each_entry(cur, &wctc4xxp_list, node) { if (cur->pos != pos) { /* Add the new entry before the one here */ list_add_tail(&wc->node, &cur->node); break; } else { ++pos; } } /* If we didn't already add the new entry to the list, add it now */ if (list_empty(&wc->node)) list_add_tail(&wc->node, &wctc4xxp_list); spin_unlock(&wctc4xxp_list_lock); return pos; } static void wctc4xxp_remove_from_device_list(struct wcdte *wc) { spin_lock(&wctc4xxp_list_lock); list_del(&wc->node); spin_unlock(&wctc4xxp_list_lock); } struct wctc4xxp_desc { const char *short_name; const char *long_name; }; static struct wctc4xxp_desc wctc400p = { .short_name = "tc400b", .long_name = "Wildcard TC400P+TC400M", }; static struct wctc4xxp_desc wctce400 = { .short_name = "tce400", .long_name = "Wildcard TCE400+TC400M", }; static int __devinit wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res, reg, position_on_list; struct wcdte *wc = NULL; struct wctc4xxp_desc *d = (struct wctc4xxp_desc *)ent->driver_data; unsigned char g729_numchannels, g723_numchannels, min_numchannels; unsigned char wctc4xxp_firmware_ver, wctc4xxp_firmware_ver_minor; unsigned int complexfmts; struct firmware embedded_firmware; const struct firmware *firmware = &embedded_firmware; #if !defined(HOTPLUG_FIRMWARE) extern void _binary_dahdi_fw_tc400m_bin_size; extern u8 _binary_dahdi_fw_tc400m_bin_start[]; #else static const char tc400m_firmware[] = "dahdi-fw-tc400m.bin"; #endif /* ------------------------------------------------------------------ * Setup the pure software constructs internal to this driver. * --------------------------------------------------------------- */ wc = kzalloc(sizeof(*wc), GFP_KERNEL); if (!wc) return -ENOMEM; position_on_list = wctc4xxp_add_to_device_list(wc); snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d", d->short_name, position_on_list); wc->iobase = pci_iomap(pdev, 1, 0); wc->pdev = pdev; wc->pos = position_on_list; wc->variety = d->long_name; wc->last_rx_seq_num = -1; if (!request_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), wc->board_name)) { dev_err(&pdev->dev, "IO Registers are in use by another " "module.\n"); wctc4xxp_remove_from_device_list(wc); kfree(wc); return -EIO; } sema_init(&wc->chansem, 1); spin_lock_init(&wc->reglock); spin_lock_init(&wc->cmd_list_lock); spin_lock_init(&wc->rx_list_lock); spin_lock_init(&wc->rx_lock); INIT_LIST_HEAD(&wc->cmd_list); INIT_LIST_HEAD(&wc->waiting_for_response_list); INIT_LIST_HEAD(&wc->rx_list); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&wc->deferred_work, deferred_work_func, wc); #else INIT_WORK(&wc->deferred_work, deferred_work_func); #endif init_waitqueue_head(&wc->waitq); if (pci_set_dma_mask(wc->pdev, DMA_BIT_MASK(32))) { release_mem_region(pci_resource_start(wc->pdev, 1), pci_resource_len(wc->pdev, 1)); if (wc->iobase) pci_iounmap(wc->pdev, wc->iobase); dev_warn(&wc->pdev->dev, "No suitable DMA available.\n"); return -EIO; } wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL); if (!wc->txd) { res = -ENOMEM; goto error_exit_swinit; } res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd, 0xe0800000, DMA_TO_DEVICE); if (res) goto error_exit_swinit; wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL); if (!wc->rxd) { res = -ENOMEM; goto error_exit_swinit; } res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0, DMA_FROM_DEVICE); if (res) goto error_exit_swinit; #if defined(HOTPLUG_FIRMWARE) res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev); if (res || !firmware) { dev_err(&wc->pdev->dev, "Firmware %s not available from userspace. (%d)\n", tc400m_firmware, res); goto error_exit_swinit; } #else embedded_firmware.data = _binary_dahdi_fw_tc400m_bin_start; embedded_firmware.size = (size_t) &_binary_dahdi_fw_tc400m_bin_size; #endif wctc4xxp_firmware_ver = firmware->data[0]; wctc4xxp_firmware_ver_minor = firmware->data[16]; g729_numchannels = firmware->data[1]; g723_numchannels = firmware->data[2]; min_numchannels = min(g723_numchannels, g729_numchannels); if (!mode || strlen(mode) < 4) { sprintf(wc->complexname, "G.729a / G.723.1"); complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1; wc->numchannels = min_numchannels; } else if (mode[3] == '9') { /* "G.729" */ sprintf(wc->complexname, "G.729a"); complexfmts = DAHDI_FORMAT_G729A; wc->numchannels = g729_numchannels; } else if (mode[3] == '3') { /* "G.723.1" */ sprintf(wc->complexname, "G.723.1"); complexfmts = DAHDI_FORMAT_G723_1; wc->numchannels = g723_numchannels; } else { sprintf(wc->complexname, "G.729a / G.723.1"); complexfmts = DAHDI_FORMAT_G729A | DAHDI_FORMAT_G723_1; wc->numchannels = min_numchannels; } res = initialize_encoders(wc, complexfmts); if (res) goto error_exit_swinit; res = initialize_decoders(wc, complexfmts); if (res) goto error_exit_swinit; if (DTE_DEBUG_NETWORK_IF & debug) { res = wctc4xxp_net_register(wc); if (res) goto error_exit_swinit; } # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) wc->watchdog.function = wctc4xxp_watchdog; wc->watchdog.data = (unsigned long)wc; init_timer(&wc->watchdog); # else setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc); # endif # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) wc->polling.function = wctc4xxp_polling; wc->polling.data = (unsigned long)wc; init_timer(&wc->polling); # else setup_timer(&wc->polling, wctc4xxp_polling, (unsigned long)wc); # endif /* ------------------------------------------------------------------ * Load the firmware and start the DTE. * --------------------------------------------------------------- */ res = pci_enable_device(pdev); if (res) { dev_err(&wc->pdev->dev, "Failed to enable device.\n"); goto error_exit_swinit;; } pci_set_master(pdev); pci_set_drvdata(pdev, wc); res = request_irq(pdev->irq, wctc4xxp_interrupt, DAHDI_IRQ_SHARED, wc->board_name, wc); if (res) { dev_err(&wc->pdev->dev, "Unable to request IRQ %d\n", pdev->irq); if (firmware != &embedded_firmware) release_firmware(firmware); goto error_exit_hwinit; } res = wctc4xxp_hardware_init(wc); if (res) { if (firmware != &embedded_firmware) release_firmware(firmware); goto error_exit_hwinit; } wctc4xxp_enable_interrupts(wc); wctc4xxp_start_dma(wc); res = wctc4xxp_boot_processor(wc, firmware); if (firmware != &embedded_firmware) release_firmware(firmware); if (res) goto error_exit_hwinit; #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_enable_polling(wc); #endif res = wctc4xxp_setup_channels(wc); if (res) goto error_exit_hwinit; /* \todo Read firmware version directly from tc400b.*/ dev_info(&wc->pdev->dev, "(%s) Transcoder support LOADED " \ "(firm ver = %d.%d)\n", wc->complexname, wctc4xxp_firmware_ver, wctc4xxp_firmware_ver_minor); reg = wctc4xxp_getctl(wc, 0x00fc); DTE_DEBUG(DTE_DEBUG_GENERAL, "debug: (post-boot) Reg fc is %08x\n", reg); dev_info(&wc->pdev->dev, "Installed a Wildcard TC: %s\n", wc->variety); DTE_DEBUG(DTE_DEBUG_GENERAL, "Operating in DEBUG mode.\n"); dahdi_transcoder_register(wc->uencode); dahdi_transcoder_register(wc->udecode); return 0; error_exit_hwinit: #if defined(CONFIG_WCTC4XXP_POLLING) wctc4xxp_disable_polling(wc); #endif wctc4xxp_stop_dma(wc); wctc4xxp_cleanup_command_list(wc); free_irq(pdev->irq, wc); pci_set_drvdata(pdev, NULL); error_exit_swinit: wctc4xxp_net_unregister(wc); kfree(wc->encoders); kfree(wc->decoders); dahdi_transcoder_free(wc->uencode); dahdi_transcoder_free(wc->udecode); wctc4xxp_cleanup_descriptor_ring(wc->txd); kfree(wc->txd); wctc4xxp_cleanup_descriptor_ring(wc->rxd); kfree(wc->rxd); release_mem_region(pci_resource_start(wc->pdev, 1), pci_resource_len(wc->pdev, 1)); if (wc->iobase) pci_iounmap(wc->pdev, wc->iobase); wctc4xxp_remove_from_device_list(wc); kfree(wc); return res; } static void wctc4xxp_cleanup_channels(struct wcdte *wc) { int i; struct dahdi_transcoder_channel *dtc_en, *dtc_de; for (i = 0; i < wc->numchannels; ++i) { dtc_en = &(wc->uencode->channels[i]); wctc4xxp_cleanup_channel_private(wc, dtc_en); dtc_de = &(wc->udecode->channels[i]); wctc4xxp_cleanup_channel_private(wc, dtc_de); } } static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev) { struct wcdte *wc = pci_get_drvdata(pdev); if (!wc) return; wctc4xxp_remove_from_device_list(wc); set_bit(DTE_SHUTDOWN, &wc->flags); if (del_timer_sync(&wc->watchdog)) del_timer_sync(&wc->watchdog); /* This should already be stopped, but it doesn't hurt to make sure. */ clear_bit(DTE_POLLING, &wc->flags); if (del_timer_sync(&wc->polling)) del_timer_sync(&wc->polling); wctc4xxp_net_unregister(wc); /* Stop any DMA */ wctc4xxp_stop_dma(wc); /* In case hardware is still there */ wctc4xxp_disable_interrupts(wc); free_irq(pdev->irq, wc); /* There isn't anything that would run in the workqueue that will wait * on an interrupt. */ dahdi_transcoder_unregister(wc->udecode); dahdi_transcoder_unregister(wc->uencode); /* Free Resources */ release_mem_region(pci_resource_start(wc->pdev, 1), pci_resource_len(wc->pdev, 1)); if (wc->iobase) pci_iounmap(wc->pdev, wc->iobase); wctc4xxp_cleanup_descriptor_ring(wc->txd); kfree(wc->txd); wctc4xxp_cleanup_descriptor_ring(wc->rxd); kfree(wc->rxd); wctc4xxp_cleanup_command_list(wc); wctc4xxp_cleanup_channels(wc); pci_set_drvdata(pdev, NULL); dahdi_transcoder_free(wc->uencode); dahdi_transcoder_free(wc->udecode); kfree(wc->encoders); kfree(wc->decoders); kfree(wc); } static DEFINE_PCI_DEVICE_TABLE(wctc4xxp_pci_tbl) = { { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */ { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */ { 0 } }; MODULE_DEVICE_TABLE(pci, wctc4xxp_pci_tbl); static int wctc4xxp_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } static struct pci_driver wctc4xxp_driver = { .name = "wctc4xxp", .probe = wctc4xxp_init_one, .remove = __devexit_p(wctc4xxp_remove_one), .id_table = wctc4xxp_pci_tbl, .suspend = wctc4xxp_suspend, }; static int __init wctc4xxp_init(void) { int res; unsigned long cache_flags; #if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)) cache_flags = SLAB_HWCACHE_ALIGN | SLAB_STORE_USER | SLAB_DEBUG_FREE; #else cache_flags = SLAB_HWCACHE_ALIGN; #endif # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, cache_flags, NULL, NULL); # else cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, cache_flags, NULL); # endif if (!cmd_cache) return -ENOMEM; spin_lock_init(&wctc4xxp_list_lock); INIT_LIST_HEAD(&wctc4xxp_list); res = dahdi_pci_module(&wctc4xxp_driver); if (res) { kmem_cache_destroy(cmd_cache); return -ENODEV; } return 0; } static void __exit wctc4xxp_cleanup(void) { pci_unregister_driver(&wctc4xxp_driver); kmem_cache_destroy(cmd_cache); } module_param(debug, int, S_IRUGO | S_IWUSR); module_param(mode, charp, S_IRUGO); MODULE_PARM_DESC(mode, "'g729', 'g723.1', or 'any'. Default 'any'."); MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver"); MODULE_AUTHOR("Digium Incorporated "); MODULE_LICENSE("GPL"); module_init(wctc4xxp_init); module_exit(wctc4xxp_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/wctc4xxp/Makefile0000644000175000017500000000026511046364366021776 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild else endif dahdi-linux-2.5.0.1/drivers/dahdi/wctc4xxp/Kbuild0000644000175000017500000000063411137730310021456 0ustar tzafrirtzafrirobj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP) += wctc4xxp.o FIRM_DIR := ../firmware EXTRA_CFLAGS += -I$(src)/.. -Wno-undef ifeq ($(HOTPLUG_FIRMWARE),yes) EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE endif wctc4xxp-objs := base.o ifneq ($(HOTPLUG_FIRMWARE),yes) wctc4xxp-objs += $(FIRM_DIR)/dahdi-fw-tc400m.o endif $(obj)/$(FIRM_DIR)/dahdi-fw-tc400m.o: $(obj)/base.o $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-tc400m.o dahdi-linux-2.5.0.1/drivers/dahdi/pciradio.c0000644000175000017500000014615011510412320020470 0ustar tzafrirtzafrir/* * PCI RADIO Card DAHDI Telephony PCI Quad Radio Interface driver * * Written by Jim Dixon * Based on previous work by Mark Spencer * Based on previous works, designs, and archetectures conceived and * written by Jim Dixon . * * Copyright (C) 2001-2007 Jim Dixon / Zapata Telephony. * * All rights reserved. * * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /* The PCI Radio Interface card interfaces up to 4 two-way radios (either a base/mobile radio or repeater system) to DAHDI channels. The driver may work either independent of an application, or with it, through the driver;s ioctl() interface. This file gives you access to specify load-time parameters for Radio channels, so that the driver may run by itself, and just act like a generic DAHDI radio interface. */ /* Latency tests: Without driver: 308496 With driver: 303826 (1.5 %) */ #include #include #include #include #include #include #include #include #include #include #include #define RAD_MAX_IFACES 128 #define NUM_CODES 15 #define SERIAL_BUFLEN 128 #define SRX_TIMEOUT 300 #define RAD_CNTL 0x00 #define RAD_OPER 0x01 #define RAD_AUXC 0x02 #define RAD_AUXD 0x03 #define XPGM 4 #define XCS 2 #define RAD_MASK0 0x04 #define RAD_MASK1 0x05 #define RAD_INTSTAT 0x06 #define RAD_AUXR 0x07 #define XINIT 8 #define XDONE 0x10 #define RAD_DMAWS 0x08 #define RAD_DMAWI 0x0c #define RAD_DMAWE 0x10 #define RAD_DMARS 0x18 #define RAD_DMARI 0x1c #define RAD_DMARE 0x20 #define RAD_AUXFUNC 0x2b #define RAD_SERCTL 0x2d #define RAD_FSCDELAY 0x2f #define RAD_REGBASE 0xc0 #define RAD_CTCSSMASK 0xf #define RAD_CTCSSOTHER 0xf #define RAD_CTCSSVALID 0x10 #define NUM_CHANS 4 #define RAD_GOTRX_DEBOUNCE_TIME 75 #define RAD_CTCSS_ACQUIRE_TIME 10 #define RAD_CTCSS_TALKOFF_TIME 1000 #define DAHDI_RADPAR_CTCSSACQUIRETIME 18 /* DEBUG only, this belongs in dahdi.h */ #define DAHDI_RADPAR_CTCSSTALKOFFTIME 19 /* DEBUG only, this belongs in dahdi.h */ /* * MX828 Commands */ #define MX828_GEN_RESET 0x01 /* W */ #define MX828_SAUDIO_CTRL 0x80 /* W */ #define MX828_SAUDIO_STATUS 0x81 /* R */ #define MX828_SAUDIO_SETUP 0x82 /* W */ #define MX828_TX_TONE 0x83 /* W16 */ #define MX828_RX_TONE 0x84 /* W16 */ #define MX828_DCS3 0x85 /* W */ #define MX828_DCS2 0x86 /* W */ #define MX828_DCS1 0x87 /* W */ #define MX828_GEN_CTRL 0x88 /* W */ #define MX828_GPT 0x8B /* W */ #define MX828_IRQ_MASK 0x8E /* W */ #define MX828_SELCALL 0x8D /* W16 */ #define MX828_AUD_CTRL 0x8A /* W16 */ #define MX828_IRQ_FLAG 0x8F /* R */ struct encdec { unsigned char state; /* 0 = idle */ int chan; unsigned char req[NUM_CHANS]; unsigned char dcsrx[NUM_CHANS]; unsigned char ctrx[NUM_CHANS]; unsigned char dcstx[NUM_CHANS]; unsigned char cttx[NUM_CHANS]; unsigned char saudio_ctrl[NUM_CHANS]; unsigned char saudio_setup[NUM_CHANS]; unsigned char txcode[NUM_CHANS]; unsigned long lastcmd; int myindex[NUM_CHANS]; unsigned long waittime; unsigned char retstate; } ; struct pciradio { struct pci_dev *dev; struct dahdi_span span; unsigned char ios; int usecount; unsigned int intcount; int dead; int pos; int freeregion; int nchans; spinlock_t lock; int remote_locked; unsigned char rxbuf[SERIAL_BUFLEN]; unsigned short rxindex; unsigned long srxtimer; unsigned char txbuf[SERIAL_BUFLEN]; unsigned short txindex; unsigned short txlen; unsigned char pasave; unsigned char pfsave; volatile unsigned long ioaddr; dma_addr_t readdma; dma_addr_t writedma; volatile unsigned int *writechunk; /* Double-word aligned write memory */ volatile unsigned int *readchunk; /* Double-word aligned read memory */ unsigned char saudio_status[NUM_CHANS]; char gotcor[NUM_CHANS]; char gotct[NUM_CHANS]; char newctcssstate[NUM_CHANS]; char ctcssstate[NUM_CHANS]; char gotrx[NUM_CHANS]; char gotrx1[NUM_CHANS]; char gottx[NUM_CHANS]; char lasttx[NUM_CHANS]; int gotrxtimer[NUM_CHANS]; int ctcsstimer[NUM_CHANS]; int debouncetime[NUM_CHANS]; int ctcssacquiretime[NUM_CHANS]; int ctcsstalkofftime[NUM_CHANS]; int bursttime[NUM_CHANS]; int bursttimer[NUM_CHANS]; unsigned char remmode[NUM_CHANS]; unsigned short present_code[NUM_CHANS]; unsigned short last_code[NUM_CHANS]; unsigned short rxcode[NUM_CHANS][NUM_CODES + 1]; unsigned short rxclass[NUM_CHANS][NUM_CODES + 1]; unsigned short txcode[NUM_CHANS][NUM_CODES + 1];; unsigned char radmode[NUM_CHANS]; #define RADMODE_INVERTCOR 1 #define RADMODE_IGNORECOR 2 #define RADMODE_EXTTONE 4 #define RADMODE_EXTINVERT 8 #define RADMODE_IGNORECT 16 #define RADMODE_NOENCODE 32 unsigned char corthresh[NUM_CHANS]; struct dahdi_chan _chans[NUM_CHANS]; struct dahdi_chan *chans; unsigned char mx828_addr; struct encdec encdec; unsigned long lastremcmd; }; static struct pciradio *ifaces[RAD_MAX_IFACES]; static void pciradio_release(struct pciradio *rad); static int debug = 0; struct tonedef { int code; unsigned char b1; unsigned char b2; } ; #include "radfw.h" static struct tonedef cttable_tx [] = { {0,0,0}, {670,0xE,0xB1}, {693,0xE,0x34}, {719,0xD,0xB1}, {744,0xD,0x3B}, {770,0xC,0xC9}, {797,0xC,0x5A}, {825,0xB,0xEF}, {854,0xB,0x87}, {885,0xB,0x1F}, {915,0xA,0xC2}, {948,0xA,0x62}, {974,0xA,0x1B}, {1000,0x9,0xD8}, {1035,0x9,0x83}, {1072,0x9,0x2F}, {1109,0x8,0xE0}, {1148,0x8,0x93}, {1188,0x8,0x49}, {1230,0x8,0x1}, {1273,0x7,0xBC}, {1318,0x7,0x78}, {1365,0x7,0x36}, {1413,0x6,0xF7}, {1462,0x6,0xBC}, {1514,0x6,0x80}, {1567,0x6,0x48}, {1598,0x6,0x29}, {1622,0x6,0x12}, {1679,0x5,0xDD}, {1738,0x5,0xAA}, {1799,0x5,0x79}, {1835,0x5,0x5D}, {1862,0x5,0x49}, {1899,0x5,0x2F}, {1928,0x5,0x1B}, {1966,0x5,0x2}, {1995,0x4,0xEF}, {2035,0x4,0xD6}, {2065,0x4,0xC4}, {2107,0x4,0xAC}, {2181,0x4,0x83}, {2257,0x4,0x5D}, {2291,0x4,0x4C}, {2336,0x4,0x37}, {2418,0x4,0x12}, {2503,0x3,0xEF}, {2541,0x3,0xE0}, {0,0,0} } ; static struct tonedef cttable_rx [] = { {0,0,0}, {670,0x3,0xD8}, {693,0x4,0x9}, {719,0x4,0x1B}, {744,0x4,0x4E}, {770,0x4,0x83}, {797,0x4,0x94}, {825,0x4,0xCB}, {854,0x5,0x2}, {885,0x5,0x14}, {915,0x5,0x4C}, {948,0x5,0x87}, {974,0x5,0x94}, {1000,0x5,0xCB}, {1035,0x6,0x7}, {1072,0x6,0x45}, {1109,0x6,0x82}, {1148,0x6,0xC0}, {1188,0x6,0xD1}, {1230,0x7,0x10}, {1273,0x7,0x50}, {1318,0x7,0xC0}, {1365,0x8,0x2}, {1413,0x8,0x44}, {1462,0x8,0x86}, {1514,0x8,0xC9}, {1567,0x9,0xC}, {1598,0x9,0x48}, {1622,0x9,0x82}, {1679,0x9,0xC6}, {1738,0xA,0xB}, {1799,0xA,0x84}, {1835,0xA,0xC2}, {1862,0xA,0xC9}, {1899,0xB,0x8}, {1928,0xB,0x44}, {1966,0xB,0x83}, {1995,0xB,0x8A}, {2035,0xB,0xC9}, {2065,0xC,0x6}, {2107,0xC,0x46}, {2181,0xC,0xC3}, {2257,0xD,0x41}, {2291,0xD,0x48}, {2336,0xD,0x89}, {2418,0xE,0x8}, {2503,0xE,0x88}, {2541,0xE,0xC7}, {0,0,0} }; static struct { int code; char b3; char b2; char b1; } dcstable[] = { {0,0,0,0}, {23,0x76,0x38,0x13}, {25,0x6B,0x78,0x15}, {26,0x65,0xD8,0x16}, {31,0x51,0xF8,0x19}, {32,0x5F,0x58,0x1A}, {43,0x5B,0x68,0x23}, {47,0x0F,0xD8,0x27}, {51,0x7C,0xA8,0x29}, {54,0x6F,0x48,0x2C}, {65,0x5D,0x18,0x35}, {71,0x67,0x98,0x39}, {72,0x69,0x38,0x3A}, {73,0x2E,0x68,0x3B}, {74,0x74,0x78,0x3C}, {114,0x35,0xE8,0x4C}, {115,0x72,0xB8,0x4D}, {116,0x7C,0x18,0x4E}, {125,0x07,0xB8,0x55}, {131,0x3D,0x38,0x59}, {132,0x33,0x98,0x5A}, {134,0x2E,0xD8,0x5C}, {143,0x37,0xA8,0x63}, {152,0x1E,0xC8,0x6A}, {155,0x44,0xD8,0x6D}, {156,0x4A,0x78,0x6E}, {162,0x6B,0xC8,0x72}, {165,0x31,0xD8,0x75}, {172,0x05,0xF8,0x7A}, {174,0x18,0xB8,0x7C}, {205,0x6E,0x98,0x85}, {223,0x68,0xE8,0x93}, {226,0x7B,0x08,0x96}, {243,0x45,0xB8,0xA3}, {244,0x1F,0xA8,0xA4}, {245,0x58,0xF8,0xA5}, {251,0x62,0x78,0xA9}, {261,0x17,0x78,0xB1}, {263,0x5E,0x88,0xB3}, {265,0x43,0xC8,0xB5}, {271,0x79,0x48,0xB9}, {306,0x0C,0xF8,0xC6}, {311,0x38,0xD8,0xC9}, {315,0x6C,0x68,0xCD}, {331,0x23,0xE8,0xD9}, {343,0x29,0x78,0xE3}, {346,0x3A,0x98,0xE6}, {351,0x0E,0xB8,0xE9}, {364,0x68,0x58,0xF4}, {365,0x2F,0x08,0xF5}, {371,0x15,0x88,0xF9}, {411,0x77,0x69,0x09}, {412,0x79,0xC9,0x0A}, {413,0x3E,0x99,0x0B}, {423,0x4B,0x99,0x13}, {431,0x6C,0x59,0x19}, {432,0x62,0xF9,0x1A}, {445,0x7B,0x89,0x25}, {464,0x27,0xE9,0x34}, {465,0x60,0xB9,0x35}, {466,0x6E,0x19,0x36}, {503,0x3C,0x69,0x43}, {506,0x2F,0x89,0x46}, {516,0x41,0xB9,0x4E}, {532,0x0E,0x39,0x5A}, {546,0x19,0xE9,0x66}, {565,0x0C,0x79,0x75}, {606,0x5D,0x99,0x86}, {612,0x67,0x19,0x8A}, {624,0x0F,0x59,0x94}, {627,0x01,0xF9,0x97}, {631,0x72,0x89,0x99}, {632,0x7C,0x29,0x9A}, {654,0x4C,0x39,0xAC}, {662,0x24,0x79,0xB2}, {664,0x39,0x39,0xB4}, {703,0x22,0xB9,0xC3}, {712,0x0B,0xD9,0xCA}, {723,0x39,0x89,0xD3}, {731,0x1E,0x49,0xD9}, {732,0x10,0xE9,0xDA}, {734,0x0D,0xA9,0xDC}, {743,0x14,0xD9,0xE3}, {754,0x20,0xF9,0xEC}, {0,0,0,0} }; static int gettxtone(int code) { int i; if (!code) return(0); for(i = 0; cttable_tx[i].code || (!i); i++) { if (cttable_tx[i].code == code) { return (i); } } return(-1); } static int getrxtone(int code) { int i; if (!code) return(0); for(i = 0; cttable_rx[i].code || (!i); i++) { if (cttable_rx[i].code == code) { return (i); } } return(-1); } static int getdcstone(int code) { int i; if (!code) return(0); for(i = 0; dcstable[i].code || (!i); i++) { if (dcstable[i].code == code) { return (i); } } return(-1); } static void __pciradio_setcreg(struct pciradio *rad, unsigned char reg, unsigned char val) { outb(val, rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2)); } static unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg) { return inb(rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2)); } static void rbi_out(struct pciradio *rad, int n, unsigned char *rbicmd) { unsigned long flags; int x; DECLARE_WAIT_QUEUE_HEAD(mywait); for(;;) { spin_lock_irqsave(&rad->lock,flags); x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2); if (!x) rad->remote_locked = 1; spin_unlock_irqrestore(&rad->lock,flags); if (x) interruptible_sleep_on_timeout(&mywait,2); else break; } spin_lock_irqsave(&rad->lock,flags); /* enable and address RBI serializer */ __pciradio_setcreg(rad,0xf,rad->pfsave | (n << 4) | 0x40); /* output commands */ for(x = 0; x < 5; x++) __pciradio_setcreg(rad,0xc,rbicmd[x]); /* output it */ __pciradio_setcreg(rad,0xb,1); rad->remote_locked = 0; spin_unlock_irqrestore(&rad->lock,flags); return; } /* * Output a command to the MX828 over the serial bus */ static void mx828_command(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2) { if(channel > 3) return; rad->mx828_addr = channel; __pciradio_setcreg(rad,0,channel); if (byte1) __pciradio_setcreg(rad,1,*byte1); if (byte2) __pciradio_setcreg(rad,2,*byte2); __pciradio_setcreg(rad,3,command); } static void mx828_command_wait(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2) { DECLARE_WAIT_QUEUE_HEAD(mywait); unsigned long flags; spin_lock_irqsave(&rad->lock,flags); while(rad->encdec.state) { spin_unlock_irqrestore(&rad->lock,flags); interruptible_sleep_on_timeout(&mywait,2); spin_lock_irqsave(&rad->lock,flags); } rad->encdec.lastcmd = jiffies + 1000; spin_unlock_irqrestore(&rad->lock,flags); while(__pciradio_getcreg(rad,0xc) & 1); rad->encdec.lastcmd = jiffies + 1000; spin_lock_irqsave(&rad->lock,flags); rad->encdec.lastcmd = jiffies + 1000; mx828_command(rad,channel,command,byte1,byte2); spin_unlock_irqrestore(&rad->lock,flags); rad->encdec.lastcmd = jiffies + 1000; while(__pciradio_getcreg(rad,0xc) & 1); rad->encdec.lastcmd = jiffies; } static void _do_encdec(struct pciradio *rad) { int i,n; unsigned char byte1 = 0,byte2 = 0; /* return doing nothing if busy */ if ((rad->encdec.lastcmd + 2) > jiffies) return; if (__pciradio_getcreg(rad,0xc) & 1) return; n = 0; byte2 = 0; switch(rad->encdec.state) { case 0: for(i = 0; i < rad->nchans; i++) { n = (unsigned)(i - rad->intcount) % rad->nchans; if (rad->encdec.req[n]) break; } if (i >= rad->nchans) return; rad->encdec.req[n] = 0; rad->encdec.dcsrx[n] = 0; rad->encdec.ctrx[n] = 0; rad->encdec.dcstx[n] = 0; rad->encdec.cttx[n] = 0; rad->encdec.myindex[n] = 0; rad->encdec.req[n] = 0; rad->encdec.chan = n; /* if something in code 0 for rx, is DCS */ if (rad->rxcode[n][0]) rad->encdec.dcsrx[n] = 1; else { /* otherwise, if something in other codes, is CT rx */ for(i = 1; i <= NUM_CODES; i++) { if (rad->rxcode[n][1]) rad->encdec.ctrx[n] = 1; } } /* get index for tx code. Will be 0 if not receiving a CT */ rad->encdec.myindex[n] = 0; if (rad->gotrx[n] && rad->encdec.ctrx[n] && (rad->present_code[n])) rad->encdec.myindex[n] = rad->present_code[n]; /* get actual tx code from array */ rad->encdec.txcode[n] = rad->txcode[n][rad->encdec.myindex[n]]; if (rad->encdec.txcode[n] & 0x8000) rad->encdec.dcstx[n] = 1; else if (rad->encdec.txcode[n]) rad->encdec.cttx[n] = 1; if (rad->radmode[n] & RADMODE_NOENCODE) rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0; if ((!rad->gottx[n]) || rad->bursttimer[n]) rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0; rad->encdec.saudio_ctrl[n] = 0; rad->encdec.saudio_setup[n] = 0; rad->encdec.state = 1; break; case 1: if (rad->encdec.dcstx[rad->encdec.chan] && (!rad->encdec.dcsrx[rad->encdec.chan])) /* if to transmit DCS */ { rad->encdec.saudio_setup[rad->encdec.chan] |= 3; rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80; byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b1; mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 ); rad->encdec.state = 2; break; } rad->encdec.state = 4; break; case 2: byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b2; mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 ); rad->encdec.state = 3; break; case 3: byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b3; mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 ); rad->encdec.state = 4; break; case 4: if (rad->encdec.cttx[rad->encdec.chan]) { rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80; byte1 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b1; byte2 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b2; mx828_command(rad,rad->encdec.chan, MX828_TX_TONE, &byte1, &byte2 ); } rad->encdec.state = 5; break; case 5: if (rad->encdec.dcsrx[rad->encdec.chan]) { rad->encdec.saudio_setup[rad->encdec.chan] |= 1; rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x41; byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b1; mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 ); rad->encdec.state = 6; break; } rad->encdec.state = 8; break; case 6: byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b2; mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 ); rad->encdec.state = 7; break; case 7: byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b3; mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 ); rad->encdec.state = 8; break; case 8: if (rad->encdec.ctrx[rad->encdec.chan]) { rad->encdec.saudio_setup[rad->encdec.chan] |= 0x80; rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x60; } byte1 = rad->encdec.saudio_setup[rad->encdec.chan]; mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_SETUP, &byte1, &byte2 ); rad->encdec.state = 9; break; case 9: byte1 = rad->encdec.saudio_ctrl[rad->encdec.chan]; mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_CTRL, &byte1, &byte2 ); rad->encdec.state = 10; break; case 10: rad->encdec.chan = 0; rad->encdec.state = 0; break; } } static inline void pciradio_transmitprep(struct pciradio *rad, unsigned char ints) { volatile unsigned int *writechunk; int x; if (ints & 0x01) /* Write is at interrupt address. Start writing from normal offset */ writechunk = rad->writechunk; else writechunk = rad->writechunk + DAHDI_CHUNKSIZE; /* Calculate Transmission */ dahdi_transmit(&rad->span); for (x=0;xchans[0].writechunk[x] << 24); writechunk[x] |= (rad->chans[1].writechunk[x] << 16); writechunk[x] |= (rad->chans[2].writechunk[x] << 8); writechunk[x] |= (rad->chans[3].writechunk[x]); } } static inline void pciradio_receiveprep(struct pciradio *rad, unsigned char ints) { volatile unsigned int *readchunk; int x; if (ints & 0x08) readchunk = rad->readchunk + DAHDI_CHUNKSIZE; else /* Read is at interrupt address. Valid data is available at normal offset */ readchunk = rad->readchunk; for (x=0;xchans[0].readchunk[x] = (readchunk[x] >> 24) & 0xff; rad->chans[1].readchunk[x] = (readchunk[x] >> 16) & 0xff; rad->chans[2].readchunk[x] = (readchunk[x] >> 8) & 0xff; rad->chans[3].readchunk[x] = (readchunk[x]) & 0xff; } for (x=0;xnchans;x++) { dahdi_ec_chunk(&rad->chans[x], rad->chans[x].readchunk, rad->chans[x].writechunk); } dahdi_receive(&rad->span); } static void pciradio_stop_dma(struct pciradio *rad); static void pciradio_reset_serial(struct pciradio *rad); static void pciradio_restart_dma(struct pciradio *rad); #ifdef LEAVE_THIS_COMMENTED_OUT static irqreturn_t pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif DAHDI_IRQ_HANDLER(pciradio_interrupt) { struct pciradio *rad = dev_id; unsigned char ints,byte1,byte2,gotcor,gotctcss,gotslowctcss,ctcss; int i,x,gotrx; ints = inb(rad->ioaddr + RAD_INTSTAT); outb(ints, rad->ioaddr + RAD_INTSTAT); if (!ints) return IRQ_NONE; if (ints & 0x10) { /* Stop DMA, wait for watchdog */ printk(KERN_INFO "RADIO PCI Master abort\n"); pciradio_stop_dma(rad); return IRQ_RETVAL(1); } if (ints & 0x20) { printk(KERN_INFO "RADIO PCI Target abort\n"); return IRQ_RETVAL(1); } if (ints & 0x0f) { rad->intcount++; x = rad->intcount % rad->nchans; /* freeze */ __pciradio_setcreg(rad,0,rad->mx828_addr | 4); /* read SAUDIO_STATUS for the proper channel */ byte1 = rad->saudio_status[x] = __pciradio_getcreg(rad,x); /* thaw */ __pciradio_setcreg(rad,0,rad->mx828_addr); /* get COR input */ byte2 = __pciradio_getcreg(rad,9); /* get bit for this channel */ gotcor = byte2 & (1 << x); if (rad->radmode[x] & RADMODE_INVERTCOR) gotcor = !gotcor; rad->gotcor[x] = gotcor; if (rad->radmode[x] & RADMODE_IGNORECOR) gotcor = 1; gotslowctcss = 0; if ((byte1 & RAD_CTCSSVALID) && ((byte1 & RAD_CTCSSMASK) != RAD_CTCSSOTHER)) gotslowctcss = 1; gotctcss = 1; ctcss = 0; /* set ctcss to 1 if decoding ctcss */ if (!rad->rxcode[x][0]) { for(i = 1; i <= NUM_CODES; i++) { if (rad->rxcode[x][i]) { ctcss = 1; break; } } } if (ctcss) { if ((!(byte1 & 0x40)) || ((!rad->gotrx[x]) && (!gotslowctcss))) gotctcss = 0; } rad->present_code[x] = 0; if (rad->rxcode[x][0]) { if (byte1 & 0x80) gotctcss = gotslowctcss = 1; else gotctcss = 0; } else if (gotslowctcss) rad->present_code[x] = (byte1 & RAD_CTCSSMASK) + 1; if (rad->radmode[x] & RADMODE_EXTTONE) { unsigned mask = 1 << (x + 4); /* they're on the UIOB's */ unsigned char byteuio; /* set UIOB as input */ byteuio = __pciradio_getcreg(rad,0xe); byteuio |= mask; __pciradio_setcreg(rad,0xe,byteuio); /* get UIO input */ byteuio = __pciradio_getcreg(rad,8); if (rad->radmode[x] & RADMODE_EXTINVERT) gotctcss = gotslowctcss = ((byteuio & mask) == 0); else gotctcss = gotslowctcss = ((byteuio & mask) != 0); } rad->gotct[x] = gotslowctcss; if ((rad->radmode[x] & RADMODE_IGNORECT) || ((!(rad->radmode[x] & RADMODE_EXTTONE)) && (!ctcss))) { gotctcss = 1; gotslowctcss = 1; rad->present_code[x] = 0; } if(rad->newctcssstate[x] != gotctcss){ rad->newctcssstate[x] = gotctcss; if(rad->newctcssstate[x]) rad->ctcsstimer[x]=rad->ctcssacquiretime[x]; else rad->ctcsstimer[x]=rad->ctcsstalkofftime[x]; } else{ if(!rad->ctcsstimer[x]) rad->ctcssstate[x] = rad->newctcssstate[x]; else rad->ctcsstimer[x]--; } gotrx = gotcor && rad->ctcssstate[x]; if (gotrx != rad->gotrx[x]) { rad->gotrxtimer[x] = rad->debouncetime[x]; } rad->gotrx[x] = gotrx; if (rad->present_code[x] != rad->last_code[x]) { rad->encdec.req[x] = 1; rad->last_code[x] = rad->present_code[x]; } _do_encdec(rad); for(x = 0; x < rad->nchans; x++) { unsigned char mask = 1 << x; if (rad->gottx[x] != rad->lasttx[x]) { if (rad->gottx[x]) { rad->bursttimer[x] = 0; rad->pasave |= mask; __pciradio_setcreg(rad, 0xa, rad->pasave); } else { if (!rad->bursttime[x]) { rad->pasave &= ~mask; __pciradio_setcreg(rad, 0xa, rad->pasave); } else { rad->bursttimer[x] = rad->bursttime[x]; } } rad->encdec.req[x] = 1; rad->lasttx[x] = rad->gottx[x]; } if (rad->bursttimer[x]) { /* if just getting to zero */ if (!(--rad->bursttimer[x])) { rad->pasave &= ~mask; __pciradio_setcreg(rad, 0xa, rad->pasave); } } /* if timer active */ if (rad->gotrxtimer[x]) { /* if just getting to zero */ if (!(--rad->gotrxtimer[x])) { mask = 1 << (x + 4); rad->pasave &= ~mask; if (gotctcss) rad->pasave |= mask; __pciradio_setcreg(rad, 0xa, rad->pasave); if (rad->gotrx[x] != rad->gotrx1[x]) { if (rad->gotrx[x]) { if (debug) { if (rad->present_code[x]) printk(KERN_DEBUG "Chan %d got rx (ctcss code %d)\n",x + 1, cttable_rx[rad->rxcode[x][rad->present_code[x]]].code); else printk(KERN_DEBUG "Chan %d got rx\n",x + 1); } dahdi_hooksig(&rad->chans[x],DAHDI_RXSIG_OFFHOOK); } else { if (debug) printk(KERN_DEBUG "Chan %d lost rx\n",x + 1); dahdi_hooksig(&rad->chans[x],DAHDI_RXSIG_ONHOOK); } rad->encdec.req[x] = 1; } rad->gotrx1[x] = rad->gotrx[x]; } } } /* process serial if any */ /* send byte if there is one in buffer to send */ if (rad->txlen && (rad->txlen != rad->txindex)) { /* if tx not busy */ if (!(__pciradio_getcreg(rad,9) & 0x80)) { __pciradio_setcreg(rad, 4, rad->txbuf[rad->txindex++]); } } rad->srxtimer++; /* if something in rx to read */ while(__pciradio_getcreg(rad,9) & 0x10) { unsigned char c = __pciradio_getcreg(rad,4); rad->srxtimer = 0; if (rad->rxindex < RAD_SERIAL_BUFLEN) { rad->rxbuf[rad->rxindex++] = c; } udelay(1); } pciradio_receiveprep(rad, ints); pciradio_transmitprep(rad, ints); i = 0; for(x = 0; x < 4; x++) { if (rad->gottx[x]) i |= (1 << (x * 2)); if (rad->gotrx[x]) i |= (2 << (x * 2)); } /* output LED's */ __pciradio_setcreg(rad, 9, i); } return IRQ_RETVAL(1); } static int pciradio_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { int i,mycode; unsigned long flags; unsigned char byte1,byte2,mask; union { struct dahdi_radio_stat s; struct dahdi_radio_param p; } stack; struct pciradio *rad = chan->pvt; DECLARE_WAIT_QUEUE_HEAD(mywait); switch (cmd) { case DAHDI_RADIO_GETPARAM: if (copy_from_user(&stack.p, (__user void *) data, sizeof(stack.p))) return -EFAULT; spin_lock_irqsave(&rad->lock,flags); stack.p.data = 0; /* start with 0 value in output */ switch(stack.p.radpar) { case DAHDI_RADPAR_INVERTCOR: if (rad->radmode[chan->chanpos - 1] & RADMODE_INVERTCOR) stack.p.data = 1; break; case DAHDI_RADPAR_IGNORECOR: if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR) stack.p.data = 1; break; case DAHDI_RADPAR_IGNORECT: if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECT) stack.p.data = 1; break; case DAHDI_RADPAR_NOENCODE: if (rad->radmode[chan->chanpos - 1] & RADMODE_NOENCODE) stack.p.data = 1; break; case DAHDI_RADPAR_CORTHRESH: stack.p.data = rad->corthresh[chan->chanpos - 1] & 7; break; case DAHDI_RADPAR_EXTRXTONE: if (rad->radmode[chan->chanpos - 1] & RADMODE_EXTTONE) { stack.p.data = 1; if (rad->radmode[chan->chanpos - 1] & RADMODE_EXTINVERT) { stack.p.data = 2; } } break; case DAHDI_RADPAR_NUMTONES: stack.p.data = NUM_CODES; break; case DAHDI_RADPAR_RXTONE: if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } stack.p.data = cttable_rx[rad->rxcode[chan->chanpos - 1][stack.p.index] & 0x7fff].code; break; case DAHDI_RADPAR_RXTONECLASS: if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } stack.p.data = rad->rxclass[chan->chanpos - 1][stack.p.index] & 0xffff; break; case DAHDI_RADPAR_TXTONE: if (stack.p.index > NUM_CODES) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } stack.p.data = cttable_tx[rad->txcode[chan->chanpos - 1][stack.p.index] & 0x7fff].code; /* if a DCS tone, return as such */ if (rad->txcode[chan->chanpos - 1][stack.p.index] & 0x8000) stack.p.data |= 0x8000; break; case DAHDI_RADPAR_DEBOUNCETIME: stack.p.data = rad->debouncetime[chan->chanpos - 1]; break; case DAHDI_RADPAR_CTCSSACQUIRETIME: stack.p.data = rad->ctcssacquiretime[chan->chanpos - 1]; break; case DAHDI_RADPAR_CTCSSTALKOFFTIME: stack.p.data = rad->ctcsstalkofftime[chan->chanpos - 1]; break; case DAHDI_RADPAR_BURSTTIME: stack.p.data = rad->bursttime[chan->chanpos - 1]; break; case DAHDI_RADPAR_UIODATA: stack.p.data = 0; byte1 = __pciradio_getcreg(rad,8); if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1; if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2; break; case DAHDI_RADPAR_UIOMODE: stack.p.data = 0; byte1 = __pciradio_getcreg(rad,0xe); if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1; if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2; break; case DAHDI_RADPAR_REMMODE: stack.p.data = rad->remmode[chan->chanpos - 1]; break; default: spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } spin_unlock_irqrestore(&rad->lock,flags); if (copy_to_user((__user void *) data, &stack.p, sizeof(stack.p))) return -EFAULT; break; case DAHDI_RADIO_SETPARAM: if (copy_from_user(&stack.p, (__user void *) data, sizeof(stack.p))) return -EFAULT; spin_lock_irqsave(&rad->lock,flags); switch(stack.p.radpar) { case DAHDI_RADPAR_INVERTCOR: if (stack.p.data) rad->radmode[chan->chanpos - 1] |= RADMODE_INVERTCOR; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_INVERTCOR; break; case DAHDI_RADPAR_IGNORECOR: if (stack.p.data) rad->radmode[chan->chanpos - 1] |= RADMODE_IGNORECOR; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECOR; break; case DAHDI_RADPAR_IGNORECT: if (stack.p.data) rad->radmode[chan->chanpos - 1] |= RADMODE_IGNORECT; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECT; break; case DAHDI_RADPAR_NOENCODE: if (stack.p.data) rad->radmode[chan->chanpos - 1] |= RADMODE_NOENCODE; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_NOENCODE; break; case DAHDI_RADPAR_CORTHRESH: if ((stack.p.data < 0) || (stack.p.data > 7)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } rad->corthresh[chan->chanpos - 1] = stack.p.data; byte1 = 0xc0 | (rad->corthresh[chan->chanpos - 1] << 2); spin_unlock_irqrestore(&rad->lock,flags); mx828_command_wait(rad,chan->chanpos - 1, MX828_GEN_CTRL, &byte1, &byte2); spin_lock_irqsave(&rad->lock,flags); break; case DAHDI_RADPAR_EXTRXTONE: if (stack.p.data) rad->radmode[chan->chanpos - 1] |= RADMODE_EXTTONE; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_EXTTONE; if (stack.p.data > 1) rad->radmode[chan->chanpos - 1] |= RADMODE_EXTINVERT; else rad->radmode[chan->chanpos - 1] &= ~RADMODE_EXTINVERT; break; case DAHDI_RADPAR_INITTONE: for(i = 0; i <= NUM_CODES; i++) { rad->rxcode[chan->chanpos - 1][i] = 0; rad->rxclass[chan->chanpos - 1][i] = 0; rad->txcode[chan->chanpos - 1][i] = 0; } spin_unlock_irqrestore(&rad->lock,flags); for(i = 0; i < NUM_CODES; i++) { /* set to no encode/decode */ byte1 = 0; mx828_command_wait(rad,chan->chanpos - 1, MX828_SAUDIO_CTRL, &byte1, &byte2 ); /* set rx tone to none */ byte1 = i << 4; byte2 = 0; mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); } spin_lock_irqsave(&rad->lock,flags); break; case DAHDI_RADPAR_RXTONE: if (!stack.p.index) /* if RX DCS mode */ { if ((stack.p.data < 0) || (stack.p.data > 777)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } mycode = getdcstone(stack.p.data); if (mycode < 0) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } rad->rxcode[chan->chanpos - 1][0] = mycode; rad->encdec.req[chan->chanpos - 1] = 1; break; } if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } mycode = getrxtone(stack.p.data); if (mycode < 0) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } rad->rxcode[chan->chanpos - 1][stack.p.index] = mycode; byte1 = cttable_rx[mycode].b1 | ((stack.p.index - 1) << 4); byte2 = cttable_rx[mycode].b2; spin_unlock_irqrestore(&rad->lock,flags); mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); spin_lock_irqsave(&rad->lock,flags); /* zot out DCS one if there */ rad->rxcode[chan->chanpos - 1][0] = 0; rad->encdec.req[chan->chanpos - 1] = 1; break; case DAHDI_RADPAR_RXTONECLASS: if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } rad->rxclass[chan->chanpos - 1][stack.p.index] = stack.p.data & 0xffff; break; case DAHDI_RADPAR_TXTONE: if (stack.p.index > NUM_CODES) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } if (stack.p.data & 0x8000) /* if dcs */ mycode = getdcstone(stack.p.data & 0x7fff); else mycode = gettxtone(stack.p.data); if (mycode < 0) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } if (stack.p.data & 0x8000) mycode |= 0x8000; rad->txcode[chan->chanpos - 1][stack.p.index] = mycode; rad->encdec.req[chan->chanpos - 1] = 1; break; case DAHDI_RADPAR_DEBOUNCETIME: rad->debouncetime[chan->chanpos - 1] = stack.p.data; break; case DAHDI_RADPAR_CTCSSACQUIRETIME: rad->ctcssacquiretime[chan->chanpos - 1] = stack.p.data; break; case DAHDI_RADPAR_CTCSSTALKOFFTIME: rad->ctcsstalkofftime[chan->chanpos - 1] = stack.p.data; break; case DAHDI_RADPAR_BURSTTIME: rad->bursttime[chan->chanpos - 1] = stack.p.data; break; case DAHDI_RADPAR_UIODATA: byte1 = __pciradio_getcreg(rad,8); byte1 &= ~(1 << (chan->chanpos - 1)); byte1 &= ~(1 << (chan->chanpos + 3)); if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1)); if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3)); __pciradio_setcreg(rad,8,byte1); break; case DAHDI_RADPAR_UIOMODE: byte1 = __pciradio_getcreg(rad,0xe); byte1 &= ~(1 << (chan->chanpos - 1)); byte1 &= ~(1 << (chan->chanpos + 3)); if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1)); if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3)); __pciradio_setcreg(rad,0xe,byte1); break; case DAHDI_RADPAR_REMMODE: rad->remmode[chan->chanpos - 1] = stack.p.data; break; case DAHDI_RADPAR_REMCOMMAND: /* if no remote mode, return an error */ if (rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_NONE) { spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } i = 0; if (rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_RBI1) { /* set UIOA and UIOB for output */ byte1 = __pciradio_getcreg(rad,0xe); mask = (1 << (chan->chanpos - 1)) | (1 << (chan->chanpos + 3)); byte2 = byte1 & (~mask); i = (byte2 != byte1); __pciradio_setcreg(rad,0xe,byte2); byte1 = __pciradio_getcreg(rad,8); mask = 1 << (chan->chanpos - 1); byte2 = byte1 | mask; i = (byte2 != byte1); __pciradio_setcreg(rad,8,byte2); spin_unlock_irqrestore(&rad->lock,flags); if (i || (jiffies < rad->lastremcmd + 10)) interruptible_sleep_on_timeout(&mywait,10); rad->lastremcmd = jiffies; rbi_out(rad,chan->chanpos - 1,(unsigned char *)&stack.p.data); spin_lock_irqsave(&rad->lock,flags); break; } spin_unlock_irqrestore(&rad->lock,flags); for(;;) { int x; spin_lock_irqsave(&rad->lock,flags); x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2); if (!x) rad->remote_locked = 1; spin_unlock_irqrestore(&rad->lock,flags); if (x) interruptible_sleep_on_timeout(&mywait,2); else break; } spin_lock_irqsave(&rad->lock,flags); /* set UIOA for input and UIOB for output */ byte1 = __pciradio_getcreg(rad,0xe); mask = 1 << (chan->chanpos + 3); /* B an output */ byte2 = byte1 & (~mask); byte2 |= 1 << (chan->chanpos - 1); /* A in input */ __pciradio_setcreg(rad,0xe,byte2); byte1 = __pciradio_getcreg(rad,8); byte2 = byte1 | mask; byte2 |= 1 << (chan->chanpos - 1); byte2 |= 1 << (chan->chanpos + 3); __pciradio_setcreg(rad,8,byte2); spin_unlock_irqrestore(&rad->lock,flags); if (byte1 != byte2) interruptible_sleep_on_timeout(&mywait,3); while (jiffies < rad->lastremcmd + 10) interruptible_sleep_on_timeout(&mywait,10); rad->lastremcmd = jiffies; for(;;) { if (!(__pciradio_getcreg(rad,0xc) & 2)) break; interruptible_sleep_on_timeout(&mywait,2); } spin_lock_irqsave(&rad->lock,flags); /* enable and address async serializer */ __pciradio_setcreg(rad,0xf,rad->pfsave | ((chan->chanpos - 1) << 4) | 0x80); /* copy tx buffer */ memcpy(rad->txbuf,stack.p.buf,stack.p.index); rad->txlen = stack.p.index; rad->txindex = 0; rad->rxindex = 0; rad->srxtimer = 0; memset(stack.p.buf,0,SERIAL_BUFLEN); stack.p.index = 0; if (stack.p.data) for(;;) { rad->rxbuf[rad->rxindex] = 0; if ((rad->rxindex < stack.p.data) && (rad->srxtimer < SRX_TIMEOUT) && ((rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_SERIAL) || (!strchr((char *)rad->rxbuf,'\r')))) { spin_unlock_irqrestore(&rad->lock,flags); interruptible_sleep_on_timeout(&mywait,2); spin_lock_irqsave(&rad->lock,flags); continue; } memset(stack.p.buf,0,SERIAL_BUFLEN); if (stack.p.data && (rad->rxindex > stack.p.data)) rad->rxindex = stack.p.data; if (rad->rxindex) memcpy(stack.p.buf,rad->rxbuf,rad->rxindex); stack.p.index = rad->rxindex; break; } /* wait for done if in SERIAL_ASCII mode, or if no Rx aftwards */ if ((rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_SERIAL_ASCII) || (!stack.p.data)) { /* wait for TX to be done if not already */ while(rad->txlen && (rad->txindex < rad->txlen)) { spin_unlock_irqrestore(&rad->lock,flags); interruptible_sleep_on_timeout(&mywait,2); spin_lock_irqsave(&rad->lock,flags); } /* disable and un-address async serializer */ __pciradio_setcreg(rad,0xf,rad->pfsave); } rad->remote_locked = 0; spin_unlock_irqrestore(&rad->lock,flags); if (rad->remmode[chan->chanpos - 1] == DAHDI_RADPAR_REM_SERIAL_ASCII) interruptible_sleep_on_timeout(&mywait,100); if (copy_to_user((__user void *) data, &stack.p, sizeof(stack.p))) return -EFAULT; return 0; default: spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; } spin_unlock_irqrestore(&rad->lock,flags); break; case DAHDI_RADIO_GETSTAT: spin_lock_irqsave(&rad->lock,flags); /* start with clean object */ memset(&stack.s, 0, sizeof(stack.s)); /* if we have rx */ if (rad->gotrx[chan->chanpos - 1]) { stack.s.radstat |= DAHDI_RADSTAT_RX; if (rad->rxcode[chan->chanpos - 1][0]) stack.s.ctcode_rx = dcstable[rad->rxcode[chan->chanpos - 1][0]].code | 0x8000; else { stack.s.ctcode_rx = cttable_rx[rad->rxcode[chan->chanpos - 1][rad->present_code[chan->chanpos - 1]]].code; stack.s.ctclass = rad->rxclass[chan->chanpos - 1][rad->present_code[chan->chanpos - 1]]; } } /* if we have tx */ if (rad->gottx[chan->chanpos - 1]) { unsigned short x,myindex; stack.s.radstat |= DAHDI_RADSTAT_TX; stack.s.radstat |= DAHDI_RADSTAT_TX; myindex = 0; if ((!rad->rxcode[chan->chanpos - 1][0]) && (rad->present_code[chan->chanpos - 1])) myindex = rad->present_code[chan->chanpos - 1]; x = rad->txcode[chan->chanpos - 1][myindex]; if (x & 0x8000) stack.s.ctcode_tx = dcstable[x & 0x7fff].code | 0x8000; else stack.s.ctcode_tx = cttable_tx[x].code; } if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR) stack.s.radstat |= DAHDI_RADSTAT_IGNCOR; if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECT) stack.s.radstat |= DAHDI_RADSTAT_IGNCT; if (rad->radmode[chan->chanpos - 1] & RADMODE_NOENCODE) stack.s.radstat |= DAHDI_RADSTAT_NOENCODE; if (rad->gotcor[chan->chanpos - 1]) stack.s.radstat |= DAHDI_RADSTAT_RXCOR; if (rad->gotct[chan->chanpos - 1]) stack.s.radstat |= DAHDI_RADSTAT_RXCT; spin_unlock_irqrestore(&rad->lock,flags); if (copy_to_user((__user void *) data, &stack.s, sizeof(stack.s))) return -EFAULT; break; default: return -ENOTTY; } return 0; } static int pciradio_open(struct dahdi_chan *chan) { struct pciradio *rad = chan->pvt; if (rad->dead) return -ENODEV; rad->usecount++; return 0; } static int pciradio_watchdog(struct dahdi_span *span, int event) { printk(KERN_INFO "PCI RADIO: Restarting DMA\n"); pciradio_restart_dma(container_of(span, struct pciradio, span)); return 0; } static int pciradio_close(struct dahdi_chan *chan) { struct pciradio *rad = chan->pvt; rad->usecount--; /* If we're dead, release us now */ if (!rad->usecount && rad->dead) pciradio_release(rad); return 0; } static int pciradio_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct pciradio *rad = chan->pvt; switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: rad->gottx[chan->chanpos - 1] = 1; break; case DAHDI_TXSIG_ONHOOK: rad->gottx[chan->chanpos - 1] = 0; break; default: printk(KERN_DEBUG "pciradio: Can't set tx state to %d\n", txsig); break; } if (debug) printk(KERN_DEBUG "pciradio: Setting Radio hook state to %d on chan %d\n", txsig, chan->chanpos); return 0; } static const struct dahdi_span_ops pciradio_span_ops = { .owner = THIS_MODULE, .hooksig = pciradio_hooksig, .open = pciradio_open, .close = pciradio_close, .ioctl = pciradio_ioctl, .watchdog = pciradio_watchdog, }; static int pciradio_initialize(struct pciradio *rad) { int x; /* DAHDI stuff */ sprintf(rad->span.name, "PCIRADIO/%d", rad->pos); sprintf(rad->span.desc, "Board %d", rad->pos + 1); rad->span.deflaw = DAHDI_LAW_MULAW; for (x=0;xnchans;x++) { sprintf(rad->chans[x].name, "PCIRADIO/%d/%d", rad->pos, x); rad->chans[x].sigcap = DAHDI_SIG_SF | DAHDI_SIG_EM; rad->chans[x].chanpos = x+1; rad->chans[x].pvt = rad; rad->debouncetime[x] = RAD_GOTRX_DEBOUNCE_TIME; rad->ctcssacquiretime[x] = RAD_CTCSS_ACQUIRE_TIME; rad->ctcsstalkofftime[x] = RAD_CTCSS_TALKOFF_TIME; } rad->span.chans = &rad->chans; rad->span.channels = rad->nchans; rad->span.flags = DAHDI_FLAG_RBS; rad->span.ops = &pciradio_span_ops; if (dahdi_register(&rad->span, 0)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } return 0; } static void wait_just_a_bit(int foo) { long newjiffies; newjiffies = jiffies + foo; while(jiffies < newjiffies); } static int pciradio_hardware_init(struct pciradio *rad) { unsigned char byte1,byte2; int x; unsigned long endjif; /* Signal Reset */ outb(0x01, rad->ioaddr + RAD_CNTL); /* Reset PCI Interface chip and registers (and serial) */ outb(0x06, rad->ioaddr + RAD_CNTL); /* Setup our proper outputs */ rad->ios = 0xfe; outb(rad->ios, rad->ioaddr + RAD_AUXD); /* Set all to outputs except AUX 3 & 4, which are inputs */ outb(0x67, rad->ioaddr + RAD_AUXC); /* Select alternate function for AUX0 */ outb(0x4, rad->ioaddr + RAD_AUXFUNC); /* Wait 1/4 of a sec */ wait_just_a_bit(HZ/4); /* attempt to load the Xilinx Chip */ /* De-assert CS+Write */ rad->ios |= XCS; outb(rad->ios, rad->ioaddr + RAD_AUXD); /* Assert PGM */ rad->ios &= ~XPGM; outb(rad->ios, rad->ioaddr + RAD_AUXD); /* wait for INIT and DONE to go low */ endjif = jiffies + 10; while (inb(rad->ioaddr + RAD_AUXR) & (XINIT | XDONE) && (jiffies <= endjif)); if (endjif < jiffies) { printk(KERN_DEBUG "Timeout waiting for INIT and DONE to go low\n"); return -1; } if (debug) printk(KERN_DEBUG "fwload: Init and done gone to low\n"); /* De-assert PGM */ rad->ios |= XPGM; outb(rad->ios, rad->ioaddr + RAD_AUXD); /* wait for INIT to go high (clearing done */ endjif = jiffies + 10; while (!(inb(rad->ioaddr + RAD_AUXR) & XINIT) && (jiffies <= endjif)); if (endjif < jiffies) { printk(KERN_DEBUG "Timeout waiting for INIT to go high\n"); return -1; } if (debug) printk(KERN_DEBUG "fwload: Init went high (clearing done)\nNow loading...\n"); /* Assert CS+Write */ rad->ios &= ~XCS; outb(rad->ios, rad->ioaddr + RAD_AUXD); for (x = 0; x < sizeof(radfw); x++) { /* write the byte */ outb(radfw[x],rad->ioaddr + RAD_REGBASE); /* if DONE signal, we're done, exit */ if (inb(rad->ioaddr + RAD_AUXR) & XDONE) break; /* if INIT drops, we're screwed, exit */ if (!(inb(rad->ioaddr + RAD_AUXR) & XINIT)) break; } if (debug) printk(KERN_DEBUG "fwload: Transferred %d bytes into chip\n",x); /* Wait for FIFO to clear */ endjif = jiffies + 2; while (jiffies < endjif); /* wait */ printk(KERN_DEBUG "Transfered %d bytes into chip\n",x); /* De-assert CS+Write */ rad->ios |= XCS; outb(rad->ios, rad->ioaddr + RAD_AUXD); if (debug) printk(KERN_INFO "fwload: Loading done!\n"); /* Wait for FIFO to clear */ endjif = jiffies + 2; while (jiffies < endjif); /* wait */ if (!(inb(rad->ioaddr + RAD_AUXR) & XINIT)) { printk(KERN_NOTICE "Drove Init low!! CRC Error!!!\n"); return -1; } if (!(inb(rad->ioaddr + RAD_AUXR) & XDONE)) { printk(KERN_INFO "Did not get DONE signal. Short file maybe??\n"); return -1; } wait_just_a_bit(2); /* get the thingy started */ outb(0,rad->ioaddr + RAD_REGBASE); outb(0,rad->ioaddr + RAD_REGBASE); printk(KERN_INFO "Xilinx Chip successfully loaded, configured and started!!\n"); wait_just_a_bit(HZ/4); /* Back to normal, with automatic DMA wrap around */ outb(0x30 | 0x01, rad->ioaddr + RAD_CNTL); /* Configure serial port for MSB->LSB operation */ outb(0xc1, rad->ioaddr + RAD_SERCTL); /* DEBUG set double dlck to 0 SR */ rad->pasave = 0; __pciradio_setcreg(rad,0xa,rad->pasave); __pciradio_setcreg(rad,0xf,rad->pfsave); __pciradio_setcreg(rad,8,0xff); __pciradio_setcreg(rad,0xe,0xff); __pciradio_setcreg(rad,9,0); rad->pfsave = 0; /* Delay FSC by 0 so it's properly aligned */ outb(/* 1 */ 0, rad->ioaddr + RAD_FSCDELAY); /* Setup DMA Addresses */ outl(rad->writedma, rad->ioaddr + RAD_DMAWS); /* Write start */ outl(rad->writedma + DAHDI_CHUNKSIZE * 4 - 4, rad->ioaddr + RAD_DMAWI); /* Middle (interrupt) */ outl(rad->writedma + DAHDI_CHUNKSIZE * 8 - 4, rad->ioaddr + RAD_DMAWE); /* End */ outl(rad->readdma, rad->ioaddr + RAD_DMARS); /* Read start */ outl(rad->readdma + DAHDI_CHUNKSIZE * 4 - 4, rad->ioaddr + RAD_DMARI); /* Middle (interrupt) */ outl(rad->readdma + DAHDI_CHUNKSIZE * 8 - 4, rad->ioaddr + RAD_DMARE); /* End */ /* Clear interrupts */ outb(0xff, rad->ioaddr + RAD_INTSTAT); /* Wait 1/4 of a second more */ wait_just_a_bit(HZ/4); for(x = 0; x < rad->nchans; x++) { mx828_command_wait(rad,x, MX828_GEN_RESET, &byte1, &byte2 ); byte1 = 0x3f; byte2 = 0x3f; mx828_command_wait(rad,x, MX828_AUD_CTRL, &byte1, &byte2 ); byte1 = 0; mx828_command_wait(rad,x, MX828_SAUDIO_SETUP, &byte1, &byte2 ); byte1 = 0; mx828_command_wait(rad,x, MX828_SAUDIO_CTRL, &byte1, &byte2 ); byte1 = 0xc8; /* default COR thresh is 2 */ mx828_command_wait(rad,x, MX828_GEN_CTRL, &byte1, &byte2); rad->corthresh[x] = 2; } /* Wait 1/4 of a sec */ wait_just_a_bit(HZ/4); return 0; } static void pciradio_enable_interrupts(struct pciradio *rad) { /* Enable interrupts (we care about all of them) */ outb(0x3f, rad->ioaddr + RAD_MASK0); /* No external interrupts */ outb(0x00, rad->ioaddr + RAD_MASK1); } static void pciradio_restart_dma(struct pciradio *rad) { /* Reset Master and serial */ outb(0x31, rad->ioaddr + RAD_CNTL); outb(0x01, rad->ioaddr + RAD_OPER); } static void pciradio_start_dma(struct pciradio *rad) { /* Reset Master and serial */ outb(0x3f, rad->ioaddr + RAD_CNTL); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); outb(0x31, rad->ioaddr + RAD_CNTL); outb(0x01, rad->ioaddr + RAD_OPER); } static void pciradio_stop_dma(struct pciradio *rad) { outb(0x00, rad->ioaddr + RAD_OPER); } static void pciradio_reset_serial(struct pciradio *rad) { /* Reset serial */ outb(0x3f, rad->ioaddr + RAD_CNTL); } static void pciradio_disable_interrupts(struct pciradio *rad) { outb(0x00, rad->ioaddr + RAD_MASK0); outb(0x00, rad->ioaddr + RAD_MASK1); } static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res; struct pciradio *rad; int x; static int initd_ifaces=0; if(initd_ifaces){ memset((void *)ifaces,0,(sizeof(struct pciradio *))*RAD_MAX_IFACES); initd_ifaces=1; } for (x=0;x= RAD_MAX_IFACES) { printk(KERN_NOTICE "Too many interfaces\n"); return -EIO; } if (pci_enable_device(pdev)) { res = -EIO; } else { rad = kmalloc(sizeof(struct pciradio), GFP_KERNEL); if (rad) { int i; ifaces[x] = rad; rad->chans = rad->_chans; memset(rad, 0, sizeof(struct pciradio)); spin_lock_init(&rad->lock); rad->nchans = 4; rad->ioaddr = pci_resource_start(pdev, 0); rad->dev = pdev; rad->pos = x; for(i = 0; i < rad->nchans; i++) rad->lasttx[x] = rad->gotrx1[i] = -1; /* Keep track of whether we need to free the region */ if (request_region(rad->ioaddr, 0xff, "pciradio")) rad->freeregion = 1; /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses 32 bits. Allocate an extra set just for control too */ rad->writechunk = pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &rad->writedma); if (!rad->writechunk) { printk(KERN_NOTICE "pciradio: Unable to allocate DMA-able memory\n"); if (rad->freeregion) release_region(rad->ioaddr, 0xff); return -ENOMEM; } rad->readchunk = rad->writechunk + DAHDI_MAX_CHUNKSIZE * 2; /* in doublewords */ rad->readdma = rad->writedma + DAHDI_MAX_CHUNKSIZE * 8; /* in bytes */ if (pciradio_initialize(rad)) { printk(KERN_INFO "pciradio: Unable to intialize\n"); /* Set Reset Low */ x=inb(rad->ioaddr + RAD_CNTL); outb((~0x1)&x, rad->ioaddr + RAD_CNTL); outb(x, rad->ioaddr + RAD_CNTL); __pciradio_setcreg(rad,8,0xff); __pciradio_setcreg(rad,0xe,0xff); /* Free Resources */ free_irq(pdev->irq, rad); if (rad->freeregion) release_region(rad->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma); kfree(rad); return -EIO; } /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, rad); if (pciradio_hardware_init(rad)) { /* Set Reset Low */ x=inb(rad->ioaddr + RAD_CNTL); outb((~0x1)&x, rad->ioaddr + RAD_CNTL); outb(x, rad->ioaddr + RAD_CNTL); __pciradio_setcreg(rad,8,0xff); __pciradio_setcreg(rad,0xe,0xff); /* Free Resources */ free_irq(pdev->irq, rad); if (rad->freeregion) release_region(rad->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma); pci_set_drvdata(pdev, NULL); dahdi_unregister(&rad->span); kfree(rad); return -EIO; } if (request_irq(pdev->irq, pciradio_interrupt, DAHDI_IRQ_SHARED, "pciradio", rad)) { printk(KERN_NOTICE "pciradio: Unable to request IRQ %d\n", pdev->irq); if (rad->freeregion) release_region(rad->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma); pci_set_drvdata(pdev, NULL); kfree(rad); return -EIO; } /* Enable interrupts */ pciradio_enable_interrupts(rad); /* Initialize Write/Buffers to all blank data */ memset((void *)rad->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 4); /* Start DMA */ pciradio_start_dma(rad); printk(KERN_INFO "Found a PCI Radio Card\n"); res = 0; } else res = -ENOMEM; } return res; } static void pciradio_release(struct pciradio *rad) { dahdi_unregister(&rad->span); if (rad->freeregion) release_region(rad->ioaddr, 0xff); kfree(rad); printk(KERN_INFO "Freed a PCI RADIO card\n"); } static void __devexit pciradio_remove_one(struct pci_dev *pdev) { struct pciradio *rad = pci_get_drvdata(pdev); if (rad) { /* Stop any DMA */ pciradio_stop_dma(rad); pciradio_reset_serial(rad); /* In case hardware is still there */ pciradio_disable_interrupts(rad); /* Immediately free resources */ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma); free_irq(pdev->irq, rad); /* Reset PCI chip and registers */ outb(0x3e, rad->ioaddr + RAD_CNTL); /* Clear Reset Line */ outb(0x3f, rad->ioaddr + RAD_CNTL); __pciradio_setcreg(rad,8,0xff); __pciradio_setcreg(rad,0xe,0xff); /* Release span, possibly delayed */ if (!rad->usecount) pciradio_release(rad); else rad->dead = 1; } } static DEFINE_PCI_DEVICE_TABLE(pciradio_pci_tbl) = { { 0xe159, 0x0001, 0xe16b, PCI_ANY_ID, 0, 0, (unsigned long)"PCIRADIO" }, { 0 } }; MODULE_DEVICE_TABLE(pci, pciradio_pci_tbl); static struct pci_driver pciradio_driver = { .name = "pciradio", .probe = pciradio_init_one, .remove = __devexit_p(pciradio_remove_one), .id_table = pciradio_pci_tbl, }; static int __init pciradio_init(void) { int res; res = dahdi_pci_module(&pciradio_driver); if (res) return -ENODEV; return 0; } static void __exit pciradio_cleanup(void) { pci_unregister_driver(&pciradio_driver); } module_param(debug, int, 0600); MODULE_DESCRIPTION("DAHDI Telephony PCI Radio Card Driver"); MODULE_AUTHOR("Jim Dixon "); MODULE_LICENSE("GPL v2"); module_init(pciradio_init); module_exit(pciradio_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_sec2.c0000644000175000017500000002503511500234716022353 0ustar tzafrirtzafrir/* * SpanDSP - a series of DSP components for telephony * * echo.c - An echo cancellor, suitable for electrical and acoustic * cancellation. This code does not currently comply with * any relevant standards (e.g. G.164/5/7/8). One day.... * * Written by Steve Underwood * * Copyright (C) 2001 Steve Underwood * * Based on a bit from here, a bit from there, eye of toad, * ear of bat, etc - plus, of course, my own 2 cents. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /* TODO: Finish the echo suppressor option, however nasty suppression may be Add an option to reintroduce side tone at -24dB under appropriate conditions. Improve double talk detector (iterative!) */ #include #include #include #include #include #include #include #include static int debug; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk(KERN_DEBUG "%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) #include "fir.h" #ifndef NULL #define NULL 0 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!FALSE) #endif #define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */ /* * According to Jim... */ #define MIN_TX_POWER_FOR_ADAPTION 512 #define MIN_RX_POWER_FOR_ADAPTION 64 /* * According to Steve... */ /* #define MIN_TX_POWER_FOR_ADAPTION 4096 #define MIN_RX_POWER_FOR_ADAPTION 64 */ static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static const char *name = "SEC2"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, }; struct ec_pvt { struct dahdi_echocan_state dahdi; int tx_power; int rx_power; int clean_rx_power; int rx_power_threshold; int nonupdate_dwell; fir16_state_t fir_state; int16_t *fir_taps16; /* 16-bit version of FIR taps */ int32_t *fir_taps32; /* 32-bit version of FIR taps */ int curr_pos; int taps; int tap_mask; int use_nlp; int use_suppressor; int32_t supp_test1; int32_t supp_test2; int32_t supp1; int32_t supp2; int32_t latest_correction; /* Indication of the magnitude of the latest adaption, or a code to indicate why adaption was skipped, for test purposes */ }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct ec_pvt *pvt; size_t size; if (ecp->param_count > 0) { printk(KERN_WARNING "SEC2 does not support parameters; failing request\n"); return -EINVAL; } size = sizeof(*pvt) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t); pvt = kzalloc(size, GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; if (ecp->param_count > 0) { printk(KERN_WARNING "SEC-2 echo canceler does not support parameters; failing request\n"); return -EINVAL; } pvt->taps = ecp->tap_length; pvt->curr_pos = ecp->tap_length - 1; pvt->tap_mask = ecp->tap_length - 1; pvt->fir_taps32 = (int32_t *) (pvt + sizeof(*pvt)); pvt->fir_taps16 = (int16_t *) (pvt + sizeof(*pvt) + ecp->tap_length * sizeof(int32_t)); /* Create FIR filter */ fir16_create(&pvt->fir_state, pvt->fir_taps16, pvt->taps); pvt->rx_power_threshold = 10000000; pvt->use_suppressor = FALSE; /* Non-linear processor - a fancy way to say "zap small signals, to avoid accumulating noise". */ pvt->use_nlp = FALSE; *ec = &pvt->dahdi; return 0; } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); fir16_free(&pvt->fir_state); kfree(pvt); } static inline int16_t sample_update(struct ec_pvt *pvt, int16_t tx, int16_t rx) { int offset1; int offset2; int32_t echo_value; int clean_rx; int nsuppr; int i; int correction; /* Evaluate the echo - i.e. apply the FIR filter */ /* Assume the gain of the FIR does not exceed unity. Exceeding unity would seem like a rather poor thing for an echo cancellor to do :) This means we can compute the result with a total disregard for overflows. 16bits x 16bits -> 31bits, so no overflow can occur in any multiply. While accumulating we may overflow and underflow the 32 bit scale often. However, if the gain does not exceed unity, everything should work itself out, and the final result will be OK, without any saturation logic. */ /* Overflow is very much possible here, and we do nothing about it because of the compute costs */ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems best */ echo_value = fir16 (&pvt->fir_state, tx); /* And the answer is..... */ clean_rx = rx - echo_value; /* That was the easy part. Now we need to adapt! */ if (pvt->nonupdate_dwell > 0) pvt->nonupdate_dwell--; /* If there is very little being transmitted, any attempt to train is futile. We would either be training on the far end's noise or signal, the channel's own noise, or our noise. Either way, this is hardly good training, so don't do it (avoid trouble). */ /* If the received power is very low, either we are sending very little or we are already well adapted. There is little point in trying to improve the adaption under these circumstanceson, so don't do it (reduce the compute load). */ if (pvt->tx_power > MIN_TX_POWER_FOR_ADAPTION && pvt->rx_power > MIN_RX_POWER_FOR_ADAPTION) { /* This is a really crude piece of decision logic, but it does OK for now. */ if (pvt->tx_power > 2*pvt->rx_power) { /* There is no far-end speech detected */ if (pvt->nonupdate_dwell == 0) { /* ... and we are not in the dwell time from previous speech. */ /* nsuppr = saturate((clean_rx << 16)/pvt->tx_power); */ nsuppr = clean_rx >> 3; /* Update the FIR taps */ offset2 = pvt->curr_pos + 1; offset1 = pvt->taps - offset2; pvt->latest_correction = 0; for (i = pvt->taps - 1; i >= offset1; i--) { correction = pvt->fir_state.history[i - offset1]*nsuppr; /* Leak to avoid false training on signals with multiple strong correlations. */ pvt->fir_taps32[i] -= (pvt->fir_taps32[i] >> 12); pvt->fir_taps32[i] += correction; pvt->fir_state.coeffs[i] = pvt->fir_taps32[i] >> 15; pvt->latest_correction += abs(correction); } for ( ; i >= 0; i--) { correction = pvt->fir_state.history[i + offset2]*nsuppr; /* Leak to avoid false training on signals with multiple strong correlations. */ pvt->fir_taps32[i] -= (pvt->fir_taps32[i] >> 12); pvt->fir_taps32[i] += correction; pvt->fir_state.coeffs[i] = pvt->fir_taps32[i] >> 15; pvt->latest_correction += abs(correction); } } else { pvt->latest_correction = -1; } } else { pvt->nonupdate_dwell = NONUPDATE_DWELL_TIME; pvt->latest_correction = -2; } } else { pvt->nonupdate_dwell = 0; pvt->latest_correction = -3; } /* Calculate short term power levels using very simple single pole IIRs */ /* TODO: Is the nasty modulus approach the fastest, or would a real tx*tx power calculation actually be faster? */ pvt->tx_power += ((abs(tx) - pvt->tx_power) >> 5); pvt->rx_power += ((abs(rx) - pvt->rx_power) >> 5); pvt->clean_rx_power += ((abs(clean_rx) - pvt->clean_rx_power) >> 5); #if defined(XYZZY) if (pvt->use_suppressor) { pvt->supp_test1 += (pvt->fir_state.history[pvt->curr_pos] - pvt->fir_state.history[(pvt->curr_pos - 7) & pvt->tap_mask]); pvt->supp_test2 += (pvt->fir_state.history[(pvt->curr_pos - 24) & pvt->tap_mask] - pvt->fir_state.history[(pvt->curr_pos - 31) & pvt->tap_mask]); if (pvt->supp_test1 > 42 && pvt->supp_test2 > 42) supp_change = 25; else supp_change = 50; supp = supp_change + k1*pvt->supp1 + k2*pvt->supp2; pvt->supp2 = pvt->supp1; pvt->supp1 = supp; clean_rx *= (1 - supp); } #endif if (pvt->use_nlp && pvt->rx_power < 32) clean_rx = 0; /* Roll around the rolling buffer */ if (pvt->curr_pos <= 0) pvt->curr_pos = pvt->taps; pvt->curr_pos--; return clean_rx; } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 x; short result; for (x = 0; x < size; x++) { result = sample_update(pvt, *iref, *isig); *isig++ = result; ++iref; } } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { struct ec_pvt *pvt = dahdi_to_pvt(ec); /* Reset hang counter to avoid adjustments after initial forced training */ pvt->nonupdate_dwell = pvt->taps << 1; if (pos >= pvt->taps) return 1; pvt->fir_taps32[pos] = val << 17; pvt->fir_taps16[pos] = val << 1; if (++pos >= pvt->taps) return 1; else return 0; } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI 'SEC2' Echo Canceler"); MODULE_AUTHOR("Steve Underwood "); MODULE_LICENSE("GPL"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/tormenta2.rbt0000644000175000017500000214653311015035664021201 0ustar tzafrirtzafrirXilinx ASCII Bitstream Created by Bitstream F.23 Design name: tormenta2.ncd Architecture: spartan2 Part: 2s50pq208 Date: Thu Oct 10 09:00:52 2002 Bits: 559200 11111111111111111111111111111111 10101010100110010101010101100110 00110000000000001000000000000001 00000000000000000000000000000111 00110000000000010110000000000001 00000000000000000000000000001011 00110000000000010010000000000001 00000000100000000011111100101101 00110000000000001100000000000001 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000001001 00110000000000000010000000000001 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000000001 00110000000000000100000000000000 01010000000000000011111000000100 00000000000100100011000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 10000000000000000000000000000000 00000000000000000000000000000000 00000000000100100011000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010000000000100 10000000000000000000000000000000 00000000000000000000000000000000 00000000000000100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000000000000000000000000 00000000000000000000000000000000 00000000000000100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000000000000000000000000 00000000000000000000000000000000 00000000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 10000000000000000000000000000000 00000000000000000000000000000000 00000000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 10000000000000000000000000000000 00000000000000000000000000000000 00000000000100100000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010000000000100 00000000000000000000000000000000 00000000000000000000000000000000 11111111000100100000000000000000 00000000000000011000000000000000 01000000000000000001100000000000 00000100000000000000000010000000 00000000011000000000000000011000 00000000000010100000000000000010 10000000000000000010000000000000 00101000000000000000001000000000 00000000000000000000000000100000 00000000000010000001111111000100 00000000000000000000000000000000 00000000000000000000000000000000 11000000000001011111101000000000 11111111100000000011111100000000 10001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111110000 00000011011111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110001000000000 10111011100000000010111000110100 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010101011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100100000000000 10100011000000000010110010000000 00001011001100000010011010001100 00000000101100110000000000101000 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000001101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010000000000000 10111011000000000010111011000010 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110010 10000010111011000000000010111011 00000000001011101100000000011011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110100000000 11111011000000000011111000010000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110111100 00000011011011000000000011111011 00000000001111101100000000001111 10110000010000111100100000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011000001000000 11111111000000000011111010100100 00001111111100000000000111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111110111000 00000011101111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000010011111000010000 00101100101100000000001111101100 00000000111110110000000000110110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111100110000 00000011101011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010000000000000 10111011000101100010111010000000 00001000101100000000001011101100 00000000101110110000000000100110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010001011000000000010111011 00000000001011101100000000001011 10111000100000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100010000000000 10110011000000000010110001000000 00001000001100000000001001001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100000000 00000010100011000000000010110011 00000000001011001100000000001011 00111110000000101111000000000000 01010000000000000000000000000000 00000000000000000000000000000000 01100000000000010001001000000000 10110111100000000010110100100000 00001000011110000100001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101001000 00000010000111100000000010110111 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110001000000 11110011000000000011110011000000 00001100001100010010001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100000000 00000011100011000000000011110011 00000000001111001100000000001111 00110000000000111101101000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011000000010000 11111111000000000011111111000100 00001111111100000000001111111100 00001000111111110000000000110111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111000000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000011011110010000010000 11111011000000000011111001000000 00001100101100000000001111101100 00001000111110110000000001111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111100000000 00000011001011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000011001000000000000 10110111000000000010110001000000 00001000011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101000000 00000010000111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000001000000001001111000000000 10110111100000000010110111100000 00011000011110000001001011011110 00000001101101111000000100101001 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101111000000 00000010000111100000000010110111 10000000001011011110000000001011 01111000000000101111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000100101001100000000000000 10110011000000000010110011000000 00011000001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100000000 00000010000011000000000010110011 00000000001011001100000000001011 00110000000000101101001100000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011011100000000000 11111010000000000011111110011100 00101100101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111111100000 00000011001010000000000011111010 00000000001111101000000000001111 00100000000000111111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000010000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000100000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001100000000011110001000000 00001101100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000110000001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000100000010111001000000 00001000100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10011000000010100010000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010110000000000 10111001000000000010111001000000 00001000100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010010100000100000011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001100000000010110001001000 00101000000100000000001011000100 00000000100100010000000001101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000100100010010 10000010110001000000000010110001 00000000001011000100000000001011 00010000000000100000001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000001010110000000000000 11111000000000000011111000000000 00001100100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000010 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000110010111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000101011111010000000000 11111001000001000011111101000100 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111111010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000000 11001001000000000011111001000000 00001100100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011001001000000000011111001 00000000001111100100000000001111 01010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10001000000000000010111000000000 00001000100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010101000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011110010000000000 10000001000000000010100001000000 00001000000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 10000100000000001011000100000000 00101100010000000000101110010000 00000010000001000000000010110001 00000000001011000100000000001011 00010000000001101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10001001000000000010111001001010 00001000100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010101001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011100010001000010 11001001000000010011111001000000 00101100100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111100010000 00000011001001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010011000000000 11111011000000010011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11001000000000000011110000000000 00001100100000000000001111100000 00000000111110000000000000110110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000100000110000101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00100000000001010010100000000000 10001010000000000010111010000000 00001000101000000000001011101000 00000000101110100000000000100110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 11100000000000100000101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000010 10000010000001000010110011000000 00001000001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000100100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010011110000000000 10000111010000000010110111000000 00001000011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01111000000000100100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11000100100000010011110011100000 00101100011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01101000000000110100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011000110000000000 11111000011000000011111011000000 00001111101100000000001111101100 00000000111110110000000000110110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000010001111 10000000000010111000001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111110110000100011001111100000 00001100111110000000001101111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011001111100000000011111111 10000000001111111110000000001111 11111000000000111101000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000100000 10110111000000000011010111000000 00001000011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000011110111000000000010110111 00000000001011011100000000001011 01100010000000101110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000000000 10110110000000000010000111000000 00001000011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010000111000000000010110111 00000000001011011100000000001011 01110000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110010000000000010010011000000 00001000001100000000001011001100 00000000101100110000000000100100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00000000000001101101100100000100 00110000000000000000000000000000 00000000000000000000000000000000 11111000000101011010110100000000 11111011000000000011001011000010 00101100101100000000001101101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011001011000000000011111011 00000000001111101100000000001111 10010000000000111110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000100000000001110110000000000 11111011000000010011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111100110000 00000011111011000000000011111011 00000010001111101100000000001111 10010000000000111110010000000000 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000100000 11111101100000010011111011000010 00001111111100000000001110111100 00000000111111110000000000111111 11000000000010111111000000000011 11111100000000001111111100000000 00111111110000000000111110110000 00000011001111000000000011111111 00000000001111111100000000001111 11101000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000100 10111000110110000010111011000000 00001001101100000000001011101100 00000000101110110000000000101110 11000000000010011011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010101011000000000010111011 00000000001011101100000000001011 10000000000000101110000101100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111001000000000010111011000000 00001011101100000000001001101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010001011000000000010111011 00000000001011101100000001001011 10010010000100101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110001000000000010110011000000 00001001001100000000001011001100 00000000101100110000000000101100 11000000000110010011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010110011 00000000001011001100000000001011 00000000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 11111001000000000011111011000000 00001111101100000000001110101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011001011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11110100000001000011111111000000 00001101111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11000000000000111110100000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111000000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111110010000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11001000000000110111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011110100010010111011100000 00001011101110000000001110101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011100010000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10001000000000100010000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10100011000001000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011000000000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00000000000001100110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000010000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000011011100000001000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000011011 10110000000000100111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111111000000100011111011000000 00001111101100000000001011101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000010111011 00000000001111101100000000001011 10011001000000110101000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000000111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000100001111111100100000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11000000000000111011100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011001000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111100101000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10010000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111111100000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011100100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 00110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011010000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011000000000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00100010000000101111100100000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011010010000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01001000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110001000000 11110011000010000011110011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110001 00000011110011000000000011110011 00000000001111001100000000001111 00100000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000010000 11111111000000100011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111101000000 00111111110000000000111111110000 01000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111111100000000011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101000000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10111000000000110010101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111100000000011010111000000 00001110011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011000000000 00101101110000000000101101110000 00010010110111000000000010110111 00000000001011011100000000001011 01000000000000110101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110011100000000010100111100000 00011011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 01101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000001100011000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001010001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100110000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110010000000100101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011101010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101010000000 00111110100000010001111110100000 00000011111010000000000011111010 00000000001111101000000000001111 11100000000000110011101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011011000000000 00001110100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000100000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111101100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10011100000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001100000000010111001000000 00001011100100000000001011100100 00000000101010010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010101000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001101010000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000001000000011111000000000 00001111100000000000001111100000 00000000111010000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000011011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111101100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 01010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111101100000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 11010000000000111100011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000010100000010111000000000 00001110100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10100000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000000111001000000 00001010100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000011011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000011011 10010000010000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101010110010000000000 11111001000000000010111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100110010000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10011000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000100 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100110000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10011001000000111100101000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011001000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000100000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111110100001000010001010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 11100000100000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110000000000001010100011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00111000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110100110000000010100111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01100000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000001000 11110100100000000011100111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01011000000000111110101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000010011011010110000000000 11110000000000100011011011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10000000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111110100000000011001111100100 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111011110000000 00110011111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111001000000110000000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110110000000000010000111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101001110000000000101101110000 00000010110111000000000010110111 00000000001011011100000100001011 01100000000010100010101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110110000000000010000111000000 00011011011100000000001011011100 00000000101001110000000000101101 11000000000010110111000000000010 11011100000000001011111100000000 00100001110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 11110000100001100000000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110000000000000010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101000110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00101100000000100000100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111001000000001011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00110010110000000000111110110000 00000011111011000000000010111011 00000000001111101100000000001011 00110000000000110010101100000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111000010000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11110101000000000011001111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11000100100000110000000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111001000000000010001011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010011011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10001000000000101010000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000010000010001011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10010100000000100010000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110010000000000010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010010011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 10010000000000101000001000000001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10000000000000110000100000000011 01010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000100 11110101000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011011111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 01000000000000111110000000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111101000000000 11111100100000000011111111100000 00001101111110010000001101111110 01001000110011111000000000110111 00000000000011111111100000000011 11111100000000001101111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000100001110011000000000 10111000100000000010111011100000 00001011101100000000001000001100 00001000100010111000000000101110 10110000000010111011100000000010 11111110000000001010101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101111000000000100 00110000000000000000000000000000 00000000000000000000000000000000 11001000000001011100100000000000 10110001000000000010110011000000 00001011001100100001001001001100 10000011100000110000000000101100 00010000000010110011000000000010 11001100000000001001001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000100011010010100000000 10111011000000000010111011000000 00001011001100000000001000001100 00000000100010110000001000001110 11000110000010111011000000000010 11101100000000000010101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 11000000000101011110110000000000 11111010010000000011111011000000 01001101101100000001001101101100 00000000110010110000000000111110 01100000000010111011000000000011 11101100000000001101101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101010000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011011100000000 11111110000000000011111111000000 00000011111100000000001111111100 00000000111111110000010000001110 11100000000011111111000000000011 11101100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000100000100001010110100000000 11101001010000000011111011000000 00001101101100001000001111101100 11000000110010110000000000111110 00010000000011001011000000000011 11001100000100001110101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101010000000000 00100000000000000000000000000000 00000000000000000000000000000000 11011000000001010010010000000001 10001011000000000010111011000000 00001001101111000000001011101111 00000000110110110000000000101110 11000000000011011011000000000010 11111100000000001000101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000100 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100000000010000 10100001000000000010110011000000 00001011001100000000001011001100 00000000100100110000000000101100 00000000010010000011000000000000 11001100000000001010001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00010000000000000000000000000000 00000000000000000000000000000000 10110000100000010011001000001000 10000100100000000110110111100001 00001011011110000000001011011110 00000000100101111000010000101101 00100000000010010111100000000010 11011110000000001010011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101110110000000100 00010000000000000000000000000000 00000000000000000000000000000000 01001000000010000000000000000000 10100001000000000011110011000000 00001111001100001000001111001100 00000000110100110001000000111100 10000000000011000011000000000011 11001100000000001110001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110001000000111101001000000010 00010000000000000000000000000000 00000000000000000000000000000000 01000000000111011001000001000000 11111110000100000011111111000000 00001101111100000000001111111100 00000000111111110000000000111111 10000000000011111111000000000011 11111100000000001101111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000000 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110100000010000 11111011001010000001111011000000 00001111101100000001101100101110 00000000110010110000000000111110 01000000000011001011000000000011 11101100110000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 11001000100100011001000000000000 00110110000000000010110111000000 00001011011100000000001000111100 00000000101001110000000000101100 11000000000010100111000000000010 11011100010000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000110 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001001101000000000 10110101110000000010110111100000 00001011011110000000001000011110 00000000100001111000000000101101 01100000000010000111100000000010 11011110100000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100001110000000 10110010100000010110110011000000 00001011101100000000001000001100 00000000101000110000000000101100 11111000000010100011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000000 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011011100000100000 11110010000000000011111010000000 00001111101000000000001100101000 00000000110010100000000000111111 10110000000011001010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101100000100 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111100 00000100000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000100 11111011000000100011001001000000 00001111100110000000001110100110 00000000111110010000000000111110 01000000000011001001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010101001000000 00001011100100000000001000100110 00000000101110010000000000101110 01000000000010001001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000100101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111011000000000010001001000000 00001011100100100000001010100100 10000000101110010000000000101110 01000000000010001001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100111000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10111001000000000010100001000000 00001011000100000000001000000100 00000000101100010000000000101100 01001000000010000001000000100010 11000100101000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100101000000101 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011001000000000 00001111001001010000001110101001 01000000111110000000000000111110 00000000001011001000000000000011 11100000100000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011111010000000000 11111001000000000010111001000000 00001111100100000000001111100100 00000000111110010000000000111111 01000100000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011100010000000000 11111001000000000011111001000000 00001111110100000000001100110100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100011000000000 01110000000000000000000000000000 00000000000000000000000000000000 01111000000100001110000000000000 10111000000000100010111000000000 00001011100000000000001101100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000110 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001011100010000000000 10110001000000000110110001000000 00001011000100000000001000000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000110000110111001000000 00001011100100000000001001100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001100000000011111001000000 00001111100100000000001100100100 00000000111110010000000000111110 01101100000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 01101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000010000111110 01100000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11101000010000000011111000000000 00001111100000000000001111100000 00000000110010000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10001010000000000010111010000000 00001011111011000000001011111001 00000000100010100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10100011000000000010110011000000 00001011101111001000001011001111 00100000100000110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101100000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010011111000000000 10000111000000000010110111000000 00001011011100001000001001011011 00000000100001110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110000000000100 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11100111100000000011110111100000 00001111011110000000001111111110 00000010110001111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000011000111110001000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000100011111011000000 00001111101100000000001111100100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000100101111111100100 00001111110110010000001100110110 00000000110011111000000000111111 11100000000011111111100000000011 11111110000000001110111110000000 00111111111000000000111111111000 00000011011111100000000011111111 10000000001111111110000000001111 11111000000000111100000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000110110111000000 00001011110000000000001101010000 00000000101001110000000000111101 11000000000010110111000000000010 11011100000000001000011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110001000000101110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 01001011010100000010001000011100 00000000100001110000000000101101 11000000000010110111000000000010 11011100000000001010011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110010000000 10110011010100000010110011000000 00001011100100000000001000100000 00000000101000110000000000101000 11100100000010110011000000000010 11001100000000001000001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100100000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010111110000000 11111011010000000011111011000000 00001111101000000010101000101100 00000000110010110000000000101110 11010100000011111011000000000011 11101100000000001110101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000001000111 10110000001100101110101100000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011001000000011111011000000 00001111100000000000001111101001 00000000111110110000000000111110 11000000000011111011000000000011 11001100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111010000000001100111000 00000000110011110000000000111101 11000000000011001111000000000011 11101100000000001100111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000000011 11110000000000111100100001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110110000000000 10111011000001000010111011000000 00001011101011010000001010101011 00100000110110110000000000101110 11000000000010101011000000000010 11101100000000001010101100000000 00101110110000000000101110110000 00000010011011000000000010111011 00000000000011101100000000001011 10110000000000101110100001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000000010010110000000000 10111011000000000110111011000000 00001011101101000000001000100100 01000000100010110000000000101110 11000000000010001011000000000010 11101100000000001000101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000000001101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000001 00001011000000000000001000000000 00000000100100110000000000100100 11000000001010000011000000000010 11001100000000001010001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 01001111100000000000101100000100 00000000110010110000000000111110 11000000000011001011000000000011 11101100000000001100101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000011 01010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000010111111000000 00001111110000000000001111110000 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000001111110100001000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111001000000011001111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 00111110000000001111111110000000 00111111111000000000111111110000 00000011011111100000000011111111 10000000001111111110000000001111 11111000000000110011000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10100000000100001110111000000000 10111111110100000000001011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 10101110000000001011101110000000 00101110111000000000101111110000 00000010101011100000000010111011 10000000001011101110000000001011 10110000000000101010000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000100 10110001000001000010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010111001000000000010 00001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000100010001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010110000000000 10111000000010000010001011000000 00001011101100000000001011101100 00000000101110110000000000100110 11000000000110111001110000000010 10101100000000001011101100000000 00100110110000000000101110110000 00000010101011000000000010111011 00000000001011101100000000001011 10110000000000101011000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11111101000000001011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011110000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011011011000000000011111011 00000000001111101100000000001111 10110000000000110000000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000000011011110000000000 11110101000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100001000 00111111110000000000111110110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011101011000000 00001111101100000000001101101100 00000000111110110000000000111110 11000000000011111001000100000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011001011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010001011000000 00001001101100000000001001101100 00000000101110110000000000101110 11000000000010110001000000000010 11101100000000001011101100001000 00101110110000000000101111110000 00001010001011000000000010011011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011100100000010100011000000 00001001001100000000001011001100 00000000101100110000000000101100 11000000000010110010000000000010 11001100000000001011001111000000 00101100110000000000101110110000 00000010000011000000000010010011 00000000001011001100000000001011 10110000000000101111100000000000 01010000000000000000000000000000 00000000000000000000000000000000 01100000000000010001111000000000 10110111100000000010000111100000 00001001011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110010000 00101101111000000000101101111001 00000010000111100000000010010111 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110001000000 11110001000000000011100011000000 00001101001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011000011000000000011010011 00000000001111001100000000001111 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000010100 11110101100000000011111111000000 00001101111100000000001101111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000100 00111111110000000000111111110100 00000011111111000000000011011111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10001000000001011110110000000000 11110001011000000011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 00101100000000001111001110000000 00110010110000000000111110110001 00001011001011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110101000010010000000111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 10011100000000001011011100000000 00110101110000000000101100110010 00000010000111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000001000000001001111000000100 10110111100000100000000111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010111111100000000010 00011110000000001011011110000000 00100001111000000000101101111000 00000010000111100000000010110111 10000000001011011110000000001011 01111000000000101111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011010100001010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 10001100000000001011001100000000 00100100110000000000101100110000 00000010000011000000000010110011 00000000001011001100000000001011 00110000010000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11110110110000000011001010000000 01001111101000000000001111101000 00000000111110100000000000111110 10000000000011111110000000000011 00101000000000001111101000000000 00110010100000000000111110100000 00000011001010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000010000 11111000000010000011111000000000 00001111100000000000000111100000 00000000111110000000000000111110 00000000000011111000100000000011 11100000000000001111100001000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011001001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001100000000011 00100100000000001111100100100000 00111110010000000000111100010000 00000011001001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000100001000110010000000000 10111001000000000110001001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010110001100000000011 01100100000000001011100111001000 00101110010000000000101110010000 00000010001001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000001000010001001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001001000000010 00100100000000001011100100000000 00101110010000000000101110010000 00000010001001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10111001001010000010100001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010111001000000000010 01000100000000001011000100000000 00101100010000000000101100010010 10000010000001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000001000001010001000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 00100000000000001111100000000000 00111110000000000100111110001010 00001011001000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111101000000000011011001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011110101000000000011 11100100000000001111100100000000 00111110010000000000111110010010 10000011111001000000000011111001 00000000001111100100000000001111 10010010100000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000000 11111101100000001011001001000000 00001011100100000000001111100100 00000000111110010000000000111110 01000000000011111101000000000011 11100100000000001111110100000000 00111110010000000000111110010000 00000000101001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000010000 10111000000000000011011000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010101000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001010000001010000001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001100000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010000001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001001000000010011001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000001000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010101001000000000010111001 00000000001011100100000000000011 10010000010000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000001000 11111001001000100011001001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001010000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011001001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11110001100000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001101000000011 11100100000000001111100100001000 00111110010000000000111100010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000010000000011001000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000010000 00111110000000000100111110000000 00001011001000000001000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00100000000001010010100000000000 10111010100000001010001010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010101000000010 11101000000000001011111000000000 00101110100000000000101110100000 00000010001010000000000010111010 00000000001011101000000000001011 10100000010000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011100000000010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110001000000000010 11001100000000001011001110000000 00101100110000010000101100110000 00000010000011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111010000000010000111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011010000000000 00101101110000000000101101110000 00000010000111000000000010110111 00000000001011011100000000001011 01110010000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110011100000001011000111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000010011110111100000000011 11011110000000001111010010000000 00111101111000000000111100111000 00000011000111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000000111100000000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110001000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011001111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001011110010010000 00111111111000000000111111111000 10000011001111100000000011111111 10000000001111111110000000001011 11111001000000111101000000000100 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110101000000000010000111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011010000000000 00101101110000000000101101110000 00000010100111000000000010110111 00000000001011011100000000001011 01110000000100101110101000000110 01100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000000000 10110011000000000010000111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011010000000010 00101101110000000000101100110000 00000010000111000000000010110111 00000000001011011100000000001011 01110000001000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110001001000000010000011000000 00001011001100000000001011001100 00000000101100110000000001101100 11000000000010110011010010000010 11001100000000001011000000000000 00101100110000000000101110110000 00000010100011000000000010110011 00000000001011001100000000001011 00110000000000101101100000000000 00110000000000000000000000000000 00000000000000000000000000000000 11111000000101011010110000000000 11111011000000001011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011010000000011 11101100000000001111100000000000 00111110110000000000111111110000 00000011001011000000000011111011 00000000001011101100000000001111 11110000000000111110111000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000100000000001110110000000000 11111011000000010011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111100001000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001011101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000000000 11110111000000000011001111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111100000000011 11111100000010001111110000000000 00111111110000000000111111110000 00000011001111000000000011111111 00000000001111111100000101001111 11110000000100111110000001100100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000001000 10111011000000000000101011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011100000000010 11101100000000001011100011100000 00101110110000000000101110110000 00000010101011000000000010111011 00000010001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010001011000000 00001011101100000000001011101100 00000000101110110000000000101010 11000000000010111011000100000010 11101100000000001011100010000000 00101110110000000000101110110000 00000010001011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110001000000000010100011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000011011000000000000 00101100110000000000101100110000 00000010100011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000101 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 11111011000000001011001011000000 00001111101100000000001111101100 00000000111110110000000000111010 11000000000011111011000000000011 11101100000000001111100000000000 00111110110000000000111110110000 00000011001011000000000011111011 00000000001111101100000001001111 10110000000100111110000000000010 00000000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000010000 11111101000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000000111110000000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000011111111100000000001111 11110000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000011011111111000000000 11101111100000000011111111100000 01001111111110000000001100111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111011000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11000000000000001110111000000000 10111011100000000010111011100000 00001011101000100000001000101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101100000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 11001000000001011100110000000000 10100011000000000010110011000000 00001011000100001000111001001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001010 00110000000000101011001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000110111011000000 00001011000100001000001001101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000010000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10010000000101011110110000000000 11101011000000000011111011000000 10001111100100010000001101101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001011101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111000100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000001000011111111000000 00001111110000000001001110111100 00000100111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01010000000100001010110000000000 11101011000000000011111011000000 01001111100101100000101100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000110001010100000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000010000000111011000000 10001011101101000000001000101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10111000000000100011001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000001000 10110011111001000000110011000000 00001011001100010000001001001100 00000000001100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110011000000100011000000000000 00000000000000000000000000000000 00000000000000000000000000000000 11110000000000010001111000000100 10110111100000000010110111100000 00001011011010010000011001011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000010100011110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001010000000000000110000000000 11110011000000000011110011000000 10011111101100010110001101001100 00000000111100110001000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000110001101000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000101011011110000000000 11111111000000000011111111000000 00001111111000010000001110111100 00000000111111110000010000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 01110000000001111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00011111100111001000001100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 11001000100100011001110000000000 10110111000000000010110111000000 00001011110100000000001000011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001001111000000000 10110111100000000010110111100000 00001010010110000001001000011110 00000000101001111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010100111 10000000001011011110000000001010 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00011011001100110000001000001100 00010000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010100000000000 11111010000000000011111010000000 00001110101000000000101100101000 00000000111010100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00101110100000000000111110100000 00000011111010000000000011101010 00000000001111101000000000001110 10100000000000101111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000100000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011101001000000 00001111101100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000110000001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10110001000000000010001001000000 00001011100110010000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 00010000100000101010000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001010000000010001001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000100000011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010000001000000 10001011001100000000001011000100 00000000100100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101000001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000100 11111000000000001011101000000000 00001111100001010000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000110010111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100110101000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110111100000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000001 11111101000000001011001001000000 00001111110100000000001100100100 00000000111110010000000000111110 01000000000111111001000000000011 11100100000000001111100100010000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 11010000000000111110111000000001 01110000000000000000000000000000 00000000000000000000000000000000 01111000000100001110000000000000 10111000000000000010001000000000 00001011000000000000001000100000 00000000101110000000000000101110 00000000000011111000000000000010 11100000000000001011100010100000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000000 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001011100010000000000 10110001000000000010010001000000 00011011000100000000011001000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100100000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000001101101001000000001 01100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000001 10111011000000000010011001000000 00001011001100000000001001100100 00000000101110010000000000101110 01000000000010101001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000010011011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 10111001000000100011011001000000 01001111100111110000101101100100 00000000111110010000000000111110 01000000000010111001000000000011 11100100000000001011100100000000 00111110010000000000101110010000 00000011111001000000000011111001 00000000001111100100000000001011 10010000000000111110000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000000011010010000000000 11111001000000000011101001000000 00001111100110000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000100000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000001000011111000000000 00001111100000011000001100100000 00000000111110000000000000111110 00000000000011111000000001000011 11100000000000001111100000000000 00110010000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10110110000010010010111010000000 00001011111010000000001000101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101010100000000000111010100000 00000010111010000000000010111010 00000000001011101000000000001011 11101100000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110000000000000010110011000000 00001011001111000000001001001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00100000110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00111000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110101000000000010110111000000 00001011010000000000001001011100 00000000101101110000001000101101 11000000000010110111000000000010 11011100000000001011011110000000 00101001110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01100000100000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110100100000000011110111100000 01001111011110000000101101011110 00000000101101111000000000111101 11100000000011110111100000000011 11011110000000001111111110000000 00110001111000000000101101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100001000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111000000000000011111011000000 10001111101000000000001110101100 00001000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000000 11111110100000000011111111100000 00011111011110000000001110111110 00000000111111111001000000111111 11100100000001111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000101101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 11100111000100000010110111000000 00001011010100100000001101011100 00000000101101110000000000111101 11000000000011110111000000000010 11011100000000001011011100000000 00101101110000000000111001110000 00000010110111000000000010110111 00000000001011011100000000001011 01000000000000101110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000000000 10110110000000000010110111000000 00001010111100000000001011011100 00000000101101110000000100101101 11000000000110110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001010 01100000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000101001100110000000000 10100010000000000010110011000000 00001011100000000000001000001100 00000000101100110000000000101000 11000000000010100011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000000011 00000000000000101101000100000100 00100000000000000000000000000000 00000000000000000000000000000000 10111000000101011010110000000000 11111000000000000011111011000000 00001110101100001000001011101100 00001000111110110000000000101110 11000000000010111011000000000011 11101100000000001111111100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10010000000000101110001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11101001010000000011111011000000 00001111100000001000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10000000001100111110010100000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000000000 11111100001000000011111111000000 00001111110110000000001100111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11011000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000000000110110000000000 10111001110000000010111011000000 00001011100001000000001111101100 00000000101110110000000000101110 11000000000011001011000000000010 11101100000000001011111100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10010000000000101110000001100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000001000 10111010000000000010111011000000 01001011101000100000011000101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110010000000101110100000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000001 10110001000000000010110011000000 00001011000000000000101001001100 00000000101100110000000000100100 11000000000010000011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00000000000000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 10111010000000000011111011000000 00001111101100000000001100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10100000000000111110000000000010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111101000000000011111111000000 00001111110000000000001110111100 00000000111111110000000000111111 11000000000011101111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000001001111 11000000000000111110100000100110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000011011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111110000000000110011111000 00000011010100100000001011001111 10000000001111111100000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11000000000000001110111000000000 10111011100000000010111011100000 00001011101110000000001110101110 00000000101110111000000000101110 11100001000010111011100000000010 11101110000000001011101110000000 00101111110000000000101000110000 00000010001000100000000010001011 10000000001011111110000000001011 10111000000000101111000000000100 00110000000000000000000000000000 00000000000000000000000000000000 11001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000100100110000 00000010110010000000000010000011 00000000001011001100000000001011 00110000000000101111001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000010 00101110110000000000101110110000 00000010111010000010000010001011 00000000001011101100000000001011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000100000101011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000110110110000 00000011111000010000000011001011 00000000001111101100000000001111 10110000000000111100000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111100110000000000111011110000 01000011001101100100000011111111 00000000001111101100000000001111 11110000000000111111110000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000010110010110000 00000011111010000000000011011011 00000000001111101100000100001110 10110000000000111101010000000100 00100000000000000000000000000000 00000000000000000000000000000000 11011000000000010010110000000000 10111011000000000010111011000000 00001110101100000000001011101100 00000000101110110000000000101110 11000000000010111011000010000010 11101100000000001011101100000000 00101111110000000000100010110000 00000010000011000000000010001011 00000000001011111100000000001000 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001001001100000000001011001100 00000000101100110000000000101100 11000000000010110011100000000010 11001100000000001011001100000000 00101100110000000000100010110000 00000010100001000000000010010011 00000000001011001100000000001010 00110000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 11110000100000010001111000000100 10110111100000000010110111100000 00001010011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000100001111001 00000010001101100000000010000111 10000000001011011100000000001000 01111000000001101111110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000000000000110001000000 11110011000000000011110011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100010000 00111100110000000000110000110000 00000011100001000000000011010011 00000000001111001100010000001110 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000101011011110000000000 11111111000000000011111111000000 00001110111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000010 11111100000000001111111100000000 00111111110001000000111111110000 01000011101101000000000011111111 00000000001111111100100000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000100 11111011000000100011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110111010100000110010110000 00000011001010000000000011111011 00000000001111101100110000001100 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 11001000100100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110100000000101001110000 00000010000111000000000010110111 00000000001011001100010000001010 01110000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000001000000001001111000000000 10110111100000000010110111100000 00001011011110000000001010011110 00000000101001111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101110000000000100001110000 00000010000110100000000010110111 10000000001011011110100000001000 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000100101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001001001100000000 00101100110000000000101000110000 00000010000011110000000010110011 00000000001011001100000000001010 00110000010000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010100000001000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000010110010100000 00000010001110101000000010111010 00000000001111101000000000001000 10100000000000101111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000010 00111100000000000010111110000100 00000011111000001000000011111000 00000000001111000000000000001111 10000000010000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001101100100000000001111100100 00000000111110010000000000111110 01000000000011111001100000000011 11100100000000001111100100000000 00111110010000000000110110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000001000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001100000000010 11100100000000001011100100000000 00101110010000000000110110010110 00000010111001000000000010111001 00000000001011100100000000001000 10010000000000101110100000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001001000000010 11100100000000001011100100000000 00101110010000000000100110010000 00000010111001000000000010111001 00000000001011100100000000001010 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000110 11000100000000001011000100000000 00101100010010100010100100010000 00000010110001000000000010110001 00000010011011000100101000001000 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000101110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111100001010000000110110000000 00000011111000000000000111111000 00000000001111100000100100011110 10000000001001111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000001 11100100000000001111100100000010 00111110011010100000111100010010 10000011111101000000000011111001 00000000001111100100000000001110 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000101011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111101000000000011 11100100000000001111100100000000 00111110010000000000110011010000 00000011001101000000000011111001 00000000001111100100000000001111 10010000000000111110111000000100 01110000000000000000000000000000 00000000000000000000000000000000 01111000000010001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000111110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000100010000000 00000010001000000000000010111000 00000000001011100000000000001011 10000000000000111100111000000010 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000010100000010000 00000010010001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000001011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101010010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000100010010000 00000010011001000000000010111001 00000000001011100100000000001011 10010000010000101000011000000000 00100000000000000000000000000000 00000000000000000000000000000000 10100000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000101110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000110010010000 01000011011001100100000011111001 00000000001111100100000000001011 10010000000000101110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 01101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011101001100000000011111001 00000000001111100100000000001111 10010000000000111101101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000110010000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00100000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010100000000010 11101000000000001011101000000000 00101110100000000000110101100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110001100000000110 11001100000000001011001100000000 00101110110000000000100000000000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001100000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000100010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000010000010 11011100000000001011011100000000 00101101110000000000100101001000 00000010110111000000000010110111 00000000001011011100000001001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000000000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000101101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111111111100000000110001010000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000100001111101100000000 00111110110010100000111110010000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111001000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111011001000 00000011000111100000000011001111 10000000001111111110000000001100 11111001000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000001 00101101110000000000100001000000 00000011010111000100000011010111 00000000001011011100000000001101 01110000001000101110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000001000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101001010000 00000010001111000000000010000111 00000000001011011100000000001000 01110000001000001100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101110110000000000100010010000 00000010010011000000000010010011 00000000001011001100000000001001 00110000000000101101000000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011110011000000000011 11101100000000001111101100000000 00111111110000000010111010100000 00000011001011010000000011001011 00000000001111101100000000001000 10110000000000111110111000000000 01100000000000000000000000000000 00000000000000000000000000000000 10010100000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000010011 11101100000000001111101100000000 00111110110000000000111110100000 00000011111011001000000011111011 00000000001111001100000100001111 10110000000000111110100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 00111100000000001111111100000000 00111110110000000000110011110001 00000011001111000000000011111111 00000000001111101100000000001100 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011100000000010 00101100000000001011101100000000 00101110110000000000100010110000 01000010101011000000000010111011 00000000001011101100000000001010 10110000000000101110010001100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000100000010 00101100000000001011101100000000 00101110110000000000100010100000 00000010001011000000000010111011 00000000001011101100000000001000 10110000000100101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 00001100000000001011001100000000 00101100110000000000100000100000 00000010100011000000000010110011 00000000001011001100000000001010 00110000000000101100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 00101100000000001111101100000000 00111111110000000000110000110000 00010011001011000001000011111011 00000000001111101100000000001100 10110000000000111110000000000010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000010011111111000000000011 11111100000000001111111100000010 00111111110000000010111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100000100100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000011011111111000000000 11111111100000000011111111100000 00001111111110000000011111111110 01000000111111111000000000110011 11100000000011111111110000000011 00111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000010001110111000000000 10111011100000000010111011100000 00001011101110000000001011101100 10000000101110111000000000101010 11100000000010111011000000000011 01101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000100001011 10111000000000101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000011011001100 00000000101100110000000000100000 11000000000010110011001000000010 00001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001010 00110000000000101011001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011010110000000000 10111011000000000010111011000000 00001011101100000001001011101100 00000000101110110000000000101010 11000000000010111011000000000010 01101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000010000101111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11111011000000000011111001000100 00001111101100000000001011101100 00000000111100110000000000110010 11000000000011110011000000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000100111100100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111101100000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111001010000 00001111101100000000001111101100 01000000111110110000000000111110 11000000000011111011001000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101010000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000010 10001011101100000000001011101111 01000000101110110110000000101110 11000000000010111011101000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11000000000001000100110000000000 10110011000000000010110010100000 00001001001100000000001011001100 00000000101100110010000000101100 11000000000010110011010000100010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111001000000000 00000000000000000000000000000000 00000000000000000000000000000000 01100000000000000101111000000000 10110111100000000010110111000000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101111110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000000000100110000000000 11110011000000000011110010010100 00001101001100000000001111001100 00000000111100110000000101111100 11000000010011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101101000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000101011011110000000000 11111111000000100011111110000000 00001111111100000001001111111100 00000000111111110000000101111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 00001000000101011110110000000000 11111011000000000011111010100000 00011101101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000011001110000000000 10110111000000000010110111000000 00001000011100000000001011011100 00000001101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00100000000100001001111000000000 10110111100000000010111101100000 01001000011110000101001010011110 00010000101001111000000000101101 11100000010010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000101001100110000000000 10110011000000000010110011000000 00001000001100000000001011001100 00000100101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011110100000000000 11111010000000000011111110101100 00001101101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000011010000000000000 11111000000000000011111000000000 00001111100000000000001111100001 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 10000000110010010100000000111110 01000000000011111001001000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001100000 00001011100100000000001011100100 00100010100010011100000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110100000000000 00000000000000000000000000000000 00000000000000000000000000000000 00111000000001010010010000000000 10111001000000000010111001000100 00001011100100000000001011000100 00000000100010010000000000101110 01000000000010111001000010000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000100000110000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000001010110000000000000 11111000000000000011111000000000 00001111100000000000001111100001 01000000110010000000000000111110 00000000000011111000010100000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110011000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000101011110010000000000 11111001000000000011110111000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000101011010010000000000 11111001000000000011111101000000 00001111100100000000001111110100 00000000111111010000000000111110 01000000000011111101000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110111000000001 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 01001011100000000000001110000000 00000000111110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000011101000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000001001000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000010010110001000000000110 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000001 00100000000000000000000000000000 00000000000000000000000000000000 00011000000000000010010000000000 10111001000000000010111001000000 00001011100100000000001010101100 00000001101010010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010101001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000001011110010000000000 11111001000000000011111001110000 00000111100100000000001111100100 00000000101110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000101110100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000011010010000000000 11111001000000000011111001110000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011101001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000000001010000000000000 11111000000000000011111000010000 00001111100000000000001111100000 00000000110110000000000000111110 00000000010011111000100000001011 00100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000101010010100000000000 10111010000000000010111010100000 00001011101000000100001011111011 00000000110111101000000000101110 10000000000010111110000000000010 00101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001101 00100000100000111000000000101100 11000000000010110011000100000010 01001100000000001010001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001100000000 01010000000000000000000000000000 00000000000000000000000000000000 10000000000100010001110000000000 10110111000000000010110101010000 00001011011100000000001011011011 00000000100101110000100000101101 11000000000010110101100000000010 01011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10001000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000110001101000000000111101 11100000000011111111100000000011 01011110000000001110011110000000 00111101111000000000101101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000001011010110000000000 11111011000000000011111001000000 00001111101100000000001111100000 00000000111110000000000000111110 11000000000011111011000000000011 10101100000000001101101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000011111 10110000000000111100001000000010 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001001011111000000000 11111111100000000011110111100000 00001110111110000000001111111110 00000000110001011000000000110011 11100000000010111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000110001001110000000000 10110111000001000010110111000100 00011000011100000000001110111000 00000000101001110000000000110101 11000000000010110100001000000010 11011100000000001011011100000000 00101101110000000000111001110000 00000011110111000000000010110111 00000000001011011100000000001111 01110000000000101110001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000000000 10110111000000000010110101000000 00001010011100000000001011011100 00000000100001000000000000100001 11000000000010110101000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101000011001000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000001001000110000000000 10110011000000000010110001110000 00001000001100000000001010101000 00000000101000000000000000100100 11000000000010111001000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010110011 00000000001011001100000000001010 00110000000000101101000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10100000000101011010110000000000 11111011000000000011110011000010 00001110101100000000001111100100 00001000110010110000000000110010 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000010111011000000000010111011 00000000001111101100000001001011 10110000000100111110111000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000100000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111100101 00000100111110100100000000111110 11000000000011111001010000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000001100111110100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10100000000100001111110000000000 11111111000000000011111111110010 00001100111100000000001111111000 01000000110011110000010000110011 11000000000011111111100100001011 00111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10100001000001000110110000000000 10111011000000000010111011100000 00001010101100000001001011100000 00000000100000000110000000101010 11000000000011111001000000000010 00101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000011101011 00000000001011101100000000001011 10110000001000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001000101100000000001011100100 00000000100010010000000000101010 11000000000010111011000010000010 00101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000101000000110000000000 10110011000000000010111011000000 00001010001100000100001011000000 00000010100000100000000000101000 11000000000010100001000000000010 00001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000010001011001100000000001001 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 10111011000000000011111011000000 00001100101100000000001111100100 00001000110010010000000000111010 11000000000010111011000000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000110 00010000000000000000000000000000 00000000000000000000000000000000 10100000000101011111110000000000 11111111000000000001111111000000 00001111111100000000001111110000 00000000111111000000000000111111 11000000000011111101000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011101111 00000000001111111100000000001111 11110000000000111110100000100110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000011011111111000000000 11111111100000000011111111100000 00001111111110000000001101111110 00000000111111111000000000111111 00000000000011001100000000000011 11110000000000001100110000000000 00110011000000000000110011000000 00000011111101000000000011001111 10000000011111111110000000011111 11111000000000111011000000000001 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001110111000000000 10111011100000000010111011100000 00001011101100000000001000101110 00000000101110111000010000101110 00000001000010001000100000000010 11100000000000001100100010000000 00100010001000000000100010001000 00000010111001100000000010001011 10000000001011101110000000001011 10111000000101101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 11001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001001001100 00000000101100110000000000101100 01000000000010010001000000000010 11000000000000001001001000000001 00100100000000000000100000000000 00000010110001000000000010010011 00000000001011001100000000001011 00110000000000101111001000000001 00110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011001100000000001001101100 00000000101110110000000000101110 01000000000010011001000000000010 11100000011000101000101000000000 00100110000000000000100010000000 10000010111001000010000010011011 00000000001011101100000000001011 10110000010001101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10010000000101011110110000000000 11111011000000000010111011000000 00001111101100000000001101101100 00000000111110110000000000111110 10000000001011011000000100010011 11100011000000101101100100000000 10110110011000000010110010000101 00010010111001010100001011011011 00000000001011101100000000001011 10110000000000111000100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001110111100 00000000111111110000000000111101 10000000000011101000100000000011 11100010000000001111110100000000 00111011011001000000111110001000 00000011110001100000000011101111 00000000001111111100000000001111 11110000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001110101100 00000000111110110000000000111110 11000000000011101001001000000011 00000001000000101100001100000000 00110100010000000000110010000100 00000011001001010000000011001011 00000000001111101100000000001111 10110000001000111101010000000100 00100000000000000000000000000000 00000000000000000000000000000000 11011000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001000101100 00000000101110110000000000101110 11000000000010001001011000000010 00100000000000001101101100000100 00100010011100100010100010000000 00001010001001000000000010001011 00000000001011101110010000001011 10110000010000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000001000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101100 00000000000010100010110000001010 00001100000000001000000010000100 00100000101100100000100000110000 00001010000010000000001010000011 00000000001011001101000000001011 00110000000001101111001000000000 00000000000000000000000000000000 00000000000000000000000000000000 11110000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001000011110 00000000101101111000000001101101 00100000000010000110100000000010 00011110000000101001010010001000 00100000101001000000100001111001 00000010000110100000000010010111 10000000001011011110001000001011 01111000000000101111110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000000000000110000000100 11110011000000100011110011000000 00001011101100000000001110001100 00000000111100110000000000111110 01000000000011100011000000000011 00001100000000001100001000000000 00110100100001000000100000110001 00000011000010000000000011000011 00000000001111001100000000001111 00110000000000111101101000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000100101011011110000000000 11111111000000000011111111000000 00001111111100000000001110111100 00000000111111110000000000111111 01000000000011111111000100000011 11111100010000001111011000010000 10111111100001000000111111110001 00000011111110100100000011101111 00000000001111111100000000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 10000000000011011010000000000011 00101110000000001100100100000000 00110010110000000000110010111000 00000011001010000000000011011011 00000000001111101100000000011111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 11001000100100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101111 10000000000010000110000000000010 00001100000000001000010100000000 00110001110000000000100000110000 00000010000010000000010110000111 00000000001011011100000000001011 01110000000000111011001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000001000000001001111000010000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010010011100000000010 00011110000000001000001110000000 00100000111000000000100101111000 00000010000110100000000010000111 10000000001011011110000000001011 01111000010000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000100000010000011000000000010 00001100000000001000001100000000 00100000110000000000100000110000 00000010000010000000000010000011 00000000001011001100000000001011 00110000000000101001001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001011101000 00000000111110100000000000111110 10100000000011011010000000001011 00101000000000101100101001000000 10110010100100000010110110100000 00001011001110000000001011001010 00000000001011101000000000001011 10100000000000101111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000010000111100 00000000000011110000010000000011 11100000000000001111100000001000 00111000000000100000111110000000 00000011110100000000000011111000 00000000001111100000000000001111 10000000000000111001001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011001001010000000011 00100100000000001111000100000000 00110010010000000000110010010000 00000011111001000000000011001001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000010000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000010010001001111000000010 00100100000000001011100100000000 00100010010000000000100010010000 00100010111001000000000010001001 00000000001011100100000000001011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010011001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010001101000000000010 00110100000000001011110100100000 00100011010101000000100011010000 00000010111101000000000010001001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000100100010000000000101101 01001011001010000101001010001010 00010100101000001011010100101000 10100001010010100000100001010010 10000010110101001010000010000001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00001000000011001000001000000011 00100000100000001111100000100000 00110010000010000010110010000010 00000011111100001000001011001000 00000000001111100000000100011111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100101000001111100100 00000000111110010000000000111110 01101010000011111001000000000011 11100110101000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000001111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001110100100 00000000111110010000000000111110 01000000000011010101000000000011 11100100000000001100110100000000 00110011010000000000110010010000 00000011111001000000000011111001 00000000001111110100000000001111 10010000000000111110111000000000 01110000000000000000000000000000 00000000000000000000000000000000 01111000000100001110000000000000 11111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101100 00000000000011011000000000000010 11000000000000001100100000000000 00100010000000000000110110000000 00000010111000000000000110111000 00000000001011100000000000001111 10000000000000101100011000000100 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001010000100 00000000101100010000000000101100 01000000000010010001000000000010 11000100000010001001000100000000 00100000010000000000100000010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10101001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101100 01010000000010011001010000000010 11100100000000001000100100100000 00100010010000000000100110010000 00000010111001000000000010111001 00000000001011100100000000001010 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 10111001000000000010111001000000 00001111100100000000001110100100 00000000111110010000000000111110 01000000000011011001000000000011 11100100000000101101100100000000 10110010010000000000110010010000 00000011111001000000000010111001 00000000001111100100000000001011 10010000000000111110100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000011111100100000000001111 10010000000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011101000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011001000000010000011 01100000000000001100000000000000 00111110000000100000111110000000 00000011111000000000000011111000 00000000001111100000000000001110 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00100000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010001110010000000010 00101000000000001000101010000000 00101101101100000000101110100000 00000010111110000000000010111010 00000000001011111000011000001000 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010100011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010000001010100000010 00101100000000001000001110000000 00101100111100000000101100110000 00000010110010000000000010110011 00000000001011001111000000001010 00110000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100100000001011011100 00000000101101110000000000101101 11000000000010000110100000000010 00011100000000001000010100001000 00101101000000100000101101110000 00000010110110000000000010110111 00000000001011011110000000001000 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011100111100000 00001111011110110000001111011110 00000000111101111000000000111101 11101000000011000110100000000011 01011111000000101100010110000000 00111101001000000000111101111000 00000011110110100000000011110111 10000000001111011110000000001110 01111000000100111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101101110000001111101100 00000000111110110000000100111110 11001100011011111010000000001011 11101100100000001111100100000000 00111110000000000000111110110000 00000011111010000000000011111011 00000000001111001100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111001000000 11111111100000000011111111100000 00001111111110000000001100111110 00000000111111111000000000111011 11110000000011000110100000100011 00111111000001001111110110000010 00110011001000000000111111111000 00000011001110100100001011001111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001101011100 00000000101101110000000000111011 11001000000011010110011000000010 00111100000000001010010100000000 00100001000100000000101101110000 00000010000110000000000010000111 00000000001011010000000000011011 01110000000000111110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000010000 10110111000000000010110111000000 00001011011100000000001001011100 00000000101101110000000000101001 11000000100010000110000000000010 00011100000000001011010100000000 00100001000000000000101101110000 00000010000110010000100110000111 00000000001011011100000000001011 01110000000000101100010010000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110011000000000010110011000000 10001011101100000000001001001100 00000000101100110000000000101010 11000000001010010010000000001010 00001100000000001010000100000000 00100000000000000000101100110000 00000010000010100000000010000011 00000000001011000000000000011011 00110000000000101001100100000100 00100000000000000000000000000000 00000000000000000000000000000000 11101000000101011010110000000000 11111011000000000011111011000000 00001111111100000000001001101100 00000000111110110000000000111011 11000000000010001010000000000011 00111100000000101111100100000000 10110010000000000000111110110000 00001010001010011000000010001011 00000000001111100000000000001011 10110000000000101110111000000000 01100000000000000000000000000000 00000000000000000000000000000000 10010100000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011110010010000000011 11101100000000001111000100000000 00111110000100000000111100110000 00000011110010000000000011111011 00000000001111100000000000001111 10110000000000111110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000000000 11111111000000000011111111000000 00011111111100000000001100111100 00000000111111110000000000111111 11000000000011001110001000000011 00111100000000001110100100010000 00110001000000000000110010110000 00000011001010000000000011001111 00000000001111110010000000001100 11110000000000111110010001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110110000000000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000100110 11000000000011011010110000000010 00101100000000001101100100000000 00100010001100000010100010110000 00001010001010000000000010001011 00000000001011000001000000001010 10110000001000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000011000101100 00000000101110110000000000100110 11000000000010001010000000000010 00001100000000001010100100000000 00100010001000000000100010110000 00000010101010000000000010001011 00000000001011101101100000001000 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000100100 11000000000010010010000000000010 00001100000000001001000100000000 10100000000000000010100000110000 00011010100010000000000010000011 00000000001011000000000000000010 00110000000000101100101000000100 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 10111011000000000011111011000000 00001011011100000000001100101100 00000000111110110000000000110111 11000000000011001010000000001011 00111100000000101110100100000000 00110010000000000000110010110000 00010011101010000000001011001011 00000000001111101100000000001100 10110000000000111110000000100010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000110111 11000000000011111110000000000011 11111100000000001111110100000010 00111111000000000000111111110000 00000011011110000000000011111111 00000000001111110000000000001111 11110000000100111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111100000000000011001111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000110011111110100001000011 00111110000000001111111110000000 00111111111000000000110111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111000110000000010001011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000100010111001100000000010 00101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101111000000000110 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110000010000001010000011000000 00001011001100000000001011001100 00000000101000110000000000101100 11000000000010111011000000000010 00001100000010001011001100000000 00101100110000000000100100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111000000110000010001011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011100000000010 00101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000000011101100000000001011 10110000000000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111100110000000011001011000000 00001111101100000000001111101100 00000000111010110000000000111110 11000000000011111010100000000011 00101100000000001111101100000000 00111110110000000000110110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101010000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11110000100000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111010011000001011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011001000000011 10101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101010000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010111000000000 10111000010000000110001011000000 00001011101100000000001011101100 00000000101110110000000000001110 11000000000010110011000000000011 01101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011100100000010000011000000 00000011001100000000001011001100 00000000101100110000000000001100 11000000000010110010010000000010 10001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111100000000000 00010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010000111100000 00001001011110000000001001011110 00000001101101111000000000101101 11100000000010110111100100000010 01011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010010111 10000000001011011110000000001011 01111000000000101110110000000100 00010000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000100000 11110011000000000010000011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 10001100010000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101101000000010 00010000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000100000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011110111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111000000000000011001011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011110010000000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110110000000000010000111000000 00001011011100000000001011011100 00010000101101110000000000101101 11000000000010110111000000000010 10011100000000001011011100000000 00111101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110010100000000010010111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 00011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110010011100000010000011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000100000010 10001100000000001011001100000000 00101000110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111110000000001011011010000001 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011110110100000000011 00101000000000001111101000000000 00101110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000100 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000010000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011001001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000001011 00100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010100000000 10110001110000000010001001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000100000010 00100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000001000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010100000000 10111001001000000010001001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 00100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100111000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110011001000000010000001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110011000000000010 00000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100101000000101 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000001011001000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 00100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111101000100000011111001000000 00001111100100000000001111100100 00000000101110010000000000111110 01000000000011111101000000000011 11100100000000001111100100000000 01111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111101100000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111101000001000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000110 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001010000000010110001000000 01001011000100000000011011000100 00000001101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001010000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000010111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001110100000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000000000011010110000100000 11111001010000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000110011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000001000000011 00100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010101110000000 10111110101000000010111010000000 00001011101000000001001011101000 00000000101110100000000000101110 10000000000010111110011000000011 01101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100100100000000 10110010000000000010110011000000 00001011001100000000001011001100 00000001101100110000000000101100 11000000000010110011000000000010 00001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001000000000000 10110100000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111100000000010 01011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110000000000100 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001101000001000 11110111100000000010110111100001 10001111011110000000001111011110 00000000111101111000000000111101 11100000010011110111100000100011 00011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111110001000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010000110101000 11111010000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011110011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001101101100000000001111 10110000000000111100001000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11100100100100000011101111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 10111110010000001111111110010000 00111111111001000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111100000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001010100000000 10000100000000000010000111000100 00001011011100000000001011011100 00000000101101110000000000101101 11000001000010110111000000000010 10011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10100101000000000110100111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010111111010010000010 00011100000001001011011100000001 00101101110000000000001101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100010000000000 10000000100000000110000011000000 00001011001100000000001011001100 00000000101100110000000001101100 11000000000010110011100000000010 10001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010100000000000 11100010000010000011101011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011110010010000000011 10101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01000000000000000000000000000000 00000000000000000000000000000000 10000000000000001110100100000000 11111000000000000011111011000000 00001111101100000000001111101100 00000100111110110000000000111110 11000000000011111011010000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001011101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111111000000000 11111111000000100011101111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111101000000000011 00111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000001001111 11110000000100111100100001000000 00110000000000000000000000000000 00000000000000000000000000000000 10000001010001000110111100000000 10111011010000000010001011000001 00001011101100000000001001101100 00000000101110110000000000111010 11000000000010111001100000000010 10101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110100001000100 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010000001000000 10111000010000000010101011000000 00011011101100000000001011101100 00000000101110110000000000101110 11000000000010111011100010000010 00101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000000000000000 10111000000000000010100011000000 00001011001100000000001001001100 00000000101100110000000000101000 11000000000010110011000000000010 10001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000101 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110010000000000 11111001000000000011101011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000100011 01010000000000000000000000000000 00000000000000000000000000000000 10100000000110011101010000000000 11111101000000000011011111000000 00001111111100000000001111111100 00000000111111110000000000111011 11000000000011110111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100100000000 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000110111 11100000000011001111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11001000000000111111000000000101 01100000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000010111011100000 00001011001100000000001011101110 00000000101100110000000000100010 11000000000011011011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10101000000000101110000000000110 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000100100 11000000000010000011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00010000000000101110001000000001 00110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000100010 11000000000010011011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10000100010000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000001000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000110110 11000000000011001011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10000000000000111100000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 10111111000000000011111111000000 00001101111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001101111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11100000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001101101100000000001110101100 00000000111110110000000000111010 11000000000011101011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110100000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001000101100 00000000101110110000000000100010 11000000000010001011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10100000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101110110000000000101010 11000000000010100011000000000010 11001100000000001001001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00000000000000101111100000000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001000011110 00000000101101111000000000100001 11100000000010000111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111001100000000001110001100 00000000111100110000000000111010 11000000000011100011000000000011 11001100000000001111001100000000 00111100110000000000101100110000 00000011110011000000000011110011 00000000001111001100000000001111 00010000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11010000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101110000000001101101100 00000000111110111000000000110010 11000000001011001011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10001000000000110110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011111100000000001000011100 00000000101101110000000000100011 11000000000010000111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000010001011 01110000000000100001001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001001011110 00000000101101111000000010100001 11100000000010000111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 11111000000000100111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001000001100 00000000101100110000000000100000 11000000000010000011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000100001001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001101101000 00000000111110100000000000110010 10000000000011001010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 11101000100000110111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011001001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000001010001001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101100 01000000000010001001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010000001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111100000000000000111110 00000000000011001000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100101000001111100100 00000000111110011010100000111110 01101010000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 01010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000110010 01000000000011001001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101000 00000000000010101000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10100000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000100000 01000000000010000001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101100010000000000101010 01000000000010101001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000001000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000110010 01000000000011001001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 10111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10011010000000111100101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000110010 00000000000011001000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001001101000000000001001101000 00000000101110100000000010100010 10000000001010001010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000100010 11000000000010000011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001001011100100000001001011100 00000000101101110001000000100001 11000000000010000111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111111111010000000110001 11100000000011000111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00000101101100011000001001101100 00000000111110110000100000111110 11010100000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011011011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001100111110 00000000111111111000000000111011 11110000000011011111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001101111110000000001110 01111000000000110001000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001101011100 00000000101101110000000000110101 11000000000010100111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000100000110110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001000011100 00000000101101110000000000101001 11000000000010010111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010010111000000000010110111 00000000001011011100000000001011 11110000000000100000010010000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011101100000000001001001100 00000000101110110000000000100100 11000000000010100011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000010001011 00111100000000100101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111111100000000001100101100 00000000111111110000000000111011 11000000000011011011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001101101100000000001110 10111101000000110010101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110010000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001100111100 00000000111111110000000000110011 11000000000011001111000000000011 11111100000000001110111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000000001 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000101010 11000000000010101011000000000010 11101100000000001001101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000000011101100000001001001 10110000001000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000100000 11000000000010001011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000001000010111011 00000000001001101100000000001001 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101000 11000000000010100011000000000010 11001100000000001001001100000000 00101100110000000000101100110000 00000000110011000000000010110011 00000000001011001100000000001001 00110000000000101100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 00001111011100000000001100101100 00000000111101110000000000110001 11000000000011001011000000000011 11101100000000001110101100000000 00111110110000000000111110110000 00000001111011000000000011111011 00000000001111101100000000001101 10110000000000111110000000000010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001011111100 00000000111111110000001000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000011000001110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11101111100000000011101111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 00111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000000111011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000010010 10101110000000001011101110000000 00101110111000000000111010111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000110100011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 00001100000010001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 10101100000000001011101100000000 00101110110000000000100110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11101011000000000011101011000000 00001111101100000000001011101100 00000000111110110000000000111110 11000000000011111011000000000011 00101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100010000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111011110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000100 01000000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011011011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000100 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010110011110100000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111011000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000100100110000000000101100 11000000000010110011000100000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000000001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100001000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101110110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111001100000000001111001100 00000000110100110000000000111100 11000000000011110011000000000011 11001100010000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111001011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000000 11111100000100001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001011111100000000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000101100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10100111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11101010000000000010111010000000 00001011101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000001001111101000000010 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000101111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001100000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000100000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000001000111111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111010000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000001 11111001000000000111111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000001111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11101001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111101000001000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001110 10010000000000111000111000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10100001000000000010110001000000 00001011000100000000001010000100 00000000101100010000000000101100 01000000000010110001000000100010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001010 00010000000000101001001000000001 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000010000 10111001000001000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000001000010 11100100000000001011100100000100 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000010000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11101001000000000011111001000000 00001011100100000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001110 10010000000000111010100000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000100111111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11101000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000111111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111110110100000010 11101000000000001011101000000000 00101110100000000000100110100000 00000010111010000000000011101010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10100011000000000010110011000000 00001011001100000000011011001100 00000000101100110000000000101100 11000000000010110011110000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000010000 10110111000001000010110111000000 00001011011100000000001011011100 00000100101101110000000000101101 11000000000010110110010000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010100111 00000000001011011100000000001011 01110000000000101100100000000000 01100000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11100111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000010110101100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000110110110000 00000011111011000000000011101011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000000011111111000000000 11111111100000010011111111100000 01001111111110000010001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110001000000 11110111000100000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111010000000010 11011100000000001110011100000000 00111001110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000010 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101001110000000000100101 11000000000010100111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001010001100000000 00101000110000000000100100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101000000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000110110 11000000000011101000000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101100000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11101011000000000011111011000000 00001111101100000000001111101100 00000100111110110000000000111110 11000000000011111000000000000011 11101100000010001111101100000000 00111110110000000001111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110100000000000 00010000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111011110000000000111111 11000000000011111101000000000011 11111100000000001111111100000000 00111111110000000001111111110000 00100011111111000000000011111111 00000000001111111100000001001111 11110000000100111100000101000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 11101011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111001110000000010 11101100000000001001101100000000 00101110110000000001101110110000 00000010111011000000000011101011 00000000001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101010 11000000000010111001100000000110 11101100000000001011101100000001 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10100011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110001000000000110 11001100000000001001001100000000 00101100110000000000101100110000 00000010110011000000000010100011 00000000001011001100000000001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111010 11000000000010111001000000000011 11101100000000001111101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000100110 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111101000000000000 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000010001111111100000000001111 11110000000000111110100000000011 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11001000000000110011000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000010111011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10001000000000100011000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10100011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101000 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010110011 00000000001011001100000000001011 10000000000000100011001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000001001011101100 00000000101110110000000000100110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000010100011000000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10100100100000110000000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011011111000000000011111111 00000000001111111100000000001111 11000000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000100111110110000001000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10100000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000001001011 00110000000000101111011000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001001001100000000001001001100 00000000101100110000000000100100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00010000000000101111101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01011000000000101111110000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001101001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00000000000000111101101000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000011011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111010110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01010000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101001111000000000101001 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01101000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000001011011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111010100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 11100000100000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000110110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000011 11100100000000001011100100000000 00101110010000000000100110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010101001000000000010111001 00000000001011100100000000011011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000100100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00100000000000000000000000000000 00000000000000000000000000000000 10111000000001010110000000000000 11111000000000000010111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011101000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000101011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 10100100000000001111100100000000 00111110010000000000110110010000 00000011111001000000000011111001 00000000001111100100000000001111 11010000000000111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 00010000000000111110111000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010100001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000011011 10010000100000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010100001000111110100000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10011010000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000100000000110000101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000100000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000100100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000001001011 00110000000000100100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 11111000000000100100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000110100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000001 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000010001111 10110000000010111000001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000100001011011100000000001011 01110010000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100010010000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000011011 00111100000000101101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10111000100000111110101000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000001001111101100000000001111 10110000000000111110110000000100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000100000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000001000010111011 00000000001011101100000101001011 10110000001000101110000101000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001001101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000100110 00000000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000010100111110100000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11101111100000000011111111100000 00001111111110010000001101110000 10000000110011111000000000111011 11100000000011111111000000000011 00110010000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000100 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 11111011100000000011101011100000 00001011101100000000001000101011 00000000100010111000000000111010 11100000000010111011110100000010 00100000000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000101000000000 01000100100000110000000001101100 11000000000010110011000000000110 00000100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011001100000000001000100001 00000000100010110000000000101110 11000000000010111011000001000010 00100110001000001011101100000000 00101110110000000000101110111000 10000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11101011000000000011111011000000 00001111101100000000001101100110 01000010110010110000000000111110 11000000000011111011000000000011 00100010000000001111101100000000 00111110110000000000111110111000 00100011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11101111000000000011101111000000 00001111111100000000000111111000 00000000111111110000000000111011 11000000000011111111000001001011 11110000000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001110001100 00000000111110110000000000111110 11000000000011111011000110000011 11101101000000001100101100000000 00111110110001000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000000 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101111110000001000101100 00000000101110110000000000101110 11000000000010110111000000000010 11101100000000001010101100000000 00101110111101000000101110010000 00000010111011000000000010111011 00000100001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001000000000 00001000101100110000000000101100 11000000000010110011110000000010 11000000000000001000001100000000 00101100111000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000100 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000000001111000000000 10110111100000000010110111100000 00001011011110000100101000011110 00000000101101111000000000100101 11100000000010110111100000000010 11010010000000001010011110000000 00101101111000000000101101110001 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111101100000001001110000000 00000000111100110000000000111100 11000000000011110011000000000011 11100000000000001100001100000000 00111100110000000000111100110000 00000111110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111001011110000000000 11111111000000000011111111000000 00001111111100000000001111111000 00000000111111110000000000111111 11000000000011111111000010000011 11110100000000011111111100000000 00111111110000000000111111110001 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101100000000101100100100 00000000110010110000000000111110 11000000000011111011100000000011 00100000000000001111101100000000 00111100111000000000110010110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000011001110000000000 10110111000000000010110111000000 00001011111100000000001000011100 00000000110101110000000001101101 11000000000010110111001000000010 00011000000000001011011100000000 00101101110000000000110101100000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001000000110 00000000100001111000000000101001 11100000000010110011101000000010 00011010000000001011011110000000 00101101111000000000100001111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00011011001100000000001000001110 00000000100100110000000000101100 11000000000010110011000001000010 00101100000000001011001100000000 00101100110000000000100100111101 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001100111011 00000000110010100000000000111110 10000000000011111010000000000011 00111010100000001111101000000000 00111110100000000000110011100101 00000011111010000000010011111010 00000100001111101000000000001111 10100000000000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 01100000111110000000000000111110 00000000000011111000000000001011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001100000100 00000000110010010000000000111110 01000000000111111001100000000011 11100110000000001100100100000000 00111110010000000000111110010000 00100011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100110010000101000100100 00000000101010010000000000101110 01000000000110111001010000000010 11100110000000001000100100000000 00101110010100000000101110010000 00000010111001000000000011111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011000100001000001000100100 00000000100010010000000000101110 01000000010010111001000101000010 11100100010000001000100100000000 01101110010000100000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001000000100 10000000101000010000000000101100 01000000000010110001001000000010 11000100000000101000000100000000 01101100010000000000100100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000001000110000000000000 11111000000000000011111000000000 00001111100001010000001100100000 00000000110010000000010000111110 00000000000010111010000000000011 11100001010010001100100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111001110010000000000 11111001000000000011111001000000 00001111100100000000001111110100 01000000111110010000000000111110 01000000000011111001000101000011 11110100000000001111100100000000 00111110010000000000111111010000 00000011111001000000000011101001 00000000001111100100000000001111 10010000000000111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000000011110010000000000 11111001000000000011111001000000 00001111110100000000001111100100 00000000110110010000000000111110 01000000000011111101000000001011 01110100000000001100100100000000 00111111010000000000110010010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100111000000101 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001110000000000000001011100000 00000000110110000000000000101110 00000000000010111000000000000010 00100010100000001101100000000000 00101110000000000000110110000000 00000011101000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000010 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010100001000000 00001011000100000000011011000100 00000000101100010000000000101100 01000000000010110001000000000010 00001110001000001000000100000000 00101100010000000000100000010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000001 01100000000000000000000000000000 00000000000000000000000000000000 00011000000100011010010000000000 10111001000000000010111001000000 00001010100100000000001011100100 00000000100110010000000000101110 01000000000010111001000000000010 00100100100000001001100100000100 00101110010000000000100110010100 00000010101001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011101001000000 00001111100100000000001111100111 00100000111110010000000000111110 01000000000011111001000000000011 01100100000000001100100100000000 00111100010000000000110010010000 00000011111001000000010011111001 00000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001110100100000000001111100111 00000000111010010000000000111110 01000000000011111001000010000011 11100100000000001111100100000000 00111110010000000000111110010100 00000001111001000000000011111001 00000000001011100100000000001111 10010000000000111101101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000100000001100000000 00000000110110000000000000111110 00000000000111111000000100000011 11100000000000001100100000000000 00111110000010000000111110000100 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011111011000000101000101000 00000000111110100000000000111010 10000000000010110110000000000010 01101000000000101000101000000000 00101111100110000000111110100000 00000010111010000000000011101010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001110000000001001001100 00000000100000110000000000101100 11000000000010110011110000000010 11101100000000001000001100000000 00101100001000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011010110001000001001001100 00000000101001110000000000100001 11000000000010110111000000000110 01011100000000001000011100000000 00101101100000000000101001110000 00000010110111000000000010100111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001101011110 00000100100001111000000000111101 11100000000010110110100000000011 11110110000000001100011110000000 00111101001000000000101101111000 00000011110111100000000011110111 10000000011111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101000000000001110101100 00000000111110110000000000111010 11000000000011111011000001000011 11100100000000001111101100000000 00111110100000000000111110110000 00000011111011000000000011101011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001100111110 00000000111111111000000000111111 11100000000011111110100000000011 00111110000000001100111110000000 00111111001000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000011110111000000 00001011110000000000011000011100 00000000101101110000000000101101 11000000000010110110000000000011 01011100000000001101011100000000 00101101000000000000111001110001 10000011110111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011010100000000001000011100 00000000101101110000000000101101 11000000000010110110000000000010 00110100000000001001011100000000 00101101010000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010100011000000 00001011100000000000001000001111 01001000101100110000000000101100 11000000000010110010000000000010 01100101001000001001001100000000 00101100000000000000101100110000 00000010100011000000010010110011 00000000001011001100000000001011 00110000000000101101000100000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000010111011000000 00001111101000000000101100101100 00001000111110110000000000111110 11000000000011111001000000000011 00101101000000001101101100000000 00111110000000000000111110111000 00000010111011000001000011111011 00000000001111101100000000001111 10110000000000111110101100000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101001000000001111101100 10000100111110110000000000111110 11000000000011111011000000000011 11101110000000001111101100000000 00111110000000000000111010110010 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110100000000100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111111000000001110011100 00000000110011110000000000111111 11000000000011111110000000000011 00110100000000001100111100000000 00111111000000000000111111110000 00000011001111000000000011111111 00000000001111111100000000001111 11110000000000111100000101000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101000000000101000101100 00000000100010110000000000101110 11000000000010110011100000000011 01110100000000001000101100000000 00101110001000000000101100110000 00000011111011000000000010111011 00000000001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011100101000000001000101100 00000000100010110000000000101110 11000000000010111010000100000010 00100110000000001000101100000000 00101110000001000000101110110000 00000010001011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001001000000000000001000001100 00000010100000110000000000101100 11000000000010110010000000000010 01000100000000001000001100000000 00101100000000000000101110110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000010111011000000 00001111100100000000001110101100 00000000110010110000000000101110 11000000000011111010000000000011 00101100000000001100101100000000 00111110010000000000111110110000 00000011001011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000110 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111110000000000001111111100 00000000111111110000000000111111 11000000000011110110000000000011 11011100000000001111111100000000 00111111000000000100111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001110111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011001111 10000000001111111110000000001111 11111000000000111011000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000000001110111000000000 10111011100000000010111011100000 00001011101110000000001100101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000011011011 10000000001011101110000000001110 10111000000000101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10100011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00100100110000000000101100110000 00000010110011000000000010000011 00000000001011001100000000001011 00110000000000101111001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001010101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010011011 00000000001011101100000000001010 10110000000000101111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011110110000000000 11111011000000000011111011000000 00001111001100000000001111101100 00000000111110110000000000111110 11000000000010111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011110011000000000011001011 00000000001111101100000000001111 10110000000000111100100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000100011011110000000000 11111111000000000011111111000000 00001111111100000000001101111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000011111111100000000001111 11110000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011101011000000 00001111101100000000001100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011101011000100000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001000101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101110001100001011 10110000000000101111000000000000 01000000000000000000000000000000 00000000000000000000000000000000 11000000000001000000110000000000 10110011000000000010100011000000 00001011001110010000001001001100 00000000101100110000000000101100 11000000000010110011000000000010 10001100000000001011001100000000 00101100110000000000101100110000 00000010100011110010000010110011 00000000001011001111001000001011 00110000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000000001111000000000 10110111100000000010110111100000 00001011011100000000001001011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000011011 01111000000000001111111000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000110000000110000000000 11110011000000000011100011000000 00001111001100010000001101001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011100011000000000011110011 00000000001111001100010000001111 00110000000000111101101000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111001011110000000000 11111111000000000011111111000000 00001111011100100000001110111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000100011111 11110000000000111101000000000010 00100000000000000000000000000000 00000000000000000000000000000000 00001000000101011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111010110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000010011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00100000000000001001111000000000 10110111100000000010110111100000 00001011011110000000011011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101001111000000000101101111000 00000010110111100000000110110111 10000000001011011110000000001011 01111000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 11101000000001001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000001011011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101001010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111010100000000000111110100000 00000011110010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10001000000100001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011011001 00000000001111100100010000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000010010000000000 10111001000000000010111001000000 00001011100100100000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001001000000010001001 00000000001011100110000000001011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010101001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010011001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010000001 00000000001011001100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000111010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011101000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011011000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10111000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110111100000110 01110000000000000000000000000000 00000000000000000000000000000000 00111000000101011110010000000000 11111001000000000011111001000000 00001111110100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111101000000000011111001 00000000001111110100000000001111 10010000000100111110111000000000 01110000000000000000000000000000 00000000000000000000000000000000 00011000000000001010000000000000 10111000000000000011101000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100011000000000 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001001000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101000010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101001010010000000000 10111001000000000010101001000000 10001011101100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000001001011100100000000001011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111010010000000000111110010000 00000011111001000000000011111001 00000000011111100100000000001111 10010000000000111110000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000000001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100001000001111 10010000000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011101000000000 00001111100000001000001110100000 00000000111110000000000000111110 00000000000011101000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000010000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000001000010100000000000 10111010000000000010111010000000 00001011111010000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111110000000000010111010 00000000001011111001000000000011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000001010100110000000000 10110011000000000010100011000000 00001011001100000000001010001100 00000000101100110000000000101100 11000000000010100011000000000010 10001100000000001011001100000000 00101000110000000000101100110000 00000010110011100000000010110011 00000000001011001110000000001011 00110000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001110000000000 10110111000000000010110111000000 00001011011100001000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111010000000110110111 00000000001011010101000000001011 01110000000000101100000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000110000001111000000000 11110111100000000011100111100000 00001111011110000000001110011110 00000000111101111000000000111101 11100000000011100111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000010001111 01111000001000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111010000000000011111011 00000000001111100000000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01100000000001001011111000000000 11111111100000000011111111100000 00001111111010010000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111110100100000011111111 10000000001111111010000000001100 11111000000000111101000000000001 00100000000000000000000000000000 00000000000000000000000000000000 10101000000000001001110000000000 10110111000000000010110111000000 00001011010000000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110101000000000011100111 00000000001011011100000000001101 01110000000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011000000000011011011100 00000000101001110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110110000000000110110111 00000000001011010000000000001000 01110000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01000000000101001000110000000000 10110011000000000010110011000000 00001011000000000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000110110000000000000010100011 00000000001011000000000000011001 00110000000000101101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011010110000000000 11111011000000000011111011000000 00001111100100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111001000000000011111011 00000000001111001100000000001100 10110000000000111110101000000000 01100000000000000000000000000000 00000000000000000000000000000000 10100000000100001110110000000000 11111011000000000011111011000000 00001111100100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000111101011 00000010001111100100000000001111 10110000000000111110110000000100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111110000000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111101100000000011111111 00000000001111111100000000101100 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011100011000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111010100000000010111011 00000000001011100000000000001000 10110000000000101110010001100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010110110000000000 10111011000000000010111011000000 00001011101100010000001011101100 00000000101110110000000000101110 11000000000010101011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111000000100000010111011 00000000001011101000000001001000 10110000000100101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011000100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110001000000000010110011 00000000001011001100000000001000 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000110000110110000000000 11111011000000000011111011000000 00001111101000000000001111101100 00000000111110110000000000111110 11000000000011101011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111000000000000011111011 00000000001111100000000000001100 10110000000000101110100000000110 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011011110000000000 11111111000000000011111111000000 00001111110000000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111100000000000011111111 00000000001111010000000000001111 11110000000000111110000000100110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111110100000000011 10111100000000101100110110000000 00110011111000000000111111111000 00000011001111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000100 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000010111011100000 00001011101110000100001011101110 00011000101110111000001000101110 11100000000010111010100000000010 00111110000000101000100100000000 00100010111000010000101110111000 00000011011011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010111010000000000010 10000100000000001010001100000000 00100000110000000000101100110000 00000010000011000000000010110011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111010100010010010 00100100000000001000100100000000 00100010110000000000101110110000 00000010011011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000100111110110000000000111110 11000000010011111010110000000011 10111100000000101110100100000000 00110010110000000000111100110000 00100011001011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000100111 11000000000011111110000000000011 11101100011000101111111100000000 10111111110000000000111111110000 00010011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111010010000000011 11000100000000001100101100000000 00111110110000000000110110110010 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000000 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000100001011101100 00000000101110110000000000101110 11000000000010110010000000000010 11100101001000101000101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000100 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001001001100000000001011001100 00000000101100110000000000100100 11000000000010110000100100000010 11000100000000101000100100000000 00101100110000000000100100110100 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111100000000000 00010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 00001001011110000000001011011110 00000100101101111000000000101101 11100000000010110100100000000010 11010110010000001000010110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000000011011110000000001011 01111000000000101100100000000100 00010000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001101001100000000001111001100 00000000111100110000000000111100 11000000000011110010000000000011 11001100000000001100001100000000 00111100110000000000110100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101101000000010 00010000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111100000100000011 11111111000000001111110100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000000 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111001000000000011 11100101000000001110100100000000 00111110110000000000111100111000 00000011001011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000001001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11010100000000001000011100000000 00101101110000000000101101110000 00000011010111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001010011111000000 00101101111000000000101101111000 00000010000111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000111010010 11001100000000001000001110000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011110110100000000011 11101000000000001110101000000001 00111110100000010000111110100000 00000011001010000000000011111010 00000000001111101000000000001111 10100000000000111111101100000100 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000100 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001110001000011 00100100000000001100100100000000 00111110010000000000111110011001 00000000111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001100000001010 00000100000000001000100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 00100110001000101000100100000001 00101110010000010000101110010000 10000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100111000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010010001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 00000100100000001000000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100101000000101 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 00100000000000101100100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000010011111101000001000011 11010100010000101111110100101000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001101100100000000001111 10010000000000111110011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111101000000000011 10110110000000101100100100000000 00110010010000000000111111010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 00100000000000001000100010100000 00110110000000010000101110000000 00000000111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101000010000000000101100 01000000000010111001000000000010 10000101000000001000100100001000 00100000010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001001000000010 00100100100000001000100100000100 00100110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011111001000000 00001111100100000000001011100100 00000000111010010000000000111110 01000000000011111001100000000011 10000100000000001100000110000000 00110010010000000000111110010000 01000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001100000000011 11100110001000101111100100100000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 00100000000001001100100000000100 00111110000000000000111110000001 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010110010100000000011 01111001000001001010101000000000 00101110100000000000101111101100 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110001000000000010 00001000000000001000001100000000 00101100110000000000101100101100 10000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101100000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001001011100 00000000101101110000000000101101 11000000000010111101010000000010 01011001000000001010011100000000 00101101110000000000101101100000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000010110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110101100000000011 00011110000000001100011110000000 00111101111000000000111101011000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111110001000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000100001111101100 00000000111110110000000000111110 11000000000011110001000000000011 11000000000000001111101100000000 00111110110000000000111110000000 00000011111011000000000011111011 00000000001101101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100000000011101111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111101100000000011 10111010000000001100111110000000 00111111111000000000111111001000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111100000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000011100111000000 00001011011100000000001111011100 00000000101101110000000000111101 11000000000010110101000000000010 00011000010000001000011100000000 00101101110000000000101101000000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010111111000000000010 10010100000000001000011100001000 00101101110000000000101101000000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101000 11000000000010110011100000000010 00000000000000101000001110000000 00101100110000000000101100000000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001011101100 00000000111110110000000000101110 11000000000011111011100010000011 10000000000000101100111110000000 00111110110000000000111110000000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011101011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111001000000100011 01100000000000001111101100000000 00111110110000000000111110000000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11100100000000001100111100000000 00111111110000000000111111011000 00000011111111000000000011111111 00000000001101111100000000001111 11110000000000111100100001000000 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000100001011101100 00000000101110110000001000101110 11000000000010111001100000010010 11100010000000101000111100000000 00101110110000000000101110001001 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110100001000100 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000100000010 11100010001000001000101100000000 00101110110000000000101110000000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011001100000000001001001100 00000000101100110000000000100100 11000000000010010001000000000010 11000000000000001000001100000000 00101100110000000000101100000000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000101 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000010011111011000000000011 11100000000010001100101100000000 00111110110000000000111110000000 00000011111011000000000011111011 00000000001101101100000000001111 10110000000000111100000000000011 01010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000001111110000000001111111 11000000000011110111000000000011 11110000000000001111111100000000 00111111110000000000111111000000 00000011111111000000000011111111 00000000001111111100000000001101 11110000000000111110100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111100 10000000001111111110000000001111 11111000000000111111000000000001 01100000000000000000000000000000 00000000000000000000000000000000 10100000000100001110111000000000 10111011100000000010111011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111001 10000000001011101110000000001011 10111000000000101110100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010110010 00000000001011001100000000001011 00110000000000101110001000000001 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010110000000000 10111011000000000010111011000000 00001011101100000100001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000100011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111000 10000000001111101100000000001111 10110000000000111100000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000001111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111100 10010000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111001 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001110101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111001 00000000001011101100000000001011 10110000010000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000001 10110011000000000010110011000000 00001001001100000000001001001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010010000 00000000001011001100000000001011 00110000000000101111100000000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000100 10110111100000000010110111100000 00001011011110000000001010011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110101 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000101100110000 00000011110011000000000011110010 00100000001111001100010000001111 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000011011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000010 01100000000000000000000000000000 00000000000000000000000000000000 10001000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111010 00000000001111101100000000001111 10110000000000111110001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110110 00000000001011011100000000001011 01110000000000101101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000010001101111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 11000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111110 11011000001111101000000000001111 10100000000000111111101100000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 10001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000100011111101 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00001100001011100100000000001011 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 11000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00100000001111100100000000001111 10010000000000111100101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001000010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000010001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011110111 10000000001100111110000000001111 11111000000100111101000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001101011100000000001011 01110000000000101110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010111111 00000000001010011100000000001011 01110000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00001000001011001100000000001011 00110000000000101101100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001110101100000000001111 10110000000000111110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001001101100000000000111 10110000000000111110010000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001100111100000001001111 11110000010100111110000001100100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010110011 00000000001000101100000000001011 10110000000000101110000101000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001000101100000001001011 10110000010000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000000000000110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010111011 00000000001000001100000000001011 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000010000110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001100101100000000001111 10110000000000111110000000000010 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000101111111100000000001111 11110000000000111110100000000010 01110000000000000000000000000000 00000000000000000000000000000000 11000000000000011111111000000000 11111111100000000011111111100000 00001111110110000001001101111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000100 01110000000000000000000000000000 00000000000000000000000000000000 10000000000000001110111000000000 10111011100000000010111011100000 00001011100110000000001000001100 00100000101110111000000000101110 11100000000010111011100000000010 11101110000001001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000010 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010100011000000 00001010001100000000001001001100 10000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000001 00101100110000000001101100110000 00000010110011000000000010110011 00000000001011001100000000001010 00110000000000101010001000000001 01100000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100001000001000101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000001 01110000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111011000000000011111011000000 00001111101111000000001101101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 10001111111110100000001110111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00010011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101110100010101100101100 00100010110010110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011001110000000001000101111 00000000100010110000000000111110 11000000000010111011000000000010 11101100000010001011101100000000 00101110110000000000101110110000 00000011111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011000001000000001000001101 00000000100000110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 00001011011010000000001000011110 00100000100001111000000000101001 11100000000010110111100000000010 11011110000000011011011110000000 00101101111000000000101101111000 00000010100111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000000000000110000000000 11110011000000000011110011000000 00001111000100000000001100001100 00000000110000110000010001101100 11000000000011110011000000000011 11001100010000001111001100000000 00111100110000000000111100110000 00000010110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111011000000000001111111100 01000000111111110000000000111111 11000000000011111111000000000011 11111100000100001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111001010000000001100001100 00000000110010110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001101011100 00000000101001110000000000111001 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001010011110000010001000011110 00000000100001111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100100000101001001100 00000000000000110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000100100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111111000001000001100101000 00000010110010100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 10001111100001000000001111100000 00000000111110000000000000111010 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100111 00000000110010010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010011001000000 00001011100111001000001011100111 00000000100010010000000000101110 01000000000010111001000001000010 11100100000000001011100100000000 00101110010000000000100110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010011001000000 00001011100110000000001011000101 00000000100010010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010010001000000 00001011000100000000001011000100 00000010101000010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00100000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011011000000000 00001111100000000000001111100001 01000000110010000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011011001000000 00001111110100000000001111100100 00000000110110010000000000111110 01000000000011111001000000000010 11100100000000001111100100000000 00111110010000000000110110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110111100000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11101001000000000011111001000000 00001111110100000000001111110100 00000000110010010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100111000000001 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000010100010000000000000101110 00000000000011111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001110100000000000001011 10000000000000101100011000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10100001000000000010110001000000 00001011000100000000001011000100 00000000100100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000001 01100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100100000001011000100 00000000100110010000000000101110 01000000000010101001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001010100100000000001011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11101001000000000011111001000000 00001111100101100000001111100100 00000010110110010000000000111110 01000000000010111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111010010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001110100100000000001111 10010000000000111101101100000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100001000000001111100000 10000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000100 00011110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011111010001000001011111010 10000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001101100000001011001110 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011010100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111010110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000101101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100001000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111100100000000001111101000 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011111111000000000 11111111100000000011111111100000 00001111011110000000001100110110 00000000110011111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011101000000001101011100 00000000100001110000000000111101 11000000000011110111000000000010 11011100000000001011011100000000 00111101110000000000111001110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001010011000000000001001011000 00000000100001110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001010 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001000010000101000001000 00000000100000110000000000001000 11000000000000100011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011010110000000000 10111011000000000011111011000000 00001111000100000000001001101000 00000010110010110000000000101110 11000000000010111011000000000011 11101100000000001111101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 10001111100101100000001111101100 00000000111110110000000000111110 11000000000111111011000000000011 11101100000001001111101100000000 00111010110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000000001111110000000000 11101111000000000011111111000000 00001111110100000000001100110010 00000000111111110000000000111111 11000000000011111111000001000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111100000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011100011000000001010101001 00000000101110110000000000101110 11000000000010111011000000000010 11101100000100001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011100110000000001000100101 01000000101010110000000000101110 11000000000010111011000000000110 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110100000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00001011000100000000101000001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000001 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011111011000000 00001111100000000000001100000000 00000000111010110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000110 00000000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111110000000000001110111000 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000001111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000011011111111000000000 11111111100000100011111111100000 00001101111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000001 01100000000000000000000000000000 00000000000000000000000000000000 11100000000000001110111000000000 10111011100000000010111011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000010001011101110000000001011 10111000000000101111000000000000 00110000000000000000000000000000 00000000000000000000000000000000 11001000000001011100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001001001100000000 00101100110000000000101100110000 00000010100011000000000010110011 00000000001011001100000000001011 00110000000000101111001000000001 00110000000000000000000000000000 00000000000000000000000000000000 11100000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11111011000000000011111011000000 00001101101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000100001111 10110000000000111100000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000010000 11111111000000000011111111000000 00000111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000001000111111100000000100 01000000000000000000000000000000 00000000000000000000000000000000 01010100000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000110110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111011000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000001000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010010011000000000010110011 00000000001011001100000000001001 00110000000000101111000100000000 00000000000000000000000000000000 00000000000000000000000000000000 10110000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101111111000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000000000000110000000000 11110011000000000011110011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000101100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101001100000110 00000000000000000000000000000000 00000000000000000000000000000000 01000000000101011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000010 00100000000000000000000000000000 00000000000000000000000000000000 10001000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 11001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000011110111000000000011110111 00000000001011011100000000001111 01110000000000111111001000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101001111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010100011 00000000001011001100000000001010 00110000000000101001101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000110110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000000011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001001100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00100000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000111 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000011111100100000000001111 10010000000000111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000011011110010000000000 11111001000000000011111001000000 00001111100100000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011101001000000000111111001 00000000001111100100000000001111 10010000000000111110111000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000000001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000111010000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001111 10000000000000111100011000000000 00110000000000000000000000000000 00000000000000000000000000000000 01001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001010000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010100001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101010010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001010 10010000000000101000011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101001010010000000000 11111001000000000011111001000000 00001111100100000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011101001000000000010111001 00000000001111100100000000001011 10010000000000101110100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01101000000000001010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111010010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000010001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001000010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000011 10101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100001000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001100000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 10011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000100101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000000000001111000000000 11110111100000000010110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 10101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000000 11111111100000000011111111100000 00001110111110000000001111111110 00000000111011111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001111 01110000000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000000010110111000000 00001010011100000000001011011100 00000000101001110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101001110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001010 00110000000000101101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001110101100000000001011101100 00000000111010110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111010110000 00000010111011000000000011111011 00000000001111101100000000001011 10110000000000111110101000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000010000111110110000000100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001101 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000111110 11000000000010111011000000000011 10101100000000001011101100000000 00101110110000000000101110110000 00000011111011000000000010111011 00000000001011101100000000001011 10110000010000101110000001100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000000000000110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101000 11000000000010110011000000000010 10001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000010000110110000000000 11111011000000000010111011000000 00001111101100000000001111101100 00000000111110110000000000101110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001101 10110000000000111110000000000110 00010000000000000000000000000000 00000000000000000000000000000000 10100000000110011111110000000000 11111111000000000011111111000000 00001111111100000000011111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011101111000000000011111111 00000000001111111100000000001111 11110000001000111110100000100010 01110000000000000000000000000000 00000000000000000000000000000000 11000000000000011111111000000000 11111111100000000011111111100000 00001101111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111100000000001011111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000000001110111000000000 10111011100000000010111011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11111110000000001011101110000000 00101110111000000000101110111000 00000010011011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000110 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000001 00001011001100000100001011001100 00000000101100110000000000001000 11000000000010110011000000000010 11001100000000001001001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001010 00110000000000101010001000000001 01100000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11111100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000001 01110000000000000000000000000000 00000000000000000000000000000000 01000000000101011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111010 11000000000011111011000000000010 11101100000000001111101100000000 00111110110000011000111110110000 00000001111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011011111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00011111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100001000001111101100000000 00111110110000000000111110110000 00000111111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000100010111011000001 10001011101100000000001011101100 00001000101110110000000000111110 11000000000010111011000000000010 11101111000000001110101100000000 00101110110000000000101110110000 00000011111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001101010000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111000000000 10110111100000000010110111100000 10011011011110000010001011011110 00000000101101111000000000101001 11100000000010110111100000000010 11011110000000001010011110000000 00101101111000000000101101111000 00000010100111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000100 00010000000000000000000000000000 00000000000000000000000000000000 01001000000000000000110000000000 11110011000000000011110011000000 00001011001100000000001111001100 00000000111100110000000000101100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000010110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000010 00010000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000010001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111110000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001110101100000001001111101100 00000000011110110000000000111110 11000000000011111011000000000011 11001100010000001100101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00000011011100000000001011011100 00000001101101110000000000111001 11000000000010010111000000000010 11011100100000001010011100000000 00101101110000000000001101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000110 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001011011110000000001010011110 00000001101001111000000000101101 11100000000010110111100000000010 11011110000000001000011110000000 00101101111000000000101101111000 00100010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000100001011001100 00000000101100110000000000101100 11000000000010010011000000000010 11001100000000001010001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000000 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001100101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000100 01010000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000001001111100000 00000100111110000000000000111010 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001100100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000111010010000000000101110 01000000000010111001000000010010 11010101000000001000100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000000010010010000000000 10111001000000000010111001000000 00011011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001000100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100111000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000110110001000000 00001011000100000000001011000100 00000000101000010000000000101100 01000000000010110001000000000010 11000100001000101000000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100101000000101 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011000010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11101010100000001100100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000011011110010000000000 11111001000000000011111001000000 00001111100100000000001011100100 00000000111010010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000101110010000000000111110 01000000000011111001000000000011 11110110000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000110111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000110 00100000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000100101100010000000001101100 01000000000010110001000000000010 11000101000000001011000100000000 00101100010000000000101100010000 00000000110001000000000010110001 00000000001011000100000000001010 00010000000000101101001000000001 00100000000000000000000000000000 00000000000000000000000000000000 00011000000100011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000011011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000001000 11111001000000000011111001000000 00001111100100000000001011100100 00000001101110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000010111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000010000011010010000000000 11111001000000000011111001000000 00001111100100000010001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000100000001011100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000001001011101000 00000000111010100000000000101110 10000000000010111010000000000010 11111000000000001011101000000000 00101110100000001000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000001100110000000000001100 11000000000010110011000000000010 11000100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11010101000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110000000000100 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000001111101 11100000010011110111100000100011 11010110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111110001000000010 00100000000000000000000000000000 00000000000000000000000000000000 00001000000011011010110000001000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111010110000000000111110 11000000000011111011000000000011 11100100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001011 10110000000000111100001000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11111111100100000011111111100100 00001011111110010000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11110110000000001100111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000000000010110111000000 00001011011100000100001011011100 01010000101101110000000000101101 11000000000010110111000000000010 11010101000000001010011100000000 00101101110000000000101101110000 00000001100111000000000010110111 00000000001011011100000000001011 01110000000000101110001000000110 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000001001110000000000 10110111000000010010110111000000 00000010011100000010001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11000100000000001001011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101000000000000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000100101100110000001000101100 11000000000010110011000000000010 11000100000000001011001100000000 00101100110000000000101100110000 00000000100011000000000010110011 00000000001011001100000000000011 00110000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001011101100 00000000111110110000000000001110 11000000000011111011000000000011 11000100000000001101101100000000 00111110110000000000101110110000 00000010111011000000000011111011 00000000001111101100000000001011 10110000000000111110101100000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000100111110 11000000010011111011000000000011 11101100000000001110101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11110100100000001101111100000000 00111111110000000001111111110000 00000011101111000000000011111111 00000000001111111100000000001111 11110000000000111100100001000100 00010000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000111110 11000000000010111011000000000010 11101110000000001000101100000000 00101110110000000000101110110000 00000011101011000000000010111011 00000000001011101100000000001011 10110000000000101110100001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010101011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101000000000001001101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000000 10110011000000000010110011000000 00011011001100000000001011001100 00000001101100110000000000101000 11000000000010110011000000000010 11001100000000001000001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000011011 00110000000000101100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00000000000011010110110000000000 11111011000000000011101011000000 00001111101100000000001111101100 00000000111110110000000000101110 11000000000011111011000000000011 11101100000000001101101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000011 00010000000000000000000000000000 00000000000000000000000000000000 10100000000110011111110000000000 11111111000000000011111111000000 00001111111100000000011111111100 00000000111111110000000001111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000001111111110000 00000011101111000000000011111111 00000000001111111100000000011111 11110000000000111110100000000101 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11101111100000000011111111100001 10001111111110000000001101111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000011101011100000 00001011101110000000001011101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000011111011100000000010111011 10000000001111101110000000001111 10111000010000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10100011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00100100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010101011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010101011000000000000111011 00000000001010101100000000001010 10110000000001101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11101011000000000011111011000000 00001111101100000000001101101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000010111011000000000011111011 00000000001011101100000000001011 10110000000000111100000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00001111111100000000000111111100 00000000111111110000000000111111 11000000000001111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000010000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000010001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111100100000000 01010000000000000000000000000000 00000000000000000000000000000000 01100000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111001100000000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000000011111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000010 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001110101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000001111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001111011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001110011100000000001111 01110000000000111101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10110111100000000010110111100000 00001010011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 01000010110111100000000010110111 10000000001011011110000000001011 01111000000000101111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000100100110000 00000010110011000000000010110011 00000000001010001100000000001010 00110000000000101001001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111010000000000011111010000000 00001110101000000000001011101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001011 10100000000000101111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001110100000000001001111 10000000000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000000111001000000 00001011100100000000001011100100 00000000100110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00100000000000000000000000000000 00000000000000000000000000000000 10111000000011000110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000110110010000000000111110 01000000000011111001000000000010 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 11111000000000000011101000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000001110000000 00000010111000000000000011111000 00000000001011100000000000001111 10000000000000101100111000000100 00010000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10101001000000000010101001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010101001 00000000001011100100000000001010 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 10111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000010111001 00000000001111100100000000001011 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000010000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000111111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000001000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111101000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110001000000 10110111000000000010110111000000 00001011011100000000001110011100 00000000101101110000000001101101 11000000000011100111000000000010 11011100000000011011011100000000 00101101110000000000101101110000 00000011110111000000000011110111 00000000001011011100000000001110 01110000000000111110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00010000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100010000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001010001100 00000000101100110000000000101100 11000000000010100011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010100011000000000010100011 00000000001011001100000000001010 00110000000000101001100100000100 00110000000000000000000000000000 00000000000000000000000000000000 10111000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000001000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000010111011000000000010111011 00000000001111101100000000001011 10110000000000101110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001110101100 00000000111110110000000000111110 11000000000011101011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000011001110 10110000000000111110010100000000 00110000000000000000000000000000 00000000000000000000000000000000 10010000000100001111110000000000 11111111000000000011111111000000 00001111111100000000001110111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000001111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000000011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000001100000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000001110 11000000000010111011000000000010 11101100000000001011101100000000 00101010110000000000101110110000 00000010111011000000000110111011 00000000001011101100000000001011 10110000000100101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000011000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001110101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000010 00000000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000010000111111110000 00000011111111000000000011111111 00000000001111111100000000011111 11110000000000111110100000000111 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111011000000000 11001111100000000011001100000000 00001000111110000000001100111110 00000100111111111000010000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110010000000000 10001010000000000010001010000000 00001000101100000000101000101110 00000000101110111000000000101110 11100000000010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000100010111011 10000000001011101110000000001011 10111000000000101110000000000110 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011110110000000010 10001011000000000010000000000000 01001000001100000000001000001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000110110011000000000010110011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010011000000000 10001011000000000010001011010000 00001000001100000100001000101100 00000000101110110000000100101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000010000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111000000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000101011110111110000100 11000010100000001011001000000000 00101100101100000000001100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000001001111101100000100001111 10110000000000111101000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011010000000000 11111110101000100011111100000000 00101111111100000010001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000100111111110000 00010011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110100000000 11001011000100000011000011010010 00001000101100000000001011101100 00000000111110110000000000111110 11000000010011111011000001000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000010111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010000110010000000 10001010000000100010001011000011 00001000101111011000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000001000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100010000000000 10000011000010010010000001000000 00101000001110000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001001000000010 10001110100000000010000111100100 00001000011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000100010110111 10000000001011011110000000001011 01111000000000101100100000000000 00010000000000000000000000000000 00000000000000000000000000000000 01001000000010000010110000000000 11000011000000010011001000000100 00101100001100010000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110000000000111100110000 00000011110011000100000011110011 00000000001111001100000000001111 00110000000000111101001000000010 00010000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000010 11110100000000101011111110000100 00001111111100010000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000010 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011100010000000010 11001011000000000010001001010010 01001100101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000000111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001010000000000 10001110000000000010000101000000 00001000011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000100101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000110 01000000000000000000000000000000 00000000000000000000000000000000 11000000000000001011111000100000 10000111100000000010000110100010 00001000011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000001101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100111000000000 10000000010010001010000011000000 00001000001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000000 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011001100100000000 11001110010000010011001010010000 00101100101000000000001111101000 00010000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00101110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000100 01110000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000100000 11111000000000000011110000010010 00001111100000000000001111100000 00000100111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110011000000000 11001001000100000011001011000100 00001100100111000100001100100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000001000110011100001000 10001001110000000010001001110000 00101000100110000000101000100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000010001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010001000010 10000011010000000010001001000000 01001000000100000000001000100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100111000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000010011000000000 10000001010000001010000011001000 00001000000101000010101000000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000010010110001 00000000001011000100000000001011 00010000000100101100101000000101 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000100000000 11001000010000010011000000000101 00001100101001000000001100100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 01111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011111010000100000 11111101000000000011111001010000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 01000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000100 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11001001000000000011001001000000 00001100100100000000000111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000000111100100000000001111 10010000000000111100011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001100000000000010 10001000000000001010001000000000 00001000110000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010111000 00000000001011100000000000001011 10000000000000101100111000000110 00100000000000000000000000000000 00000000000000000000000000000000 00001000000001011101010000000010 10000101000000000010000101000000 00001000010100000100001001000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001001000100000000 01101100010000000000001100010000 00100000110001000000000010110001 00000000001011000100000000001011 00010000000000101101001000000001 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010011000001000 10000101000000000010000101000000 00001000111100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000100110010000 00000000111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 00100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010010000010 11001001001000000011001001101000 00101100100100000000001101100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001101100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000100100 11111001100101000011111001001000 00001111100100000000001111100100 00000100111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101001000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000100000000 11001000110001000011001000100000 00001111100000000000001100100000 00001000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000001010011111000 00000000000111100000000001001111 10000000010000111100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010010101100000000 10001010000000000010001010001000 00001011101000000000001000101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000010001011101000000010 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010110110101000000 10000011000000000010000011100000 00001011001110000000001000001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10000111000000001010000111000000 00001011011111000000001000011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000010 00101101110000000000101101110000 01000010110111000000000010110111 00000000001011011100000000001011 01110000000000101110000000000100 01100000000000000000000000000000 00000000000000000000000000000000 10101000000010000001101000000010 11001111100000001011000111100000 00001111111010010000101100011110 00001000111101111000000000111101 11100000100011110111100000000011 11011110000000001111011110000000 00011101111000000000111101111000 00000011110111100000100011110111 10000000001111011110000000001111 01111000000000111110001000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010000000000000 11111000000000000011111010000000 00001111101000000010001111101100 00000000111110110000000000111110 11000000000011111011000000000010 11101100000001001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001011101100000000001111 10110000000000111100001000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000001011111111000000000 11001111100000000011001111100100 00001100111110000000001010111110 01000000111111111000001000011111 11100000100001111111100000000011 11111110000000001111111110010000 00111111111000000000111111111001 00000010111111100100100011111111 10000000001111111110000000001011 11111001000000111100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000000011001110000000000 10000111001010000010000101000010 00001000011100100000001000011100 00000000001101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110001 00010010010111000000000010110111 00000000001011011100000000001011 01110000000000101110101000000110 00100000000000000000000000000000 00000000000000000000000000000000 00000000000100001001100000000000 10000111000000010110000111000000 10001000010000000100001000011100 00000000101101110000000000100101 11000000000010110111000000000010 11011100000000001011011100000010 00101101110000000000101101110000 00100000110111000000100010110111 00000000001011011100000000001011 01110000001000101100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000101001110001001000000 10001000000000100100001000110000 00001000100000000000001000001100 00000000101100110000000001100100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000010000100100110000 00000010010011000000000010110011 00000000001011001100000100001011 00110000000000101100100100000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000010 11001001010000010011001011000000 00001100101100000000100100101100 00000000111110110000000000110110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000001111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110100000000 11111011000000000011111011000000 00001111100000000000001111101100 00000000111110110000000100111110 11000000010011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00010011011011000000000011111011 00000000001111101100000001001111 10110000000000111110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00000001000100001111110000100000 11001101000010000011001101000010 01001100111100000000001101111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111100100001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110010110010000 10001000010000000010001000010000 00001000101000000000011000101100 00000000101110110000000000101110 11000000000010111011000001000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110100001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010001000000010 10001000100010000010001010110000 00001000101110000010001000101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101010110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000000000000010 10000011000000001010000000000000 01001000000000000000001000001100 00000100101100110000000000101100 11000000000010110011000000010010 11001100000000001011001100000000 00001100110000000000101100110000 00000000110011000000000110110011 00000000001011001100000001001011 00110000000000101100001000000101 00000000000000000000000000000000 00000000000000000000000000000000 00000000000001010100100000000000 11000000000000000011000011000000 01001100000100000000101100101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000011 01010000000000000000000000000000 00000000000000000000000000000000 10100000000101011111000000000000 11111100000000000011111100000000 00000111110000000100001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000010000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100000000000 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11111111100000000011111111100000 00001110111110000000001101111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001101111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10111011100000000010111011100000 00001011101110000001001011101110 00000000101110111000000000101110 11100000100010111011100000000010 11101110000000001011101110000000 00101110111000000000101110111000 00000010111011100000000010111011 10000000001011101110000000001011 10111000000000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10110011000000000010110011000000 00001010001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00100100110000001000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000100111011000000000000111011 00000000001011101100000000001011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11111011000001010011111011000000 01001110101100000000001101101100 00000000111110110000000000111110 11000000000011111011000001000011 11101100000000001101101100000000 00111110110000000000111110110000 00000011111011000001000011111011 00000000001111101100000000001111 10110000000000111100100000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000000000011111111000000 00000111111100000000001011111100 00000000111111110000000000011111 11000000000001111111000000000011 11111100000000001111111100000000 01111111110000000000111111110000 00010011111111000000000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001110101100000000001110101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10110011000000000010110011000001 00000011001100000100000011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000001000000110011 00000000001011001100000000001011 00110000000000101111000000000000 01010000000000000000000000000000 00000000000000000000000000000000 01100000000000010001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000001101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101101100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000000 00001111001100010000001110001100 00000000111100110000000001111100 11000000000011110011000001010011 11001100000000001111001100000000 00111100110001000000111100110000 01000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101101000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000000 11111111000000000011111111000000 00001111111100000100001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000010000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000110 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110111000000000010110111000000 00001011011100000000011011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000001101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000001000000001001111000000000 10110111100000000010110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000100101100110000000000101100 11000000000010110011000000100010 11001100000000001011001100000000 00101100110000000001100100110000 00000010010011000000000010110011 00000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000100101011010100000000000 11111010000000000011111010000000 00001111101000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000000 00111110100000000000111110100000 00000011111010000000000011111010 00000000001111101000000000001111 10100000000000111111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001010000000001110000000000000 11111000000000010011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000001001111 10000000000000111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001010000100001110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00100000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000010 11100100000000001011100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000001 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000000111000000000000010111000 00000000001011100000000000001011 10000000010000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000001011100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 01010000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000101110010000000000101110 01000000100010111001000000000010 11100100000000001011100100000000 00101110010000010000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 10111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000010000 00100000000000000000000000000000 00000000000000000000000000000000 00101000000100001010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000001000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00100000100001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010111010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000000000010001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000001000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100000000011110111100000 00001111011110000000001111011110 00000000111101111000000000111101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000010 01100000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000001000 11111111100000000011111111100000 00001111111110000000001111111110 00000000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011111111100000000011111111 10000000000111111110000000001111 11111000000000111101000000000000 01110000000000000000000000000000 00000000000000000000000000000000 11101000000100011001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000100101101 11000000000110110111000000000010 11011100000001001011011100000000 00101101110000000000101101110000 00000010110111000100000010110111 00000000001011011100000000011011 01110000000000101110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000000001001110000000000 10110111000000000010110111000000 00001011011100000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100010001000000 00100000000000000000000000000000 00000000000000000000000000000000 00100000000101001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000001000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000111111011000000000011111011 00000010001111101100000011001111 10110000000100111110111000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000010001111101100000100 00111110110000000000111110110000 00000011111011000000100011111011 00000001001111101100000000001111 10110000001000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 11000000000100001111110000000000 11111111000000000011111111000000 00001111111100000000001111111100 00000000111111110000000000111011 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000000010111011000000 00001011101100000000000011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000000000101110 11000000000010111011000000000010 11101100000000001011101100000001 00101110110000000000101110110000 00000010111011000000000010111011 00000100000001101100000000001011 10110000000000101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000100 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000100010110011 00000100001011001100000000001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111010 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110000000000010 00000000000000000000000000000000 00000000000000000000000000000000 11100000000111011111110000000000 11111111000000000011111111000001 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000010000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111110100000000110 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000000 11000100100000100011001111100000 00001100111010000000001111111110 00000000110011111000000000111111 11100000000011111111100000000011 11111110000000001100111110000110 00111111111000000000111111111000 00000011111111100000000011001111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10001001100001100010001011100001 00001000101010000000001011101110 00000010100010111000000000101110 11100001100010111011100000000010 11101110000000101000101110000000 00101110111000000000101110111000 01000010111011100000010010001011 10000000001011101110000000001011 10111000000000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10011010000000000010010011000000 00001001001000000000001011001100 00000000100000110000000000101100 11000000000010110011000000000010 11001100000000001000001100000000 00101100110000001000001100110000 00000010110011000000001010010011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000101011010110000000000 10011001000000000010011011000000 01001001101000000010001011101100 00000000100010110000000000101110 11000000000010111011000000000010 11101100000000001000101100000000 00101110110000010000101110110000 00000010111011000000000010011011 00000000001011101100000000001011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101001000110000000000 11011011100100000011010011000000 00001101101000000100001111101100 00000010110010110000000000111110 11000000000011111011000000000011 11101100000000001100101100000000 00111110110000000000101110110000 00000011111011000000100011011011 00000000001111101100000000001111 10110000000000111100000000000000 01010000000000000000000000000000 00000000000000000000000000000000 11100001000000001011110000001000 11101100000000010011101111000000 00001110111000000001001111111100 00000000111111110000000000110111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000100111111110000 00010011111111000000000011101111 00000000001111111100000000001111 11110000000000111111100000000100 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11001011000000000011001011000000 00001100101000010010001100101100 00010000111110110000000000111110 11000000000011111011000000110011 11101100000010001111101100000000 00111110110000000000111110110000 01100011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001000010110000000100 10000010000000000010001011000001 00001000101011000000001000001100 00000000101110110000000000101110 11000000000010111011000000000010 11001100000000001011101100000000 00101110110000000000101110110000 00000010110011000000000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000000000 10000000000000000010010011000000 00001001001010000000001000001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000000000101111000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00100000000000010001111100000000 10001100110000000010010111110000 10001001011011000000001000011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000000 00101101111000000000101101111000 00100010110111100000010010110111 10000000001011011110000000001011 01111000000000101100100000010100 00000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11000010000000000011010011000100 00001101001000010000001100001100 00000000111100110000000000111100 11000000100011110011000000000011 11001100000000001111001100000000 00111100110001000000111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011000110000000000 11111010000000100011100011000001 00001010001000000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000010001111101100000000 00111110110000001000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000001011110110000000000 11110000000000000010001011000000 00001111101000000100001111101100 00001000011110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000101110110000 00000011110011100001001011001011 00000000001111101100000000001111 10110000000000111100001000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10110100000000000010000111000000 00001011011000000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000000 00101101110000000100101101110000 00000010110111000000000010000111 00000000001011011100000000001011 01110000001000101101001000000100 01000000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000000 10111110100000001010000111100000 00001011011010000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000001 00101101111000000000001101111000 00000010110111100000000010000111 10000000001011011110000000001011 01111000000000101100100000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10110010000000000010000011000000 00001011001000000000001011001100 00000000101100110000000001101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000010000101100110000 00000010110011000000000010000011 00000000001011001100000000001011 00110000000000101101101000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11111110000000000011001010000000 00001111111000000000001111101000 00000000111110100000000000111110 10000000000011111010000000000011 11101000000000001111101000000010 00111110100000000000111110100000 00000011111010000000000011001010 00000000001111101000000000001111 10100000000000111111101000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000001000 11111000100000001011111000000000 00001111100000000000001111100000 00000100111110000000000000111110 00000000000011111000000000000011 11100000000010001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111101001000000100 00100000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000001011001001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00100000000000000000000000000000 00000000000000000000000000000000 10000000000000000110010000000000 10110001000000000010001001000001 00001011100100000000001110100100 00000000101110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000100 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00011000000001000010011000000001 10111011100001000010001001100000 00001011100110000000001011100100 00000000101110010000000000101010 01000000000010111001000000000010 11100100000000001011100100000010 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000010000 10110001000000000010000001000000 00001011000100000001001010000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000010011011000100000000 00101100010000000000101100010000 00000010110001000000010010110001 00000000001011000100000000001011 00010000000100101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000010010110000000000000 11111000000000000011001000000001 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011111010000000000 11111101000000000011111001000000 00001111100100000000001110100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 01000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110111000000110 01110000000000000000000000000000 00000000000000000000000000000000 00011000000001011110010000000000 11111011000000000011001001000000 00001111100100000000001111110100 00000000111110010000000000110110 01000000000011111001000000000011 11110100000000001111100100000000 00111110010000000000111110010000 00000011111101000000000011001001 00000000001111100100000000001111 10010000000000111100111000000000 01110000000000000000000000000000 00000000000000000000000000000000 00111100000100001110000000000000 10111000000000000010001000000000 00001011110000000000001011100000 00000000001110000000000000101110 00000000000010111000000000010010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000000010001000 00000000001011100000000000001011 10000000000000101100011000000000 00010000000000000000000000000000 00000000000000000000000000000000 00001000000001011101010000000000 10111101000000000010010101000001 00001011010100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000001010000001 00000000001011000100000000001011 00010000000000101101001000000000 00100000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111101100000001010011101000000 00001011110100000000001011100100 00010000101110010000000000101110 01000000000110111001000000100010 11100100000001000011100100000101 00101110010000000000100110010000 00000010111001000000000010001001 00000000011011100100000000001011 10010000000000101100011000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101001010010000010000 11111001100000000011011001000000 00001111100100000000001111100100 00000000111110010000000100110110 01000000100011111001000000100011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011001001 00000000001111100100000010001111 10010000000000111110100000000000 00100000000000000000000000000000 00000000000000000000000000000000 00101010000000001010010000000000 11111001000000000011101001000000 00001111100100000000001111100100 00000100111110010000000000101110 01000000000011111001000000000001 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111101101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101010000100001010000000000000 11111000000000000011111000000000 00001111110000100000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000001001111100000000000 00111110000000000000011110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000100001000010100000000100 10110010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000010110010000000000010111010 00000000001011101000000000001011 10100000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000000000 10110011000000100010110011000000 00001011001000000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000100010110011 00000000001011001100000000001011 00110000000000101100001100000000 01010000000000000000000000000000 00000000000000000000000000000000 00100000000000010001100000010000 10110110000000000010110110000000 00001011011000000000001011011100 00000000101101110000000000101101 11000000000010110111000000000010 11011100000000001011011100000001 00101101110000000000101101110000 00000010110111000000000010110111 00000000001011011100000000001011 01110000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 00111000000010000001011000000000 11110101100000000011110101100000 00001111010010000000001111011110 00000000111101111000001000111101 11100000000011110111100000100011 11011110000000001111011110000000 00111101111000000000111101111000 00000011110111100000000011110111 10000000001111011110000000001111 01111000000000111100101000000110 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010000000000000 11111000000000000011111000000000 10001111100000000000001111101100 00010100111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000010 00111110110000000000111110110000 01000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000010 11001111100000000011111111100000 00001111111110010000001111111110 00000000111111111001000000111111 11100000000011111111100000000011 11111110000000001111111110010000 00111111111001000000111111111000 00000011110111100000000011001111 10000000001111111110000000001111 11111000000000111101100000000000 00100000000000000000000000000000 00000000000000000000000000000000 10101000000100011001100001010000 11010110000100000010110110000000 00001011011100000000001001011100 00000100111101110000000100101101 11000000010010110111000100000010 11011100000000001011011100000000 00111101110000000000101101110000 01010010110111000000010010000111 00000000001011011100000000001011 01110000000000101110101000000000 00100000000000000000000000000000 00000000000000000000000000000000 10000000000000001011010000000000 10000101000010000010110101000000 00001011010110000000011001011100 00000000101001110000000001101101 11000000000010110111000000000010 11011100000000001011011100000010 01100101110000000001101101110000 00000010110111000000000010000111 00000000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000101001100000000000010 10000000100000000010110000000000 00001011000100000000001001001100 00000100101100110000000000101100 11000000000110110011000001000010 11001100000100000011001100000100 00101000110000010000101100110000 00000010110011000001001010000011 00000100001011001100000100001011 00110000000000101101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 10101000000101011010110000000000 10000011110000000011111011000000 00001111101000000000001101101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001011101100000000 00101110110000000000111110110000 00000011111011000001000011001011 00000000001111101100000000001111 10110000001100111110101000000000 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110100000010000 11111010000010000011111010000000 01001111101000000000001101101100 00000000111010110000000100111110 11000000000011111011000000000011 11101100000000001111101100000000 01111110110000000000111110110000 00000011111011000000000011111011 00000010001111101100000001001111 10110000000000111110100000010100 00110000000000000000000000000000 00000000000000000000000000000000 00000001000100001111010000000000 11111101000000000011001101000000 00001111110000000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000100111111110000 00010011111111000000100011111111 00000000001111111100000000001111 11110000000000111100000001000100 00110000000000000000000000000000 00000000000000000000000000000000 11000001000001000110000000010000 10111000000000000010001000000000 00001011100000000100001011101100 00010000101110110000000000101110 11000001000110111011000000010010 11101100000000001011101100000000 00101110110000000000101110110000 00000010111011000001000010111011 00000000001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 11000000000001010010110000001000 10111011000000000010001011000000 00001011101100000000001010101100 00000000101110110000000000101110 11000000010010101011000000010010 11101100000010001011101100000000 00101110110000000000101110110000 00000000111011000000000010111011 00000000001011101100000001001011 10110000000100101110000000000000 01010000000000000000000000000000 00000000000000000000000000000000 00001000010000000000100000000000 10111010000000001010000010000000 01001011001100000001001011001100 00000000101100110000000000101100 11000000000010110011000000010010 11001100000000001011001100000001 00101100110000000000101100110000 00000010110011000000010010110011 00000000001011001100000001001011 00110000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 01000000000011000110010000000000 11111001000000000011001001000000 00001111100100000000001110101100 00000000111110110000000000111110 11000000000011101011000000000011 11101100000010001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000011100000000000110 00000000000000000000000000000000 00000000000000000000000000000000 10100000000111011101000000000000 01111100000001000011111100000001 00001111110100000100001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000011111111100000000 00111111110000010000111111110000 01000011111111000001000011111111 00000000001111111100000000001111 11110000010000111110100000000010 01110000000000000000000000000000 00000000000000000000000000000000 11000000000001011111111000000010 11001111100000000011111111100000 10001111111110000000001101111110 00001000111111111000000000111111 11100000000011111111100000000011 11111110000000001111111110000000 00111111111000000000111111111000 00000011011111100000011011001111 10000000001111111110000000001111 11111000000000111111000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10000000000100001110111000000000 10001011100000000010111011100000 00001011101110000001001011101110 00001000101110111000001100101110 11100000010010111011100000010010 11101110000000001011101110000000 00101110111000000000101110111000 00010010011011100000000010001011 10000000001011101110000000001011 10111000000000101110000000000100 00110000000000000000000000000000 00000000000000000000000000000000 10001000000001011100110000000000 10000011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101100110000 00000010110011000000000010000011 00000000001011001100000000001011 00110000000000101110001000000001 01110000000000000000000000000000 00000000000000000000000000000000 11000000000100011010110000000000 10001011000001000010111011000000 00001011101100000000001011101100 00000000101110110000000000100110 11000000000000111011000001000010 11101100000000001011101100000000 00101110110000001000101110110000 00000110011011000000000010001011 00000000001011101100000000000011 10110000000000101111000000000100 01100000000000000000000000000000 00000000000000000000000000000000 00000000000101011110110000000000 11001011000000000011111011000000 00001111101100000000001101101100 00000000111110110000000000111110 11000001000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011011011000000010011001011 00000100001111101100000000001111 10110000000000111101000000000100 01110000000000000000000000000000 00000000000000000000000000000000 11100000000000011011110000000000 11111111000001000011111111000000 00000111111100000100001111111100 00000000111111110000000000101111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00010011111111000001000011111111 00000000001111111100000000001111 11110000000000111111100000000000 01100000000000000000000000000000 00000000000000000000000000000000 01000000000100001010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00011000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00010011111011000000010011111011 00000100001111101100000000001111 10110000000000111101000000000100 00100000000000000000000000000000 00000000000000000000000000000000 11001000000001010000110000000000 10111011000001000010111011000000 00001011101100000100001011101100 00000000111110110000010000101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000000101110110000 00000000110011000001000010111011 00000000001011101100000000001011 10110000000000101111001000000000 01000000000000000000000000000000 00000000000000000000000000000000 11100000000001010100110000010000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000001100110000 00000010110011000000000010110011 00000000001011001100000100000011 00110000000000101111100000000000 01010000000000000000000000000000 00000000000000000000000000000000 01100000010000010001111000000000 10110111100000000110110111100000 00001011011110000000001011011110 00000000101101111000000000101101 11100000000010110111100000000010 11011110000000001011011110000100 00101101111000000000101101111000 00000010110111100000000010110111 10000000001011011110000000001011 01111000000000101100100000000000 01000000000000000000000000000000 00000000000000000000000000000000 01001000000010000000110000000000 11110011000000000011110011000001 00001111001100010000001111001100 00000000111100110000000000111100 11000000000011110011000000000011 11001100000000001111001100000000 00111100110001000100111100110000 00000011110011000000000011110011 00000000001111001100000000001111 00110000000000111101001000000010 00000000000000000000000000000000 00000000000000000000000000000000 01000000000111011011110000000001 11111111000000000011111111000000 00000111111100010100001111111100 00000000111011110000000001111111 11000000000011111111000000010011 11111100010000001111111100010000 00111111110000000000111111110001 00010111111111000000000011111111 00000000001111111100000000001111 11110000000000111101000000000010 01100000000000000000000000000000 00000000000000000000000000000000 10101000000001011100111000000000 11001011000000000011111011000000 00001111101100000000001111001110 00000000110010110000000000111110 11000000000011111011000000000011 11001110000000001100101100000000 00111110110000001000111110110000 00000011110011100000000011001011 00000000001111101100000000001111 10110000000000111110101000000000 01110000000000000000000000000000 00000000000000000000000000000000 01001000000100011001110000000000 10000111000000000010110111000000 00001011011100000001001011011100 00000000100001110000000001101101 11000000000010110111000000000010 11011100000000001000011100000100 00101101110000000000100101110000 00000010110111000000000010000111 00000000001011011100000000001011 01110000000000101101001000000100 01100000000000000000000000000000 00000000000000000000000000000000 11000000000000001001111000000010 10000111100000000010110111100000 00001011011110000000001011011110 00010011100101111000000000101101 11100000000010110111100001100010 11011110000010101000011110000000 00101101111000000000101101111000 00000010110111100000011010000111 10000100001011011110000000001011 01111000000000101111000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01001000000101001100110000000000 10000011000000010010110011000000 00001011001100000000001011001100 00000000100100110000000000101100 11000000000010110011000000000010 11001100000000001000001100000001 00101100110000000001100100110000 00000010110011000000000010000011 00000000001011001100000000001011 00110000000000101101001000000100 00110000000000000000000000000000 00000000000000000000000000000000 11101000000101011010100000000000 11001010000000000011111010000000 00001111101000000000001111101000 00000000110110100000000000111110 10000000000011111010000000000111 11101000000000001100101000000000 00111110100000000000111110100000 01000011111010000000000011001010 00000000011111101000000000001111 10100000000000111111101000000100 01100000000000000000000000000000 00000000000000000000000000000000 01001000000000001110000000000000 11111000000000100011111000000000 00001011100000000000001111100000 00000000111010000000000000111110 00000000000011111000000000000111 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000001001111 10000000000100111101001000000000 00110000000000000000000000000000 00000000000000000000000000000000 00001000000100001110010000000000 11111001000000000011101001000000 00001111100100000000001111100100 00000000111110010000000000111110 01000000000011111001000000000011 11100100000001001111100100000000 00111110010000000000111110010000 01100011111001000000000011111001 00000000001111100100000000001111 10010000000000111100001000000100 00110000000000000000000000000000 00000000000000000000000000000000 10000000000001000110010000000000 10111001000000000010111001000000 00001011100100000000001011100100 00000000100110010000000000101110 01000000000010111001000000000010 11100100000000001011100100000000 00101110010000000000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101110000000000000 00010000000000000000000000000000 00000000000000000000000000000000 00011000000001010010010000000000 10111001000000000010111001000001 00001011100100000000001011100100 00000000101110010000000000101110 01000000000010111001000000000010 10100100000000001011100100000000 00101110010000000000001110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000010010 11000100000000001011000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00000000000000000000000000000000 00000000000000000000000000000000 10111000000011010110000000000000 11111000000000000011101000000000 00001111100000000000001111100000 00000000111110000000000000111110 00000000000011111000000000000011 11100000000000001111100000000000 00111110000000000000111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111110111000000011 01010000000000000000000000000000 00000000000000000000000000000000 10011000000111011110010000000000 11111001000000000011111001000000 01001111100100000000001111100100 00000000110110010000000000111110 01000000000011111001000000000001 11100100000001001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111110011000000110 01110000000000000000000000000000 00000000000000000000000000000000 10011000000001011111010000000000 11111001000000000011111001000000 00001111100100000000001111110100 00000000111110010000000000110110 01000000000011111001000000000011 11110100000000001111100100000000 00111110010000000000111110010000 00000011111101000000000011111001 00000000001111100100000000001111 10010000000000111100011000000001 01100000000000000000000000000000 00000000000000000000000000000000 00111000000100001110000000000000 10111000000000000010111000000000 00001011100000000000001011100000 00000000101110000000000000101110 00000000000010111000000000000010 11100000000000001011100000000000 00101110000000000000101110000000 00000010111000000000010010111000 00000000001011100000000000001011 10000000000000101100111000000100 00110000000000000000000000000000 00000000000000000000000000000000 00001000000000001100010000000000 10110001000000000010110001000000 00001011000100000000001011000100 00000000101100010000000000101100 01000000000010110001000000000010 11000100000000001010000100000000 00101100010000000000101100010000 00000010110001000000000010110001 00000000001011000100000000001011 00010000000000101100001000000001 00110000000000000000000000000000 00000000000000000000000000000000 00011000000101011010010000000000 10111001000000000010111001000000 00001011100100000000011011100100 00000000101110010000000100101110 01000000000010111001000001000010 11100100000000001011100100000000 00101110010000010000101110010000 00000010111001000000000010111001 00000000001011100100000000001011 10010000000000101100011000000100 01100000000000000000000000000000 00000000000000000000000000000000 10100000000101011110010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00010000111110010000010000110110 01000000000011111001000000000011 11100100000000001110100100000000 00111110010000000000111110010000 00000010111001000000000011111001 00000000001111100100000000001111 10010000000000111110100000000100 01110000000000000000000000000000 00000000000000000000000000000000 00101000000000011010010000000000 11111001000000000011111001000000 00001111100100000000001111100100 00000000111110010000000000101110 01000000000011111001000000000011 11100100000000001111100100000000 00111110010000000000111110010000 00000011111001000000000011111001 00000000001111100100000000001111 10010000000000111100101000000000 01100000000000000000000000000000 00000000000000000000000000000000 00101000000100000010000000000000 11111000000000000011111000000000 00001111100000000000001111100000 00000000111110000000000001111110 00000001000011111000000000000011 11100000000000001111100000000000 00111110000000000001111110000000 00000011111000000000000011111000 00000000001111100000000000001111 10000000000000111100101000000100 00100000000000000000000000000000 00000000000000000000000000000000 00101000000001010010100000000000 10111010000000000010111010000000 00001011101000000000001011101000 00000000101110100000000000101110 10000000000010111010000000000010 11101000000000001011101000000000 00101110100000000000101110100000 00000011101010000000000010111010 00000000001011101000000000001011 10100000000000101100101000000000 01000000000000000000000000000000 00000000000000000000000000000000 00101000000001010100110000010000 10110011000000000010110011000000 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000100 00101100110000000000101100110000 00000010110011000000000010110011 00000000001011001100000000001011 00110000010000101100101000000000 01010000000000000000000000000000 00000000000000000000000000000000 10100000010000010001110000000000 10110111000000000010110111000000 00011011011100000000001011011100 00000000101101110000000000001101 11000000000010110111000000000010 11011100000000001011011100000001 00101101110000000000101101110000 00000000100111000000000010110111 00000000001011011100000000001011 01110000000000101110100000000000 01000000000000000000000000000000 00000000000000000000000000000000 10101000000010000001111000000000 11110111100001000111110111100000 00001111011110000000001111011110 00000000111101111000000000101101 11100000000011110111100000000011 11011110000000001111011110000000 00111101111000000000101101111000 01000011110111100000000011110111 10000000001111011110000000001111 01111000000000111110101000000010 00000000000000000000000000000000 00000000000000000000000000000000 00001000000111011010110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000100111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100001000000110 01100000000000000000000000000000 00000000000000000000000000000000 01000000000001011111111000000000 11111111100000000011111111100100 00001111111110000000001111111110 00000000111111111000011000111111 11100000000011101111100000000011 11111110000000001111111110000000 00111111111000000000111111111001 00000011111111100000000011111111 00100000001111111110000000001111 11111000000000111100000000000000 01110000000000000000000000000000 00000000000000000000000000000000 10101000000100011001110000000000 10110111000100000010110111000000 00001011011100000000001011011100 00000000101101110001000000101101 11000000010010110111000000000010 11011100000010001011011100000000 00101101110000000000101101110001 00000010110111000100000010110111 00000000001011011100000010001011 01110000000000101110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 00011000000000001001110000000000 10110111000000000010110111000001 00011011011100000000001011011100 00000000101101110000000000101101 11000000000010100111000000000010 11011100000000001011011100000000 00101101110000000000101101110000 00000110110111000000000010110111 00010000001011011100000000001011 01110000000000101100000000000000 00100000000000000000000000000000 00000000000000000000000000000000 01100000000100001100110000000000 10110011000000000010110011000000 00001011001100000000001011001100 00000101101100110000000000101100 11000001000010110011000000000010 11001100000000001011001100000000 00101100110000000001101100110000 01000010110011000000000010110011 00000000001011001100000000001011 00110000000000101100100000000100 00110000000000000000000000000000 00000000000000000000000000000000 10111000000101011010110000000000 11111011000000000111111011000000 00001111101100000010001111101100 00000000111110110000000000111110 11000000000011101011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111110101000000100 01100000000000000000000000000000 00000000000000000000000000000000 10000000000000001110110000000000 11111011000000000011111011000000 00001111101100000000001111101100 00000000111110110000000000111110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000111110110000 00000011111011000000000011111011 00000001001111101100000000000111 10110000000000111110000000000000 00110000000000000000000000000000 00000000000000000000000000000000 10000000000100001111110000000000 11111111000000000011111111000000 00001111111100000000001110111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000000000111111110000 00000011111111000000000011111111 00000000001111111100000000001111 11110000000000111100000001000100 00110000000000000000000000000000 00000000000000000000000000000000 10000001000001000110110000000000 10111011000000010011101011000000 00001011101100000000000011101100 00000000101110110000000001101110 11000000000010111011000000000010 11101100000000001011101100000000 00101110110000000001111010110000 00000011101011000000110010111011 00000100001011101100000000001011 10110000000000101110000001000000 00010000000000000000000000000000 00000000000000000000000000000000 10000000000001010010110000000000 10111011000000000010111011000000 00001011101100000000001011101100 00000000101110110000010000101110 11000000000010111011000000000110 11101100000000001011101100000000 00101110110000010000101110110000 00000010111011000000000010111011 00000000001011101100000000001011 10110000000000101110000000000000 01000000000000000000000000000000 00000000000000000000000000000000 00001000000001000000110000000100 10110011000000000010100011000001 00001011001100000000001011001100 00000000101100110000000000101100 11000000000010110011000000000010 11001100000000001011001100000000 00101100110000000000101000110000 00010010100011000001100010110011 00000100001011001100000000001011 00110000000000101100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 10000000000011010110110000000100 11111011000000100011111011000000 10001111101100000000001110101100 00000000101110110000000000101110 11000000000011111011000000000011 11101100000000001111101100000000 00111110110000000000101110110000 00000011111011000000000011111011 00000000001111101100000000001111 10110000000000111100000000000011 00010000000000000000000000000000 00000000000000000000000000000000 10100000000111011111110000000000 11111111000000000011111111000001 00001111111100000000001111111100 00000000111111110000000000111111 11000000000011111111000000000011 11111100000000001111111100000000 00111111110000010000111011110000 00000011101111000000000011111111 00000000001111111100000000001111 11110000000000111110100100000011 01110000000000000000000000000000 00000000000000000000000000000000 00000000110001010000000000000010 01110001010000001001110000010000 00110111000111000101010111000001 00000011011100000100000010011100 00010000001101110001010000001101 11000111000000110111000111000001 11011100010100000111011100010100 00010101110000010000000101110000 01000000010111000001000001010111 00000100000111011100000000100001 00000000000000000000000000000000 00000000000000000000000000000000 00000000110000010100010000100101 01110001000000010101110001000000 01010111000100000001010001000100 00000101011100010000000001011100 01000000010101110001000001010101 11000100000001010011000100000001 01011100010000000101011100010000 00011100100001000000010000110001 00000001110111000100000001010111 00010000000101011100000000010001 00010000000000000000000000000000 00000000000000000000000000000000 00000000100001000000001000000001 00100000100000000100100000100000 00010010000110000000000010000010 00000001001000001000000001001000 00100000000100100000100000000100 10000010000000000010000010000000 01001000011000000001001000011000 00000100100000100000000101110000 10000000010010000010000000010010 00001000000001001000000000100000 01000000000000000000000000000000 00000000000000000000000000000000 00000000100000000000000000000001 01100000000000000101100000000000 00010110000000000000010110000000 00000001011000000000010001010000 00000000000101100000000000000101 10000100000000010110000100000000 01011000000000000001011000001000 00000001100000000010010101100000 00000000010110000000000000010110 00000000000101011000000000110001 00010000000000000000000000000000 00000000000000000000000000000000 00000000010001010100100101000101 01110010000000010001110010000000 01000111001000000000010111001000 00000101011100100000000000011100 10000000010101110010000000010101 11001000000001010111001000000000 01011100110000000001011100100000 00000101110010000000010101110010 00000001010111001000000001000111 00100000000100011100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000110001010100000000000000 01100000000000000001100000000000 00000110000000000000000110000000 00000000011000000000000100011000 00010000000001100000000000000001 10000000000000000110000000000000 00011000000000000000011000000000 00000000100001000000000001100000 00000000000110000000000000000110 00010000000000011000000000110001 01000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100100000000100 00100010000000010000100010010000 01000010000000000000000010001000 00000100001000000000000100001000 10000000010000100010000000010000 10001000000001000010001000000000 00001000101000000000001000000100 00000000100001000000010000100000 00000001000010000000000001000010 00110000000100001000000000100001 00000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100111100000101 01000010100000010101000011100000 01010100000000000000010100001010 00000101010000001000000101010000 11100000010101000010110000010101 00001010000001010100001111000001 01010000111000000101010000000000 00000100000000100000000101000000 11000000010100000010000001000100 00101100000000010000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000100000000001110100000001 00010011000000000101010111000000 00010101011100000001010101011100 00000001000001110000000001000001 11000000000100000111000000000100 01011100000000010101001100000000 01000101110000000001010100110000 00000101010111000000000101010011 00000000010001011100000000010101 00110000000001000100000000100000 01000000000000000000000000000000 00000000000000000000000000000000 00000000100001000000010000000000 00010000000000000001000001000000 00000100001110000000000100000000 00000000000000000000000000000000 01100001000001000000000000000000 01000000000000000100000110000000 00000100010000000000010000110000 00000001000011000000000001000000 00000001000001001000000000000100 00010000000000000100000100100001 00010000000000000000000000000000 00000000000000000000000000000000 00000000110000010110000000000010 00011000000000001000001000000000 00100000100000000000100000100000 00000010000010000000000110000010 00000000001000001000000010001000 01100000000000100000100000000000 10000110000000000010000010000000 00001000001001000000001000001000 00000000100001100000000000100000 10000000000010000100000100010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000110001010001000000000101 01100000000000010101100100000000 01010110010000000000110110010000 00000001001001000000000001001001 00000000010101100100000000010101 10010000000000010110000000000000 01011001000000000001011000000000 00011101100100100000011101100000 00000001010110010000000001110110 00000000000101011000000000010001 00000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100000000000001 01100000000000001101100000000000 00110110001000000000010110000000 00000111011000000000000011011000 00000001001101100000000000001101 10000000000001110110000000000001 11011000000000000101011000100000 00010101100010000000010101110000 00000000010110001000000001010110 00000000000111011000000000100001 00010000000000000000000000000000 00000000000000000000000000000000 00000000110001010100001000000100 00110000100001010000110000100000 01000011000011000001000011000010 00000100001100001000000000001100 00100001010000110000100001010000 11000010000001000011000010000001 00001100001000000010001100001000 00000000110000100000010001100000 10000001100011000010000001100011 00001000000100001100000000110001 01010000000000000000000000000000 00000000000000000000000000000000 00000000100000000000000000000000 00110000000000000000110000000000 00000011000000000000000011000000 00000000001100100000000000001100 00000000000000110000000000000000 11000000000000000011000000000000 00001100000000000000001100000000 00000000110000000000000000100010 00000000000011000000000000000011 00000000000000001100000000000001 01000000000000000000000000000000 00000000000000000000000000000000 00000000100000000000001000000001 00110000100000000100110000100000 00010011000010000001010011000010 00000101001100101100000001001100 00100000000100110000100000000100 11000010000000010011000010000000 01001100001000000001001100001100 00000100110000110000000100110010 11000000010011000011000000010011 00001000000001001100000000110001 01000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100001000000101 01100000100000010101100000100000 01010110000011000001000110000010 00000001011000001100000000001000 00100000010101100000100000010101 10000010000000010110000010000000 01011000001000000001011000001100 00010101100000110000000101100000 11000001010111000011000001010110 00001000000001011000000000010000 01010000000000000000000000000000 00000000000000000000000000000000 00000000110001010100001000000000 00100000100000000000100000100000 00000010000010000000000011000010 00000000011000001000000100001000 00100000000000100000100000000000 10000010000000000010000010000000 00001000001000000000001000001000 00000000110000100000010000110000 10000000000110000010000000000011 00001000000000001000000000110001 00000000000000000000000000000000 00000000000000000000000000000000 00000000110001010001001000000100 01100000100000010001100100100000 01000110010010000001000011010010 00000000001001001000000100001001 00100000010001100100100000010001 10000010000000000110010010000000 00011001001000000000011001001000 00010000110100100000010000110100 10000001000010000010000001000011 01001000000000011000000000000001 01000000000000000000000000000000 00000000000000000000000000000000 00000000010001010110000000000101 01011000000000010101011000000000 01000101100000000000000001100000 00000001010110000000000100000010 00000000010101011000000000010101 01100000000001010101100000000001 01010110000000000001010110000000 00010100011000000000010100011000 00000000010001100000000000010001 10000000000101010100000000000001 01010000000000000000000000000000 00000000000000000000000000000000 00000000100001000010011000000001 01000001100000000101000001100000 00010100000110000000010100000110 00000001010000011000000001010000 01100000000101000001100000000101 00000110000000010100000110000000 01010000011000000001010000011000 00000001000000100000000101000001 10000000010100000110000000010100 00011000000001010000000000010001 00010000000000000000000000000000 00000000000000000000000000000000 00000000100000000001001000000001 00000000100000000100000100100000 00010000010010000000010000010010 00000001000001001000000001000001 00100000000100100100100000000100 00000010000000010000010010000100 01000001001000000001000001001000 00010100000100100000000100000100 10000001010000000010000000010000 01001000000001000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100011000000011 01010001100000001101010001100000 00110101000110000000110101000110 00000011010100011000000111000000 01100000001101010001100000001101 01000110000000110101000110000000 11010100011000000001010100011000 00000101010001100000001101010001 10000000110101000110000000110101 00011000000011010100000000110001 01010000000000000000000000000000 00000000000000000000000000000000 00000000110001010100001000000111 01110001100000010101110001100000 00010111000110000000110111000110 00000000011100011000001001011100 01100000000101110001000000010101 11000110000000010111000110000000 01011100011000001110011100011000 00010101110001100000011101110001 10000001010111000110000001110111 00011000000001011100000000010001 00000000000000000000000000000000 00000000000000000000000000000000 00000000010001010100011000000011 01110001100000001101110001100000 01100111000110000101010111000110 00000010011100011000000011011100 01100000011101110001100000001101 11000110000001100111000110000001 11011100011000000010011100011000 00010001110001100000010101110001 10000000010111000110000001010111 00011000000011011100000000000001 01000000000000000000000000000000 00000000000000000000000000000000 00000000010001010100011000000101 01110001100000010101110001100000 01010111000110000001000011000110 00000101011100011000000000011100 01100001010101110001100000010100 11000110000101010111000110000001 01011100011000000101011100011000 00011000110001100000011001110001 10000001100111000110000001000011 00011000000101011100000000000001 01010000000000000000000000000000 00000000000000000000000000000000 00000000000000000000001000000001 00100000100000000100100000100000 00010010000010000000010111000010 00000001001000001000000001001000 00100000000100100000100000000101 10000010000000010010000010000000 01001000001000000001001000001000 00000101110000100000000100110000 10000000010010000010000000010111 00001000000001001000000000010000 00000000000000000000000000000000 00000000000000000000000000000000 00000000010000000000011000000001 01100001100000000101100001100000 00010110000110000000010110000110 00000001011000011000000001001000 01100000000101100001100000000101 10000110000001010110000110000001 00011000011000000001011000011000 00000101100001100000000101100001 10000000010010000110000000010110 00011000000001011000000000100001 01000000000000000000000000000000 00000000000000000000000000000000 00000000010001010100000000000101 01110000000000010101110000000000 00010011000000000001010011000000 00000101001100000000000001001100 00000000000000110000000000010101 11000000000000010111000000000001 01011100000000000101011100000000 00000101110000000000010100110000 00000001000111000000000000010011 00000000000101011100000000110001 00010000000000000000000000000000 00000000000000000000000000000000 00000000010001000100001100000000 01100000100000000001100000110000 00000010000010000000000010000010 00000000001000001000000100011000 00100000000000100000100000000001 10000010000000000110000010000000 00011000001000000000011000001000 00000000000000100000000000100000 10000000000110000010000000000010 00001000000000011000000000000001 00010000000000000000000000000000 00000000000000000000000000000000 00000000010001000100001000000100 00100000100000010000100000100000 00000110000010000001000110001010 00000100011000001000000100001000 10100000000001100100100000010000 10000010000000000010000010000001 00001000001000000100001000001000 00000000100000100000010000100000 10000001000010000010000000000110 00001000000100001000000000010001 00000000000000000000000000000000 00000000000000000000000000000000 00000000010001000100001100000101 01000000100000010101000000100000 01010101000011000001010101000011 00000101010100001100000101010100 00110000010101010000100000010101 00000010000000010100000010000000 01010000001000000101010000001000 00000100000100110000000100000000 10000000010100000011000001000101 00001000000101010000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000000000010000001100000001 00010000110000000101010000110000 00010101000011000000010101001010 00000001010100001000000001010100 10100000000101010000100000000101 01000011000000010101000010000000 01010100001100000001010100001100 00000101010000110000000101010000 10000000010101000011000000010101 00001000000001010100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000010000100000000000 00010010000000000001000000000000 00000100000000000000000100000000 00000000011000000000000000011000 00000000000001000010000000000001 00001000000000000100001000000000 00010000100000000000010000100000 01000001000100000000000001000010 00000001000110000000000000000100 00100000000000010000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000010001000100001100000010 00010000100000001000000010100000 00100000001010000000100000000010 00000010000000001000000110000000 00100000001000000000100000001000 00000010000000100000000010000000 10000000001000000010000000001000 00001000000110100100001000000000 10000000100000001010000000100000 00001000000010000000000000110001 01010000000000000000000000000000 00000000000000000000000000000000 00000000000001010100000000001001 01100000000000010101100000000000 00010110000000000000110110000000 00000101011000000000001001011000 00000000000101100100000010010101 10000000000000010110000000000001 01011000000000000101011000000000 00011101100000000000011101100000 00000001010110000000000010110110 00000000001001011000000000010001 00000000000000000000000000000000 00000000000000000000000000000000 00000000110001010100000000000010 01100000000000011101100000000000 00010110000000000000010111000000 00000000011000000000000001001000 00000000001101100000000000000101 10000000000000010110000000000000 10011000000000000011011000000000 00000101110000000000000101110000 00000000110010000000000000010111 00000000000011011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 00110000000000000000110000000000 01000011000000000000000110000000 00000100001100000000000000001000 00000001010000110100000000000000 11000000000000000011000000000001 00001100000000000100001100000000 00010001100000000000010001100000 00000000100010000000000001000110 00000000000100001100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000000000 00110100000000000000110001101000 00000011010000000001000010000100 00000000001101000000000000001000 00000000000000110101000000000000 11010100000001000011010000000000 00001101010000000000001101000000 00000000100101001000000000100100 00000000000010010000000000000010 00000000000000001100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000011000000001 00110001010000010100110001010000 00010011000101000001010011000110 10000001001100010000000001001000 01000000000100110101100000000100 11000101000000010011000100000000 01001100010100000001001100010100 01010100111001011000010100110001 00000000010010000101000001010011 00010000000001001100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010001100000101 01101000110000000101101000110000 01000110100011000001010100100011 10000101011010001100000001011010 00110000010101101101110000010101 10100011000001010110100011000001 01011010000100000101001010001100 00010001101000100000010101101000 11000001010110100011000001010110 10001100000100011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000000000 00100100000000000000100011000000 00000010011000000000000010000100 00000000001001000000000100001000 00000000000000100100000000000000 10010101000000000010010000000000 00001001000000000000001001000000 00000000100111000000000000110100 00000000000010011000000000000010 00000000000000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100000000100 01100010000100000001100000000100 01000110000000010001000110000000 01000100011000000001000100011000 00000100010001100010000000010001 10001000000001000110001000010001 00011000100000000100001000100001 00010001100000000100010000110010 00010001000110000000010001000110 00100001000100011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000001000101 01010000000100000101010000000000 01000101000000100000000101000000 01100101010100000001000100010100 00000100010001010000000100010101 01000000010101010101000000010001 00010100000100000100010100000000 00000101010000010000000100010000 00010000010101000000010000000101 00000001000101010100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100000100001 01000010000000000001000010000010 00010101001000001000000101001000 00100001010100100000100000010100 10000010000101010010000000000101 00001000000000010100001000000000 01010000100000000001010000100010 10000101000010000010000101010010 00001000010100001000001000010101 00100000100001010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000101000000001 00000010100000000100000010100000 01000000001010010000010000001010 00000100000000101000000100000000 10100000000100000010100000000100 00001010000000010000001010000000 01000000101000000001000000101001 01000100000010100000000100000010 10000000010000001010000000000000 00101000000001000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000110010000011 01010011000000000101010011000000 00100001001100000000000101001100 00000010000100110000000000000100 11001000001000010011000000000101 01001100000000010101001100100000 11010100110000000011010100110001 00001101010011000000001000010011 00000000010101001100000000100001 00110010000011010100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100010000101 01110010000000010001110010000000 01010111001000000001010111001000 00001101011100100000001101011100 10001000010101100010000000011001 11001000000001000111001000001001 01011100100000000100011100100000 00001001110010000000011101100010 00000001010111001000000001110111 00100000100101011100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000001100001000 01001000110001000001000000110000 10000100000011000000000100000011 00001000010000001100000000010000 00110000100001000000110000000001 00000011000100000100100011000000 00010000001100000000010010001100 00000001000000110000000001001000 11000000000100000011000100000100 10001100001000010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 01001111111111111101001111111111 11110100111111111111110100111111 11111111010011111111111111010011 11111111111101000111111111011101 00011111111111110100111111111111 11010011111111111111010011111111 11111101001111111111111101001111 11111111110100111111111111110100 11111111111111010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111011 00001011001101111101001111111111 10110000101101111111110100111110 11011011000010110011011011000010 11011111101100000111101101011101 00011110110111110100101101111111 11010011111111111111010010110111 11111101001111111111101100001011 00110110110000101100110110110000 10110111111011000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111100 01001100110011111101001111111111 11000100110011111111110100111111 00111100010011001100111100010011 00111111110001000111110011011101 00011111001111110100110011111111 11010011111111111111010011001111 11111101001111111111110001001100 11001111000100110011001111000100 11001111111100010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011101100011110 01001110110111111001001000110111 11100100100011011110000100100011 00011110010010001100011000010010 00110001111001000110110001011101 00011011011111100100111011000111 10010011101101111110010011101101 11100001001000110111100001001110 11000110000100100011011110000100 11101100011110010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000100000010 01110000010000001001110000010000 00100111000001000000100111000001 00000010011100000100000010011100 00010000001100110000010000001001 11000001000000100111000001000001 10011100000100010110011100000100 00001001110000010000001001110000 01000000100111000001000001100111 00000100000110011100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000010000000101 01110001000000010101110001000000 01010111000100000001010111000100 00000101011100010000000101011100 01000000010100110001000000010101 11000100000001010111000100000001 01011100010000000101011100010000 00010101110001000000010101110001 00000001010111000100000001010111 00010000000101011100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000001000000001 00100000100000000100100000100000 00010010000010000000010010000010 00000001001000001000000001001000 00100000000100100000100000000100 10000010000000010010000010000000 01001000001000000001001000001000 00000100100000100000000100100000 10000000010010000010000000010010 00001000000001001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01100000000000000001100000000000 00000110000000000000000110000000 00000000011000000000000000011000 00000000000001100000000000000001 10000000000000000110000000000000 00011000000000010000011000000000 00000001100000000001000001100000 00000000000110000000000000000110 00000000000000011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100000000100 01110010000000010001110010000000 01000111001000000001000111001000 00000100011100100000000100011100 10000000010001110010000000010001 11001000000001000111001000000000 00011100100000000000011100100000 00010001110010000000010001110010 00000001000111001000000000000111 00100000000000011100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01100000000000000001100000000000 00000110000000000000000110000000 00000000011000000000000000011000 00000000000001100000000000000001 10000000000000000110000000000000 00011000000000000000011000000000 00000001100000000000000001100000 00000000000110000000000000000110 00000000000000011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000100000000100 00100010000000010000100010000000 01000010001000000001000010001000 00000100001000100000000100001000 10000000010000100010000000010000 10001000000001000010001000000000 00001000100000000000001000100000 00010000100010000000010000100010 00000001000010001000000000000010 00100000000000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010101000000100 01001010100000010001001010100000 01000100101010000001000100101010 00000100010010101000000100010010 10100000010001001010100000010001 00101010000001000100101010000001 00010010101000000000010010101000 00010001001010100000010001001010 10000001000100101010000001000100 10101000000100010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000110000000000110000000000 01010011000000000001010011000000 00000101001100000000000101001100 00000000010100110000000000010100 11000000000001010011000000000001 01001100000000000101001100000000 00010100110000000100010100110000 00000001010011000000000001010011 00000000000101001100000000000101 00110000000000010100000000010000 00000000000000000000000000000000 00000000000000000000000000000000 00000000110000000000000000000000 01000000000000000001000000000000 00000100000000000000000100000000 00000000010000000000000000010000 00000001000001000000000000000001 00000000000000000100000000000000 00010000000000000000010000000000 00000001000000000000000001000000 00000000000100000000000000000100 00000000000000010000000000110000 00000000000000000000000000000000 00000000000000000000000000000000 00001000110000000100000000000010 00000000000000001000000000000000 00100000000000000000100000000000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000110000 00000000000000000000000000000000 00000000000000000000000000000000 00001000110000000100000000000100 01100000000000010001100000000000 01000110000000000000000110000000 00000000011000000000000100011000 00000000010001100000000000010001 10000000000010000110000000000000 00011000000000000000011000000000 00010001100000000000000001100000 00000001000110000000000000000110 00000000000000011000000000110000 00000000000000000000000000000000 00000000000000000000000000000000 00010000000000010100000000000010 01100000000000001001100000000000 00100110000000000000100110000000 00010110011000000000000010011000 00000000001001100000000000001001 10000000000000100110000000000000 10011000000000000010011000000000 00001001100000000000001001100000 00000000100110000000000000100110 00000000000010011000001000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000010001010100001000000100 00110000100000010000110000100000 01000011000010000001000011000010 00000100001100001000000100001100 00100000010000110000100000010000 11000010000001000011000010000001 00001100001000000100001100001000 00010000110000100000010000110000 10000001000011000010000001000011 00001000000100001100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000000000000000000000 00110000000000000000110000000000 00000011000000000000000011000000 00000000001100000000000000001100 00000000000000110000000000000000 11000000000000000011000000000000 00001100000000000000001100000000 00000000110000000000000000110000 00000000000011000000000000000011 00000000000000001100000000110001 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000000000001000000000 00110000100000000000110000100000 00000011000010000000000011000010 00000000001100001000000000001100 00100000000000110000100000000000 11000010000000000011000010000000 00001100001000000000001100001000 00000000110000100000000000110000 10000000000011000010000000000011 00001000000000001100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100001000000100 01100000100000010001100000100000 01000110000010000001000110000010 00000000011000001000000100011000 00100000010001100000100000010001 10000010000001000110000010000001 00011000001000000100011000001000 00010001100000100000010001100000 10000001000110000010000001000110 00001000000100011000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010100001000000000 00100000100000000000100000100000 00000010000010000000000010000010 00000000001000001000000000001000 00100000000000100000100000000000 10000010000000000010000010000000 00001000001000000000001000001000 00000000100000100000000000100000 10000000000010000010000000000010 00001000000000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01010000010000010100001000000100 01100000100000010001100000100000 01000110000010000001000110000010 00000000011000001000000100011000 00100000010001100000100000010001 10000010000001000110000010000001 00011000001000000100011000001000 00010001100000100000010001100000 10000001000110000010000001000110 00001000000100011000000000010000 01000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100000000000100 01010000000000010001010000000000 01000101000000000001000101000000 00000000010100000000000100010100 00000000010001010000000000010001 01000000000001000101000000000001 00010100000000000100010100000000 00010001010000000000010001010000 00000001000101000000000001000101 00000000000100010100001000010001 01010000000000000000000000000000 00000000000000000000000000000000 01001000010000010000011000000000 01000001100000000001000001100000 00000100000110000000000100000110 00000100010000011000000000010000 01100000000001000001100000000001 00000110000000000100000110000000 00010000011000000000010000011000 00000001000001100000000001000001 10000000000100000110000000000100 00011000000000010000000000010000 00000000000000000000000000000000 00000000000000000000000000000000 01001000000001000000001000000001 00000000100000000100000000100000 00010000000010000000010000000010 00000001000000001000000001000000 00100000000100000000100000000100 00000010000000010000000010000000 01000000001000000001000000001000 00000100000000100000000100000000 10000000010000000010000000010000 00001000000001000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100011000000011 01010001100000001101010001100000 00110101000110000000110101000110 00000011010100011000000011010100 01100000001101010001100000001101 01000110000000110101000110000000 11010100011000000011010100011000 00001101010001100000001101010001 10000000110101000110000000110101 00011000000011010100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 00000000000000010000011000000100 01110001100000010001110001100000 01000111000110000001000111000110 00000100011100011000000100011100 01100000010001110001100000010001 11000110000001000111000110000001 00011100011000000100011100011000 00010001110001100000010001110001 10000001000111000110000001000111 00011000000100011100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000010100011000000000 01110001100000001001110001100000 00100111000110000000100111000110 00000010011100011000010110011100 01100000001001110001100000001001 11000110000000100111000110000000 10011100011000000010011100011000 00011001110001100000001001110001 10000000100111000110000000100111 00011000000010011100000000010001 00010000000000000000000000000000 00000000000000000000000000000000 01010000010001010100011000000001 01110001100000010101110001100000 01010111000110000001010111000110 00000101011100011000000101011100 01100000010101110001100000010101 11000110000001010111000110000001 01011100011000000101011100011000 00010101110001100000010101110001 10000001010111000110000001010111 00011000000101011100001000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010000001000000001 00100000100000000100100000100000 00010010000010000000010010000010 00000001001000001000000001001000 00100000000100100000100000000100 10000010000000010010000010000000 01001000001000000001001000001000 00000100100000100000000100100000 10000000010010000010000000010010 00001000000001001000000000010001 01000000000000000000000000000000 00000000000000000000000000000000 01000000000000000000011000000000 01100001100000000001100001100000 00000110000110000000000110000110 00000000011000011000000000011000 01100000000001100001100000000001 10000110000000000110000110000000 00011000011000000000011000011000 00000001100001100000000001100001 10000000000110000110000000000110 00011000000000011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000010001010110000000000100 01111000000000010001111000000000 01000111100000000001000111100000 00000100011110000000000000011110 00000000010001111000000000010001 11100000000001000111100000000001 00011110000000000100011110000000 00000001111000000000010001111000 00000001000111100000000001000111 10000000000100011100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010100001000000000 01100000100000000001100000100000 00000110000010000000000110000010 00000000011000001000000000011000 00100000000001100000100000000001 10000010000000000110000010000000 00011000001000000000011000001000 00000001100000100000000001100000 10000000000110000010000000000110 00001000000000011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000010100001000000100 00100000100000010000100000100000 01000010000010000001000010000010 00000100001000001000000000001000 00100000010000100000100000010000 10000010000001000010000010000001 00001000001000000100001000001000 00000000100000100000010000100000 10000001000010000010000001000010 00001000000100001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100001000000100 01000000100000010001000000100000 01000100000010000001000100000010 00000100010000001000000100010000 00100001010001000000100000010001 00000010000001000100000010000001 00010000001000000100010000001000 00010001000000100000010001000000 10000001000100000010000001000100 00001000000100010000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000000000001100000001 00000000110000000001010000110000 00000101000011000000000101000011 00000000010100001100000000010100 00110000000001010000110000000001 01000011000000000101000011000000 00010100001100000000010100001100 00000001010000110000000001010000 11000000000101000011000000000101 00001100000000010100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000000000100000000100 01000010000000000001000010000001 00000100001000000000000100001000 00000000010000100000000000010000 10000000000001000010000000000001 00001000000000000100001000000000 00010000100000000000010000100000 00000000000010000000000001000010 00000000000100001000000000000100 00100000000000010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100001000000000 00000000100000001000000000100000 00100000000010000000100000000010 00000010000000001000000010000000 00100000001000000000100000001000 00000010000000100000000010000000 10000000001000000010000000001000 00001000000000100000001000000000 10000000100000000010000000100000 00001000000010000000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010100000000000100 01100000000000010001100000000000 01000110000000000001000110000000 00000100011000000000000000011000 00000000010001100000000000010001 10000000000001000110000000000001 00011000000000000100011000000000 00100100100000000000010001100000 00000001000110000000000001000110 00000000000100011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000010100000000000010 01100000000000001001100000000000 00000110000000000000100110000000 00000010011000000000000010011000 00000000001001100000000000001001 10000000000100100110000000000000 10011000000000000110011000000000 00001001100000000000001001100000 00000000100110000000000100100110 00000000000010011000000000000001 00010000000000000000000000000000 00000000000000000000000000000000 01000000010001010110000000000100 00111000000000010000111000000000 00000011100000000001000011100000 00000100001110000000000100001110 00000000010000111000000000010000 11100000000000000011100000000001 00001110000000000100001110000000 00010000111000000000010000111000 00000001000011100000000001000011 10000000000100001100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01010000000000000000000100000000 00110000010000000000110000010000 00000011000001000000000011000001 00000000001100000100000000001100 00010000000000110000010000000000 11000001000000000011000001000000 00001100000100000000001100000100 00000000110000010000000000110000 01000000000011000001000000000011 00000100000000001100000000000001 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000000000010100000000 00110001010000000000110001010000 00000011000101000000000011000101 00010000001100010100000000001100 01010000000000110001010000000000 11000101000000000011000101000000 00001100010100000000001100010100 00000000110001010000000000110001 01000000000011000101000000000011 00010100000000001100001000010000 01000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100001100000100 01100000110000010001100000110000 01000110000011000001000110000011 00000100011000001100000100011000 00110000010001100000110000010001 10000011000001000110000011000001 00011000001100000000011000001100 00010001100000110000010001100000 11000001000110000011000001000110 00001100000100011000000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010100000000000000 00100000000000000000100000000000 00000010000000000000000010000000 00000000001000000000000000001000 00000000000000100000000000000000 10000000000000000010000000000000 00001000000000000000001000000000 00000000100000000000000000100000 00000000000010000000000000000010 00000000000000001000000000110000 00000000000000000000000000000000 00000000000000000000000000000000 01000000000000010000100001000100 01100010000100010001100010000100 01000110001000010001000110001000 01000100011000100001000100011000 10000100010001100010000100010001 10001000010001000110001000010001 00011000100001000000011000100001 00010001100010000100010001100010 00010001000110001000010001000110 00100001000100011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100000001000100 01010000000100010001010000000100 01000101000000010001000101000000 01000100010100000001000100010100 00000100010001010000000100010001 01000000010001000101000000010001 00010100000001000100010100000001 00010100000000000100010001010000 00010001000101000000010001000101 00000001000100010100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000001010000100000100000 01000010000010000001000010000010 00000100001000001000000100001000 00100000010000100000100000010000 10000010000001000010000010000001 00001000001000000100001000001000 00010000100000100000010000100000 10000001000010000010000001000010 00001000000100001000001000000100 00100000100000010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000101000000001 00000010100000000100000010100000 01010000001010000000010000001010 00000001000000101000010001000000 10100000000100000010100000000100 00001010000000010000001010000000 01000000101000000001000000101000 00000100000010100000000100000010 10000000010000001010000000010000 00101000000001000000000000010001 01000000000000000000000000000000 00000000000000000000000000000000 01000000010001010100110100000011 01010011010000001101010011010000 00010101001101000000110101001101 00000011010100110100000011010100 11010000001101010011010000001101 01001101000000010101001101000000 11010100110100000011010100110100 00001101010011010000001101010011 01000000110101001101000000110101 00110100000011010100000000010001 01010000000000000000000000000000 00000000000000000000000000000000 01000000000000010100100000000100 01110010000000010001110010000000 01000111001000000001000111001000 00000000011100100000000100011100 10000000010001110010000000010001 11001000000001000111001000000001 00011100100000000000011100100000 00010001110010000000010001110010 00000001000101001000000001000111 00100000000100011100000000110001 00010000000000000000000000000000 00000000000000000000000000000000 00000000000000000010001100011000 01001000110001100001001000110001 10000100100011000110000100100011 00011000010010001100011000010010 00110001100001001000110001100001 00100011000110000100100011000110 00010010001100011000010010001100 01100001001000110001100001001000 11000110000100100011000110000100 10001100011000010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 01001111111111111101001111111111 11110100111111111111110100111111 11111111010011111111111111010011 11111111111101001111111111111101 00111111111111110100111111111111 11010011111111111111010011111111 11111101001111111111111101001111 11111111110100111111111111110100 11111111111111010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010110011011011 00001011001101101100001011001101 10110000101100110110110000101100 11011011000010110011011011000010 11001101101100001011001101101100 00101100110110110000101100110110 11000010110011011011000010110011 01101100001011001101101100001011 00110110110000101100110110110000 10110011011011000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011001100111100 01001100110011110001001100110011 11000100110011001111000100110011 00111100010011001100111100010011 00110011110001001100110011110001 00110011001111000100110011001111 00010011001100111100010011001100 11110001001100110011110001001100 11001111000100110011001111000100 11001100111100010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011101101111110 01001110110111111001001110110111 11100100111011011111100100111011 01111110010011101101111110010011 10110111111001001110110111111001 00111011011111100100111011011111 10010011101101111110010011101101 11111001001110110111111001001110 11011111100100111011011111100100 11101101111110010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000001010000101 00100000001000010000000100101000 01000001000010100001000000010010 10000010001100001010000011000101 00101000010000000000101000011000 00010010100001000010000010100001 00000000001010000111000100001010 00010100000000001000010000101100 10100001000000000010010001000010 00001001000100001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000100 00010000000100010000010000000000 01000010001010000001000000111000 00000110000001000000000100001000 00000000010100110010000000010100 00011000000001010011010000000001 11000000000000000111000100000000 00010000000000000000010000111000 00000001000000000010010001000000 00000000000100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011000010000101 00100100100000010000100000000000 01000011000000100001000010000000 10000101001000000001000100001000 00001000011000100000001000011000 10000000100001110011001000100001 11001010000010000111001000000010 00010100000100101000010000100000 00100001000000110000000001000010 00000001000100001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000101 00000000100100010000101100000000 01000011000000000001000010000000 00000100001000000001000100001111 00000000010000110000000000010000 10000000000001110000010000000001 10001011000000000101001100000000 00010100000000000000010000010000 00000001000000000000000001000010 00000000000100001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000000 00010100001000001100110100001000 00000001000010100000010011000000 10000001000001000010000011000001 00001000001100000000001000000000 00010000100000110001010000100000 00001000000010000000000000000010 00000100110100001000000000110000 00100000000000000000000000000000 00000010000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000001000000001 00000000100100000000000000000000 00000010000000000000010001000010 00000011000000001000000000001000 00100000000100000000100000001000 00000010000000100000000010000000 00000000001000000000000000001000 00000100100000100000000100110000 10000000000000000000000000000000 00001000000000000000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000001000010000001 00100010101000000000100110001100 00000001001000100000100010001000 10000011000001100010000000001010 10001000001100000010001000000100 00001000100000010010111000100000 00001000100010000000000000100010 00000000111110001000000100111110 00100000000010011000110000000010 00100010000000001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000100000000011 00000010000000001100110110100000 00000001001010000000010001001000 00000010000000100000000000001000 10000000001000000000000000000000 00001000000000000010001000000000 00001010100000000000000000100000 00001000110010000000001100011010 00000000000010001010010000000010 00100000000000001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000011101010000111 00101010001000010000010010101000 01000011001000010001000010001000 10000101000100101010000101000000 10101000011000000010101000010000 01001010100001100001001010100001 10000001101010000100000100101010 00010100111010001000010100000010 00100001000000001000100001000000 00100010000100000000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000001100000000100 00101110000000010000100010000000 01000011001010000001000011101000 00000101000010100000000100000001 10000000011100000010000000010000 11101010000001010010011000000001 00001100100000000100001100100000 00010100110110100000011100100110 00000001000001111000000001000001 00101001000100000000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000000010000100 00000000101000010000110100000100 01000011000000100001000010100010 10000000001010000010000101001010 00001000011100000000001000010000 11010000100001100001100000100000 01001000000010000101001000000010 00010100100000001000011100110000 10100001000010100000100001000010 00000010000100001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000100000000000000000111 00100000000000010000110000000000 01000001010010000001000011010010 00000110000001000000000101001000 00000000011000110100000000011100 01110000000001010011010000000001 01000000000000000101000001000000 00011100100000100100011000100000 10000001110001000000000001110001 00000000000100001000001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000010000010000111 00000100101000010000100000100000 01110000010000100001010000010000 10000101001101000010000111001110 00001000010100100000001000011100 01000010100001110000000000100001 00000001000010000111001110000010 00011000100000001000011100010000 00100001110011010000100001000000 00000001000100001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001001000000001 00001000000000000000010100000100 01000010000000000000100010100010 00000101000110001000000100001000 00000000001000100100100000010000 01000000000001000010100010000000 00000000001000000111000001001000 00010100100100000000011000100000 10000001000000000000000000000011 11000000000000000100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000001 00100100101000000000100100000000 01000010010010100000010011000010 10000111001001000010000100001110 00001000000100110100001000010000 10000000100001000011100000100000 00001000000010000111000001000010 00010100000000101000010100111000 10100001000000000000000000000010 01000010000000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000100001000000000000011 00100000100000000000000100100100 00000001100010000000000011000000 00000001001100000000000011001000 00100000000100101000000000000000 00100010000000000010000000000000 00001001000000000010001100000000 00001100001000100100000100101000 00000000110011010010000000000001 00001000000000001000000000000100 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000000010000 01000000100000000000000000000000 00000000000000000001000000010000 00000000000000000000000000000000 00000000000100000000000000000000 10010000000000000000000000000000 00000000000000000001000000000000 00000000100100000010000000000000 00000000000000000000000000000000 00000000001000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00111100001111000011000000000000 10000000100000000000000000000000 00010000000000000000000000110000 10000000000000001000000000000000 00000000000100000010000000010000 00110000100000000000000010000000 00000000000000000000000000100000 00010000001100000000000000000000 01000000000000000000000000010000 00000000000000000000111100001111 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000011001 10000000000110011000000000111111 11011001101111111101100110000000 00011001101111111101100100000000 00011111101100101011100011001111 10000000000000000001100110100110 00000000000000011000111101001011 01101000010000000001100110000000 00011001110000000011111111011001 10111111110110011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000001000000000111110 10111110101111101011111010000000 00000000000000000010000000000000 00010010000100101000011010000010 00010110100000000001011010100000 00000000000001100000010000000000 00010000000000000000000000000000 00000000000000000010100000010000 00111110100101101100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010001000 01000100100000010100000110000000 00000000000000000000000000000000 11000000000000000000000000000000 00000000000000000000000000000000 00000000110000000000000000000000 00000000000000000000000000000000 00000000000000001000000101111000 01000001101100010000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111101111111111111111111111 11000000000000000000000000000000 00000000001111111111111111101111 11111101110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000101101 11111111101011101111111111000000 00000000000000000000000000000000 00111111101111111111111111111110 00000000000000000000000000000000 00000000001101111111111011111111 01111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111101 11111111111111111011111111000000 00000000000000000000000000000000 00111111101111111111111111111111 11000000000000000000000000000000 00000000001111111111111111111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000001111111111111111111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111100111111 11000000000000000000000000000000 00000000001111111111111111111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111101111111111111111000000 00000000000000000000000000000000 00111111111111111011111111111111 11000000000000000000000000000000 00000000001111111111111100111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000011000111 00100100101000010000100000001000 01000001000000100001000010010010 10000100000000001010000000001000 00101000010000010000101000011000 10110010110001010000010010100001 00001000001010000100000100001010 00010000101100101000011100000100 10110001000001000000100001000000 00000010000100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000001000111 00010000100000010000110000000000 01000011000000000001000001110000 00000101000010000000000000001001 00000000010000100000000000011100 01000000000001100000100000000001 00000000000000000111001000000000 00010000001000000000011100101100 00000001000010000000000001000000 00000000000100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000011000111 00101000001000010000100100101100 01000011000010100001000010000000 10000110000001000010000000001000 00001000010000010000001100011100 10000000100001010000010000100001 00001000000010000101000000000001 00010000100000001000011100000000 00000001000011000000010001000000 00001010000100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000000000100 00101000000000010000010100000000 01000011000000000001000010000000 00000100000001000000000000001101 00000000010000000000000000011000 00000000000001010000010000000001 00000010000000000110000100000001 00010000100000000000010000010000 00010001000010110010000001000000 00001000000100000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000010001011000000 00100000101000000000000100001000 00000010000000100000000010000000 10000000000000000010000000000101 00001000001100100000001000000100 00100000110000000000000000100000 10001001000010000010000000000010 00001100000000000100000000000000 00110000000000010000010000000000 00000001000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000000001000000 00000000000000000000010000100000 00000000000010000000000001000010 00000000000000001000000000001100 00100000000100010000100000001000 00000010000000000000000010000000 01000000001000000001000000001000 00001100010000100100000000100000 10000000000000000010000000000001 00001000000000000100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001101000000000 00100110001000000000100110101100 00000010001000100000010010001000 10000001000001100010000000001101 10001000001100100010001100000100 10011000100000000000011000100000 10001001100010000010000000100010 00001100100010000100000000011110 00100000000010011000000000000010 00101010000000001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000010100000000000 00000110100000000000000010000000 00000010001000000000010000001000 00000001000000100000000000000010 10000000001000000010000000000000 10001000000000000000011000000000 00001000100000000000000000100000 00000100000110000100000000001010 00000000000010001000000000000010 00100000000000001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000101010000111 00101010101000010000010110001000 01000001001010100001000010001010 10000101000100101010000110000001 10101000011000000010101000010000 01101000100001010001001010100001 01000001101010000100000000101001 00010100000010100000011100100010 10000001000001011010000001000001 00101001000100000000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000010100000000111 00110010000000010000110010000000 01010011001000000001000001101000 00000111000010100000000101000100 10000000011100100010000000010000 10101000000001100010001010000001 10001000100000000100000000100001 00011000110010000100011100010110 00000001000010001000010001000010 00100001000100000100001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000111 00110000001000010000110100001000 01000010000000010001000010100000 10000111001010000010000110001000 00001000010100010000001000010000 01000010100001010000100000100001 01000101000010000101000000000010 00010100111000001000011100100000 00100001000001100000000001000001 00000001000100001000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00001000000100000001000000000111 00010100000000011100010000100000 01100011000000000001110001000000 00000101000111000000000101001100 00000000010100100000000000011100 11000010000001110011010000000001 11001100000000000101000010000000 00011100010100000100011100010100 00000001110011000000010001110010 00000001000111001100001000000100 00000000000000000000000000000000 00000000000000000000000000000000 00001000000000000000001010000100 00001000001000010000000000001000 01000010010000010001000010000000 10000111000000000010000101000010 00001000010000100000001000010100 00010000100001110010100010100001 01001010000010000101000000000010 00011100000000001000010100100000 00110001100001100000010001000010 01000010000100000000001000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000000000000 00000100100000000000000100100000 00000010000010000000000011110010 00000011000010001000000010001001 00100000000100100000100000001000 01100010000001000010000000000000 10000001001000000011000000001000 00011000100100100000001000101000 10000000010010010010000000000010 00001001000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000010000000 00100100001000000000100000101000 00000011000000100000000010010000 10000011001001000010000001001100 00001000000000111100001000000100 10010010100001000010100000100000 01001000000010000011000001000001 00010100100000000100000100101000 00100000000011000000010000000010 01000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000100001010001000000000 00100000000000000000101000000000 00000010100000010000000011000000 00000001001000000000000001001000 00000000001000111000000000000000 10000000000000110010000010000000 00000000000000000000000010000001 00000000100100000000000000110000 00000000100010000000000000000011 10000001000000000000000000000100 00100000000000000000000000000000 00000000000000000000000000000000 00000000000000000001000000000000 01000000000000000000000000000000 00000000000000000001000000010000 00000000000000000000000000000000 00000000000100000000000000000000 10010000000000000000000000000000 00000000000000000001000010000000 00100000100100000000000000000000 00000000000000000000000000000000 00000000001000001000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00111100001111000011000000000000 10100000000000000000000000000000 00010000000000000000000000110000 10000000000000001000000000000000 00000000000000000010000000010000 10110000100000000000000010000000 00000000000000000001000000100000 00010000101100000000000001000000 11000000000000000000000000010000 00000000000000000000111100001111 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000100000000111111 11011001101111111101100110000000 00100110010110011001100100000000 00011111001100010111100000011101 11011001100000000010011001000000 00000000000010001000001111001000 01101111100000000001100110000000 00000000110000000011111111011001 10111111110110011000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000101000 00101001001010000010000001000000 00000000000000000010000010000000 00000100100001101000010010000110 00000000000000000000000000100000 10000000000000101001001000010000 10000100000000000000000000000000 00000000100000000010100000000000 00101000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000010000100 10000001000000010101000100000000 00000000000000000000000000000000 11000000000000000000000000000000 00000000000000000000000000000000 00000000100000000000000000000000 00000000000000000000000000000000 00000000000000001000000101111000 01001000101100010100000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000101111 11111011111111111110111111000000 00000000000000000000000000000000 00011111100111111001111111011111 11000000000000000000000000000000 00000000001011111111111111111111 11110111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 01011111010011101111111111000000 00000000000000000000000000000000 00101111011011110110111111111101 01000000000000000000000000000000 00000000001111110011111101001111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000011111 11111111101111111111111111000000 00000000000000000000000000000000 00101111001111111011111111111111 11000000000000000000000000000000 00000000001111110111111110111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000001111111111111011111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111110111111 11000000000000000000000000000000 00000000001111111111111111111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000011111111111111 11111111111111111100000000000000 00000000000000000000000000111111 11111111111111111111111111000000 00000000000000000000000000000000 00111111111111111111111111111111 11000000000000000000000000000000 00000000001111111111111111111111 11111111110000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000010000000000001 00000010000000000000000000000000 00110000000000000100001100001100 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000010000000000001 00000010000000100000000000000000 00110000000000000100001100000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000000000000000000001 00000000000000001010100001101000 00110000000000001000000000000001 00000000000000000000000000000011 00110000000000000100000000001100 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00110000000000001000000000000001 00000000000000000000000000000101 00110000000000001010000000000001 00000000000000000000000000000000 00110000000000000000000000000001 00000000000000001110000101011010 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000 dahdi-linux-2.5.0.1/drivers/dahdi/Kconfig0000644000175000017500000001635011341545412020046 0ustar tzafrirtzafrir# # DAHDI configuration # menuconfig DAHDI tristate "DAHDI support" select CRC_CCITT default m ---help--- DAHDI basic infrastructure. To compile this driver as a module, choose M here: the module will be called dahdi. If unsure, say Y. config DAHDI_ECHOCAN tristate "DADHI Echo Cancelers (software)" depends on DAHDI default DAHDI config DAHDI_ECHOCAN_MG2 tristate "DADHI MG2 Echo Canceler" depends on DAHDI_ECHOCAN default DAHDI_ECHOCAN ---help--- To compile this driver as a module, choose M here: the module will be called dahdi_echocancel_mg2. If unsure, say Y. config DAHDI_ECHOCAN_KB1 tristate "DADHI KB1 Echo Canceler" depends on DAHDI_ECHOCAN default DAHDI_ECHOCAN ---help--- To compile this driver as a module, choose M here: the module will be called dahdi_echocancel_kb1. If unsure, say Y. config DAHDI_ECHOCAN_SEC tristate "DADHI SEC Echo Canceler" depends on DAHDI_ECHOCAN default DAHDI_ECHOCAN ---help--- To compile this driver as a module, choose M here: the module will be called dahdi_echocancel_sec. If unsure, say Y. config DAHDI_ECHOCAN_SEC2 tristate "DADHI SEC2 Echo Canceler" depends on DAHDI_ECHOCAN default DAHDI_ECHOCAN ---help--- To compile this driver as a module, choose M here: the module will be called dahdi_echocancel_sec2. If unsure, say Y. config DAHDI_ECHOCAN_HPEC tristate "DADHI HPEC Echo Canceler" depends on DAHDI_ECHOCAN default DAHDI_ECHOCAN ---help--- To compile this driver as a module, choose M here: the module will be called dahdi_echocancel_hpec. If unsure, say Y. config DAHDI_WCTDM tristate "Digium Wildcard TDM400P Support" depends on DAHDI && PCI default DAHDI ---help--- This driver provides support for the Digium Wildcard TDM400P. To compile this driver as a module, choose M here: the module will be called wctdm. If unsure, say Y. config DAHDI_WCT4XXP tristate "Digium Wildcard dual- and quad-T1/E1/J1 Support" depends on DAHDI && PCI default DAHDI ---help--- This driver provides support for the following Digium Wildcard products: * TE205/206/207/210/211/212P (PCI/PCI-X) * TE220 (PCI-E) * TE405/406/407/410/411/412P (PCI/PCI-X) * TE420 (PCI-E) To compile this driver as a module, choose M here: the module will be called wct4xxp. If unsure, say Y. config DAHDI_TRANSCODE tristate "DAHDI transcoding support" depends on DAHDI default DAHDI ---help--- DAHDI transcoding infrastructure. To compile this driver as a module, choose M here: the module will be called dahdi_transcode. If unsure, say Y. config DAHDI_WCTC4XXP tristate "Digium Wildcard TC400B Support" depends on DAHDI_TRANSCODE && PCI default DAHDI ---help--- This driver provides support for the Digium Wildcard TC400B. To compile this driver as a module, choose M here: the module will be called wctc4xxp. If unsure, say Y. config DAHDI_VOICEBUS tristate "VoiceBus(tm) Interface Library" depends on PCI default DAHDI ---help--- This driver provides the common interface for telephony cards that use the VoiceBus(tm) interface. It also contains common supporting libraries for the VPMADT032 hardware echo cancelation module that is available for the VoiceBus cards. To compile this driver as a module, choose M here: the module will be called voicebus. If unsure, say Y. config DAHDI_WCTDM24XXP tristate "Digium Wildcard VoiceBus analog card Support" depends on DAHDI && DAHDI_VOICEBUS default DAHDI ---help--- This driver provides support for the following Digium Wildcard products: * TDM410P (PCI/PCI-X) * AEX410 (PCI-E) * TDM800P (PCI/PCI-X) * AEX800 (PCI-E) * TDM2400P (PCI/PCI-X) * AEX2400 (PCI-E) To compile this driver as a module, choose M here: the module will be called wctdm24xxp. If unsure, say Y. config DAHDI_WCTE12XP tristate "Digium Wildcard VoiceBus digital card Support" depends on DAHDI && DAHDI_VOICEBUS default DAHDI ---help--- This driver provides support for the following Digium Wildcard products: * TE120P (PCI/PCI-X) * TE121 (PCI/PCI-X) * TE122 (PCI-E) To compile this driver as a module, choose M here: the module will be called wcte12xp. If unsure, say Y. config DAHDI_PCIRADIO tristate "PCI Radio Support" depends on DAHDI && PCI default DAHDI ---help--- To compile this driver as a module, choose M here: the module will be called pciradio. If unsure, say Y. config DAHDI_DUMMY tristate "Dummy (no hardware) Timing Support" depends on DAHDI default DAHDI ---help--- This module provides timing support for applications that use DAHDI conference mixing services, pseudo channels or for other purposes. To compile this driver as a module, choose M here: the module will be called dahdi_dummy. If unsure, say Y. config DAHDI_DYNAMIC tristate "Dynamic (virtual) Span Support" depends on DAHDI default DAHDI ---help--- This module provides support for virtual spans, which are emulated or provided using various technologies. To compile this driver as a module, choose M here: the module will be called dahdi_dynamic. If unsure, say Y. config DAHDI_DYNAMIC_ETH tristate "Ethernet (TDMoE) Span Support" depends on DAHDI && DAHDI_DYNAMIC default DAHDI ---help--- This module provides support for spans over Ethernet, using the TDMoE protocol. To compile this driver as a module, choose M here: the module will be called dahdi_dynamic_eth. If unsure, say Y. config DAHDI_DYNAMIC_ETHMF tristate "Ethernet (TDMoE) Multi-Frame Span Support" depends on DAHDI && DAHDI_DYNAMIC default DAHDI ---help--- This module provides support for spans over Ethernet, using the TDMoE-Multi-Frame protocol. To compile this driver as a module, choose M here: the module will be called dahdi_dynamic_ethmf. If unsure, say Y. config DAHDI_DYNAMIC_LOC tristate "Local (loopback) Span Support" depends on DAHDI && DAHDI_DYNAMIC default DAHDI ---help--- This module provides support for spans in the local system, primarily used for looping and monitoring other spans. To compile this driver as a module, choose M here: the module will be called dahdi_dynamic_loc. If unsure, say Y. config DAHDI_TOR2 tristate "Tormenta2 quad-port T1/E1 Support" depends on DAHDI && PCI default DAHDI ---help--- To compile this driver as a module, choose M here: the module will be called tor2. If unsure, say Y. config DAHDI_WCFXO tristate "Digium Wildcard X100P Support" depends on DAHDI && PCI default DAHDI ---help--- To compile this driver as a module, choose M here: the module will be called wcfxo. If unsure, say Y. config DAHDI_WCT1XXP tristate "Digium Wildcard T100P Support" depends on DAHDI && PCI default DAHDI ---help--- To compile this driver as a module, choose M here: the module will be called wct1xxp. If unsure, say Y. config DAHDI_WCTE11XP tristate "Digium Wildcard TE110P Support" depends on DAHDI && PCI default DAHDI ---help--- To compile this driver as a module, choose M here: the module will be called wcte11xp. If unsure, say Y. source "drivers/dahdi/xpp/Kconfig" dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_dummy.c0000644000175000017500000001662311510412325021170 0ustar tzafrirtzafrir/* * Dummy DAHDI Driver for DAHDI Telephony interface * * Required: kernel > 2.6.0 * * Written by Robert Pleh * 2.6 version by Tony Hoyle * Unified by Mark Spencer * * Converted to use HighResTimers on i386 by Jeffery Palmer * * Copyright (C) 2002, Hermes Softlab * Copyright (C) 2004-2009, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /* * To use the high resolution timers, in your kernel CONFIG_HIGH_RES_TIMERS * needs to be enabled (Processor type and features -> High Resolution * Timer Support), and optionally HPET (Processor type and features -> * HPET Timer Support) provides a better clock source. */ #include #if defined(CONFIG_HIGH_RES_TIMERS) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) #define USE_HIGHRESTIMER #endif #include #include #include #include #include #include #if defined(USE_HIGHRESTIMER) #include #else #include #endif #include #ifndef HAVE_HRTIMER_ACCESSORS #if defined(USE_HIGHRESTIMER) && \ (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)) /* Compatibility with new hrtimer interface */ static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer) { return timer->expires; } static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) { timer->expires = time; } #endif #endif struct dahdi_dummy { struct dahdi_span span; struct dahdi_chan _chan; struct dahdi_chan *chan; #if !defined(USE_HIGHRESTIMER) unsigned long calls_since_start; struct timespec start_interval; #endif }; static struct dahdi_dummy *ztd; static int debug = 0; #ifdef USE_HIGHRESTIMER #define CLOCK_SRC "HRtimer" static struct hrtimer zaptimer; #define DAHDI_RATE 1000 /* DAHDI ticks per second */ #define DAHDI_TIME (1000000 / DAHDI_RATE) /* DAHDI tick time in us */ #define DAHDI_TIME_NS (DAHDI_TIME * 1000) /* DAHDI tick time in ns */ #else #define CLOCK_SRC "Linux26" static struct timer_list timer; static atomic_t shutdown; #define JIFFIES_INTERVAL max(HZ/250, 1) /* 4ms is fine for dahdi_dummy */ #endif /* Different bits of the debug variable: */ #define DEBUG_GENERAL (1 << 0) #define DEBUG_TICKS (1 << 1) #if defined(USE_HIGHRESTIMER) static enum hrtimer_restart dahdi_dummy_hr_int(struct hrtimer *htmr) { unsigned long overrun; /* Trigger DAHDI */ dahdi_receive(&ztd->span); dahdi_transmit(&ztd->span); /* Overrun should always return 1, since we are in the timer that * expired. * We should worry if overrun is 2 or more; then we really missed * a tick */ overrun = hrtimer_forward(&zaptimer, hrtimer_get_expires(htmr), ktime_set(0, DAHDI_TIME_NS)); if(overrun > 1) { if(printk_ratelimit()) printk(KERN_NOTICE "dahdi_dummy: HRTimer missed %lu ticks\n", overrun - 1); } if(debug && DEBUG_TICKS) { static int count = 0; /* Printk every 5 seconds, good test to see if timer is * running properly */ if (count++ % 5000 == 0) printk(KERN_DEBUG "dahdi_dummy: 5000 ticks from hrtimer\n"); } /* Always restart the timer */ return HRTIMER_RESTART; } #else static unsigned long timespec_diff_ms(struct timespec *t0, struct timespec *t1) { long nanosec, sec; unsigned long ms; sec = (t1->tv_sec - t0->tv_sec); nanosec = (t1->tv_nsec - t0->tv_nsec); while (nanosec >= NSEC_PER_SEC) { nanosec -= NSEC_PER_SEC; ++sec; } while (nanosec < 0) { nanosec += NSEC_PER_SEC; --sec; } ms = (sec * 1000) + (nanosec / 1000000L); return ms; } static void dahdi_dummy_timer(unsigned long param) { unsigned long ms_since_start; struct timespec now; const unsigned long MAX_INTERVAL = 100000L; const unsigned long MS_LIMIT = 3000; if (!atomic_read(&shutdown)) mod_timer(&timer, jiffies + JIFFIES_INTERVAL); now = current_kernel_time(); ms_since_start = timespec_diff_ms(&ztd->start_interval, &now); /* * If the system time has changed, it is possible for us to be far * behind. If we are more than MS_LIMIT milliseconds behind, just * reset our time base and continue so that we do not hang the system * here. * */ if (unlikely((ms_since_start - ztd->calls_since_start) > MS_LIMIT)) { if (printk_ratelimit()) { printk(KERN_INFO "dahdi_dummy: Detected time shift.\n"); } ztd->calls_since_start = 0; ztd->start_interval = now; return; } while (ms_since_start > ztd->calls_since_start) { ztd->calls_since_start++; dahdi_receive(&ztd->span); dahdi_transmit(&ztd->span); } if (ms_since_start > MAX_INTERVAL) { ztd->calls_since_start = 0; ztd->start_interval = now; } } #endif static const struct dahdi_span_ops dummy_ops = { .owner = THIS_MODULE, }; static int dahdi_dummy_initialize(struct dahdi_dummy *ztd) { /* DAHDI stuff */ ztd->chan = &ztd->_chan; sprintf(ztd->span.name, "DAHDI_DUMMY/1"); snprintf(ztd->span.desc, sizeof(ztd->span.desc) - 1, "%s (source: " CLOCK_SRC ") %d", ztd->span.name, 1); sprintf(ztd->chan->name, "DAHDI_DUMMY/%d/%d", 1, 0); strlcpy(ztd->span.devicetype, "DAHDI Dummy Timing", sizeof(ztd->span.devicetype)); ztd->chan->chanpos = 1; ztd->span.chans = &ztd->chan; ztd->span.channels = 0; /* no channels on our span */ ztd->span.deflaw = DAHDI_LAW_MULAW; ztd->chan->pvt = ztd; ztd->span.ops = &dummy_ops; if (dahdi_register(&ztd->span, 0)) { return -1; } return 0; } int init_module(void) { ztd = kzalloc(sizeof(*ztd), GFP_KERNEL); if (ztd == NULL) { printk(KERN_ERR "dahdi_dummy: Unable to allocate memory\n"); return -ENOMEM; } if (dahdi_dummy_initialize(ztd)) { printk(KERN_ERR "dahdi_dummy: Unable to intialize DAHDI driver\n"); kfree(ztd); return -ENODEV; } #if defined(USE_HIGHRESTIMER) printk(KERN_DEBUG "dahdi_dummy: Trying to load High Resolution Timer\n"); hrtimer_init(&zaptimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); printk(KERN_DEBUG "dahdi_dummy: Initialized High Resolution Timer\n"); /* Set timer callback function */ zaptimer.function = dahdi_dummy_hr_int; printk(KERN_DEBUG "dahdi_dummy: Starting High Resolution Timer\n"); hrtimer_start(&zaptimer, ktime_set(0, DAHDI_TIME_NS), HRTIMER_MODE_REL); printk(KERN_INFO "dahdi_dummy: High Resolution Timer started, good to go\n"); #else init_timer(&timer); timer.function = dahdi_dummy_timer; ztd->start_interval = current_kernel_time(); timer.expires = jiffies + JIFFIES_INTERVAL; atomic_set(&shutdown, 0); add_timer(&timer); #endif if (debug) printk(KERN_DEBUG "dahdi_dummy: init() finished\n"); return 0; } void cleanup_module(void) { #if defined(USE_HIGHRESTIMER) /* Stop high resolution timer */ hrtimer_cancel(&zaptimer); #else atomic_set(&shutdown, 1); del_timer_sync(&timer); #endif dahdi_unregister(&ztd->span); kfree(ztd); if (debug) printk(KERN_DEBUG "dahdi_dummy: cleanup() finished\n"); } module_param(debug, int, 0600); MODULE_DESCRIPTION("Timing-Only Driver"); MODULE_AUTHOR("Robert Pleh "); MODULE_LICENSE("GPL v2"); dahdi-linux-2.5.0.1/drivers/dahdi/wcfxo.c0000644000175000017500000007107711510412325020036 0ustar tzafrirtzafrir/* * Wildcard X100P FXO Interface Driver for DAHDI Telephony interface * * Written by Mark Spencer * Matthew Fredrickson * * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include /* Uncomment to enable tasklet handling in the FXO driver. Not recommended in general, but may improve interactive performance */ /* #define ENABLE_TASKLETS */ /* Un-comment the following for POTS line support for Japan */ /* #define JAPAN */ /* Un-comment for lines (eg from and ISDN TA) that remove */ /* phone power during ringing */ /* #define ZERO_BATT_RING */ #define WC_MAX_IFACES 128 #define WC_CNTL 0x00 #define WC_OPER 0x01 #define WC_AUXC 0x02 #define WC_AUXD 0x03 #define WC_MASK0 0x04 #define WC_MASK1 0x05 #define WC_INTSTAT 0x06 #define WC_DMAWS 0x08 #define WC_DMAWI 0x0c #define WC_DMAWE 0x10 #define WC_DMARS 0x18 #define WC_DMARI 0x1c #define WC_DMARE 0x20 #define WC_AUXFUNC 0x2b #define WC_SERCTL 0x2d #define WC_FSCDELAY 0x2f /* DAA registers */ #define WC_DAA_CTL1 1 #define WC_DAA_CTL2 2 #define WC_DAA_DCTL1 5 #define WC_DAA_DCTL2 6 #define WC_DAA_PLL1_N1 7 #define WC_DAA_PLL1_M1 8 #define WC_DAA_PLL2_N2_M2 9 #define WC_DAA_PLL_CTL 10 #define WC_DAA_CHIPA_REV 11 #define WC_DAA_LINE_STAT 12 #define WC_DAA_CHIPB_REV 13 #define WC_DAA_DAISY_CTL 14 #define WC_DAA_TXRX_GCTL 15 #define WC_DAA_INT_CTL1 16 #define WC_DAA_INT_CTL2 17 #define WC_DAA_INT_CTL3 18 #define WC_DAA_INT_CTL4 19 #define FLAG_EMPTY 0 #define FLAG_WRITE 1 #define FLAG_READ 2 #ifdef ZERO_BATT_RING /* Need to debounce Off/On hook too */ #define JAPAN #endif #define RING_DEBOUNCE 64 /* Ringer Debounce (in ms) */ #ifdef JAPAN #define BATT_DEBOUNCE 30 /* Battery debounce (in ms) */ #define OH_DEBOUNCE 350 /* Off/On hook debounce (in ms) */ #else #define BATT_DEBOUNCE 80 /* Battery debounce (in ms) */ #endif #define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ #define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ #define PEGCOUNT 5 /* 5 cycles of pegging means RING */ #define wcfxo_printk(level, span, fmt, ...) \ printk(KERN_ ## level "%s-%s: %s: " fmt, #level, \ THIS_MODULE->name, (span).name, ## __VA_ARGS__) #define wcfxo_notice(span, fmt, ...) \ wcfxo_printk(NOTICE, span, fmt, ## __VA_ARGS__) #define wcfxo_dbg(span, fmt, ...) \ ((void)((debug) && wcfxo_printk(DEBUG, span, "%s: " fmt, \ __FUNCTION__, ## __VA_ARGS__) ) ) struct reg { unsigned long flags; unsigned char index; unsigned char reg; unsigned char value; }; static int wecareregs[] = { WC_DAA_DCTL1, WC_DAA_DCTL2, WC_DAA_PLL2_N2_M2, WC_DAA_CHIPA_REV, WC_DAA_LINE_STAT, WC_DAA_CHIPB_REV, WC_DAA_INT_CTL2, WC_DAA_INT_CTL4, }; struct wcfxo { struct pci_dev *dev; char *variety; struct dahdi_span span; struct dahdi_chan _chan; struct dahdi_chan *chan; int usecount; int dead; int pos; unsigned long flags; int freeregion; int ring; int offhook; int battery; int wregcount; int readpos; int rreadpos; unsigned int pegtimer; int pegcount; int peg; int battdebounce; int nobatttimer; int ringdebounce; #ifdef JAPAN int ohdebounce; #endif int allread; int regoffset; /* How far off our registers are from what we expect */ int alt; int ignoreread; int reset; /* Up to 6 register can be written at a time */ struct reg regs[DAHDI_CHUNKSIZE]; struct reg oldregs[DAHDI_CHUNKSIZE]; unsigned char lasttx[DAHDI_CHUNKSIZE]; /* Up to 32 registers of whatever we most recently read */ unsigned char readregs[32]; unsigned long ioaddr; dma_addr_t readdma; dma_addr_t writedma; volatile int *writechunk; /* Double-word aligned write memory */ volatile int *readchunk; /* Double-word aligned read memory */ #ifdef ZERO_BATT_RING int onhook; #endif #ifdef ENABLE_TASKLETS int taskletrun; int taskletsched; int taskletpending; int taskletexec; int txerrors; int ints; struct tasklet_struct wcfxo_tlet; #endif }; #define FLAG_INVERTSER (1 << 0) #define FLAG_USE_XTAL (1 << 1) #define FLAG_DOUBLE_CLOCK (1 << 2) #define FLAG_RESET_ON_AUX5 (1 << 3) #define FLAG_NO_I18N_REGS (1 << 4) /*!< Uses si3035, rather si3034 */ struct wcfxo_desc { char *name; unsigned long flags; }; static struct wcfxo_desc wcx100p = { "Wildcard X100P", FLAG_INVERTSER | FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; static struct wcfxo_desc wcx101p = { "Wildcard X101P", FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; static struct wcfxo_desc generic = { "Generic Clone", FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; static struct wcfxo *ifaces[WC_MAX_IFACES]; static void wcfxo_release(struct wcfxo *wc); static int debug = 0; static int monitor = 0; static int quiet = 0; static int boost = 0; static int opermode = 0; static struct fxo_mode { char *name; int ohs; int act; int dct; int rz; int rt; int lim; int vol; } fxo_modes[] = { { "FCC", 0, 0, 2, 0, 0, 0, 0 }, /* US */ { "CTR21", 0, 0, 3, 0, 0, 3, 0 }, /* Austria, Belgium, Denmark, Finland, France, Germany, Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands, Norway, Portugal, Spain, Sweden, Switzerland, and UK */ }; static inline void wcfxo_transmitprep(struct wcfxo *wc, unsigned char ints) { volatile int *writechunk; int x; int written=0; unsigned short cmd; /* if nothing to transmit, have to do the dahdi_transmit() anyway */ if (!(ints & 3)) { /* Calculate Transmission */ dahdi_transmit(&wc->span); return; } /* Remember what it was we just sent */ memcpy(wc->lasttx, wc->chan->writechunk, DAHDI_CHUNKSIZE); if (ints & 0x01) { /* Write is at interrupt address. Start writing from normal offset */ writechunk = wc->writechunk; } else { writechunk = wc->writechunk + DAHDI_CHUNKSIZE * 2; } dahdi_transmit(&wc->span); for (x=0;xflags & FLAG_INVERTSER) writechunk[x << 1] = cpu_to_le32( ~((unsigned short)(DAHDI_XLAW(wc->chan->writechunk[x], wc->chan))| 0x1) << 16 ); else writechunk[x << 1] = cpu_to_le32( ((unsigned short)(DAHDI_XLAW(wc->chan->writechunk[x], wc->chan))| 0x1) << 16 ); /* We always have a command to follow our signal */ if (!wc->regs[x].flags) { /* Fill in an empty register command with a read for a potentially useful register */ wc->regs[x].flags = FLAG_READ; wc->regs[x].reg = wecareregs[wc->readpos]; wc->regs[x].index = wc->readpos; wc->readpos++; if (wc->readpos >= (sizeof(wecareregs) / sizeof(wecareregs[0]))) { wc->allread = 1; wc->readpos = 0; } } /* Prepare the command to follow it */ switch(wc->regs[x].flags) { case FLAG_READ: cmd = (wc->regs[x].reg | 0x20) << 8; break; case FLAG_WRITE: cmd = (wc->regs[x].reg << 8) | (wc->regs[x].value & 0xff); written = 1; /* Wait at least four samples before reading */ wc->ignoreread = 4; break; default: printk(KERN_DEBUG "wcfxo: Huh? No read or write??\n"); cmd = 0; } /* Setup the write chunk */ if (wc->flags & FLAG_INVERTSER) writechunk[(x << 1) + 1] = cpu_to_le32(~(cmd << 16)); else writechunk[(x << 1) + 1] = cpu_to_le32(cmd << 16); } if (written) wc->readpos = 0; wc->wregcount = 0; for (x=0;xoldregs[x] = wc->regs[x]; wc->regs[x].flags = FLAG_EMPTY; } } static inline void wcfxo_receiveprep(struct wcfxo *wc, unsigned char ints) { volatile int *readchunk; int x; int realreg; int realval; int sample; if (ints & 0x04) /* Read is at interrupt address. Valid data is available at normal offset */ readchunk = wc->readchunk; else readchunk = wc->readchunk + DAHDI_CHUNKSIZE * 2; /* Keep track of how quickly our peg alternates */ wc->pegtimer+=DAHDI_CHUNKSIZE; for (x=0;xoldregs[x].flags == FLAG_READ && !wc->ignoreread) { realreg = wecareregs[(wc->regs[x].index + wc->regoffset) % (sizeof(wecareregs) / sizeof(wecareregs[0]))]; realval = (le32_to_cpu(readchunk[(x << 1) +wc->alt]) >> 16) & 0xff; if ((realval == 0x89) && (realreg != WC_DAA_PLL2_N2_M2)) { /* Some sort of slippage, correct for it */ while(realreg != WC_DAA_PLL2_N2_M2) { /* Find register 9 */ realreg = wecareregs[(wc->regs[x].index + ++wc->regoffset) % (sizeof(wecareregs) / sizeof(wecareregs[0]))]; wc->regoffset = wc->regoffset % (sizeof(wecareregs) / sizeof(wecareregs[0])); } if (debug) printk(KERN_DEBUG "New regoffset: %d\n", wc->regoffset); } /* Receive into the proper register */ wc->readregs[realreg] = realval; } /* Look for pegging to indicate ringing */ sample = (short)(le32_to_cpu(readchunk[(x << 1) + (1 - wc->alt)]) >> 16); if ((sample > 32000) && (wc->peg != 1)) { if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME)) wc->pegcount++; wc->pegtimer = 0; wc->peg = 1; } else if ((sample < -32000) && (wc->peg != -1)) { if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME)) wc->pegcount++; wc->pegtimer = 0; wc->peg = -1; } wc->chan->readchunk[x] = DAHDI_LIN2X((sample), (wc->chan)); } if (wc->pegtimer > PEGTIME) { /* Reset pegcount if our timer expires */ wc->pegcount = 0; } /* Decrement debouncer if appropriate */ if (wc->ringdebounce) wc->ringdebounce--; if (!wc->offhook && !wc->ringdebounce) { if (!wc->ring && (wc->pegcount > PEGCOUNT)) { /* It's ringing */ if (debug) printk(KERN_DEBUG "RING!\n"); dahdi_hooksig(wc->chan, DAHDI_RXSIG_RING); wc->ring = 1; } if (wc->ring && !wc->pegcount) { /* No more ring */ if (debug) printk(KERN_DEBUG "NO RING!\n"); dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); wc->ring = 0; } } if (wc->ignoreread) wc->ignoreread--; /* Do the echo cancellation... We are echo cancelling against what we sent two chunks ago*/ dahdi_ec_chunk(wc->chan, wc->chan->readchunk, wc->lasttx); /* Receive the result */ dahdi_receive(&wc->span); } #ifdef ENABLE_TASKLETS static void wcfxo_tasklet(unsigned long data) { struct wcfxo *wc = (struct wcfxo *)data; wc->taskletrun++; /* Run tasklet */ if (wc->taskletpending) { wc->taskletexec++; wcfxo_receiveprep(wc, wc->ints); wcfxo_transmitprep(wc, wc->ints); } wc->taskletpending = 0; } #endif static void wcfxo_stop_dma(struct wcfxo *wc); static void wcfxo_restart_dma(struct wcfxo *wc); DAHDI_IRQ_HANDLER(wcfxo_interrupt) { struct wcfxo *wc = dev_id; unsigned char ints; unsigned char b; #ifdef DEBUG_RING static int oldb = 0; static int oldcnt = 0; #endif ints = inb(wc->ioaddr + WC_INTSTAT); if (!ints) return IRQ_NONE; outb(ints, wc->ioaddr + WC_INTSTAT); if (ints & 0x0c) { /* if there is a rx interrupt pending */ #ifdef ENABLE_TASKLETS wc->ints = ints; if (!wc->taskletpending) { wc->taskletpending = 1; wc->taskletsched++; tasklet_hi_schedule(&wc->wcfxo_tlet); } else wc->txerrors++; #else wcfxo_receiveprep(wc, ints); /* transmitprep looks to see if there is anything to transmit and returns by itself if there is nothing */ wcfxo_transmitprep(wc, ints); #endif } if (ints & 0x10) { printk(KERN_INFO "FXO PCI Master abort\n"); /* Stop DMA andlet the watchdog start it again */ wcfxo_stop_dma(wc); return IRQ_RETVAL(1); } if (ints & 0x20) { printk(KERN_INFO "PCI Target abort\n"); return IRQ_RETVAL(1); } if (1 /* !(wc->report % 0xf) */) { /* Check for BATTERY from register and debounce for 8 ms */ b = wc->readregs[WC_DAA_LINE_STAT] & 0xf; if (!b) { wc->nobatttimer++; #if 0 if (wc->battery) printk(KERN_DEBUG "Battery loss: %d (%d debounce)\n", b, wc->battdebounce); #endif if (wc->battery && !wc->battdebounce) { if (debug) printk(KERN_DEBUG "NO BATTERY!\n"); wc->battery = 0; #ifdef JAPAN if ((!wc->ohdebounce) && wc->offhook) { dahdi_hooksig(wc->chan, DAHDI_RXSIG_ONHOOK); if (debug) printk(KERN_DEBUG "Signalled On Hook\n"); #ifdef ZERO_BATT_RING wc->onhook++; #endif } #else dahdi_hooksig(wc->chan, DAHDI_RXSIG_ONHOOK); #endif wc->battdebounce = BATT_DEBOUNCE; } else if (!wc->battery) wc->battdebounce = BATT_DEBOUNCE; if ((wc->nobatttimer > 5000) && #ifdef ZERO_BATT_RING !(wc->readregs[WC_DAA_DCTL1] & 0x04) && #endif (!wc->span.alarms)) { wc->span.alarms = DAHDI_ALARM_RED; dahdi_alarm_notify(&wc->span); } } else if (b == 0xf) { if (!wc->battery && !wc->battdebounce) { if (debug) printk(KERN_DEBUG "BATTERY!\n"); #ifdef ZERO_BATT_RING if (wc->onhook) { wc->onhook = 0; dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); if (debug) printk(KERN_DEBUG "Signalled Off Hook\n"); } #else dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); #endif wc->battery = 1; wc->nobatttimer = 0; wc->battdebounce = BATT_DEBOUNCE; if (wc->span.alarms) { wc->span.alarms = 0; dahdi_alarm_notify(&wc->span); } } else if (wc->battery) wc->battdebounce = BATT_DEBOUNCE; } else { /* It's something else... */ wc->battdebounce = BATT_DEBOUNCE; } if (wc->battdebounce) wc->battdebounce--; #ifdef JAPAN if (wc->ohdebounce) wc->ohdebounce--; #endif } return IRQ_RETVAL(1); } static int wcfxo_setreg(struct wcfxo *wc, unsigned char reg, unsigned char value) { int x; if (wc->wregcount < DAHDI_CHUNKSIZE) { x = wc->wregcount; wc->regs[x].reg = reg; wc->regs[x].value = value; wc->regs[x].flags = FLAG_WRITE; wc->wregcount++; return 0; } printk(KERN_NOTICE "wcfxo: Out of space to write register %02x with %02x\n", reg, value); return -1; } static inline struct wcfxo *wcfxo_from_span(struct dahdi_span *span) { return container_of(span, struct wcfxo, span); } static int wcfxo_open(struct dahdi_chan *chan) { struct wcfxo *wc = chan->pvt; if (wc->dead) return -ENODEV; wc->usecount++; return 0; } static int wcfxo_watchdog(struct dahdi_span *span, int event) { printk(KERN_INFO "FXO: Restarting DMA\n"); wcfxo_restart_dma(wcfxo_from_span(span)); return 0; } static int wcfxo_close(struct dahdi_chan *chan) { struct wcfxo *wc = chan->pvt; wc->usecount--; /* If we're dead, release us now */ if (!wc->usecount && wc->dead) wcfxo_release(wc); return 0; } static int wcfxo_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wcfxo *wc = chan->pvt; int reg=0; switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: /* Take off hook and enable normal mode reception. This must be done in two steps because of a hardware bug. */ reg = wc->readregs[WC_DAA_DCTL1] & ~0x08; wcfxo_setreg(wc, WC_DAA_DCTL1, reg); reg = reg | 0x1; wcfxo_setreg(wc, WC_DAA_DCTL1, reg); wc->offhook = 1; #ifdef JAPAN wc->battery = 1; wc->battdebounce = BATT_DEBOUNCE; wc->ohdebounce = OH_DEBOUNCE; #endif break; case DAHDI_TXSIG_ONHOOK: /* Put on hook and enable on hook line monitor */ reg = wc->readregs[WC_DAA_DCTL1] & 0xfe; wcfxo_setreg(wc, WC_DAA_DCTL1, reg); reg = reg | 0x08; wcfxo_setreg(wc, WC_DAA_DCTL1, reg); wc->offhook = 0; /* Don't accept a ring for another 1000 ms */ wc->ringdebounce = 1000; #ifdef JAPAN wc->ohdebounce = OH_DEBOUNCE; #endif break; default: printk(KERN_NOTICE "wcfxo: Can't set tx state to %d\n", txsig); } if (debug) printk(KERN_DEBUG "Setting hook state to %d (%02x)\n", txsig, reg); return 0; } static const struct dahdi_span_ops wcfxo_span_ops = { .owner = THIS_MODULE, .hooksig = wcfxo_hooksig, .open = wcfxo_open, .close = wcfxo_close, .watchdog = wcfxo_watchdog, }; static int wcfxo_initialize(struct wcfxo *wc) { /* DAHDI stuff */ sprintf(wc->span.name, "WCFXO/%d", wc->pos); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); sprintf(wc->chan->name, "WCFXO/%d/%d", wc->pos, 0); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); wc->span.manufacturer = "Digium"; strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); wc->chan->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF; wc->chan->chanpos = 1; wc->span.chans = &wc->chan; wc->span.channels = 1; wc->span.irq = wc->dev->irq; wc->span.flags = DAHDI_FLAG_RBS; wc->span.deflaw = DAHDI_LAW_MULAW; #ifdef ENABLE_TASKLETS tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc); #endif wc->chan->pvt = wc; wc->span.ops = &wcfxo_span_ops; if (dahdi_register(&wc->span, 0)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } return 0; } static int wcfxo_hardware_init(struct wcfxo *wc) { /* Hardware stuff */ /* Reset PCI Interface chip and registers */ outb(0x0e, wc->ioaddr + WC_CNTL); /* Set all to outputs except AUX 4, which is an input */ outb(0xef, wc->ioaddr + WC_AUXC); /* Reset the DAA (DAA uses AUX5 for reset) */ outb(0x00, wc->ioaddr + WC_AUXD); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1 + HZ / 800); /* Set hook state to on hook & un-reset the DAA */ if (wc->flags & FLAG_RESET_ON_AUX5) { /* Set hook state to on hook for when we switch. Make sure reset is high */ outb(0x34, wc->ioaddr + WC_AUXD); } else { /* Set hook state to on hook for when we switch */ outb(0x24, wc->ioaddr + WC_AUXD); } /* Back to normal, with automatic DMA wrap around */ outb(0x01, wc->ioaddr + WC_CNTL); /* Make sure serial port and DMA are out of reset */ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL); /* Configure serial port for MSB->LSB operation */ if (wc->flags & FLAG_DOUBLE_CLOCK) outb(0xc1, wc->ioaddr + WC_SERCTL); else outb(0xc0, wc->ioaddr + WC_SERCTL); if (wc->flags & FLAG_USE_XTAL) { /* Use the crystal oscillator */ outb(0x04, wc->ioaddr + WC_AUXFUNC); } /* Delay FSC by 2 so it's properly aligned */ outb(0x2, wc->ioaddr + WC_FSCDELAY); /* Setup DMA Addresses */ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ outl(wc->writedma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ outl(wc->writedma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMAWE); /* End */ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ outl(wc->readdma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ outl(wc->readdma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMARE); /* End */ /* Clear interrupts */ outb(0xff, wc->ioaddr + WC_INTSTAT); return 0; } static void wcfxo_enable_interrupts(struct wcfxo *wc) { /* Enable interrupts (we care about all of them) */ outb(0x3f, wc->ioaddr + WC_MASK0); /* No external interrupts */ outb(0x00, wc->ioaddr + WC_MASK1); } static void wcfxo_start_dma(struct wcfxo *wc) { /* Reset Master and TDM */ outb(0x0f, wc->ioaddr + WC_CNTL); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); outb(0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); } static void wcfxo_restart_dma(struct wcfxo *wc) { /* Reset Master and TDM */ outb(0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); } static void wcfxo_stop_dma(struct wcfxo *wc) { outb(0x00, wc->ioaddr + WC_OPER); } static void wcfxo_reset_tdm(struct wcfxo *wc) { /* Reset TDM */ outb(0x0f, wc->ioaddr + WC_CNTL); } static void wcfxo_disable_interrupts(struct wcfxo *wc) { outb(0x00, wc->ioaddr + WC_MASK0); outb(0x00, wc->ioaddr + WC_MASK1); } static void wcfxo_set_daa_mode(struct wcfxo *wc) { /* Set country specific parameters (OHS, ACT, DCT, RZ, RT, LIM, VOL) */ int reg16 = ((fxo_modes[opermode].ohs & 0x1) << 6) | ((fxo_modes[opermode].act & 0x1) << 5) | ((fxo_modes[opermode].dct & 0x3) << 2) | ((fxo_modes[opermode].rz & 0x1) << 1) | ((fxo_modes[opermode].rt & 0x1) << 0); int reg17 = ((fxo_modes[opermode].lim & 0x3) << 3); int reg18 = ((fxo_modes[opermode].vol & 0x3) << 3); if (wc->flags & FLAG_NO_I18N_REGS) { wcfxo_dbg(wc->span, "This card does not support international settings.\n"); return; } wcfxo_setreg(wc, WC_DAA_INT_CTL1, reg16); wcfxo_setreg(wc, WC_DAA_INT_CTL2, reg17); wcfxo_setreg(wc, WC_DAA_INT_CTL3, reg18); /* Wait a couple of jiffies for our writes to finish */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); printk(KERN_INFO "wcfxo: DAA mode is '%s'\n", fxo_modes[opermode].name); } static int wcfxo_init_daa(struct wcfxo *wc) { /* This must not be called in an interrupt */ /* We let things settle for a bit */ unsigned char reg15; int chip_revb; // set_current_state(TASK_INTERRUPTIBLE); // schedule_timeout(10); /* Soft-reset it */ wcfxo_setreg(wc, WC_DAA_CTL1, 0x80); /* Let the reset go */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); /* We have a clock at 18.432 Mhz, so N1=1, M1=2, CGM=0 */ wcfxo_setreg(wc, WC_DAA_PLL1_N1, 0x0); /* This value is N1 - 1 */ wcfxo_setreg(wc, WC_DAA_PLL1_M1, 0x1); /* This value is M1 - 1 */ /* We want to sample at 8khz, so N2 = 9, M2 = 10 (N2-1, M2-1) */ wcfxo_setreg(wc, WC_DAA_PLL2_N2_M2, 0x89); /* Wait until the PLL's are locked. Time is between 100 uSec and 1 mSec */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1 + HZ/1000 + (DAHDI_CHUNKSIZE * HZ) / 800); /* No additional ration is applied to the PLL and faster lock times * are possible */ wcfxo_setreg(wc, WC_DAA_PLL_CTL, 0x0); /* Enable off hook pin */ wcfxo_setreg(wc, WC_DAA_DCTL1, 0x0a); if (monitor) { /* Enable ISOcap and external speaker and charge pump if present */ wcfxo_setreg(wc, WC_DAA_DCTL2, 0x80); } else { /* Enable ISOcap and charge pump if present (leave speaker disabled) */ wcfxo_setreg(wc, WC_DAA_DCTL2, 0xe0); } /* Wait a couple of jiffies for our writes to finish */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); reg15 = 0x0; /* Go ahead and attenuate transmit signal by 6 db */ if (quiet) { printk(KERN_INFO "wcfxo: Attenuating transmit signal for quiet operation\n"); reg15 |= (quiet & 0x3) << 4; } if (boost) { printk(KERN_INFO "wcfxo: Boosting receive signal\n"); reg15 |= (boost & 0x3); } wcfxo_setreg(wc, WC_DAA_TXRX_GCTL, reg15); /* REVB: reg. 13, bits 5:2 */ chip_revb = (wc->readregs[WC_DAA_CHIPB_REV] >> 2) & 0xF; wcfxo_dbg(wc->span, "DAA chip REVB is %x\n", chip_revb); switch(chip_revb) { case 1: case 2: case 3: /* This is a si3034. Nothing to do */ break; case 4: case 5: case 7: /* This is 3035. Has no support for international registers */ wc->flags |= FLAG_NO_I18N_REGS; break; default: wcfxo_notice(wc->span, "Unknown DAA chip revision: REVB=%d\n", chip_revb); } /* Didn't get it right. Register 9 is still garbage */ if (wc->readregs[WC_DAA_PLL2_N2_M2] != 0x89) return -1; #if 0 { int x; int y; for (y=0;y<100;y++) { printk(KERN_DEBUG " reg dump ====== %d ======\n", y); for (x=0;xreadregs[wecareregs[x]]); } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100); } } #endif return 0; } static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct wcfxo *wc; struct wcfxo_desc *d = (struct wcfxo_desc *)ent->driver_data; int x; for (x=0;x= WC_MAX_IFACES) { printk(KERN_ERR "Too many interfaces: Found %d, can only handle %d.\n", x, WC_MAX_IFACES - 1); return -EIO; } if (pci_enable_device(pdev)) return -EIO; wc = kmalloc(sizeof(struct wcfxo), GFP_KERNEL); if (!wc) { printk(KERN_ERR "wcfxo: Failed initializinf card. Not enough memory."); return -ENOMEM; } ifaces[x] = wc; memset(wc, 0, sizeof(struct wcfxo)); wc->chan = &wc->_chan; wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->pos = x; wc->variety = d->name; wc->flags = d->flags; /* Keep track of whether we need to free the region */ if (request_region(wc->ioaddr, 0xff, "wcfxo")) wc->freeregion = 1; /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses 32 bits. Allocate an extra set just for control too */ wc->writechunk = (int *)pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma); if (!wc->writechunk) { printk(KERN_NOTICE "wcfxo: Unable to allocate DMA-able memory\n"); if (wc->freeregion) release_region(wc->ioaddr, 0xff); return -ENOMEM; } wc->readchunk = wc->writechunk + DAHDI_MAX_CHUNKSIZE * 4; /* in doublewords */ wc->readdma = wc->writedma + DAHDI_MAX_CHUNKSIZE * 16; /* in bytes */ if (wcfxo_initialize(wc)) { printk(KERN_NOTICE "wcfxo: Unable to intialize modem\n"); if (wc->freeregion) release_region(wc->ioaddr, 0xff); kfree(wc); return -EIO; } /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, wcfxo_interrupt, DAHDI_IRQ_SHARED, "wcfxo", wc)) { printk(KERN_NOTICE "wcfxo: Unable to request IRQ %d\n", pdev->irq); if (wc->freeregion) release_region(wc->ioaddr, 0xff); kfree(wc); return -EIO; } wcfxo_hardware_init(wc); /* Enable interrupts */ wcfxo_enable_interrupts(wc); /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4); /* Start DMA */ wcfxo_start_dma(wc); /* Initialize DAA (after it's started) */ if (wcfxo_init_daa(wc)) { printk(KERN_NOTICE "Failed to initailize DAA, giving up...\n"); wcfxo_stop_dma(wc); wcfxo_disable_interrupts(wc); dahdi_unregister(&wc->span); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(0x0e, wc->ioaddr + WC_CNTL); if (wc->freeregion) release_region(wc->ioaddr, 0xff); kfree(wc); return -EIO; } wcfxo_set_daa_mode(wc); printk(KERN_INFO "Found a Wildcard FXO: %s\n", wc->variety); return 0; } static void wcfxo_release(struct wcfxo *wc) { dahdi_unregister(&wc->span); if (wc->freeregion) release_region(wc->ioaddr, 0xff); kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } static void __devexit wcfxo_remove_one(struct pci_dev *pdev) { struct wcfxo *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ wcfxo_stop_dma(wc); wcfxo_reset_tdm(wc); /* In case hardware is still there */ wcfxo_disable_interrupts(wc); /* Immediately free resources */ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(0x0e, wc->ioaddr + WC_CNTL); /* Release span, possibly delayed */ if (!wc->usecount) wcfxo_release(wc); else wc->dead = 1; } } static DEFINE_PCI_DEVICE_TABLE(wcfxo_pci_tbl) = { { 0xe159, 0x0001, 0x8084, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, { 0xe159, 0x0001, 0x8085, PCI_ANY_ID, 0, 0, (unsigned long) &wcx101p }, { 0xe159, 0x0001, 0x8086, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, { 0xe159, 0x0001, 0x8087, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, { 0x1057, 0x5608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcx100p }, { 0 } }; MODULE_DEVICE_TABLE (pci, wcfxo_pci_tbl); static struct pci_driver wcfxo_driver = { .name = "wcfxo", .probe = wcfxo_init_one, .remove = __devexit_p(wcfxo_remove_one), .id_table = wcfxo_pci_tbl, }; static int __init wcfxo_init(void) { int res; int x; if ((opermode >= sizeof(fxo_modes) / sizeof(fxo_modes[0])) || (opermode < 0)) { printk(KERN_NOTICE "Invalid/unknown operating mode specified. Please choose one of:\n"); for (x=0;x"); MODULE_LICENSE("GPL v2"); module_init(wcfxo_init); module_exit(wcfxo_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_oslec.c0000644000175000017500000001112311500234716022615 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface to the Open Source Line Echo Canceller (OSLEC) * * Written by Tzafrir Cohen * Copyright (C) 2008 Xorcom, Inc. * * All rights reserved. * * Based on dahdi_echocan_hpec.c, Copyright (C) 2006-2008 Digium, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include /* Fix this if OSLEC is elsewhere */ #include "../staging/echo/oslec.h" //#include #include #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); #ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX static void echo_can_hpf_tx(struct dahdi_echocan_state *ec, short *tx, u32 size); #endif static const char *name = "OSLEC"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, #ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX .echocan_process_tx = echo_can_hpf_tx, #endif }; struct ec_pvt { struct oslec_state *oslec; struct dahdi_echocan_state dahdi; }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); oslec_free(pvt->oslec); kfree(pvt); } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 SampleNum; for (SampleNum = 0; SampleNum < size; SampleNum++, iref++) { short iCleanSample; iCleanSample = oslec_update(pvt->oslec, *iref, *isig); *isig++ = iCleanSample; } } static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct ec_pvt *pvt; if (ecp->param_count > 0) { printk(KERN_WARNING "OSLEC does not support parameters; failing request\n"); return -EINVAL; } pvt = kzalloc(sizeof(*pvt), GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; pvt->oslec = oslec_create(ecp->tap_length, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CLIP | ECHO_CAN_USE_TX_HPF | ECHO_CAN_USE_RX_HPF); if (!pvt->oslec) { kfree(pvt); *ec = NULL; return -ENOTTY; } else { *ec = &pvt->dahdi; return 0; } } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { return 1; } #ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX static void echo_can_hpf_tx(struct dahdi_echocan_state *ec, short *tx, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 SampleNum; for (SampleNum = 0; SampleNum < size; SampleNum++, tx++) { short iCleanSample; iCleanSample = oslec_hpf_tx(pvt->oslec, *tx); *tx = iCleanSample; } } #endif static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_INFO, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } MODULE_DESCRIPTION("DAHDI OSLEC wrapper"); MODULE_AUTHOR("Tzafrir Cohen "); MODULE_LICENSE("GPL"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/makefw.c0000644000175000017500000000345011046411244020153 0ustar tzafrirtzafrir/* Xilinx firmware convertor program. * * Written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2008 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #define SWATH 12 int main(int argc, char *argv[]) { FILE *fp; int i,j,nbytes; unsigned char c; char buf[300]; if (argc < 3) { puts("Usage... makefw filename.rbt array_name"); exit(1); } fp = fopen(argv[1],"r"); if (!fp) { perror("bit file open"); exit(1); } nbytes = 0; printf("static unsigned char %s[] = {\n",argv[2]); i = 0; while(fgets(buf,sizeof(buf) - 1,fp)) { if (!buf[0]) continue; if (buf[strlen(buf) - 1] < ' ') buf[strlen(buf) - 1] = 0; if (!buf[0]) continue; if (buf[strlen(buf) - 1] < ' ') buf[strlen(buf) - 1] = 0; if (!buf[0]) continue; if (strlen(buf) < 32) continue; if ((buf[0] != '0') && (buf[0] != '1')) continue; c = 0; for(j = 0; buf[j]; j++) { if (buf[j] > '0') c |= 1 << (j & 7); if ((j & 7) == 7) { nbytes++; if (i) printf(","); printf("0x%02x",c); if (i++ == SWATH) { printf(",\n"); i = 0; } c = 0; } } } printf("\n};\n\n"); fprintf(stderr,"Loaded %d bytes from file\n",nbytes); fclose(fp); exit(0); } dahdi-linux-2.5.0.1/drivers/dahdi/vpmadt032_loader/0000755000175000017500000000000011631523354021607 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c0000644000175000017500000000752011510361534026152 0ustar tzafrirtzafrir/* * DAHDI Telephony Interface to VPMADT032 Firmware Loader * * Copyright (C) 2008-2011 Digium, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include static int debug; #include "voicebus/voicebus.h" #include "voicebus/vpmadtreg.h" #include "vpmadt032_loader.h" vpmlinkage static int __attribute__((format (printf, 1, 2))) logger(const char *format, ...) { int res; va_list args; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) va_start(args, format); res = vprintk(format, args); va_end(args); #else char buf[256]; va_start(args, format); res = vsnprintf(buf, sizeof(buf), format, args); va_end(args); printk(KERN_INFO "%s" buf); #endif return res; } vpmlinkage static void *memalloc(size_t len) { return kmalloc(len, GFP_KERNEL); } vpmlinkage static void memfree(void *ptr) { kfree(ptr); } struct private_context { struct voicebus *vb; void *pvt; struct completion done; struct voicebus_operations ops; }; static void handle_receive(struct voicebus *vb, struct list_head *buffers) { struct vbb *vbb; struct private_context *ctx = container_of(vb->ops, struct private_context, ops); list_for_each_entry(vbb, buffers, entry) { __vpmadt032_receive(ctx->pvt, vbb->data); if (__vpmadt032_done(ctx->pvt)) complete(&ctx->done); } } static void handle_transmit(struct voicebus *vb, struct list_head *buffers) { struct vbb *vbb; struct private_context *ctx = container_of(vb->ops, struct private_context, ops); list_for_each_entry(vbb, buffers, entry) __vpmadt032_transmit(ctx->pvt, vbb->data); } static void init_private_context(struct private_context *ctx) { init_completion(&ctx->done); ctx->ops.handle_receive = handle_receive; ctx->ops.handle_transmit = handle_transmit; } static int vpmadt032_load_firmware(struct voicebus *vb) { int ret = 0; struct private_context *ctx; const struct voicebus_operations *old; int id; might_sleep(); ctx = kzalloc(sizeof(struct private_context), GFP_KERNEL); if (!ctx) return -ENOMEM; init_private_context(ctx); ctx->vb = vb; if (0x8007 == vb->pdev->device || 0x8008 == vb->pdev->device) id = vb->pdev->vendor << 16 | 0x2400; else id = vb->pdev->vendor << 16 | vb->pdev->device; ret = __vpmadt032_start_load(0, id, &ctx->pvt); if (ret) goto error_exit; old = vb->ops; vb->ops = &ctx->ops; if (!wait_for_completion_timeout(&ctx->done, HZ*20)) ret = -EIO; vb->ops = old; __vpmadt032_cleanup(ctx->pvt); error_exit: kfree(ctx); return ret; } static struct vpmadt_loader loader = { .owner = THIS_MODULE, .load = vpmadt032_load_firmware, }; static int __init vpmadt032_loader_init(void) { __vpmadt032_init(logger, debug, memalloc, memfree); vpmadtreg_register(&loader); return 0; } static void __exit vpmadt032_loader_exit(void) { vpmadtreg_unregister(&loader); return; } module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI VPMADT032 (Hardware Echo Canceller) Firmware Loader"); MODULE_AUTHOR("Digium Incorporated "); MODULE_LICENSE("Digium Commercial"); module_init(vpmadt032_loader_init); module_exit(vpmadt032_loader_exit); dahdi-linux-2.5.0.1/drivers/dahdi/firmware/0000755000175000017500000000000011631523356020357 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/firmware/make_firmware_object.in0000644000175000017500000000035711026033022025033 0ustar tzafrirtzafrir#!/bin/sh -e # make an object file from a raw binary firmware file # arguments: # 1 - firmware file # 2 - output file objcopy -I binary ${1} -B BFDARCH -O BFDNAME ${2} --rename-section .data=.rodata,alloc,load,data,contents,readonly dahdi-linux-2.5.0.1/drivers/dahdi/firmware/Makefile0000644000175000017500000002302511627250314022015 0ustar tzafrirtzafrir# # DAHDI # # Makefile for firmware downloading/installation # # Copyright (C) 2007-2010, Digium, Inc. # # Joshua Colp # # # See http://www.asterisk.org for more information about # the Asterisk project. Please do not directly contact # any of the maintainers of this project for assistance; # the project provides a web site, mailing lists and IRC # channels for your use. # # This program is free software, distributed under the terms of # the GNU General Public License Version 2 as published by the # Free Software Foundation. See the LICENSE file included with # this program for more details. # .PHONY: dist-clean clean all uninstall have_download install object-build hotplug-install hotplug-dirs hotplug-uninstall make_firmware_object firmware-loaders OCT6114_064_VERSION:=1.05.01 OCT6114_128_VERSION:=1.05.01 TC400M_VERSION:=MR6.12 VPMADT032_VERSION:=1.25.0 HX8_VERSION:=2.06 VPMOCT032_VERSION:=1.11.0 FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases ALL_FIRMWARE=FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 # Firmware files should use the naming convention: dahdi-fw--- or dahdi-fw-- # First example: dahdi-fw-oct6114-064-1.05.01 # This means this is version 1.05.01 of the oct6114-064 firmware # Second example: dahdi-fw-tc400m-MR5.6 # This means this is version MR5.6 of the tc400m firmware # Build a list of firmware package filenames we need FIRMWARE:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-064=dahdi-fw-oct6114-064-$(OCT6114_064_VERSION).tar.gz) FIRMWARE:=$(FIRMWARE:FIRMWARE-OCT6114-128=dahdi-fw-oct6114-128-$(OCT6114_128_VERSION).tar.gz) FIRMWARE:=$(FIRMWARE:FIRMWARE-TC400M=dahdi-fw-tc400m-$(TC400M_VERSION).tar.gz) FIRMWARE:=$(FIRMWARE:FIRMWARE-HX8=dahdi-fw-hx8-$(HX8_VERSION).tar.gz) FIRMWARE:=$(FIRMWARE:FIRMWARE-VPMOCT032=dahdi-fw-vpmoct032-$(VPMOCT032_VERSION).tar.gz) FWLOADERS:=dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz # Build a list of object files if hotplug will not be used OBJECT_FILES:=$(ALL_FIRMWARE:FIRMWARE-OCT6114-064=dahdi-fw-oct6114-064.o) OBJECT_FILES:=$(OBJECT_FILES:FIRMWARE-OCT6114-128=dahdi-fw-oct6114-128.o) OBJECT_FILES:=$(OBJECT_FILES:FIRMWARE-TC400M=dahdi-fw-tc400m.o) OBJECT_FILES:=$(OBJECT_FILES:FIRMWARE-HX8=dahdi-fw-hx8.o) # Force usage of wget, for now DOWNLOAD=wget WGET=wget # If "fetch" is used, --continue is not a valid option. ifeq ($(WGET),wget) WGET_ARGS:=--continue endif all: $(FIRMWARE) # Clean up any downloaded/extracted firmware packages dist-clean: clean rm -f dahdi-fw-*.bin rm -f dahdi-fw-*.tar.gz rm -f dahdi-fwload-*.tar.gz rm -f make_firmware_object # Clean up anything we built clean: rm -f dahdi-fw-*.o # Download and extract firmware tarballs dahdi-fw-%.tar.gz: @if ( [ "$(HOTPLUG_FIRMWARE)" = "no" ] ) || ( [ -d $(DESTDIR)/usr/lib/hotplug/firmware ] && ! [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.$(subst .tar.gz,,$*) ] ) || ( [ -d $(DESTDIR)/lib/firmware ] && ! [ -f $(DESTDIR)/lib/firmware/.$(subst .tar.gz,,$*) ] ); then \ echo "Attempting to download $@"; \ if test ! -f $@; then $(DOWNLOAD) $(WGET_ARGS) $(FIRMWARE_URL)/$@; fi; \ if test ! -f $@; then exit 1; fi; \ (cat $@ | gzip -d | tar --no-same-owner -xf -) \ fi firmware-loaders: $(FWLOADERS) .PHONY: dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz: @if test ! -f $@; then echo "Attempting to download $@"; $(DOWNLOAD) $(WGET_ARGS) $(FIRMWARE_URL)/$@; fi; \ if test ! -f $@; then exit 1; fi; \ (cd ../../..; cat drivers/dahdi/firmware/$@ | gzip -d | tar --no-same-owner -xf -) # Create object files suitable for linking against object-build: $(FIRMWARE) $(OBJECT_FILES) $(DESTDIR)/usr/lib/hotplug/firmware $(DESTDIR)/lib/firmware: mkdir -p $@ # Install all downloaded firmware images for hotplug usage hotplug-install: $(DESTDIR)/usr/lib/hotplug/firmware $(DESTDIR)/lib/firmware $(FIRMWARE) ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes) @echo "Installing dahdi-fw-oct6114-064.bin to hotplug firmware directories" @install -m 644 dahdi-fw-oct6114-064.bin $(DESTDIR)/usr/lib/hotplug/firmware @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-064-* @touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) @install -m 644 dahdi-fw-oct6114-064.bin $(DESTDIR)/lib/firmware @rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-064-* @touch $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-064-$(OCT6114_064_VERSION) else @echo "Firmware dahdi-fw-oct6114-064.bin is already installed with required version $(OCT6114_064_VERSION)" endif ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-128-$(OCT6114_128_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-128-$(OCT6114_128_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes) @echo "Installing dahdi-fw-oct6114-128.bin to hotplug firmware directories" @install -m 644 dahdi-fw-oct6114-128.bin $(DESTDIR)/usr/lib/hotplug/firmware @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-128-* @touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-oct6114-128-$(OCT6114_128_VERSION) @install -m 644 dahdi-fw-oct6114-128.bin $(DESTDIR)/lib/firmware @rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-128-* @touch $(DESTDIR)/lib/firmware/.dahdi-fw-oct6114-128-$(OCT6114_128_VERSION) else @echo "Firmware dahdi-fw-oct6114-128.bin is already installed with required version $(OCT6114_128_VERSION)" endif ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-tc400m-$(TC400M_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-tc400m-$(TC400M_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes) @echo "Installing dahdi-fw-tc400m.bin to hotplug firmware directories" @install -m 644 dahdi-fw-tc400m.bin $(DESTDIR)/usr/lib/hotplug/firmware @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-tc400m-* @touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-tc400m-$(TC400M_VERSION) @install -m 644 dahdi-fw-tc400m.bin $(DESTDIR)/lib/firmware @rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-tc400m-* @touch $(DESTDIR)/lib/firmware/.dahdi-fw-tc400m-$(TC400M_VERSION) else @echo "Firmware dahdi-fw-tc400m.bin is already installed with required version $(TC400M_VERSION)" endif ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-hx8-$(HX8_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-hx8-$(HX8_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes) @echo "Installing dahdi-fw-hx8.bin to hotplug firmware directories" @install -m 644 dahdi-fw-hx8.bin $(DESTDIR)/usr/lib/hotplug/firmware @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-hx8-* @touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-hx8-$(HX8_VERSION) @install -m 644 dahdi-fw-hx8.bin $(DESTDIR)/lib/firmware @rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-hx8-* @touch $(DESTDIR)/lib/firmware/.dahdi-fw-hx8-$(HX8_VERSION) else @echo "Firmware dahdi-fw-hx8.bin is already installed with required version $(HX8_VERSION)" endif ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-vpmoct032-$(VPMOCT032_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-vpmoct032-$(VPMOCT032_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes) @echo "Installing dahdi-fw-vpmoct032.bin to hotplug firmware directories" @install -m 644 dahdi-fw-vpmoct032.bin $(DESTDIR)/usr/lib/hotplug/firmware @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-vpmoct032-* @touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-vpmoct032-$(VPMOCT032_VERSION) @install -m 644 dahdi-fw-vpmoct032.bin $(DESTDIR)/lib/firmware @rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-vpmoct032-* @touch $(DESTDIR)/lib/firmware/.dahdi-fw-vpmoct032-$(VPMOCT032_VERSION) else @echo "Firmware dahdi-fw-vpmoct032.bin is already installed with required version $(VPMOCT032_VERSION)" endif # Uninstall any installed dahdi firmware images from hotplug firmware directories hotplug-uninstall: if [ -d $(DESTDIR)/usr/lib/hotplug/firmware ]; then \ rm -f $(DESTDIR)/usr/lib/hotplug/firmware/dahdi-fw-*.bin; \ rm -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw*; \ fi if [ -d $(DESTDIR)/lib/firmware ]; then \ rm -f $(DESTDIR)/lib/firmware/dahdi-fw-*.bin; \ rm -f $(DESTDIR)/lib/firmware/.dahdi-fw*; \ fi make_firmware_object: make_firmware_object.in ../dahdi-base.o @export BFDNAME=`LANG=C objdump -f ../dahdi-base.o | grep -e "dahdi-base.o:" | sed "s/.*file format \(.*\)/\1/"`; \ export BFDARCH=`LANG=C objdump -f ../dahdi-base.o | grep -e "architecture:" | sed "s/.*ture: \(.*\),.*/\1/"`; \ sed -e s/BFDNAME/$${BFDNAME}/ -e s/BFDARCH/$${BFDARCH}/ $< > $@ @chmod +x $@ # Build object file of an oct6114 064 firmware image for linking dahdi-fw-oct6114-064.o: dahdi-fw-oct6114-064-$(OCT6114_064_VERSION).tar.gz dahdi-fw-oct6114-064.bin make_firmware_object @echo Making firmware object file for dahdi-fw-oct6114-064.bin ./make_firmware_object dahdi-fw-oct6114-064.bin $@ # Build object file of an oct6114 128 firmware image for linking dahdi-fw-oct6114-128.o: dahdi-fw-oct6114-128-$(OCT6114_128_VERSION).tar.gz dahdi-fw-oct6114-128.bin make_firmware_object @echo Making firmware object file for dahdi-fw-oct6114-128.bin ./make_firmware_object dahdi-fw-oct6114-128.bin $@ # Build object file of a TC400M firmware image for linking dahdi-fw-tc400m.o: dahdi-fw-tc400m-$(TC400M_VERSION).tar.gz dahdi-fw-tc400m.bin make_firmware_object @echo Making firmware object file for dahdi-fw-tc400m.bin ./make_firmware_object dahdi-fw-tc400m.bin $@ dahdi-linux-2.5.0.1/drivers/dahdi/Makefile0000644000175000017500000000026011026016414020167 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild endif dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/0000755000175000017500000000000011631523355020566 5ustar tzafrirtzafrirdahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/xhfc.h0000644000175000017500000000310611571766203021673 0ustar tzafrirtzafrir/* * B400M Quad-BRI module Driver * Written by Andrew Kohlsmith * * Copyright (C) 2010 Digium, Inc. * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _B4XXM_H_ #define _B4XXM_H_ extern int bri_debug; extern int bri_spanfilter; extern int bri_teignorered; extern int bri_alarmdebounce; extern int bri_persistentlayer1; extern int timingcable; struct b400m; /* probes the given card to see if it's a B400M */ int wctdm_init_b400m(struct wctdm *wc, int card); void wctdm_bri_checkisr(struct wctdm *wc, struct wctdm_module *const mod, int offset); void wctdm_unload_b400m(struct wctdm *wc, int card); void wctdm_hdlc_hard_xmit(struct dahdi_chan *chan); int b400m_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc); int b400m_dchan(struct dahdi_span *span); int b400m_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype); void b400m_post_init(struct b400m *b4); void b400m_set_dahdi_span(struct b400m *b4, int spanno, struct wctdm_span *wspan); void b400m_module_init(void); void b400m_module_cleanup(void); #endif /* _B4XX_H_ */ dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/base.c0000644000175000017500000047366611623564577021706 0ustar tzafrirtzafrir/* * Wildcard TDM2400P TDM FXS/FXO Interface Driver for DAHDI Telephony interface * * Written by Mark Spencer * Support for TDM800P and VPM150M by Matthew Fredrickson * * Support for Hx8 by Andrew Kohlsmith and Matthew * Fredrickson * * Copyright (C) 2005 - 2011 Digium, Inc. * All rights reserved. * * Sections for QRV cards written by Jim Dixon * Copyright (C) 2006, Jim Dixon and QRV Communications * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ /* For QRV DRI cards, gain is signed short, expressed in hundredths of db (in reference to 1v Peak @ 1000Hz) , as follows: Rx Gain: -11.99 to 15.52 db Tx Gain - No Pre-Emphasis: -35.99 to 12.00 db Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db */ #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #include #else #include #endif #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) /* Define this if you would like to load the modules in parallel. While this * can speed up loads when multiple cards handled by this driver are installed, * it also makes it impossible to abort module loads with ctrl-c */ #undef USE_ASYNC_INIT #include #else #undef USE_ASYNC_INIT #endif #include #include #include "proslic.h" #include "wctdm24xxp.h" #include "xhfc.h" #include "adt_lec.h" #include "voicebus/GpakCust.h" #include "voicebus/GpakApi.h" #if VOICEBUS_SFRAME_SIZE != SFRAME_SIZE #error SFRAME_SIZE must match the VOICEBUS_SFRAME_SIZE #endif /* Experimental max loop current limit for the proslic Loop current limit is from 20 mA to 41 mA in steps of 3 (according to datasheet) So set the value below to: 0x00 : 20mA (default) 0x01 : 23mA 0x02 : 26mA 0x03 : 29mA 0x04 : 32mA 0x05 : 35mA 0x06 : 37mA 0x07 : 41mA */ static int loopcurrent = 20; /* Following define is a logical exclusive OR to determine if the polarity of an fxs line is to be reversed. * The items taken into account are: * overall polarity reversal for the module, * polarity reversal for the port, * and the state of the line reversal MWI indicator */ #define POLARITY_XOR(fxs) \ ((reversepolarity != 0) ^ ((fxs)->reversepolarity != 0) ^ \ ((fxs)->vmwi_linereverse != 0)) static int reversepolarity = 0; static alpha indirect_regs[] = { {0,255,"DTMF_ROW_0_PEAK",0x55C2}, {1,255,"DTMF_ROW_1_PEAK",0x51E6}, {2,255,"DTMF_ROW2_PEAK",0x4B85}, {3,255,"DTMF_ROW3_PEAK",0x4937}, {4,255,"DTMF_COL1_PEAK",0x3333}, {5,255,"DTMF_FWD_TWIST",0x0202}, {6,255,"DTMF_RVS_TWIST",0x0202}, {7,255,"DTMF_ROW_RATIO_TRES",0x0198}, {8,255,"DTMF_COL_RATIO_TRES",0x0198}, {9,255,"DTMF_ROW_2ND_ARM",0x0611}, {10,255,"DTMF_COL_2ND_ARM",0x0202}, {11,255,"DTMF_PWR_MIN_TRES",0x00E5}, {12,255,"DTMF_OT_LIM_TRES",0x0A1C}, {13,0,"OSC1_COEF",0x7B30}, {14,1,"OSC1X",0x0063}, {15,2,"OSC1Y",0x0000}, {16,3,"OSC2_COEF",0x7870}, {17,4,"OSC2X",0x007D}, {18,5,"OSC2Y",0x0000}, {19,6,"RING_V_OFF",0x0000}, {20,7,"RING_OSC",0x7EF0}, {21,8,"RING_X",0x0160}, {22,9,"RING_Y",0x0000}, {23,255,"PULSE_ENVEL",0x2000}, {24,255,"PULSE_X",0x2000}, {25,255,"PULSE_Y",0x0000}, //{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower {26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower {27,14,"XMIT_DIGITAL_GAIN",0x4000}, //{27,14,"XMIT_DIGITAL_GAIN",0x2000}, {28,15,"LOOP_CLOSE_TRES",0x1000}, {29,16,"RING_TRIP_TRES",0x3600}, {30,17,"COMMON_MIN_TRES",0x1000}, {31,18,"COMMON_MAX_TRES",0x0200}, {32,19,"PWR_ALARM_Q1Q2",0x07C0}, {33,20,"PWR_ALARM_Q3Q4", 0x4C00 /* 0x2600 */}, {34,21,"PWR_ALARM_Q5Q6",0x1B80}, {35,22,"LOOP_CLOSURE_FILTER",0x8000}, {36,23,"RING_TRIP_FILTER",0x0320}, {37,24,"TERM_LP_POLE_Q1Q2",0x008C}, {38,25,"TERM_LP_POLE_Q3Q4",0x0100}, {39,26,"TERM_LP_POLE_Q5Q6",0x0010}, {40,27,"CM_BIAS_RINGING",0x0C00}, {41,64,"DCDC_MIN_V",0x0C00}, {42,255,"DCDC_XTRA",0x1000}, {43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, }; /* names of HWEC modules */ static const char *vpmadt032_name = "VPMADT032"; static const char *vpmoct_name = "VPMOCT032"; /* Undefine to enable Power alarm / Transistor debug -- note: do not enable for normal operation! */ /* #define PAQ_DEBUG */ #define DEBUG_CARD (1 << 0) #define DEBUG_ECHOCAN (1 << 1) #include "fxo_modes.h" struct wctdm_desc { const char *name; const int flags; const int ports; }; static const struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 }; static const struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 }; static const struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 }; static const struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 }; static const struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 }; static const struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 }; static const struct wctdm_desc wcha80000 = { "HA8-0000", 0, 8 }; static const struct wctdm_desc wchb80000 = { "HB8-0000", FLAG_EXPRESS, 8 }; /** * Returns true if the card is one of the Hybrid Digital Analog Cards. */ static inline bool is_hx8(const struct wctdm *wc) { return (&wcha80000 == wc->desc) || (&wchb80000 == wc->desc); } static inline struct dahdi_chan * get_dahdi_chan(const struct wctdm *wc, struct wctdm_module *const mod) { return wc->aspan->span.chans[mod->card]; } static inline void mod_hooksig(struct wctdm *wc, struct wctdm_module *mod, enum dahdi_rxsig rxsig) { dahdi_hooksig(get_dahdi_chan(wc, mod), rxsig); } struct wctdm *ifaces[WC_MAX_IFACES]; DEFINE_SEMAPHORE(ifacelock); static void wctdm_release(struct wctdm *wc); static int fxovoltage = 0; static unsigned int battdebounce; static unsigned int battalarm; static unsigned int battthresh; static int debug = 0; #ifdef DEBUG static int robust = 0; static int digitalloopback; #endif static int lowpower = 0; static int boostringer = 0; static int fastringer = 0; static int _opermode = 0; static char *opermode = "FCC"; static int fxshonormode = 0; static int alawoverride = 0; static char *companding = "auto"; static int fastpickup = -1; /* -1 auto, 0 no, 1 yes */ static int fxotxgain = 0; static int fxorxgain = 0; static int fxstxgain = 0; static int fxsrxgain = 0; static int nativebridge = 0; static int ringdebounce = DEFAULT_RING_DEBOUNCE; static int fwringdetect = 0; static int latency = VOICEBUS_DEFAULT_LATENCY; static unsigned int max_latency = VOICEBUS_DEFAULT_MAXLATENCY; static int forceload; #define MS_PER_HOOKCHECK (1) #define NEONMWI_ON_DEBOUNCE (100/MS_PER_HOOKCHECK) static int neonmwi_monitor = 0; /* Note: this causes use of full wave ring detect */ static int neonmwi_level = 75; /* neon mwi trip voltage */ static int neonmwi_envelope = 10; static int neonmwi_offlimit = 16000; /* Time in milliseconds the monitor is checked before saying no message is waiting */ static int neonmwi_offlimit_cycles; /* Time in milliseconds the monitor is checked before saying no message is waiting */ static int vpmsupport = 1; static int vpmnlptype = DEFAULT_NLPTYPE; static int vpmnlpthresh = DEFAULT_NLPTHRESH; static int vpmnlpmaxsupp = DEFAULT_NLPMAXSUPP; static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static const struct dahdi_echocan_features vpm_ec_features = { .NLP_automatic = 1, .CED_tx_detect = 1, .CED_rx_detect = 1, }; static const struct dahdi_echocan_ops vpm_ec_ops = { .echocan_free = echocan_free, }; static int wctdm_init_proslic(struct wctdm *wc, struct wctdm_module *const mod, int fast, int manual, int sane); static void set_offsets(struct wctdm_module *const mod, int altcs) { int card = mod->card; int bit; mod->subaddr = (altcs) ? 0 : (mod->card & 0x3); for (bit = 0; bit < ARRAY_SIZE(mod->offsets); ++bit) { /* Let's add some trickery to make the TDM410 work */ if (altcs == 3) { if (card == 2) { card = 4; altcs = 0; } else if (card == 3) { card = 5; altcs = 2; } } mod->offsets[bit] = ((((card & 0x3) * 3 + bit) * 7) + (card >> 2) + altcs + ((altcs) ? -21 : 0)); } } static inline __attribute_const__ int CMD_BYTE(const struct wctdm_module *const mod, const int bit) { return mod->offsets[bit]; } static inline __attribute_const__ int VPM_CMD_BYTE(int timeslot, int bit) { return ((((timeslot) & 0x3) * 3 + (bit)) * 7) + ((timeslot) >> 2); } static void setchanconfig_from_state(struct vpmadt032 *vpm, int channel, GpakChannelConfig_t *chanconfig) { GpakEcanParms_t *p; BUG_ON(!vpm); chanconfig->PcmInPortA = 3; chanconfig->PcmInSlotA = channel; chanconfig->PcmOutPortA = SerialPortNull; chanconfig->PcmOutSlotA = channel; chanconfig->PcmInPortB = 2; chanconfig->PcmInSlotB = channel; chanconfig->PcmOutPortB = 3; chanconfig->PcmOutSlotB = channel; chanconfig->ToneTypesA = Null_tone; chanconfig->MuteToneA = Disabled; chanconfig->FaxCngDetA = Disabled; chanconfig->ToneTypesB = Null_tone; chanconfig->EcanEnableA = Enabled; chanconfig->EcanEnableB = Disabled; chanconfig->MuteToneB = Disabled; chanconfig->FaxCngDetB = Disabled; /* The software companding will be overridden on a channel by channel * basis when the channel is enabled. */ chanconfig->SoftwareCompand = cmpPCMU; chanconfig->FrameRate = rate2ms; p = &chanconfig->EcanParametersA; vpmadt032_get_default_parameters(p); p->EcanNlpType = vpm->curecstate[channel].nlp_type; p->EcanNlpThreshold = vpm->curecstate[channel].nlp_threshold; p->EcanNlpMaxSuppress = vpm->curecstate[channel].nlp_max_suppress; memcpy(&chanconfig->EcanParametersB, &chanconfig->EcanParametersA, sizeof(chanconfig->EcanParametersB)); } static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc) { int res, i; GpakPortConfig_t portconfig = {0}; gpakConfigPortStatus_t configportstatus; GPAK_PortConfigStat_t pstatus; GpakChannelConfig_t chanconfig; GPAK_ChannelConfigStat_t cstatus; GPAK_AlgControlStat_t algstatus; /* First Serial Port config */ portconfig.SlotsSelect1 = SlotCfgNone; portconfig.FirstBlockNum1 = 0; portconfig.FirstSlotMask1 = 0x0000; portconfig.SecBlockNum1 = 1; portconfig.SecSlotMask1 = 0x0000; portconfig.SerialWordSize1 = SerWordSize8; portconfig.CompandingMode1 = cmpNone; portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh; portconfig.TxClockPolarity1 = SerClockActHigh; portconfig.RxClockPolarity1 = SerClockActHigh; portconfig.TxDataDelay1 = DataDelay0; portconfig.RxDataDelay1 = DataDelay0; portconfig.DxDelay1 = Disabled; portconfig.ThirdSlotMask1 = 0x0000; portconfig.FouthSlotMask1 = 0x0000; portconfig.FifthSlotMask1 = 0x0000; portconfig.SixthSlotMask1 = 0x0000; portconfig.SevenSlotMask1 = 0x0000; portconfig.EightSlotMask1 = 0x0000; /* Second Serial Port config */ portconfig.SlotsSelect2 = SlotCfg2Groups; portconfig.FirstBlockNum2 = 0; portconfig.FirstSlotMask2 = 0xffff; portconfig.SecBlockNum2 = 1; portconfig.SecSlotMask2 = 0xffff; portconfig.SerialWordSize2 = SerWordSize8; portconfig.CompandingMode2 = cmpNone; portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh; portconfig.TxClockPolarity2 = SerClockActHigh; portconfig.RxClockPolarity2 = SerClockActLow; portconfig.TxDataDelay2 = DataDelay0; portconfig.RxDataDelay2 = DataDelay0; portconfig.DxDelay2 = Disabled; portconfig.ThirdSlotMask2 = 0x0000; portconfig.FouthSlotMask2 = 0x0000; portconfig.FifthSlotMask2 = 0x0000; portconfig.SixthSlotMask2 = 0x0000; portconfig.SevenSlotMask2 = 0x0000; portconfig.EightSlotMask2 = 0x0000; /* Third Serial Port Config */ portconfig.SlotsSelect3 = SlotCfg2Groups; portconfig.FirstBlockNum3 = 0; portconfig.FirstSlotMask3 = 0xffff; portconfig.SecBlockNum3 = 1; portconfig.SecSlotMask3 = 0xffff; portconfig.SerialWordSize3 = SerWordSize8; portconfig.CompandingMode3 = cmpNone; portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh; portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh; portconfig.TxClockPolarity3 = SerClockActHigh; portconfig.RxClockPolarity3 = SerClockActLow; portconfig.TxDataDelay3 = DataDelay0; portconfig.RxDataDelay3 = DataDelay0; portconfig.DxDelay3 = Disabled; portconfig.ThirdSlotMask3 = 0x0000; portconfig.FouthSlotMask3 = 0x0000; portconfig.FifthSlotMask3 = 0x0000; portconfig.SixthSlotMask3 = 0x0000; portconfig.SevenSlotMask3 = 0x0000; portconfig.EightSlotMask3 = 0x0000; if ((configportstatus = gpakConfigurePorts(vpm->dspid, &portconfig, &pstatus))) { dev_notice(&wc->vb.pdev->dev, "Configuration of ports failed (%d)!\n", configportstatus); return -1; } else { if (vpm->options.debug & DEBUG_ECHOCAN) dev_info(&wc->vb.pdev->dev, "Configured McBSP ports successfully\n"); } res = gpakPingDsp(vpm->dspid, &vpm->version); if (res) { dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res); return -1; } for (i = 0; i < vpm->options.channels; ++i) { struct dahdi_chan *const chan = &wc->chans[i]->chan; vpm->curecstate[i].tap_length = 0; vpm->curecstate[i].nlp_type = vpm->options.vpmnlptype; vpm->curecstate[i].nlp_threshold = vpm->options.vpmnlpthresh; vpm->curecstate[i].nlp_max_suppress = vpm->options.vpmnlpmaxsupp; vpm->curecstate[i].companding = (chan->span->deflaw == DAHDI_LAW_ALAW) ? ADT_COMP_ALAW : ADT_COMP_ULAW; /* set_vpmadt032_chanconfig_from_state(&vpm->curecstate[i], &vpm->options, i, &chanconfig); !!! */ vpm->setchanconfig_from_state(vpm, i, &chanconfig); if ((res = gpakConfigureChannel(vpm->dspid, i, tdmToTdm, &chanconfig, &cstatus))) { dev_notice(&wc->vb.pdev->dev, "Unable to configure channel #%d (%d)", i, res); if (res == 1) { printk(KERN_CONT ", reason %d", cstatus); } printk(KERN_CONT "\n"); return -1; } if ((res = gpakAlgControl(vpm->dspid, i, BypassEcanA, &algstatus))) { dev_notice(&wc->vb.pdev->dev, "Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus); return -1; } if ((res = gpakAlgControl(vpm->dspid, i, BypassSwCompanding, &algstatus))) { dev_notice(&wc->vb.pdev->dev, "Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus); return -1; } } if ((res = gpakPingDsp(vpm->dspid, &vpm->version))) { dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res); return -1; } set_bit(VPM150M_ACTIVE, &vpm->control); return 0; } /** * is_good_frame() - Whether the SFRAME received was one sent. * */ static inline bool is_good_frame(const u8 *sframe) { const u8 a = sframe[0*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; const u8 b = sframe[1*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; return a != b; } static inline void cmd_dequeue_vpmoct(struct wctdm *wc, u8 *eframe) { struct vpmoct *vpm = wc->vpmoct; struct vpmoct_cmd *cmd; u8 i; /* Pop a command off pending list */ spin_lock(&vpm->list_lock); if (list_empty(&vpm->pending_list)) { spin_unlock(&vpm->list_lock); return; } cmd = list_entry(vpm->pending_list.next, struct vpmoct_cmd, node); if (is_vpmoct_cmd_read(cmd)) list_move_tail(&cmd->node, &vpm->active_list); else list_del_init(&cmd->node); /* Skip audio (24 bytes) and ignore first 6 timeslots */ eframe += 30; /* Save ident so we can match the return eframe */ cmd->txident = wc->txident; /* We have four timeslots to work with for a regular spi packet */ /* TODO: Create debug flag for this in dev */ /* The vpmoct requires a "sync" spi command as the first three bytes * of an eframe */ eframe[7*0] = 0x12; eframe[7*1] = 0x34; eframe[7*2] = 0x56; eframe[7*3] = cmd->command; eframe[7*4] = cmd->address; eframe[7*5] = cmd->data[0]; for (i = 1; i < cmd->chunksize; i++) eframe[(7*5)+7*i] = cmd->data[i]; /* Clean up fire-and-forget messages from memory */ if (list_empty(&cmd->node)) kfree(cmd); spin_unlock(&vpm->list_lock); } static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *eframe) { struct vpmadt032_cmd *curcmd = NULL; struct vpmadt032 *vpmadt032 = wc->vpmadt032; int x; unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7; /* Skip audio */ eframe += 24; if (test_bit(VPM150M_HPIRESET, &vpmadt032->control)) { if (debug & DEBUG_ECHOCAN) dev_info(&wc->vb.pdev->dev, "HW Resetting VPMADT032...\n"); for (x = 24; x < 28; x++) { if (x == 24) { if (test_and_clear_bit(VPM150M_HPIRESET, &vpmadt032->control)) { eframe[VPM_CMD_BYTE(x, 0)] = 0x0b; } else { eframe[VPM_CMD_BYTE(x, 0)] = leds; } } else { eframe[VPM_CMD_BYTE(x, 0)] = leds; } eframe[VPM_CMD_BYTE(x, 1)] = 0; eframe[VPM_CMD_BYTE(x, 2)] = 0x00; } return; } if ((curcmd = vpmadt032_get_ready_cmd(vpmadt032))) { curcmd->txident = wc->txident; #if 0 // if (printk_ratelimit()) dev_info(&wc->vb.pdev->dev, "Transmitting txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", curcmd->txident, curcmd->desc, curcmd->address, curcmd->data); #endif if (curcmd->desc & __VPM150M_RWPAGE) { /* Set CTRL access to page*/ eframe[VPM_CMD_BYTE(24, 0)] = (0x8 << 4); eframe[VPM_CMD_BYTE(24, 1)] = 0; eframe[VPM_CMD_BYTE(24, 2)] = 0x20; /* Do a page write */ if (curcmd->desc & __VPM150M_WR) eframe[VPM_CMD_BYTE(25, 0)] = ((0x8 | 0x4) << 4); else eframe[VPM_CMD_BYTE(25, 0)] = ((0x8 | 0x4 | 0x1) << 4); eframe[VPM_CMD_BYTE(25, 1)] = 0; if (curcmd->desc & __VPM150M_WR) eframe[VPM_CMD_BYTE(25, 2)] = curcmd->data & 0xf; else eframe[VPM_CMD_BYTE(25, 2)] = 0; /* Clear XADD */ eframe[VPM_CMD_BYTE(26, 0)] = (0x8 << 4); eframe[VPM_CMD_BYTE(26, 1)] = 0; eframe[VPM_CMD_BYTE(26, 2)] = 0; /* Fill in to buffer to size */ eframe[VPM_CMD_BYTE(27, 0)] = 0; eframe[VPM_CMD_BYTE(27, 1)] = 0; eframe[VPM_CMD_BYTE(27, 2)] = 0; } else { /* Set address */ eframe[VPM_CMD_BYTE(24, 0)] = ((0x8 | 0x4) << 4); eframe[VPM_CMD_BYTE(24, 1)] = (curcmd->address >> 8) & 0xff; eframe[VPM_CMD_BYTE(24, 2)] = curcmd->address & 0xff; /* Send/Get our data */ eframe[VPM_CMD_BYTE(25, 0)] = (curcmd->desc & __VPM150M_WR) ? ((0x8 | (0x3 << 1)) << 4) : ((0x8 | (0x3 << 1) | 0x1) << 4); eframe[VPM_CMD_BYTE(25, 1)] = (curcmd->data >> 8) & 0xff; eframe[VPM_CMD_BYTE(25, 2)] = curcmd->data & 0xff; eframe[VPM_CMD_BYTE(26, 0)] = 0; eframe[VPM_CMD_BYTE(26, 1)] = 0; eframe[VPM_CMD_BYTE(26, 2)] = 0; /* Fill in the rest */ eframe[VPM_CMD_BYTE(27, 0)] = 0; eframe[VPM_CMD_BYTE(27, 1)] = 0; eframe[VPM_CMD_BYTE(27, 2)] = 0; } } else if (test_and_clear_bit(VPM150M_SWRESET, &vpmadt032->control)) { for (x = 24; x < 28; x++) { if (x == 24) eframe[VPM_CMD_BYTE(x, 0)] = (0x8 << 4); else eframe[VPM_CMD_BYTE(x, 0)] = 0x00; eframe[VPM_CMD_BYTE(x, 1)] = 0; if (x == 24) eframe[VPM_CMD_BYTE(x, 2)] = 0x01; else eframe[VPM_CMD_BYTE(x, 2)] = 0x00; } } else { for (x = 24; x < 28; x++) { eframe[VPM_CMD_BYTE(x, 0)] = 0x00; eframe[VPM_CMD_BYTE(x, 1)] = 0x00; eframe[VPM_CMD_BYTE(x, 2)] = 0x00; } } /* Add our leds in */ for (x = 24; x < 28; x++) { eframe[VPM_CMD_BYTE(x, 0)] |= leds; } } /* Call with wc->reglock held and local interrupts disabled */ static void _cmd_dequeue(struct wctdm *wc, u8 *eframe, int card, int pos) { struct wctdm_module *const mod = &wc->mods[card]; unsigned int curcmd=0; /* QRV only use commands relating to the first channel */ if ((card & 0x03) && (mod->type == QRV)) return; /* Skip audio */ eframe += 24; /* Search for something waiting to transmit */ if (pos) { if (!list_empty(&mod->pending_cmds)) { struct wctdm_cmd *const cmd = list_entry(mod->pending_cmds.next, struct wctdm_cmd, node); curcmd = cmd->cmd; cmd->ident = wc->txident; list_move_tail(&cmd->node, &mod->active_cmds); } } if (!curcmd) { /* If nothing else, use filler */ switch (mod->type) { case FXS: curcmd = CMD_RD(LINE_STATE); break; case FXO: curcmd = CMD_RD(12); break; case BRI: curcmd = 0x101010; break; case QRV: curcmd = CMD_RD(3); break; default: break; } } switch (mod->type) { case FXS: eframe[CMD_BYTE(mod, 0)] = (1 << (mod->subaddr)); if (curcmd & __CMD_WR) eframe[CMD_BYTE(mod, 1)] = (curcmd >> 8) & 0x7f; else eframe[CMD_BYTE(mod, 1)] = 0x80 | ((curcmd >> 8) & 0x7f); eframe[CMD_BYTE(mod, 2)] = curcmd & 0xff; break; case FXO: { static const int ADDRS[4] = {0x00, 0x08, 0x04, 0x0c}; if (curcmd & __CMD_WR) eframe[CMD_BYTE(mod, 0)] = 0x20 | ADDRS[mod->subaddr]; else eframe[CMD_BYTE(mod, 0)] = 0x60 | ADDRS[mod->subaddr]; eframe[CMD_BYTE(mod, 1)] = (curcmd >> 8) & 0xff; eframe[CMD_BYTE(mod, 2)] = curcmd & 0xff; break; } case FXSINIT: /* Special case, we initialize the FXS's into the three-byte command mode then switch to the regular mode. To send it into thee byte mode, treat the path as 6 two-byte commands and in the last one we initialize register 0 to 0x80. All modules read this as the command to switch to daisy chain mode and we're done. */ eframe[CMD_BYTE(mod, 0)] = 0x00; eframe[CMD_BYTE(mod, 1)] = 0x00; if ((card & 0x1) == 0x1) eframe[CMD_BYTE(mod, 2)] = 0x80; else eframe[CMD_BYTE(mod, 2)] = 0x00; break; case BRI: if (unlikely((curcmd != 0x101010) && (curcmd & 0x1010) == 0x1010)) /* b400m CPLD */ eframe[CMD_BYTE(mod, 0)] = 0x55; else /* xhfc */ eframe[CMD_BYTE(mod, 0)] = 0x10; eframe[CMD_BYTE(mod, 1)] = (curcmd >> 8) & 0xff; eframe[CMD_BYTE(mod, 2)] = curcmd & 0xff; break; case QRV: eframe[CMD_BYTE(mod, 0)] = 0x00; if (!curcmd) { eframe[CMD_BYTE(mod, 1)] = 0x00; eframe[CMD_BYTE(mod, 2)] = 0x00; } else { if (curcmd & __CMD_WR) eframe[CMD_BYTE(mod, 1)] = 0x40 | ((curcmd >> 8) & 0x3f); else eframe[CMD_BYTE(mod, 1)] = 0xc0 | ((curcmd >> 8) & 0x3f); eframe[CMD_BYTE(mod, 2)] = curcmd & 0xff; } break; case NONE: eframe[CMD_BYTE(mod, 0)] = 0x10; eframe[CMD_BYTE(mod, 1)] = 0x10; eframe[CMD_BYTE(mod, 2)] = 0x10; break; } } static inline void cmd_decipher_vpmoct(struct wctdm *wc, const u8 *eframe) { struct vpmoct *vpm = wc->vpmoct; struct vpmoct_cmd *cmd; int i; /* Skip audio and first 6 timeslots */ eframe += 30; spin_lock(&vpm->list_lock); /* No command to handle, just exit */ if (list_empty(&vpm->active_list)) { spin_unlock(&vpm->list_lock); return; } cmd = list_entry(vpm->active_list.next, struct vpmoct_cmd, node); if (wc->rxident == cmd->txident) list_del_init(&cmd->node); else cmd = NULL; spin_unlock(&vpm->list_lock); if (!cmd) return; /* Store result, Ignoring the first "sync spi command" bytes */ cmd->command = eframe[7*3]; cmd->address = eframe[7*4]; for (i = 0; i < cmd->chunksize; ++i) cmd->data[i] = eframe[7*(5+i)]; complete(&cmd->complete); } static inline void cmd_decipher_vpmadt032(struct wctdm *wc, const u8 *eframe) { struct vpmadt032 *const vpm = wc->vpmadt032; struct vpmadt032_cmd *cmd; BUG_ON(!vpm); /* If the hardware is not processing any commands currently, then * there is nothing for us to do here. */ if (list_empty(&vpm->active_cmds)) { return; } spin_lock(&vpm->list_lock); cmd = list_entry(vpm->active_cmds.next, struct vpmadt032_cmd, node); if (wc->rxident == cmd->txident) { list_del_init(&cmd->node); } else { cmd = NULL; } spin_unlock(&vpm->list_lock); if (!cmd) return; /* Skip audio */ eframe += 24; /* Store result */ cmd->data = (0xff & eframe[VPM_CMD_BYTE(25, 1)]) << 8; cmd->data |= eframe[VPM_CMD_BYTE(25, 2)]; if (cmd->desc & __VPM150M_WR) { kfree(cmd); } else { cmd->desc |= __VPM150M_FIN; complete(&cmd->complete); } } /** * Call with the reglock held and local interrupts disabled */ static void _cmd_decipher(struct wctdm *wc, const u8 *eframe, int card) { enum { TDM_BYTES = 24, }; struct wctdm_module *const mod = &wc->mods[card]; struct wctdm_cmd *cmd; u8 address; u8 value; if (list_empty(&mod->active_cmds)) return; cmd = list_entry(mod->active_cmds.next, struct wctdm_cmd, node); if (cmd->ident != wc->rxident) return; list_del(&cmd->node); if (cmd->cmd & __CMD_WR) { kfree(cmd); return; } address = (cmd->cmd >> 8) & 0xff; cmd->cmd = eframe[TDM_BYTES + CMD_BYTE(mod, 2)]; value = (cmd->cmd & 0xff); if (cmd->complete) { complete(cmd->complete); return; } list_add(&cmd->node, &wc->free_isr_commands); switch (mod->type) { case FXS: mod->isrshadow[(68 == address) ? 0 : 1] = value; break; case FXO: /* 5 = Hook/Ring 29 = Battery */ mod->isrshadow[(5 == address) ? 0 : 1] = value; break; case QRV: /* wctdm_isr_getreg(wc, mod, 3); */ /* COR/CTCSS state */ /* TODO: This looks broken to me, but I have no way to * resolved it. */ /* wc->mods[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3); */ break; default: break; } } /* Call with wc.reglock held and local interrupts disabled. */ static void wctdm_isr_getreg(struct wctdm *wc, struct wctdm_module *const mod, u8 address) { struct wctdm_cmd *cmd; if (!list_empty(&wc->free_isr_commands)) { cmd = list_entry(wc->free_isr_commands.next, struct wctdm_cmd, node); list_del(&cmd->node); } else { cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); if (unlikely(!cmd)) return; } cmd->cmd = CMD_RD(address); cmd->complete = NULL; list_add(&cmd->node, &mod->pending_cmds); } static inline void wctdm_setreg_intr(struct wctdm *wc, struct wctdm_module *mod, int addr, int val); static void cmd_checkisr(struct wctdm *wc, struct wctdm_module *const mod) { if (mod->sethook) { wctdm_setreg_intr(wc, mod, ((mod->sethook >> 8) & 0xff), mod->sethook & 0xff); mod->sethook = 0; return; } switch (mod->type) { case FXS: wctdm_isr_getreg(wc, mod, 68); /* Hook state */ #ifdef PAQ_DEBUG wctdm_isr_getreg(wc, mod, 19); /* Transistor interrupts */ #else wctdm_isr_getreg(wc, mod, LINE_STATE); #endif break; case FXO: wctdm_isr_getreg(wc, mod, 5); /* Hook/Ring state */ wctdm_isr_getreg(wc, mod, 29); /* Battery */ break; case QRV: wctdm_isr_getreg(wc, mod, 3); /* COR/CTCSS state */ /* TODO: This looks broken to me, but I have no way to * resolved it. */ /* wc->mods[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3); */ break; case BRI: /* TODO: Two calls needed here? */ wctdm_bri_checkisr(wc, mod, 0); wctdm_bri_checkisr(wc, mod, 1); break; default: break; } } /** * insert_tdm_data() - Move TDM data from channels to sframe. * */ static void insert_tdm_data(const struct wctdm *wc, u8 *sframe) { int i; register u8 *chanchunk; for (i = 0; i < wc->avchannels; i += 4) { chanchunk = &wc->chans[0 + i]->chan.writechunk[0]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*3] = chanchunk[3]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*4] = chanchunk[4]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*5] = chanchunk[5]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6]; sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7]; chanchunk = &wc->chans[1 + i]->chan.writechunk[0]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*3] = chanchunk[3]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*4] = chanchunk[4]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*5] = chanchunk[5]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6]; sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7]; chanchunk = &wc->chans[2 + i]->chan.writechunk[0]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*3] = chanchunk[3]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*4] = chanchunk[4]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*5] = chanchunk[5]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6]; sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7]; chanchunk = &wc->chans[3 + i]->chan.writechunk[0]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0] = chanchunk[0]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1] = chanchunk[1]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2] = chanchunk[2]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*3] = chanchunk[3]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*4] = chanchunk[4]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*5] = chanchunk[5]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*6] = chanchunk[6]; sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*7] = chanchunk[7]; } } static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *sframe) { unsigned long flags; int x, y; struct dahdi_span *s; unsigned char *eframe = sframe; /* Calculate Transmission */ if (likely(is_initialized(wc))) { for (x = 0; x < MAX_SPANS; x++) { if (wc->spans[x]) { s = &wc->spans[x]->span; dahdi_transmit(s); } } insert_tdm_data(wc, sframe); #ifdef CONFIG_VOICEBUS_ECREFERENCE for (x = 0; x < wc->avchannels; ++x) { __dahdi_fifo_put(wc->ec_reference[x], wc->chans[x]->chan.writechunk, DAHDI_CHUNKSIZE); } #endif } spin_lock_irqsave(&wc->reglock, flags); for (x = 0; x < DAHDI_CHUNKSIZE; x++) { /* Send a sample, as a 32-bit word */ /* TODO: ABK: hmm, this was originally mods_per_board, but we * need to worry about all the active "voice" timeslots, since * BRI modules have a different number of TDM channels than * installed modules. */ for (y = 0; y < wc->avchannels; y++) { if (y < wc->mods_per_board) _cmd_dequeue(wc, eframe, y, x); } if (wc->vpmadt032) cmd_dequeue_vpmadt032(wc, eframe); else if (wc->vpmoct) cmd_dequeue_vpmoct(wc, eframe); if (x < DAHDI_CHUNKSIZE - 1) { eframe[EFRAME_SIZE] = wc->ctlreg; eframe[EFRAME_SIZE + 1] = wc->txident++; if (4 == wc->desc->ports) eframe[EFRAME_SIZE + 2] = wc->tdm410leds; } eframe += (EFRAME_SIZE + EFRAME_GAP); } spin_unlock_irqrestore(&wc->reglock, flags); } /* Must be called with wc.reglock held and local interrupts disabled */ static inline void wctdm_setreg_intr(struct wctdm *wc, struct wctdm_module *mod, int addr, int val) { struct wctdm_cmd *cmd; cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); if (unlikely(!cmd)) return; cmd->complete = NULL; cmd->cmd = CMD_WR(addr, val); list_add_tail(&cmd->node, &mod->pending_cmds); } int wctdm_setreg(struct wctdm *wc, struct wctdm_module *mod, int addr, int val) { struct wctdm_cmd *cmd; unsigned long flags; #if 0 /* TODO */ /* QRV and BRI cards are only addressed at their first "port" */ if ((card & 0x03) && ((wc->mods[card].type == QRV) || (wc->mods[card].type == BRI))) return 0; #endif cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); if (unlikely(!cmd)) return -ENOMEM; cmd->complete = NULL; cmd->cmd = CMD_WR(addr, val); spin_lock_irqsave(&wc->reglock, flags); list_add_tail(&cmd->node, &mod->pending_cmds); spin_unlock_irqrestore(&wc->reglock, flags); return 0; } int wctdm_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr) { unsigned long flags; struct wctdm_cmd *cmd; int val; #if 0 /* TODO */ /* if a QRV card, use only its first channel */ if (wc->mods[card].type == QRV) { if (card & 3) return 0; } #endif cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; cmd->complete = kmalloc(sizeof(*cmd->complete), GFP_KERNEL); if (!cmd->complete) { kfree(cmd); return -ENOMEM; } init_completion(cmd->complete); cmd->cmd = CMD_RD(addr); spin_lock_irqsave(&wc->reglock, flags); list_add_tail(&cmd->node, &mod->pending_cmds); spin_unlock_irqrestore(&wc->reglock, flags); wait_for_completion(cmd->complete); val = cmd->cmd & 0xff; kfree(cmd->complete); kfree(cmd); return val; } static int wctdm_getregs(struct wctdm *wc, struct wctdm_module *const mod, int *const addresses, const size_t count) { int x; unsigned long flags; struct wctdm_cmd *cmd; struct wctdm_cmd **cmds = kmalloc(sizeof(cmd) * count, GFP_KERNEL); if (!cmds) return -ENOMEM; for (x = 0; x < count; ++x) { cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { kfree(cmds); return -ENOMEM; } cmd->complete = kmalloc(sizeof(*cmd->complete), GFP_KERNEL); if (!cmd->complete) { kfree(cmd); kfree(cmds); return -ENOMEM; } init_completion(cmd->complete); cmd->cmd = CMD_RD(addresses[x]); spin_lock_irqsave(&wc->reglock, flags); list_add_tail(&cmd->node, &mod->pending_cmds); spin_unlock_irqrestore(&wc->reglock, flags); cmds[x] = cmd; } for (x = count - 1; x >= 0; --x) { cmd = cmds[x]; wait_for_completion(cmd->complete); addresses[x] = cmd->cmd & 0xff; kfree(cmd->complete); kfree(cmd); } kfree(cmds); return 0; } /** * call with wc->reglock held and interrupts disabled. */ static void cmd_retransmit(struct wctdm *wc) { int x; for (x = 0; x < wc->mods_per_board; x++) { struct wctdm_module *const mod = &wc->mods[x]; if (mod->type == BRI) continue; list_splice_init(&mod->active_cmds, &mod->pending_cmds); } #ifdef VPM_SUPPORT if (wc->vpmadt032) vpmadt032_resend(wc->vpmadt032); #endif } /** * extract_tdm_data() - Move TDM data from sframe to channels. * */ static void extract_tdm_data(struct wctdm *wc, const u8 *sframe) { int i; register u8 *chanchunk; for (i = 0; i < wc->avchannels; i += 4) { chanchunk = &wc->chans[0 + i]->chan.readchunk[0]; chanchunk[0] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; chanchunk = &wc->chans[1 + i]->chan.readchunk[0]; chanchunk[0] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; chanchunk = &wc->chans[2 + i]->chan.readchunk[0]; chanchunk[0] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; chanchunk = &wc->chans[3 + i]->chan.readchunk[0]; chanchunk[0] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; } /* Pre-echo with the vpmoct overwrites the 24th timeslot with the * specified channel's pre-echo audio stream. This data is ignored * on all but the 24xx card, so we store it in a temporary buffer. */ if (wc->vpmoct && wc->vpmoct->preecho_enabled) { chanchunk = &wc->vpmoct->preecho_buf[0]; chanchunk[0] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*0]; chanchunk[1] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*1]; chanchunk[2] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*2]; chanchunk[3] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*3]; chanchunk[4] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*4]; chanchunk[5] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*5]; chanchunk[6] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*6]; chanchunk[7] = sframe[23 + (EFRAME_SIZE + EFRAME_GAP)*7]; } } static inline void wctdm_receiveprep(struct wctdm *wc, const u8 *sframe) { unsigned long flags; int x, y; bool irqmiss = false; unsigned char expected; const u8 *eframe = sframe; if (unlikely(!is_good_frame(sframe))) return; spin_lock_irqsave(&wc->reglock, flags); if (likely(is_initialized(wc))) extract_tdm_data(wc, sframe); for (x = 0; x < DAHDI_CHUNKSIZE; x++) { if (x < DAHDI_CHUNKSIZE - 1) { expected = wc->rxident + 1; wc->rxident = eframe[EFRAME_SIZE + 1]; if (wc->rxident != expected) { irqmiss = true; cmd_retransmit(wc); } } for (y = 0; y < wc->avchannels; y++) _cmd_decipher(wc, eframe, y); if (wc->vpmadt032) cmd_decipher_vpmadt032(wc, eframe); else if (wc->vpmoct) cmd_decipher_vpmoct(wc, eframe); eframe += (EFRAME_SIZE + EFRAME_GAP); } spin_unlock_irqrestore(&wc->reglock, flags); /* XXX We're wasting 8 taps. We should get closer :( */ if (likely(is_initialized(wc))) { for (x = 0; x < wc->avchannels; x++) { struct wctdm_chan *const wchan = wc->chans[x]; struct dahdi_chan *const c = &wchan->chan; #ifdef CONFIG_VOICEBUS_ECREFERENCE unsigned char buffer[DAHDI_CHUNKSIZE]; __dahdi_fifo_get(wc->ec_reference[x], buffer, ARRAY_SIZE(buffer)); dahdi_ec_chunk(c, c->readchunk, buffer); #else if ((wc->vpmoct) && (wchan->timeslot == wc->vpmoct->preecho_timeslot) && (wc->vpmoct->preecho_enabled)) { __dahdi_ec_chunk(c, c->readchunk, wc->vpmoct->preecho_buf, c->writechunk); } else { __dahdi_ec_chunk(c, c->readchunk, c->readchunk, c->writechunk); } #endif } for (x = 0; x < MAX_SPANS; x++) { if (wc->spans[x]) { struct dahdi_span *s = &wc->spans[x]->span; #if 1 /* Check for digital spans */ if (s->ops->chanconfig == b400m_chanconfig) { BUG_ON(!is_hx8(wc)); if (s->flags & DAHDI_FLAG_RUNNING) b400m_dchan(s); } #endif dahdi_receive(s); if (unlikely(irqmiss)) ++s->irqmisses; } } } } static int wait_access(struct wctdm *wc, struct wctdm_module *const mod) { unsigned char data = 0; int count = 0; #define MAX 10 /* attempts */ /* Wait for indirect access */ while (count++ < MAX) { data = wctdm_getreg(wc, mod, I_STATUS); if (!data) return 0; } if (count > (MAX-1)) { dev_notice(&wc->vb.pdev->dev, " ##### Loop error (%02x) #####\n", data); } return 0; } static unsigned char translate_3215(unsigned char address) { int x; for (x = 0; x < ARRAY_SIZE(indirect_regs); x++) { if (indirect_regs[x].address == address) { address = indirect_regs[x].altaddr; break; } } return address; } static int wctdm_proslic_setreg_indirect(struct wctdm *wc, struct wctdm_module *const mod, unsigned char address, unsigned short data) { int res = -1; address = translate_3215(address); if (address == 255) return 0; if (!wait_access(wc, mod)) { wctdm_setreg(wc, mod, IDA_LO, (u8)(data & 0xFF)); wctdm_setreg(wc, mod, IDA_HI, (u8)((data & 0xFF00)>>8)); wctdm_setreg(wc, mod, IAA, address); res = 0; }; return res; } static int wctdm_proslic_getreg_indirect(struct wctdm *wc, struct wctdm_module *const mod, unsigned char address) { int res = -1; char *p=NULL; address = translate_3215(address); if (address == 255) return 0; if (!wait_access(wc, mod)) { wctdm_setreg(wc, mod, IAA, address); if (!wait_access(wc, mod)) { int addresses[2] = {IDA_LO, IDA_HI}; wctdm_getregs(wc, mod, addresses, ARRAY_SIZE(addresses)); res = addresses[0] | (addresses[1] << 8); } else p = "Failed to wait inside\n"; } else p = "failed to wait\n"; if (p) dev_notice(&wc->vb.pdev->dev, "%s", p); return res; } static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, struct wctdm_module *mod) { unsigned char i; for (i = 0; i < ARRAY_SIZE(indirect_regs); i++) { if (wctdm_proslic_setreg_indirect(wc, mod, indirect_regs[i].address, indirect_regs[i].initial)) return -1; } return 0; } static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, struct wctdm_module *mod) { int passed = 1; unsigned short i, initial; int j; for (i = 0; i < ARRAY_SIZE(indirect_regs); i++) { j = wctdm_proslic_getreg_indirect(wc, mod, (u8)indirect_regs[i].address); if (j < 0) { dev_notice(&wc->vb.pdev->dev, "Failed to read indirect register %d\n", i); return -1; } initial = indirect_regs[i].initial; if ((j != initial) && (indirect_regs[i].altaddr != 255)) { dev_notice(&wc->vb.pdev->dev, "!!!!!!! %s iREG %X = %X should be %X\n", indirect_regs[i].name, indirect_regs[i].address, j, initial); passed = 0; } } if (passed) { if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Init Indirect Registers completed successfully.\n"); } } else { dev_notice(&wc->vb.pdev->dev, " !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); return -1; } return 0; } /* 1ms interrupt */ static void wctdm_proslic_check_oppending(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; int res; if (!(fxs->lasttxhook & SLIC_LF_OPPENDING)) return; /* Monitor the Pending LF state change, for the next 100ms */ spin_lock(&wc->reglock); if (!(fxs->lasttxhook & SLIC_LF_OPPENDING)) { spin_unlock(&wc->reglock); return; } res = mod->isrshadow[1]; if ((res & SLIC_LF_SETMASK) == (fxs->lasttxhook & SLIC_LF_SETMASK)) { fxs->lasttxhook &= SLIC_LF_SETMASK; fxs->oppending_ms = 0; if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "SLIC_LF OK: card=%d shadow=%02x " "lasttxhook=%02x intcount=%d\n", mod->card, res, fxs->lasttxhook, wc->intcount); } } else if (fxs->oppending_ms && (--fxs->oppending_ms == 0)) { wctdm_setreg_intr(wc, mod, LINE_STATE, fxs->lasttxhook); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "SLIC_LF RETRY: card=%d shadow=%02x " "lasttxhook=%02x intcount=%d\n", mod->card, res, fxs->lasttxhook, wc->intcount); } } else { /* Start 100ms Timeout */ fxs->oppending_ms = 100; } spin_unlock(&wc->reglock); } /* 256ms interrupt */ static void wctdm_proslic_recheck_sanity(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; int res; #ifdef PAQ_DEBUG res = mod->isrshadow[1]; res &= ~0x3; if (res) { mod->isrshadow[1] = 0; fxs->palarms++; if (fxs->palarms < MAX_ALARMS) { dev_notice(&wc->vb.pdev->dev, "Power alarm (%02x) on module %d, resetting!\n", res, card + 1); mod->sethook = CMD_WR(19, res); /* Update shadow register to avoid extra power alarms until next read */ mod->isrshadow[1] = 0; } else { if (fxs->palarms == MAX_ALARMS) dev_notice(&wc->vb.pdev->dev, "Too many power alarms on card %d, NOT resetting!\n", card + 1); } } #else spin_lock(&wc->reglock); res = mod->isrshadow[1]; #if 0 /* This makes sure the lasthook was put in reg 64 the linefeed reg */ if (fxs->lasttxhook & SLIC_LF_OPPENDING) { if ((res & SLIC_LF_SETMASK) == (fxs->lasttxhook & SLIC_LF_SETMASK)) { fxs->lasttxhook &= SLIC_LF_SETMASK; if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "SLIC_LF OK: intcount=%d channel=%d shadow=%02x lasttxhook=%02x\n", wc->intcount, card, res, fxs->lasttxhook); } } else if (!(wc->intcount & 0x03)) { mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "SLIC_LF RETRY: intcount=%d channel=%d shadow=%02x lasttxhook=%02x\n", wc->intcount, card, res, fxs->lasttxhook); } } } if (debug & DEBUG_CARD) { if (!(wc->intcount % 100)) { dev_info(&wc->vb.pdev->dev, "SLIC_LF DEBUG: intcount=%d channel=%d shadow=%02x lasttxhook=%02x\n", wc->intcount, card, res, fxs->lasttxhook); } } #endif res = !res && /* reg 64 has to be zero at last isr read */ !(fxs->lasttxhook & SLIC_LF_OPPENDING) && /* not a transition */ fxs->lasttxhook; /* not an intended zero */ if (res) { fxs->palarms++; if (fxs->palarms < MAX_ALARMS) { dev_notice(&wc->vb.pdev->dev, "Power alarm on module %d, resetting!\n", mod->card + 1); if (fxs->lasttxhook == SLIC_LF_RINGING) { fxs->lasttxhook = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD;; } fxs->lasttxhook |= SLIC_LF_OPPENDING; mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); /* Update shadow register to avoid extra power alarms until next read */ mod->isrshadow[1] = fxs->lasttxhook; } else { if (fxs->palarms == MAX_ALARMS) { dev_notice(&wc->vb.pdev->dev, "Too many power alarms on card %d, " "NOT resetting!\n", mod->card + 1); } } } spin_unlock(&wc->reglock); #endif } static void wctdm_qrvdri_check_hook(struct wctdm *wc, int card) { signed char b,b1; int qrvcard = card & 0xfc; if (wc->mods[card].mod.qrv.debtime >= 2) wc->mods[card].mod.qrv.debtime--; b = wc->mods[qrvcard].isrshadow[0]; /* Hook/Ring state */ b &= 0xcc; /* use bits 3-4 and 6-7 only */ if (wc->mods[qrvcard].mod.qrv.radmode & RADMODE_IGNORECOR) b &= ~4; else if (!(wc->mods[qrvcard].mod.qrv.radmode & RADMODE_INVERTCOR)) b ^= 4; if (wc->mods[qrvcard + 1].mod.qrv.radmode | RADMODE_IGNORECOR) b &= ~0x40; else if (!(wc->mods[qrvcard + 1].mod.qrv.radmode | RADMODE_INVERTCOR)) b ^= 0x40; if ((wc->mods[qrvcard].mod.qrv.radmode & RADMODE_IGNORECT) || (!(wc->mods[qrvcard].mod.qrv.radmode & RADMODE_EXTTONE))) b &= ~8; else if (!(wc->mods[qrvcard].mod.qrv.radmode & RADMODE_EXTINVERT)) b ^= 8; if ((wc->mods[qrvcard + 1].mod.qrv.radmode & RADMODE_IGNORECT) || (!(wc->mods[qrvcard + 1].mod.qrv.radmode & RADMODE_EXTTONE))) b &= ~0x80; else if (!(wc->mods[qrvcard + 1].mod.qrv.radmode & RADMODE_EXTINVERT)) b ^= 0x80; /* now b & MASK should be zero, if its active */ /* check for change in chan 0 */ if ((!(b & 0xc)) != wc->mods[qrvcard + 2].mod.qrv.hook) { wc->mods[qrvcard].mod.qrv.debtime = wc->mods[qrvcard].mod.qrv.debouncetime; wc->mods[qrvcard + 2].mod.qrv.hook = !(b & 0xc); } /* if timed-out and ready */ if (wc->mods[qrvcard].mod.qrv.debtime == 1) { b1 = wc->mods[qrvcard + 2].mod.qrv.hook; if (debug) { dev_info(&wc->vb.pdev->dev, "QRV channel %d rx state changed to %d\n", qrvcard, wc->mods[qrvcard + 2].mod.qrv.hook); } dahdi_hooksig(wc->aspan->span.chans[qrvcard], (b1) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK); wc->mods[card].mod.qrv.debtime = 0; } /* check for change in chan 1 */ if ((!(b & 0xc0)) != wc->mods[qrvcard + 3].mod.qrv.hook) { wc->mods[qrvcard + 1].mod.qrv.debtime = QRV_DEBOUNCETIME; wc->mods[qrvcard + 3].mod.qrv.hook = !(b & 0xc0); } if (wc->mods[qrvcard + 1].mod.qrv.debtime == 1) { b1 = wc->mods[qrvcard + 3].mod.qrv.hook; if (debug) { dev_info(&wc->vb.pdev->dev, "QRV channel %d rx state changed to %d\n", qrvcard + 1, wc->mods[qrvcard + 3].mod.qrv.hook); } dahdi_hooksig(wc->aspan->span.chans[qrvcard + 1], (b1) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK); wc->mods[card].mod.qrv.debtime = 0; } return; } static void wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod) { #define MS_PER_CHECK_HOOK 1 unsigned char res; signed char b; unsigned int abs_voltage; struct fxo *const fxo = &mod->mod.fxo; /* Try to track issues that plague slot one FXO's */ b = mod->isrshadow[0]; /* Hook/Ring state */ b &= 0x9b; if (fxo->offhook) { if (b != 0x9) wctdm_setreg_intr(wc, mod, 5, 0x9); } else { if (b != 0x8) wctdm_setreg_intr(wc, mod, 5, 0x8); } if (!fxo->offhook) { if (fwringdetect || neonmwi_monitor) { /* Look for ring status bits (Ring Detect Signal Negative and * Ring Detect Signal Positive) to transition back and forth * some number of times to indicate that a ring is occurring. * Provide some number of samples to allow for the transitions * to occur before ginving up. * NOTE: neon mwi voltages will trigger one of these bits to go active * but not to have transitions between the two bits (i.e. no negative * to positive or positive to negative transversals ) */ res = mod->isrshadow[0] & 0x60; if (0 == fxo->wasringing) { if (res) { /* Look for positive/negative crossings in ring status reg */ fxo->wasringing = 2; fxo->ringdebounce = ringdebounce /16; fxo->lastrdtx = res; fxo->lastrdtx_count = 0; } } else if (2 == fxo->wasringing) { /* If ring detect signal has transversed */ if (res && res != fxo->lastrdtx) { /* if there are at least 3 ring polarity transversals */ if (++fxo->lastrdtx_count >= 2) { fxo->wasringing = 1; if (debug) dev_info(&wc->vb.pdev->dev, "FW RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); mod_hooksig(wc, mod, DAHDI_RXSIG_RING); fxo->ringdebounce = ringdebounce / 16; } else { fxo->lastrdtx = res; fxo->ringdebounce = ringdebounce / 16; } /* ring indicator (positve or negative) has not transitioned, check debounce count */ } else if (--fxo->ringdebounce == 0) { fxo->wasringing = 0; } } else { /* I am in ring state */ if (res) { /* If any ringdetect bits are still active */ fxo->ringdebounce = ringdebounce / 16; } else if (--fxo->ringdebounce == 0) { fxo->wasringing = 0; if (debug) dev_info(&wc->vb.pdev->dev, "FW NO RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); mod_hooksig(wc, mod, DAHDI_RXSIG_OFFHOOK); } } } else { res = mod->isrshadow[0]; if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) { fxo->ringdebounce += (DAHDI_CHUNKSIZE * 16); if (fxo->ringdebounce >= DAHDI_CHUNKSIZE * ringdebounce) { if (!fxo->wasringing) { fxo->wasringing = 1; mod_hooksig(wc, mod, DAHDI_RXSIG_RING); if (debug) dev_info(&wc->vb.pdev->dev, "RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); } fxo->ringdebounce = DAHDI_CHUNKSIZE * ringdebounce; } } else { fxo->ringdebounce -= DAHDI_CHUNKSIZE * 4; if (fxo->ringdebounce <= 0) { if (fxo->wasringing) { fxo->wasringing = 0; mod_hooksig(wc, mod, DAHDI_RXSIG_OFFHOOK); if (debug) dev_info(&wc->vb.pdev->dev, "NO RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); } fxo->ringdebounce = 0; } } } } b = mod->isrshadow[1]; /* Voltage */ abs_voltage = abs(b); if (fxovoltage) { if (!(wc->intcount % 100)) { dev_info(&wc->vb.pdev->dev, "Port %d: Voltage: %d Debounce %d\n", mod->card + 1, b, fxo->battdebounce); } } if (unlikely(DAHDI_RXSIG_INITIAL == get_dahdi_chan(wc, mod)->rxhooksig)) { /* * dahdi-base will set DAHDI_RXSIG_INITIAL after a * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events * will be queued on the channel with the current received * hook state. Channels that use robbed-bit signalling always * report the current received state via the dahdi_rbsbits * call. Since we only call dahdi_hooksig when we've detected * a change to report, let's forget our current state in order * to force us to report it again via dahdi_hooksig. * */ fxo->battery = BATTERY_UNKNOWN; } if (abs_voltage < battthresh) { /* possible existing states: battery lost, no debounce timer battery lost, debounce timer (going to battery present) battery present or unknown, no debounce timer battery present or unknown, debounce timer (going to battery lost) */ if (fxo->battery == BATTERY_LOST) { if (fxo->battdebounce) { /* we were going to BATTERY_PRESENT, but battery was lost again, so clear the debounce timer */ fxo->battdebounce = 0; } } else { if (fxo->battdebounce) { /* going to BATTERY_LOST, see if we are there yet */ if (--fxo->battdebounce == 0) { fxo->battery = BATTERY_LOST; if (debug) dev_info(&wc->vb.pdev->dev, "NO BATTERY on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); #ifdef JAPAN if (!wc->ohdebounce && wc->offhook) { dahdi_hooksig(wc->aspan->chans[card], DAHDI_RXSIG_ONHOOK); if (debug) dev_info(&wc->vb.pdev->dev, "Signalled On Hook\n"); #ifdef ZERO_BATT_RING wc->onhook++; #endif } #else mod_hooksig(wc, mod, DAHDI_RXSIG_ONHOOK); /* set the alarm timer, taking into account that part of its time period has already passed while debouncing occurred */ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK; #endif } } else { /* start the debounce timer to verify that battery has been lost */ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK; } } } else { /* possible existing states: battery lost or unknown, no debounce timer battery lost or unknown, debounce timer (going to battery present) battery present, no debounce timer battery present, debounce timer (going to battery lost) */ if (fxo->battery == BATTERY_PRESENT) { if (fxo->battdebounce) { /* we were going to BATTERY_LOST, but battery appeared again, so clear the debounce timer */ fxo->battdebounce = 0; } } else { if (fxo->battdebounce) { /* going to BATTERY_PRESENT, see if we are there yet */ if (--fxo->battdebounce == 0) { fxo->battery = BATTERY_PRESENT; if (debug) { dev_info(&wc->vb.pdev->dev, "BATTERY on %d/%d (%s)!\n", wc->aspan->span.spanno, mod->card + 1, (b < 0) ? "-" : "+"); } #ifdef ZERO_BATT_RING if (wc->onhook) { wc->onhook = 0; mod_hooksig(wc, mod, DAHDI_RXSIG_OFFHOOK); if (debug) dev_info(&wc->vb.pdev->dev, "Signalled Off Hook\n"); } #else mod_hooksig(wc, mod, DAHDI_RXSIG_OFFHOOK); #endif /* set the alarm timer, taking into account that part of its time period has already passed while debouncing occurred */ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK; } } else { /* start the debounce timer to verify that battery has appeared */ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK; } } if (fxo->lastpol >= 0) { if (b < 0) { fxo->lastpol = -1; fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; } } if (fxo->lastpol <= 0) { if (b > 0) { fxo->lastpol = 1; fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; } } } if (fxo->battalarm) { if (--fxo->battalarm == 0) { /* the alarm timer has expired, so update the battery alarm state for this channel */ dahdi_alarm_channel(get_dahdi_chan(wc, mod), (fxo->battery == BATTERY_LOST) ? DAHDI_ALARM_RED : DAHDI_ALARM_NONE); } } if (fxo->polaritydebounce) { fxo->polaritydebounce--; if (fxo->polaritydebounce < 1) { if (fxo->lastpol != fxo->polarity) { if (debug & DEBUG_CARD) dev_info(&wc->vb.pdev->dev, "%lu Polarity reversed (%d -> %d)\n", jiffies, fxo->polarity, fxo->lastpol); if (fxo->polarity) dahdi_qevent_lock(get_dahdi_chan(wc, mod), DAHDI_EVENT_POLARITY); fxo->polarity = fxo->lastpol; } } } /* Look for neon mwi pulse */ if (neonmwi_monitor && !fxo->offhook) { /* Look for 4 consecutive voltage readings * where the voltage is over the neon limit but * does not vary greatly from the last reading */ if (fxo->battery == 1 && abs_voltage > neonmwi_level && (0 == fxo->neonmwi_last_voltage || (b >= fxo->neonmwi_last_voltage - neonmwi_envelope && b <= fxo->neonmwi_last_voltage + neonmwi_envelope ))) { fxo->neonmwi_last_voltage = b; if (NEONMWI_ON_DEBOUNCE == fxo->neonmwi_debounce) { fxo->neonmwi_offcounter = neonmwi_offlimit_cycles; if (0 == fxo->neonmwi_state) { dahdi_qevent_lock(get_dahdi_chan(wc, mod), DAHDI_EVENT_NEONMWI_ACTIVE); fxo->neonmwi_state = 1; if (debug) dev_info(&wc->vb.pdev->dev, "NEON MWI active for card %d\n", mod->card+1); } fxo->neonmwi_debounce++; /* terminate the processing */ } else if (NEONMWI_ON_DEBOUNCE > fxo->neonmwi_debounce) { fxo->neonmwi_debounce++; } else { /* Insure the count gets reset */ fxo->neonmwi_offcounter = neonmwi_offlimit_cycles; } } else { fxo->neonmwi_debounce = 0; fxo->neonmwi_last_voltage = 0; } /* If no neon mwi pulse for given period of time, indicte no neon mwi state */ if (fxo->neonmwi_state && 0 < fxo->neonmwi_offcounter ) { fxo->neonmwi_offcounter--; if (0 == fxo->neonmwi_offcounter) { dahdi_qevent_lock(get_dahdi_chan(wc, mod), DAHDI_EVENT_NEONMWI_INACTIVE); fxo->neonmwi_state = 0; if (debug) dev_info(&wc->vb.pdev->dev, "NEON MWI cleared for card %d\n", mod->card+1); } } } #undef MS_PER_CHECK_HOOK } static void wctdm_fxs_hooksig(struct wctdm *wc, struct wctdm_module *const mod, enum dahdi_txsig txsig) { int x = 0; unsigned long flags; struct fxs *const fxs = &mod->mod.fxs; spin_lock_irqsave(&wc->reglock, flags); switch (txsig) { case DAHDI_TXSIG_ONHOOK: switch (get_dahdi_chan(wc, mod)->sig) { case DAHDI_SIG_EM: case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: x = fxs->idletxhookstate; break; case DAHDI_SIG_FXOGS: x = (POLARITY_XOR(fxs)) ? SLIC_LF_RING_OPEN : SLIC_LF_TIP_OPEN; break; default: WARN_ONCE(1, "%x is an invalid signaling state for " "an FXS module.\n", get_dahdi_chan(wc, mod)->sig); break; } break; case DAHDI_TXSIG_OFFHOOK: switch (get_dahdi_chan(wc, mod)->sig) { case DAHDI_SIG_EM: x = (POLARITY_XOR(fxs)) ? SLIC_LF_ACTIVE_FWD : SLIC_LF_ACTIVE_REV; break; default: x = fxs->idletxhookstate; break; } break; case DAHDI_TXSIG_START: x = SLIC_LF_RINGING; break; case DAHDI_TXSIG_KEWL: x = SLIC_LF_OPEN; break; default: spin_unlock_irqrestore(&wc->reglock, flags); dev_notice(&wc->vb.pdev->dev, "wctdm24xxp: Can't set tx state to %d\n", txsig); return; } if (x != fxs->lasttxhook) { fxs->lasttxhook = x | SLIC_LF_OPPENDING; mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); spin_unlock_irqrestore(&wc->reglock, flags); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Setting FXS hook state " "to %d (%02x) intcount=%d\n", txsig, x, wc->intcount); } } else { spin_unlock_irqrestore(&wc->reglock, flags); } } static void wctdm_fxs_off_hook(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; if (debug & DEBUG_CARD) dev_info(&wc->vb.pdev->dev, "fxs_off_hook: Card %d Going off hook\n", mod->card); switch (fxs->lasttxhook) { case SLIC_LF_RINGING: /* Ringing */ case SLIC_LF_OHTRAN_FWD: /* Forward On Hook Transfer */ case SLIC_LF_OHTRAN_REV: /* Reverse On Hook Transfer */ /* just detected OffHook, during Ringing or OnHookTransfer */ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; break; } if ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN) wctdm_fxs_hooksig(wc, mod, DAHDI_TXSIG_OFFHOOK); dahdi_hooksig(get_dahdi_chan(wc, mod), DAHDI_RXSIG_OFFHOOK); #ifdef DEBUG if (robust) wctdm_init_proslic(wc, mod, 1, 0, 1); #endif fxs->oldrxhook = 1; } /** * wctdm_fxs_on_hook - Report on hook to DAHDI. * @wc: Board hosting the module. * @card: Index of the module / port to place on hook. * * If we are intentionally dropping battery to signal a forward * disconnect we do not want to place the line "On-Hook". In this * case, the core of DAHDI will place us on hook when one of the RBS * timers expires. * */ static void wctdm_fxs_on_hook(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "fxs_on_hook: Card %d Going on hook\n", mod->card); } if ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN) wctdm_fxs_hooksig(wc, mod, DAHDI_TXSIG_ONHOOK); dahdi_hooksig(get_dahdi_chan(wc, mod), DAHDI_RXSIG_ONHOOK); fxs->oldrxhook = 0; } static void wctdm_proslic_check_hook(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; char res; int hook; /* For some reason we have to debounce the hook detector. */ res = mod->isrshadow[0]; /* Hook state */ hook = (res & 1); if (hook != fxs->lastrxhook) { /* Reset the debounce (must be multiple of 4ms) */ fxs->debounce = 8 * (4 * 8); #if 0 dev_info(&wc->vb.pdev->dev, "Resetting debounce card %d hook %d, %d\n", card, hook, fxs->debounce); #endif } else { if (fxs->debounce > 0) { fxs->debounce -= 4 * DAHDI_CHUNKSIZE; #if 0 dev_info(&wc->vb.pdev->dev, "Sustaining hook %d, %d\n", hook, fxs->debounce); #endif if (!fxs->debounce) { #if 0 dev_info(&wc->vb.pdev->dev, "Counted down debounce, newhook: %d...\n", hook); #endif fxs->debouncehook = hook; } if (!fxs->oldrxhook && fxs->debouncehook) wctdm_fxs_off_hook(wc, mod); else if (fxs->oldrxhook && !fxs->debouncehook) wctdm_fxs_on_hook(wc, mod); } } fxs->lastrxhook = hook; } static const char *wctdm_echocan_name(const struct dahdi_chan *chan) { struct wctdm *wc = chan->pvt; if (wc->vpmadt032) return vpmadt032_name; else if (wc->vpmoct) return vpmoct_name; return NULL; } static int wctdm_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { struct wctdm *wc = chan->pvt; struct wctdm_chan *wchan = container_of(chan, struct wctdm_chan, chan); const struct dahdi_echocan_ops *ops; const struct dahdi_echocan_features *features; enum adt_companding comp; #ifdef VPM_SUPPORT if (!vpmsupport) return -ENODEV; #endif if (wc->vpmadt032) { ops = &vpm_ec_ops; features = &vpm_ec_features; *ec = &wchan->ec; (*ec)->ops = ops; (*ec)->features = *features; comp = (DAHDI_LAW_ALAW == chan->span->deflaw) ? ADT_COMP_ALAW : ADT_COMP_ULAW; return vpmadt032_echocan_create(wc->vpmadt032, wchan->timeslot, comp, ecp, p); } else if (wc->vpmoct) { ops = &vpm_ec_ops; features = &vpm_ec_features; *ec = &wchan->ec; (*ec)->ops = ops; (*ec)->features = *features; return vpmoct_echocan_create(wc->vpmoct, wchan->timeslot, chan->span->deflaw); } else { return -ENODEV; } } static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct wctdm *wc = chan->pvt; struct wctdm_chan *wchan = container_of(chan, struct wctdm_chan, chan); if (wc->vpmadt032) { memset(ec, 0, sizeof(*ec)); vpmadt032_echocan_free(wc->vpmadt032, wchan->timeslot, ec); } else if (wc->vpmoct) { memset(ec, 0, sizeof(*ec)); vpmoct_echocan_free(wc->vpmoct, wchan->timeslot); } } /* 1ms interrupt */ static void wctdm_isr_misc_fxs(struct wctdm *wc, struct wctdm_module *const mod) { struct fxs *const fxs = &mod->mod.fxs; if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ if (fxs->palarms) fxs->palarms--; } wctdm_proslic_check_hook(wc, mod); wctdm_proslic_check_oppending(wc, mod); if (!(wc->intcount & 0xfc)) /* every 256ms */ wctdm_proslic_recheck_sanity(wc, mod); if (SLIC_LF_RINGING == fxs->lasttxhook) { /* RINGing, prepare for OHT */ fxs->ohttimer = OHT_TIMER << 3; /* OHT mode when idle */ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; } else if (fxs->ohttimer) { /* check if still OnHook */ if (!fxs->oldrxhook) { fxs->ohttimer -= DAHDI_CHUNKSIZE; if (fxs->ohttimer) return; /* Switch to active */ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; spin_lock(&wc->reglock); if (SLIC_LF_OHTRAN_FWD == fxs->lasttxhook) { /* Apply the change if appropriate */ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_FWD; /* Data enqueued here */ mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d OnHookTransfer " "stop\n", mod->card); } } else if (SLIC_LF_OHTRAN_REV == fxs->lasttxhook) { /* Apply the change if appropriate */ fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_REV; /* Data enqueued here */ mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d OnHookTransfer " "stop\n", mod->card); } } spin_unlock(&wc->reglock); } else { fxs->ohttimer = 0; /* Switch to active */ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d OnHookTransfer abort\n", mod->card); } } } } /* 1ms interrupt */ static inline void wctdm_isr_misc(struct wctdm *wc) { int x; if (unlikely(!is_initialized(wc))) return; for (x = 0; x < wc->mods_per_board; x++) { struct wctdm_module *const mod = &wc->mods[x]; spin_lock(&wc->reglock); cmd_checkisr(wc, mod); spin_unlock(&wc->reglock); switch (mod->type) { case FXS: wctdm_isr_misc_fxs(wc, mod); break; case FXO: wctdm_voicedaa_check_hook(wc, mod); break; case QRV: wctdm_qrvdri_check_hook(wc, x); break; default: break; } } } static void handle_receive(struct voicebus *vb, struct list_head *buffers) { struct wctdm *wc = container_of(vb, struct wctdm, vb); struct vbb *vbb; list_for_each_entry(vbb, buffers, entry) wctdm_receiveprep(wc, vbb->data); } static void handle_transmit(struct voicebus *vb, struct list_head *buffers) { struct wctdm *wc = container_of(vb, struct wctdm, vb); struct vbb *vbb; list_for_each_entry(vbb, buffers, entry) { memset(vbb->data, 0, sizeof(vbb->data)); wctdm_transmitprep(wc, vbb->data); wctdm_isr_misc(wc); wc->intcount++; } } struct sframe_packet { struct list_head node; u8 sframe[SFRAME_SIZE]; }; /** * handle_hx8_bootmode_receive() - queue up the receive packet for later... * * This function is called from interrupt context and isn't optimal, but it's * not the main code path. */ static void handle_hx8_bootmode_receive(struct wctdm *wc, const void *vbb) { struct sframe_packet *frame; frame = kzalloc(sizeof(*frame), GFP_ATOMIC); if (unlikely(!frame)) { WARN_ON(1); return; } memcpy(frame->sframe, vbb, sizeof(frame->sframe)); spin_lock(&wc->frame_list_lock); list_add_tail(&frame->node, &wc->frame_list); spin_unlock(&wc->frame_list_lock); /* Wake up anyone waiting for a new packet. */ wake_up(&wc->regq); return; } static void handle_hx8_receive(struct voicebus *vb, struct list_head *buffers) { struct wctdm *wc = container_of(vb, struct wctdm, vb); struct vbb *vbb; list_for_each_entry(vbb, buffers, entry) handle_hx8_bootmode_receive(wc, vbb->data); } static void handle_hx8_transmit(struct voicebus *vb, struct list_head *buffers) { struct vbb *vbb, *n; list_for_each_entry_safe(vbb, n, buffers, entry) { list_del(&vbb->entry); dma_pool_free(vb->pool, vbb, vbb->dma_addr); } } static int wctdm_voicedaa_insane(struct wctdm *wc, struct wctdm_module *mod) { int blah; blah = wctdm_getreg(wc, mod, 2); if (blah != 0x3) return -2; blah = wctdm_getreg(wc, mod, 11); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "VoiceDAA System: %02x\n", blah & 0xf); } return 0; } static int wctdm_proslic_insane(struct wctdm *wc, struct wctdm_module *const mod) { int blah, reg1, insane_report; insane_report=0; blah = wctdm_getreg(wc, mod, 0); if (blah != 0xff && (debug & DEBUG_CARD)) { dev_info(&wc->vb.pdev->dev, "ProSLIC on module %d, product %d, " "version %d\n", mod->card, (blah & 0x30) >> 4, (blah & 0xf)); } #if 0 if ((blah & 0x30) >> 4) { dev_info(&wc->vb.pdev->dev, "ProSLIC on module %d is not a 3210.\n", mod->card); return -1; } #endif if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { /* SLIC not loaded */ return -1; } /* let's be really sure this is an FXS before we continue */ reg1 = wctdm_getreg(wc, mod, 1); if ((0x80 != (blah & 0xf0)) || (0x88 != reg1)) { if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "DEBUG: not FXS b/c reg0=%x or " "reg1 != 0x88 (%x).\n", blah, reg1); } return -1; } blah = wctdm_getreg(wc, mod, 8); if (blah != 0x2) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d insane (1) %d should be 2\n", mod->card, blah); return -1; } else if (insane_report) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d Reg 8 Reads %d Expected " "is 0x2\n", mod->card, blah); } blah = wctdm_getreg(wc, mod, 64); if (blah != 0x0) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d insane (2)\n", mod->card); return -1; } else if (insane_report) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d Reg 64 Reads %d Expected " "is 0x0\n", mod->card, blah); } blah = wctdm_getreg(wc, mod, 11); if (blah != 0x33) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d insane (3)\n", mod->card); return -1; } else if (insane_report) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d Reg 11 Reads %d " "Expected is 0x33\n", mod->card, blah); } /* Just be sure it's setup right. */ wctdm_setreg(wc, mod, 30, 0); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "ProSLIC on module %d seems sane.\n", mod->card); } return 0; } static int wctdm_proslic_powerleak_test(struct wctdm *wc, struct wctdm_module *const mod) { unsigned long start; unsigned char vbat; /* Turn off linefeed */ wctdm_setreg(wc, mod, LINE_STATE, 0); /* Power down */ wctdm_setreg(wc, mod, 14, 0x10); start = jiffies; /* TODO: Why is this sleep necessary. Without it, the first read * comes back with a 0 value. */ msleep(20); while ((vbat = wctdm_getreg(wc, mod, 82)) > 0x6) { if (time_after(jiffies, start + HZ/4)) break; } if (vbat < 0x06) { dev_notice(&wc->vb.pdev->dev, "Excessive leakage detected on module %d: %d " "volts (%02x) after %d ms\n", mod->card, 376 * vbat / 1000, vbat, (int)((jiffies - start) * 1000 / HZ)); return -1; } else if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Post-leakage voltage: %d volts\n", 376 * vbat / 1000); } return 0; } static int wctdm_powerup_proslic(struct wctdm *wc, struct wctdm_module *mod, int fast) { unsigned char vbat; unsigned long origjiffies; int lim; /* Set period of DC-DC converter to 1/64 khz */ wctdm_setreg(wc, mod, 92, 0xc0 /* was 0xff */); /* Wait for VBat to powerup */ origjiffies = jiffies; /* Disable powerdown */ wctdm_setreg(wc, mod, 14, 0); /* If fast, don't bother checking anymore */ if (fast) return 0; while ((vbat = wctdm_getreg(wc, mod, 82)) < 0xc0) { /* Wait no more than 500ms */ if ((jiffies - origjiffies) > HZ/2) { break; } } if (vbat < 0xc0) { dev_notice(&wc->vb.pdev->dev, "ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE TDM CARD??\n", mod->card, (int)(((jiffies - origjiffies) * 1000 / HZ)), vbat * 375); return -1; } else if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "ProSLIC on module %d powered up to -%d volts (%02x) " "in %d ms\n", mod->card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); } /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */ /* If out of range, just set it to the default value */ lim = (loopcurrent - 20) / 3; if ( loopcurrent > 41 ) { lim = 0; if (debug & DEBUG_CARD) dev_info(&wc->vb.pdev->dev, "Loop current out of range! Setting to default 20mA!\n"); } else if (debug & DEBUG_CARD) dev_info(&wc->vb.pdev->dev, "Loop current set to %dmA!\n",(lim*3)+20); wctdm_setreg(wc, mod, LOOP_I_LIMIT, lim); /* Engage DC-DC converter */ wctdm_setreg(wc, mod, 93, 0x19 /* was 0x19 */); return 0; } static int wctdm_proslic_manual_calibrate(struct wctdm *wc, struct wctdm_module *const mod) { unsigned long origjiffies; unsigned char i; /* Disable all interupts in DR21-23 */ wctdm_setreg(wc, mod, 21, 0); wctdm_setreg(wc, mod, 22, 0); wctdm_setreg(wc, mod, 23, 0); wctdm_setreg(wc, mod, 64, 0); /* (0x18) Calibrations without the ADC and DAC offset and without * common mode calibration. */ wctdm_setreg(wc, mod, 97, 0x18); /* (0x47) Calibrate common mode and differential DAC mode DAC + ILIM */ wctdm_setreg(wc, mod, 96, 0x47); origjiffies=jiffies; while (wctdm_getreg(wc, mod, 96) != 0) { if ((jiffies-origjiffies) > 80) return -1; } //Initialized DR 98 and 99 to get consistant results. // 98 and 99 are the results registers and the search should have same intial conditions. /*******************************The following is the manual gain mismatch calibration****************************/ /*******************************This is also available as a function *******************************************/ msleep(10); wctdm_proslic_setreg_indirect(wc, mod, 88, 0); wctdm_proslic_setreg_indirect(wc, mod, 89, 0); wctdm_proslic_setreg_indirect(wc, mod, 90, 0); wctdm_proslic_setreg_indirect(wc, mod, 91, 0); wctdm_proslic_setreg_indirect(wc, mod, 92, 0); wctdm_proslic_setreg_indirect(wc, mod, 93, 0); /* This is necessary if the calibration occurs other than at reset */ wctdm_setreg(wc, mod, 98, 0x10); wctdm_setreg(wc, mod, 99, 0x10); for ( i=0x1f; i>0; i--) { wctdm_setreg(wc, mod, 98, i); msleep(40); if ((wctdm_getreg(wc, mod, 88)) == 0) break; } // for for ( i=0x1f; i>0; i--) { wctdm_setreg(wc, mod, 99, i); msleep(40); if ((wctdm_getreg(wc, mod, 89)) == 0) break; }//for /*******************************The preceding is the manual gain mismatch calibration****************************/ /**********************************The following is the longitudinal Balance Cal***********************************/ wctdm_setreg(wc, mod, 64, 1); msleep(100); wctdm_setreg(wc, mod, 64, 0); /* enable interrupt for the balance Cal */ wctdm_setreg(wc, mod, 23, 0x4); /* this is a singular calibration bit for longitudinal calibration */ wctdm_setreg(wc, mod, 97, 0x1); wctdm_setreg(wc, mod, 96, 0x40); wctdm_getreg(wc, mod, 96); /* Read Reg 96 just cause */ wctdm_setreg(wc, mod, 21, 0xFF); wctdm_setreg(wc, mod, 22, 0xFF); wctdm_setreg(wc, mod, 23, 0xFF); /**The preceding is the longitudinal Balance Cal***/ return(0); } static int wctdm_proslic_calibrate(struct wctdm *wc, struct wctdm_module *mod) { unsigned long origjiffies; int x; /* Perform all calibrations */ wctdm_setreg(wc, mod, 97, 0x1f); /* Begin, no speedup */ wctdm_setreg(wc, mod, 96, 0x5f); /* Wait for it to finish */ origjiffies = jiffies; while (wctdm_getreg(wc, mod, 96)) { if (time_after(jiffies, (origjiffies + (2*HZ)))) { dev_notice(&wc->vb.pdev->dev, "Timeout waiting for calibration of " "module %d\n", mod->card); return -1; } } if (debug & DEBUG_CARD) { /* Print calibration parameters */ dev_info(&wc->vb.pdev->dev, "Calibration Vector Regs 98 - 107:\n"); for (x=98;x<108;x++) { dev_info(&wc->vb.pdev->dev, "%d: %02x\n", x, wctdm_getreg(wc, mod, x)); } } return 0; } /********************************************************************* * Set the hwgain on the analog modules * * card = the card position for this module (0-23) * gain = gain in dB x10 (e.g. -3.5dB would be gain=-35) * tx = (0 for rx; 1 for tx) * *******************************************************************/ static int wctdm_set_hwgain(struct wctdm *wc, struct wctdm_module *mod, __s32 gain, __u32 tx) { if (mod->type != FXO) { dev_notice(&wc->vb.pdev->dev, "Cannot adjust gain. Unsupported module type!\n"); return -1; } if (tx) { if (debug) { dev_info(&wc->vb.pdev->dev, "setting FXO tx gain for card=%d to %d\n", mod->card, gain); } if (gain >= -150 && gain <= 0) { wctdm_setreg(wc, mod, 38, 16 + (gain / -10)); wctdm_setreg(wc, mod, 40, 16 + (-gain % 10)); } else if (gain <= 120 && gain > 0) { wctdm_setreg(wc, mod, 38, gain/10); wctdm_setreg(wc, mod, 40, (gain%10)); } else { dev_notice(&wc->vb.pdev->dev, "FXO tx gain is out of range (%d)\n", gain); return -1; } } else { /* rx */ if (debug) { dev_info(&wc->vb.pdev->dev, "setting FXO rx gain for card=%d to %d\n", mod->card, gain); } if (gain >= -150 && gain <= 0) { wctdm_setreg(wc, mod, 39, 16 + (gain / -10)); wctdm_setreg(wc, mod, 41, 16 + (-gain % 10)); } else if (gain <= 120 && gain > 0) { wctdm_setreg(wc, mod, 39, gain/10); wctdm_setreg(wc, mod, 41, (gain%10)); } else { dev_notice(&wc->vb.pdev->dev, "FXO rx gain is out of range (%d)\n", gain); return -1; } } return 0; } static int set_lasttxhook_interruptible(struct wctdm *wc, struct fxs *fxs, unsigned newval, int *psethook) { int res = 0; unsigned long flags; int timeout = 0; do { spin_lock_irqsave(&wc->reglock, flags); if (SLIC_LF_OPPENDING & fxs->lasttxhook) { spin_unlock_irqrestore(&wc->reglock, flags); if (timeout++ > 100) return -1; msleep(1); } else { fxs->lasttxhook = (newval & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING; *psethook = CMD_WR(LINE_STATE, fxs->lasttxhook); spin_unlock_irqrestore(&wc->reglock, flags); break; } } while (1); return res; } /* Must be called from within an interruptible context */ static int set_vmwi(struct wctdm *wc, struct wctdm_module *const mod) { int x; struct fxs *const fxs = &mod->mod.fxs; /* Presently only supports line reversal MWI */ if ((fxs->vmwi_active_messages) && (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV)) fxs->vmwi_linereverse = 1; else fxs->vmwi_linereverse = 0; /* Set line polarity for new VMWI state */ if (POLARITY_XOR(fxs)) { fxs->idletxhookstate |= SLIC_LF_REVMASK; /* Do not set while currently ringing or open */ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) && ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) { x = fxs->lasttxhook; x |= SLIC_LF_REVMASK; set_lasttxhook_interruptible(wc, fxs, x, &mod->sethook); } } else { fxs->idletxhookstate &= ~SLIC_LF_REVMASK; /* Do not set while currently ringing or open */ if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) && ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) { x = fxs->lasttxhook; x &= ~SLIC_LF_REVMASK; set_lasttxhook_interruptible(wc, fxs, x, &mod->sethook); } } if (debug) { dev_info(&wc->vb.pdev->dev, "Setting VMWI on channel %d, messages=%d, lrev=%d\n", mod->card, fxs->vmwi_active_messages, fxs->vmwi_linereverse); } return 0; } static void wctdm_voicedaa_set_ts(struct wctdm *wc, struct wctdm_module *mod, int ts) { wctdm_setreg(wc, mod, 34, (ts * 8) & 0xff); wctdm_setreg(wc, mod, 35, (ts * 8) >> 8); wctdm_setreg(wc, mod, 36, (ts * 8) & 0xff); wctdm_setreg(wc, mod, 37, (ts * 8) >> 8); if (debug) { dev_info(&wc->vb.pdev->dev, "voicedaa: card %d new timeslot: %d\n", mod->card + 1, ts); } } static int wctdm_init_voicedaa(struct wctdm *wc, struct wctdm_module *mod, int fast, int manual, int sane) { unsigned char reg16=0, reg26=0, reg30=0, reg31=0; unsigned long flags; long newjiffies; #if 0 /* TODO */ if ((wc->mods[card & 0xfc].type == QRV) || (wc->mods[card & 0xfc].type == BRI)) return -2; #endif spin_lock_irqsave(&wc->reglock, flags); mod->type = NONE; spin_unlock_irqrestore(&wc->reglock, flags); msleep(20); spin_lock_irqsave(&wc->reglock, flags); mod->type = FXO; spin_unlock_irqrestore(&wc->reglock, flags); msleep(20); if (!sane && wctdm_voicedaa_insane(wc, mod)) return -2; /* Software reset */ wctdm_setreg(wc, mod, 1, 0x80); msleep(100); /* Set On-hook speed, Ringer impedence, and ringer threshold */ reg16 |= (fxo_modes[_opermode].ohs << 6); reg16 |= (fxo_modes[_opermode].rz << 1); reg16 |= (fxo_modes[_opermode].rt); wctdm_setreg(wc, mod, 16, reg16); /* Enable ring detector full-wave rectifier mode */ wctdm_setreg(wc, mod, 18, 2); wctdm_setreg(wc, mod, 24, 0); /* Set DC Termination: Tip/Ring voltage adjust, minimum operational current, current limitation */ reg26 |= (fxo_modes[_opermode].dcv << 6); reg26 |= (fxo_modes[_opermode].mini << 4); reg26 |= (fxo_modes[_opermode].ilim << 1); wctdm_setreg(wc, mod, 26, reg26); /* Set AC Impedence */ reg30 = (fxo_modes[_opermode].acim); wctdm_setreg(wc, mod, 30, reg30); /* Misc. DAA parameters */ /* If fast pickup is set, then the off hook counter will be set to 8 * ms, otherwise 128 ms. */ reg31 = (fastpickup) ? 0xe3 : 0xa3; reg31 |= (fxo_modes[_opermode].ohs2 << 3); wctdm_setreg(wc, mod, 31, reg31); wctdm_voicedaa_set_ts(wc, mod, mod->card); /* Enable ISO-Cap */ wctdm_setreg(wc, mod, 6, 0x00); /* Turn off the calibration delay when fastpickup is enabled. */ if (fastpickup) wctdm_setreg(wc, mod, 17, wctdm_getreg(wc, mod, 17) | 0x20); /* Wait 1000ms for ISO-cap to come up */ newjiffies = jiffies; newjiffies += 2 * HZ; while ((jiffies < newjiffies) && !(wctdm_getreg(wc, mod, 11) & 0xf0)) msleep(100); if (!(wctdm_getreg(wc, mod, 11) & 0xf0)) { dev_notice(&wc->vb.pdev->dev, "VoiceDAA did not bring up ISO link properly!\n"); return -1; } if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "ISO-Cap is now up, line side: %02x rev %02x\n", wctdm_getreg(wc, mod, 11) >> 4, (wctdm_getreg(wc, mod, 13) >> 2) & 0xf); } /* Enable on-hook line monitor */ wctdm_setreg(wc, mod, 5, 0x08); /* Take values for fxotxgain and fxorxgain and apply them to module */ wctdm_set_hwgain(wc, mod, fxotxgain, 1); wctdm_set_hwgain(wc, mod, fxorxgain, 0); #ifdef DEBUG if (digitalloopback) { dev_info(&wc->vb.pdev->dev, "Turning on digital loopback for port %d.\n", mod->card + 1); wctdm_setreg(wc, mod, 10, 0x01); } #endif if (debug) { dev_info(&wc->vb.pdev->dev, "DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, mod, 38)/16) ? -(wctdm_getreg(wc, mod, 38) - 16) : wctdm_getreg(wc, mod, 38), (wctdm_getreg(wc, mod, 40)/16) ? -(wctdm_getreg(wc, mod, 40) - 16) : wctdm_getreg(wc, mod, 40), (wctdm_getreg(wc, mod, 39)/16) ? -(wctdm_getreg(wc, mod, 39) - 16) : wctdm_getreg(wc, mod, 39), (wctdm_getreg(wc, mod, 41)/16) ? -(wctdm_getreg(wc, mod, 41) - 16) : wctdm_getreg(wc, mod, 41)); } return 0; } static void wctdm_proslic_set_ts(struct wctdm *wc, struct wctdm_module *mod, int ts) { wctdm_setreg(wc, mod, 2, (ts * 8) & 0xff); /* Tx Start low byte 0 */ wctdm_setreg(wc, mod, 3, (ts * 8) >> 8); /* Tx Start high byte 0 */ wctdm_setreg(wc, mod, 4, (ts * 8) & 0xff); /* Rx Start low byte 0 */ wctdm_setreg(wc, mod, 5, (ts * 8) >> 8); /* Rx Start high byte 0 */ if (debug) { dev_info(&wc->vb.pdev->dev, "proslic: card %d new timeslot: %d\n", mod->card + 1, ts); } } static int wctdm_init_proslic(struct wctdm *wc, struct wctdm_module *const mod, int fast, int manual, int sane) { struct fxs *const fxs = &mod->mod.fxs; unsigned short tmp[5]; unsigned long flags; unsigned char r19,r9; int x; int fxsmode=0; int addresses[NUM_CAL_REGS]; #if 0 /* TODO */ if (wc->mods[mod->card & 0xfc].type == QRV) return -2; #endif spin_lock_irqsave(&wc->reglock, flags); mod->type = FXS; spin_unlock_irqrestore(&wc->reglock, flags); /* msleep(100); */ /* Sanity check the ProSLIC */ if (!sane && wctdm_proslic_insane(wc, mod)) return -2; /* Initialize VMWI settings */ memset(&(fxs->vmwisetting), 0, sizeof(fxs->vmwisetting)); fxs->vmwi_linereverse = 0; /* By default, don't send on hook */ if (!reversepolarity != !fxs->reversepolarity) fxs->idletxhookstate = SLIC_LF_ACTIVE_REV; else fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; if (sane) { /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ wctdm_setreg(wc, mod, 14, 0x10); } if (wctdm_proslic_init_indirect_regs(wc, mod)) { dev_info(&wc->vb.pdev->dev, "Indirect Registers failed to initialize on " "module %d.\n", mod->card); return -1; } /* Clear scratch pad area */ wctdm_proslic_setreg_indirect(wc, mod, 97, 0); /* Clear digital loopback */ wctdm_setreg(wc, mod, 8, 0); /* Revision C optimization */ wctdm_setreg(wc, mod, 108, 0xeb); /* Disable automatic VBat switching for safety to prevent * Q7 from accidently turning on and burning out. * If pulse dialing has trouble at high REN loads change this to 0x17 */ wctdm_setreg(wc, mod, 67, 0x07); /* Turn off Q7 */ wctdm_setreg(wc, mod, 66, 1); /* Flush ProSLIC digital filters by setting to clear, while saving old values */ for (x=0;x<5;x++) { tmp[x] = wctdm_proslic_getreg_indirect(wc, mod, x + 35); wctdm_proslic_setreg_indirect(wc, mod, x + 35, 0x8000); } /* Power up the DC-DC converter */ if (wctdm_powerup_proslic(wc, mod, fast)) { dev_notice(&wc->vb.pdev->dev, "Unable to do INITIAL ProSLIC powerup on " "module %d\n", mod->card); return -1; } if (!fast) { /* Check for power leaks */ if (wctdm_proslic_powerleak_test(wc, mod)) { dev_notice(&wc->vb.pdev->dev, "ProSLIC module %d failed leakage test. " "Check for short circuit\n", mod->card); } /* Power up again */ if (wctdm_powerup_proslic(wc, mod, fast)) { dev_notice(&wc->vb.pdev->dev, "Unable to do FINAL ProSLIC powerup on " "module %d\n", mod->card); return -1; } #ifndef NO_CALIBRATION /* Perform calibration */ if (manual) { if (wctdm_proslic_manual_calibrate(wc, mod)) { //dev_notice(&wc->vb.pdev->dev, "Proslic failed on Manual Calibration\n"); if (wctdm_proslic_manual_calibrate(wc, mod)) { dev_notice(&wc->vb.pdev->dev, "Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); return -1; } dev_info(&wc->vb.pdev->dev, "Proslic Passed Manual Calibration on Second Attempt\n"); } } else { if (wctdm_proslic_calibrate(wc, mod)) { //dev_notice(&wc->vb.pdev->dev, "ProSlic died on Auto Calibration.\n"); if (wctdm_proslic_calibrate(wc, mod)) { dev_notice(&wc->vb.pdev->dev, "Proslic Failed on Second Attempt to Auto Calibrate\n"); return -1; } dev_info(&wc->vb.pdev->dev, "Proslic Passed Auto Calibration on Second Attempt\n"); } } /* Perform DC-DC calibration */ wctdm_setreg(wc, mod, 93, 0x99); r19 = wctdm_getreg(wc, mod, 107); if ((r19 < 0x2) || (r19 > 0xd)) { dev_notice(&wc->vb.pdev->dev, "DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); wctdm_setreg(wc, mod, 107, 0x8); } /* Save calibration vectors */ for (x = 0; x < NUM_CAL_REGS; x++) addresses[x] = 96 + x; wctdm_getregs(wc, mod, addresses, ARRAY_SIZE(addresses)); for (x = 0; x < NUM_CAL_REGS; x++) fxs->calregs.vals[x] = addresses[x]; #endif } else { /* Restore calibration registers */ for (x = 0; x < NUM_CAL_REGS; x++) wctdm_setreg(wc, mod, 96 + x, fxs->calregs.vals[x]); } /* Calibration complete, restore original values */ for (x=0;x<5;x++) { wctdm_proslic_setreg_indirect(wc, mod, x + 35, tmp[x]); } if (wctdm_proslic_verify_indirect_regs(wc, mod)) { dev_info(&wc->vb.pdev->dev, "Indirect Registers failed verification.\n"); return -1; } #if 0 /* Disable Auto Power Alarm Detect and other "features" */ wctdm_setreg(wc, card, 67, 0x0e); blah = wctdm_getreg(wc, card, 67); #endif #if 0 if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix dev_info(&wc->vb.pdev->dev, "ProSlic IndirectReg Died.\n"); return -1; } #endif /* U-Law 8-bit interface */ wctdm_proslic_set_ts(wc, mod, mod->card); wctdm_setreg(wc, mod, 18, 0xff); /* clear all interrupt */ wctdm_setreg(wc, mod, 19, 0xff); wctdm_setreg(wc, mod, 20, 0xff); wctdm_setreg(wc, mod, 22, 0xff); wctdm_setreg(wc, mod, 73, 0x04); if (fxshonormode) { static const int ACIM2TISS[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; fxsmode = ACIM2TISS[fxo_modes[_opermode].acim]; wctdm_setreg(wc, mod, 10, 0x08 | fxsmode); if (fxo_modes[_opermode].ring_osc) { wctdm_proslic_setreg_indirect(wc, mod, 20, fxo_modes[_opermode].ring_osc); } if (fxo_modes[_opermode].ring_x) { wctdm_proslic_setreg_indirect(wc, mod, 21, fxo_modes[_opermode].ring_x); } } if (lowpower) wctdm_setreg(wc, mod, 72, 0x10); #if 0 wctdm_setreg(wc, card, 21, 0x00); // enable interrupt wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt #endif #if 0 /* Enable loopback */ wctdm_setreg(wc, card, 8, 0x2); wctdm_setreg(wc, card, 14, 0x0); wctdm_setreg(wc, card, 64, 0x0); wctdm_setreg(wc, card, 1, 0x08); #endif if (fastringer) { /* Speed up Ringer */ wctdm_proslic_setreg_indirect(wc, mod, 20, 0x7e6d); wctdm_proslic_setreg_indirect(wc, mod, 21, 0x01b9); /* Beef up Ringing voltage to 89V */ if (boostringer) { wctdm_setreg(wc, mod, 74, 0x3f); if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x247)) return -1; dev_info(&wc->vb.pdev->dev, "Boosting fast ringer on slot %d (89V peak)\n", mod->card + 1); } else if (lowpower) { if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x14b)) return -1; dev_info(&wc->vb.pdev->dev, "Reducing fast ring power on slot %d " "(50V peak)\n", mod->card + 1); } else dev_info(&wc->vb.pdev->dev, "Speeding up ringer on slot %d (25Hz)\n", mod->card + 1); } else { /* Beef up Ringing voltage to 89V */ if (boostringer) { wctdm_setreg(wc, mod, 74, 0x3f); if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x1d1)) return -1; dev_info(&wc->vb.pdev->dev, "Boosting ringer on slot %d (89V peak)\n", mod->card + 1); } else if (lowpower) { if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x108)) return -1; dev_info(&wc->vb.pdev->dev, "Reducing ring power on slot %d " "(50V peak)\n", mod->card + 1); } } if (fxstxgain || fxsrxgain) { r9 = wctdm_getreg(wc, mod, 9); switch (fxstxgain) { case 35: r9+=8; break; case -35: r9+=4; break; case 0: break; } switch (fxsrxgain) { case 35: r9+=2; break; case -35: r9+=1; break; case 0: break; } wctdm_setreg(wc, mod, 9, r9); } if (debug) { dev_info(&wc->vb.pdev->dev, "DEBUG: fxstxgain:%s fxsrxgain:%s\n", ((wctdm_getreg(wc, mod, 9) / 8) == 1) ? "3.5" : (((wctdm_getreg(wc, mod, 9) / 4) == 1) ? "-3.5" : "0.0"), ((wctdm_getreg(wc, mod, 9) / 2) == 1) ? "3.5" : ((wctdm_getreg(wc, mod, 9) % 2) ? "-3.5" : "0.0")); } fxs->lasttxhook = fxs->idletxhookstate; wctdm_setreg(wc, mod, LINE_STATE, fxs->lasttxhook); /* Preset the isrshadow register so that we won't get a power alarm * when we finish initialization, otherwise the line state register * may not have been read yet. */ mod->isrshadow[1] = fxs->lasttxhook; return 0; } static void wctdm_qrvdri_set_ts(struct wctdm *wc, struct wctdm_module *mod, int ts) { wctdm_setreg(wc, mod, 0x13, ts + 0x80); /* codec 2 tx, ts0 */ wctdm_setreg(wc, mod, 0x17, ts + 0x80); /* codec 0 rx, ts0 */ wctdm_setreg(wc, mod, 0x14, ts + 0x81); /* codec 1 tx, ts1 */ wctdm_setreg(wc, mod, 0x18, ts + 0x81); /* codec 1 rx, ts1 */ if (debug) { dev_info(&wc->vb.pdev->dev, "qrvdri: card %d new timeslot: %d\n", mod->card + 1, ts); } } static int wctdm_init_qrvdri(struct wctdm *wc, int card) { struct wctdm_module *const mod = &wc->mods[card]; unsigned char x,y; if (BRI == wc->mods[card & 0xfc].type) return -2; /* have to set this, at least for now */ mod->type = QRV; if (!(card & 3)) { /* if at base of card, reset and write it */ struct qrv *const qrv = &mod->mod.qrv; struct qrv *const qrv1 = &wc->mods[card + 1].mod.qrv; struct qrv *const qrv2 = &wc->mods[card + 2].mod.qrv; struct qrv *const qrv3 = &wc->mods[card + 3].mod.qrv; wctdm_setreg(wc, mod, 0, 0x80); wctdm_setreg(wc, mod, 0, 0x55); wctdm_setreg(wc, mod, 1, 0x69); qrv->hook = qrv1->hook = 0; qrv2->hook = qrv3->hook = 0xff; qrv->debouncetime = qrv1->debouncetime = QRV_DEBOUNCETIME; qrv->debtime = qrv1->debtime = 0; qrv->radmode = qrv1->radmode = 0; qrv->txgain = qrv1->txgain = 3599; qrv->rxgain = qrv1->rxgain = 1199; } else { /* channel is on same card as base, no need to test */ if (wc->mods[card & 0x7c].type == QRV) { /* only lower 2 are valid */ if (!(card & 2)) return 0; } mod->type = NONE; return 1; } x = wctdm_getreg(wc, mod, 0); y = wctdm_getreg(wc, mod, 1); /* if not a QRV card, return as such */ if ((x != 0x55) || (y != 0x69)) { mod->type = NONE; return 1; } for (x = 0; x < 0x30; x++) { if ((x >= 0x1c) && (x <= 0x1e)) wctdm_setreg(wc, mod, x, 0xff); else wctdm_setreg(wc, mod, x, 0); } wctdm_setreg(wc, mod, 0, 0x80); msleep(100); wctdm_setreg(wc, mod, 0, 0x10); wctdm_setreg(wc, mod, 0, 0x10); msleep(100); /* set up modes */ wctdm_setreg(wc, mod, 0, 0x1c); /* set up I/O directions */ wctdm_setreg(wc, mod, 1, 0x33); wctdm_setreg(wc, mod, 2, 0x0f); wctdm_setreg(wc, mod, 5, 0x0f); /* set up I/O to quiescent state */ wctdm_setreg(wc, mod, 3, 0x11); /* D0-7 */ wctdm_setreg(wc, mod, 4, 0xa); /* D8-11 */ wctdm_setreg(wc, mod, 7, 0); /* CS outputs */ wctdm_qrvdri_set_ts(wc, mod, card); /* set up for max gains */ wctdm_setreg(wc, mod, 0x26, 0x24); wctdm_setreg(wc, mod, 0x27, 0x24); wctdm_setreg(wc, mod, 0x0b, 0x01); /* "Transmit" gain codec 0 */ wctdm_setreg(wc, mod, 0x0c, 0x01); /* "Transmit" gain codec 1 */ wctdm_setreg(wc, mod, 0x0f, 0xff); /* "Receive" gain codec 0 */ wctdm_setreg(wc, mod, 0x10, 0xff); /* "Receive" gain codec 1 */ return 0; } static void qrv_dosetup(struct dahdi_chan *chan, struct wctdm *wc) { struct wctdm_module *qrvmod; struct wctdm_module *nextqrvmod; int qrvcard; unsigned char r; long l; /* actually do something with the values */ qrvcard = (chan->chanpos - 1) & 0xfc; qrvmod = &wc->mods[qrvcard]; nextqrvmod = &wc->mods[qrvcard + 1]; if (debug) { dev_info(&wc->vb.pdev->dev, "@@@@@ radmodes: %d,%d rxgains: %d,%d " "txgains: %d,%d\n", wc->mods[qrvcard].mod.qrv.radmode, nextqrvmod->mod.qrv.radmode, wc->mods[qrvcard].mod.qrv.rxgain, nextqrvmod->mod.qrv.rxgain, wc->mods[qrvcard].mod.qrv.txgain, nextqrvmod->mod.qrv.txgain); } r = 0; if (qrvmod->mod.qrv.radmode & RADMODE_DEEMP) r |= 4; if (nextqrvmod->mod.qrv.radmode & RADMODE_DEEMP) r |= 8; if (qrvmod->mod.qrv.rxgain < 1200) r |= 1; if (nextqrvmod->mod.qrv.rxgain < 1200) r |= 2; wctdm_setreg(wc, qrvmod, 7, r); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 7 to %02x hex\n",r); r = 0; if (qrvmod->mod.qrv.radmode & RADMODE_PREEMP) r |= 3; else if (qrvmod->mod.qrv.txgain >= 3600) r |= 1; else if (qrvmod->mod.qrv.txgain >= 1200) r |= 2; if (nextqrvmod->mod.qrv.radmode & RADMODE_PREEMP) r |= 0xc; else if (nextqrvmod->mod.qrv.txgain >= 3600) r |= 4; else if (nextqrvmod->mod.qrv.txgain >= 1200) r |= 8; wctdm_setreg(wc, qrvmod, 4, r); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 4 to %02x hex\n",r); r = 0; if (qrvmod->mod.qrv.rxgain >= 2400) r |= 1; if (nextqrvmod->mod.qrv.rxgain >= 2400) r |= 2; wctdm_setreg(wc, qrvmod, 0x25, r); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x25 to %02x hex\n",r); r = 0; if (qrvmod->mod.qrv.txgain < 2400) r |= 1; else r |= 4; if (nextqrvmod->mod.qrv.txgain < 2400) r |= 8; else r |= 0x20; wctdm_setreg(wc, qrvmod, 0x26, r); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x26 to %02x hex\n",r); l = ((long)(qrvmod->mod.qrv.rxgain % 1200) * 10000) / 46875; if (l == 0) l = 1; if (qrvmod->mod.qrv.rxgain >= 2400) l += 181; wctdm_setreg(wc, qrvmod, 0x0b, (unsigned char)l); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x0b to %02x hex\n",(unsigned char)l); l = ((long)(nextqrvmod->mod.qrv.rxgain % 1200) * 10000) / 46875; if (l == 0) l = 1; if (nextqrvmod->mod.qrv.rxgain >= 2400) l += 181; wctdm_setreg(wc, qrvmod, 0x0c, (unsigned char)l); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x0c to %02x hex\n",(unsigned char)l); l = ((long)(qrvmod->mod.qrv.txgain % 1200) * 10000) / 46875; if (l == 0) l = 1; wctdm_setreg(wc, qrvmod, 0x0f, (unsigned char)l); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x0f to %02x hex\n", (unsigned char)l); l = ((long)(nextqrvmod->mod.qrv.txgain % 1200) * 10000) / 46875; if (l == 0) l = 1; wctdm_setreg(wc, qrvmod, 0x10, (unsigned char)l); if (debug) dev_info(&wc->vb.pdev->dev, "@@@@@ setting reg 0x10 to %02x hex\n",(unsigned char)l); return; } static void wctdm24xxp_get_fxs_regs(struct wctdm *wc, struct wctdm_module *mod, struct wctdm_regs *regs) { int x; for (x = 0; x < NUM_INDIRECT_REGS; x++) regs->indirect[x] = wctdm_proslic_getreg_indirect(wc, mod, x); for (x = 0; x < NUM_REGS; x++) regs->direct[x] = wctdm_getreg(wc, mod, x); } static void wctdm24xxp_get_fxo_regs(struct wctdm *wc, struct wctdm_module *mod, struct wctdm_regs *regs) { int x; for (x = 0; x < NUM_FXO_REGS; x++) regs->direct[x] = wctdm_getreg(wc, mod, x); } static void wctdm24xxp_get_qrv_regs(struct wctdm *wc, struct wctdm_module *mod, struct wctdm_regs *regs) { int x; for (x = 0; x < 0x32; x++) regs->direct[x] = wctdm_getreg(wc, mod, x); } static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { struct wctdm_stats stats; struct wctdm_regop regop; struct wctdm_echo_coefs echoregs; struct dahdi_hwgain hwgain; struct wctdm *wc = chan->pvt; int x; union { struct dahdi_radio_stat s; struct dahdi_radio_param p; } stack; struct wctdm_module *const mod = &wc->mods[chan->chanpos - 1]; struct fxs *const fxs = &mod->mod.fxs; switch (cmd) { case DAHDI_ONHOOKTRANSFER: if (mod->type != FXS) return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; fxs->ohttimer = x << 3; /* Active mode when idle */ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) || ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) { x = set_lasttxhook_interruptible(wc, fxs, (POLARITY_XOR(fxs) ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD), &mod->sethook); if (debug & DEBUG_CARD) { if (x) { dev_info(&wc->vb.pdev->dev, "Channel %d TIMEOUT: " "OnHookTransfer start\n", chan->chanpos - 1); } else { dev_info(&wc->vb.pdev->dev, "Channel %d OnHookTransfer " "start\n", chan->chanpos - 1); } } } break; case DAHDI_VMWI_CONFIG: if (mod->type != FXS) return -EINVAL; if (copy_from_user(&(fxs->vmwisetting), (__user void *)data, sizeof(fxs->vmwisetting))) return -EFAULT; set_vmwi(wc, mod); break; case DAHDI_VMWI: if (mod->type != FXS) return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; if (0 > x) return -EFAULT; fxs->vmwi_active_messages = x; set_vmwi(wc, mod); break; case WCTDM_GET_STATS: if (mod->type == FXS) { stats.tipvolt = wctdm_getreg(wc, mod, 80) * -376; stats.ringvolt = wctdm_getreg(wc, mod, 81) * -376; stats.batvolt = wctdm_getreg(wc, mod, 82) * -376; } else if (mod->type == FXO) { stats.tipvolt = (s8)wctdm_getreg(wc, mod, 29) * 1000; stats.ringvolt = (s8)wctdm_getreg(wc, mod, 29) * 1000; stats.batvolt = (s8)wctdm_getreg(wc, mod, 29) * 1000; } else return -EINVAL; if (copy_to_user((__user void *) data, &stats, sizeof(stats))) return -EFAULT; break; case WCTDM_GET_REGS: { struct wctdm_regs *regs = kzalloc(sizeof(*regs), GFP_KERNEL); if (!regs) return -ENOMEM; if (mod->type == FXS) wctdm24xxp_get_fxs_regs(wc, mod, regs); else if (mod->type == QRV) wctdm24xxp_get_qrv_regs(wc, mod, regs); else wctdm24xxp_get_fxo_regs(wc, mod, regs); if (copy_to_user((__user void *)data, regs, sizeof(*regs))) { kfree(regs); return -EFAULT; } kfree(regs); break; } case WCTDM_SET_REG: if (copy_from_user(®op, (__user void *) data, sizeof(regop))) return -EFAULT; if (regop.indirect) { if (mod->type != FXS) return -EINVAL; dev_info(&wc->vb.pdev->dev, "Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); wctdm_proslic_setreg_indirect(wc, mod, regop.reg, regop.val); } else { regop.val &= 0xff; if (regop.reg == LINE_STATE) { /* Set feedback register to indicate the new state that is being set */ fxs->lasttxhook = (regop.val & 0x0f) | SLIC_LF_OPPENDING; } dev_info(&wc->vb.pdev->dev, "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); wctdm_setreg(wc, mod, regop.reg, regop.val); } break; case WCTDM_SET_ECHOTUNE: dev_info(&wc->vb.pdev->dev, "-- Setting echo registers: \n"); if (copy_from_user(&echoregs, (__user void *) data, sizeof(echoregs))) return -EFAULT; if (mod->type == FXO) { /* Set the ACIM register */ wctdm_setreg(wc, mod, 30, echoregs.acim); /* Set the digital echo canceller registers */ wctdm_setreg(wc, mod, 45, echoregs.coef1); wctdm_setreg(wc, mod, 46, echoregs.coef2); wctdm_setreg(wc, mod, 47, echoregs.coef3); wctdm_setreg(wc, mod, 48, echoregs.coef4); wctdm_setreg(wc, mod, 49, echoregs.coef5); wctdm_setreg(wc, mod, 50, echoregs.coef6); wctdm_setreg(wc, mod, 51, echoregs.coef7); wctdm_setreg(wc, mod, 52, echoregs.coef8); dev_info(&wc->vb.pdev->dev, "-- Set echo registers successfully\n"); break; } else { return -EINVAL; } break; case DAHDI_SET_HWGAIN: if (copy_from_user(&hwgain, (__user void *) data, sizeof(hwgain))) return -EFAULT; wctdm_set_hwgain(wc, mod, hwgain.newgain, hwgain.tx); if (debug) dev_info(&wc->vb.pdev->dev, "Setting hwgain on channel %d to %d for %s direction\n", chan->chanpos-1, hwgain.newgain, hwgain.tx ? "tx" : "rx"); break; #ifdef VPM_SUPPORT case DAHDI_TONEDETECT: /* Hardware DTMF detection is not supported. */ return -ENOSYS; #endif case DAHDI_SETPOLARITY: if (get_user(x, (__user int *) data)) return -EFAULT; if (mod->type != FXS) return -EINVAL; /* Can't change polarity while ringing or when open */ if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_RINGING) || ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_OPEN)) { if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d Unable to Set Polarity\n", chan->chanpos - 1); } return -EINVAL; } fxs->reversepolarity = (x) ? 1 : 0; if (POLARITY_XOR(fxs)) { fxs->idletxhookstate |= SLIC_LF_REVMASK; x = fxs->lasttxhook & SLIC_LF_SETMASK; x |= SLIC_LF_REVMASK; if (x != fxs->lasttxhook) { x = set_lasttxhook_interruptible(wc, fxs, x, &mod->sethook); if ((debug & DEBUG_CARD) && x) { dev_info(&wc->vb.pdev->dev, "Channel %d TIMEOUT: Set Reverse " "Polarity\n", chan->chanpos - 1); } else if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d Set Reverse Polarity\n", chan->chanpos - 1); } } } else { fxs->idletxhookstate &= ~SLIC_LF_REVMASK; x = fxs->lasttxhook & SLIC_LF_SETMASK; x &= ~SLIC_LF_REVMASK; if (x != fxs->lasttxhook) { x = set_lasttxhook_interruptible(wc, fxs, x, &mod->sethook); if ((debug & DEBUG_CARD) & x) { dev_info(&wc->vb.pdev->dev, "Channel %d TIMEOUT: Set Normal " "Polarity\n", chan->chanpos - 1); } else if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d Set Normal Polarity\n", chan->chanpos - 1); } } } break; case DAHDI_RADIO_GETPARAM: if (mod->type != QRV) return -ENOTTY; if (copy_from_user(&stack.p, (__user void *) data, sizeof(stack.p))) return -EFAULT; stack.p.data = 0; /* start with 0 value in output */ switch(stack.p.radpar) { case DAHDI_RADPAR_INVERTCOR: if (mod->mod.qrv.radmode & RADMODE_INVERTCOR) stack.p.data = 1; break; case DAHDI_RADPAR_IGNORECOR: if (mod->mod.qrv.radmode & RADMODE_IGNORECOR) stack.p.data = 1; break; case DAHDI_RADPAR_IGNORECT: if (mod->mod.qrv.radmode & RADMODE_IGNORECT) stack.p.data = 1; break; case DAHDI_RADPAR_EXTRXTONE: stack.p.data = 0; if (mod->mod.qrv.radmode & RADMODE_EXTTONE) { stack.p.data = 1; if (mod->mod.qrv.radmode & RADMODE_EXTINVERT) stack.p.data = 2; } break; case DAHDI_RADPAR_DEBOUNCETIME: stack.p.data = mod->mod.qrv.debouncetime; break; case DAHDI_RADPAR_RXGAIN: stack.p.data = mod->mod.qrv.rxgain - 1199; break; case DAHDI_RADPAR_TXGAIN: stack.p.data = mod->mod.qrv.txgain - 3599; break; case DAHDI_RADPAR_DEEMP: stack.p.data = 0; if (mod->mod.qrv.radmode & RADMODE_DEEMP) stack.p.data = 1; break; case DAHDI_RADPAR_PREEMP: stack.p.data = 0; if (mod->mod.qrv.radmode & RADMODE_PREEMP) stack.p.data = 1; break; default: return -EINVAL; } if (copy_to_user((__user void *) data, &stack.p, sizeof(stack.p))) return -EFAULT; break; case DAHDI_RADIO_SETPARAM: if (mod->type != QRV) return -ENOTTY; if (copy_from_user(&stack.p, (__user void *) data, sizeof(stack.p))) return -EFAULT; switch(stack.p.radpar) { case DAHDI_RADPAR_INVERTCOR: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_INVERTCOR; else mod->mod.qrv.radmode &= ~RADMODE_INVERTCOR; return 0; case DAHDI_RADPAR_IGNORECOR: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_IGNORECOR; else mod->mod.qrv.radmode &= ~RADMODE_IGNORECOR; return 0; case DAHDI_RADPAR_IGNORECT: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_IGNORECT; else mod->mod.qrv.radmode &= ~RADMODE_IGNORECT; return 0; case DAHDI_RADPAR_EXTRXTONE: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_EXTTONE; else mod->mod.qrv.radmode &= ~RADMODE_EXTTONE; if (stack.p.data > 1) mod->mod.qrv.radmode |= RADMODE_EXTINVERT; else mod->mod.qrv.radmode &= ~RADMODE_EXTINVERT; return 0; case DAHDI_RADPAR_DEBOUNCETIME: mod->mod.qrv.debouncetime = stack.p.data; return 0; case DAHDI_RADPAR_RXGAIN: /* if out of range */ if ((stack.p.data <= -1200) || (stack.p.data > 1552)) { return -EINVAL; } mod->mod.qrv.rxgain = stack.p.data + 1199; break; case DAHDI_RADPAR_TXGAIN: /* if out of range */ if (mod->mod.qrv.radmode & RADMODE_PREEMP) { if ((stack.p.data <= -2400) || (stack.p.data > 0)) return -EINVAL; } else { if ((stack.p.data <= -3600) || (stack.p.data > 1200)) return -EINVAL; } mod->mod.qrv.txgain = stack.p.data + 3599; break; case DAHDI_RADPAR_DEEMP: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_DEEMP; else mod->mod.qrv.radmode &= ~RADMODE_DEEMP; mod->mod.qrv.rxgain = 1199; break; case DAHDI_RADPAR_PREEMP: if (stack.p.data) mod->mod.qrv.radmode |= RADMODE_PREEMP; else mod->mod.qrv.radmode &= ~RADMODE_PREEMP; mod->mod.qrv.txgain = 3599; break; default: return -EINVAL; } qrv_dosetup(chan,wc); return 0; default: return -ENOTTY; } return 0; } static int wctdm_open(struct dahdi_chan *chan) { struct wctdm *const wc = chan->pvt; unsigned long flags; struct wctdm_module *const mod = &wc->mods[chan->chanpos - 1]; #if 0 if (wc->dead) return -ENODEV; #endif if (mod->type == FXO) { /* Reset the mwi indicators */ spin_lock_irqsave(&wc->reglock, flags); mod->mod.fxo.neonmwi_debounce = 0; mod->mod.fxo.neonmwi_offcounter = 0; mod->mod.fxo.neonmwi_state = 0; spin_unlock_irqrestore(&wc->reglock, flags); } return 0; } static inline struct wctdm *span_to_wctdm(struct dahdi_span *span) { struct wctdm_span *s = container_of(span, struct wctdm_span, span); return s->wc; } static int wctdm_watchdog(struct dahdi_span *span, int event) { struct wctdm *wc = span_to_wctdm(span); dev_info(&wc->vb.pdev->dev, "TDM: Called watchdog\n"); return 0; } static int wctdm_close(struct dahdi_chan *chan) { struct wctdm *wc; int x; signed char reg; wc = chan->pvt; for (x = 0; x < wc->mods_per_board; x++) { struct wctdm_module *const mod = &wc->mods[x]; if (FXS == mod->type) { mod->mod.fxs.idletxhookstate = POLARITY_XOR(&mod->mod.fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; } else if (QRV == mod->type) { int qrvcard = x & 0xfc; mod->mod.qrv.hook = 0; wc->mods[x + 2].mod.qrv.hook = 0xff; mod->mod.qrv.debouncetime = QRV_DEBOUNCETIME; mod->mod.qrv.debtime = 0; mod->mod.qrv.radmode = 0; mod->mod.qrv.txgain = 3599; mod->mod.qrv.rxgain = 1199; reg = 0; if (!wc->mods[qrvcard].mod.qrv.hook) reg |= 1; if (!wc->mods[qrvcard + 1].mod.qrv.hook) reg |= 0x10; wc->mods[qrvcard].sethook = CMD_WR(3, reg); qrv_dosetup(chan,wc); } } return 0; } static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wctdm *wc = chan->pvt; int reg = 0; struct wctdm_module *const mod = &wc->mods[chan->chanpos - 1]; if (mod->type == QRV) { const int qrvcard = (chan->chanpos - 1) & 0xfc; switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: mod->mod.qrv.hook = 1; break; case DAHDI_TXSIG_ONHOOK: mod->mod.qrv.hook = 0; break; default: dev_notice(&wc->vb.pdev->dev, "wctdm24xxp: Can't set tx state to %d\n", txsig); } reg = 0; if (!wc->mods[qrvcard].mod.qrv.hook) reg |= 1; if (!wc->mods[qrvcard + 1].mod.qrv.hook) reg |= 0x10; wc->mods[qrvcard].sethook = CMD_WR(3, reg); /* wctdm_setreg(wc, qrvcard, 3, reg); */ } else if (mod->type == FXO) { switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: mod->mod.fxo.offhook = 1; mod->sethook = CMD_WR(5, 0x9); /* wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9); */ break; case DAHDI_TXSIG_ONHOOK: mod->mod.fxo.offhook = 0; mod->sethook = CMD_WR(5, 0x8); /* wctdm_setreg(wc, chan->chanpos - 1, 5, 0x8); */ break; default: dev_notice(&wc->vb.pdev->dev, "wctdm24xxp: Can't set tx state to %d\n", txsig); } } else if (mod->type == FXS) { wctdm_fxs_hooksig(wc, mod, txsig); } return 0; } static void wctdm_dacs_connect(struct wctdm *wc, int srccard, int dstcard) { struct wctdm_module *const srcmod = &wc->mods[srccard]; struct wctdm_module *const dstmod = &wc->mods[dstcard]; unsigned int type; if (wc->mods[dstcard].dacssrc > -1) { dev_notice(&wc->vb.pdev->dev, "wctdm_dacs_connect: Can't have double sourcing yet!\n"); return; } type = wc->mods[srccard].type; if ((type == FXS) || (type == FXO)) { dev_notice(&wc->vb.pdev->dev, "wctdm_dacs_connect: Unsupported modtype for " "card %d\n", srccard); return; } type = wc->mods[dstcard].type; if ((type != FXS) && (type != FXO)) { dev_notice(&wc->vb.pdev->dev, "wctdm_dacs_connect: Unsupported modtype " "for card %d\n", dstcard); return; } if (debug) { dev_info(&wc->vb.pdev->dev, "connect %d => %d\n", srccard, dstcard); } dstmod->dacssrc = srccard; /* make srccard transmit to srccard+24 on the TDM bus */ if (srcmod->type == FXS) { /* proslic */ wctdm_setreg(wc, srcmod, PCM_XMIT_START_COUNT_LSB, ((srccard+24) * 8) & 0xff); wctdm_setreg(wc, srcmod, PCM_XMIT_START_COUNT_MSB, ((srccard+24) * 8) >> 8); } else if (srcmod->type == FXO) { /* daa TX */ wctdm_setreg(wc, srcmod, 34, ((srccard+24) * 8) & 0xff); wctdm_setreg(wc, srcmod, 35, ((srccard+24) * 8) >> 8); } /* have dstcard receive from srccard+24 on the TDM bus */ if (dstmod->type == FXS) { /* proslic */ wctdm_setreg(wc, dstmod, PCM_RCV_START_COUNT_LSB, ((srccard+24) * 8) & 0xff); wctdm_setreg(wc, dstmod, PCM_RCV_START_COUNT_MSB, ((srccard+24) * 8) >> 8); } else if (dstmod->type == FXO) { /* daa RX */ wctdm_setreg(wc, dstmod, 36, ((srccard+24) * 8) & 0xff); wctdm_setreg(wc, dstmod, 37, ((srccard+24) * 8) >> 8); } } static void wctdm_dacs_disconnect(struct wctdm *wc, int card) { struct wctdm_module *const mod = &wc->mods[card]; struct wctdm_module *dacssrc; if (mod->dacssrc <= -1) return; dacssrc = &wc->mods[mod->dacssrc]; if (debug) { dev_info(&wc->vb.pdev->dev, "wctdm_dacs_disconnect: " "restoring TX for %d and RX for %d\n", mod->dacssrc, card); } /* restore TX (source card) */ if (dacssrc->type == FXS) { wctdm_setreg(wc, dacssrc, PCM_XMIT_START_COUNT_LSB, (mod->dacssrc * 8) & 0xff); wctdm_setreg(wc, dacssrc, PCM_XMIT_START_COUNT_MSB, (mod->dacssrc * 8) >> 8); } else if (dacssrc->type == FXO) { wctdm_setreg(wc, mod, 34, (card * 8) & 0xff); wctdm_setreg(wc, mod, 35, (card * 8) >> 8); } else { dev_warn(&wc->vb.pdev->dev, "WARNING: wctdm_dacs_disconnect() called " "on unsupported modtype\n"); } /* restore RX (this card) */ if (FXS == mod->type) { wctdm_setreg(wc, mod, PCM_RCV_START_COUNT_LSB, (card * 8) & 0xff); wctdm_setreg(wc, mod, PCM_RCV_START_COUNT_MSB, (card * 8) >> 8); } else if (FXO == mod->type) { wctdm_setreg(wc, mod, 36, (card * 8) & 0xff); wctdm_setreg(wc, mod, 37, (card * 8) >> 8); } else { dev_warn(&wc->vb.pdev->dev, "WARNING: wctdm_dacs_disconnect() called " "on unsupported modtype\n"); } mod->dacssrc = -1; } static int wctdm_dacs(struct dahdi_chan *dst, struct dahdi_chan *src) { struct wctdm *wc; if (!nativebridge) return 0; /* should this return -1 since unsuccessful? */ wc = dst->pvt; if (src) { wctdm_dacs_connect(wc, src->chanpos - 1, dst->chanpos - 1); if (debug) dev_info(&wc->vb.pdev->dev, "dacs connecct: %d -> %d!\n\n", src->chanpos, dst->chanpos); } else { wctdm_dacs_disconnect(wc, dst->chanpos - 1); if (debug) dev_info(&wc->vb.pdev->dev, "dacs disconnect: %d!\n", dst->chanpos); } return 0; } /** * wctdm_wait_for_ready * * Check if the board has finished any setup and is ready to start processing * calls. */ int wctdm_wait_for_ready(struct wctdm *wc) { while (!is_initialized(wc)) { if (fatal_signal_pending(current)) return -EIO; msleep_interruptible(250); } return 0; } static int wctdm_enable_hw_preechocan(struct dahdi_chan *chan) { struct wctdm *wc = chan->pvt; struct wctdm_chan *wchan = container_of(chan, struct wctdm_chan, chan); if (!wc->vpmoct) return 0; return vpmoct_preecho_enable(wc->vpmoct, wchan->timeslot); } static void wctdm_disable_hw_preechocan(struct dahdi_chan *chan) { struct wctdm *wc = chan->pvt; struct wctdm_chan *wchan = container_of(chan, struct wctdm_chan, chan); if (!wc->vpmoct) return; vpmoct_preecho_disable(wc->vpmoct, wchan->timeslot); } /** * wctdm_chanconfig - Called when the channels are being configured. * * Ensure that the card is completely ready to go before we allow the channels * to be completely configured. This is to allow lengthy initialization * actions to take place in background on driver load and ensure we're synced * up by the time dahdi_cfg is run. * */ static int wctdm_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { struct wctdm *wc = chan->pvt; if ((file->f_flags & O_NONBLOCK) && !is_initialized(wc)) return -EAGAIN; return wctdm_wait_for_ready(wc); } static const struct dahdi_span_ops wctdm24xxp_analog_span_ops = { .owner = THIS_MODULE, .hooksig = wctdm_hooksig, .open = wctdm_open, .close = wctdm_close, .ioctl = wctdm_ioctl, .watchdog = wctdm_watchdog, .chanconfig = wctdm_chanconfig, .dacs = wctdm_dacs, #ifdef VPM_SUPPORT .enable_hw_preechocan = wctdm_enable_hw_preechocan, .disable_hw_preechocan = wctdm_disable_hw_preechocan, .echocan_create = wctdm_echocan_create, .echocan_name = wctdm_echocan_name, #endif }; static const struct dahdi_span_ops wctdm24xxp_digital_span_ops = { .owner = THIS_MODULE, .open = wctdm_open, .close = wctdm_close, .ioctl = wctdm_ioctl, .watchdog = wctdm_watchdog, .hdlc_hard_xmit = wctdm_hdlc_hard_xmit, .spanconfig = b400m_spanconfig, .chanconfig = b400m_chanconfig, .dacs = wctdm_dacs, #ifdef VPM_SUPPORT .enable_hw_preechocan = wctdm_enable_hw_preechocan, .disable_hw_preechocan = wctdm_disable_hw_preechocan, .echocan_create = wctdm_echocan_create, .echocan_name = wctdm_echocan_name, #endif }; static inline bool dahdi_is_digital_span(const struct dahdi_span *s) { return (s->linecompat > 0); } static struct wctdm_chan * wctdm_init_chan(struct wctdm *wc, struct wctdm_span *s, int chanoffset, int channo, unsigned int card_position) { struct wctdm_chan *c; c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return NULL; /* Do not change the procfs representation for non-hx8 cards. */ if (dahdi_is_digital_span(&s->span)) { sprintf(c->chan.name, "WCBRI/%d/%d/%d", card_position, s->spanno, channo); } else { sprintf(c->chan.name, "WCTDM/%d/%d", card_position, channo); } c->chan.chanpos = channo+1; c->chan.span = &s->span; c->chan.pvt = wc; c->timeslot = chanoffset + channo; return c; } #if 0 /** * wctdm_span_count() - Return the number of spans exported by this board. * * This is only called during initialization so let's just count the spans each * time we need this information as opposed to storing another variable in the * wctdm structure. */ static int wctdm_span_count(const struct wctdm *wc) { int i; int count = 0; for (i = 0; i < MAX_SPANS; ++i) { if (wc->spans[i]) ++count; } return count; } #endif static struct wctdm_span * wctdm_init_span(struct wctdm *wc, int spanno, int chanoffset, int chancount, int digital_span, unsigned int card_position) { int x; struct pci_dev *pdev = wc->vb.pdev; struct wctdm_chan *c; struct wctdm_span *s; static int spancount; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return NULL; /* DAHDI stuff */ s->span.offset = spanno; s->spanno = spancount++; s->wc = wc; /* Do not change the procfs representation for non-hx8 cards. */ if (digital_span) sprintf(s->span.name, "WCBRI/%d/%d", card_position, s->spanno); else sprintf(s->span.name, "WCTDM/%d", card_position); snprintf(s->span.desc, sizeof(s->span.desc) - 1, "%s", wc->desc->name); snprintf(s->span.location, sizeof(s->span.location) - 1, "PCI%s Bus %02d Slot %02d", (wc->desc->flags & FLAG_EXPRESS) ? " Express" : "", pdev->bus->number, PCI_SLOT(pdev->devfn) + 1); s->span.manufacturer = "Digium"; strncpy(s->span.devicetype, wc->desc->name, sizeof(s->span.devicetype) - 1); if (wc->companding == DAHDI_LAW_DEFAULT) { if (wc->digi_mods || digital_span) /* If we have a BRI module, Auto set to alaw */ s->span.deflaw = DAHDI_LAW_ALAW; else /* Auto set to ulaw */ s->span.deflaw = DAHDI_LAW_MULAW; } else if (wc->companding == DAHDI_LAW_ALAW) { /* Force everything to alaw */ s->span.deflaw = DAHDI_LAW_ALAW; } else { /* Auto set to ulaw */ s->span.deflaw = DAHDI_LAW_MULAW; } if (digital_span) { s->span.ops = &wctdm24xxp_digital_span_ops; s->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4; s->span.linecompat |= DAHDI_CONFIG_ESF | DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; s->span.linecompat |= DAHDI_CONFIG_NTTE | DAHDI_CONFIG_TERM; s->span.spantype = "TE"; } else { s->span.ops = &wctdm24xxp_analog_span_ops; s->span.flags = DAHDI_FLAG_RBS; /* analog sigcap handled in fixup_analog_span() */ } s->span.chans = kmalloc(sizeof(struct dahdi_chan *) * chancount, GFP_KERNEL); if (!s->span.chans) return NULL; /* allocate channels for the span */ for (x = 0; x < chancount; x++) { c = wctdm_init_chan(wc, s, chanoffset, x, card_position); if (!c) return NULL; wc->chans[chanoffset + x] = c; s->span.chans[x] = &c->chan; } s->span.channels = chancount; s->span.irq = pdev->irq; if (digital_span) { wc->chans[chanoffset + 0]->chan.sigcap = DAHDI_SIG_CLEAR; wc->chans[chanoffset + 1]->chan.sigcap = DAHDI_SIG_CLEAR; wc->chans[chanoffset + 2]->chan.sigcap = DAHDI_SIG_HARDHDLC; } wc->spans[spanno] = s; return s; } /** * should_set_alaw() - Should be called after all the spans are initialized. * * Returns true if the module companding should be set to alaw, otherwise * false. */ static bool should_set_alaw(const struct wctdm *wc) { if (DAHDI_LAW_DEFAULT == wc->companding) return (wc->digi_mods > 0); else if (DAHDI_LAW_ALAW == wc->companding) return true; else return false; } static void wctdm_fixup_analog_span(struct wctdm *wc, int spanno) { struct dahdi_span *s; int x, y; /* Finalize signalling */ y = 0; s = &wc->spans[spanno]->span; for (x = 0; x < wc->desc->ports; x++) { struct wctdm_module *const mod = &wc->mods[x]; if (debug) { dev_info(&wc->vb.pdev->dev, "fixup_analog: x=%d, y=%d modtype=%d, " "s->chans[%d]=%p\n", x, y, mod->type, y, s->chans[y]); } if (mod->type == FXO) { int val; s->chans[y++]->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR; val = should_set_alaw(wc) ? 0x20 : 0x28; #ifdef DEBUG val = (digitalloopback) ? 0x30 : val; #endif wctdm_setreg(wc, mod, 33, val); } else if (mod->type == FXS) { s->chans[y++]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR; wctdm_setreg(wc, mod, 1, (should_set_alaw(wc) ? 0x20 : 0x28)); } else if (mod->type == QRV) { s->chans[y++]->sigcap = DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR; } else { s->chans[y++]->sigcap = 0; } } for (x = 0; x < MAX_SPANS; x++) { if (!wc->spans[x]) continue; if (wc->vpmadt032) strncat(wc->spans[x]->span.devicetype, " (VPMADT032)", sizeof(wc->spans[x]->span.devicetype) - 1); } } static int wctdm_initialize_vpmadt032(struct wctdm *wc) { int res; struct vpmadt032_options options; options.debug = debug; options.vpmnlptype = vpmnlptype; options.vpmnlpthresh = vpmnlpthresh; options.vpmnlpmaxsupp = vpmnlpmaxsupp; options.channels = wc->avchannels; wc->vpmadt032 = vpmadt032_alloc(&options); if (!wc->vpmadt032) return -ENOMEM; wc->vpmadt032->setchanconfig_from_state = setchanconfig_from_state; /* wc->vpmadt032->context = wc; */ /* Pull the configuration information from the span holding * the analog channels. */ res = vpmadt032_test(wc->vpmadt032, &wc->vb); if (!res) res = vpmadt032_init(wc->vpmadt032); if (res) { vpmadt032_free(wc->vpmadt032); wc->vpmadt032 = NULL; return res; } /* Now we need to configure the VPMADT032 module for this * particular board. */ res = config_vpmadt032(wc->vpmadt032, wc); if (res) { vpmadt032_free(wc->vpmadt032); wc->vpmadt032 = NULL; return res; } return 0; } static void wctdm_vpm_load_complete(struct device *dev, bool operational) { unsigned long flags; struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct wctdm *wc = pci_get_drvdata(pdev); struct vpmoct *vpm = NULL; WARN_ON(!wc || !wc->not_ready); if (!wc || !wc->not_ready) return; spin_lock_irqsave(&wc->reglock, flags); wc->not_ready--; if (operational) { wc->ctlreg |= 0x10; } else { vpm = wc->vpmoct; wc->vpmoct = NULL; } spin_unlock_irqrestore(&wc->reglock, flags); if (vpm) vpmoct_free(vpm); } static void wctdm_initialize_vpm(struct wctdm *wc) { int res = 0; if (!vpmsupport) return; res = wctdm_initialize_vpmadt032(wc); if (!res) { wc->ctlreg |= 0x10; return; } else { struct vpmoct *vpm; unsigned long flags; vpm = vpmoct_alloc(); if (!vpm) { dev_info(&wc->vb.pdev->dev, "Unable to allocate memory for struct vpmoct\n"); return; } vpm->dev = &wc->vb.pdev->dev; spin_lock_irqsave(&wc->reglock, flags); wc->vpmoct = vpm; wc->not_ready++; spin_unlock_irqrestore(&wc->reglock, flags); res = vpmoct_init(vpm, wctdm_vpm_load_complete); if (-EINVAL == res) { spin_lock_irqsave(&wc->reglock, flags); wc->vpmoct = NULL; wc->not_ready--; spin_unlock_irqrestore(&wc->reglock, flags); vpmoct_free(vpm); } } return; } static void wctdm_identify_modules(struct wctdm *wc) { int x; unsigned long flags; wc->ctlreg = 0x00; /* * This looks a little weird. * * There are only 8 physical ports on the TDM/AEX800, but the code * immediately below sets 24 modules up. This has to do with the * altcs magic that allows us to have single-port and quad-port * modules on these products. The variable "mods_per_board" is set to * the appropriate value just below the next code block. * * Now why this is important: The FXS modules come out of reset in a * two-byte, non-chainable SPI mode. This is currently incompatible * with how we do things, so we need to set them to a chained, 3-byte * command mode. This is done by setting the module type to FXSINIT * for a little while so that cmd_dequeue will initialize the SLIC * into the appropriate mode. * * This "go to 3-byte chained mode" command, however, wreaks havoc * with HybridBRI. * * The solution: Since HybridBRI is only designed to work in an 8-port * card, and since the single-port modules "show up" in SPI slots >= 8 * in these cards, we only set SPI slots 8-23 to FXSINIT. The * HybridBRI will never see the command that causes it to freak out * and the single-port FXS cards get what they need so that when we * probe with altcs we see them. */ /* Make sure all units go into daisy chain mode */ spin_lock_irqsave(&wc->reglock, flags); for (x = 0; x < ARRAY_SIZE(wc->mods); x++) wc->mods[x].type = FXSINIT; spin_unlock_irqrestore(&wc->reglock, flags); /* Wait just a bit; this makes sure that cmd_dequeue is emitting SPI * commands in the appropriate mode(s). */ udelay(2000); /* Now that all the cards have been reset, we can stop checking them * all if there aren't as many */ spin_lock_irqsave(&wc->reglock, flags); wc->mods_per_board = wc->desc->ports; spin_unlock_irqrestore(&wc->reglock, flags); /* Reset modules */ for (x = 0; x < wc->mods_per_board; x++) { struct wctdm_module *const mod = &wc->mods[x]; enum {SANE = 1, UNKNOWN = 0}; int ret = 0, readi = 0; bool altcs = false; if (fatal_signal_pending(current)) break; retry: ret = wctdm_init_proslic(wc, mod, 0, 0, UNKNOWN); if (!ret) { if (debug & DEBUG_CARD) { readi = wctdm_getreg(wc, mod, LOOP_I_LIMIT); dev_info(&wc->vb.pdev->dev, "Proslic module %d loop current " "is %dmA\n", x, ((readi*3) + 20)); } dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- AUTO FXS/DPO\n", x + 1); continue; } if (ret != -2) { /* Init with Manual Calibration */ if (!wctdm_init_proslic(wc, mod, 0, 1, SANE)) { if (debug & DEBUG_CARD) { readi = wctdm_getreg(wc, mod, LOOP_I_LIMIT); dev_info(&wc->vb.pdev->dev, "Proslic module %d loop " "current is %dmA\n", x, ((readi*3)+20)); } dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- MANUAL FXS\n", x + 1); } else { dev_notice(&wc->vb.pdev->dev, "Port %d: FAILED FXS (%s)\n", x + 1, fxshonormode ? fxo_modes[_opermode].name : "FCC"); } continue; } ret = wctdm_init_voicedaa(wc, mod, 0, 0, UNKNOWN); if (!ret) { dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- " "AUTO FXO (%s mode)\n", x + 1, fxo_modes[_opermode].name); continue; } if (!wctdm_init_qrvdri(wc, x)) { dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- QRV DRI card\n", x + 1); continue; } if (is_hx8(wc) && !wctdm_init_b400m(wc, x)) { dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- BRI " "quad-span module\n", x + 1); continue; } if ((wc->desc->ports != 24) && ((x&0x3) == 1) && !altcs) { spin_lock_irqsave(&wc->reglock, flags); set_offsets(mod, 2); altcs = true; if (wc->desc->ports == 4) { set_offsets(&wc->mods[x+1], 3); set_offsets(&wc->mods[x+2], 3); } mod->type = FXSINIT; spin_unlock_irqrestore(&wc->reglock, flags); udelay(1000); udelay(1000); spin_lock_irqsave(&wc->reglock, flags); mod->type = FXS; spin_unlock_irqrestore(&wc->reglock, flags); if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Trying port %d with alternate chip " "select\n", x + 1); } goto retry; } mod->type = NONE; dev_info(&wc->vb.pdev->dev, "Port %d: Not installed\n", x + 1); } /* for (x...) */ } static struct pci_driver wctdm_driver; static void wctdm_back_out_gracefully(struct wctdm *wc) { int i; unsigned long flags; LIST_HEAD(local_list); voicebus_release(&wc->vb); #ifdef CONFIG_VOICEBUS_ECREFERENCE for (i = 0; i < ARRAY_SIZE(wc->ec_reference); ++i) { if (wc->ec_reference[i]) dahdi_fifo_free(wc->ec_reference[i]); } #endif for (i = 0; i < ARRAY_SIZE(wc->spans); ++i) { if (wc->spans[i] && wc->spans[i]->span.chans) kfree(wc->spans[i]->span.chans); kfree(wc->spans[i]); wc->spans[i] = NULL; } spin_lock_irqsave(&wc->reglock, flags); for (i = 0; i < ARRAY_SIZE(wc->mods); ++i) { struct wctdm_module *const mod = &wc->mods[i]; kfree(wc->chans[i]); wc->chans[i] = NULL; list_splice_init(&mod->pending_cmds, &local_list); list_splice_init(&mod->active_cmds, &local_list); } list_splice_init(&wc->free_isr_commands, &local_list); spin_unlock_irqrestore(&wc->reglock, flags); while (!list_empty(&local_list)) { struct wctdm_cmd *cmd; cmd = list_entry(local_list.next, struct wctdm_cmd, node); list_del(&cmd->node); kfree(cmd->complete); kfree(cmd); } spin_lock_irqsave(&wc->frame_list_lock, flags); list_splice(&wc->frame_list, &local_list); spin_unlock_irqrestore(&wc->frame_list_lock, flags); while (!list_empty(&local_list)) { struct sframe_packet *frame; frame = list_entry(local_list.next, struct sframe_packet, node); list_del(&frame->node); kfree(frame); } kfree(wc->board_name); kfree(wc); } static const struct voicebus_operations voicebus_operations = { .handle_receive = handle_receive, .handle_transmit = handle_transmit, }; static const struct voicebus_operations hx8_voicebus_operations = { .handle_receive = handle_hx8_receive, .handle_transmit = handle_hx8_transmit, }; struct cmd_results { u8 results[8]; }; static int hx8_send_command(struct wctdm *wc, const u8 *command, size_t count, int checksum, int application, int bootloader, struct cmd_results *results) { int ret = 0; struct vbb *vbb; struct sframe_packet *frame; const int MAX_COMMAND_LENGTH = 264 + 4; unsigned long flags; dma_addr_t dma_addr; might_sleep(); /* can't boot both into the application and the bootloader at once. */ WARN_ON((application > 0) && (bootloader > 0)); if ((application > 0) && (bootloader > 0)) return -EINVAL; WARN_ON(count > MAX_COMMAND_LENGTH); if (count > MAX_COMMAND_LENGTH) return -EINVAL; vbb = dma_pool_alloc(wc->vb.pool, GFP_KERNEL, &dma_addr); WARN_ON(!vbb); if (!vbb) return -ENOMEM; vbb->dma_addr = dma_addr; memset(vbb->data, 0, SFRAME_SIZE); memcpy(&vbb->data[EFRAME_SIZE + EFRAME_GAP], command, count); vbb->data[EFRAME_SIZE] = 0x80 | ((application) ? 0 : 0x40) | ((checksum) ? 0x20 : 0) | ((count & 0x100) >> 4); vbb->data[EFRAME_SIZE + 1] = count & 0xff; if (bootloader) vbb->data[EFRAME_SIZE + 3] = 0xAA; spin_lock_irqsave(&wc->vb.lock, flags); voicebus_transmit(&wc->vb, vbb); spin_unlock_irqrestore(&wc->vb.lock, flags); /* Do not wait for the response if the caller doesn't care about the * results. */ if (NULL == results) return 0; if (!wait_event_timeout(wc->regq, !list_empty(&wc->frame_list), 2*HZ)) { dev_err(&wc->vb.pdev->dev, "Timeout waiting " "for receive frame.\n"); ret = -EIO; } /* We only want the last packet received. Throw away anything else on * the list */ frame = NULL; spin_lock_irqsave(&wc->frame_list_lock, flags); while (!list_empty(&wc->frame_list)) { frame = list_entry(wc->frame_list.next, struct sframe_packet, node); list_del(&frame->node); if (!list_empty(&wc->frame_list)) { kfree(frame); frame = NULL; } } spin_unlock_irqrestore(&wc->frame_list_lock, flags); if (frame) { memcpy(results->results, &frame->sframe[EFRAME_SIZE], sizeof(results->results)); } else { ret = -EIO; } return ret; } static int hx8_get_fpga_version(struct wctdm *wc, u8 *major, u8 *minor) { int ret; struct cmd_results results; u8 command[] = {0xD7, 0x00}; ret = hx8_send_command(wc, command, ARRAY_SIZE(command), 0, 0, 0, &results); if (ret) return ret; *major = results.results[0]; *minor = results.results[2]; return 0; } static void hx8_cleanup_frame_list(struct wctdm *wc) { unsigned long flags; LIST_HEAD(local_list); struct sframe_packet *frame; spin_lock_irqsave(&wc->frame_list_lock, flags); list_splice_init(&wc->frame_list, &local_list); spin_unlock_irqrestore(&wc->frame_list_lock, flags); while (!list_empty(&local_list)) { frame = list_entry(local_list.next, struct sframe_packet, node); list_del(&frame->node); kfree(frame); } } static int hx8_switch_to_application(struct wctdm *wc) { int ret; u8 command[] = {0xD7, 0x00}; ret = hx8_send_command(wc, command, ARRAY_SIZE(command), 0, 1, 0, NULL); if (ret) return ret; msleep(1000); hx8_cleanup_frame_list(wc); return 0; } /** * hx8_switch_to_bootloader() - Send packet to switch hx8 into bootloader * */ static int hx8_switch_to_bootloader(struct wctdm *wc) { int ret; u8 command[] = {0xD7, 0x00}; ret = hx8_send_command(wc, command, ARRAY_SIZE(command), 0, 0, 1, NULL); if (ret) return ret; /* It takes some time for the FPGA to reload and switch it's * configuration. */ msleep(300); hx8_cleanup_frame_list(wc); return 0; } struct ha80000_firmware { u8 header[6]; u8 major_ver; u8 minor_ver; u8 data[54648]; __le32 chksum; } __attribute__((packed)); static void hx8_send_dummy(struct wctdm *wc) { u8 command[] = {0xD7, 0x00}; hx8_send_command(wc, command, ARRAY_SIZE(command), 0, 0, 0, NULL); } static int hx8_read_status_register(struct wctdm *wc, u8 *status) { int ret; struct cmd_results results; u8 command[] = {0xD7, 0x00}; ret = hx8_send_command(wc, command, ARRAY_SIZE(command), 0, 0, 0, &results); if (ret) return ret; *status = results.results[3]; return 0; } static const unsigned int HYBRID_PAGE_SIZE = 264; static int hx8_write_buffer(struct wctdm *wc, const u8 *buffer, size_t size) { int ret = 0; struct cmd_results results; int padding_bytes = 0; u8 *local_data; u8 command[] = {0x84, 0, 0, 0}; if (size > HYBRID_PAGE_SIZE) return -EINVAL; if (size < HYBRID_PAGE_SIZE) padding_bytes = HYBRID_PAGE_SIZE - size; local_data = kmalloc(sizeof(command) + size + padding_bytes, GFP_KERNEL); if (!local_data) return -ENOMEM; memcpy(local_data, command, sizeof(command)); memcpy(&local_data[sizeof(command)], buffer, size); memset(&local_data[sizeof(command) + size], 0xff, padding_bytes); ret = hx8_send_command(wc, local_data, sizeof(command) + size + padding_bytes, 1, 0, 0, &results); if (ret) goto cleanup; cleanup: kfree(local_data); return ret; } static int hx8_buffer_to_page(struct wctdm *wc, const unsigned int page) { int ret; struct cmd_results results; u8 command[] = {0x83, (page & 0x180) >> 7, (page & 0x7f) << 1, 0x00}; ret = hx8_send_command(wc, command, sizeof(command), 1, 0, 0, &results); if (ret) return ret; return 0; } static int hx8_wait_for_ready(struct wctdm *wc, const int timeout) { int ret; u8 status; unsigned long local_timeout = jiffies + timeout; do { ret = hx8_read_status_register(wc, &status); if (ret) return ret; if ((status & 0x80) > 0) break; } while (time_after(local_timeout, jiffies)); if (time_after(jiffies, local_timeout)) return -EIO; return 0; } /** * hx8_reload_application - reload the application firmware * * NOTE: The caller should ensure that the board is in bootloader mode before * calling this function. */ static int hx8_reload_application(struct wctdm *wc, const struct ha80000_firmware *ha8_fw) { unsigned int cur_page; const u8 *data; u8 status; int ret = 0; const int HYBRID_PAGE_COUNT = (sizeof(ha8_fw->data)) / HYBRID_PAGE_SIZE; dev_info(&wc->vb.pdev->dev, "Reloading firmware. Do not power down " "the system until the process is complete.\n"); BUG_ON(!ha8_fw); might_sleep(); data = &ha8_fw->data[0]; ret = hx8_read_status_register(wc, &status); if (ret) return ret; for (cur_page = 0; cur_page < HYBRID_PAGE_COUNT; ++cur_page) { ret = hx8_write_buffer(wc, data, HYBRID_PAGE_SIZE); if (ret) return ret; /* The application starts out at page 0x100 */ ret = hx8_buffer_to_page(wc, 0x100 + cur_page); if (ret) return ret; /* wait no more than a second for the write to the page to * finish */ ret = hx8_wait_for_ready(wc, HZ); if (ret) return ret; data += HYBRID_PAGE_SIZE; } return ret; } static void print_hx8_recovery_message(struct device *dev) { dev_warn(dev, "The firmware may be corrupted. Please completely " "power off your system, power on, and then reload the driver " "with the 'forceload' module parameter set to 1 to attempt " "recovery.\n"); } /** * hx8_check_firmware - Check the firmware version and load a new one possibly. * */ static int hx8_check_firmware(struct wctdm *wc) { int ret; u8 major; u8 minor; const struct firmware *fw; const struct ha80000_firmware *ha8_fw; struct device *dev = &wc->vb.pdev->dev; int retries = 10; BUG_ON(!is_hx8(wc)); might_sleep(); do { hx8_send_dummy(wc); ret = hx8_get_fpga_version(wc, &major, &minor); if (!ret) break; if (fatal_signal_pending(current)) return -EINTR; } while (--retries); if (ret) { print_hx8_recovery_message(dev); return ret; } /* If we're in the bootloader, try to jump into the application. */ if ((1 == major) && (0x80 == minor) && !forceload) { dev_dbg(dev, "Switching to application.\n"); hx8_switch_to_application(wc); ret = hx8_get_fpga_version(wc, &major, &minor); if (ret) { print_hx8_recovery_message(dev); return ret; } } dev_dbg(dev, "FPGA VERSION: %02x.%02x\n", major, minor); ret = request_firmware(&fw, "dahdi-fw-hx8.bin", dev); if (ret) { dev_warn(dev, "Failed to load firmware from userspace, skipping " "check. (%d)\n", ret); return 0; } ha8_fw = (const struct ha80000_firmware *)fw->data; if ((fw->size != sizeof(*ha8_fw)) || (0 != memcmp("DIGIUM", ha8_fw->header, sizeof(ha8_fw->header))) || ((crc32(~0, (void *)ha8_fw, sizeof(*ha8_fw) - sizeof(u32)) ^ ~0) != le32_to_cpu(ha8_fw->chksum))) { dev_warn(dev, "Firmware file is invalid. Skipping load.\n"); ret = 0; goto cleanup; } dev_dbg(dev, "FIRMWARE: %02x.%02x\n", ha8_fw->major_ver, ha8_fw->minor_ver); if (ha8_fw->major_ver == major && ha8_fw->minor_ver == minor) { dev_dbg(dev, "Firmware versions match, skipping load.\n"); ret = 0; goto cleanup; } if (2 == major) { hx8_switch_to_bootloader(wc); ret = hx8_get_fpga_version(wc, &major, &minor); if (ret) goto cleanup; } /* so now we're in boot loader mode, ready to load the new firmware. */ ret = hx8_reload_application(wc, ha8_fw); if (ret) goto cleanup; dev_dbg(dev, "Firmware reloaded. Booting into application.\n"); hx8_switch_to_application(wc); ret = hx8_get_fpga_version(wc, &major, &minor); if (ret) goto cleanup; dev_dbg(dev, "FPGA VERSION AFTER LOAD: %02x.%02x\n", major, minor); if (forceload) { dev_warn(dev, "Please unset forceload if your card is able to " "detect the installed modules.\n"); } cleanup: release_firmware(fw); dev_info(dev, "Hx8 firmware version: %d.%02d\n", major, minor); return ret; } #ifdef CONFIG_VOICEBUS_SYSFS static ssize_t voicebus_current_latency_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long flags; struct wctdm *wc = dev_get_drvdata(dev); unsigned int current_latency; spin_lock_irqsave(&wc->vb.lock, flags); current_latency = wc->vb.min_tx_buffer_count; spin_unlock_irqrestore(&wc->vb.lock, flags); return sprintf(buf, "%d\n", current_latency); } static DEVICE_ATTR(voicebus_current_latency, 0400, voicebus_current_latency_show, NULL); static ssize_t vpm_firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) { int res; u16 version = 0; struct wctdm *wc = dev_get_drvdata(dev); if (wc->vpmadt032) { res = gpakPingDsp(wc->vpmadt032->dspid, &version); if (res) { dev_info(&wc->vb.pdev->dev, "Failed gpakPingDsp %d\n", res); version = -1; } } return sprintf(buf, "%x.%02x\n", (version & 0xff00) >> 8, (version & 0xff)); } static DEVICE_ATTR(vpm_firmware_version, 0400, vpm_firmware_version_show, NULL); static ssize_t enable_vpm_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long flags; struct wctdm *wc = dev_get_drvdata(dev); unsigned int enable_vpm; spin_lock_irqsave(&wc->reglock, flags); enable_vpm = (wc->ctlreg & 0x10) != 0; spin_unlock_irqrestore(&wc->reglock, flags); return sprintf(buf, "%d\n", enable_vpm); } static ssize_t enable_vpm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long flags; struct wctdm *wc = dev_get_drvdata(dev); unsigned int enable_vpm; if (count < 2) return -EINVAL; if (('0' == buf[0]) || (0 == buf[0])) enable_vpm = 0; else enable_vpm = 1; spin_lock_irqsave(&wc->reglock, flags); if (enable_vpm) wc->ctlreg |= 0x10; else wc->ctlreg &= ~0x10; spin_unlock_irqrestore(&wc->reglock, flags); return count; } static DEVICE_ATTR(enable_vpm, 0644, enable_vpm_show, enable_vpm_store); static void create_sysfs_files(struct wctdm *wc) { int ret; ret = device_create_file(&wc->vb.pdev->dev, &dev_attr_voicebus_current_latency); if (ret) { dev_info(&wc->vb.pdev->dev, "Failed to create device attributes.\n"); } ret = device_create_file(&wc->vb.pdev->dev, &dev_attr_vpm_firmware_version); if (ret) { dev_info(&wc->vb.pdev->dev, "Failed to create device attributes.\n"); } ret = device_create_file(&wc->vb.pdev->dev, &dev_attr_enable_vpm); if (ret) { dev_info(&wc->vb.pdev->dev, "Failed to create device attributes.\n"); } } static void remove_sysfs_files(struct wctdm *wc) { device_remove_file(&wc->vb.pdev->dev, &dev_attr_enable_vpm); device_remove_file(&wc->vb.pdev->dev, &dev_attr_vpm_firmware_version); device_remove_file(&wc->vb.pdev->dev, &dev_attr_voicebus_current_latency); } #else static inline void create_sysfs_files(struct wctdm *wc) { return; } static inline void remove_sysfs_files(struct wctdm *wc) { return; } #endif /* CONFIG_VOICEBUS_SYSFS */ static void wctdm_set_tdm410_leds(struct wctdm *wc) { int i; if (4 != wc->desc->ports) return; wc->tdm410leds = 0; /* all on by default */ for (i = 0; i < wc->desc->ports; ++i) { /* Turn off the LED for any module that isn't installed. */ if (NONE == wc->mods[i].type) wc->tdm410leds |= (1 << i); } } /** * wctdm_allocate_irq_commands - Preallocate some commands for use in interrupt context. * @wc: The board which we're allocating for. * @count: The number of IRQ commands to allocate. * * We need a minimum of 4 * the current latency worth of commands for each * analog module. When the latency grows, new commands will be allocated, but * this just represents are best guess as to the number of commands we'll need * after probing for modules, and reduces the chance that we'll allocate * memory in interrupt context when the driver first loads. * */ static void wctdm_allocate_irq_commands(struct wctdm *wc, unsigned int count) { unsigned long flags; LIST_HEAD(local_list); if (!count) return; while (count--) { struct wctdm_cmd *cmd; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) break; list_add(&cmd->node, &local_list); } spin_lock_irqsave(&wc->reglock, flags); list_splice(&local_list, &wc->free_isr_commands); spin_unlock_irqrestore(&wc->reglock, flags); } #ifdef USE_ASYNC_INIT struct async_data { struct pci_dev *pdev; const struct pci_device_id *ent; }; static int __devinit __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent, async_cookie_t cookie) #else static int __devinit __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #endif { struct wctdm *wc; unsigned int pos; int i, ret; int anamods, digimods, curchan, curspan; neonmwi_offlimit_cycles = neonmwi_offlimit / MS_PER_HOOKCHECK; wc = kzalloc(sizeof(*wc), GFP_KERNEL); if (!wc) return -ENOMEM; wc->not_ready = 1; down(&ifacelock); /* \todo this is a candidate for removal... */ for (pos = 0; pos < WC_MAX_IFACES; ++pos) { if (!ifaces[pos]) { ifaces[pos] = wc; break; } } up(&ifacelock); wc->desc = (struct wctdm_desc *)ent->driver_data; /* This is to insure that the analog span is given lowest priority */ sema_init(&wc->syncsem, 1); INIT_LIST_HEAD(&wc->frame_list); spin_lock_init(&wc->frame_list_lock); init_waitqueue_head(&wc->regq); spin_lock_init(&wc->reglock); INIT_LIST_HEAD(&wc->free_isr_commands); wc->oldsync = -1; wc->board_name = kasprintf(GFP_KERNEL, "%s%d", wctdm_driver.name, pos); if (!wc->board_name) { wctdm_back_out_gracefully(wc); return -ENOMEM; } #ifdef CONFIG_VOICEBUS_ECREFERENCE for (i = 0; i < ARRAY_SIZE(wc->ec_reference); ++i) { /* 256 is the smallest power of 2 that will contains the * maximum possible amount of latency. */ wc->ec_reference[i] = dahdi_fifo_alloc(256, GFP_KERNEL); if (IS_ERR(wc->ec_reference[i])) { ret = PTR_ERR(wc->ec_reference[i]); wc->ec_reference[i] = NULL; wctdm_back_out_gracefully(wc); return ret; } } #endif pci_set_drvdata(pdev, wc); wc->vb.ops = &voicebus_operations; wc->vb.pdev = pdev; wc->vb.debug = &debug; if (is_hx8(wc)) { wc->vb.ops = &hx8_voicebus_operations; ret = voicebus_boot_init(&wc->vb, wc->board_name); } else { wc->vb.ops = &voicebus_operations; ret = voicebus_init(&wc->vb, wc->board_name); voicebus_set_minlatency(&wc->vb, latency); voicebus_set_maxlatency(&wc->vb, max_latency); } if (ret) { wctdm_back_out_gracefully(wc); return ret; } create_sysfs_files(wc); voicebus_lock_latency(&wc->vb); wc->mods_per_board = NUM_MODULES; wc->txident = 1; if (alawoverride) { companding = "alaw"; dev_info(&wc->vb.pdev->dev, "The module parameter alawoverride"\ " has been deprecated. Please use the "\ "parameter companding=alaw instead"); } if (!strcasecmp(companding, "alaw")) /* Force this card's companding to alaw */ wc->companding = DAHDI_LAW_ALAW; else if (!strcasecmp(companding, "ulaw")) /* Force this card's companding to ulaw */ wc->companding = DAHDI_LAW_MULAW; else /* Auto detect this card's companding */ wc->companding = DAHDI_LAW_DEFAULT; for (i = 0; i < ARRAY_SIZE(wc->mods); i++) { struct wctdm_module *const mod = &wc->mods[i]; INIT_LIST_HEAD(&mod->pending_cmds); INIT_LIST_HEAD(&mod->active_cmds); mod->dacssrc = -1; mod->card = i; set_offsets(mod, 0); } /* Start the hardware processing. */ if (voicebus_start(&wc->vb)) { BUG_ON(1); } if (is_hx8(wc)) { ret = hx8_check_firmware(wc); if (ret) { voicebus_release(&wc->vb); wctdm_back_out_gracefully(wc); return -EIO; } /* Switch to the normal operating mode for this card. */ voicebus_stop(&wc->vb); wc->vb.ops = &voicebus_operations; voicebus_set_minlatency(&wc->vb, latency); voicebus_set_maxlatency(&wc->vb, max_latency); voicebus_set_hx8_mode(&wc->vb); if (voicebus_start(&wc->vb)) BUG_ON(1); } /* first we have to make sure that we process all module data, we'll fine-tune it later in this routine. */ wc->avchannels = NUM_MODULES; /* Now track down what modules are installed */ wctdm_identify_modules(wc); wctdm_set_tdm410_leds(wc); if (fatal_signal_pending(current)) { wctdm_back_out_gracefully(wc); return -EINTR; } /* * Walk the module list and create a 3-channel span for every BRI module found. * Empty and analog modules get a common span which is allocated outside of this loop. */ anamods = digimods = 0; curchan = curspan = 0; for (i = 0; i < wc->mods_per_board; i++) { struct wctdm_module *const mod = &wc->mods[i]; struct b400m *b4; if (mod->type == NONE) { ++curspan; continue; } else if (mod->type == BRI) { if (!is_hx8(wc)) { dev_info(&wc->vb.pdev->dev, "Digital modules " "detected on a non-hybrid card. " "This is unsupported.\n"); wctdm_back_out_gracefully(wc); return -EIO; } wc->spans[curspan] = wctdm_init_span(wc, curspan, curchan, 3, 1, pos); if (!wc->spans[curspan]) { wctdm_back_out_gracefully(wc); return -EIO; } b4 = mod->mod.bri; b400m_set_dahdi_span(b4, i & 0x03, wc->spans[curspan]); ++curspan; curchan += 3; if (!(i & 0x03)) { b400m_post_init(b4); ++digimods; } } else { /* * FIXME: ABK: * create a wctdm_chan for every analog module and link them into a span of their own down below. * then evaluate all of the callbacks and hard-code whether they are receiving a dahdi_chan or wctdm_chan *. * Finally, move the union from the wctdm structure to the dahdi_chan structure, and we should have something * resembling a clean dynamic # of channels/dynamic # of spans driver. */ ++curspan; ++anamods; } if (digimods > 2) { dev_info(&wc->vb.pdev->dev, "More than two digital modules detected. This is unsupported.\n"); wctdm_back_out_gracefully(wc); return -EIO; } } wc->digi_mods = digimods; /* create an analog span if there are analog modules, or if there are no digital ones. */ if (anamods || !digimods) { if (!digimods) { curspan = 0; } wctdm_init_span(wc, curspan, curchan, wc->desc->ports, 0, pos); wctdm_fixup_analog_span(wc, curspan); wc->aspan = wc->spans[curspan]; curchan += wc->desc->ports; ++curspan; } /* Now fix up the timeslots for the analog modules, since the digital * modules are always first */ for (i = 0; i < wc->mods_per_board; i++) { struct wctdm_module *const mod = &wc->mods[i]; switch (mod->type) { case FXS: wctdm_proslic_set_ts(wc, mod, (digimods * 12) + i); break; case FXO: wctdm_voicedaa_set_ts(wc, mod, (digimods * 12) + i); break; case QRV: wctdm_qrvdri_set_ts(wc, mod, (digimods * 12) + i); break; default: break; } } /* This shouldn't ever occur, but if we don't try to trap it, the driver * will be scribbling into memory it doesn't own. */ BUG_ON(curchan > 24); wc->avchannels = curchan; wctdm_initialize_vpm(wc); #ifdef USE_ASYNC_INIT async_synchronize_cookie(cookie); #endif /* We should be ready for DAHDI to come in now. */ for (i = 0; i < MAX_SPANS; ++i) { if (!wc->spans[i]) continue; if (dahdi_register(&wc->spans[i]->span, 0)) { dev_notice(&wc->vb.pdev->dev, "Unable to register span %d with DAHDI\n", i); while (i) dahdi_unregister(&wc->spans[i--]->span); wctdm_back_out_gracefully(wc); return -1; } } wctdm_allocate_irq_commands(wc, anamods * latency * 4); wc->not_ready--; dev_info(&wc->vb.pdev->dev, "Found a %s: %s (%d BRI spans, %d analog %s)\n", (is_hx8(wc)) ? "Hybrid card" : "Wildcard TDM", wc->desc->name, digimods*4, anamods, (anamods == 1) ? "channel" : "channels"); ret = 0; voicebus_unlock_latency(&wc->vb); return 0; } #ifdef USE_ASYNC_INIT static __devinit void wctdm_init_one_async(void *data, async_cookie_t cookie) { struct async_data *dat = data; __wctdm_init_one(dat->pdev, dat->ent, cookie); kfree(dat); } static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct async_data *dat; dat = kmalloc(sizeof(*dat), GFP_KERNEL); /* If we can't allocate the memory for the async_data, odds are we won't * be able to initialize the device either, but let's try synchronously * anyway... */ if (!dat) return __wctdm_init_one(pdev, ent, 0); dat->pdev = pdev; dat->ent = ent; async_schedule(wctdm_init_one_async, dat); return 0; } #else static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { return __wctdm_init_one(pdev, ent); } #endif static void wctdm_release(struct wctdm *wc) { int i; if (is_initialized(wc)) { for (i = 0; i < MAX_SPANS; i++) { if (wc->spans[i]) dahdi_unregister(&wc->spans[i]->span); } } down(&ifacelock); for (i = 0; i < WC_MAX_IFACES; i++) if (ifaces[i] == wc) break; ifaces[i] = NULL; up(&ifacelock); wctdm_back_out_gracefully(wc); } static void __devexit wctdm_remove_one(struct pci_dev *pdev) { int i; unsigned long flags; struct wctdm *wc = pci_get_drvdata(pdev); struct vpmadt032 *vpmadt032; struct vpmoct *vpmoct; if (!wc) return; vpmadt032 = wc->vpmadt032; vpmoct = wc->vpmoct; remove_sysfs_files(wc); if (vpmadt032) { clear_bit(VPM150M_ACTIVE, &vpmadt032->control); flush_scheduled_work(); } else if (vpmoct) { while (wctdm_wait_for_ready(wc)) schedule(); } /* shut down any BRI modules */ for (i = 0; i < wc->mods_per_board; i += 4) { if (wc->mods[i].type == BRI) wctdm_unload_b400m(wc, i); } voicebus_stop(&wc->vb); if (vpmadt032) { vpmadt032_free(vpmadt032); wc->vpmadt032 = NULL; } else if (vpmoct) { spin_lock_irqsave(&wc->reglock, flags); wc->vpmoct = NULL; spin_unlock_irqrestore(&wc->reglock, flags); vpmoct_free(vpmoct); } dev_info(&wc->vb.pdev->dev, "Freed a %s\n", (is_hx8(wc)) ? "Hybrid card" : "Wildcard"); /* Release span */ wctdm_release(wc); } static DEFINE_PCI_DEVICE_TABLE(wctdm_pci_tbl) = { { 0xd161, 0x2400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm2400 }, { 0xd161, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm800 }, { 0xd161, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex800 }, { 0xd161, 0x8003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex2400 }, { 0xd161, 0x8005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm410 }, { 0xd161, 0x8006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex410 }, { 0xd161, 0x8007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcha80000 }, { 0xd161, 0x8008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wchb80000 }, { 0 } }; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) static void wctdm_shutdown(struct pci_dev *pdev) { struct wctdm *wc = pci_get_drvdata(pdev); voicebus_quiesce(&wc->vb); } #endif MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl); static int wctdm_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } static struct pci_driver wctdm_driver = { .name = "wctdm24xxp", .probe = wctdm_init_one, .remove = __devexit_p(wctdm_remove_one), #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) .shutdown = wctdm_shutdown, #endif .suspend = wctdm_suspend, .id_table = wctdm_pci_tbl, }; static int __init wctdm_init(void) { int res; int x; for (x = 0; x < ARRAY_SIZE(fxo_modes); x++) { if (!strcmp(fxo_modes[x].name, opermode)) break; } if (x < ARRAY_SIZE(fxo_modes)) { _opermode = x; } else { printk(KERN_NOTICE "Invalid/unknown operating mode '%s' " "specified. Please choose one of:\n", opermode); for (x = 0; x < ARRAY_SIZE(fxo_modes); x++) printk(KERN_CONT " %s\n", fxo_modes[x].name); printk(KERN_NOTICE "Note this option is CASE SENSITIVE!\n"); return -ENODEV; } if (!strcmp(opermode, "AUSTRALIA")) { boostringer = 1; fxshonormode = 1; } if (-1 == fastpickup) { if (!strcmp(opermode, "JAPAN")) fastpickup = 1; else fastpickup = 0; } /* for the voicedaa_check_hook defaults, if the user has not overridden them by specifying them as module parameters, then get the values from the selected operating mode */ if (battdebounce == 0) { battdebounce = fxo_modes[_opermode].battdebounce; } if (battalarm == 0) { battalarm = fxo_modes[_opermode].battalarm; } if (battthresh == 0) { battthresh = fxo_modes[_opermode].battthresh; } b400m_module_init(); res = dahdi_pci_module(&wctdm_driver); if (res) return -ENODEV; #ifdef USE_ASYNC_INIT async_synchronize_full(); #endif return 0; } static void __exit wctdm_cleanup(void) { pci_unregister_driver(&wctdm_driver); } module_param(debug, int, 0600); module_param(fastpickup, int, 0400); MODULE_PARM_DESC(fastpickup, "Set to 1 to shorten the calibration delay when taking " \ "an FXO port off hook. This can be required for Type-II " \ "CID. If -1 the calibration delay will depend on the " \ "current opermode.\n"); module_param(fxovoltage, int, 0600); module_param(loopcurrent, int, 0600); module_param(reversepolarity, int, 0600); #ifdef DEBUG module_param(robust, int, 0600); module_param(digitalloopback, int, 0400); MODULE_PARM_DESC(digitalloopback, "Set to 1 to place FXO modules into " \ "loopback mode for troubleshooting."); #endif module_param(opermode, charp, 0600); module_param(lowpower, int, 0600); module_param(boostringer, int, 0600); module_param(fastringer, int, 0600); module_param(fxshonormode, int, 0600); module_param(battdebounce, uint, 0600); module_param(battalarm, uint, 0600); module_param(battthresh, uint, 0600); module_param(nativebridge, int, 0600); module_param(fxotxgain, int, 0600); module_param(fxorxgain, int, 0600); module_param(fxstxgain, int, 0600); module_param(fxsrxgain, int, 0600); module_param(ringdebounce, int, 0600); module_param(fwringdetect, int, 0600); module_param(latency, int, 0400); module_param(max_latency, int, 0400); module_param(neonmwi_monitor, int, 0600); module_param(neonmwi_level, int, 0600); module_param(neonmwi_envelope, int, 0600); module_param(neonmwi_offlimit, int, 0600); #ifdef VPM_SUPPORT module_param(vpmsupport, int, 0400); module_param(vpmnlptype, int, 0400); module_param(vpmnlpthresh, int, 0400); module_param(vpmnlpmaxsupp, int, 0400); #endif /* Module parameters backed by code in xhfc.c */ module_param(bri_debug, int, 0600); MODULE_PARM_DESC(bri_debug, "bitmap: 1=general 2=dtmf 4=regops 8=fops 16=ec 32=st state 64=hdlc 128=alarm"); module_param(bri_spanfilter, int, 0600); MODULE_PARM_DESC(bri_spanfilter, "debug filter for spans. bitmap: 1=port 1, 2=port 2, 4=port 3, 8=port 4"); module_param(bri_alarmdebounce, int, 0600); MODULE_PARM_DESC(bri_alarmdebounce, "msec to wait before set/clear alarm condition"); module_param(bri_teignorered, int, 0600); MODULE_PARM_DESC(bri_teignorered, "1=ignore (do not inform DAHDI) if a red alarm exists in TE mode"); module_param(bri_persistentlayer1, int, 0600); MODULE_PARM_DESC(bri_persistentlayer1, "Set to 0 for disabling automatic layer 1 reactivation (when other end deactivates it)"); module_param(timingcable, int, 0600); MODULE_PARM_DESC(timingcable, "Set to 1 for enabling timing cable. This means that *all* cards in the system are linked together with a single timing cable"); module_param(forceload, int, 0600); MODULE_PARM_DESC(forceload, "Set to 1 in order to force an FPGA reload after power on (currently only for HA8/HB8 cards)."); module_param(alawoverride, int, 0400); MODULE_PARM_DESC(alawoverride, "This option has been deprecated. Please use "\ "the parameter \"companding\" instead"); module_param(companding, charp, 0400); MODULE_PARM_DESC(companding, "Change the companding to \"auto\" or \"alaw\" " \ "or \"ulaw\". Auto (default) will set everything to ulaw " \ "unless a BRI module is installed. It will use alaw in that " "case."); MODULE_DESCRIPTION("VoiceBus Driver for Wildcard Analog and Hybrid Cards"); MODULE_AUTHOR("Digium Incorporated "); MODULE_ALIAS("wctdm8xxp"); MODULE_ALIAS("wctdm4xxp"); MODULE_ALIAS("wcaex24xx"); MODULE_ALIAS("wcaex8xx"); MODULE_ALIAS("wcaex4xx"); MODULE_LICENSE("GPL v2"); module_init(wctdm_init); module_exit(wctdm_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/Makefile0000644000175000017500000000026011026016414022213 0ustar tzafrirtzafririfdef KBUILD_EXTMOD # We only get here on kernels 2.6.0-2.6.9 . # For newer kernels, Kbuild will be included directly by the kernel # build system. include $(src)/Kbuild endif dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/xhfc.c0000644000175000017500000023173111602452654021672 0ustar tzafrirtzafrir/* * B400M Quad-BRI module Driver * Written by Andrew Kohlsmith * * Copyright (C) 2010 Digium, Inc. * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #define FAST_HDLC_NEED_TABLES #include #include #include "wctdm24xxp.h" #include "xhfc.h" #define HFC_NR_FIFOS 16 #define HFC_ZMIN 0x00 /* from datasheet */ #define HFC_ZMAX 0x7f #define HFC_FMIN 0x00 #define HFC_FMAX 0x07 /* * yuck. Any reg which is not mandated read/write or read-only is write-only. * Also, there are dozens of registers with the same address. Additionally, * there are array registers (A_) which have an index register These A_ * registers require an index register to be written to indicate WHICH in the * array you want. */ #define R_CIRM 0x00 /* WO */ #define R_CTRL 0x01 /* WO */ #define R_CLK_CFG 0x02 /* WO */ #define A_Z1 0x04 /* RO */ #define A_Z2 0x06 /* RO */ #define R_RAM_ADDR 0x08 /* WO */ #define R_RAM_CTRL 0x09 /* WO */ #define R_FIRST_FIFO 0x0b /* WO */ #define R_FIFO_THRES 0x0c /* WO */ #define A_F1 0x0c /* RO */ #define R_FIFO_MD 0x0d /* WO */ #define A_F2 0x0d /* RO */ #define A_INC_RES_FIFO 0x0e /* WO */ #define A_FIFO_STA 0x0e /* RO */ #define R_FSM_IDX 0x0f /* WO */ #define R_FIFO 0x0f /* WO */ #define R_SLOT 0x10 /* WO */ #define R_IRQ_OVIEW 0x10 /* RO */ #define R_MISC_IRQMSK 0x11 /* WO */ #define R_MISC_IRQ 0x11 /* RO */ #define R_SU_IRQMSK 0x12 /* WO */ #define R_SU_IRQ 0x12 /* RO */ #define R_IRQ_CTRL 0x13 /* WO */ #define R_AF0_OVIEW 0x13 /* RO */ #define R_PCM_MD0 0x14 /* WO */ #define A_USAGE 0x14 /* RO */ #define R_MSS0 0x15 /* WO */ #define R_MSS1 0x15 /* WO */ #define R_PCM_MD1 0x15 /* WO */ #define R_PCM_MD2 0x15 /* WO */ #define R_SH0H 0x15 /* WO */ #define R_SH1H 0x15 /* WO */ #define R_SH0L 0x15 /* WO */ #define R_SH1L 0x15 /* WO */ #define R_SL_SEL0 0x15 /* WO */ #define R_SL_SEL1 0x15 /* WO */ #define R_SL_SEL7 0x15 /* WO */ #define R_RAM_USE 0x15 /* RO */ #define R_SU_SEL 0x16 /* WO */ #define R_CHIP_ID 0x16 /* RO */ #define R_SU_SYNC 0x17 /* WO */ #define R_BERT_STA 0x17 /* RO */ #define R_F0_CNTL 0x18 /* RO */ #define R_F0_CNTH 0x19 /* RO */ #define R_TI_WD 0x1a /* WO */ #define R_BERT_ECL 0x1a /* RO */ #define R_BERT_WD_MD 0x1b /* WO */ #define R_BERT_ECH 0x1b /* RO */ #define R_STATUS 0x1c /* RO */ #define R_SL_MAX 0x1d /* RO */ #define R_PWM_CFG 0x1e /* WO */ #define R_CHIP_RV 0x1f /* RO */ #define R_FIFO_BL0_IRQ 0x20 /* RO */ #define R_FIFO_BL1_IRQ 0x21 /* RO */ #define R_FIFO_BL2_IRQ 0x22 /* RO */ #define R_FIFO_BL3_IRQ 0x23 /* RO */ #define R_FILL_BL0 0x24 /* RO */ #define R_FILL_BL1 0x25 /* RO */ #define R_FILL_BL2 0x26 /* RO */ #define R_FILL_BL3 0x27 /* RO */ #define R_CI_TX 0x28 /* WO */ #define R_CI_RX 0x28 /* RO */ #define R_CGI_CFG0 0x29 /* WO */ #define R_CGI_STA 0x29 /* RO */ #define R_CGI_CFG1 0x2a /* WO */ #define R_MON_RX 0x2a /* RO */ #define R_MON_TX 0x2b /* WO */ #define A_SU_WR_STA 0x30 /* WO */ #define A_SU_RD_STA 0x30 /* RO */ #define A_SU_CTRL0 0x31 /* WO */ #define A_SU_DLYL 0x31 /* RO */ #define A_SU_CTRL1 0x32 /* WO */ #define A_SU_DLYH 0x32 /* RO */ #define A_SU_CTRL2 0x33 /* WO */ #define A_MS_TX 0x34 /* WO */ #define A_MS_RX 0x34 /* RO */ #define A_ST_CTRL3 0x35 /* WO */ #define A_UP_CTRL3 0x35 /* WO */ #define A_SU_STA 0x35 /* RO */ #define A_MS_DF 0x36 /* WO */ #define A_SU_CLK_DLY 0x37 /* WO */ #define R_PWM0 0x38 /* WO */ #define R_PWM1 0x39 /* WO */ #define A_B1_TX 0x3c /* WO */ #define A_B1_RX 0x3c /* RO */ #define A_B2_TX 0x3d /* WO */ #define A_B2_RX 0x3d /* RO */ #define A_D_TX 0x3e /* WO */ #define A_D_RX 0x3e /* RO */ #define A_BAC_S_TX 0x3f /* WO */ #define A_E_RX 0x3f /* RO */ #define R_GPIO_OUT1 0x40 /* WO */ #define R_GPIO_IN1 0x40 /* RO */ #define R_GPIO_OUT3 0x41 /* WO */ #define R_GPIO_IN3 0x41 /* RO */ #define R_GPIO_EN1 0x42 /* WO */ #define R_GPIO_EN3 0x43 /* WO */ #define R_GPIO_SEL_BL 0x44 /* WO */ #define R_GPIO_OUT2 0x45 /* WO */ #define R_GPIO_IN2 0x45 /* RO */ #define R_PWM_MD 0x46 /* WO */ #define R_GPIO_EN2 0x47 /* WO */ #define R_GPIO_OUT0 0x48 /* WO */ #define R_GPIO_IN0 0x48 /* RO */ #define R_GPIO_EN0 0x4a /* WO */ #define R_GPIO_SEL 0x4c /* WO */ #define R_PLL_CTRL 0x50 /* WO */ #define R_PLL_STA 0x50 /* RO */ #define R_PLL_P 0x51 /* RW */ #define R_PLL_N 0x52 /* RW */ #define R_PLL_S 0x53 /* RW */ #define A_FIFO_DATA 0x80 /* RW */ #define A_FIFO_DATA_NOINC 0x84 /* RW */ #define R_INT_DATA 0x88 /* RO */ #define R_RAM_DATA 0xc0 /* RW */ #define A_SL_CFG 0xd0 /* RW */ #define A_CH_MSK 0xf4 /* RW */ #define A_CON_HDLC 0xfa /* RW */ #define A_SUBCH_CFG 0xfb /* RW */ #define A_CHANNEL 0xfc /* RW */ #define A_FIFO_SEQ 0xfd /* RW */ #define A_FIFO_CTRL 0xff /* RW */ /* R_CIRM bits */ #define V_CLK_OFF (1 << 0) /* 1=internal clocks disabled */ #define V_WAIT_PROC (1 << 1) /* 1=additional /WAIT after write access */ #define V_WAIT_REG (1 << 2) /* 1=additional /WAIT for internal BUSY phase */ #define V_SRES (1 << 3) /* soft reset (group 0) */ #define V_HFC_RES (1 << 4) /* HFC reset (group 1) */ #define V_PCM_RES (1 << 5) /* PCM reset (group 2) */ #define V_SU_RES (1 << 6) /* S/T reset (group 3) */ #define XHFC_FULL_RESET (V_SRES | V_HFC_RES | V_PCM_RES | V_SU_RES) /* R_STATUS bits */ #define V_BUSY (1 << 0) /* 1=HFC busy, limited register access */ #define V_PROC (1 << 1) /* 1=HFC in processing phase */ #define V_LOST_STA (1 << 3) /* 1=frames have been lost */ #define V_PCM_INIT (1 << 4) /* 1=PCM init in progress */ #define V_WAK_STA (1 << 5) /* state of WAKEUP pin wien V_WAK_EN=1 */ #define V_MISC_IRQSTA (1 << 6) /* 1=misc interrupt has occurred */ #define V_FR_IRQSTA (1 << 7) /* 1=fifo interrupt has occured */ #define XHFC_INTS (V_MISC_IRQSTA | V_FR_IRQSTA) /* R_FIFO_BLx_IRQ bits */ #define V_FIFOx_TX_IRQ (1 << 0) /* FIFO TX interrupt occurred */ #define V_FIFOx_RX_IRQ (1 << 1) /* FIFO RX interrupt occurred */ #define FIFOx_TXRX_IRQ (V_FIFOx_TX_IRQ | V_FIFOx_RX_IRQ) /* R_FILL_BLx bits */ #define V_FILL_FIFOx_TX (1 << 0) /* TX FIFO reached V_THRES_TX level */ #define V_FILL_FIFOx_RX (1 << 1) /* RX FIFO reached V_THRES_RX level */ #define FILL_FIFOx_TXRX (V_FILL_FIFOx_TX | V_FILL_FIFOx_RX) /* R_MISC_IRQ / R_MISC_IRQMSK bits */ #define V_SLP_IRQ (1 << 0) /* frame sync pulse flips */ #define V_TI_IRQ (1 << 1) /* timer elapsed */ #define V_PROC_IRQ (1 << 2) /* processing/non-processing transition */ #define V_CI_IRQ (1 << 4) /* indication bits changed */ #define V_WAK_IRQ (1 << 5) /* WAKEUP pin */ #define V_MON_TX_IRQ (1 << 6) /* monitor byte can be written */ #define V_MON_RX_IRQ (1 << 7) /* monitor byte received */ /* R_SU_IRQ/R_SU_IRQMSK bits */ #define V_SU0_IRQ (1 << 0) /* interrupt/mask port 1 */ #define V_SU1_IRQ (1 << 1) /* interrupt/mask port 2 */ #define V_SU2_IRQ (1 << 2) /* interrupt/mask port 3 */ #define V_SU3_IRQ (1 << 3) /* interrupt/mask port 4 */ /* R_IRQ_CTRL bits */ #define V_FIFO_IRQ_EN (1 << 0) /* enable any unmasked FIFO IRQs */ #define V_GLOB_IRQ_EN (1 << 3) /* enable any unmasked IRQs */ #define V_IRQ_POL (1 << 4) /* 1=IRQ active high */ /* R_BERT_WD_MD bits */ #define V_BERT_ERR (1 << 3) /* 1=generate an error bit in BERT stream */ #define V_AUTO_WD_RES (1 << 5) /* 1=automatically kick the watchdog */ #define V_WD_RES (1 << 7) /* 1=kick the watchdog (bit auto clears) */ /* R_TI_WD bits */ #define V_EV_TS_SHIFT (0) #define V_EV_TS_MASK (0x0f) #define V_WD_TS_SHIFT (4) #define V_WD_TS_MASK (0xf0) /* A_FIFO_CTRL bits */ #define V_FIFO_IRQMSK (1 << 0) /* 1=FIFO can generate interrupts */ #define V_BERT_EN (1 << 1) /* 1=BERT data replaces FIFO data */ #define V_MIX_IRQ (1 << 2) /* IRQ when 0=end of frame only, 1=also when Z1==Z2 */ #define V_FR_ABO (1 << 3) /* 1=generate frame abort/frame abort detected */ #define V_NO_CRC (1 << 4) /* 1=do not send CRC at end of frame */ #define V_NO_REP (1 << 5) /* 1=frame deleted after d-chan contention */ /* R_CLK_CFG bits */ #define V_CLK_PLL (1 << 0) /* Sysclk select 0=OSC_IN, 1=PLL output */ #define V_CLKO_HI (1 << 1) /* CLKOUT selection 0=PLL/8, 1=PLL */ #define V_CLKO_PLL (1 << 2) /* CLKOUT source 0=divider or PLL input, 1=PLL output */ #define V_PCM_CLK (1 << 5) /* 1=PCM clk = OSC, 0 = PCM clk is 2x OSC */ #define V_CLKO_OFF (1 << 6) /* CLKOUT enable 0=enabled */ #define V_CLK_F1 (1 << 7) /* PLL input pin 0=OSC_IN, 1=F1_1 */ /* R_PCM_MD0 bits */ #define V_PCM_MD (1 << 0) /* 1=PCM master */ #define V_C4_POL (1 << 1) /* 1=F0IO sampled on rising edge of C4IO */ #define V_F0_NEG (1 << 2) /* 1=negative polarity of F0IO */ #define V_F0_LEN (1 << 3) /* 1=F0IO active for 2 C4IO clocks */ #define V_PCM_IDX_SEL0 (0x0 << 4) /* reg15 = R_SL_SEL0 */ #define V_PCM_IDX_SEL1 (0x1 << 4) /* reg15 = R_SL_SEL1 */ #define V_PCM_IDX_SEL7 (0x7 << 4) /* reg15 = R_SL_SEL7 */ #define V_PCM_IDX_MSS0 (0x8 << 4) /* reg15 = R_MSS0 */ #define V_PCM_IDX_MD1 (0x9 << 4) /* reg15 = R_PCM_MD1 */ #define V_PCM_IDX_MD2 (0xa << 4) /* reg15 = R_PCM_MD2 */ #define V_PCM_IDX_MSS1 (0xb << 4) /* reg15 = R_MSS1 */ #define V_PCM_IDX_SH0L (0xc << 4) /* reg15 = R_SH0L */ #define V_PCM_IDX_SH0H (0xd << 4) /* reg15 = R_SH0H */ #define V_PCM_IDX_SH1L (0xe << 4) /* reg15 = R_SH1L */ #define V_PCM_IDX_SH1H (0xf << 4) /* reg15 = R_SH1H */ #define V_PCM_IDX_MASK (0xf0) /* R_PCM_MD1 bits */ #define V_PLL_ADJ_00 (0x0 << 2) /* adj 4 times by 0.5 system clk cycles */ #define V_PLL_ADJ_01 (0x1 << 2) /* adj 3 times by 0.5 system clk cycles */ #define V_PLL_ADJ_10 (0x2 << 2) /* adj 2 times by 0.5 system clk cycles */ #define V_PLL_ADJ_11 (0x3 << 2) /* adj 1 time by 0.5 system clk cycles */ #define V_PCM_DR_2048 (0x0 << 4) /* 2.048Mbps, 32 timeslots */ #define V_PCM_DR_4096 (0x1 << 4) /* 4.096Mbps, 64 timeslots */ #define V_PCM_DR_8192 (0x2 << 4) /* 8.192Mbps, 128 timeslots */ #define V_PCM_DR_075 (0x3 << 4) /* 0.75Mbps, 12 timeslots */ #define V_PCM_LOOP (1 << 6) /* 1=internal loopback */ #define V_PCM_SMPL (1 << 7) /* 0=sample at middle of bit cell, 1=sample at 3/4 point */ #define V_PLL_ADJ_MASK (0x3 << 2) #define V_PCM_DR_MASK (0x3 << 4) /* R_PCM_MD2 bits */ #define V_SYNC_OUT1 (1 << 1) /* SYNC_O source 0=SYNC_I or FSX_RX, 1=512kHz from PLL or multiframe */ #define V_SYNC_SRC (1 << 2) /* 0=line interface, 1=SYNC_I */ #define V_SYNC_OUT2 (1 << 3) /* SYNC_O source 0=rx sync or FSC_RX 1=SYNC_I or received superframe */ #define V_C2O_EN (1 << 4) /* C2IO output enable (when V_C2I_EN=0) */ #define V_C2I_EN (1 << 5) /* PCM controller clock source 0=C4IO, 1=C2IO */ #define V_PLL_ICR (1 << 6) /* 0=reduce PCM frame time, 1=increase */ #define V_PLL_MAN (1 << 7) /* 0=auto, 1=manual */ /* A_SL_CFG bits */ #define V_CH_SDIR (1 << 0) /* 1=HFC channel receives data from PCM TS */ #define V_ROUT_TX_DIS (0x0 << 6) /* disabled, output disabled */ #define V_ROUT_TX_LOOP (0x1 << 6) /* internally looped, output disabled */ #define V_ROUT_TX_STIO1 (0x2 << 6) /* output data to STIO1 */ #define V_ROUT_TX_STIO2 (0x3 << 6) /* output data to STIO2 */ #define V_ROUT_RX_DIS (0x0 << 6) /* disabled, input data ignored */ #define V_ROUT_RX_LOOP (0x1 << 6) /* internally looped, input data ignored */ #define V_ROUT_RX_STIO2 (0x2 << 6) /* channel data comes from STIO1 */ #define V_ROUT_RX_STIO1 (0x3 << 6) /* channel data comes from STIO2 */ #define V_CH_SNUM_SHIFT (1) #define V_CH_SNUM_MASK (31 << 1) /* A_CON_HDLC bits */ #define V_IFF (1 << 0) /* Inter-Frame Fill: 0=0x7e, 1=0xff */ #define V_HDLC_TRP (1 << 1) /* 0=HDLC mode, 1=transparent */ #define V_TRP_DISABLED (0x0 << 2) /* FIFO disabled, no interrupt */ #define V_TRP_IRQ_64 (0x1 << 2) /* FIFO enabled, int @ 8 bytes */ #define V_TRP_IRQ_128 (0x2 << 2) /* FIFO enabled, int @ 16 bytes */ #define V_TRP_IRQ_256 (0x3 << 2) /* FIFO enabled, int @ 32 bytes */ #define V_TRP_IRQ_512 (0x4 << 2) /* FIFO enabled, int @ 64 bytes */ #define V_TRP_IRQ_1024 (0x5 << 2) /* FIFO enabled, int @ 128 bytes */ #define V_TRP_NO_IRQ (0x7 << 2) /* FIFO enabled, no interrupt */ #define V_HDLC_IRQ (0x3 << 2) /* HDLC: FIFO enabled, interrupt at end of frame or when FIFO > 16 byte boundary (Mixed IRQ) */ #define V_DATA_FLOW_000 (0x0 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_001 (0x1 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_010 (0x2 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_011 (0x3 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_100 (0x4 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_101 (0x5 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_110 (0x6 << 5) /* see A_CON_HDLC reg description in datasheet */ #define V_DATA_FLOW_111 (0x7 << 5) /* see A_CON_HDLC reg description in datasheet */ /* R_FIFO bits */ #define V_FIFO_DIR (1 << 0) /* 1=RX FIFO data */ #define V_REV (1 << 7) /* 1=MSB first */ #define V_FIFO_NUM_SHIFT (1) #define V_FIFO_NUM_MASK (0x3e) /* A_CHANNEL bits */ #define V_CH_FDIR (1 << 0) /* 1=HFC chan for RX data */ #define V_CH_FNUM_SHIFT (1) #define V_CH_FNUM_MASK (0x3e) /* R_SLOT bits */ #define V_SL_DIR (1 << 0) /* 1=timeslot will RX PCM data from bus */ #define V_SL_NUM_SHIFT (1) #define V_SL_NUM_MASK (0xfe) /* A_INC_RES_FIFO bits */ #define V_INC_F (1 << 0) /* 1=increment FIFO F-counter (bit auto-clears) */ #define V_RES_FIFO (1 << 1) /* 1=reset FIFO (bit auto-clears) */ #define V_RES_LOST (1 << 2) /* 1=reset LOST error (bit auto-clears) */ #define V_RES_FIFO_ERR (1 << 3) /* 1=reset FIFO error (bit auto-clears), check V_ABO_DONE before setting */ /* R_FIFO_MD bits */ #define V_FIFO_MD_00 (0x0 << 0) /* 16 FIFOs, 64 bytes TX/RX, 128 TX or RX if V_UNIDIR_RX */ #define V_FIFO_MD_01 (0x1 << 0) /* 8 FIFOs, 128 bytes TX/RX, 256 TX or RX if V_UNIDIR_RX */ #define V_FIFO_MD_10 (0x2 << 0) /* 4 FIFOs, 256 bytes TX/RX, invalid mode with V_UNIDIR_RX */ #define V_DF_MD_SM (0x0 << 2) /* simple data flow mode */ #define V_DF_MD_CSM (0x1 << 2) /* channel select mode */ #define V_DF_MD_FSM (0x3 << 2) /* FIFO sequence mode */ #define V_UNIDIR_MD (1 << 4) /* 1=unidirectional FIFO mode */ #define V_UNIDIR_RX (1 << 5) /* 1=unidirection FIFO is RX */ /* A_SUBCH_CFG bits */ #define V_BIT_CNT_8BIT (0) /* process 8 bits */ #define V_BIT_CNT_1BIT (1) /* process 1 bit */ #define V_BIT_CNT_2BIT (2) /* process 2 bits */ #define V_BIT_CNT_3BIT (3) /* process 3 bits */ #define V_BIT_CNT_4BIT (4) /* process 4 bits */ #define V_BIT_CNT_5BIT (5) /* process 5 bits */ #define V_BIT_CNT_6BIT (6) /* process 6 bits */ #define V_BIT_CNT_7BIT (7) /* process 7 bits */ #define V_LOOP_FIFO (1 << 6) /* loop FIFO data */ #define V_INV_DATA (1 << 7) /* invert FIFO data */ #define V_START_BIT_SHIFT (3) #define V_START_BIT_MASK (0x38) /* R_SU_SYNC bits */ #define V_SYNC_SEL_PORT0 (0x0 << 0) /* sync to TE port 0 */ #define V_SYNC_SEL_PORT1 (0x1 << 0) /* sync to TE port 1 */ #define V_SYNC_SEL_PORT2 (0x2 << 0) /* sync to TE port 2 */ #define V_SYNC_SEL_PORT3 (0x3 << 0) /* sync to TE port 3 */ #define V_SYNC_SEL_SYNCI (0x4 << 0) /* sync to SYNC_I */ #define V_MAN_SYNC (1 << 3) /* 1=manual sync mode */ #define V_AUTO_SYNCI (1 << 4) /* 1=SYNC_I used if FSC_RX not found */ #define V_D_MERGE_TX (1 << 5) /* 1=all 4 dchan taken from one byte in TX */ #define V_E_MERGE_RX (1 << 6) /* 1=all 4 echan combined in RX direction */ #define V_D_MERGE_RX (1 << 7) /* 1=all 4 dchan combined in RX direction */ #define V_SYNC_SEL_MASK (0x03) /* A_SU_WR_STA bits */ #define V_SU_SET_STA_MASK (0x0f) #define V_SU_LD_STA (1 << 4) /* 1=force SU_SET_STA mode, must be manually cleared 6us later */ #define V_SU_ACT_NOP (0x0 << 5) /* NOP */ #define V_SU_ACT_DEACTIVATE (0x2 << 5) /* start deactivation. auto-clears */ #define V_SU_ACT_ACTIVATE (0x3 << 5) /* start activation. auto-clears. */ #define V_SET_G2_G3 (1 << 7) /* 1=auto G2->G3 in NT mode. auto-clears after transition. */ /* A_SU_RD_STA */ #define V_SU_STA_MASK (0x0f) #define V_SU_FR_SYNC (1 << 4) /* 1=synchronized */ #define V_SU_T2_EXP (1 << 5) /* 1=T2 expired (NT only) */ #define V_SU_INFO0 (1 << 6) /* 1=INFO0 */ #define V_G2_G3 (1 << 7) /* 1=allows G2->G3 (NT only, auto-clears) */ /* A_SU_CLK_DLY bits */ #define V_SU_DLY_MASK (0x0f) #define V_SU_SMPL_MASK (0xf0) #define V_SU_SMPL_SHIFT (4) /* A_SU_CTRL0 bits */ #define V_B1_TX_EN (1 << 0) /* 1=B1-channel transmit */ #define V_B2_TX_EN (1 << 1) /* 1=B2-channel transmit */ #define V_SU_MD (1 << 2) /* 0=TE, 1=NT */ #define V_ST_D_LPRIO (1 << 3) /* D-Chan priority 0=high, 1=low */ #define V_ST_SQ_EN (1 << 4) /* S/Q bits transmit (1=enabled) */ #define V_SU_TST_SIG (1 << 5) /* 1=transmit test signal */ #define V_ST_PU_CTRL (1 << 6) /* 1=enable end of pulse control */ #define V_SU_STOP (1 << 7) /* 1=power down */ /* A_SU_CTRL1 bits */ #define V_G2_G3_EN (1 << 0) /* 1=G2->G3 allowed without V_SET_G2_G3 */ #define V_D_RES (1 << 2) /* 1=D-chan reset */ #define V_ST_E_IGNO (1 << 3) /* TE:1=ignore Echan, NT:should always be 1. */ #define V_ST_E_LO (1 << 4) /* NT only: 1=force Echan low */ #define V_BAC_D (1 << 6) /* 1=BAC bit controls Dchan TX */ #define V_B12_SWAP (1 << 7) /* 1=swap B1/B2 */ /* A_SU_CTRL2 bits */ #define V_B1_RX_EN (1 << 0) /* 1=enable B1 RX */ #define V_B2_RX_EN (1 << 1) /* 1=enable B2 RX */ #define V_MS_SSYNC2 (1 << 2) /* 0 normally, see datasheet */ #define V_BAC_S_SEL (1 << 3) /* see datasheet */ #define V_SU_SYNC_NT (1 << 4) /* 0=sync pulses generated only in TE, 1=in TE and NT */ #define V_SU_2KHZ (1 << 5) /* 0=96kHz test tone, 1=2kHz */ #define V_SU_TRI (1 << 6) /* 1=tristate output buffer */ #define V_SU_EXCHG (1 << 7) /* 1=invert output drivers */ /* R_IRQ_OVIEW bits */ #define V_FIFO_BL0_IRQ (1 << 0) /* FIFO 0-3 IRQ */ #define V_FIFO_BL1_IRQ (1 << 1) /* FIFO 4-7 IRQ */ #define V_FIFO_BL2_IRQ (1 << 2) /* FIFO 8-11 IRQ */ #define V_FIFO_BL3_IRQ (1 << 3) /* FIFO 12-15 IRQ */ #define V_MISC_IRQ (1 << 4) /* R_MISC_IRQ changed */ #define V_STUP_IRQ (1 << 5) /* R_SU_IRQ changed */ #define V_FIFO_BLx_IRQ (V_FIFO_BL0_IRQ | V_FIFO_BL1_IRQ | V_FIFO_BL2_IRQ | V_FIFO_BL3_IRQ) /* R_FIRST_FIFO bits */ #define V_FIRST_FIFO_NUM_SHIFT (1) /* A_FIFO_SEQ bits */ #define V_NEXT_FIFO_NUM_SHIFT (1) #define V_SEQ_END (1 << 6) #if (DAHDI_CHUNKSIZE != 8) #error Sorry, the b400m does not support chunksize != 8 #endif /* general debug messages */ #define DEBUG_GENERAL (1 << 0) /* emit DTMF detector messages */ #define DEBUG_DTMF (1 << 1) /* emit register read/write, but only if the kernel's DEBUG is defined */ #define DEBUG_REGS (1 << 2) /* emit file operation messages */ #define DEBUG_FOPS (1 << 3) #define DEBUG_ECHOCAN (1 << 4) /* S/T state machine */ #define DEBUG_ST_STATE (1 << 5) /* HDLC controller */ #define DEBUG_HDLC (1 << 6) /* alarm changes */ #define DEBUG_ALARM (1 << 7) /* Timing related changes */ #define DEBUG_TIMING (1 << 8) #define DBG (bri_debug & DEBUG_GENERAL) #define DBG_DTMF (bri_debug & DEBUG_DTMF) #define DBG_REGS (bri_debug & DEBUG_REGS) #define DBG_FOPS (bri_debug & DEBUG_FOPS) #define DBG_EC (bri_debug & DEBUG_ECHOCAN) #define DBG_ST (bri_debug & DEBUG_ST_STATE) #define DBG_HDLC (bri_debug & DEBUG_HDLC) #define DBG_ALARM (bri_debug & DEBUG_ALARM) #define DBG_TIMING (bri_debug & DEBUG_TIMING) #define DBG_SPANFILTER ((1 << bspan->port) & bri_spanfilter) /* #define HARDHDLC_RX */ /* Any static variables not initialized by default should be set * to 0 automatically */ int bri_debug; int bri_spanfilter = 9; int bri_teignorered = 1; int bri_alarmdebounce; int bri_persistentlayer1; int timingcable; static int synccard = -1; static int syncspan = -1; static const int TIMER_3_MS = 30000; #define b4_info(b4, format, arg...) \ dev_info(&(b4)->wc->vb.pdev->dev , format , ## arg) /* if defined, swaps ports 2 and 3 on the B400M module */ #define SWAP_PORTS #define XHFC_T1 0 #define XHFC_T2 1 #define XHFC_T3 2 /* T4 - Special timer, used for debug purposes for monitoring of L1 state during activation attempt. */ #define XHFC_T4 3 #define B400M_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */ #define B400M_HDLC_BUF_LEN 128 /* arbitrary, just the max # of byts we will send to DAHDI per call */ #define get_F(f1, f2, flen) { \ f1 = hfc_readcounter8(b4, A_F1); \ f2 = hfc_readcounter8(b4, A_F2); \ flen = f1 - f2; \ \ if (flen < 0) \ flen += (HFC_FMAX - HFC_FMIN) + 1; \ } #define get_Z(z1, z2, zlen) { \ z1 = hfc_readcounter8(b4, A_Z1); \ z2 = hfc_readcounter8(b4, A_Z2); \ zlen = z1 - z2; \ \ if (zlen < 0) \ zlen += (HFC_ZMAX - HFC_ZMIN) + 1; \ } struct b400m_span { struct b400m *parent; unsigned int port; /* which S/T port this span belongs to */ int oldstate; /* old state machine state */ int newalarm; /* alarm to send to DAHDI once alarm timer expires */ unsigned long alarmtimer; unsigned int te_mode:1; /* 1=TE, 0=NT */ unsigned int term_on:1; /* 1= 390 ohm termination enable, 0 = disabled */ unsigned long hfc_timers[B400M_CHANNELS_PER_SPAN+1]; /* T1, T2, T3 */ int hfc_timer_on[B400M_CHANNELS_PER_SPAN+1]; /* 1=timer active */ int fifos[B400M_CHANNELS_PER_SPAN]; /* B1, B2, D <--> host fifo numbers */ /* HDLC controller fields */ struct wctdm_span *wspan; /* pointer to the actual dahdi_span */ struct dahdi_chan *sigchan; /* pointer to the signalling channel for this span */ int sigactive; /* nonzero means we're in the middle of sending an HDLC frame */ atomic_t hdlc_pending; /* hdlc_hard_xmit() increments, hdlc_tx_frame() decrements */ unsigned int frames_out; unsigned int frames_in; struct fasthdlc_state rxhdlc; int infcs; int f_sz; }; /* This structure exists one per module */ struct b400m { char name[10]; int position; /* module position in carrier board */ int b400m_no; /* 0-based B400M number in system */ struct wctdm *wc; /* parent structure */ spinlock_t reglock; /* lock for all register accesses */ unsigned long ticks; unsigned long fifo_en_rxint; /* each bit is the RX int enable for that FIFO */ unsigned long fifo_en_txint; /* each bit is the TX int enable for that FIFO */ unsigned char fifo_irqstatus; /* top-half ORs in new interrupts, bottom-half ANDs them out */ int setsyncspan; /* Span reported from HFC for sync on this card */ int reportedsyncspan; /* Span reported from HFC for sync on this card */ unsigned int running:1; /* interrupts are enabled */ unsigned int shutdown:1; /* 1=bottom half doesn't process anything, just returns */ unsigned int inited:1; /* FIXME: temporary */ unsigned int misc_irq_mask:1; /* 1= interrupt is valid */ struct b400m_span spans[4]; /* Individual spans */ struct workqueue_struct *xhfc_ws; struct work_struct xhfc_wq; unsigned char irq_oview; /* copy of r_irq_oview */ unsigned char fifo_fill; /* copy of R_FILL_BL0 */ struct semaphore regsem; /* lock for low-level register accesses */ struct semaphore fifosem; /* lock for fifo accesses */ unsigned char lastreg; /* last XHFC register accessed (used to speed up multiple address "hits" */ }; static void hfc_start_st(struct b400m_span *s); static void hfc_stop_st(struct b400m_span *s); void b400m_set_dahdi_span(struct b400m *b4, int spanno, struct wctdm_span *wspan) { b4->spans[spanno].wspan = wspan; wspan->bspan = &b4->spans[spanno]; } static inline void flush_hw(void) { } static int xhfc_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr, u8 *lastreg) { int x; if (*lastreg != (unsigned char)addr) { wctdm_setreg(wc, mod, 0x60, addr); *lastreg = (unsigned char)addr; } x = wctdm_getreg(wc, mod, 0x80); return x; } static int xhfc_setreg(struct wctdm *wc, struct wctdm_module *const mod, int addr, int val, u8 *lastreg) { if (*lastreg != (unsigned char)addr) { wctdm_setreg(wc, mod, 0x60, addr); *lastreg = (unsigned char)addr; } return wctdm_setreg(wc, mod, 0x00, val); } static inline struct wctdm_module *get_mod(struct b400m *b4) { return &b4->wc->mods[b4->position]; } static int b400m_getreg(struct b400m *b4, int addr) { int x; if (down_trylock(&b4->regsem)) { if (down_interruptible(&b4->regsem)) { b4_info(b4, "b400m_getreg(0x%02x) interrupted\n", addr); return -1; } } x = xhfc_getreg(b4->wc, get_mod(b4), addr, &b4->lastreg); up(&b4->regsem); return x; } static int b400m_setreg(struct b400m *b4, const int addr, const int val) { int x; if (down_trylock(&b4->regsem)) { if (down_interruptible(&b4->regsem)) { b4_info(b4, "b400m_setreg(0x%02x -> 0x%02x) " "interrupted\n", val, addr); return -1; } } x = xhfc_setreg(b4->wc, get_mod(b4), addr, val, &b4->lastreg); up(&b4->regsem); return x; } /* * A lot of the registers in the XHFC are indexed. * this function sets the index, and then writes to the indexed register. */ static void b400m_setreg_ra(struct b400m *b4, u8 r, u8 rd, u8 a, u8 ad) { if (down_trylock(&b4->regsem)) { if (down_interruptible(&b4->regsem)) { b4_info(b4, "b400m_setreg_ra(0x%02x -> 0x%02x) " "interrupted\n", a, ad); return; } } xhfc_setreg(b4->wc, get_mod(b4), r, rd, &b4->lastreg); xhfc_setreg(b4->wc, get_mod(b4), a, ad, &b4->lastreg); up(&b4->regsem); } static u8 b400m_getreg_ra(struct b400m *b4, u8 r, u8 rd, u8 a) { unsigned char res; if (down_trylock(&b4->regsem)) { if (down_interruptible(&b4->regsem)) { b4_info(b4, "b400m_getreg_ra(0x%02x) interrupted\n", a); return -1; } } xhfc_setreg(b4->wc, get_mod(b4), r, rd, &b4->lastreg); res = xhfc_getreg(b4->wc, get_mod(b4), a, &b4->lastreg); up(&b4->regsem); return res; } /* * XHFC-4S GPIO routines * * the xhfc doesn't use its gpio for anything. :-) */ /* * initialize XHFC GPIO. * GPIO 0-7 are output, low (unconnected, or used for their primary function). */ static void hfc_gpio_init(struct b400m *b4) { /* GPIO0..3,7 are GPIO, 4,5,6 primary function */ b400m_setreg(b4, R_GPIO_SEL, 0x8f); /* GPIO0..7 drivers set low */ b400m_setreg(b4, R_GPIO_OUT0, 0x00); /* GPIO0..7 drivers enabled */ b400m_setreg(b4, R_GPIO_EN0, 0xff); /* all other GPIO set to primary function */ b400m_setreg(b4, R_GPIO_SEL_BL, 0x00); } /* performs a register write and then waits for the HFC "busy" bit to clear * NOTE: doesn't actually read status, since busy bit is 1us typically, and * we're much, much slower than that. */ static void hfc_setreg_waitbusy(struct b400m *b4, const unsigned int reg, const unsigned int val) { b400m_setreg(b4, reg, val); } /* * reads an 8-bit register over over and over until the same value is read * twice, then returns that value. */ static unsigned char hfc_readcounter8(struct b400m *b4, const unsigned int reg) { unsigned char r1, r2; unsigned long maxwait = 1048576; do { r1 = b400m_getreg(b4, reg); r2 = b400m_getreg(b4, reg); } while ((r1 != r2) && maxwait--); if (!maxwait) { if (printk_ratelimit()) { dev_warn(&b4->wc->vb.pdev->dev, "hfc_readcounter8(reg 0x%02x) timed out " \ "waiting for data to settle!\n", reg); } } return r1; } /* performs a soft-reset of the HFC-4S. */ static void hfc_reset(struct b400m *b4) { unsigned long start; int TIMEOUT = HZ; /* 1s */ /* Set the FIFOs to 8 128 bytes FIFOs, bidirectional, and set up the * flow controller for channel select mode. */ /* Note, this reg has to be set *before* the SW reset */ b400m_setreg(b4, R_FIFO_MD, V_FIFO_MD_01 | V_DF_MD_FSM); msleep(1); /* wait a bit for clock to settle */ /* reset everything, wait 100ms, then allow the XHFC to come out of reset */ b400m_setreg(b4, R_CIRM, V_SRES); flush_hw(); msleep(100); b400m_setreg(b4, R_CIRM, 0x00); flush_hw(); /* wait for XHFC to come out of reset. */ start = jiffies; while (b400m_getreg(b4, R_STATUS) & (V_BUSY | V_PCM_INIT)) { if (time_after(jiffies, start + TIMEOUT)) { b4_info(b4, "hfc_reset() Module won't come out of " "reset... continuing.\n"); break; } }; /* Disable the output clock pin, and also the PLL (it's not needed) */ b400m_setreg(b4, R_CTRL, 0x00); } static void hfc_enable_fifo_irqs(struct b400m *b4) { b400m_setreg(b4, R_IRQ_CTRL, V_FIFO_IRQ_EN | V_GLOB_IRQ_EN); flush_hw(); } static void hfc_enable_interrupts(struct b400m *b4) { b4->running = 1; /* mask all misc interrupts */ b4->misc_irq_mask = 0x01; b400m_setreg(b4, R_MISC_IRQMSK, b4->misc_irq_mask); /* clear any pending interrupts */ b400m_getreg(b4, R_STATUS); b400m_getreg(b4, R_MISC_IRQ); b400m_getreg(b4, R_FIFO_BL0_IRQ); b400m_getreg(b4, R_FIFO_BL1_IRQ); b400m_getreg(b4, R_FIFO_BL2_IRQ); b400m_getreg(b4, R_FIFO_BL3_IRQ); hfc_enable_fifo_irqs(b4); } static inline void hfc_reset_fifo(struct b400m *b4) { hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO | V_RES_LOST | V_RES_FIFO_ERR); } static void hfc_setup_fifo(struct b400m *b4, int fifo) { if (fifo < 4) { /* TX */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b400m_setreg(b4, A_CON_HDLC, V_HDLC_IRQ | V_DATA_FLOW_000 | V_IFF); hfc_reset_fifo(b4); /* RX */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b400m_setreg(b4, A_CON_HDLC, V_HDLC_IRQ | V_DATA_FLOW_000 | V_IFF); hfc_reset_fifo(b4); } else { /* TX */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); b400m_setreg(b4, A_CON_HDLC, V_HDLC_TRP | V_TRP_NO_IRQ | V_DATA_FLOW_110); hfc_reset_fifo(b4); /* RX */ hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); b400m_setreg(b4, A_CON_HDLC, V_HDLC_TRP | V_TRP_NO_IRQ | V_DATA_FLOW_110); hfc_reset_fifo(b4); } } static void hfc_setup_pcm(struct b400m *b4, int port) { int physport; int offset; int hfc_chan; int ts; #ifdef HARDHDLC_RX const int MAX_OFFSET = 2; #else const int MAX_OFFSET = 3; #endif #ifdef SWAP_PORTS /* swap the middle ports */ physport = (1 == port) ? 2 : (2 == port) ? 1 : port; #else physport = port; #endif for (offset = 0; offset < MAX_OFFSET; offset++) { hfc_chan = (port * 4) + offset; ts = (physport * 3) + offset; ts += (b4->b400m_no * 12); b400m_setreg(b4, R_SLOT, (ts << V_SL_NUM_SHIFT)); b400m_setreg(b4, A_SL_CFG, (hfc_chan << V_CH_SNUM_SHIFT) | V_ROUT_TX_STIO2); if (offset < 2) { b400m_setreg(b4, R_SLOT, (ts << V_SL_NUM_SHIFT) | V_SL_DIR); b400m_setreg(b4, A_SL_CFG, (hfc_chan << V_CH_SNUM_SHIFT) | V_ROUT_RX_STIO1 | V_CH_SDIR); } } } #ifdef SWAP_PORTS #ifdef HARDHDLC_RX static const int fifos[24] = {0, 0, 2, 2, 1, 1, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 5, 5, 5, 5, 7, 7, 7, 7 }; #else static const int fifos[24] = {0, 4, 2, 6, 1, 5, 3, 7, 4, 4, 4, 4, 6, 6, 6, 6, 5, 5, 5, 5, 7, 7, 7, 7 }; #endif static const int hfc_chans[12] = {2, 10, 6, 14, 0, 1, 8, 9, 4, 5, 12, 13 }; #else #ifdef HARDHDLC_RX static const int fifos[24] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7 }; #else static const int fifos[24] = {0, 4, 1, 5, 2, 6, 3, 7, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7 }; #endif static const int hfc_chans[12] = { 2, 6, 10, 14, 0, 1, 4, 5, 8, 9, 12, 13 }; #endif static void hfc_setup_fifo_arrays(struct b400m *b4, int fifo) { int val; if (!fifo) { val = (fifos[fifo] << V_FIRST_FIFO_NUM_SHIFT) | (fifo & 1); b400m_setreg(b4, R_FIRST_FIFO, val); } else { #ifdef HARDHDLC_RX val = (fifos[fifo] << V_NEXT_FIFO_NUM_SHIFT) | (fifo & 1); #else val = (fifo < 8) ? (fifos[fifo] << V_NEXT_FIFO_NUM_SHIFT) : (fifos[fifo] << V_NEXT_FIFO_NUM_SHIFT) | (fifo&1); #endif b400m_setreg(b4, A_FIFO_SEQ, val); } b400m_setreg(b4, R_FSM_IDX, fifo); val = (fifo < 8) ? (hfc_chans[fifo>>1] << V_CH_FNUM_SHIFT) : (hfc_chans[fifo>>1] << V_CH_FNUM_SHIFT) | (fifo & 1); b400m_setreg(b4, A_CHANNEL, val); b400m_setreg(b4, A_SUBCH_CFG, 0x02); } static void hfc_setup_fsm(struct b400m *b4) { int chan, fifo, port, offset; #ifdef SWAP_PORTS const int chan_to_fifo[12] = { 4, 4, 0, 6, 6, 2, 5, 5, 1, 7, 7, 3 }; #else const int chan_to_fifo[12] = { 4, 4, 0, 5, 5, 1, 6, 6, 2, 7, 7, 3 }; #endif for (port = 0; port < 4; port++) { for (offset = 0; offset < 3; offset++) { b4->spans[port].fifos[offset] = chan_to_fifo[(port * 3) + offset]; } } for (chan = 0; chan < ARRAY_SIZE(fifos); chan++) hfc_setup_fifo_arrays(b4, chan); b400m_setreg(b4, A_FIFO_SEQ, V_SEQ_END); for (fifo = 0; fifo < 8; fifo++) hfc_setup_fifo(b4, fifo); for (port = 0; port < 4; port++) hfc_setup_pcm(b4, port); } /* takes a read/write fifo pair and optionally resets it, optionally enabling * the rx/tx interrupt */ static void hfc_reset_fifo_pair(struct b400m *b4, int fifo, int reset, int force_no_irq) { unsigned char b; if (down_interruptible(&b4->fifosem)) { b4_info(b4, "Unable to retrieve fifo sem\n"); return; } b = (!force_no_irq && b4->fifo_en_txint & (1 << fifo)) ? V_FIFO_IRQMSK : 0; hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); if (fifo < 4) b |= V_MIX_IRQ; b400m_setreg(b4, A_FIFO_CTRL, b); if (reset) hfc_reset_fifo(b4); b = (!force_no_irq && b4->fifo_en_rxint & (1 << fifo)) ? V_FIFO_IRQMSK : 0; hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); if (fifo < 4) b |= V_MIX_IRQ; b400m_setreg(b4, A_FIFO_CTRL, b); if (reset) hfc_reset_fifo(b4); up(&b4->fifosem); } static void xhfc_set_sync_src(struct b400m *b4, int port) { int b; /* -2 means we need to go back and try again later */ if (port == -2) return; if (port == b4->setsyncspan) return; else b4->setsyncspan = port; b4_info(b4, "xhfc_set_sync_src - modpos %d: setting sync to " "be port %d\n", b4->position, port); if (port == -1) /* automatic */ b = 0; else { #ifdef SWAP_PORTS port = (1 == port) ? 2 : (2 == port) ? 1 : port; #endif b = (port & V_SYNC_SEL_MASK) | V_MAN_SYNC; } b400m_setreg(b4, R_SU_SYNC, b); } static void wctdm_change_card_sync_src(struct wctdm *wc, int newsrc, int master) { int newctlreg; newctlreg = wc->ctlreg; if (master) newctlreg |= (1 << 5); else newctlreg &= ~(1 << 5); newctlreg &= 0xfc; newctlreg |= newsrc; if (DBG_TIMING) { dev_info(&wc->vb.pdev->dev, "Final ctlreg before swap: %02x\n", newctlreg); } wc->ctlreg = newctlreg; wc->oldsync = newsrc; msleep(10); } static void wctdm_change_system_sync_src(int oldsync, int oldspan, int newsync, int newspan) { struct wctdm *wc; struct wctdm *oldsyncwc = NULL, *newsyncwc = NULL; int newspot; int i; int max_latency = 0; if (oldsync > -1) oldsyncwc = ifaces[oldsync]; if (newsync > -1) newsyncwc = ifaces[newsync]; if (newsync == -1) { BUG_ON(!ifaces[0]); newsyncwc = ifaces[0]; newsync = 0; } newspot = (-1 == newspan) ? 0 : 2 | (newspan >> 2); if ((oldsync == newsync) && (oldspan == newspan)) { dev_info(&newsyncwc->vb.pdev->dev, "No need for timing change. All is same\n"); return; } /* First we set all sources to local timing */ for (i = 0; i < WC_MAX_IFACES; i++) { wc = ifaces[i]; if ((wc != oldsyncwc) && wc) { wctdm_change_card_sync_src(wc, 0, 0); if (voicebus_current_latency(&wc->vb) > max_latency) max_latency = voicebus_current_latency(&wc->vb); } } msleep(max_latency << 1); /* Set the old sync source to local timing, not driving timing */ if (oldsyncwc) { wctdm_change_card_sync_src(oldsyncwc, 0, 0); msleep(voicebus_current_latency(&oldsyncwc->vb) << 1); } dev_info(&newsyncwc->vb.pdev->dev, "Setting new card %d now to be timing master\n", newsync); /* Finally, set the new sync source to broadcast master timing */ wctdm_change_card_sync_src(newsyncwc, newspot, 1); msleep(voicebus_current_latency(&newsyncwc->vb) << 1); /* Last we double verify and set all the remaining cards to be timing * slaves */ for (i = 0; (i < WC_MAX_IFACES) && ifaces[i]; i++) { wc = ifaces[i]; if (i == newsync) continue; dev_info(&wc->vb.pdev->dev, "Setting card %d to be timing slave\n", i); wctdm_change_card_sync_src(wc, 1, 0); } msleep(max_latency << 1); synccard = newsync; syncspan = newspan; } static int xhfc_find_sync_with_timingcable(struct b400m *b4) { struct wctdm *wc = b4->wc; int i, j, osrc, src = -1; int lowestprio = 10000; int lowestcard = -1; if (down_trylock(&ifacelock)) { set_bit(WCTDM_CHECK_TIMING, &wc->checkflag); return -2; } for (j = 0; j < WC_MAX_IFACES && ifaces[j]; j++) { if (is_initialized(ifaces[j])) { set_bit(WCTDM_CHECK_TIMING, &wc->checkflag); osrc = -2; goto out; } else { for (i = 0; i < (MAX_SPANS - 1); i++) { struct wctdm_span *wspan = ifaces[j]->spans[i]; if (wspan && wspan->timing_priority && !wspan->span.alarms && (wspan->timing_priority < lowestprio)) { src = i; lowestprio = wspan->timing_priority; lowestcard = j; } } } } if (lowestcard != synccard) { b4_info(b4, "Found new timing master, card " "%d. Old is card %d\n", lowestcard, synccard); } else if (src != syncspan) { b4_info(b4, "Timing change, but only from %d to %d on " "card %d\n", syncspan, src, lowestcard); } wctdm_change_system_sync_src(synccard, syncspan, lowestcard, src); osrc = -1; if (wc == ifaces[lowestcard]) { if (src < (b4->position + 4) && (src >= b4->position)) osrc = src - b4->position; } out: up(&ifacelock); return osrc; } static int xhfc_find_sync_without_timingcable(struct b400m *b4) { struct wctdm *wc = b4->wc; int i, osrc, src = -1; int lowestprio = 10000; int newctlregmux; if (down_trylock(&wc->syncsem)) { set_bit(WCTDM_CHECK_TIMING, &wc->checkflag); return -2; } /* Find lowest slave timing priority on digital spans */ for (i = 0; i < (MAX_SPANS - 1); i++) { struct wctdm_span *const wspan = wc->spans[i]; if (wspan && wspan->timing_priority && !wspan->span.alarms && (wspan->timing_priority < lowestprio)) { src = i; lowestprio = wspan->timing_priority; } } if (src < 0) { if (DBG_TIMING) b4_info(b4, "Picked analog span\n"); osrc = src; goto check_card_timing; } else { if (DBG_TIMING) { b4_info(b4, "Picked span offset %d to be timing " "source\n", src); } } osrc = ((src < (b4->position + 4)) && (src >= b4->position)) ? src - b4->position : -1; if (DBG_TIMING) { b4_info(b4, "For b4->position %d timing is %d\n", b4->position, osrc); } check_card_timing: if (src != -1) newctlregmux = 2 | (src >> 2); else newctlregmux = 0; if ((newctlregmux & 3) != (wc->ctlreg & 3)) { if (DBG_TIMING) { b4_info(b4, "!!!Need to change timing " "on baseboard to spot %d!!!\n", src >> 2); } wctdm_change_card_sync_src(wc, newctlregmux, 0); } else { if (DBG_TIMING) { dev_info(&b4->wc->vb.pdev->dev, "!!!No need to change timing " \ "on baseboard to spot %d, already there!!!\n", src >> 2); } } up(&wc->syncsem); return osrc; } /* * Finds the highest-priority sync span that is not in alarm and returns it. * Note: the span #s in b4->spans[].sync are 1-based, and this returns a * 0-based span, or -1 if no spans are found. */ static inline int xhfc_find_sync(struct b400m *b4) { if (timingcable) return xhfc_find_sync_with_timingcable(b4); else return xhfc_find_sync_without_timingcable(b4); } /* * allocates memory and pretty-prints a given S/T state engine state to it. * calling routine is responsible for freeing the pointer returned! Performs * no hardware access whatsoever, but does use GFP_KERNEL so do not call from * IRQ context. if full == 1, prints a "full" dump; otherwise just prints * current state. */ static char *hfc_decode_st_state(struct b400m *b4, struct b400m_span *span, unsigned char state, int full) { int nt, sta; char s[128], *str; const char *ststr[2][16] = { /* TE, NT */ { "RESET", "?", "SENSING", "DEACT.", "AWAIT.SIG", "IDENT.INPUT", "SYNCD", "ACTIVATED", "LOSTFRAMING", "?", "?", "?", "?", "?", "?", "?" }, { "RESET", "DEACT.", "PEND.ACT", "ACTIVE", "PEND.DEACT", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" } }; str = kmalloc(256, GFP_KERNEL); if (!str) { dev_warn(&b4->wc->vb.pdev->dev, "could not allocate mem for ST state decode " \ "string!\n"); return NULL; } nt = (span->te_mode == 0); sta = (state & V_SU_STA_MASK); sprintf(str, "P%d: %s state %c%d (%s)", span->port + 1, (nt ? "NT" : "TE"), (nt ? 'G' : 'F'), sta, ststr[nt][sta]); if (full) { sprintf(s, " SYNC: %s, RX INFO0: %s", ((state & V_SU_FR_SYNC) ? "yes" : "no"), ((state & V_SU_INFO0) ? "yes" : "no")); strcat(str, s); if (nt) { sprintf(s, ", T2 %s, auto G2->G3: %s", ((state & V_SU_T2_EXP) ? "expired" : "OK"), ((state & V_G2_G3) ? "yes" : "no")); strcat(str, s); } } return str; } /* * sets an S/T port state machine to a given state. if 'auto' is nonzero, * will put the state machine back in auto mode after setting the state. */ static void hfc_handle_state(struct b400m_span *s); static void hfc_force_st_state(struct b400m *b4, struct b400m_span *s, int state, int resume_auto) { b400m_setreg_ra(b4, R_SU_SEL, s->port, A_SU_WR_STA, state | V_SU_LD_STA); if (resume_auto) b400m_setreg_ra(b4, R_SU_SEL, s->port, A_SU_WR_STA, state); if (DBG_ST && ((1 << s->port) & bri_spanfilter)) { char *x; x = hfc_decode_st_state(b4, s, state, 1); b4_info(b4, "forced port %d to state %d (auto: %d), " "new decode: %s\n", s->port + 1, state, resume_auto, x); kfree(x); } /* make sure that we activate any timers/etc needed by this state * change */ hfc_handle_state(s); } /* figures out what to do when an S/T port's timer expires. */ static void hfc_timer_expire(struct b400m_span *s, int t_no) { struct b400m *b4 = s->parent; if (DBG_ST && ((1 << s->port) & bri_spanfilter)) { b4_info(b4, "%lu: hfc_timer_expire, Port %d T%d " "expired (value=%lu ena=%d)\n", b4->ticks, s->port + 1, t_no + 1, s->hfc_timers[t_no], s->hfc_timer_on[t_no]); } /* * there are three timers associated with every HFC S/T port. * * T1 is used by the NT state machine, and is the maximum time the NT * side should wait for G3 (active) state. * * T2 is not actually used in the driver, it is handled by the HFC-4S * internally. * * T3 is used by the TE state machine; it is the maximum time the TE * side should wait for the INFO4 (activated) signal. */ /* First, disable the expired timer; hfc_force_st_state() may activate * it again. */ s->hfc_timer_on[t_no] = 0; switch (t_no) { case XHFC_T1: /* switch to G4 (pending deact.), resume auto mode */ hfc_force_st_state(b4, s, 4, 1); break; case XHFC_T2: /* switch to G1 (deactivated), resume auto mode */ hfc_force_st_state(b4, s, 1, 1); break; case XHFC_T3: /* switch to F3 (deactivated), resume auto mode */ hfc_stop_st(s); if (bri_persistentlayer1) hfc_start_st(s); break; case XHFC_T4: /* switch to F3 (deactivated), resume auto mode */ hfc_handle_state(s); s->hfc_timers[XHFC_T4] = b4->ticks + 1000; s->hfc_timer_on[XHFC_T4] = 1; break; default: if (printk_ratelimit()) { dev_warn(&b4->wc->vb.pdev->dev, "hfc_timer_expire found an unknown expired " "timer (%d)??\n", t_no); } } } /* * Run through the active timers on a card and deal with any expiries. * Also see if the alarm debounce time has expired and if it has, tell DAHDI. */ static void hfc_update_st_timers(struct b400m *b4) { int i, j; struct b400m_span *s; for (i = 0; i < 4; i++) { s = &b4->spans[i]; for (j = XHFC_T1; j <= XHFC_T4; j++) { /* we don't really do timer2, it is expired by the * state change handler */ if (j == XHFC_T2) continue; if (s->hfc_timer_on[j] && time_after_eq(b4->ticks, s->hfc_timers[j])) hfc_timer_expire(s, j); } if (s->wspan && s->newalarm != s->wspan->span.alarms && time_after_eq(b4->ticks, s->alarmtimer)) { s->wspan->span.alarms = s->newalarm; if ((!s->newalarm && bri_teignorered) || (!bri_teignorered)) dahdi_alarm_notify(&s->wspan->span); if (DBG_ALARM) { dev_info(&b4->wc->vb.pdev->dev, "span %d: alarm " \ "%d debounced\n", i + 1, s->newalarm); } set_bit(WCTDM_CHECK_TIMING, &b4->wc->checkflag); } } if (test_and_clear_bit(WCTDM_CHECK_TIMING, &b4->wc->checkflag)) xhfc_set_sync_src(b4, xhfc_find_sync(b4)); } /* this is the driver-level state machine for an S/T port */ static void hfc_handle_state(struct b400m_span *s) { struct b400m *b4; unsigned char state, sta; int nt, newsync, oldalarm; unsigned long oldtimer; b4 = s->parent; nt = !s->te_mode; state = b400m_getreg_ra(b4, R_SU_SEL, s->port, A_SU_RD_STA); sta = (state & V_SU_STA_MASK); if (DBG_ST && ((1 << s->port) & bri_spanfilter)) { char *x; x = hfc_decode_st_state(b4, s, state, 1); b4_info(b4, "port %d A_SU_RD_STA old=0x%02x " "now=0x%02x, decoded: %s\n", s->port + 1, s->oldstate, state, x); kfree(x); } oldalarm = s->newalarm; oldtimer = s->alarmtimer; if (nt) { switch (sta) { default: /* Invalid NT state */ case 0x0: /* NT state G0: Reset */ case 0x1: /* NT state G1: Deactivated */ case 0x4: /* NT state G4: Pending Deactivation */ s->newalarm = DAHDI_ALARM_RED; break; case 0x2: /* NT state G2: Pending Activation */ s->newalarm = DAHDI_ALARM_YELLOW; break; case 0x3: /* NT state G3: Active */ s->hfc_timer_on[XHFC_T1] = 0; s->newalarm = 0; break; } } else { switch (sta) { default: /* Invalid TE state */ case 0x0: /* TE state F0: Reset */ case 0x2: /* TE state F2: Sensing */ case 0x3: /* TE state F3: Deactivated */ case 0x4: /* TE state F4: Awaiting Signal */ case 0x8: /* TE state F8: Lost Framing */ s->newalarm = DAHDI_ALARM_RED; break; case 0x5: /* TE state F5: Identifying Input */ case 0x6: /* TE state F6: Synchronized */ s->newalarm = DAHDI_ALARM_YELLOW; break; case 0x7: /* TE state F7: Activated */ s->hfc_timer_on[XHFC_T3] = 0; s->hfc_timer_on[XHFC_T4] = 0; s->newalarm = 0; break; } } s->alarmtimer = b4->ticks + bri_alarmdebounce; s->oldstate = state; if (DBG_ALARM) { b4_info(b4, "span %d: old alarm %d expires %ld, " "new alarm %d expires %ld\n", s->port + 1, oldalarm, oldtimer, s->newalarm, s->alarmtimer); } /* we only care about T2 expiry in G4. */ if (nt && (sta == 4) && (state & V_SU_T2_EXP)) { if (s->hfc_timer_on[XHFC_T2]) hfc_timer_expire(s, XHFC_T2); /* handle T2 expiry */ } /* If we're in F3 and receiving INFO0, start T3 and jump to F4 */ if (!nt && (sta == 3) && (state & V_SU_INFO0)) { if (bri_persistentlayer1) { s->hfc_timers[XHFC_T3] = b4->ticks + TIMER_3_MS; s->hfc_timer_on[XHFC_T3] = 1; if (DBG_ST) { b4_info(b4, "port %d: receiving " "INFO0 in state 3, setting T3 and " "jumping to F4\n", s->port + 1); } hfc_start_st(s); } } /* read in R_BERT_STA to determine where our current sync source is */ newsync = b400m_getreg(b4, R_BERT_STA) & 0x07; if (newsync != b4->reportedsyncspan) { if (DBG_TIMING) { if (newsync == 5) { b4_info(b4, "new card sync source: SYNC_I\n"); } else { b4_info(b4, "Card position %d: new " "sync source: port %d\n", b4->position, newsync); } } b4->reportedsyncspan = newsync; } } static void hfc_stop_all_timers(struct b400m_span *s) { s->hfc_timer_on[XHFC_T4] = 0; s->hfc_timer_on[XHFC_T3] = 0; s->hfc_timer_on[XHFC_T2] = 0; s->hfc_timer_on[XHFC_T1] = 0; } static void hfc_stop_st(struct b400m_span *s) { struct b400m *b4 = s->parent; hfc_stop_all_timers(s); b400m_setreg_ra(b4, R_SU_SEL, s->port, A_SU_WR_STA, V_SU_ACT_DEACTIVATE); } /* * resets an S/T interface to a given NT/TE mode */ static void hfc_reset_st(struct b400m_span *s) { int b; struct b400m *b4; b4 = s->parent; hfc_stop_st(s); /* force state G0/F0 (reset), then force state 1/2 * (deactivated/sensing) */ b400m_setreg_ra(b4, R_SU_SEL, s->port, A_SU_WR_STA, V_SU_LD_STA); flush_hw(); /* make sure write hit hardware */ s->wspan->span.alarms = DAHDI_ALARM_RED; s->newalarm = DAHDI_ALARM_RED; dahdi_alarm_notify(&s->wspan->span); /* set up the clock control register. Must be done before we activate * the interface. */ if (s->te_mode) b = 0x0e; else b = 0x0c | (6 << V_SU_SMPL_SHIFT); b400m_setreg(b4, A_SU_CLK_DLY, b); /* set TE/NT mode, enable B and D channels. */ b400m_setreg(b4, A_SU_CTRL0, V_B1_TX_EN | V_B2_TX_EN | (s->te_mode ? 0 : V_SU_MD) | V_ST_PU_CTRL); b400m_setreg(b4, A_SU_CTRL1, V_G2_G3_EN); b400m_setreg(b4, A_SU_CTRL2, V_B1_RX_EN | V_B2_RX_EN); b400m_setreg(b4, A_ST_CTRL3, (0x7c << 1)); /* enable the state machine. */ b400m_setreg(b4, A_SU_WR_STA, 0x00); flush_hw(); } static void hfc_start_st(struct b400m_span *s) { struct b400m *b4 = s->parent; b400m_setreg_ra(b4, R_SU_SEL, s->port, A_SU_WR_STA, V_SU_ACT_ACTIVATE); /* start T1 if in NT mode, T3 if in TE mode */ if (s->te_mode) { /* 500ms wait first time, TIMER_3_MS afterward. */ s->hfc_timers[XHFC_T3] = b4->ticks + TIMER_3_MS; s->hfc_timer_on[XHFC_T3] = 1; s->hfc_timer_on[XHFC_T1] = 0; s->hfc_timers[XHFC_T4] = b4->ticks + 1000; s->hfc_timer_on[XHFC_T4] = 1; if (DBG_ST) { b4_info(b4, "setting port %d t3 timer to %lu\n", s->port + 1, s->hfc_timers[XHFC_T3]); } } else { static const int TIMER_1_MS = 2000; s->hfc_timers[XHFC_T1] = b4->ticks + TIMER_1_MS; s->hfc_timer_on[XHFC_T1] = 1; s->hfc_timer_on[XHFC_T3] = 0; if (DBG_ST) { b4_info(b4, "setting port %d t1 timer to %lu\n", s->port + 1, s->hfc_timers[XHFC_T1]); } } } /* * read in the HFC GPIO to determine each port's mode (TE or NT). * Then, reset and start the port. * the flow controller should be set up before this is called. */ static int hdlc_start(struct b400m *b4, int fifo); static void hfc_init_all_st(struct b400m *b4) { int i; struct b400m_span *s; for (i = 0; i < 4; i++) { s = &b4->spans[i]; s->parent = b4; #ifdef SWAP_PORTS s->port = (1 == i) ? 2 : (2 == i) ? 1 : i; #else s->port = i; #endif s->te_mode = 1; hdlc_start(b4, s->fifos[2]); } } /* NOTE: assumes fifo lock is held */ #define debug_fz(b4, fifo, prefix, buf) \ do { \ sprintf(buf, "%s: (fifo %d): f1/f2/flen=%d/%d/%d, " \ "z1/z2/zlen=%d/%d/%d\n", prefix, fifo, f1, f2, flen, z1, \ z2, zlen); \ } while (0) /* enable FIFO RX int and reset the FIFO */ static int hdlc_start(struct b400m *b4, int fifo) { b4->fifo_en_txint |= (1 << fifo); b4->fifo_en_rxint |= (1 << fifo); hfc_reset_fifo_pair(b4, fifo, 1, 0); return 0; } #ifdef HARDHDLC_RX /** * hdlc_signal_complete() - Signal dahdi that we have a complete frame. * * @bpan: The span which received the frame. * @stat: The frame status from the XHFC controller. * */ static void hdlc_signal_complete(struct b400m_span *bspan, u8 stat) { struct b400m *b4 = bspan->parent; /* if STAT != 0, indicates bad frame */ if (stat != 0x00) { if (DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "(span %d) STAT=0x%02x indicates " \ "frame problem: %s\n", bspan->port + 1, stat, (0xff == stat) ? "HDLC Abort" : "Bad FCS"); } dahdi_hdlc_abort(bspan->sigchan, (0xff == stat) ? DAHDI_EVENT_ABORT : DAHDI_EVENT_BADFCS); /* STAT == 0, means frame was OK */ } else { if (DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "(span %d) Frame %d is good!\n", bspan->port + 1, bspan->frames_in); } dahdi_hdlc_finish(bspan->sigchan); } } /* * Inner loop for D-channel receive function. Retrieves HDLC data from the * hardware. If the hardware indicates that the frame is complete, we check * the HDLC engine's STAT byte and update DAHDI as needed. * * Returns the number of HDLC frames left in the FIFO, or -1 if we couldn't * get the lock. */ static int hdlc_rx_frame(struct b400m_span *bspan) { int fifo, i, j, x, zleft; int z1, z2, zlen, f1, f2, flen, new_flen; unsigned char buf[B400M_HDLC_BUF_LEN]; char debugbuf[256]; struct b400m *b4 = bspan->parent; fifo = bspan->fifos[2]; if (DBG_HDLC && DBG_SPANFILTER) b4_info(b4, "hdlc_rx_frame fifo %d: start\n", fifo); if (down_trylock(&b4->fifosem) && DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "rx_frame: fifo %d 1: couldn't get lock\n", fifo); return -1; } hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); get_F(f1, f2, flen); get_Z(z1, z2, zlen); debug_fz(b4, fifo, "hdlc_rx_frame", debugbuf); up(&b4->fifosem); if (DBG_HDLC && DBG_SPANFILTER) pr_info("%s", debugbuf); /* if we have at least one complete frame, increment zleft to include * status byte */ zleft = zlen; if (flen) zleft++; do { if (zleft > B400M_HDLC_BUF_LEN) j = B400M_HDLC_BUF_LEN; else j = zleft; if (down_trylock(&b4->fifosem) && DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "rx_frame fifo %d 2: couldn't get lock\n", fifo); return -1; } hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); for (i = 0; i < j; i++) buf[i] = b400m_getreg(b4, A_FIFO_DATA); up(&b4->fifosem); /* don't send STAT byte to DAHDI */ x = j; if (bspan->sigchan) { if ((j != B400M_HDLC_BUF_LEN) && flen) x--; if (x) dahdi_hdlc_putbuf(bspan->sigchan, buf, x); } zleft -= j; if (DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "transmitted %d bytes to dahdi, " \ "zleft=%d\n", x, zleft); } if (DBG_HDLC && DBG_SPANFILTER) { /* !!! */ b4_info(b4, "hdlc_rx_frame(span %d): " \ "z1/z2/zlen=%d/%d/%d, zleft=%d\n", bspan->port + 1, z1, z2, zlen, zleft); for (i = 0; i < j; i++) { b4_info(b4, "%02x%c", buf[i], (i < (j - 1)) ? ' ' : '\n'); } } } while (zleft > 0); /* Frame received, increment F2 and get an updated count of frames * left */ if (down_trylock(&b4->fifosem) && DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "rx_frame fifo %d 3: couldn't get lock\n", fifo); return 0; } /* go get the F count again, just in case another frame snuck in while * we weren't looking. */ if (flen) { hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_INC_F); ++bspan->frames_in; get_F(f1, f2, new_flen); } else new_flen = flen; up(&b4->fifosem); /* If this channel is not configured with a signalling span we don't * need to notify the rest of dahdi about this frame. */ if (!bspan->sigchan) { if (DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "hdlc_rx_frame fifo %d: " \ "new_flen %d, early end.\n", fifo, new_flen); } return new_flen; } if (flen) { /* disable < 3 check for now */ if (0 && zlen < 3) { if (DBG_HDLC && DBG_SPANFILTER) b4_info(b4, "odd, zlen less then 3?\n"); dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_ABORT); } else { hdlc_signal_complete(bspan, buf[i - 1]); } } if (DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "hdlc_rx_frame fifo %d: new_flen=%d end.\n", fifo, new_flen); } return new_flen; } #endif /* HARDHDLC_RX */ /* * Takes one blob of data from DAHDI and shoots it out to the hardware. The * blob may or may not be a complete HDLC frame. If it isn't, the D-channel * FIFO interrupt handler will take care of pulling the rest. Returns nonzero * if there is still data to send in the current HDLC frame. */ static int hdlc_tx_frame(struct b400m_span *bspan) { struct b400m *b4 = bspan->parent; int res, i, fifo; int z1, z2, zlen; int f1 = -1, f2 = -1, flen = -1; unsigned char buf[B400M_HDLC_BUF_LEN]; unsigned int size = ARRAY_SIZE(buf); char debugbuf[256]; /* if we're ignoring TE red alarms and we are in alarm, restart the * S/T state machine */ if (bspan->te_mode && (bspan->newalarm != 0)) { hfc_start_st(bspan); } fifo = bspan->fifos[2]; res = dahdi_hdlc_getbuf(bspan->sigchan, buf, &size); if (down_interruptible(&b4->fifosem)) { static int arg; b4_info(b4, "b400m: arg (%d), grabbed data from DAHDI " \ "but couldn't grab the lock!\n", ++arg); /* TODO: Inform DAHDI that we have grabbed data and can't use * it */ dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_OVERRUN); return 1; /* return 1 so we keep trying */ } hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); get_Z(z1, z2, zlen); debug_fz(b4, fifo, __func__, debugbuf); /* TODO: check zlen, etc. */ if ((HFC_ZMAX-zlen) < size) { static int arg; b4_info(b4, "b400m: arg (%d), zlen (%d) < what we " \ "grabbed from DAHDI (%d)!\n", ++arg, zlen, size); size = zlen; dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_OVERRUN); } if (size > 0) { bspan->sigactive = 1; for (i = 0; i < size; i++) b400m_setreg(b4, A_FIFO_DATA, buf[i]); /* * If we got a full frame from DAHDI, increment F and * decrement our HDLC pending counter. Otherwise, select the * FIFO again (to start transmission) and make sure the TX IRQ * is enabled so we will get called again to finish off the * data */ if (res != 0) { ++bspan->frames_out; bspan->sigactive = 0; hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_INC_F); atomic_dec(&bspan->hdlc_pending); } else { hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT)); } } up(&b4->fifosem); if (0 && DBG_HDLC && DBG_SPANFILTER) { b4_info(b4, "%s", debugbuf); b4_info(b4, "hdlc_tx_frame(span %d): DAHDI gave %d " \ "bytes for FIFO %d (res = %d)\n", bspan->port + 1, size, fifo, res); for (i = 0; i < size; i++) b4_info(b4, "%02x%c\n", buf[i], (i < (size - 1)) ? ' ' : '\n'); if (size && res != 0) { pr_info("Transmitted frame %d on span %d\n", bspan->frames_out - 1, bspan->port); } } return (res == 0); } /* * b400m lowlevel functions These are functions which impact more than just * the HFC controller. (those are named hfc_xxx()) */ /* * Performs a total reset of the card, reinitializes GPIO. The card is * initialized enough to have LEDs running, and that's about it. Anything to * do with audio and enabling any kind of processing is done in stage2. */ static void xhfc_init_stage1(struct b400m *b4) { int i; hfc_reset(b4); hfc_gpio_init(b4); /* make sure interrupts are disabled */ b400m_setreg(b4, R_IRQ_CTRL, 0x00); /* make sure write hits hardware */ flush_hw(); /* disable all FIFO interrupts */ for (i = 0; i < HFC_NR_FIFOS; i++) { hfc_setreg_waitbusy(b4, R_FIFO, (i << V_FIFO_NUM_SHIFT)); /* disable the interrupt */ b400m_setreg(b4, A_FIFO_CTRL, 0x00); hfc_setreg_waitbusy(b4, R_FIFO, (i << V_FIFO_NUM_SHIFT) | V_FIFO_DIR); /* disable the interrupt */ b400m_setreg(b4, A_FIFO_CTRL, 0x00); flush_hw(); } /* set fill threshhold to 16 bytes */ b400m_setreg(b4, R_FIFO_THRES, 0x11); /* clear any pending FIFO interrupts */ b400m_getreg(b4, R_FIFO_BL2_IRQ); b400m_getreg(b4, R_FIFO_BL3_IRQ); b4->misc_irq_mask = 0x00; b400m_setreg(b4, R_MISC_IRQMSK, b4->misc_irq_mask); b400m_setreg(b4, R_IRQ_CTRL, 0); } /* * Stage 2 hardware init. Sets up the flow controller, PCM and FIFOs. * Initializes the echo cancellers. S/T interfaces are not initialized here, * that is done later, in hfc_init_all_st(). Interrupts are enabled and once * the s/t interfaces are configured, chip should be pretty much operational. */ static void xhfc_init_stage2(struct b400m *b4) { /* * set up PCM bus. XHFC is PCM slave C2IO is the clock, auto sync, * SYNC_O follows SYNC_I. 128 timeslots, long frame sync positive * polarity, sample on falling clock edge. STIO2 is transmit-only, * STIO1 is receive-only. */ b400m_setreg(b4, R_PCM_MD0, V_PCM_IDX_MD1); b400m_setreg(b4, R_PCM_MD1, V_PCM_DR_8192 | (0x3 << 2)); b400m_setreg(b4, R_PCM_MD0, V_PCM_IDX_MD2); b400m_setreg(b4, R_PCM_MD2, V_C2I_EN | V_SYNC_OUT1); b400m_setreg(b4, R_SU_SYNC, V_SYNC_SEL_PORT0); /* Now set up the flow controller. */ hfc_setup_fsm(b4); /* * At this point, everything's set up and ready to go. Don't actually * enable the global interrupt pin. DAHDI still needs to start up the * spans, and we don't know exactly when. */ } static inline struct b400m_span *bspan_from_dspan(struct dahdi_span *span) { return container_of(span, struct wctdm_span, span)->bspan; } static int xhfc_startup(struct dahdi_span *span) { struct b400m_span *bspan = bspan_from_dspan(span); struct b400m *b4 = bspan->parent; if (!b4->running) hfc_enable_interrupts(bspan->parent); return 0; } /* resets all the FIFOs for a given span. Disables IRQs for the span FIFOs */ static void xhfc_reset_span(struct b400m_span *bspan) { int i; struct b400m *b4 = bspan->parent; /* b4_info(b4, "xhfc_reset_span()\n"); */ for (i = 0; i < 3; i++) hfc_reset_fifo_pair(b4, bspan->fifos[i], (i == 2) ? 1 : 0, 1); } static void b400m_enable_workqueues(struct wctdm *wc) { struct b400m *b4s[2]; int i, numb4s = 0; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); for (i = 0; i < wc->mods_per_board; i += 4) { if (wc->mods[i].type == BRI) b4s[numb4s++] = wc->mods[i].mod.bri; } spin_unlock_irqrestore(&wc->reglock, flags); for (i = 0; i < numb4s; i++) { if (b4s[i]) b4s[i]->shutdown = 0; } } static void b400m_disable_workqueues(struct wctdm *wc) { struct b400m *b4s[2]; int i, numb4s = 0; unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); for (i = 0; i < wc->mods_per_board; i += 4) { if (wc->mods[i].type == BRI) b4s[numb4s++] = wc->mods[i].mod.bri; } spin_unlock_irqrestore(&wc->reglock, flags); for (i = 0; i < numb4s; i++) { if (b4s[i]) { down(&wc->syncsem); b4s[i]->shutdown = 1; up(&wc->syncsem); flush_workqueue(b4s[i]->xhfc_ws); } } } /* * Software selectable NT and TE mode settings on the B400M. * * mode - bitwise selection of NT vs TE mode * 1 = NT; 0 = TE; * bit 0 is port 0 * bit 1 is port 1 * ... * term - termination resistance * 0 = no termination resistance * 1 = 390 ohm termination resistance switched on */ static int b400m_set_ntte(struct b400m_span *bspan, int te_mode, int term_on) { struct b400m *b4 = bspan->parent; unsigned char data; unsigned char addr; int all_modes = 0, all_terms = 0; int i; bspan->wspan->span.spantype = (te_mode > 0) ? "TE" : "NT"; bspan->te_mode = te_mode; bspan->term_on = term_on; for (i = 0; i < 4; i++) { if (!b4->spans[i].te_mode) all_modes |= (1 << i); if (b4->spans[i].term_on) all_terms |= (1 << i); } data = 0x10 | ((all_terms << 4) & 0xc0) | ((all_terms << 2) & 0x0c); addr = 0x10 | all_modes; msleep(voicebus_current_latency(&b4->wc->vb) + 2); wctdm_setreg(b4->wc, get_mod(b4), addr, data); b4->lastreg = 0xff; msleep(voicebus_current_latency(&b4->wc->vb) + 2); hfc_reset_st(bspan); if (bri_persistentlayer1) hfc_start_st(bspan); return 0; } /* spanconfig for us means ...? */ int b400m_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct b400m_span *bspan; struct b400m *b4; struct wctdm *wc; int te_mode, term; int pos; int res; bspan = bspan_from_dspan(span); b4 = bspan->parent; wc = b4->wc; if ((file->f_flags & O_NONBLOCK) && !is_initialized(wc)) return -EAGAIN; res = wctdm_wait_for_ready(wc); if (res) return res; b400m_disable_workqueues(b4->wc); te_mode = (lc->lineconfig & DAHDI_CONFIG_NTTE) ? 0 : 1; term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0; b4_info(b4, "xhfc: Configuring port %d span %d in %s " \ "mode with termination resistance %s\n", bspan->port, span->spanno, (te_mode) ? "TE" : "NT", (term) ? "ENABLED" : "DISABLED"); b400m_set_ntte(bspan, te_mode, term); if (lc->sync < 0) { b4_info(b4, "Span %d has invalid sync priority (%d), " \ "removing from sync source list\n", span->spanno, lc->sync); lc->sync = 0; } if (span->offset >= 4) { pos = span->offset; } else { /* This is tricky. Have to figure out if we're slot 1 or slot * 2 */ pos = span->offset + b4->position; } if (!te_mode && lc->sync) { b4_info(b4, "NT Spans cannot be timing sources. " \ "Span %d requested to be timing source of " \ "priority %d. Changing priority to 0\n", pos, lc->sync); lc->sync = 0; } wc->spans[pos]->timing_priority = lc->sync; bspan->wspan = container_of(span, struct wctdm_span, span); xhfc_reset_span(bspan); /* call startup() manually here, because DAHDI won't call the startup * function unless it receives an IOCTL to do so, and dahdi_cfg * doesn't. */ xhfc_startup(span); span->flags |= DAHDI_FLAG_RUNNING; set_bit(WCTDM_CHECK_TIMING, &wc->checkflag); b400m_enable_workqueues(b4->wc); return 0; } /* chanconfig for us means to configure the HDLC controller, if appropriate * * NOTE: apparently the DAHDI ioctl function calls us with a interrupts * disabled. This means we cannot actually touch the hardware, because all * register accesses are wrapped up in a mutex that can sleep. * * The solution to that is to simply increment the span's "restart" flag, and * the driver's workqueue will do the dirty work on our behalf. */ int b400m_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { int alreadyrunning; struct b400m_span *bspan = bspan_from_dspan(chan->span); struct b400m *b4 = bspan->parent; int res; if ((file->f_flags & O_NONBLOCK) && !is_initialized(b4->wc)) return -EAGAIN; res = wctdm_wait_for_ready(b4->wc); if (res) return res; alreadyrunning = bspan->wspan->span.flags & DAHDI_FLAG_RUNNING; if (DBG_FOPS) { b4_info(b4, "%s channel %d (%s) sigtype %08x\n", alreadyrunning ? "Reconfigured" : "Configured", chan->channo, chan->name, sigtype); } switch (sigtype) { case DAHDI_SIG_HARDHDLC: if (DBG_FOPS) { b4_info(b4, "%sonfiguring hardware HDLC on %s\n", ((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : "Unc"), chan->name); } bspan->sigchan = chan; bspan->sigactive = 0; atomic_set(&bspan->hdlc_pending, 0); res = 0; break; case DAHDI_SIG_HDLCFCS: case DAHDI_SIG_HDLCNET: case DAHDI_SIG_HDLCRAW: /* Only HARDHDLC is supported for the signalling channel on BRI * spans. */ res = -EINVAL; break; default: res = 0; break; }; return res; } int b400m_dchan(struct dahdi_span *span) { struct b400m_span *bspan; struct b400m *b4; unsigned char *rxb; int res; int i; bspan = bspan_from_dspan(span); b4 = bspan->parent; #ifdef HARDHDLC_RX return 0; #else #endif if (!bspan->sigchan) return 0; rxb = bspan->sigchan->readchunk; if (!rxb) { b4_info(b4, "No RXB!\n"); return 0; } for (i = 0; i < DAHDI_CHUNKSIZE; i++) { fasthdlc_rx_load_nocheck(&bspan->rxhdlc, *(rxb++)); res = fasthdlc_rx_run(&bspan->rxhdlc); /* If there is nothing there, continue */ if (res & RETURN_EMPTY_FLAG) continue; else if (res & RETURN_COMPLETE_FLAG) { if (!bspan->f_sz) continue; /* Only count this if it's a non-empty frame */ if (bspan->infcs != PPP_GOODFCS) { dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_BADFCS); } else { dahdi_hdlc_finish(bspan->sigchan); } bspan->infcs = PPP_INITFCS; bspan->f_sz = 0; continue; } else if (res & RETURN_DISCARD_FLAG) { if (!bspan->f_sz) continue; dahdi_hdlc_abort(bspan->sigchan, DAHDI_EVENT_ABORT); bspan->infcs = PPP_INITFCS; bspan->f_sz = 0; break; } else { unsigned char rxc = res; bspan->infcs = PPP_FCS(bspan->infcs, rxc); bspan->f_sz++; dahdi_hdlc_putbuf(bspan->sigchan, &rxc, 1); } } return 0; } /* internal functions, not specific to the hardware or DAHDI */ /* */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void xhfc_work(void *data) { struct b400m *b4 = data; #else static void xhfc_work(struct work_struct *work) { struct b400m *b4 = container_of(work, struct b400m, xhfc_wq); #endif int i, j, k, fifo; unsigned char b, b2; if (b4->shutdown || !is_initialized(b4->wc)) return; b4->irq_oview = b400m_getreg(b4, R_IRQ_OVIEW); b4->fifo_fill = b400m_getreg(b4, R_FILL_BL0); if (b4->irq_oview & V_FIFO_BL0_IRQ) { b4->fifo_irqstatus |= b400m_getreg(b4, R_FIFO_BL0_IRQ); b4->irq_oview &= ~V_FIFO_BL0_IRQ; } /* only look at BL0, we put all D channel FIFOs in the first block. */ b = b2 = b4->fifo_irqstatus; for (j = 0; j < 4; j++) { #ifdef SWAP_PORTS fifo = (1 == j) ? 2 : (2 == j) ? 1 : j; #else fifo = j; #endif #ifdef HARDHDLC_RX if (b & V_FIFOx_RX_IRQ) { if (fifo < 4) { /* d-channel FIFO */ /* * I have to loop here until hdlc_rx_frame * says there are no more frames waiting. for * whatever reason, the HFC will not generate * another interrupt if there are still HDLC * frames waiting to be received. i.e. I get * an int when F1 changes, not when F1 != F2. * */ do { k = hdlc_rx_frame(&b4->spans[fifo]); } while (k); } } #endif b >>= 2; } /* zero the bits we just processed */ b4->fifo_irqstatus &= ~b2; b4->fifo_fill &= ~b2; #if 1 /* All four D channel FIFOs are in BL0. */ b = b2 = b4->fifo_fill; for (j = 0; j < 4; j++) { #ifdef SWAP_PORTS fifo = (1 == j) ? 2 : (2 == j) ? 1 : j; #else fifo = j; #endif if (b4->spans[fifo].sigactive && (b & V_FIFOx_TX_IRQ)) hdlc_tx_frame(&b4->spans[fifo]); #ifdef HARDHDLC_RX if (b & V_FIFOx_RX_IRQ) hdlc_rx_frame(&b4->spans[fifo]); #endif b >>= 2; } #endif /* Check for outgoing HDLC frame requests The HFC does not generate TX * interrupts when there is room to send, so I use an atomic counter * that is incremented every time DAHDI wants to send a frame, and * decremented every time I send a frame. It'd be better if I could * just use the interrupt handler, but the HFC seems to trigger a FIFO * TX IRQ only when it has finished sending a frame, not when one can * be sent. */ for (i = 0; i < ARRAY_SIZE(b4->spans); i++) { struct b400m_span *bspan = &b4->spans[i]; if (atomic_read(&bspan->hdlc_pending)) { do { k = hdlc_tx_frame(bspan); } while (k); } } b = b400m_getreg(b4, R_SU_IRQ); if (b) { for (i = 0; i < ARRAY_SIZE(b4->spans); i++) { int physport; #ifdef SWAP_PORTS if (i == 1) physport = 2; else if (i == 2) physport = 1; else physport = i; #else physport = i; #endif if (b & (1 << i)) hfc_handle_state(&b4->spans[physport]); } } hfc_update_st_timers(b4); } void wctdm_bri_checkisr(struct wctdm *wc, struct wctdm_module *const mod, int offset) { struct b400m *b4 = mod->mod.bri; /* don't do anything for non-base card slots */ if (mod->card & 0x03) return; /* DEFINITELY don't do anything if our structures aren't ready! */ if (!is_initialized(wc) || !b4 || !b4->inited) return; if (offset == 0) { if (!b4->shutdown) queue_work(b4->xhfc_ws, &b4->xhfc_wq); b4->ticks++; } return; } /* DAHDI calls this when it has data it wants to send to the HDLC controller */ void wctdm_hdlc_hard_xmit(struct dahdi_chan *chan) { struct b400m *b4; struct b400m_span *bspan; struct dahdi_span *dspan; int span; dspan = chan->span; bspan = bspan_from_dspan(dspan); b4 = bspan->parent; span = bspan->port; if ((DBG_FOPS || DBG_HDLC) && DBG_SPANFILTER) { b4_info(b4, "hdlc_hard_xmit on chan %s (%i/%i), " \ "span=%i (sigchan=%p, chan=%p)\n", chan->name, chan->channo, chan->chanpos, span + 1, bspan->sigchan, chan); } /* Increment the hdlc_pending counter and trigger the bottom-half so * it will be picked up and sent. */ if (bspan->sigchan == chan) atomic_inc(&bspan->hdlc_pending); } static int b400m_probe(struct wctdm *wc, int modpos) { unsigned char id, x; struct b400m *b4; unsigned long flags; int chiprev; wctdm_setreg(wc, &wc->mods[modpos], 0x10, 0x10); id = xhfc_getreg(wc, &wc->mods[modpos], R_CHIP_ID, &x); /* chip ID high 7 bits must be 0x62, see datasheet */ if ((id & 0xfe) != 0x62) return -2; b4 = kzalloc(sizeof(struct b400m), GFP_KERNEL); if (!b4) { dev_err(&wc->vb.pdev->dev, "Couldn't allocate memory for b400m structure!\n"); return -ENOMEM; } /* card found, enabled and main struct allocated. Fill it out. */ b4->wc = wc; b4->position = modpos; /* which B400M in the system is this one? count all of them found so * far */ for (x = 0; x < modpos; x += 4) { if (wc->mods[x].type == BRI) ++b4->b400m_no; } spin_lock_init(&b4->reglock); sema_init(&b4->regsem, 1); sema_init(&b4->fifosem, 1); for (x = 0; x < 4; x++) { fasthdlc_init(&b4->spans[x].rxhdlc, FASTHDLC_MODE_16); b4->spans[x].infcs = PPP_INITFCS; } b4->lastreg = 0xff; /* a register we won't hit right off the bat */ chiprev = b400m_getreg(b4, R_CHIP_RV); b4->setsyncspan = -1; /* sync span is unknown */ b4->reportedsyncspan = -1; /* sync span is unknown */ if (DBG) { b4_info(b4, "Identified controller rev %d in module %d.\n", chiprev, b4->position); } xhfc_init_stage1(b4); xhfc_init_stage2(b4); hfc_init_all_st(b4); hfc_enable_interrupts(b4); spin_lock_irqsave(&wc->reglock, flags); wc->mods[modpos].mod.bri = (void *)b4; spin_unlock_irqrestore(&wc->reglock, flags); return 0; } void b400m_post_init(struct b400m *b4) { snprintf(b4->name, sizeof(b4->name) - 1, "b400m-%d", b4->b400m_no); b4->xhfc_ws = create_singlethread_workqueue(b4->name); # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&b4->xhfc_wq, xhfc_work, b4); # else INIT_WORK(&b4->xhfc_wq, xhfc_work); # endif b4->inited = 1; } /* functions called from the wctdm code */ int wctdm_init_b400m(struct wctdm *wc, int card) { int ret = 0; unsigned long flags; if (wc->mods[card & 0xfc].type == QRV) return -2; if (!(card & 0x03)) { /* only init if at lowest port in module */ spin_lock_irqsave(&wc->reglock, flags); wc->mods[card + 0].type = BRI; wc->mods[card + 0].mod.bri = NULL; wc->mods[card + 1].type = BRI; wc->mods[card + 1].mod.bri = NULL; wc->mods[card + 2].type = BRI; wc->mods[card + 2].mod.bri = NULL; wc->mods[card + 3].type = BRI; wc->mods[card + 3].mod.bri = NULL; spin_unlock_irqrestore(&wc->reglock, flags); msleep(20); if (b400m_probe(wc, card) != 0) { spin_lock_irqsave(&wc->reglock, flags); wc->mods[card + 0].type = NONE; wc->mods[card + 1].type = NONE; wc->mods[card + 2].type = NONE; wc->mods[card + 3].type = NONE; spin_unlock_irqrestore(&wc->reglock, flags); ret = -2; } } else { /* for the "sub-cards" */ if (wc->mods[card & 0xfc].type == BRI) { spin_lock_irqsave(&wc->reglock, flags); wc->mods[card].type = BRI; wc->mods[card].mod.bri = wc->mods[card & 0xfc].mod.bri; spin_unlock_irqrestore(&wc->reglock, flags); } else { ret = -2; } } return ret; } void wctdm_unload_b400m(struct wctdm *wc, int card) { struct b400m *b4 = wc->mods[card].mod.bri; int i; /* TODO: shutdown once won't work if just a single card is hotswapped * out. But since most of the time this is called because the entire * driver is in the process of unloading, I'll leave it here. */ static int shutdown_once; /* only really unload with the 'base' card number. base+1/2/3 aren't * real. */ if (card & 0x03) return; if (timingcable && !shutdown_once) { b4_info(b4, "Disabling all workqueues for B400Ms\n"); /* Gotta shut down timing change potential during this */ for (i = 0; i < WC_MAX_IFACES; i++) { if (ifaces[i]) b400m_disable_workqueues(ifaces[i]); } b4_info(b4, "Forcing sync to card 0\n"); /* Put the timing configuration in a known state: card 0 is * master */ wctdm_change_system_sync_src(synccard, syncspan, -1, -1); /* Change all other cards in the system to self time before * card 0 is removed */ b4_info(b4, "Setting all cards to return to self sync\n"); for (i = 1; i < WC_MAX_IFACES; i++) { if (ifaces[i]) wctdm_change_card_sync_src(ifaces[i], 0, 0); } b4_info(b4, "Finished preparing timing linked cards for " "shutdown\n"); shutdown_once = 1; } if (b4) { b4->inited = 0; msleep(100); /* TODO: wait for tdm24xx driver to unregister the spans */ /* do { ... } while(not_unregistered); */ /* Change sync source back to base board so we don't freeze up * when we reset the XHFC */ b400m_disable_workqueues(wc); for (i = 0; i < (MAX_SPANS - 1); i++) { if (wc->spans[i]) wc->spans[i]->timing_priority = 0; } for (i = 0; i < ARRAY_SIZE(b4->spans); i++) b4->spans[i].wspan->span.flags &= ~DAHDI_FLAG_RUNNING; wctdm_change_card_sync_src(b4->wc, 0, 0); xhfc_init_stage1(b4); destroy_workqueue(b4->xhfc_ws); /* Set these to NONE to ensure that our checkisr * routines are not entered */ wc->mods[card].type = NONE; wc->mods[card + 1].type = NONE; wc->mods[card + 2].type = NONE; wc->mods[card + 3].type = NONE; wc->mods[card].mod.bri = NULL; wc->mods[card + 1].mod.bri = NULL; wc->mods[card + 2].mod.bri = NULL; wc->mods[card + 3].mod.bri = NULL; msleep(voicebus_current_latency(&wc->vb) << 1); b4_info(b4, "Driver unloaded.\n"); kfree(b4); } } void b400m_module_init(void) { fasthdlc_precalc(); } void b400m_module_cleanup(void) { } dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/Kbuild0000644000175000017500000000021311341774614021723 0ustar tzafrirtzafrirobj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP) += wctdm24xxp.o EXTRA_CFLAGS += -I$(src)/.. -Wno-undef wctdm24xxp-objs := base.o xhfc.o dahdi-linux-2.5.0.1/drivers/dahdi/wctdm24xxp/wctdm24xxp.h0000644000175000017500000001573311623264545023000 0ustar tzafrirtzafrir/* * Wildcard TDM2400P TDM FXS/FXO Interface Driver for DAHDI Telephony interface * * Written by Mark Spencer * Support for TDM800P and VPM150M by Matthew Fredrickson * * Copyright (C) 2005-2010 Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _WCTDM24XXP_H #define _WCTDM24XXP_H #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #include #else #include #endif #include "voicebus/voicebus.h" #define NUM_FXO_REGS 60 #define WC_MAX_IFACES 128 /*! * \brief Default ringer debounce (in ms) */ #define DEFAULT_RING_DEBOUNCE 1024 #define POLARITY_DEBOUNCE 64 /* Polarity debounce (in ms) */ #define OHT_TIMER 6000 /* How long after RING to retain OHT */ #define FLAG_EXPRESS (1 << 0) #define EFRAME_SIZE 108L #define EFRAME_GAP 20L #define SFRAME_SIZE ((EFRAME_SIZE * DAHDI_CHUNKSIZE) + (EFRAME_GAP * (DAHDI_CHUNKSIZE - 1))) #define MAX_ALARMS 10 #define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ #define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ #define PEGCOUNT 5 /* 5 cycles of pegging means RING */ #define SDI_CLK (0x00010000) #define SDI_DOUT (0x00020000) #define SDI_DREAD (0x00040000) #define SDI_DIN (0x00080000) #define __CMD_RD (1 << 20) /* Read Operation */ #define __CMD_WR (1 << 21) /* Write Operation */ #define __CMD_FIN (1 << 22) /* Has finished receive */ #define __CMD_TX (1 << 23) /* Has been transmitted */ #define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR) #define CMD_RD(a) (((a) << 8) | __CMD_RD) #if 0 #define CMD_BYTE(card,bit,altcs) (((((card) & 0x3) * 3 + (bit)) * 7) \ + ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0)) #endif #define NUM_MODULES 24 #define NUM_SLOTS 6 #define MAX_SPANS 9 #define NUM_CAL_REGS 12 #define ISR_COMMANDS 2 #define QRV_DEBOUNCETIME 20 #define VPM150M_HPI_CONTROL 0x00 #define VPM150M_HPI_ADDRESS 0x02 #define VPM150M_HPI_DATA 0x03 #define VPM_SUPPORT #define VPM150M_SUPPORT #ifdef VPM150M_SUPPORT #include "voicebus/GpakCust.h" #endif #include "voicebus/vpmoct.h" struct calregs { unsigned char vals[NUM_CAL_REGS]; }; enum battery_state { BATTERY_UNKNOWN = 0, BATTERY_PRESENT, BATTERY_LOST, }; struct wctdm_cmd { struct list_head node; struct completion *complete; u32 cmd; u8 ident; }; /** * struct wctdm_span - * @span: dahdi_span to register. * @timing_priority: What the priority of this span is relative to the other * spans. * @spanno: Which span on the card this is. * * NOTE: spanno would normally be taken care of by dahdi_span.offset, but * appears to have meaning in xhfc.c, and that needs to be audited before * changing. !!!TODO!!! * */ struct wctdm_span { struct dahdi_span span; int timing_priority; int spanno; struct wctdm *wc; struct b400m_span *bspan; }; struct wctdm_chan { struct dahdi_chan chan; struct dahdi_echocan_state ec; int timeslot; unsigned int hwpreec_enabled:1; }; struct fxo { int wasringing; int lastrdtx; int lastrdtx_count; int ringdebounce; int offhook; int battdebounce; int battalarm; enum battery_state battery; int lastpol; int polarity; int polaritydebounce; int neonmwi_state; int neonmwi_last_voltage; unsigned int neonmwi_debounce; unsigned int neonmwi_offcounter; }; struct fxs { int oldrxhook; int debouncehook; int lastrxhook; int debounce; int ohttimer; int idletxhookstate; /* IDLE changing hook state */ /* lasttxhook reflects the last value written to the proslic's reg * 64 (LINEFEED_CONTROL) in bits 0-2. Bit 4 indicates if the last * write is pending i.e. it is in process of being written to the * register * NOTE: in order for this value to actually be written to the * proslic, the appropriate matching value must be written into the * sethook variable so that it gets queued and handled by the * voicebus ISR. */ int lasttxhook; int oppending_ms; int palarms; struct dahdi_vmwi_info vmwisetting; int vmwi_active_messages; int vmwi_linereverse; int reversepolarity; /* polarity reversal */ struct calregs calregs; }; struct qrv { #define RADMODE_INVERTCOR 1 #define RADMODE_IGNORECOR 2 #define RADMODE_EXTTONE 4 #define RADMODE_EXTINVERT 8 #define RADMODE_IGNORECT 16 #define RADMODE_PREEMP 32 #define RADMODE_DEEMP 64 char hook; unsigned short debouncetime; unsigned short debtime; int radmode; signed short rxgain; signed short txgain; }; enum module_type { NONE = 0, FXS, FXO, FXSINIT, QRV, BRI, }; struct wctdm_module { union { struct fxo fxo; struct fxs fxs; struct qrv qrv; struct b400m *bri; } mod; /* Protected by wctdm.reglock */ struct list_head pending_cmds; struct list_head active_cmds; u8 offsets[3]; u8 subaddr; u8 isrshadow[ISR_COMMANDS]; u8 card; enum module_type type; int sethook; /* pending hook state command */ int dacssrc; }; struct wctdm { const struct wctdm_desc *desc; const char *board_name; spinlock_t frame_list_lock; struct list_head frame_list; unsigned int intcount; unsigned char txident; unsigned char rxident; u8 ctlreg; u8 tdm410leds; int mods_per_board; /* maximum number of modules for this board */ int digi_mods; /* number of digital modules present */ int avchannels; /* active "voice" (voice, B and D) channels */ spinlock_t reglock; /* held when accessing anything affecting the module array */ wait_queue_head_t regq; struct list_head free_isr_commands; struct wctdm_module mods[NUM_MODULES]; struct vpmadt032 *vpmadt032; struct vpmoct *vpmoct; struct voicebus vb; struct wctdm_span *aspan; /* pointer to the spans[] holding the analog span */ struct wctdm_span *spans[MAX_SPANS]; struct wctdm_chan *chans[NUM_MODULES]; #ifdef CONFIG_VOICEBUS_ECREFERENCE struct dahdi_fifo *ec_reference[NUM_MODULES]; #endif /* Only care about digital spans here */ /* int span_timing_prio[MAX_SPANS - 1]; */ struct semaphore syncsem; int oldsync; int not_ready; /* 0 when the entire card is ready to go */ unsigned long checkflag; /* Internal state flags and task bits */ int companding; }; static inline bool is_initialized(struct wctdm *wc) { WARN_ON(wc->not_ready < 0); return (wc->not_ready == 0); } /* Atomic flag bits for checkflag field */ #define WCTDM_CHECK_TIMING 0 int wctdm_getreg(struct wctdm *wc, struct wctdm_module *const mod, int addr); int wctdm_setreg(struct wctdm *wc, struct wctdm_module *const mod, int addr, int val); int wctdm_wait_for_ready(struct wctdm *wc); extern struct semaphore ifacelock; extern struct wctdm *ifaces[WC_MAX_IFACES]; #endif dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_mg2.c0000644000175000017500000006477711500234716022224 0ustar tzafrirtzafrir/* * ECHO_CAN_MG2 * * by Michael Gernoth * * Based upon kb1ec.h and mec2.h * * Copyright (C) 2002, Digium, Inc. * * Additional background on the techniques used in this code can be found in: * * Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine; * Winship, Peter; "Digital Voice Echo Canceller with a TMS32020," * in Digital Signal Processing Applications with the TMS320 Family, * pp. 415-437, Texas Instruments, Inc., 1986. * * A pdf of which is available by searching on the document title at http://www.ti.com/ * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include static int debug; static int aggressive; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk("%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) #define ABS(a) abs(a!=-32768?a:-32767) #define RESTORE_COEFFS {\ int x;\ memcpy(pvt->a_i, pvt->c_i, pvt->N_d*sizeof(int));\ for (x = 0; x < pvt->N_d; x++) {\ pvt->a_s[x] = pvt->a_i[x] >> 16;\ }\ pvt->backup = BACKUP;\ } /* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */ /* #define MEC2_STATS 4000 */ /* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */ /* #define MEC2_STATS_DETAILED */ /* Uncomment to generate per-call DC bias offset messages */ /* #define MEC2_DCBIAS_MESSAGE */ /* Get optimized routines for math */ #include "arith.h" /* Important constants for tuning mg2 echo can */ /* Convergence (aka. adaptation) speed -- higher means slower */ #define DEFAULT_BETA1_I 2048 /* Constants for various power computations */ #define DEFAULT_SIGMA_LY_I 7 #define DEFAULT_SIGMA_LU_I 7 #define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */ #define DEFAULT_ALPHA_YT_I 5 #define DEFAULT_CUTOFF_I 128 /* Define the near-end speech hangover counter: if near-end speech * is declared, hcntr is set equal to hangt (see pg. 432) */ #define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */ /* define the residual error suppression threshold */ #define DEFAULT_SUPPR_I 16 /* 16 = -24db */ /* This is the minimum reference signal power estimate level * that will result in filter adaptation. * If this is too low then background noise will cause the filter * coefficients to constantly be updated. */ #define MIN_UPDATE_THRESH_I 2048 /* The number of samples used to update coefficients using the * the block update method (M). It should be related back to the * length of the echo can. * ie. it only updates coefficients when (sample number MOD default_m) = 0 * * Getting this wrong may cause an oops. Consider yourself warned! */ #define DEFAULT_M 16 /* every 16th sample */ /* If AGGRESSIVE supression is enabled, then we start cancelling residual * echos again even while there is potentially the very end of a near-side * signal present. * This defines how many samples of DEFAULT_HANGT can remain before we * kick back in */ #define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */ /* Treat sample as error if it has a different sign as the * input signal and is this number larger in ABS() as * the input-signal */ #define MAX_SIGN_ERROR 3000 /* Number of coefficients really used for calculating the * simulated echo. The value specifies how many of the * biggest coefficients are used for calculating rs. * This helps on long echo-tails by artificially limiting * the number of coefficients for the calculation and * preventing overflows. * Comment this to deactivate the code */ #define USED_COEFFS 64 /* Backup coefficients every this number of samples */ #define BACKUP 256 /***************************************************************/ /* The following knobs are not implemented in the current code */ /* we need a dynamic level of suppression varying with the ratio of the power of the echo to the power of the reference signal this is done so that we have a smoother background. we have a higher suppression when the power ratio is closer to suppr_ceil and reduces logarithmically as we approach suppr_floor. */ #define SUPPR_FLOOR -64 #define SUPPR_CEIL -24 /* in a second departure, we calculate the residual error suppression * as a percentage of the reference signal energy level. The threshold * is defined in terms of dB below the reference signal. */ #define RES_SUPR_FACTOR -20 #define DC_NORMALIZE #ifndef NULL #define NULL 0 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!FALSE) #endif /* Generic circular buffer definition */ typedef struct { /* Pointer to the relative 'start' of the buffer */ int idx_d; /* The absolute size of the buffer */ int size_d; /* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */ short *buf_d; } echo_can_cb_s; static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable); static const char *name = "MG2"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_features my_features = { .NLP_toggle = 1, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, .echocan_NLP_toggle = echocan_NLP_toggle, }; struct ec_pvt { struct dahdi_echocan_state dahdi; /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */ int id; /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */ int i_d; /* Pre-computed constants */ /* ---------------------- */ /* Number of filter coefficents */ int N_d; /* Rate of adaptation of filter */ int beta2_i; /* Accumulators for power computations */ /* ----------------------------------- */ /* reference signal power estimate - aka. Average absolute value of y(k) */ int Ly_i; /* ... */ int Lu_i; /* Accumulators for signal detectors */ /* --------------------------------- */ /* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */ int s_tilde_i; /* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */ int y_tilde_i; /* Near end speech detection counter - stores Hangover counter time remaining, in samples */ int HCNTR_d; /* Circular buffers and coefficients */ /* --------------------------------- */ /* ... */ int *a_i; /* ... */ short *a_s; /* Backups */ int *b_i; int *c_i; /* Reference samples of far-end receive signal */ echo_can_cb_s y_s; /* Reference samples of near-end signal */ echo_can_cb_s s_s; /* Reference samples of near-end signal minus echo estimate */ echo_can_cb_s u_s; /* Reference samples of far-end receive signal used to calculate short-time average */ echo_can_cb_s y_tilde_s; /* Peak far-end receive signal */ /* --------------------------- */ /* Highest y_tilde value in the sample buffer */ short max_y_tilde; /* Index of the sample containing the max_y_tilde value */ int max_y_tilde_pos; #ifdef MEC2_STATS /* Storage for performance statistics */ int cntr_nearend_speech_frames; int cntr_residualcorrected_frames; int cntr_residualcorrected_framesskipped; int cntr_coeff_updates; int cntr_coeff_missedupdates; int avg_Lu_i_toolow; int avg_Lu_i_ok; #endif unsigned int aggressive:1; short lastsig; int lastcount; int backup; #ifdef DC_NORMALIZE int dc_estimate; #endif int use_nlp; }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where) { cb->buf_d = (short *)where; cb->idx_d = 0; cb->size_d = len; } static inline void add_cc_s(echo_can_cb_s *cb, short newval) { /* Can't use modulus because N+M isn't a power of two (generally) */ cb->idx_d--; if (cb->idx_d < (int)0) /* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */ cb->idx_d += cb->size_d; /* Load two copies into memory */ cb->buf_d[cb->idx_d] = newval; cb->buf_d[cb->idx_d + cb->size_d] = newval; } static inline short get_cc_s(echo_can_cb_s *cb, int pos) { /* Load two copies into memory */ return cb->buf_d[cb->idx_d + pos]; } static inline void init_cc(struct ec_pvt *pvt, int N, int maxy, int maxu) { char *ptr = (char *) pvt; unsigned long tmp; /* Double-word align past end of state */ ptr += sizeof(*pvt); tmp = (unsigned long)ptr; tmp += 3; tmp &= ~3L; ptr = (void *)tmp; /* Reset parameters */ pvt->N_d = N; pvt->beta2_i = DEFAULT_BETA1_I; /* Allocate coefficient memory */ pvt->a_i = (int *) ptr; ptr += (sizeof(int) * pvt->N_d); pvt->a_s = (short *) ptr; ptr += (sizeof(short) * pvt->N_d); /* Allocate backup memory */ pvt->b_i = (int *) ptr; ptr += (sizeof(int) * pvt->N_d); pvt->c_i = (int *) ptr; ptr += (sizeof(int) * pvt->N_d); /* Reset Y circular buffer (short version) */ init_cb_s(&pvt->y_s, maxy, ptr); ptr += (sizeof(short) * (maxy) * 2); /* Reset Sigma circular buffer (short version for FIR filter) */ init_cb_s(&pvt->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr); ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2); init_cb_s(&pvt->u_s, maxu, ptr); ptr += (sizeof(short) * maxu * 2); /* Allocate a buffer for the reference signal power computation */ init_cb_s(&pvt->y_tilde_s, pvt->N_d, ptr); /* Reset the absolute time index */ pvt->i_d = (int)0; /* Reset the power computations (for y and u) */ pvt->Ly_i = DEFAULT_CUTOFF_I; pvt->Lu_i = DEFAULT_CUTOFF_I; #ifdef MEC2_STATS /* set the identity */ pvt->id = (int)&ptr; /* Reset performance stats */ pvt->cntr_nearend_speech_frames = (int)0; pvt->cntr_residualcorrected_frames = (int)0; pvt->cntr_residualcorrected_framesskipped = (int)0; pvt->cntr_coeff_updates = (int)0; pvt->cntr_coeff_missedupdates = (int)0; pvt->avg_Lu_i_toolow = (int)0; pvt->avg_Lu_i_ok = (int)0; #endif /* Reset the near-end speech detector */ pvt->s_tilde_i = (int)0; pvt->y_tilde_i = (int)0; pvt->HCNTR_d = (int)0; } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); #if defined(DC_NORMALIZE) && defined(MEC2_DCBIAS_MESSAGE) printk(KERN_INFO "EC: DC bias calculated: %d V\n", pvt->dc_estimate >> 15); #endif kfree(pvt); } #ifdef DC_NORMALIZE static inline short dc_removal(int *dc_estimate, short samp) { *dc_estimate += ((((int)samp << 15) - *dc_estimate) >> 9); return samp - (*dc_estimate >> 15); } #endif static inline short sample_update(struct ec_pvt *pvt, short iref, short isig) { /* Declare local variables that are used more than once */ /* ... */ int k; /* ... */ int rs; /* ... */ short u; /* ... */ int Py_i; /* ... */ int two_beta_i; #ifdef DC_NORMALIZE isig = dc_removal(&pvt->dc_estimate, isig); #endif /* flow A on pg. 428 */ /* eq. (16): high-pass filter the input to generate the next value; * push the current value into the circular buffer * * sdc_im1_d = sdc_d; * sdc_d = sig; * s_i_d = sdc_d; * s_d = s_i_d; * s_i_d = (float)(1.0 - gamma_d) * s_i_d * + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */ /* Update the Far-end receive signal circular buffers and accumulators */ /* ------------------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->y_tilde_i -= abs(get_cc_s(&pvt->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1)) >> DEFAULT_ALPHA_YT_I; /* Add the new sample to the power estimate accumulator */ pvt->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I; /* Push a copy of the new sample into its circular buffer */ add_cc_s(&pvt->y_s, iref); /* eq. (2): compute r in fixed-point */ rs = CONVOLVE2(pvt->a_s, pvt->y_s.buf_d + pvt->y_s.idx_d, pvt->N_d); rs >>= 15; if (pvt->lastsig == isig) { pvt->lastcount++; } else { pvt->lastcount = 0; pvt->lastsig = isig; } if (isig == 0) { u = 0; } else if (pvt->lastcount > 255) { /* We have seen the same input-signal more than 255 times, * we should pass it through uncancelled, as we are likely on hold */ u = isig; } else { int sign_error; if (rs < -32768) { rs = -32768; pvt->HCNTR_d = DEFAULT_HANGT; RESTORE_COEFFS; } else if (rs > 32767) { rs = 32767; pvt->HCNTR_d = DEFAULT_HANGT; RESTORE_COEFFS; } sign_error = ABS(rs) - ABS(isig); if (ABS(sign_error) > MAX_SIGN_ERROR) { rs = 0; RESTORE_COEFFS; } /* eq. (3): compute the output value (see figure 3) and the error * note: the error is the same as the output signal when near-end * speech is not present */ u = isig - rs; if (u / isig < 0) u = isig - (rs >> 1); } /* Push a copy of the output value sample into its circular buffer */ add_cc_s(&pvt->u_s, u); if (!pvt->backup) { /* Backup coefficients periodically */ pvt->backup = BACKUP; memcpy(pvt->c_i, pvt->b_i, pvt->N_d*sizeof(int)); memcpy(pvt->b_i, pvt->a_i, pvt->N_d*sizeof(int)); } else pvt->backup--; /* Update the Near-end hybrid signal circular buffers and accumulators */ /* ------------------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->s_tilde_i -= abs(get_cc_s(&pvt->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1)); /* Add the new sample to the power estimate accumulator */ pvt->s_tilde_i += abs(isig); /* Push a copy of the new sample into it's circular buffer */ add_cc_s(&pvt->s_s, isig); /* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */ add_cc_s(&pvt->y_tilde_s, pvt->y_tilde_i); /* flow B on pg. 428 */ /* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */ if (!pvt->HCNTR_d) { Py_i = (pvt->Ly_i >> DEFAULT_SIGMA_LY_I) * (pvt->Ly_i >> DEFAULT_SIGMA_LY_I); Py_i >>= 15; } else { Py_i = (1 << 15); } #if 0 /* Vary rate of adaptation depending on position in the file * Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech * has begun of the file to allow the echo cancellor to estimate the * channel accurately * Still needs conversion! */ if (pvt->start_speech_d != 0) { if (pvt->i_d > (DEFAULT_T0 + pvt->start_speech_d)*(SAMPLE_FREQ)) { pvt->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((pvt->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - pvt->start_speech_d))); } } else { pvt->beta2_d = DEFAULT_BETA1; } #endif /* Fixed point, inverted */ pvt->beta2_i = DEFAULT_BETA1_I; /* Fixed point version, inverted */ two_beta_i = (pvt->beta2_i * Py_i) >> 15; if (!two_beta_i) two_beta_i++; /* Update the Suppressed signal power estimate accumulator */ /* ------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->Lu_i -= abs(get_cc_s(&pvt->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1)); /* Add the new sample to the power estimate accumulator */ pvt->Lu_i += abs(u); /* Update the Far-end reference signal power estimate accumulator */ /* -------------------------------------------------------------- */ /* eq. (10): update power estimate of the reference */ /* Delete the oldest sample from the power estimate accumulator */ pvt->Ly_i -= abs(get_cc_s(&pvt->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ; /* Add the new sample to the power estimate accumulator */ pvt->Ly_i += abs(iref); if (pvt->Ly_i < DEFAULT_CUTOFF_I) pvt->Ly_i = DEFAULT_CUTOFF_I; /* Update the Peak far-end receive signal detected */ /* ----------------------------------------------- */ if (pvt->y_tilde_i > pvt->max_y_tilde) { /* New highest y_tilde with full life */ pvt->max_y_tilde = pvt->y_tilde_i; pvt->max_y_tilde_pos = pvt->N_d - 1; } else if (--pvt->max_y_tilde_pos < 0) { /* Time to find new max y tilde... */ pvt->max_y_tilde = MAX16(pvt->y_tilde_s.buf_d + pvt->y_tilde_s.idx_d, pvt->N_d, &pvt->max_y_tilde_pos); } /* Determine if near end speech was detected in this sample */ /* -------------------------------------------------------- */ if (((pvt->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > pvt->max_y_tilde) && (pvt->max_y_tilde > 0)) { /* Then start the Hangover counter */ pvt->HCNTR_d = DEFAULT_HANGT; RESTORE_COEFFS; #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", pvt->s_tilde_i, (pvt->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), pvt->max_y_tilde); #endif #ifdef MEC2_STATS ++pvt->cntr_nearend_speech_frames; #endif } else if (pvt->HCNTR_d > (int)0) { /* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */ #ifdef MEC2_STATS ++pvt->cntr_nearend_speech_frames; #endif pvt->HCNTR_d--; } /* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0) * and we have enough signal to bother trying to update. * -------------------------------------------------------------------------- */ if (!pvt->HCNTR_d && /* no near-end speech present */ !(pvt->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */ if (pvt->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */ /* so loop over all the filter coefficients */ #ifdef USED_COEFFS int max_coeffs[USED_COEFFS]; int *pos; if (pvt->N_d > USED_COEFFS) memset(max_coeffs, 0, USED_COEFFS*sizeof(int)); #endif #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "updating coefficients with: pvt->Lu_i %9d\n", pvt->Lu_i); #endif #ifdef MEC2_STATS pvt->avg_Lu_i_ok = pvt->avg_Lu_i_ok + pvt->Lu_i; ++pvt->cntr_coeff_updates; #endif for (k = 0; k < pvt->N_d; k++) { /* eq. (7): compute an expectation over M_d samples */ int grad2; grad2 = CONVOLVE2(pvt->u_s.buf_d + pvt->u_s.idx_d, pvt->y_s.buf_d + pvt->y_s.idx_d + k, DEFAULT_M); /* eq. (7): update the coefficient */ pvt->a_i[k] += grad2 / two_beta_i; pvt->a_s[k] = pvt->a_i[k] >> 16; #ifdef USED_COEFFS if (pvt->N_d > USED_COEFFS) { if (abs(pvt->a_i[k]) > max_coeffs[USED_COEFFS-1]) { /* More or less insertion-sort... */ pos = max_coeffs; while (*pos > abs(pvt->a_i[k])) pos++; if (*pos > max_coeffs[USED_COEFFS-1]) memmove(pos+1, pos, (USED_COEFFS-(pos-max_coeffs)-1)*sizeof(int)); *pos = abs(pvt->a_i[k]); } } #endif } #ifdef USED_COEFFS /* Filter out irrelevant coefficients */ if (pvt->N_d > USED_COEFFS) for (k = 0; k < pvt->N_d; k++) if (abs(pvt->a_i[k]) < max_coeffs[USED_COEFFS-1]) pvt->a_i[k] = pvt->a_s[k] = 0; #endif } else { #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "insufficient signal to update coefficients pvt->Lu_i %5d < %5d\n", pvt->Lu_i, MIN_UPDATE_THRESH_I); #endif #ifdef MEC2_STATS pvt->avg_Lu_i_toolow = pvt->avg_Lu_i_toolow + pvt->Lu_i; ++pvt->cntr_coeff_missedupdates; #endif } } /* paragraph below eq. (15): if no near-end speech in the sample and * the reference signal power estimate > cutoff threshold * then perform residual error suppression */ #ifdef MEC2_STATS_DETAILED if (pvt->HCNTR_d == 0) printk(KERN_INFO "possibly correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d and expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifndef NO_ECHO_SUPPRESSOR if (pvt->use_nlp) { if (pvt->aggressive) { if ((pvt->HCNTR_d < AGGRESSIVE_HCNTR) && (pvt->Ly_i > (pvt->Lu_i << 1))) { for (k = 0; k < 2; k++) { u = u * (pvt->Lu_i >> DEFAULT_SIGMA_LU_I) / ((pvt->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); } #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "aggresively correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifdef MEC2_STATS ++pvt->cntr_residualcorrected_frames; #endif } } else { if (pvt->HCNTR_d == 0) { if ((pvt->Ly_i/(pvt->Lu_i + 1)) > DEFAULT_SUPPR_I) { for (k = 0; k < 1; k++) { u = u * (pvt->Lu_i >> DEFAULT_SIGMA_LU_I) / ((pvt->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); } #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifdef MEC2_STATS ++pvt->cntr_residualcorrected_frames; #endif } #ifdef MEC2_STATS else { ++pvt->cntr_residualcorrected_framesskipped; } #endif } } } #endif #if 0 /* This will generate a non-linear supression factor, once converted */ if ((pvt->HCNTR_d == 0) && ((pvt->Lu_d/pvt->Ly_d) < DEFAULT_SUPPR) && (pvt->Lu_d/pvt->Ly_d > EC_MIN_DB_VALUE)) { suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(pvt->Lu_d/pvt->Ly_d) - SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL); u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr; } #endif #ifdef MEC2_STATS /* Periodically dump performance stats */ if ((pvt->i_d % MEC2_STATS) == 0) { /* make sure to avoid div0's! */ if (pvt->cntr_coeff_missedupdates > 0) pvt->avg_Lu_i_toolow = (int)(pvt->avg_Lu_i_toolow / pvt->cntr_coeff_missedupdates); else pvt->avg_Lu_i_toolow = -1; if (pvt->cntr_coeff_updates > 0) pvt->avg_Lu_i_ok = (pvt->avg_Lu_i_ok / pvt->cntr_coeff_updates); else pvt->avg_Lu_i_ok = -1; printk(KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", pvt->id, pvt->cntr_nearend_speech_frames, pvt->cntr_residualcorrected_frames, pvt->cntr_residualcorrected_framesskipped, pvt->cntr_coeff_updates, pvt->cntr_coeff_missedupdates, pvt->avg_Lu_i_ok, pvt->avg_Lu_i_toolow); pvt->cntr_nearend_speech_frames = 0; pvt->cntr_residualcorrected_frames = 0; pvt->cntr_residualcorrected_framesskipped = 0; pvt->cntr_coeff_updates = 0; pvt->cntr_coeff_missedupdates = 0; pvt->avg_Lu_i_ok = 0; pvt->avg_Lu_i_toolow = 0; } #endif /* Increment the sample index and return the corrected sample */ pvt->i_d++; return u; } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 x; short result; for (x = 0; x < size; x++) { result = sample_update(pvt, *iref, *isig); *isig++ = result; ++iref; } } static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { int maxy; int maxu; size_t size; unsigned int x; char *c; struct ec_pvt *pvt; maxy = ecp->tap_length + DEFAULT_M; maxu = DEFAULT_M; if (maxy < (1 << DEFAULT_ALPHA_YT_I)) maxy = (1 << DEFAULT_ALPHA_YT_I); if (maxy < (1 << DEFAULT_SIGMA_LY_I)) maxy = (1 << DEFAULT_SIGMA_LY_I); if (maxu < (1 << DEFAULT_SIGMA_LU_I)) maxu = (1 << DEFAULT_SIGMA_LU_I); size = sizeof(**ec) + 4 + /* align */ sizeof(int) * ecp->tap_length + /* a_i */ sizeof(short) * ecp->tap_length + /* a_s */ sizeof(int) * ecp->tap_length + /* b_i */ sizeof(int) * ecp->tap_length + /* c_i */ 2 * sizeof(short) * (maxy) + /* y_s */ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ 2 * sizeof(short) * (maxu) + /* u_s */ 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */ pvt = kzalloc(size, GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; pvt->aggressive = aggressive; pvt->dahdi.features = my_features; for (x = 0; x < ecp->param_count; x++) { for (c = p[x].name; *c; c++) *c = tolower(*c); if (!strcmp(p[x].name, "aggressive")) { pvt->aggressive = p[x].value ? 1 : 0; } else { printk(KERN_WARNING "Unknown parameter supplied to MG2 echo canceler: '%s'\n", p[x].name); kfree(pvt); return -EINVAL; } } init_cc(pvt, ecp->tap_length, maxy, maxu); /* Non-linear processor - a fancy way to say "zap small signals, to avoid accumulating noise". */ pvt->use_nlp = TRUE; *ec = &pvt->dahdi; return 0; } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { struct ec_pvt *pvt = dahdi_to_pvt(ec); /* Set the hangover counter to the length of the can to * avoid adjustments occuring immediately after initial forced training */ pvt->HCNTR_d = pvt->N_d << 1; if (pos >= pvt->N_d) { memcpy(pvt->b_i, pvt->a_i, pvt->N_d*sizeof(int)); memcpy(pvt->c_i, pvt->a_i, pvt->N_d*sizeof(int)); return 1; } pvt->a_i[pos] = val << 17; pvt->a_s[pos] = val << 1; if (++pos >= pvt->N_d) { memcpy(pvt->b_i, pvt->a_i, pvt->N_d*sizeof(int)); memcpy(pvt->c_i, pvt->a_i, pvt->N_d*sizeof(int)); return 1; } return 0; } static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable) { struct ec_pvt *pvt = dahdi_to_pvt(ec); pvt->use_nlp = enable ? 1 : 0; } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } module_param(debug, int, S_IRUGO | S_IWUSR); module_param(aggressive, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI 'MG2' Echo Canceler"); MODULE_AUTHOR("Michael Gernoth"); MODULE_LICENSE("GPL v2"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/fir.h0000644000175000017500000000664211046164220017473 0ustar tzafrirtzafrir/* * SpanDSP - a series of DSP components for telephony * * fir.h - General telephony FIR routines * * Written by Steve Underwood * * Copyright (C) 2002 Steve Underwood * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #if !defined(_FIR_H_) #define _FIR_H_ typedef struct { int taps; int curr_pos; int16_t *coeffs; int16_t *history; } fir16_state_t; typedef struct { int taps; int curr_pos; int32_t *coeffs; int16_t *history; } fir32_state_t; static inline void fir16_create (fir16_state_t *fir, int16_t *coeffs, int taps) { fir->taps = taps; fir->curr_pos = taps - 1; fir->coeffs = coeffs; fir->history = kmalloc(taps*sizeof (int16_t), GFP_KERNEL); if (fir->history) memset (fir->history, '\0', taps*sizeof (int16_t)); } /*- End of function --------------------------------------------------------*/ static inline void fir16_free (fir16_state_t *fir) { kfree(fir->history); } /*- End of function --------------------------------------------------------*/ static inline int16_t fir16 (fir16_state_t *fir, int16_t sample) { int i; int offset1; int offset2; int32_t y; fir->history[fir->curr_pos] = sample; offset2 = fir->curr_pos + 1; offset1 = fir->taps - offset2; y = 0; for (i = fir->taps - 1; i >= offset1; i--) y += fir->coeffs[i]*fir->history[i - offset1]; for ( ; i >= 0; i--) y += fir->coeffs[i]*fir->history[i + offset2]; if (fir->curr_pos <= 0) fir->curr_pos = fir->taps; fir->curr_pos--; return y >> 15; } /*- End of function --------------------------------------------------------*/ static inline void fir32_create (fir32_state_t *fir, int32_t *coeffs, int taps) { fir->taps = taps; fir->curr_pos = taps - 1; fir->coeffs = coeffs; fir->history = kmalloc(taps*sizeof (int16_t), GFP_KERNEL); if (fir->history) memset (fir->history, '\0', taps*sizeof (int16_t)); } /*- End of function --------------------------------------------------------*/ static inline void fir32_free (fir32_state_t *fir) { kfree(fir->history); } /*- End of function --------------------------------------------------------*/ static inline int16_t fir32 (fir32_state_t *fir, int16_t sample) { int i; int offset1; int offset2; int32_t y; fir->history[fir->curr_pos] = sample; offset2 = fir->curr_pos + 1; offset1 = fir->taps - offset2; y = 0; for (i = fir->taps - 1; i >= offset1; i--) y += fir->coeffs[i]*fir->history[i - offset1]; for ( ; i >= 0; i--) y += fir->coeffs[i]*fir->history[i + offset2]; if (fir->curr_pos <= 0) fir->curr_pos = fir->taps; fir->curr_pos--; return y >> 15; } /*- End of function --------------------------------------------------------*/ #endif /*- End of file ------------------------------------------------------------*/ dahdi-linux-2.5.0.1/drivers/dahdi/wct1xxp.c0000644000175000017500000010712511571766036020342 0ustar tzafrirtzafrir/* * Digium, Inc. Wildcard T100P T1/PRI card Driver * * Written by Mark Spencer * Matthew Fredrickson * William Meadows * * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #define WC_MAX_CARDS 32 /* #define TEST_REGS */ /* Define to get more attention-grabbing but slightly more I/O using alarm status */ #define FANCY_ALARM #define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ #define WC_CNTL 0x00 #define WC_OPER 0x01 #define WC_AUXC 0x02 #define WC_AUXD 0x03 #define WC_MASK0 0x04 #define WC_MASK1 0x05 #define WC_INTSTAT 0x06 #define WC_DMAWS 0x08 #define WC_DMAWI 0x0c #define WC_DMAWE 0x10 #define WC_DMARS 0x18 #define WC_DMARI 0x1c #define WC_DMARE 0x20 #define WC_CURPOS 0x24 #define WC_SERC 0x2d #define WC_FSCDELAY 0x2f #define WC_USERREG 0xc0 #define WC_CLOCK 0x0 #define WC_LEDTEST 0x1 #define WC_VERSION 0x2 /* Offset between transmit and receive */ #define WC_OFFSET 4 #define BIT_CS (1 << 7) #define BIT_ADDR (0xf << 3) #define BIT_LED0 (1 << 0) #define BIT_LED1 (1 << 1) #define BIT_TEST (1 << 2) static char *chips[] = { "DS2152", "DS21352", "DS21552", "Unknown Chip (3)", "DS2154", "DS21354", "DS21554", "Unknown Chip (7)", }; static int chanmap_t1[] = { 2,1,0, 6,5,4, 10,9,8, 14,13,12, 18,17,16, 22,21,20, 26,25,24, 30,29,28 }; static int chanmap_e1[] = { 2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12, 19,18,17,16, 23,22,21,20, 27,26,25,24, 31,30,29,28 }; #ifdef FANCY_ALARM static int altab[] = { 0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, }; #endif struct t1xxp { struct pci_dev *dev; spinlock_t lock; int ise1; int num; /* Our offset for finding channel 1 */ int offset; char *variety; unsigned int intcount; int usecount; int clocktimeout; int sync; int dead; int blinktimer; int alarmtimer; int loopupcnt; int loopdowncnt; int miss; int misslast; int *chanmap; #ifdef FANCY_ALARM int alarmpos; #endif unsigned char ledtestreg; unsigned char outbyte; unsigned long ioaddr; unsigned short canary; /* T1 signalling */ unsigned char txsiga[3]; unsigned char txsigb[3]; dma_addr_t readdma; dma_addr_t writedma; volatile unsigned char *writechunk; /* Double-word aligned write memory */ volatile unsigned char *readchunk; /* Double-word aligned read memory */ unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; unsigned char tempo[32]; struct dahdi_span span; /* Span */ struct dahdi_chan *chans[31]; /* Channels */ }; #define CANARY 0xca1e static int debug = 0; /* doesnt do anything */ static struct t1xxp *cards[WC_MAX_CARDS]; static inline void start_alarm(struct t1xxp *wc) { #ifdef FANCY_ALARM wc->alarmpos = 0; #endif wc->blinktimer = 0; } static inline void stop_alarm(struct t1xxp *wc) { #ifdef FANCY_ALARM wc->alarmpos = 0; #endif wc->blinktimer = 0; } static inline void __select_framer(struct t1xxp *wc, int reg) { /* Top four bits of address from AUX 6-3 */ wc->outbyte &= ~BIT_CS; wc->outbyte &= ~BIT_ADDR; wc->outbyte |= (reg & 0xf0) >> 1; outb(wc->outbyte, wc->ioaddr + WC_AUXD); } static inline void __select_control(struct t1xxp *wc) { if (!(wc->outbyte & BIT_CS)) { wc->outbyte |= BIT_CS; outb(wc->outbyte, wc->ioaddr + WC_AUXD); } } static int t1xxp_open(struct dahdi_chan *chan) { struct t1xxp *wc = chan->pvt; if (wc->dead) return -ENODEV; wc->usecount++; return 0; } static int __t1_get_reg(struct t1xxp *wc, int reg) { unsigned char res; __select_framer(wc, reg); /* Get value */ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; } static int __t1_set_reg(struct t1xxp *wc, int reg, unsigned char val) { __select_framer(wc, reg); /* Send address */ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return 0; } static int __control_set_reg(struct t1xxp *wc, int reg, unsigned char val) { __select_control(wc); outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return 0; } static int control_set_reg(struct t1xxp *wc, int reg, unsigned char val) { unsigned long flags; int res; spin_lock_irqsave(&wc->lock, flags); res = __control_set_reg(wc, reg, val); spin_unlock_irqrestore(&wc->lock, flags); return res; } static int __control_get_reg(struct t1xxp *wc, int reg) { unsigned char res; /* The following makes UTTERLY no sense, but what was happening was that reads in some cases were not actually happening on the physical bus. Why, we dunno. But in debugging, we found that writing before reading (in this case to an unused position) seems to get rid of the problem */ __control_set_reg(wc,3,0x69); /* do magic here */ /* now get the read byte from the Xilinx part */ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; } static int control_get_reg(struct t1xxp *wc, int reg) { unsigned long flags; int res; spin_lock_irqsave(&wc->lock, flags); res = __control_get_reg(wc, reg); spin_unlock_irqrestore(&wc->lock, flags); return res; } static void t1xxp_release(struct t1xxp *wc) { unsigned int x; dahdi_unregister(&wc->span); for (x = 0; x < (wc->ise1 ? 31 : 24); x++) { kfree(wc->chans[x]); } kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } static int t1xxp_close(struct dahdi_chan *chan) { struct t1xxp *wc = chan->pvt; wc->usecount--; /* If we're dead, release us now */ if (!wc->usecount && wc->dead) t1xxp_release(wc); return 0; } static void t1xxp_enable_interrupts(struct t1xxp *wc) { /* Clear interrupts */ outb(0xff, wc->ioaddr + WC_INTSTAT); /* Enable interrupts (we care about all of them) */ outb(0x3c /* 0x3f */, wc->ioaddr + WC_MASK0); /* No external interrupts */ outb(0x00, wc->ioaddr + WC_MASK1); } static void t1xxp_start_dma(struct t1xxp *wc) { /* Reset Master and TDM */ outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); if (debug) printk(KERN_DEBUG "Started DMA\n"); } static void __t1xxp_stop_dma(struct t1xxp *wc) { outb(0x00, wc->ioaddr + WC_OPER); } static void __t1xxp_disable_interrupts(struct t1xxp *wc) { outb(0x00, wc->ioaddr + WC_MASK0); outb(0x00, wc->ioaddr + WC_MASK1); } static void __t1xxp_set_clear(struct t1xxp *wc) { /* Setup registers */ int x,y; unsigned char b; /* No such thing under E1 */ if (wc->ise1) { printk(KERN_NOTICE "Can't set clear mode on an E1!\n"); return; } for (x=0;x<3;x++) { b = 0; for (y=0;y<8;y++) if (wc->chans[x * 8 + y]->sig & DAHDI_SIG_CLEAR) b |= (1 << y); __t1_set_reg(wc, 0x39 + x, b); } } static void t1xxp_t1_framer_start(struct t1xxp *wc) { int i; char *coding, *framing; unsigned long endjiffies; int alreadyrunning = wc->span.flags & DAHDI_FLAG_RUNNING; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); /* Build up config */ i = 0x20; if (wc->span.lineconfig & DAHDI_CONFIG_ESF) { coding = "ESF"; i = 0x88; } else { coding = "SF"; } if (wc->span.lineconfig & DAHDI_CONFIG_B8ZS) { framing = "B8ZS"; i |= 0x44; } else { framing = "AMI"; } __t1_set_reg(wc, 0x38, i); if (!(wc->span.lineconfig & DAHDI_CONFIG_ESF)) { /* 1c in FDL bit */ __t1_set_reg(wc, 0x7e, 0x1c); } else { __t1_set_reg(wc, 0x7e, 0x00); } /* Set outgoing LBO */ __t1_set_reg(wc, 0x7c, wc->span.txlevel << 5); printk(KERN_DEBUG "Using %s/%s coding/framing\n", coding, framing); if (!alreadyrunning) { /* Setup the clear channels */ __t1xxp_set_clear(wc); /* Set LIRST bit to 1 */ __t1_set_reg(wc, 0x0a, 0x80); spin_unlock_irqrestore(&wc->lock, flags); /* Wait 100ms to give plenty of time for reset */ endjiffies = jiffies + 10; while(endjiffies < jiffies); spin_lock_irqsave(&wc->lock, flags); /* Reset LIRST bit and reset elastic stores */ __t1_set_reg(wc, 0xa, 0x30); wc->span.flags |= DAHDI_FLAG_RUNNING; } spin_unlock_irqrestore(&wc->lock, flags); } static void t1xxp_e1_framer_start(struct t1xxp *wc) { int i; char *coding, *framing; unsigned long endjiffies; int alreadyrunning = wc->span.flags & DAHDI_FLAG_RUNNING; unsigned long flags; char *crcing = ""; unsigned char ccr1, tcr1, tcr2; spin_lock_irqsave(&wc->lock, flags); /* Build up config */ ccr1 = 0; tcr1 = 8; tcr2 = 0; if (wc->span.lineconfig & DAHDI_CONFIG_CCS) { coding = "CCS"; /* Receive CCS */ ccr1 |= 8; } else { tcr1 |= 0x20; coding = "CAS"; } if (wc->span.lineconfig & DAHDI_CONFIG_HDB3) { ccr1 |= 0x44; /* TX/RX HDB3 */ framing = "HDB3"; } else { framing = "AMI"; } if (wc->span.lineconfig & DAHDI_CONFIG_CRC4) { ccr1 |= 0x11; tcr2 |= 0x02; crcing = " with CRC4"; } __t1_set_reg(wc, 0x12, tcr1); __t1_set_reg(wc, 0x13, tcr2); __t1_set_reg(wc, 0x14, ccr1); __t1_set_reg(wc, 0x18, 0x20); /* 120 Ohm */ #if 0 /* XXX Does LBO Matter? XXX */ /* Set outgoing LBO */ __t1_set_reg(wc, 0x7c, wc->span.txlevel << 5); #endif printk(KERN_DEBUG "Using %s/%s coding/framing%s 120 Ohms\n", coding, framing,crcing); if (!alreadyrunning) { __t1_set_reg(wc,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */ __t1_set_reg(wc,0x20,0x1b); /* TAFR */ __t1_set_reg(wc,0x21,0x5f); /* TNAFR */ __t1_set_reg(wc,0x40,0xb); /* TSR1 */ for(i = 0x41; i <= 0x4f; i++) __t1_set_reg(wc,i,0x55); for(i = 0x22; i <= 0x25; i++) __t1_set_reg(wc,i,0xff); spin_unlock_irqrestore(&wc->lock, flags); /* Wait 100ms to give plenty of time for reset */ endjiffies = jiffies + 10; while(endjiffies < jiffies); spin_lock_irqsave(&wc->lock, flags); __t1_set_reg(wc, 0x1b, 0x9a); /* Set ESR */ __t1_set_reg(wc, 0x1b, 0x82); /* TSCLKM only now */ /* Reset LIRST bit and reset elastic stores */ wc->span.flags |= DAHDI_FLAG_RUNNING; } spin_unlock_irqrestore(&wc->lock, flags); } static int t1xxp_framer_sanity_check(struct t1xxp *wc) { int res; int chipid; unsigned long flags; int x; /* Sanity check */ spin_lock_irqsave(&wc->lock, flags); for (x=0x0;x<192;x++) __t1_set_reg(wc, x, 0); res = __t1_get_reg(wc, 0x0f); res = __t1_get_reg(wc, 0x0f); chipid = ((res & 0x80) >> 5) | ((res & 0x30) >> 4); wc->ise1 = (res & 0x80) ? (1 << 4) : 0; spin_unlock_irqrestore(&wc->lock, flags); printk(KERN_DEBUG "Framer: %s, Revision: %d (%s)\n", chips[chipid], res & 0xf, wc->ise1 ? "E1" : "T1"); return 0; } static int t1xxp_framer_hard_reset(struct t1xxp *wc) { int x; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); /* Initialize all registers to 0 */ for (x=0x0;x<192;x++) __t1_set_reg(wc, x, 0); if (wc->ise1) { /* Set LOTCMC (switch to RCLCK if TCLK fails) */ __t1_set_reg(wc, 0x1a, 0x04); /* RSYNC is an input */ __t1_set_reg(wc, 0x10, 0x20); /* Rx elastic store enabled, 2.048 Mhz (in theory) */ __t1_set_reg(wc, 0x11, 0x06); /* TSYNC is an input, Tsis mode */ __t1_set_reg(wc, 0x12, 0x08); /* Tx elastic store enabled, 2.048 Mhz (in theory) */ __t1_set_reg(wc, 0x1b, 0x82); } else { /* Full-on sync required for T1 */ __t1_set_reg(wc, 0x2b, 0x08); /* RSYNC is an input */ __t1_set_reg(wc, 0x2c, 0x08); /* Enable tx RBS bits */ __t1_set_reg(wc, 0x35, 0x10); /* TSYNC is output */ __t1_set_reg(wc, 0x36, 0x04); /* Tx and Rx elastic store enabled, 2.048 Mhz (in theory) */ __t1_set_reg(wc, 0x37, 0x9c); /* Setup Loopup / Loopdown codes */ __t1_set_reg(wc, 0x12, 0x22); __t1_set_reg(wc, 0x14, 0x80); __t1_set_reg(wc, 0x15, 0x80); } spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) { struct t1xxp *wc = chan->pvt; unsigned long flags; int b,o; unsigned char mask; /* Byte offset */ spin_lock_irqsave(&wc->lock, flags); if (wc->ise1) { if (chan->chanpos < 16) { mask = ((bits << 4) | wc->chans[chan->chanpos - 1 + 16]->txsig); __t1_set_reg(wc, 0x40 + chan->chanpos, mask); } else if (chan->chanpos > 16) { mask = (bits | (wc->chans[chan->chanpos - 1 - 16]->txsig << 4)); __t1_set_reg(wc, 0x40 + chan->chanpos - 16, mask); } wc->chans[chan->chanpos - 1]->txsig = bits; } else { b = (chan->chanpos - 1) / 8; o = (chan->chanpos - 1) % 8; mask = (1 << o); if (bits & DAHDI_ABIT) { /* Set A-bit */ wc->txsiga[b] |= mask; } else { /* Clear A-bit */ wc->txsiga[b] &= ~mask; } if (bits & DAHDI_BBIT) { /* Set B-bit */ wc->txsigb[b] |= mask; } else { wc->txsigb[b] &= ~mask; } /* Output new values */ __t1_set_reg(wc, 0x70 + b, wc->txsiga[b]); __t1_set_reg(wc, 0x73 + b, wc->txsigb[b]); __t1_set_reg(wc, 0x76 + b, wc->txsiga[b]); __t1_set_reg(wc, 0x79 + b, wc->txsigb[b]); } spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { switch(cmd) { default: return -ENOTTY; } } static inline struct t1xxp *t1xxp_from_span(struct dahdi_span *span) { return container_of(span, struct t1xxp, span); } static int t1xxp_startup(struct file *file, struct dahdi_span *span) { struct t1xxp *wc = t1xxp_from_span(span); int i,alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; /* initialize the start value for the entire chunk of last ec buffer */ for(i = 0; i < span->channels; i++) { memset(wc->ec_chunk1[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); memset(wc->ec_chunk2[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); } /* Reset framer with proper parameters and start */ if (wc->ise1) t1xxp_e1_framer_start(wc); else t1xxp_t1_framer_start(wc); printk(KERN_INFO "Calling startup (flags is %lu)\n", span->flags); if (!alreadyrunning) { /* Only if we're not already going */ t1xxp_enable_interrupts(wc); t1xxp_start_dma(wc); span->flags |= DAHDI_FLAG_RUNNING; } return 0; } static int t1xxp_shutdown(struct dahdi_span *span) { struct t1xxp *wc = t1xxp_from_span(span); unsigned long flags; spin_lock_irqsave(&wc->lock, flags); __t1xxp_stop_dma(wc); __t1xxp_disable_interrupts(wc); span->flags &= ~DAHDI_FLAG_RUNNING; spin_unlock_irqrestore(&wc->lock, flags); t1xxp_framer_hard_reset(wc); return 0; } static int t1xxp_maint(struct dahdi_span *span, int cmd) { struct t1xxp *wc = t1xxp_from_span(span); int res = 0; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->ise1) { switch(cmd) { case DAHDI_MAINT_NONE: __t1_set_reg(wc,0xa8,0); /* no loops */ break; case DAHDI_MAINT_LOCALLOOP: __t1_set_reg(wc,0xa8,0x40); /* local loop */ break; case DAHDI_MAINT_REMOTELOOP: __t1_set_reg(wc,0xa8,0x80); /* remote loop */ break; case DAHDI_MAINT_LOOPUP: case DAHDI_MAINT_LOOPDOWN: res = -ENOSYS; break; default: printk(KERN_NOTICE "wct1xxp/E1: Unknown maint command: %d\n", cmd); res = -EINVAL; break; } } else { switch(cmd) { case DAHDI_MAINT_NONE: __t1_set_reg(wc,0x19,0); /* no local loop */ __t1_set_reg(wc,0x0a,0); /* no remote loop */ __t1_set_reg(wc, 0x30, 0); /* stop sending loopup code*/ break; case DAHDI_MAINT_LOCALLOOP: __t1_set_reg(wc,0x19,0x40); /* local loop */ __t1_set_reg(wc,0x0a,0); /* no remote loop */ break; case DAHDI_MAINT_REMOTELOOP: __t1_set_reg(wc,0x1e,0); /* no local loop */ __t1_set_reg(wc,0x0a,0x40); /* remote loop */ break; case DAHDI_MAINT_LOOPUP: __t1_set_reg(wc,0x30,2); /* send loopup code */ __t1_set_reg(wc,0x12,0x22); /* send loopup code */ __t1_set_reg(wc,0x13,0x80); /* send loopup code */ break; case DAHDI_MAINT_LOOPDOWN: __t1_set_reg(wc,0x30,2); /* send loopdown code */ __t1_set_reg(wc,0x12,0x62); /* send loopdown code */ __t1_set_reg(wc,0x13,0x90); /* send loopdown code */ break; default: printk(KERN_NOTICE "wct1xxp/T1: Unknown maint command: %d\n", cmd); res = -EINVAL; } } spin_unlock_irqrestore(&wc->lock, flags); return res; } static int t1xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { struct t1xxp *wc = chan->pvt; unsigned long flags; int alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING; spin_lock_irqsave(&wc->lock, flags); if (alreadyrunning && !wc->ise1) __t1xxp_set_clear(wc); spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct t1xxp *wc = t1xxp_from_span(span); /* Do we want to SYNC on receive or not */ wc->sync = (lc->sync) ? 1 : 0; /* If already running, apply changes immediately */ if (span->flags & DAHDI_FLAG_RUNNING) return t1xxp_startup(file, span); return 0; } static const struct dahdi_span_ops t1xxp_span_ops = { .owner = THIS_MODULE, .spanconfig = t1xxp_spanconfig, .chanconfig = t1xxp_chanconfig, .startup = t1xxp_startup, .shutdown = t1xxp_shutdown, .rbsbits = t1xxp_rbsbits, .maint = t1xxp_maint, .open = t1xxp_open, .close = t1xxp_close, .ioctl = t1xxp_ioctl, }; static int t1xxp_software_init(struct t1xxp *wc) { int x; /* Find position */ for (x=0;x= WC_MAX_CARDS) return -1; wc->num = x; sprintf(wc->span.name, "WCT1/%d", wc->num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); wc->span.manufacturer = "Digium"; strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); wc->span.irq = wc->dev->irq; wc->span.chans = wc->chans; wc->span.flags = DAHDI_FLAG_RBS; if (wc->ise1) { wc->span.channels = 31; wc->span.deflaw = DAHDI_LAW_ALAW; wc->span.linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; wc->span.spantype = "E1"; } else { wc->span.channels = 24; wc->span.deflaw = DAHDI_LAW_MULAW; wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; wc->span.spantype = "T1"; } for (x=0;xspan.channels;x++) { sprintf(wc->chans[x]->name, "WCT1/%d/%d", wc->num, x + 1); wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF; wc->chans[x]->pvt = wc; wc->chans[x]->chanpos = x + 1; } wc->span.ops = &t1xxp_span_ops; if (dahdi_register(&wc->span, 0)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } return 0; } static inline void __handle_leds(struct t1xxp *wc) { int oldreg; wc->blinktimer++; if (wc->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) { /* Red/Blue alarm */ #ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } if (wc->blinktimer == 0xf) { wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); wc->blinktimer = -1; wc->alarmpos++; if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) wc->alarmpos = 0; } #else if (wc->blinktimer == 160) { wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } else if (wc->blinktimer == 480) { wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); wc->blinktimer = 0; } #endif } else if (wc->span.alarms & DAHDI_ALARM_YELLOW) { /* Yellow Alarm */ if (!(wc->blinktimer % 2)) wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; else wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } else { /* No Alarm */ oldreg = wc->ledtestreg; if (wc->span.maintstat != DAHDI_MAINT_NONE) wc->ledtestreg |= BIT_TEST; else wc->ledtestreg &= ~BIT_TEST; if (wc->span.flags & DAHDI_FLAG_RUNNING) wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; else wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); if (oldreg != wc->ledtestreg) __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } } static void t1xxp_transmitprep(struct t1xxp *wc, int ints) { volatile unsigned char *txbuf; int x,y; int pos; if (ints & 0x04 /* 0x01 */) { /* We just finished sending the first buffer, start filling it now */ txbuf = wc->writechunk; } else { /* Just finished sending second buffer, fill it now */ txbuf = wc->writechunk + 32 * DAHDI_CHUNKSIZE; } dahdi_transmit(&wc->span); for (x=0;xoffset;x++) txbuf[x] = wc->tempo[x]; for (y=0;yspan.channels;x++) { pos = y * 32 + wc->chanmap[x] + wc->offset; /* Put channel number as outgoing data */ if (pos < 32 * DAHDI_CHUNKSIZE) txbuf[pos] = wc->chans[x]->writechunk[y]; else wc->tempo[pos - 32 * DAHDI_CHUNKSIZE] = wc->chans[x]->writechunk[y]; } } } static void t1xxp_receiveprep(struct t1xxp *wc, int ints) { volatile unsigned char *rxbuf; volatile unsigned int *canary; int x; int y; unsigned int oldcan; if (ints & 0x04) { /* Just received first buffer */ rxbuf = wc->readchunk; canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 64 - 4); } else { rxbuf = wc->readchunk + DAHDI_CHUNKSIZE * 32; canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 32 - 4); } oldcan = *canary; if (((oldcan & 0xffff0000) >> 16) != CANARY) { /* Check top part */ if (debug) printk(KERN_DEBUG "Expecting top %04x, got %04x\n", CANARY, (oldcan & 0xffff0000) >> 16); wc->span.irqmisses++; } else if ((oldcan & 0xffff) != ((wc->canary - 1) & 0xffff)) { if (debug) printk(KERN_DEBUG "Expecting bottom %d, got %d\n", wc->canary - 1, oldcan & 0xffff); wc->span.irqmisses++; } for (y=0;yspan.channels;x++) { /* XXX Optimize, remove * and + XXX */ /* Must map received channels into appropriate data */ wc->chans[x]->readchunk[y] = rxbuf[32 * y + ((wc->chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)]; } if (!wc->ise1) { for (x=3;x<32;x+=4) { if (rxbuf[32 * y + ((x + WC_OFFSET) & 0x1f)] == 0x7f) { if (wc->offset != (x-3)) { /* Resync */ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1); wc->clocktimeout = 100; #if 1 if (debug) printk(KERN_DEBUG "T1: Lost our place, resyncing\n"); #endif } } } } else { if (!wc->clocktimeout && !wc->span.alarms) { if ((rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)] & 0x7f) != 0x1b) { if (wc->miss) { if (debug) printk(KERN_DEBUG "Double miss (%d, %d)...\n", wc->misslast, rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]); control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1); wc->clocktimeout = 100; } else { wc->miss = 1; wc->misslast = rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]; } } else { wc->miss = 0; } } else { wc->miss = 0; } } } /* Store the next canary */ canary = (unsigned int *)(rxbuf + DAHDI_CHUNKSIZE * 32 - 4); *canary = (wc->canary++) | (CANARY << 16); for (x=0;xspan.channels;x++) { dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->ec_chunk2[x]); memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],DAHDI_CHUNKSIZE); memcpy(wc->ec_chunk1[x],wc->chans[x]->writechunk,DAHDI_CHUNKSIZE); } dahdi_receive(&wc->span); } static void t1xxp_check_sigbits(struct t1xxp *wc, int x) { int a,b,i,y,rxs; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->ise1) { /* Read 5 registers at a time, loading 10 channels at a time */ for (i = (x * 5); i < (x * 5) + 5; i++) { a = __t1_get_reg(wc, 0x31 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->chans[i+16]->sig & DAHDI_SIG_CLEAR)) { if (wc->chans[i+16]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->chans[i+16], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a >> 4) & 0xf; if (!(wc->chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->chans[i]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->chans[i], rxs); spin_lock_irqsave(&wc->lock, flags); } } } } else { a = __t1_get_reg(wc, 0x60 + x); b = __t1_get_reg(wc, 0x63 + x); for (y=0;y<8;y++) { i = x * 8 + y; rxs = 0; if (a & (1 << y)) rxs |= DAHDI_ABIT; if (b & (1 << y)) rxs |= DAHDI_BBIT; if (!(wc->chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->chans[i]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->chans[i], rxs); spin_lock_irqsave(&wc->lock, flags); } } } } spin_unlock_irqrestore(&wc->lock, flags); } static void t1xxp_check_alarms(struct t1xxp *wc) { unsigned char c,d; int alarms; int x,j; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->ise1) { __t1_set_reg(wc, 0x06, 0xff); c = __t1_get_reg(wc, 0x6); } else { /* Get RIR2 */ c = __t1_get_reg(wc, 0x31); wc->span.rxlevel = c >> 6; /* Get status register s*/ __t1_set_reg(wc, 0x20, 0xff); c = __t1_get_reg(wc, 0x20); } /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); if (wc->ise1) { /* XXX Implement me XXX */ } else { /* Detect loopup code if we're not sending one */ if ((!wc->span.mainttimer) && (c & 0x80)) { /* Loop-up code detected */ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { __t1_set_reg(wc, 0x1e, 0); /* No local loop */ __t1_set_reg(wc, 0x0a, 0x40); /* Remote Loop */ wc->span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else { wc->loopupcnt = 0; } /* Same for loopdown code */ if ((!wc->span.mainttimer) && (c & 0x40)) { /* Loop-down code detected */ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { __t1_set_reg(wc, 0x1e, 0); /* No local loop */ __t1_set_reg(wc, 0x0a, 0x0); /* No remote Loop */ wc->span.maintstat = DAHDI_MAINT_NONE; } } else wc->loopdowncnt = 0; } if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { for (x=0,j=0;x < wc->span.channels;x++) if ((wc->chans[x]->flags & DAHDI_FLAG_OPEN) || dahdi_have_netdev(wc->chans[x])) j++; if (!j) alarms |= DAHDI_ALARM_NOTOPEN; } if (wc->ise1) { if (c & 0x9) alarms |= DAHDI_ALARM_RED; if (c & 0x2) alarms |= DAHDI_ALARM_BLUE; } else { /* Check actual alarm status */ if (c & 0x3) alarms |= DAHDI_ALARM_RED; if (c & 0x8) alarms |= DAHDI_ALARM_BLUE; } /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) wc->alarmtimer = DAHDI_ALARMSETTLE_TIME; /* If receiving alarms, go into Yellow alarm state */ if (alarms && (!wc->span.alarms)) { #if 0 printk(KERN_DEBUG "Going into yellow alarm\n"); #endif if (wc->ise1) __t1_set_reg(wc, 0x21, 0x7f); else __t1_set_reg(wc, 0x35, 0x11); } if (wc->span.alarms != alarms) { d = __control_get_reg(wc, WC_CLOCK); start_alarm(wc); if (!(alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK)) && wc->sync) { /* Use the receive signalling */ wc->span.syncsrc = wc->span.spanno; d |= 1; } else { wc->span.syncsrc = 0; d &= ~1; } __control_set_reg(wc, WC_CLOCK, d); } if (wc->alarmtimer) alarms |= DAHDI_ALARM_RECOVER; if (c & 0x4) alarms |= DAHDI_ALARM_YELLOW; wc->span.alarms = alarms; spin_unlock_irqrestore(&wc->lock, flags); dahdi_alarm_notify(&wc->span); } static void t1xxp_do_counters(struct t1xxp *wc) { unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->alarmtimer) { if (!--wc->alarmtimer) { wc->span.alarms &= ~(DAHDI_ALARM_RECOVER); /* Clear yellow alarm */ #if 0 printk(KERN_DEBUG "Coming out of alarm\n"); #endif if (wc->ise1) __t1_set_reg(wc, 0x21, 0x5f); else __t1_set_reg(wc, 0x35, 0x10); spin_unlock_irqrestore(&wc->lock, flags); dahdi_alarm_notify(&wc->span); spin_lock_irqsave(&wc->lock, flags); } } spin_unlock_irqrestore(&wc->lock, flags); } DAHDI_IRQ_HANDLER(t1xxp_interrupt) { struct t1xxp *wc = dev_id; unsigned char ints; unsigned long flags; int x; ints = inb(wc->ioaddr + WC_INTSTAT); if (!ints) return IRQ_NONE; outb(ints, wc->ioaddr + WC_INTSTAT); if (!wc->intcount) { if (debug) printk(KERN_DEBUG "Got interrupt: 0x%04x\n", ints); } wc->intcount++; if (wc->clocktimeout && !--wc->clocktimeout) control_set_reg(wc, WC_CLOCK, 0x00 | wc->sync | wc->ise1); if (ints & 0x0f) { t1xxp_receiveprep(wc, ints); t1xxp_transmitprep(wc, ints); } spin_lock_irqsave(&wc->lock, flags); #if 1 __handle_leds(wc); #endif spin_unlock_irqrestore(&wc->lock, flags); /* Count down timers */ t1xxp_do_counters(wc); /* Do some things that we don't have to do very often */ x = wc->intcount & 15 /* 63 */; switch(x) { case 0: case 1: case 2: t1xxp_check_sigbits(wc, x); break; case 4: /* Check alarms 1/4 as frequently */ if (!(wc->intcount & 0x30)) t1xxp_check_alarms(wc); break; } if (ints & 0x10) printk(KERN_INFO "PCI Master abort\n"); if (ints & 0x20) printk(KERN_INFO "PCI Target abort\n"); return IRQ_RETVAL(1); } static int t1xxp_hardware_init(struct t1xxp *wc) { /* Hardware PCI stuff */ /* Reset chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Set all outputs to 0 */ outb(0x00, wc->ioaddr + WC_AUXD); /* Set all to outputs except AUX1 (TDO). */ outb(0xfd, wc->ioaddr + WC_AUXC); /* Configure the serial port: double clock, 20ns width, no inversion, MSB first */ outb(0xc8, wc->ioaddr + WC_SERC); /* Internally delay FSC by one */ outb(0x01, wc->ioaddr + WC_FSCDELAY); /* Back to normal, with automatic DMA wrap around */ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); /* Make sure serial port and DMA are out of reset */ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL); /* Setup DMA Addresses */ /* Start at writedma */ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ /* First frame */ outl(wc->writedma + DAHDI_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ /* Second frame */ outl(wc->writedma + DAHDI_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE); /* End */ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ /* First frame */ outl(wc->readdma + DAHDI_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ /* Second frame */ outl(wc->readdma + DAHDI_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */ if (debug) printk(KERN_DEBUG "Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma); /* Check out the controller */ if (debug) printk(KERN_DEBUG "Controller version: %02x\n", control_get_reg(wc, WC_VERSION)); control_set_reg(wc, WC_LEDTEST, 0x00); /* Sanity check also determines e1 or t1 */ if (t1xxp_framer_sanity_check(wc)) return -1; if (wc->ise1) wc->chanmap = chanmap_e1; else wc->chanmap = chanmap_t1; /* Setup clock appropriately */ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1); wc->clocktimeout = 100; /* Reset the T1 and report */ t1xxp_framer_hard_reset(wc); start_alarm(wc); return 0; } static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct t1xxp *wc; unsigned int *canary; unsigned int x; if (pci_enable_device(pdev)) { printk(KERN_ERR "%s: pci_enable_device failed\n", __FUNCTION__); return -EIO; } if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { printk(KERN_ERR "%s: Failed allocation a wc\n", __FUNCTION__); return -ENOMEM; } memset(wc, 0x0, sizeof(*wc)); spin_lock_init(&wc->lock); wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->offset = 28; /* And you thought 42 was the answer */ wc->writechunk = /* 32 channels, Double-buffer, Read/Write */ (unsigned char *)pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma); if (!wc->writechunk) { printk(KERN_NOTICE "wct1xxp: Unable to allocate DMA-able memory\n"); return -ENOMEM; } /* Read is after the whole write piece (in bytes) */ wc->readchunk = wc->writechunk + DAHDI_CHUNKSIZE * 32 * 2; /* Same thing... */ wc->readdma = wc->writedma + DAHDI_CHUNKSIZE * 32 * 2; /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0x00,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32); /* Initialize canary */ canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 64 - 4); *canary = (CANARY << 16) | (0xffff); /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, t1xxp_interrupt, DAHDI_IRQ_SHARED_DISABLED, "t1xxp", wc)) { printk(KERN_NOTICE "t1xxp: Unable to request IRQ %d\n", pdev->irq); kfree(wc); return -EIO; } /* Initialize hardware */ t1xxp_hardware_init(wc); /* We now know which version of card we have */ if (wc->ise1) { wc->variety = "Digium Wildcard E100P E1/PRA"; } else { wc->variety = "Digium Wildcard T100P T1/PRI"; } for (x = 0; x < (wc->ise1 ? 31 : 24); x++) { if (!(wc->chans[x] = kmalloc(sizeof(*wc->chans[x]), GFP_KERNEL))) { while (x) { kfree(wc->chans[--x]); } kfree(wc); return -ENOMEM; } memset(wc->chans[x], 0, sizeof(*wc->chans[x])); } /* Misc. software stuff */ t1xxp_software_init(wc); printk(KERN_INFO "Found a Wildcard: %s\n", wc->variety); return 0; } static void t1xxp_stop_stuff(struct t1xxp *wc) { /* Kill clock */ control_set_reg(wc, WC_CLOCK, 0); /* Turn off LED's */ control_set_reg(wc, WC_LEDTEST, 0); /* Reset the T1 */ t1xxp_framer_hard_reset(wc); } static void __devexit t1xxp_remove_one(struct pci_dev *pdev) { struct t1xxp *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ __t1xxp_stop_dma(wc); /* In case hardware is still there */ __t1xxp_disable_interrupts(wc); t1xxp_stop_stuff(wc); /* Immediately free resources */ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Release span, possibly delayed */ if (!wc->usecount) t1xxp_release(wc); else wc->dead = 1; } } static DEFINE_PCI_DEVICE_TABLE(t1xxp_pci_tbl) = { { 0xe159, 0x0001, 0x6159, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard T100P T1/PRI or E100P E1/PRA Board" }, { 0 } }; MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl); static struct pci_driver t1xxp_driver = { .name = "t1xxp", .probe = t1xxp_init_one, .remove = __devexit_p(t1xxp_remove_one), .suspend = NULL, .resume = NULL, . id_table = t1xxp_pci_tbl, }; static int __init t1xxp_init(void) { int res; res = dahdi_pci_module(&t1xxp_driver); if (res) return -ENODEV; return 0; } static void __exit t1xxp_cleanup(void) { pci_unregister_driver(&t1xxp_driver); } module_param(debug, int, 0600); MODULE_DESCRIPTION("Wildcard T100P/E100P Driver"); MODULE_AUTHOR("Mark Spencer "); MODULE_LICENSE("GPL v2"); module_init(t1xxp_init); module_exit(t1xxp_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_dynamic_eth.c0000644000175000017500000002346211510412325022320 0ustar tzafrirtzafrir/* * Dynamic Span Interface for DAHDI (Ethernet Interface) * * Written by Mark Spencer * * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #define ETH_P_DAHDI_DETH 0xd00d struct ztdeth_header { unsigned short subaddr; }; /* We take the raw message, put it in an ethernet frame, and add a two byte addressing header at the top for future use */ static DEFINE_SPINLOCK(zlock); static struct sk_buff_head skbs; static struct ztdeth { unsigned char addr[ETH_ALEN]; unsigned short subaddr; /* Network byte order */ struct dahdi_span *span; char ethdev[IFNAMSIZ]; struct net_device *dev; struct ztdeth *next; } *zdevs = NULL; static struct dahdi_span *ztdeth_getspan(unsigned char *addr, unsigned short subaddr) { unsigned long flags; struct ztdeth *z; struct dahdi_span *span = NULL; spin_lock_irqsave(&zlock, flags); z = zdevs; while(z) { if (!memcmp(addr, z->addr, ETH_ALEN) && z->subaddr == subaddr) break; z = z->next; } if (z) span = z->span; spin_unlock_irqrestore(&zlock, flags); return span; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) #else static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) #endif { struct dahdi_span *span; struct ztdeth_header *zh; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) zh = (struct ztdeth_header *)skb_network_header(skb); #else zh = (struct ztdeth_header *)skb->nh.raw; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) span = ztdeth_getspan(eth_hdr(skb)->h_source, zh->subaddr); #else span = ztdeth_getspan(skb->mac.ethernet->h_source, zh->subaddr); #endif if (span) { skb_pull(skb, sizeof(struct ztdeth_header)); #ifdef NEW_SKB_LINEARIZE if (skb_is_nonlinear(skb)) skb_linearize(skb); #else if (skb_is_nonlinear(skb)) skb_linearize(skb, GFP_KERNEL); #endif dahdi_dynamic_receive(span, (unsigned char *)skb->data, skb->len); } kfree_skb(skb); return 0; } static int ztdeth_notifier(struct notifier_block *block, unsigned long event, void *ptr) { struct net_device *dev = ptr; struct ztdeth *z; unsigned long flags; switch(event) { case NETDEV_GOING_DOWN: case NETDEV_DOWN: spin_lock_irqsave(&zlock, flags); z = zdevs; while(z) { /* Note that the device no longer exists */ if (z->dev == dev) z->dev = NULL; z = z->next; } spin_unlock_irqrestore(&zlock, flags); break; case NETDEV_UP: spin_lock_irqsave(&zlock, flags); z = zdevs; while(z) { /* Now that the device exists again, use it */ if (!strcmp(z->ethdev, dev->name)) z->dev = dev; z = z->next; } spin_unlock_irqrestore(&zlock, flags); break; } return 0; } static void ztdeth_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) { struct ztdeth *z; struct sk_buff *skb; struct ztdeth_header *zh; unsigned long flags; struct net_device *dev; unsigned char addr[ETH_ALEN]; unsigned short subaddr; /* Network byte order */ spin_lock_irqsave(&zlock, flags); z = dyn->pvt; if (z->dev) { /* Copy fields to local variables to remove spinlock ASAP */ dev = z->dev; memcpy(addr, z->addr, sizeof(z->addr)); subaddr = z->subaddr; spin_unlock_irqrestore(&zlock, flags); skb = dev_alloc_skb(msglen + dev->hard_header_len + sizeof(struct ztdeth_header) + 32); if (skb) { /* Reserve header space */ skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header)); /* Copy message body */ memcpy(skb_put(skb, msglen), msg, msglen); /* Throw on header */ zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header)); zh->subaddr = subaddr; /* Setup protocol and such */ skb->protocol = __constant_htons(ETH_P_DAHDI_DETH); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) skb_set_network_header(skb, 0); #else skb->nh.raw = skb->data; #endif skb->dev = dev; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) dev_hard_header(skb, dev, ETH_P_DAHDI_DETH, addr, dev->dev_addr, skb->len); #else if (dev->hard_header) dev->hard_header(skb, dev, ETH_P_DAHDI_DETH, addr, dev->dev_addr, skb->len); #endif skb_queue_tail(&skbs, skb); } } else spin_unlock_irqrestore(&zlock, flags); } static int ztdeth_flush(void) { struct sk_buff *skb; /* Handle all transmissions now */ while ((skb = skb_dequeue(&skbs))) { dev_queue_xmit(skb); } return 0; } static struct packet_type ztdeth_ptype = { .type = __constant_htons(ETH_P_DAHDI_DETH), /* Protocol */ .dev = NULL, /* Device (NULL = wildcard) */ .func = ztdeth_rcv, /* Receiver */ }; static int digit2int(char d) { switch(d) { case 'F': case 'E': case 'D': case 'C': case 'B': case 'A': return d - 'A' + 10; case 'f': case 'e': case 'd': case 'c': case 'b': case 'a': return d - 'a' + 10; case '9': case '8': case '7': case '6': case '5': case '4': case '3': case '2': case '1': case '0': return d - '0'; } return -1; } static int hex2int(char *s) { int res; int tmp; /* Gotta be at least one digit */ if (strlen(s) < 1) return -1; /* Can't be more than two */ if (strlen(s) > 2) return -1; /* Grab the first digit */ res = digit2int(s[0]); if (res < 0) return -1; tmp = res; /* Grab the next */ if (strlen(s) > 1) { res = digit2int(s[1]); if (res < 0) return -1; tmp = tmp * 16 + res; } return tmp; } static void ztdeth_destroy(struct dahdi_dynamic *dyn) { struct ztdeth *z = dyn->pvt; unsigned long flags; struct ztdeth *prev=NULL, *cur; spin_lock_irqsave(&zlock, flags); cur = zdevs; while(cur) { if (cur == z) { if (prev) prev->next = cur->next; else zdevs = cur->next; break; } prev = cur; cur = cur->next; } spin_unlock_irqrestore(&zlock, flags); if (cur == z) { /* Successfully removed */ printk(KERN_INFO "TDMoE: Removed interface for %s\n", z->span->name); kfree(z); } } static int ztdeth_create(struct dahdi_dynamic *dyn, const char *addr) { struct ztdeth *z; char src[256]; char tmp[256], *tmp2, *tmp3, *tmp4 = NULL; int res,x; unsigned long flags; struct dahdi_span *const span = &dyn->span; z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL); if (z) { /* Zero it out */ memset(z, 0, sizeof(struct ztdeth)); /* Address should be /[/subaddr] */ strlcpy(tmp, addr, sizeof(tmp)); tmp2 = strchr(tmp, '/'); if (tmp2) { *tmp2 = '\0'; tmp2++; strlcpy(z->ethdev, tmp, sizeof(z->ethdev)); } else { printk(KERN_NOTICE "Invalid TDMoE address (no device) '%s'\n", addr); kfree(z); return -EINVAL; } if (tmp2) { tmp4 = strchr(tmp2+1, '/'); if (tmp4) { *tmp4 = '\0'; tmp4++; } /* We don't have SSCANF :( Gotta do this the hard way */ tmp3 = strchr(tmp2, ':'); for (x=0;x<6;x++) { if (tmp2) { if (tmp3) { *tmp3 = '\0'; tmp3++; } res = hex2int(tmp2); if (res < 0) break; z->addr[x] = res & 0xff; } else break; if ((tmp2 = tmp3)) tmp3 = strchr(tmp2, ':'); } if (x != 6) { printk(KERN_NOTICE "TDMoE: Invalid MAC address in: %s\n", addr); kfree(z); return -EINVAL; } } else { printk(KERN_NOTICE "TDMoE: Missing MAC address\n"); kfree(z); return -EINVAL; } if (tmp4) { int sub = 0; int mul = 1; /* We have a subaddr */ tmp3 = tmp4 + strlen (tmp4) - 1; while (tmp3 >= tmp4) { if (*tmp3 >= '0' && *tmp3 <= '9') { sub += (*tmp3 - '0') * mul; } else { printk(KERN_NOTICE "TDMoE: Invalid subaddress\n"); kfree(z); return -EINVAL; } mul *= 10; tmp3--; } z->subaddr = htons(sub); } z->dev = dev_get_by_name( #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) &init_net, #endif z->ethdev); if (!z->dev) { printk(KERN_NOTICE "TDMoE: Invalid device '%s'\n", z->ethdev); kfree(z); return -EINVAL; } z->span = span; src[0] ='\0'; for (x=0;x<5;x++) sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]); sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]); printk(KERN_INFO "TDMoE: Added new interface for %s at %s (addr=%s, src=%s, subaddr=%d)\n", span->name, z->dev->name, addr, src, ntohs(z->subaddr)); spin_lock_irqsave(&zlock, flags); z->next = zdevs; zdevs = z; dyn->pvt = z; spin_unlock_irqrestore(&zlock, flags); } return (z) ? 0 : -ENOMEM; } static struct dahdi_dynamic_driver ztd_eth = { .owner = THIS_MODULE, .name = "eth", .desc = "Ethernet", .create = ztdeth_create, .destroy = ztdeth_destroy, .transmit = ztdeth_transmit, .flush = ztdeth_flush, }; static struct notifier_block ztdeth_nblock = { .notifier_call = ztdeth_notifier, }; static int __init ztdeth_init(void) { dev_add_pack(&ztdeth_ptype); register_netdevice_notifier(&ztdeth_nblock); dahdi_dynamic_register_driver(&ztd_eth); skb_queue_head_init(&skbs); return 0; } static void __exit ztdeth_exit(void) { dev_remove_pack(&ztdeth_ptype); unregister_netdevice_notifier(&ztdeth_nblock); dahdi_dynamic_unregister_driver(&ztd_eth); } MODULE_DESCRIPTION("DAHDI Dynamic TDMoE Support"); MODULE_AUTHOR("Mark Spencer "); MODULE_LICENSE("GPL v2"); module_init(ztdeth_init); module_exit(ztdeth_exit); dahdi-linux-2.5.0.1/drivers/dahdi/wcte11xp.c0000644000175000017500000013221611571766036020377 0ustar tzafrirtzafrir/* * Digium, Inc. Wildcard TE110P T1/PRI card Driver * * Written by Mark Spencer * Matthew Fredrickson * William Meadows * * Copyright (C) 2004, Digium, Inc. * * All rights reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include /* XXX: fix this */ #include "wct4xxp/wct4xxp.h" /* For certain definitions */ #define WC_MAX_CARDS 32 /* #define TEST_REGS */ /* Define to get more attention-grabbing but slightly more I/O using alarm status */ #define FANCY_ALARM /* Define to enable the V2.1 errata register settings */ #if 0 #define TRUST_INFINEON_ERRATA #endif #define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ #define WC_CNTL 0x00 #define WC_OPER 0x01 #define WC_AUXC 0x02 #define WC_AUXD 0x03 #define WC_MASK0 0x04 #define WC_MASK1 0x05 #define WC_INTSTAT 0x06 #define WC_DMAWS 0x08 #define WC_DMAWI 0x0c #define WC_DMAWE 0x10 #define WC_DMARS 0x18 #define WC_DMARI 0x1c #define WC_DMARE 0x20 #define WC_CURPOS 0x24 #define WC_SERC 0x2d #define WC_FSCDELAY 0x2f #define WC_USERREG 0xc0 #define WC_CLOCK 0x0 #define WC_LEDTEST 0x1 #define WC_VERSION 0x2 /* Offset between transmit and receive */ #define WC_OFFSET 4 #define BIT_CS (1 << 7) #define BIT_ADDR (0xf << 3) #define BIT_LED1 (1 << 0) #define BIT_LED0 (1 << 1) #define BIT_TEST (1 << 2) #define FLAG_STARTED (1 << 0) #define FLAG_NMF (1 << 1) #define FLAG_SENDINGYELLOW (1 << 2) #define FLAG_FALC12 (1 << 3) #define TYPE_T1 1 /* is a T1 card */ #define TYPE_E1 2 /* is an E1 card */ static int chanmap_t1[] = { 2,1,0, 6,5,4, 10,9,8, 14,13,12, 18,17,16, 22,21,20, 26,25,24, 30,29,28 }; static int chanmap_e1[] = { 2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12, 19,18,17,16, 23,22,21,20, 27,26,25,24, 31,30,29,28 }; static int chanmap_e1uc[] = { 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12, 19,18,17,16, 23,22,21,20, 27,26,25,24, 31,30,29,28 }; #ifdef FANCY_ALARM static int altab[] = { 0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, }; #endif struct t1 { struct pci_dev *dev; spinlock_t lock; int spantype; int spanflags; /* Span flags */ unsigned char txsigs[16]; /* Copy of tx sig registers */ int num; int alarmcount; /* How much red alarm we've seen */ int alarmdebounce; /* Our offset for finding channel 1 */ int offset; char *variety; unsigned int intcount; int usecount; int clocktimeout; int sync; int dead; int blinktimer; int alarmtimer; int checktiming; /* Set >0 to cause the timing source to be checked */ int loopupcnt; int loopdowncnt; int miss; int misslast; int *chanmap; #ifdef FANCY_ALARM int alarmpos; #endif unsigned char ledtestreg; unsigned char outbyte; unsigned long ioaddr; unsigned short canary; /* T1 signalling */ dma_addr_t readdma; dma_addr_t writedma; volatile unsigned char *writechunk; /* Double-word aligned write memory */ volatile unsigned char *readchunk; /* Double-word aligned read memory */ unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE]; unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE]; unsigned char tempo[33]; struct dahdi_span span; /* Span */ struct dahdi_chan *chans[32]; /* Channels */ }; #define CANARY 0xca1e static int debug = 0; /* doesnt do anything */ static int j1mode = 0; static int alarmdebounce = 0; static int loopback = 0; static int clockextra = 0; static int t1e1override = -1; static int unchannelized = 0; static struct t1 *cards[WC_MAX_CARDS]; static inline void start_alarm(struct t1 *wc) { #ifdef FANCY_ALARM wc->alarmpos = 0; #endif wc->blinktimer = 0; } static inline void stop_alarm(struct t1 *wc) { #ifdef FANCY_ALARM wc->alarmpos = 0; #endif wc->blinktimer = 0; } static inline void __select_framer(struct t1 *wc, int reg) { /* Top four bits of address from AUX 6-3 */ wc->outbyte &= ~BIT_CS; wc->outbyte &= ~BIT_ADDR; wc->outbyte |= (reg & 0xf0) >> 1; outb(wc->outbyte, wc->ioaddr + WC_AUXD); } static inline void __select_control(struct t1 *wc) { if (!(wc->outbyte & BIT_CS)) { wc->outbyte |= BIT_CS; outb(wc->outbyte, wc->ioaddr + WC_AUXD); } } static int t1xxp_open(struct dahdi_chan *chan) { struct t1 *wc = chan->pvt; if (wc->dead) return -ENODEV; wc->usecount++; return 0; } static int __control_set_reg(struct t1 *wc, int reg, unsigned char val) { __select_control(wc); outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return 0; } static int control_set_reg(struct t1 *wc, int reg, unsigned char val) { unsigned long flags; int res; spin_lock_irqsave(&wc->lock, flags); res = __control_set_reg(wc, reg, val); spin_unlock_irqrestore(&wc->lock, flags); return res; } static int __control_get_reg(struct t1 *wc, int reg) { unsigned char res; /* The following makes UTTERLY no sense, but what was happening was that reads in some cases were not actually happening on the physical bus. Why, we dunno. But in debugging, we found that writing before reading (in this case to an unused position) seems to get rid of the problem */ __control_set_reg(wc,3,0x69); /* do magic here */ /* now get the read byte from the Xilinx part */ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; } static int control_get_reg(struct t1 *wc, int reg) { unsigned long flags; int res; spin_lock_irqsave(&wc->lock, flags); res = __control_get_reg(wc, reg); spin_unlock_irqrestore(&wc->lock, flags); return res; } static inline unsigned int __t1_framer_in(struct t1 *wc, const unsigned int reg) { unsigned char res; __select_framer(wc, reg); /* Get value */ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); return res; #if 0 unsigned int ret; __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | ( 1 << 10) | WC_LREAD); ret = __t1_pci_in(wc, WC_LDATA); __t1_pci_out(wc, WC_LADDR, 0); return ret & 0xff; #endif } static inline unsigned int t1_framer_in(struct t1 *wc, const unsigned int addr) { unsigned long flags; unsigned int ret; spin_lock_irqsave(&wc->lock, flags); ret = __t1_framer_in(wc, addr); spin_unlock_irqrestore(&wc->lock, flags); return ret; } static inline void __t1_framer_out(struct t1 *wc, const unsigned int reg, const unsigned int val) { if (debug > 1) printk(KERN_DEBUG "Writing %02x to address %02x\n", val, reg); __select_framer(wc, reg); /* Send address */ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2)); #if 0 __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); __t1_pci_out(wc, WC_LDATA, value); __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10)); __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10) | WC_LWRITE); __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10)); __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff)); __t1_pci_out(wc, WC_LADDR, 0); if (debug) printk(KERN_DEBUG "Write complete\n"); #endif #if 0 { unsigned int tmp; tmp = t1_framer_in(wc, unit, addr); if (tmp != value) { printk(KERN_DEBUG "Expected %d from unit %d register %d but got %d instead\n", value, unit, addr, tmp); } } #endif } static inline void t1_framer_out(struct t1 *wc, const unsigned int addr, const unsigned int value) { unsigned long flags; spin_lock_irqsave(&wc->lock, flags); __t1_framer_out(wc, addr, value); spin_unlock_irqrestore(&wc->lock, flags); } static void t1xxp_release(struct t1 *wc) { unsigned int x; dahdi_unregister(&wc->span); for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { kfree(wc->chans[x]); } kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } static int t1xxp_close(struct dahdi_chan *chan) { struct t1 *wc = chan->pvt; wc->usecount--; /* If we're dead, release us now */ if (!wc->usecount && wc->dead) t1xxp_release(wc); return 0; } static void t1xxp_enable_interrupts(struct t1 *wc) { /* Clear interrupts */ outb(0xff, wc->ioaddr + WC_INTSTAT); /* Enable interrupts (we care about all of them) */ outb(0x3c /* 0x3f */, wc->ioaddr + WC_MASK0); /* No external interrupts */ outb(0x00, wc->ioaddr + WC_MASK1); if (debug) printk(KERN_DEBUG "Enabled interrupts!\n"); } static void t1xxp_start_dma(struct t1 *wc) { /* Reset Master and TDM */ outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); if (debug) printk(KERN_DEBUG "Started DMA\n"); outb(0x03, wc->ioaddr + WC_OPER); outb(0x01, wc->ioaddr + WC_OPER); } static void __t1xxp_stop_dma(struct t1 *wc) { outb(0x00, wc->ioaddr + WC_OPER); } static void __t1xxp_disable_interrupts(struct t1 *wc) { outb(0x00, wc->ioaddr + WC_MASK0); outb(0x00, wc->ioaddr + WC_MASK1); } static void __t1xxp_set_clear(struct t1 *wc) { int i,j; unsigned short val=0; for (i=0;i<24;i++) { j = (i/8); if (wc->span.chans[i]->flags & DAHDI_FLAG_CLEAR) val |= 1 << (7 - (i % 8)); if ((i % 8)==7) { if (debug > 1) printk(KERN_DEBUG "Putting %d in register %02x\n", val, 0x2f + j); __t1_framer_out(wc, 0x2f + j, val); val = 0; } } } static int t1xxp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { struct t4_regs regs; int x; struct t1 *wc; switch(cmd) { case WCT4_GET_REGS: wc = chan->pvt; for (x=0;xioaddr + (x << 2))) | (inb(wc->ioaddr + (x << 2) + 1) << 8) | (inb(wc->ioaddr + (x << 2) + 2) << 16) | (inb(wc->ioaddr + (x << 2) + 3) << 24); #else regs.pci[x] = (inb(wc->ioaddr + x)); #endif for (x=0;xspantype == TYPE_E1) { switch(cmd) { case DAHDI_MAINT_NONE: printk(KERN_INFO "XXX Turn off local and remote loops E1 XXX\n"); break; case DAHDI_MAINT_LOCALLOOP: printk(KERN_INFO "XXX Turn on local loopback E1 XXX\n"); break; case DAHDI_MAINT_REMOTELOOP: printk(KERN_INFO "XXX Turn on remote loopback E1 XXX\n"); break; case DAHDI_MAINT_LOOPUP: printk(KERN_INFO "XXX Send loopup code E1 XXX\n"); break; case DAHDI_MAINT_LOOPDOWN: printk(KERN_INFO "XXX Send loopdown code E1 XXX\n"); break; default: printk(KERN_NOTICE "TE110P: Unknown E1 maint command: %d\n", cmd); break; } } else { switch(cmd) { case DAHDI_MAINT_NONE: printk(KERN_INFO "XXX Turn off local and remote loops T1 XXX\n"); t1_framer_out(wc, 0x21, 0x40); break; case DAHDI_MAINT_LOCALLOOP: printk(KERN_INFO "XXX Turn on local loop and no remote loop XXX\n"); break; case DAHDI_MAINT_REMOTELOOP: printk(KERN_INFO "XXX Turn on remote loopup XXX\n"); break; case DAHDI_MAINT_LOOPUP: t1_framer_out(wc, 0x21, 0x50); /* FMR5: Nothing but RBS mode */ break; case DAHDI_MAINT_LOOPDOWN: t1_framer_out(wc, 0x21, 0x60); /* FMR5: Nothing but RBS mode */ break; default: printk(KERN_NOTICE "TE110P: Unknown T1 maint command: %d\n", cmd); break; } } return 0; } static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) { u_char m,c; int n,b; struct t1 *wc = chan->pvt; unsigned long flags; if(debug > 1) printk(KERN_DEBUG "Setting bits to %d on channel %s\n", bits, chan->name); spin_lock_irqsave(&wc->lock, flags); if (wc->spantype == TYPE_E1) { /* do it E1 way */ if (chan->chanpos == 16) { spin_unlock_irqrestore(&wc->lock, flags); return 0; } n = chan->chanpos - 1; if (chan->chanpos > 15) n--; b = (n % 15); c = wc->txsigs[b]; m = (n / 15) << 2; /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ wc->txsigs[b] = c; /* output them to the chip */ __t1_framer_out(wc,0x71 + b,c); } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { n = chan->chanpos - 1; b = (n/4); c = wc->txsigs[b]; m = ((3 - (n % 4)) << 1); /* nibble selector */ c &= ~(0x3 << m); /* keep the other nibble */ c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */ wc->txsigs[b] = c; /* output them to the chip */ __t1_framer_out(wc,0x70 + b,c); __t1_framer_out(wc,0x70 + b + 6,c); } else if (wc->span.lineconfig & DAHDI_CONFIG_ESF) { n = chan->chanpos - 1; b = (n/2); c = wc->txsigs[b]; m = ((n % 2) << 2); /* nibble selector */ c &= (0xf << m); /* keep the other nibble */ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ wc->txsigs[b] = c; /* output them to the chip */ __t1_framer_out(wc,0x70 + b,c); } spin_unlock_irqrestore(&wc->lock, flags); if (debug > 1) printk(KERN_DEBUG "Finished setting RBS bits\n"); return 0; } static void t1_check_sigbits(struct t1 *wc) { int a,i,rxs; unsigned long flags; if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) return; spin_lock_irqsave(&wc->lock, flags); if (wc->spantype == TYPE_E1) { for (i = 0; i < 15; i++) { a = __t1_framer_in(wc, 0x71 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+16]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i+16], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i], rxs); spin_lock_irqsave(&wc->lock, flags); } } } } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { for (i = 0; i < 24; i+=4) { a = __t1_framer_in(wc, 0x70 + (i>>2)); /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(wc->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+3]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i+3], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a & 0xc); if (!(wc->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+2]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i+2], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a >> 2) & 0xc; if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i+1], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a >> 4) & 0xc; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i], rxs); spin_lock_irqsave(&wc->lock, flags); } } } } else { for (i = 0; i < 24; i+=2) { a = __t1_framer_in(wc, 0x70 + (i>>1)); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i+1], rxs); spin_lock_irqsave(&wc->lock, flags); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { spin_unlock_irqrestore(&wc->lock, flags); dahdi_rbsbits(wc->span.chans[i], rxs); spin_lock_irqsave(&wc->lock, flags); } } } } spin_unlock_irqrestore(&wc->lock, flags); } static void t4_serial_setup(struct t1 *wc) { printk(KERN_INFO "TE110P: Setting up global serial parameters for %s %s\n", wc->spantype == TYPE_E1 ? (unchannelized ? "Unchannelized E1" : "E1") : "T1", wc->spanflags & FLAG_FALC12 ? "FALC V1.2" : "FALC V2.2"); t1_framer_out(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */ t1_framer_out(wc, 0x08, 0x05); /* IPC: Interrupt push/pull active low */ if (wc->spanflags & FLAG_FALC12) { t1_framer_out(wc, 0x92, 0x00); t1_framer_out(wc, 0x93, 0x58); t1_framer_out(wc, 0x94, 0xd2); t1_framer_out(wc, 0x95, 0xc2); t1_framer_out(wc, 0x96, 0x03); t1_framer_out(wc, 0x97, 0x10); } else { /* Global clocks (8.192 Mhz CLK) */ t1_framer_out(wc, 0x92, 0x00); t1_framer_out(wc, 0x93, 0x18); t1_framer_out(wc, 0x94, 0xfb); t1_framer_out(wc, 0x95, 0x0b); t1_framer_out(wc, 0x96, 0x00); t1_framer_out(wc, 0x97, 0x0b); t1_framer_out(wc, 0x98, 0xdb); t1_framer_out(wc, 0x99, 0xdf); } /* Configure interrupts */ t1_framer_out(wc, 0x46, 0x40); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */ /* Configure system interface */ t1_framer_out(wc, 0x3e, 0x02); /* SIC1: 4.096 Mhz clock/bus, double buffer receive / transmit, byte interleaved */ t1_framer_out(wc, 0x3f, 0x00); /* SIC2: No FFS, no center receive eliastic buffer, phase 0 */ t1_framer_out(wc, 0x40, 0x04); /* SIC3: Edges for capture */ t1_framer_out(wc, 0x44, 0x30); /* CMR1: RCLK is at 8.192 Mhz dejittered */ t1_framer_out(wc, 0x45, 0x00); /* CMR2: We provide sync and clock for tx and rx. */ t1_framer_out(wc, 0x22, 0x00); /* XC0: Normal operation of Sa-bits */ t1_framer_out(wc, 0x23, 0x04); /* XC1: 0 offset */ t1_framer_out(wc, 0x24, 0x07); /* RC0: Just shy of 255 */ if (wc->spanflags & FLAG_FALC12) t1_framer_out(wc, 0x25, 0x04); /* RC1: The rest of RC0 */ else t1_framer_out(wc, 0x25, 0x05); /* RC1: The rest of RC0 */ /* Configure ports */ t1_framer_out(wc, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */ t1_framer_out(wc, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */ t1_framer_out(wc, 0x82, 0x65); /* PC3: Some unused stuff */ t1_framer_out(wc, 0x83, 0x35); /* PC4: Some more unused stuff */ t1_framer_out(wc, 0x84, 0x31); /* PC5: XMFS active low, SCLKR is input, RCLK is output */ t1_framer_out(wc, 0x86, 0x03); /* PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R */ t1_framer_out(wc, 0x3b, 0x00); /* Clear LCR1 */ printk(KERN_INFO "TE110P: Successfully initialized serial bus for card\n"); } static void __t1_configure_t1(struct t1 *wc, int lineconfig, int txlevel) { unsigned int fmr4, fmr2, fmr1, fmr0, lim2; char *framing, *line; int mytxlevel; if ((txlevel > 7) || (txlevel < 4)) mytxlevel = 0; else mytxlevel = txlevel - 4; fmr1 = 0x1c; /* FMR1: Mode 0, T1 mode, CRC on for ESF, 2.048 Mhz system data rate, no XAIS */ fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */ if (loopback) fmr2 |= 0x4; if (j1mode) fmr4 = 0x1c; else fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */ lim2 = 0x21; /* LIM2: 50% peak is a "1", Advanced Loss recovery */ lim2 |= (mytxlevel << 6); /* LIM2: Add line buildout */ __t1_framer_out(wc, 0x1d, fmr1); __t1_framer_out(wc, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; fmr0 = 0xa0; } else { line = "B8ZS"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_D4) { framing = "D4"; } else { framing = "ESF"; fmr4 |= 0x2; fmr2 |= 0xc0; } __t1_framer_out(wc, 0x1c, fmr0); __t1_framer_out(wc, 0x20, fmr4); __t1_framer_out(wc, 0x21, 0x40); /* FMR5: Enable RBS mode */ __t1_framer_out(wc, 0x37, 0xf8); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ __t1_framer_out(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ __t1_framer_out(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ __t1_framer_out(wc, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */ __t1_framer_out(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ __t1_framer_out(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ if (j1mode) __t1_framer_out(wc, 0x24, 0x80); /* J1 overide */ /* Generate pulse mask for T1 */ switch(mytxlevel) { case 3: __t1_framer_out(wc, 0x26, 0x07); /* XPM0 */ __t1_framer_out(wc, 0x27, 0x01); /* XPM1 */ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */ break; case 2: __t1_framer_out(wc, 0x26, 0x8c); /* XPM0 */ __t1_framer_out(wc, 0x27, 0x11); /* XPM1 */ __t1_framer_out(wc, 0x28, 0x01); /* XPM2 */ break; case 1: __t1_framer_out(wc, 0x26, 0x8c); /* XPM0 */ __t1_framer_out(wc, 0x27, 0x01); /* XPM1 */ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */ break; case 0: default: __t1_framer_out(wc, 0x26, 0xd7); /* XPM0 */ __t1_framer_out(wc, 0x27, 0x22); /* XPM1 */ __t1_framer_out(wc, 0x28, 0x01); /* XPM2 */ break; } printk(KERN_INFO "TE110P: Span configured for %s/%s\n", framing, line); } static void __t1_configure_e1(struct t1 *wc, int lineconfig) { unsigned int fmr2, fmr1, fmr0; unsigned int cas = 0; char *crc4 = ""; char *framing, *line; fmr1 = 0x44; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ fmr2 = 0x03; /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, no payload loopback */ if (unchannelized) fmr2 |= 0x30; if (loopback) fmr2 |= 0x4; if (lineconfig & DAHDI_CONFIG_CRC4) { fmr1 |= 0x08; /* CRC4 transmit */ fmr2 |= 0xc0; /* CRC4 receive */ crc4 = "/CRC4"; } __t1_framer_out(wc, 0x1d, fmr1); __t1_framer_out(wc, 0x1e, fmr2); /* Configure line interface */ if (lineconfig & DAHDI_CONFIG_AMI) { line = "AMI"; fmr0 = 0xa0; } else { line = "HDB3"; fmr0 = 0xf0; } if (lineconfig & DAHDI_CONFIG_CCS) { framing = "CCS"; } else { framing = "CAS"; cas = 0x40; } __t1_framer_out(wc, 0x1c, fmr0); if (unchannelized) __t1_framer_out(wc, 0x1f, 0x40); __t1_framer_out(wc, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */ __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ __t1_framer_out(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */ __t1_framer_out(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */ /* Condition receive line interface for E1 after reset */ __t1_framer_out(wc, 0xbb, 0x17); __t1_framer_out(wc, 0xbc, 0x55); __t1_framer_out(wc, 0xbb, 0x97); __t1_framer_out(wc, 0xbb, 0x11); __t1_framer_out(wc, 0xbc, 0xaa); __t1_framer_out(wc, 0xbb, 0x91); __t1_framer_out(wc, 0xbb, 0x12); __t1_framer_out(wc, 0xbc, 0x55); __t1_framer_out(wc, 0xbb, 0x92); __t1_framer_out(wc, 0xbb, 0x0c); __t1_framer_out(wc, 0xbb, 0x00); __t1_framer_out(wc, 0xbb, 0x8c); __t1_framer_out(wc, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */ __t1_framer_out(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */ __t1_framer_out(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */ __t1_framer_out(wc, 0x20, 0x9f); /* XSW: Spare bits all to 1 */ if (unchannelized) __t1_framer_out(wc, 0x21, 0x3c); else __t1_framer_out(wc, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */ /* Generate pulse mask for E1 */ __t1_framer_out(wc, 0x26, 0x54); /* XPM0 */ __t1_framer_out(wc, 0x27, 0x02); /* XPM1 */ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */ printk(KERN_INFO "TE110P: Span configured for %s/%s%s\n", framing, line, crc4); } static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) { int alreadyrunning = wc->span.flags & DAHDI_FLAG_RUNNING; unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->spantype == TYPE_E1) { /* if this is an E1 card */ __t1_configure_e1(wc, span->lineconfig); } else { /* is a T1 card */ __t1_configure_t1(wc, span->lineconfig, span->txlevel); __t1xxp_set_clear(wc); } if (!alreadyrunning) wc->span.flags |= DAHDI_FLAG_RUNNING; spin_unlock_irqrestore(&wc->lock, flags); } static int t1xxp_startup(struct file *file, struct dahdi_span *span) { struct t1 *wc = t1_from_span(span); int i,alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; /* initialize the start value for the entire chunk of last ec buffer */ for(i = 0; i < span->channels; i++) { memset(wc->ec_chunk1[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); memset(wc->ec_chunk2[i], DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE); } /* Reset framer with proper parameters and start */ t1xxp_framer_start(wc, span); printk(KERN_INFO "Calling startup (flags is %lu)\n", span->flags); if (!alreadyrunning) { /* Only if we're not already going */ t1xxp_enable_interrupts(wc); t1xxp_start_dma(wc); span->flags |= DAHDI_FLAG_RUNNING; } return 0; } static int t1xxp_shutdown(struct dahdi_span *span) { struct t1 *wc = t1_from_span(span); unsigned long flags; spin_lock_irqsave(&wc->lock, flags); __t1xxp_stop_dma(wc); __t1xxp_disable_interrupts(wc); span->flags &= ~DAHDI_FLAG_RUNNING; spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { struct t1 *wc = chan->pvt; unsigned long flags; int alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING; spin_lock_irqsave(&wc->lock, flags); if (alreadyrunning && (wc->spantype != TYPE_E1)) __t1xxp_set_clear(wc); spin_unlock_irqrestore(&wc->lock, flags); return 0; } static int t1xxp_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) { struct t1 *wc = t1_from_span(span); /* Do we want to SYNC on receive or not */ wc->sync = (lc->sync) ? 1 : 0; /* If already running, apply changes immediately */ if (span->flags & DAHDI_FLAG_RUNNING) return t1xxp_startup(file, span); return 0; } static const struct dahdi_span_ops t1xxp_span_ops = { .owner = THIS_MODULE, .startup = t1xxp_startup, .shutdown = t1xxp_shutdown, .rbsbits = t1xxp_rbsbits, .maint = t1xxp_maint, .open = t1xxp_open, .close = t1xxp_close, .spanconfig = t1xxp_spanconfig, .chanconfig = t1xxp_chanconfig, .ioctl = t1xxp_ioctl, }; static int t1xxp_software_init(struct t1 *wc) { int x; /* Find position */ for (x=0;x= WC_MAX_CARDS) return -1; t4_serial_setup(wc); wc->num = x; sprintf(wc->span.name, "WCT1/%d", wc->num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); wc->span.manufacturer = "Digium"; strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); wc->span.irq = wc->dev->irq; if (wc->spantype == TYPE_E1) { if (unchannelized) wc->span.channels = 32; else wc->span.channels = 31; wc->span.deflaw = DAHDI_LAW_ALAW; wc->span.spantype = "E1"; wc->span.linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; } else { wc->span.channels = 24; wc->span.deflaw = DAHDI_LAW_MULAW; wc->span.spantype = "T1"; wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; } wc->span.chans = wc->chans; wc->span.flags = DAHDI_FLAG_RBS; for (x=0;xspan.channels;x++) { sprintf(wc->chans[x]->name, "WCT1/%d/%d", wc->num, x + 1); wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_MTP2 | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF; wc->chans[x]->pvt = wc; wc->chans[x]->chanpos = x + 1; } wc->span.ops = &t1xxp_span_ops; if (dahdi_register(&wc->span, 0)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } return 0; } static inline void __handle_leds(struct t1 *wc) { int oldreg; if (wc->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) { /* Red/Blue alarm */ wc->blinktimer++; #ifdef FANCY_ALARM if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) { wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } if (wc->blinktimer >= 0xf) { wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); wc->blinktimer = -1; wc->alarmpos++; if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0]))) wc->alarmpos = 0; } #else if (wc->blinktimer == 160) { wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } else if (wc->blinktimer == 480) { wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); wc->blinktimer = 0; } #endif } else if (wc->span.alarms & DAHDI_ALARM_YELLOW) { /* Yellow Alarm */ if (!(wc->blinktimer % 2)) wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0; else wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } else { /* No Alarm */ oldreg = wc->ledtestreg; if (wc->span.maintstat != DAHDI_MAINT_NONE) wc->ledtestreg |= BIT_TEST; else wc->ledtestreg &= ~BIT_TEST; if (wc->span.flags & DAHDI_FLAG_RUNNING) wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1; else wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1); if (oldreg != wc->ledtestreg) __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg); } } static void t1xxp_transmitprep(struct t1 *wc, int ints) { volatile unsigned char *txbuf; int x,y; int pos; if (ints & 0x04 /* 0x01 */) { /* We just finished sending the first buffer, start filling it now */ txbuf = wc->writechunk; } else { /* Just finished sending second buffer, fill it now */ txbuf = wc->writechunk + 32 * DAHDI_CHUNKSIZE; } dahdi_transmit(&wc->span); for (x=0;xoffset;x++) txbuf[x] = wc->tempo[x]; for (y=0;yspan.channels;x++) { pos = y * 32 + wc->chanmap[x] + wc->offset; /* Put channel number as outgoing data */ if (pos < 32 * DAHDI_CHUNKSIZE) txbuf[pos] = wc->chans[x]->writechunk[y]; else wc->tempo[pos - 32 * DAHDI_CHUNKSIZE] = wc->chans[x]->writechunk[y]; } } } static void t1xxp_receiveprep(struct t1 *wc, int ints) { volatile unsigned char *rxbuf; volatile unsigned int *canary; int x; int y; unsigned int oldcan; if (ints & 0x04) { /* Just received first buffer */ rxbuf = wc->readchunk; canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 64 - 4); } else { rxbuf = wc->readchunk + DAHDI_CHUNKSIZE * 32; canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 32 - 4); } oldcan = *canary; if (((oldcan & 0xffff0000) >> 16) != CANARY) { /* Check top part */ if (debug) printk(KERN_DEBUG "Expecting top %04x, got %04x\n", CANARY, (oldcan & 0xffff0000) >> 16); wc->span.irqmisses++; } else if ((oldcan & 0xffff) != ((wc->canary - 1) & 0xffff)) { if (debug) printk(KERN_DEBUG "Expecting bottom %d, got %d\n", wc->canary - 1, oldcan & 0xffff); wc->span.irqmisses++; } for (y=0;yspan.channels;x++) { /* XXX Optimize, remove * and + XXX */ /* Must map received channels into appropriate data */ wc->chans[x]->readchunk[y] = rxbuf[32 * y + ((wc->chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)]; } if (wc->spantype != TYPE_E1) { for (x=3;x<32;x+=4) { if (rxbuf[32 * y + ((x + WC_OFFSET) & 0x1f)] == 0x7f) { if (wc->offset != (x-3)) { /* Resync */ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100; #if 1 if (debug) printk(KERN_DEBUG "T1: Lost our place, resyncing\n"); #endif } } } } else if (!unchannelized) { if (!wc->clocktimeout && !wc->span.alarms) { if ((rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)] & 0x7f) != 0x1b) { if (wc->miss) { if (debug) printk(KERN_DEBUG "Double miss (%d, %d)...\n", wc->misslast, rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]); control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100; } else { wc->miss = 1; wc->misslast = rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]; } } else { wc->miss = 0; } } else { wc->miss = 0; } } } /* Store the next canary */ canary = (unsigned int *)(rxbuf + DAHDI_CHUNKSIZE * 32 - 4); *canary = (wc->canary++) | (CANARY << 16); for (x=0;xspan.channels;x++) { dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->ec_chunk2[x]); memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],DAHDI_CHUNKSIZE); memcpy(wc->ec_chunk1[x],wc->chans[x]->writechunk,DAHDI_CHUNKSIZE); } dahdi_receive(&wc->span); } static void t1_check_alarms(struct t1 *wc) { unsigned char c,d; int alarms; int x,j; unsigned long flags; if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) return; spin_lock_irqsave(&wc->lock, flags); c = __t1_framer_in(wc, 0x4c); if (wc->spanflags & FLAG_FALC12) d = __t1_framer_in(wc, 0x4f); else d = __t1_framer_in(wc, 0x4d); /* Assume no alarms */ alarms = 0; /* And consider only carrier alarms */ wc->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); if (wc->spantype == TYPE_E1) { if (c & 0x04) { /* No multiframe found, force RAI high after 400ms only if we haven't found a multiframe since last loss of frame */ if (!(wc->spanflags & FLAG_NMF)) { __t1_framer_out(wc, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ wc->spanflags |= FLAG_NMF; printk(KERN_DEBUG "NMF workaround on!\n"); } __t1_framer_out(wc, 0x1e, 0xc3); /* Reset to CRC4 mode */ __t1_framer_out(wc, 0x1c, 0xf2); /* Force Resync */ __t1_framer_out(wc, 0x1c, 0xf0); /* Force Resync */ } else if (!(c & 0x02)) { if ((wc->spanflags & FLAG_NMF)) { __t1_framer_out(wc, 0x20, 0x9f); /* LIM0: Clear forced RAI */ wc->spanflags &= ~FLAG_NMF; printk(KERN_DEBUG "NMF workaround off!\n"); } } } else { /* Detect loopup code if we're not sending one */ if ((!wc->span.mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ __t1_framer_out(wc, 0x37, 0xf6 ); /* LIM1: Enable remote loop */ wc->span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else wc->loopupcnt = 0; /* Same for loopdown code */ if ((!wc->span.mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */ __t1_framer_out(wc, 0x37, 0xf0 ); /* LIM1: Disable remote loop */ wc->span.maintstat = DAHDI_MAINT_NONE; } } else wc->loopdowncnt = 0; } if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { for (x=0,j=0;x < wc->span.channels;x++) if ((wc->span.chans[x]->flags & DAHDI_FLAG_OPEN) || dahdi_have_netdev(wc->span.chans[x])) j++; if (!j) alarms |= DAHDI_ALARM_NOTOPEN; } if (c & 0xa0) { if (wc->alarmcount >= alarmdebounce) { if (!unchannelized) alarms |= DAHDI_ALARM_RED; } else wc->alarmcount++; } else wc->alarmcount = 0; if (c & 0x4) alarms |= DAHDI_ALARM_BLUE; if (((!wc->span.alarms) && alarms) || (wc->span.alarms && (!alarms))) wc->checktiming = 1; /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) wc->alarmtimer = DAHDI_ALARMSETTLE_TIME; if (wc->alarmtimer) alarms |= DAHDI_ALARM_RECOVER; /* If receiving alarms, go into Yellow alarm state */ if (alarms && !(wc->spanflags & FLAG_SENDINGYELLOW)) { unsigned char fmr4; #if 1 printk(KERN_INFO "wcte1xxp: Setting yellow alarm\n"); #endif /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ fmr4 = __t1_framer_in(wc, 0x20); __t1_framer_out(wc, 0x20, fmr4 | 0x20); wc->spanflags |= FLAG_SENDINGYELLOW; } else if ((!alarms) && (wc->spanflags & FLAG_SENDINGYELLOW)) { unsigned char fmr4; #if 1 printk(KERN_INFO "wcte1xxp: Clearing yellow alarm\n"); #endif /* We manually do yellow alarm to handle RECOVER */ fmr4 = __t1_framer_in(wc, 0x20); __t1_framer_out(wc, 0x20, fmr4 & ~0x20); wc->spanflags &= ~FLAG_SENDINGYELLOW; } /* Re-check the timing source when we enter/leave alarm, not withstanding yellow alarm */ if ((c & 0x10) && !unchannelized) alarms |= DAHDI_ALARM_YELLOW; if (wc->span.mainttimer || wc->span.maintstat) alarms |= DAHDI_ALARM_LOOPBACK; wc->span.alarms = alarms; spin_unlock_irqrestore(&wc->lock, flags); dahdi_alarm_notify(&wc->span); } static void t1_do_counters(struct t1 *wc) { unsigned long flags; spin_lock_irqsave(&wc->lock, flags); if (wc->alarmtimer) { if (!--wc->alarmtimer) { wc->span.alarms &= ~(DAHDI_ALARM_RECOVER); spin_unlock_irqrestore(&wc->lock, flags); dahdi_alarm_notify(&wc->span); spin_lock_irqsave(&wc->lock, flags); } } spin_unlock_irqrestore(&wc->lock, flags); } DAHDI_IRQ_HANDLER(t1xxp_interrupt) { struct t1 *wc = dev_id; unsigned char ints; unsigned long flags; int x; ints = inb(wc->ioaddr + WC_INTSTAT); if (!ints) return IRQ_NONE; outb(ints, wc->ioaddr + WC_INTSTAT); if (!wc->intcount) { if (debug) printk(KERN_DEBUG "Got interrupt: 0x%04x\n", ints); } wc->intcount++; if (wc->clocktimeout && !--wc->clocktimeout) control_set_reg(wc, WC_CLOCK, 0x04 | wc->sync | clockextra); if (ints & 0x0f) { t1xxp_receiveprep(wc, ints); t1xxp_transmitprep(wc, ints); } spin_lock_irqsave(&wc->lock, flags); #if 1 __handle_leds(wc); #endif spin_unlock_irqrestore(&wc->lock, flags); /* Count down timers */ t1_do_counters(wc); /* Do some things that we don't have to do very often */ x = wc->intcount & 15 /* 63 */; switch(x) { case 0: case 1: break; case 2: t1_check_sigbits(wc); break; case 4: /* Check alarms 1/4 as frequently */ if (!(wc->intcount & 0x30)) t1_check_alarms(wc); break; } if (ints & 0x10) printk(KERN_NOTICE "PCI Master abort\n"); if (ints & 0x20) printk(KERN_NOTICE "PCI Target abort\n"); return IRQ_RETVAL(1); } static int t1xxp_hardware_init(struct t1 *wc) { unsigned int falcver; unsigned int x; /* Hardware PCI stuff */ /* Reset chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Set all outputs to 0 */ outb(0x00, wc->ioaddr + WC_AUXD); /* Set all to outputs except AUX1 (TDO). */ outb(0xfd, wc->ioaddr + WC_AUXC); /* Configure the serial port: double clock, 20ns width, no inversion, MSB first */ outb(0xc8, wc->ioaddr + WC_SERC); /* Internally delay FSC by one */ outb(0x01, wc->ioaddr + WC_FSCDELAY); /* Back to normal, with automatic DMA wrap around */ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL); /* Make sure serial port and DMA are out of reset */ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL); /* Setup DMA Addresses */ /* Start at writedma */ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ /* First frame */ outl(wc->writedma + DAHDI_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ /* Second frame */ outl(wc->writedma + DAHDI_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE); /* End */ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ /* First frame */ outl(wc->readdma + DAHDI_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ /* Second frame */ outl(wc->readdma + DAHDI_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */ if (debug) printk(KERN_DEBUG "Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma); if (t1e1override > -1) { if (t1e1override) wc->spantype = TYPE_E1; else wc->spantype = TYPE_T1; } else { if (control_get_reg(wc, WC_CLOCK) & 0x20) wc->spantype = TYPE_T1; else wc->spantype = TYPE_E1; } /* Check out the controller */ if (debug) printk(KERN_DEBUG "Controller version: %02x\n", control_get_reg(wc, WC_VERSION)); control_set_reg(wc, WC_LEDTEST, 0x00); if (wc->spantype == TYPE_E1) { if (unchannelized) wc->chanmap = chanmap_e1uc; else wc->chanmap = chanmap_e1; } else wc->chanmap = chanmap_t1; /* Setup clock appropriately */ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra); wc->clocktimeout = 100; /* Perform register test on FALC */ for (x=0;x<256;x++) { t1_framer_out(wc, 0x14, x); if ((falcver = t1_framer_in(wc, 0x14)) != x) printk(KERN_DEBUG "Wrote '%x' but read '%x'\n", x, falcver); } t1_framer_out(wc, 0x4a, 0xaa); falcver = t1_framer_in(wc ,0x4a); printk(KERN_INFO "FALC version: %08x\n", falcver); if (!falcver) wc->spanflags |= FLAG_FALC12; start_alarm(wc); return 0; } static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct t1 *wc; unsigned int *canary; unsigned int x; if (pci_enable_device(pdev)) { return -EIO; } if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { return -ENOMEM; } memset(wc, 0x0, sizeof(*wc)); spin_lock_init(&wc->lock); wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->offset = 28; /* And you thought 42 was the answer */ wc->writechunk = /* 32 channels, Double-buffer, Read/Write */ (unsigned char *)pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma); if (!wc->writechunk) { printk(KERN_NOTICE "wcte11xp: Unable to allocate DMA-able memory\n"); return -ENOMEM; } /* Read is after the whole write piece (in bytes) */ wc->readchunk = wc->writechunk + DAHDI_CHUNKSIZE * 32 * 2; /* Same thing... */ wc->readdma = wc->writedma + DAHDI_CHUNKSIZE * 32 * 2; /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0x00,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32); /* Initialize canary */ canary = (unsigned int *)(wc->readchunk + DAHDI_CHUNKSIZE * 64 - 4); *canary = (CANARY << 16) | (0xffff); /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, t1xxp_interrupt, DAHDI_IRQ_SHARED_DISABLED, "wcte11xp", wc)) { printk(KERN_NOTICE "wcte11xp: Unable to request IRQ %d\n", pdev->irq); kfree(wc); return -EIO; } /* Initialize hardware */ t1xxp_hardware_init(wc); /* We now know which version of card we have */ wc->variety = "Digium Wildcard TE110P T1/E1"; for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { if (!(wc->chans[x] = kmalloc(sizeof(*wc->chans[x]), GFP_KERNEL))) { while (x) { kfree(wc->chans[--x]); } kfree(wc); return -ENOMEM; } memset(wc->chans[x], 0, sizeof(*wc->chans[x])); } /* Misc. software stuff */ t1xxp_software_init(wc); printk(KERN_INFO "Found a Wildcard: %s\n", wc->variety); return 0; } static void t1xxp_stop_stuff(struct t1 *wc) { /* Kill clock */ control_set_reg(wc, WC_CLOCK, 0); /* Turn off LED's */ control_set_reg(wc, WC_LEDTEST, 0); } static void __devexit t1xxp_remove_one(struct pci_dev *pdev) { struct t1 *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ __t1xxp_stop_dma(wc); /* In case hardware is still there */ __t1xxp_disable_interrupts(wc); t1xxp_stop_stuff(wc); /* Immediately free resources */ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL); /* Release span, possibly delayed */ if (!wc->usecount) t1xxp_release(wc); else wc->dead = 1; } } static DEFINE_PCI_DEVICE_TABLE(t1xxp_pci_tbl) = { { 0xe159, 0x0001, 0x71fe, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" }, { 0xe159, 0x0001, 0x79fe, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" }, { 0xe159, 0x0001, 0x795e, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" }, { 0xe159, 0x0001, 0x79de, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" }, { 0xe159, 0x0001, 0x797e, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" }, { 0 } }; MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl); static struct pci_driver t1xxp_driver = { .name = "wcte11xp", .probe = t1xxp_init_one, .remove = __devexit_p(t1xxp_remove_one), .suspend = NULL, .resume = NULL, .id_table = t1xxp_pci_tbl, }; static int __init t1xxp_init(void) { int res; res = dahdi_pci_module(&t1xxp_driver); if (res) return -ENODEV; return 0; } static void __exit t1xxp_cleanup(void) { pci_unregister_driver(&t1xxp_driver); } module_param(alarmdebounce, int, 0600); module_param(loopback, int, 0600); module_param(t1e1override, int, 0600); module_param(unchannelized, int, 0600); module_param(clockextra, int, 0600); module_param(debug, int, 0600); module_param(j1mode, int, 0600); MODULE_DESCRIPTION("Wildcard TE110P Driver"); MODULE_AUTHOR("Mark Spencer "); MODULE_LICENSE("GPL v2"); module_init(t1xxp_init); module_exit(t1xxp_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/wctdm.c0000644000175000017500000024235511623564573020047 0ustar tzafrirtzafrir/* * Wildcard TDM400P TDM FXS/FXO Interface Driver for DAHDI Telephony interface * * Written by Mark Spencer * Matthew Fredrickson * * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include "proslic.h" /* * Define for audio vs. register based ring detection * */ /* #define AUDIO_RINGCHECK */ /* Experimental max loop current limit for the proslic Loop current limit is from 20 mA to 41 mA in steps of 3 (according to datasheet) So set the value below to: 0x00 : 20mA (default) 0x01 : 23mA 0x02 : 26mA 0x03 : 29mA 0x04 : 32mA 0x05 : 35mA 0x06 : 37mA 0x07 : 41mA */ static int loopcurrent = 20; #define POLARITY_XOR (\ (reversepolarity != 0) ^ (fxs->reversepolarity != 0) ^\ (fxs->vmwi_lrev != 0) ^\ ((fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) != 0)) static int reversepolarity = 0; static alpha indirect_regs[] = { {0,255,"DTMF_ROW_0_PEAK",0x55C2}, {1,255,"DTMF_ROW_1_PEAK",0x51E6}, {2,255,"DTMF_ROW2_PEAK",0x4B85}, {3,255,"DTMF_ROW3_PEAK",0x4937}, {4,255,"DTMF_COL1_PEAK",0x3333}, {5,255,"DTMF_FWD_TWIST",0x0202}, {6,255,"DTMF_RVS_TWIST",0x0202}, {7,255,"DTMF_ROW_RATIO_TRES",0x0198}, {8,255,"DTMF_COL_RATIO_TRES",0x0198}, {9,255,"DTMF_ROW_2ND_ARM",0x0611}, {10,255,"DTMF_COL_2ND_ARM",0x0202}, {11,255,"DTMF_PWR_MIN_TRES",0x00E5}, {12,255,"DTMF_OT_LIM_TRES",0x0A1C}, {13,0,"OSC1_COEF",0x7B30}, {14,1,"OSC1X",0x0063}, {15,2,"OSC1Y",0x0000}, {16,3,"OSC2_COEF",0x7870}, {17,4,"OSC2X",0x007D}, {18,5,"OSC2Y",0x0000}, {19,6,"RING_V_OFF",0x0000}, {20,7,"RING_OSC",0x7EF0}, {21,8,"RING_X",0x0160}, {22,9,"RING_Y",0x0000}, {23,255,"PULSE_ENVEL",0x2000}, {24,255,"PULSE_X",0x2000}, {25,255,"PULSE_Y",0x0000}, //{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower {26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower {27,14,"XMIT_DIGITAL_GAIN",0x4000}, //{27,14,"XMIT_DIGITAL_GAIN",0x2000}, {28,15,"LOOP_CLOSE_TRES",0x1000}, {29,16,"RING_TRIP_TRES",0x3600}, {30,17,"COMMON_MIN_TRES",0x1000}, {31,18,"COMMON_MAX_TRES",0x0200}, {32,19,"PWR_ALARM_Q1Q2",0x07C0}, {33,20,"PWR_ALARM_Q3Q4",0x2600}, {34,21,"PWR_ALARM_Q5Q6",0x1B80}, {35,22,"LOOP_CLOSURE_FILTER",0x8000}, {36,23,"RING_TRIP_FILTER",0x0320}, {37,24,"TERM_LP_POLE_Q1Q2",0x008C}, {38,25,"TERM_LP_POLE_Q3Q4",0x0100}, {39,26,"TERM_LP_POLE_Q5Q6",0x0010}, {40,27,"CM_BIAS_RINGING",0x0C00}, {41,64,"DCDC_MIN_V",0x0C00}, {42,255,"DCDC_XTRA",0x1000}, {43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, }; #include #include #include "fxo_modes.h" #define NUM_FXO_REGS 60 #define WC_MAX_IFACES 128 #define WC_CNTL 0x00 #define WC_OPER 0x01 #define WC_AUXC 0x02 #define WC_AUXD 0x03 #define WC_MASK0 0x04 #define WC_MASK1 0x05 #define WC_INTSTAT 0x06 #define WC_AUXR 0x07 #define WC_DMAWS 0x08 #define WC_DMAWI 0x0c #define WC_DMAWE 0x10 #define WC_DMARS 0x18 #define WC_DMARI 0x1c #define WC_DMARE 0x20 #define WC_AUXFUNC 0x2b #define WC_SERCTL 0x2d #define WC_FSCDELAY 0x2f #define WC_REGBASE 0xc0 #define WC_SYNC 0x0 #define WC_TEST 0x1 #define WC_CS 0x2 #define WC_VER 0x3 #define BIT_CS (1 << 2) #define BIT_SCLK (1 << 3) #define BIT_SDI (1 << 4) #define BIT_SDO (1 << 5) #define FLAG_EMPTY 0 #define FLAG_WRITE 1 #define FLAG_READ 2 #define DEFAULT_RING_DEBOUNCE 64 /* Ringer Debounce (64 ms) */ #define POLARITY_DEBOUNCE 64 /* Polarity debounce (64 ms) */ #define OHT_TIMER 6000 /* How long after RING to retain OHT */ /* NEON MWI pulse width - Make larger for longer period time * For more information on NEON MWI generation using the proslic * refer to Silicon Labs App Note "AN33-SI321X NEON FLASHING" * RNGY = RNGY 1/2 * Period * 8000 */ #define NEON_MWI_RNGY_PULSEWIDTH 0x3e8 /*=> period of 250 mS */ #define FLAG_3215 (1 << 0) #define NUM_CARDS 4 #define MAX_ALARMS 10 #define MOD_TYPE_FXS 0 #define MOD_TYPE_FXO 1 #define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ #define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ #define PEGCOUNT 5 /* 5 cycles of pegging means RING */ #define NUM_CAL_REGS 12 struct calregs { unsigned char vals[NUM_CAL_REGS]; }; enum proslic_power_warn { PROSLIC_POWER_UNKNOWN = 0, PROSLIC_POWER_ON, PROSLIC_POWER_WARNED, }; enum battery_state { BATTERY_UNKNOWN = 0, BATTERY_PRESENT, BATTERY_LOST, }; struct wctdm { struct pci_dev *dev; char *variety; struct dahdi_span span; unsigned char ios; int usecount; unsigned int intcount; int dead; int pos; int flags[NUM_CARDS]; int freeregion; int alt; int curcard; int cardflag; /* Bit-map of present cards */ enum proslic_power_warn proslic_power; spinlock_t lock; union { struct fxo { #ifdef AUDIO_RINGCHECK unsigned int pegtimer; int pegcount; int peg; int ring; #else int wasringing; int lastrdtx; #endif int ringdebounce; int offhook; unsigned int battdebounce; unsigned int battalarm; enum battery_state battery; int lastpol; int polarity; int polaritydebounce; } fxo; struct fxs { int oldrxhook; int debouncehook; int lastrxhook; int debounce; int ohttimer; int idletxhookstate; /* IDLE changing hook state */ int lasttxhook; int palarms; int reversepolarity; /* Reverse Line */ int mwisendtype; struct dahdi_vmwi_info vmwisetting; int vmwi_active_messages; u32 vmwi_lrev:1; /*MWI Line Reversal*/ u32 vmwi_hvdc:1; /*MWI High Voltage DC Idle line*/ u32 vmwi_hvac:1; /*MWI Neon High Voltage AC Idle line*/ u32 neonringing:1; /*Ring Generator is set for NEON*/ struct calregs calregs; } fxs; } mod[NUM_CARDS]; /* Receive hook state and debouncing */ int modtype[NUM_CARDS]; unsigned char reg0shadow[NUM_CARDS]; unsigned char reg1shadow[NUM_CARDS]; unsigned long ioaddr; dma_addr_t readdma; dma_addr_t writedma; volatile unsigned int *writechunk; /* Double-word aligned write memory */ volatile unsigned int *readchunk; /* Double-word aligned read memory */ struct dahdi_chan _chans[NUM_CARDS]; struct dahdi_chan *chans[NUM_CARDS]; }; struct wctdm_desc { char *name; int flags; }; static struct wctdm_desc wctdm = { "Wildcard S400P Prototype", 0 }; static struct wctdm_desc wctdme = { "Wildcard TDM400P REV E/F", 0 }; static struct wctdm_desc wctdmh = { "Wildcard TDM400P REV H", 0 }; static struct wctdm_desc wctdmi = { "Wildcard TDM400P REV I", 0 }; static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; static struct wctdm *ifaces[WC_MAX_IFACES]; static void wctdm_release(struct wctdm *wc); static unsigned int fxovoltage; static unsigned int battdebounce; static unsigned int battalarm; static unsigned int battthresh; static int ringdebounce = DEFAULT_RING_DEBOUNCE; /* times 4, because must be a multiple of 4ms: */ static int dialdebounce = 8 * 8; static int fwringdetect = 0; static int debug = 0; static int robust = 0; static int timingonly = 0; static int lowpower = 0; static int boostringer = 0; static int fastringer = 0; static int _opermode = 0; static char *opermode = "FCC"; static int fxshonormode = 0; static int alawoverride = 0; static int fastpickup = 0; static int fxotxgain = 0; static int fxorxgain = 0; static int fxstxgain = 0; static int fxsrxgain = 0; static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane); static int wctdm_init_ring_generator_mode(struct wctdm *wc, int card); static int wctdm_set_ring_generator_mode(struct wctdm *wc, int card, int mode); static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char ints) { volatile unsigned int *writechunk; int x; if (ints & 0x01) /* Write is at interrupt address. Start writing from normal offset */ writechunk = wc->writechunk; else writechunk = wc->writechunk + DAHDI_CHUNKSIZE; /* Calculate Transmission */ dahdi_transmit(&wc->span); for (x=0;xcardflag & (1 << 3)) writechunk[x] |= (wc->chans[3]->writechunk[x]); if (wc->cardflag & (1 << 2)) writechunk[x] |= (wc->chans[2]->writechunk[x] << 8); if (wc->cardflag & (1 << 1)) writechunk[x] |= (wc->chans[1]->writechunk[x] << 16); if (wc->cardflag & (1 << 0)) writechunk[x] |= (wc->chans[0]->writechunk[x] << 24); #else if (wc->cardflag & (1 << 3)) writechunk[x] |= (wc->chans[3]->writechunk[x] << 24); if (wc->cardflag & (1 << 2)) writechunk[x] |= (wc->chans[2]->writechunk[x] << 16); if (wc->cardflag & (1 << 1)) writechunk[x] |= (wc->chans[1]->writechunk[x] << 8); if (wc->cardflag & (1 << 0)) writechunk[x] |= (wc->chans[0]->writechunk[x]); #endif } } #ifdef AUDIO_RINGCHECK static inline void ring_check(struct wctdm *wc, int card) { int x; short sample; if (wc->modtype[card] != MOD_TYPE_FXO) return; wc->mod[card].fxo.pegtimer += DAHDI_CHUNKSIZE; for (x=0;xchans[card].readchunk[x], (&(wc->chans[card]))); if ((sample > 10000) && (wc->mod[card].fxo.peg != 1)) { if (debug > 1) printk(KERN_DEBUG "High peg!\n"); if ((wc->mod[card].fxo.pegtimer < PEGTIME) && (wc->mod[card].fxo.pegtimer > MINPEGTIME)) wc->mod[card].fxo.pegcount++; wc->mod[card].fxo.pegtimer = 0; wc->mod[card].fxo.peg = 1; } else if ((sample < -10000) && (wc->mod[card].fxo.peg != -1)) { if (debug > 1) printk(KERN_DEBUG "Low peg!\n"); if ((wc->mod[card].fxo.pegtimer < (PEGTIME >> 2)) && (wc->mod[card].fxo.pegtimer > (MINPEGTIME >> 2))) wc->mod[card].fxo.pegcount++; wc->mod[card].fxo.pegtimer = 0; wc->mod[card].fxo.peg = -1; } } if (wc->mod[card].fxo.pegtimer > PEGTIME) { /* Reset pegcount if our timer expires */ wc->mod[card].fxo.pegcount = 0; } /* Decrement debouncer if appropriate */ if (wc->mod[card].fxo.ringdebounce) wc->mod[card].fxo.ringdebounce--; if (!wc->mod[card].fxo.offhook && !wc->mod[card].fxo.ringdebounce) { if (!wc->mod[card].fxo.ring && (wc->mod[card].fxo.pegcount > PEGCOUNT)) { /* It's ringing */ if (debug) printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1); if (!wc->mod[card].fxo.offhook) dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); wc->mod[card].fxo.ring = 1; } if (wc->mod[card].fxo.ring && !wc->mod[card].fxo.pegcount) { /* No more ring */ if (debug) printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1); dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); wc->mod[card].fxo.ring = 0; } } } #endif static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char ints) { volatile unsigned int *readchunk; int x; if (ints & 0x08) readchunk = wc->readchunk + DAHDI_CHUNKSIZE; else /* Read is at interrupt address. Valid data is available at normal offset */ readchunk = wc->readchunk; for (x=0;xcardflag & (1 << 3)) wc->chans[3]->readchunk[x] = (readchunk[x]) & 0xff; if (wc->cardflag & (1 << 2)) wc->chans[2]->readchunk[x] = (readchunk[x] >> 8) & 0xff; if (wc->cardflag & (1 << 1)) wc->chans[1]->readchunk[x] = (readchunk[x] >> 16) & 0xff; if (wc->cardflag & (1 << 0)) wc->chans[0]->readchunk[x] = (readchunk[x] >> 24) & 0xff; #else if (wc->cardflag & (1 << 3)) wc->chans[3]->readchunk[x] = (readchunk[x] >> 24) & 0xff; if (wc->cardflag & (1 << 2)) wc->chans[2]->readchunk[x] = (readchunk[x] >> 16) & 0xff; if (wc->cardflag & (1 << 1)) wc->chans[1]->readchunk[x] = (readchunk[x] >> 8) & 0xff; if (wc->cardflag & (1 << 0)) wc->chans[0]->readchunk[x] = (readchunk[x]) & 0xff; #endif } #ifdef AUDIO_RINGCHECK for (x=0;xcards;x++) ring_check(wc, x); #endif /* XXX We're wasting 8 taps. We should get closer :( */ for (x = 0; x < NUM_CARDS; x++) { if (wc->cardflag & (1 << x)) dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk); } dahdi_receive(&wc->span); } static void wctdm_stop_dma(struct wctdm *wc); static void wctdm_reset_tdm(struct wctdm *wc); static void wctdm_restart_dma(struct wctdm *wc); static inline void __write_8bits(struct wctdm *wc, unsigned char bits) { /* Out BIT_CS --\________________________________/---- */ /* Out BIT_SCLK ---\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/------ */ /* Out BIT_SDI ---\___/---\___/---\___/---\___/-------- */ /* Data Bit 7 6 5 4 3 2 1 0 */ /* Data written 0 1 0 1 0 1 0 1 */ int x; /* Drop chip select */ wc->ios &= ~BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); for (x=0;x<8;x++) { /* Send out each bit, MSB first, drop SCLK as we do so */ if (bits & 0x80) wc->ios |= BIT_SDI; else wc->ios &= ~BIT_SDI; wc->ios &= ~BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Now raise SCLK high again and repeat */ wc->ios |= BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); bits <<= 1; } /* Finally raise CS back high again */ wc->ios |= BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); } static inline void __reset_spi(struct wctdm *wc) { /* Drop chip select and clock once and raise and clock once */ wc->ios |= BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); wc->ios &= ~BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); wc->ios |= BIT_SDI; wc->ios &= ~BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Now raise SCLK high again and repeat */ wc->ios |= BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Finally raise CS back high again */ wc->ios |= BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Clock again */ wc->ios &= ~BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Now raise SCLK high again and repeat */ wc->ios |= BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); } static inline unsigned char __read_8bits(struct wctdm *wc) { /* Out BIT_CS --\________________________________________/----*/ /* Out BIT_SCLK ---\_/--\_/--\_/--\_/--\_/--\_/--\_/--\_/-------*/ /* In BIT_SDO ????/1111\0000/1111\0000/1111\0000/1111\0000/???*/ /* Data bit 7 6 5 4 3 2 1 0 */ /* Data Read 1 0 1 0 1 0 1 0 */ /* Note: Clock High time is 2x Low time, due to input read */ unsigned char res=0, c; int x; /* Drop chip select */ wc->ios &= ~BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); for (x=0;x<8;x++) { res <<= 1; /* Drop SCLK */ wc->ios &= ~BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Now raise SCLK high again */ wc->ios |= BIT_SCLK; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Read back the value */ c = inb(wc->ioaddr + WC_AUXR); if (c & BIT_SDO) res |= 1; } /* Finally raise CS back high again */ wc->ios |= BIT_CS; outb(wc->ios, wc->ioaddr + WC_AUXD); /* And return our result */ return res; } static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val) { outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); } static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg) { return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); } static inline void __wctdm_setcard(struct wctdm *wc, int card) { if (wc->curcard != card) { __wctdm_setcreg(wc, WC_CS, (1 << card)); wc->curcard = card; } } static void __wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value) { __wctdm_setcard(wc, card); if (wc->modtype[card] == MOD_TYPE_FXO) { __write_8bits(wc, 0x20); __write_8bits(wc, reg & 0x7f); } else { __write_8bits(wc, reg & 0x7f); } __write_8bits(wc, value); } static void wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value) { unsigned long flags; spin_lock_irqsave(&wc->lock, flags); __wctdm_setreg(wc, card, reg, value); spin_unlock_irqrestore(&wc->lock, flags); } static unsigned char __wctdm_getreg(struct wctdm *wc, int card, unsigned char reg) { __wctdm_setcard(wc, card); if (wc->modtype[card] == MOD_TYPE_FXO) { __write_8bits(wc, 0x60); __write_8bits(wc, reg & 0x7f); } else { __write_8bits(wc, reg | 0x80); } return __read_8bits(wc); } static inline void reset_spi(struct wctdm *wc, int card) { unsigned long flags; spin_lock_irqsave(&wc->lock, flags); __wctdm_setcard(wc, card); __reset_spi(wc); __reset_spi(wc); spin_unlock_irqrestore(&wc->lock, flags); } static unsigned char wctdm_getreg(struct wctdm *wc, int card, unsigned char reg) { unsigned long flags; unsigned char res; spin_lock_irqsave(&wc->lock, flags); res = __wctdm_getreg(wc, card, reg); spin_unlock_irqrestore(&wc->lock, flags); return res; } static int __wait_access(struct wctdm *wc, int card) { unsigned char data = 0; int count = 0; #define MAX 6000 /* attempts */ /* Wait for indirect access */ while (count++ < MAX) { data = __wctdm_getreg(wc, card, I_STATUS); if (!data) return 0; } if(count > (MAX-1)) printk(KERN_NOTICE " ##### Loop error (%02x) #####\n", data); return 0; } static unsigned char translate_3215(unsigned char address) { int x; for (x=0;xflags[card] & FLAG_3215) { address = translate_3215(address); if (address == 255) return 0; } spin_lock_irqsave(&wc->lock, flags); if(!__wait_access(wc, card)) { __wctdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF)); __wctdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); __wctdm_setreg(wc, card, IAA,address); res = 0; }; spin_unlock_irqrestore(&wc->lock, flags); return res; } static int wctdm_proslic_getreg_indirect(struct wctdm *wc, int card, unsigned char address) { unsigned long flags; int res = -1; char *p=NULL; /* Translate 3215 addresses */ if (wc->flags[card] & FLAG_3215) { address = translate_3215(address); if (address == 255) return 0; } spin_lock_irqsave(&wc->lock, flags); if (!__wait_access(wc, card)) { __wctdm_setreg(wc, card, IAA, address); if (!__wait_access(wc, card)) { unsigned char data1, data2; data1 = __wctdm_getreg(wc, card, IDA_LO); data2 = __wctdm_getreg(wc, card, IDA_HI); res = data1 | (data2 << 8); } else p = "Failed to wait inside\n"; } else p = "failed to wait\n"; spin_unlock_irqrestore(&wc->lock, flags); if (p) printk(KERN_NOTICE "%s", p); return res; } static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card) { unsigned char i; for (i=0; iflags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255))) { printk(KERN_NOTICE "!!!!!!! %s iREG %X = %X should be %X\n", indirect_regs[i].name,indirect_regs[i].address,j,initial ); passed = 0; } } if (passed) { if (debug) printk(KERN_DEBUG "Init Indirect Registers completed successfully.\n"); } else { printk(KERN_NOTICE " !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); return -1; } return 0; } static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card) { struct fxs *const fxs = &wc->mod[card].fxs; int res; /* Check loopback */ res = wc->reg1shadow[card]; if (!res && (res != fxs->lasttxhook)) { res = wctdm_getreg(wc, card, 8); if (res) { printk(KERN_NOTICE "Ouch, part reset, quickly restoring reality (%d)\n", card); wctdm_init_proslic(wc, card, 1, 0, 1); } else { if (fxs->palarms++ < MAX_ALARMS) { printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1); if (fxs->lasttxhook == SLIC_LF_RINGING) fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; wctdm_setreg(wc, card, 64, fxs->lasttxhook); } else { if (fxs->palarms == MAX_ALARMS) printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1); } } } } static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) { #define MS_PER_CHECK_HOOK 16 #ifndef AUDIO_RINGCHECK unsigned char res; #endif signed char b; int errors = 0; struct fxo *fxo = &wc->mod[card].fxo; /* Try to track issues that plague slot one FXO's */ b = wc->reg0shadow[card]; if ((b & 0x2) || !(b & 0x8)) { /* Not good -- don't look at anything else */ if (debug) printk(KERN_DEBUG "Error (%02x) on card %d!\n", b, card + 1); errors++; } b &= 0x9b; if (fxo->offhook) { if (b != 0x9) wctdm_setreg(wc, card, 5, 0x9); } else { if (b != 0x8) wctdm_setreg(wc, card, 5, 0x8); } if (errors) return; if (!fxo->offhook) { if (fwringdetect) { res = wc->reg0shadow[card] & 0x60; if (fxo->ringdebounce) { --fxo->ringdebounce; if (res && (res != fxo->lastrdtx) && (fxo->battery == BATTERY_PRESENT)) { if (!fxo->wasringing) { fxo->wasringing = 1; if (debug) printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1); dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); } fxo->lastrdtx = res; fxo->ringdebounce = 10; } else if (!res) { if ((fxo->ringdebounce == 0) && fxo->wasringing) { fxo->wasringing = 0; if (debug) printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1); dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); } } } else if (res && (fxo->battery == BATTERY_PRESENT)) { fxo->lastrdtx = res; fxo->ringdebounce = 10; } } else { res = wc->reg0shadow[card]; if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) { fxo->ringdebounce += (DAHDI_CHUNKSIZE * 16); if (fxo->ringdebounce >= DAHDI_CHUNKSIZE * ringdebounce) { if (!fxo->wasringing) { fxo->wasringing = 1; dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); if (debug) printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1); } fxo->ringdebounce = DAHDI_CHUNKSIZE * ringdebounce; } } else { fxo->ringdebounce -= DAHDI_CHUNKSIZE * 4; if (fxo->ringdebounce <= 0) { if (fxo->wasringing) { fxo->wasringing = 0; dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); if (debug) printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1); } fxo->ringdebounce = 0; } } } } b = wc->reg1shadow[card]; if (fxovoltage) { static int count = 0; if (!(count++ % 100)) { printk(KERN_DEBUG "Card %d: Voltage: %d Debounce %d\n", card + 1, b, fxo->battdebounce); } } if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) { /* * dahdi-base will set DAHDI_RXSIG_INITIAL after a * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events * will be queued on the channel with the current received * hook state. Channels that use robbed-bit signalling always * report the current received state via the dahdi_rbsbits * call. Since we only call dahdi_hooksig when we've detected * a change to report, let's forget our current state in order * to force us to report it again via dahdi_hooksig. * */ fxo->battery = BATTERY_UNKNOWN; } if (abs(b) < battthresh) { /* possible existing states: battery lost, no debounce timer battery lost, debounce timer (going to battery present) battery present or unknown, no debounce timer battery present or unknown, debounce timer (going to battery lost) */ if (fxo->battery == BATTERY_LOST) { if (fxo->battdebounce) { /* we were going to BATTERY_PRESENT, but battery was lost again, so clear the debounce timer */ fxo->battdebounce = 0; } } else { if (fxo->battdebounce) { /* going to BATTERY_LOST, see if we are there yet */ if (--fxo->battdebounce == 0) { fxo->battery = BATTERY_LOST; if (debug) printk(KERN_DEBUG "NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1); #ifdef JAPAN if (!wc->ohdebounce && wc->offhook) { dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); if (debug) printk(KERN_DEBUG "Signalled On Hook\n"); #ifdef ZERO_BATT_RING wc->onhook++; #endif } #else dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); /* set the alarm timer, taking into account that part of its time period has already passed while debouncing occurred */ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK; #endif } } else { /* start the debounce timer to verify that battery has been lost */ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK; } } } else { /* possible existing states: battery lost or unknown, no debounce timer battery lost or unknown, debounce timer (going to battery present) battery present, no debounce timer battery present, debounce timer (going to battery lost) */ if (fxo->battery == BATTERY_PRESENT) { if (fxo->battdebounce) { /* we were going to BATTERY_LOST, but battery appeared again, so clear the debounce timer */ fxo->battdebounce = 0; } } else { if (fxo->battdebounce) { /* going to BATTERY_PRESENT, see if we are there yet */ if (--fxo->battdebounce == 0) { fxo->battery = BATTERY_PRESENT; if (debug) printk(KERN_DEBUG "BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1, (b < 0) ? "-" : "+"); #ifdef ZERO_BATT_RING if (wc->onhook) { wc->onhook = 0; dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); if (debug) printk(KERN_DEBUG "Signalled Off Hook\n"); } #else dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); #endif /* set the alarm timer, taking into account that part of its time period has already passed while debouncing occurred */ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK; } } else { /* start the debounce timer to verify that battery has appeared */ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK; } } } if (fxo->lastpol >= 0) { if (b < 0) { fxo->lastpol = -1; fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; } } if (fxo->lastpol <= 0) { if (b > 0) { fxo->lastpol = 1; fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK; } } if (fxo->battalarm) { if (--fxo->battalarm == 0) { /* the alarm timer has expired, so update the battery alarm state for this channel */ dahdi_alarm_channel(wc->chans[card], fxo->battery == BATTERY_LOST ? DAHDI_ALARM_RED : DAHDI_ALARM_NONE); } } if (fxo->polaritydebounce) { if (--fxo->polaritydebounce == 0) { if (fxo->lastpol != fxo->polarity) { if (debug) printk(KERN_DEBUG "%lu Polarity reversed (%d -> %d)\n", jiffies, fxo->polarity, fxo->lastpol); if (fxo->polarity) dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY); fxo->polarity = fxo->lastpol; } } } #undef MS_PER_CHECK_HOOK } static void wctdm_fxs_hooksig(struct wctdm *wc, const int card, enum dahdi_txsig txsig) { struct fxs *const fxs = &wc->mod[card].fxs; switch (txsig) { case DAHDI_TXSIG_ONHOOK: switch (wc->span.chans[card]->sig) { case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: /* Can't change Ring Generator during OHT */ if (!fxs->ohttimer) { wctdm_set_ring_generator_mode(wc, card, fxs->vmwi_hvac); fxs->lasttxhook = fxs->vmwi_hvac ? SLIC_LF_RINGING : fxs->idletxhookstate; } else { fxs->lasttxhook = fxs->idletxhookstate; } break; case DAHDI_SIG_EM: fxs->lasttxhook = fxs->idletxhookstate; break; case DAHDI_SIG_FXOGS: fxs->lasttxhook = SLIC_LF_TIP_OPEN; break; } break; case DAHDI_TXSIG_OFFHOOK: switch (wc->span.chans[card]->sig) { case DAHDI_SIG_EM: fxs->lasttxhook = SLIC_LF_ACTIVE_REV; break; default: fxs->lasttxhook = fxs->idletxhookstate; break; } break; case DAHDI_TXSIG_START: /* Set ringer mode */ wctdm_set_ring_generator_mode(wc, card, 0); fxs->lasttxhook = SLIC_LF_RINGING; break; case DAHDI_TXSIG_KEWL: fxs->lasttxhook = SLIC_LF_OPEN; break; default: printk(KERN_NOTICE "wctdm: Can't set tx state to %d\n", txsig); return; } if (debug) { printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, fxs->lasttxhook); } wctdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); } static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) { struct fxs *const fxs = &wc->mod[card].fxs; char res; int hook; /* For some reason we have to debounce the hook detector. */ res = wc->reg0shadow[card]; hook = (res & 1); if (hook != fxs->lastrxhook) { /* Reset the debounce (must be multiple of 4ms) */ fxs->debounce = dialdebounce * 4; #if 0 printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, fxs->debounce); #endif } else { if (fxs->debounce > 0) { fxs->debounce -= 16 * DAHDI_CHUNKSIZE; #if 0 printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, fxs->debounce); #endif if (!fxs->debounce) { #if 0 printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook); #endif fxs->debouncehook = hook; } if (!fxs->oldrxhook && fxs->debouncehook) { /* Off hook */ #if 1 if (debug) #endif printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card); switch (fxs->lasttxhook) { case SLIC_LF_RINGING: case SLIC_LF_OHTRAN_FWD: case SLIC_LF_OHTRAN_REV: /* just detected OffHook, during * Ringing or OnHookTransfer */ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; break; } wctdm_fxs_hooksig(wc, card, DAHDI_TXSIG_OFFHOOK); dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); if (robust) wctdm_init_proslic(wc, card, 1, 0, 1); fxs->oldrxhook = 1; } else if (fxs->oldrxhook && !fxs->debouncehook) { /* On hook */ #if 1 if (debug) #endif printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card); wctdm_fxs_hooksig(wc, card, DAHDI_TXSIG_ONHOOK); dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); fxs->oldrxhook = 0; } } } fxs->lastrxhook = hook; } DAHDI_IRQ_HANDLER(wctdm_interrupt) { struct wctdm *wc = dev_id; unsigned char ints; int x; int mode; ints = inb(wc->ioaddr + WC_INTSTAT); if (!ints) return IRQ_NONE; outb(ints, wc->ioaddr + WC_INTSTAT); if (ints & 0x10) { /* Stop DMA, wait for watchdog */ printk(KERN_INFO "TDM PCI Master abort\n"); wctdm_stop_dma(wc); return IRQ_RETVAL(1); } if (ints & 0x20) { printk(KERN_INFO "PCI Target abort\n"); return IRQ_RETVAL(1); } for (x=0;x<4;x++) { if (wc->cardflag & (1 << x) && (wc->modtype[x] == MOD_TYPE_FXS)) { struct fxs *const fxs = &wc->mod[x].fxs; if (fxs->lasttxhook == SLIC_LF_RINGING && !fxs->neonringing) { /* RINGing, prepare for OHT */ fxs->ohttimer = OHT_TIMER << 3; /* logical XOR 3 variables module parameter 'reversepolarity', global reverse all FXS lines. ioctl channel variable fxs 'reversepolarity', Line Reversal Alert Signal if required. ioctl channel variable fxs 'vmwi_lrev', VMWI pending. */ /* OHT mode when idle */ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; } else if (fxs->ohttimer) { /* check if still OnHook */ if (!fxs->oldrxhook) { fxs->ohttimer -= DAHDI_CHUNKSIZE; if (!fxs->ohttimer) { fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; /* Switch to Active, Rev or Fwd */ /* if currently OHT */ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) || (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) { if (fxs->vmwi_hvac) { /* force idle polarity Forward if ringing */ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; /* Set ring generator for neon */ wctdm_set_ring_generator_mode(wc, x, 1); fxs->lasttxhook = SLIC_LF_RINGING; } else { fxs->lasttxhook = fxs->idletxhookstate; } /* Apply the change as appropriate */ wctdm_setreg(wc, x, LINE_STATE, fxs->lasttxhook); } } } else { fxs->ohttimer = 0; /* Switch to Active, Rev or Fwd */ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; } } } } if (ints & 0x0f) { wc->intcount++; x = wc->intcount & 0x3; mode = wc->intcount & 0xc; if (wc->cardflag & (1 << x)) { switch(mode) { case 0: /* Rest */ break; case 4: /* Read first shadow reg */ if (wc->modtype[x] == MOD_TYPE_FXS) wc->reg0shadow[x] = wctdm_getreg(wc, x, 68); else if (wc->modtype[x] == MOD_TYPE_FXO) wc->reg0shadow[x] = wctdm_getreg(wc, x, 5); break; case 8: /* Read second shadow reg */ if (wc->modtype[x] == MOD_TYPE_FXS) wc->reg1shadow[x] = wctdm_getreg(wc, x, LINE_STATE); else if (wc->modtype[x] == MOD_TYPE_FXO) wc->reg1shadow[x] = wctdm_getreg(wc, x, 29); break; case 12: /* Perform processing */ if (wc->modtype[x] == MOD_TYPE_FXS) { wctdm_proslic_check_hook(wc, x); if (!(wc->intcount & 0xf0)) { wctdm_proslic_recheck_sanity(wc, x); } } else if (wc->modtype[x] == MOD_TYPE_FXO) { wctdm_voicedaa_check_hook(wc, x); } break; } } if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ for (x=0;x<4;x++) if (wc->modtype[x] == MOD_TYPE_FXS) { if (wc->mod[x].fxs.palarms) wc->mod[x].fxs.palarms--; } } wctdm_receiveprep(wc, ints); wctdm_transmitprep(wc, ints); } return IRQ_RETVAL(1); } static int wctdm_voicedaa_insane(struct wctdm *wc, int card) { int blah; blah = wctdm_getreg(wc, card, 2); if (blah != 0x3) return -2; blah = wctdm_getreg(wc, card, 11); if (debug) printk(KERN_DEBUG "VoiceDAA System: %02x\n", blah & 0xf); return 0; } static int wctdm_proslic_insane(struct wctdm *wc, int card) { int blah,insane_report; insane_report=0; blah = wctdm_getreg(wc, card, 0); if (debug) printk(KERN_DEBUG "ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf)); #if 0 if ((blah & 0x30) >> 4) { printk(KERN_DEBUG "ProSLIC on module %d is not a 3210.\n", card); return -1; } #endif if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) { /* SLIC not loaded */ return -1; } if ((blah & 0xf) < 2) { printk(KERN_NOTICE "ProSLIC 3210 version %d is too old\n", blah & 0xf); return -1; } if (wctdm_getreg(wc, card, 1) & 0x80) /* ProSLIC 3215, not a 3210 */ wc->flags[card] |= FLAG_3215; blah = wctdm_getreg(wc, card, 8); if (blah != 0x2) { printk(KERN_NOTICE "ProSLIC on module %d insane (1) %d should be 2\n", card, blah); return -1; } else if ( insane_report) printk(KERN_NOTICE "ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah); blah = wctdm_getreg(wc, card, 64); if (blah != 0x0) { printk(KERN_NOTICE "ProSLIC on module %d insane (2)\n", card); return -1; } else if ( insane_report) printk(KERN_NOTICE "ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah); blah = wctdm_getreg(wc, card, 11); if (blah != 0x33) { printk(KERN_NOTICE "ProSLIC on module %d insane (3)\n", card); return -1; } else if ( insane_report) printk(KERN_NOTICE "ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah); /* Just be sure it's setup right. */ wctdm_setreg(wc, card, 30, 0); if (debug) printk(KERN_DEBUG "ProSLIC on module %d seems sane.\n", card); return 0; } static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card) { unsigned long origjiffies; unsigned char vbat; /* Turn off linefeed */ wctdm_setreg(wc, card, 64, 0); /* Power down */ wctdm_setreg(wc, card, 14, 0x10); /* Wait for one second */ origjiffies = jiffies; while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) { if ((jiffies - origjiffies) >= (HZ/2)) break;; } if (vbat < 0x06) { printk(KERN_NOTICE "Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card, 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ)); return -1; } else if (debug) { printk(KERN_NOTICE "Post-leakage voltage: %d volts\n", 376 * vbat / 1000); } return 0; } static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast) { unsigned char vbat; unsigned long origjiffies; int lim; /* Set period of DC-DC converter to 1/64 khz */ wctdm_setreg(wc, card, 92, 0xff /* was 0xff */); /* Wait for VBat to powerup */ origjiffies = jiffies; /* Disable powerdown */ wctdm_setreg(wc, card, 14, 0); /* If fast, don't bother checking anymore */ if (fast) return 0; while((vbat = wctdm_getreg(wc, card, 82)) < 0xc0) { /* Wait no more than 500ms */ if ((jiffies - origjiffies) > HZ/2) { break; } } if (vbat < 0xc0) { if (wc->proslic_power == PROSLIC_POWER_UNKNOWN) printk(KERN_NOTICE "ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE TDM400P??\n", card, (int)(((jiffies - origjiffies) * 1000 / HZ)), vbat * 375); wc->proslic_power = PROSLIC_POWER_WARNED; return -1; } else if (debug) { printk(KERN_DEBUG "ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); } wc->proslic_power = PROSLIC_POWER_ON; /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */ /* If out of range, just set it to the default value */ lim = (loopcurrent - 20) / 3; if ( loopcurrent > 41 ) { lim = 0; if (debug) printk(KERN_DEBUG "Loop current out of range! Setting to default 20mA!\n"); } else if (debug) printk(KERN_DEBUG "Loop current set to %dmA!\n",(lim*3)+20); wctdm_setreg(wc,card,LOOP_I_LIMIT,lim); /* Engage DC-DC converter */ wctdm_setreg(wc, card, 93, 0x19 /* was 0x19 */); #if 0 origjiffies = jiffies; while(0x80 & wctdm_getreg(wc, card, 93)) { if ((jiffies - origjiffies) > 2 * HZ) { printk(KERN_DEBUG "Timeout waiting for DC-DC calibration on module %d\n", card); return -1; } } #if 0 /* Wait a full two seconds */ while((jiffies - origjiffies) < 2 * HZ); /* Just check to be sure */ vbat = wctdm_getreg(wc, card, 82); printk(KERN_DEBUG "ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); #endif #endif return 0; } static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){ unsigned long origjiffies; unsigned char i; wctdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21 wctdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21 wctdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21 wctdm_setreg(wc, card, 64, 0);//(0) wctdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. wctdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM origjiffies=jiffies; while( wctdm_getreg(wc,card,96)!=0 ){ if((jiffies-origjiffies)>80) return -1; } //Initialized DR 98 and 99 to get consistant results. // 98 and 99 are the results registers and the search should have same intial conditions. /*******************************The following is the manual gain mismatch calibration****************************/ /*******************************This is also available as a function *******************************************/ // Delay 10ms origjiffies=jiffies; while((jiffies-origjiffies)<1); wctdm_proslic_setreg_indirect(wc, card, 88, 0); wctdm_proslic_setreg_indirect(wc, card, 89, 0); wctdm_proslic_setreg_indirect(wc, card, 90, 0); wctdm_proslic_setreg_indirect(wc, card, 91, 0); wctdm_proslic_setreg_indirect(wc, card, 92, 0); wctdm_proslic_setreg_indirect(wc, card, 93, 0); wctdm_setreg(wc, card, 98, 0x10); // This is necessary if the calibration occurs other than at reset time wctdm_setreg(wc, card, 99, 0x10); for ( i=0x1f; i>0; i--) { wctdm_setreg(wc, card, 98, i); origjiffies=jiffies; while((jiffies-origjiffies)<4); if((wctdm_getreg(wc, card, 88)) == 0) break; } // for for ( i=0x1f; i>0; i--) { wctdm_setreg(wc, card, 99, i); origjiffies=jiffies; while((jiffies-origjiffies)<4); if((wctdm_getreg(wc, card, 89)) == 0) break; }//for /*******************************The preceding is the manual gain mismatch calibration****************************/ /**********************************The following is the longitudinal Balance Cal***********************************/ wctdm_setreg(wc,card,64,1); while((jiffies-origjiffies)<10); // Sleep 100? wctdm_setreg(wc, card, 64, 0); wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration wctdm_setreg(wc, card, 96, 0x40); wctdm_getreg(wc, card, 96); /* Read Reg 96 just cause */ wctdm_setreg(wc, card, 21, 0xFF); wctdm_setreg(wc, card, 22, 0xFF); wctdm_setreg(wc, card, 23, 0xFF); /**The preceding is the longitudinal Balance Cal***/ return(0); } #if 1 static int wctdm_proslic_calibrate(struct wctdm *wc, int card) { unsigned long origjiffies; int x; /* Perform all calibrations */ wctdm_setreg(wc, card, 97, 0x1f); /* Begin, no speedup */ wctdm_setreg(wc, card, 96, 0x5f); /* Wait for it to finish */ origjiffies = jiffies; while(wctdm_getreg(wc, card, 96)) { if ((jiffies - origjiffies) > 2 * HZ) { printk(KERN_NOTICE "Timeout waiting for calibration of module %d\n", card); return -1; } } if (debug) { /* Print calibration parameters */ printk(KERN_DEBUG "Calibration Vector Regs 98 - 107: \n"); for (x=98;x<108;x++) { printk(KERN_DEBUG "%d: %02x\n", x, wctdm_getreg(wc, card, x)); } } return 0; } #endif static void wait_just_a_bit(int foo) { long newjiffies; newjiffies = jiffies + foo; while(jiffies < newjiffies); } /********************************************************************* * Set the hwgain on the analog modules * * card = the card position for this module (0-23) * gain = gain in dB x10 (e.g. -3.5dB would be gain=-35) * tx = (0 for rx; 1 for tx) * *******************************************************************/ static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx) { if (!(wc->modtype[card] == MOD_TYPE_FXO)) { printk(KERN_NOTICE "Cannot adjust gain. Unsupported module type!\n"); return -1; } if (tx) { if (debug) printk(KERN_DEBUG "setting FXO tx gain for card=%d to %d\n", card, gain); if (gain >= -150 && gain <= 0) { wctdm_setreg(wc, card, 38, 16 + (gain/-10)); wctdm_setreg(wc, card, 40, 16 + (-gain%10)); } else if (gain <= 120 && gain > 0) { wctdm_setreg(wc, card, 38, gain/10); wctdm_setreg(wc, card, 40, (gain%10)); } else { printk(KERN_INFO "FXO tx gain is out of range (%d)\n", gain); return -1; } } else { /* rx */ if (debug) printk(KERN_DEBUG "setting FXO rx gain for card=%d to %d\n", card, gain); if (gain >= -150 && gain <= 0) { wctdm_setreg(wc, card, 39, 16+ (gain/-10)); wctdm_setreg(wc, card, 41, 16 + (-gain%10)); } else if (gain <= 120 && gain > 0) { wctdm_setreg(wc, card, 39, gain/10); wctdm_setreg(wc, card, 41, (gain%10)); } else { printk(KERN_INFO "FXO rx gain is out of range (%d)\n", gain); return -1; } } return 0; } static int set_vmwi(struct wctdm * wc, int chan_idx) { struct fxs *const fxs = &wc->mod[chan_idx].fxs; if (fxs->vmwi_active_messages) { fxs->vmwi_lrev = (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV) ? 1 : 0; fxs->vmwi_hvdc = (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVDC) ? 1 : 0; fxs->vmwi_hvac = (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) ? 1 : 0; } else { fxs->vmwi_lrev = 0; fxs->vmwi_hvdc = 0; fxs->vmwi_hvac = 0; } if (debug) { printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, " "lrev=%d, hvdc=%d, hvac=%d\n", chan_idx, fxs->vmwi_active_messages, fxs->vmwi_lrev, fxs->vmwi_hvdc, fxs->vmwi_hvac ); } if (fxs->vmwi_hvac) { /* Can't change ring generator while in On Hook Transfer mode*/ if (!fxs->ohttimer) { if (POLARITY_XOR) fxs->idletxhookstate |= SLIC_LF_REVMASK; else fxs->idletxhookstate &= ~SLIC_LF_REVMASK; /* Set ring generator for neon */ wctdm_set_ring_generator_mode(wc, chan_idx, 1); /* Activate ring to send neon pulses */ fxs->lasttxhook = SLIC_LF_RINGING; wctdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); } } else { if (fxs->neonringing) { /* Set ring generator for normal ringer */ wctdm_set_ring_generator_mode(wc, chan_idx, 0); /* ACTIVE, polarity determined later */ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; } else if ((fxs->lasttxhook == SLIC_LF_RINGING) || (fxs->lasttxhook == SLIC_LF_OPEN)) { /* Can't change polarity while ringing or when open, set idlehookstate instead */ if (POLARITY_XOR) fxs->idletxhookstate |= SLIC_LF_REVMASK; else fxs->idletxhookstate &= ~SLIC_LF_REVMASK; printk(KERN_DEBUG "Unable to change polarity on channel" "%d, lasttxhook=0x%X\n", chan_idx, fxs->lasttxhook ); return 0; } if (POLARITY_XOR) { fxs->idletxhookstate |= SLIC_LF_REVMASK; fxs->lasttxhook |= SLIC_LF_REVMASK; } else { fxs->idletxhookstate &= ~SLIC_LF_REVMASK; fxs->lasttxhook &= ~SLIC_LF_REVMASK; } wctdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); } return 0; } static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, int sane) { unsigned char reg16=0, reg26=0, reg30=0, reg31=0; long newjiffies; wc->modtype[card] = MOD_TYPE_FXO; /* Sanity check the ProSLIC */ reset_spi(wc, card); if (!sane && wctdm_voicedaa_insane(wc, card)) return -2; /* Software reset */ wctdm_setreg(wc, card, 1, 0x80); /* Wait just a bit */ wait_just_a_bit(HZ/10); /* Enable PCM, ulaw */ if (alawoverride){ wctdm_setreg(wc, card, 33, 0x20); } else { wctdm_setreg(wc, card, 33, 0x28); } /* Set On-hook speed, Ringer impedence, and ringer threshold */ reg16 |= (fxo_modes[_opermode].ohs << 6); reg16 |= (fxo_modes[_opermode].rz << 1); reg16 |= (fxo_modes[_opermode].rt); wctdm_setreg(wc, card, 16, reg16); if(fwringdetect) { /* Enable ring detector full-wave rectifier mode */ wctdm_setreg(wc, card, 18, 2); wctdm_setreg(wc, card, 24, 0); } else { /* Set to the device defaults */ wctdm_setreg(wc, card, 18, 0); wctdm_setreg(wc, card, 24, 0x19); } /* Set DC Termination: Tip/Ring voltage adjust, minimum operational current, current limitation */ reg26 |= (fxo_modes[_opermode].dcv << 6); reg26 |= (fxo_modes[_opermode].mini << 4); reg26 |= (fxo_modes[_opermode].ilim << 1); wctdm_setreg(wc, card, 26, reg26); /* Set AC Impedence */ reg30 = (fxo_modes[_opermode].acim); wctdm_setreg(wc, card, 30, reg30); /* Misc. DAA parameters */ if (fastpickup) reg31 = 0xe3; else reg31 = 0xa3; reg31 |= (fxo_modes[_opermode].ohs2 << 3); wctdm_setreg(wc, card, 31, reg31); /* Set Transmit/Receive timeslot */ wctdm_setreg(wc, card, 34, (3-card) * 8); wctdm_setreg(wc, card, 35, 0x00); wctdm_setreg(wc, card, 36, (3-card) * 8); wctdm_setreg(wc, card, 37, 0x00); /* Enable ISO-Cap */ wctdm_setreg(wc, card, 6, 0x00); if (fastpickup) wctdm_setreg(wc, card, 17, wctdm_getreg(wc, card, 17) | 0x20); /* Wait 1000ms for ISO-cap to come up */ newjiffies = jiffies; newjiffies += 2 * HZ; while((jiffies < newjiffies) && !(wctdm_getreg(wc, card, 11) & 0xf0)) wait_just_a_bit(HZ/10); if (!(wctdm_getreg(wc, card, 11) & 0xf0)) { printk(KERN_NOTICE "VoiceDAA did not bring up ISO link properly!\n"); return -1; } if (debug) printk(KERN_DEBUG "ISO-Cap is now up, line side: %02x rev %02x\n", wctdm_getreg(wc, card, 11) >> 4, (wctdm_getreg(wc, card, 13) >> 2) & 0xf); /* Enable on-hook line monitor */ wctdm_setreg(wc, card, 5, 0x08); /* Take values for fxotxgain and fxorxgain and apply them to module */ wctdm_set_hwgain(wc, card, fxotxgain, 1); wctdm_set_hwgain(wc, card, fxorxgain, 0); /* NZ -- crank the tx gain up by 7 dB */ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) { printk(KERN_INFO "Adjusting gain\n"); wctdm_set_hwgain(wc, card, 7, 1); } if(debug) printk(KERN_DEBUG "DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16)?-(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16)? -(wctdm_getreg(wc, card, 40) - 16):wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16)? -(wctdm_getreg(wc, card, 39) - 16) : wctdm_getreg(wc, card, 39),(wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16):wctdm_getreg(wc, card, 41)); return 0; } static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, int sane) { unsigned short tmp[5]; unsigned char r19,r9; int x; int fxsmode=0; struct fxs *const fxs = &wc->mod[card].fxs; /* Sanity check the ProSLIC */ if (!sane && wctdm_proslic_insane(wc, card)) return -2; /* default messages to none and method to FSK */ memset(&fxs->vmwisetting, 0, sizeof(fxs->vmwisetting)); fxs->vmwi_lrev = 0; fxs->vmwi_hvdc = 0; fxs->vmwi_hvac = 0; /* By default, don't send on hook */ if (!reversepolarity != !fxs->reversepolarity) fxs->idletxhookstate = SLIC_LF_ACTIVE_REV; else fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; if (sane) { /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ wctdm_setreg(wc, card, 14, 0x10); } if (wctdm_proslic_init_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card); return -1; } /* Clear scratch pad area */ wctdm_proslic_setreg_indirect(wc, card, 97,0); /* Clear digital loopback */ wctdm_setreg(wc, card, 8, 0); /* Revision C optimization */ wctdm_setreg(wc, card, 108, 0xeb); /* Disable automatic VBat switching for safety to prevent Q7 from accidently turning on and burning out. */ wctdm_setreg(wc, card, 67, 0x07); /* Note, if pulse dialing has problems at high REN loads change this to 0x17 */ /* Turn off Q7 */ wctdm_setreg(wc, card, 66, 1); /* Flush ProSLIC digital filters by setting to clear, while saving old values */ for (x=0;x<5;x++) { tmp[x] = wctdm_proslic_getreg_indirect(wc, card, x + 35); wctdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000); } /* Power up the DC-DC converter */ if (wctdm_powerup_proslic(wc, card, fast)) { printk(KERN_NOTICE "Unable to do INITIAL ProSLIC powerup on module %d\n", card); return -1; } if (!fast) { /* Check for power leaks */ if (wctdm_proslic_powerleak_test(wc, card)) { printk(KERN_NOTICE "ProSLIC module %d failed leakage test. Check for short circuit\n", card); } /* Power up again */ if (wctdm_powerup_proslic(wc, card, fast)) { printk(KERN_NOTICE "Unable to do FINAL ProSLIC powerup on module %d\n", card); return -1; } #ifndef NO_CALIBRATION /* Perform calibration */ if(manual) { if (wctdm_proslic_manual_calibrate(wc, card)) { //printk(KERN_NOTICE "Proslic failed on Manual Calibration\n"); if (wctdm_proslic_manual_calibrate(wc, card)) { printk(KERN_NOTICE "Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); return -1; } printk(KERN_NOTICE "Proslic Passed Manual Calibration on Second Attempt\n"); } } else { if(wctdm_proslic_calibrate(wc, card)) { //printk(KERN_NOTICE "ProSlic died on Auto Calibration.\n"); if (wctdm_proslic_calibrate(wc, card)) { printk(KERN_NOTICE "Proslic Failed on Second Attempt to Auto Calibrate\n"); return -1; } printk(KERN_NOTICE "Proslic Passed Auto Calibration on Second Attempt\n"); } } /* Perform DC-DC calibration */ wctdm_setreg(wc, card, 93, 0x99); r19 = wctdm_getreg(wc, card, 107); if ((r19 < 0x2) || (r19 > 0xd)) { printk(KERN_NOTICE "DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); wctdm_setreg(wc, card, 107, 0x8); } /* Save calibration vectors */ for (x=0;xcalregs.vals[x] = wctdm_getreg(wc, card, 96 + x); #endif } else { /* Restore calibration registers */ for (x=0;xcalregs.vals[x]); } /* Calibration complete, restore original values */ for (x=0;x<5;x++) { wctdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); } if (wctdm_proslic_verify_indirect_regs(wc, card)) { printk(KERN_INFO "Indirect Registers failed verification.\n"); return -1; } #if 0 /* Disable Auto Power Alarm Detect and other "features" */ wctdm_setreg(wc, card, 67, 0x0e); blah = wctdm_getreg(wc, card, 67); #endif #if 0 if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix printk(KERN_INFO "ProSlic IndirectReg Died.\n"); return -1; } #endif if (alawoverride) wctdm_setreg(wc, card, 1, 0x20); else wctdm_setreg(wc, card, 1, 0x28); // U-Law 8-bit interface wctdm_setreg(wc, card, 2, (3-card) * 8); // Tx Start count low byte 0 wctdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 wctdm_setreg(wc, card, 4, (3-card) * 8); // Rx Start count low byte 0 wctdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 wctdm_setreg(wc, card, 18, 0xff); // clear all interrupt wctdm_setreg(wc, card, 19, 0xff); wctdm_setreg(wc, card, 20, 0xff); wctdm_setreg(wc, card, 73, 0x04); if (fxshonormode) { fxsmode = acim2tiss[fxo_modes[_opermode].acim]; wctdm_setreg(wc, card, 10, 0x08 | fxsmode); } if (lowpower) wctdm_setreg(wc, card, 72, 0x10); #if 0 wctdm_setreg(wc, card, 21, 0x00); // enable interrupt wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt #endif #if 0 /* Enable loopback */ wctdm_setreg(wc, card, 8, 0x2); wctdm_setreg(wc, card, 14, 0x0); wctdm_setreg(wc, card, 64, 0x0); wctdm_setreg(wc, card, 1, 0x08); #endif if (wctdm_init_ring_generator_mode(wc, card)) { return -1; } if(fxstxgain || fxsrxgain) { r9 = wctdm_getreg(wc, card, 9); switch (fxstxgain) { case 35: r9+=8; break; case -35: r9+=4; break; case 0: break; } switch (fxsrxgain) { case 35: r9+=2; break; case -35: r9+=1; break; case 0: break; } wctdm_setreg(wc,card,9,r9); } if(debug) printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0")); fxs->lasttxhook = fxs->idletxhookstate; wctdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); return 0; } static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) { struct wctdm_stats stats; struct wctdm_regs regs; struct wctdm_regop regop; struct wctdm_echo_coefs echoregs; struct dahdi_hwgain hwgain; struct wctdm *wc = chan->pvt; struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; int x; switch (cmd) { case DAHDI_ONHOOKTRANSFER: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; fxs->ohttimer = x << 3; /* Active mode when idle */ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; if (fxs->neonringing) { /* keep same Forward polarity */ fxs->lasttxhook = SLIC_LF_OHTRAN_FWD; printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", chan->chanpos - 1); wctdm_setreg(wc, chan->chanpos - 1, LINE_STATE, fxs->lasttxhook); } else if (fxs->lasttxhook == SLIC_LF_ACTIVE_FWD || fxs->lasttxhook == SLIC_LF_ACTIVE_REV) { /* Apply the change if appropriate */ fxs->lasttxhook = POLARITY_XOR ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", chan->chanpos - 1); wctdm_setreg(wc, chan->chanpos - 1, LINE_STATE, fxs->lasttxhook); } break; case DAHDI_SETPOLARITY: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; /* Can't change polarity while ringing or when open */ if ((fxs->lasttxhook == SLIC_LF_RINGING) || (fxs->lasttxhook == SLIC_LF_OPEN)) return -EINVAL; fxs->reversepolarity = x; if (POLARITY_XOR) { fxs->lasttxhook |= SLIC_LF_REVMASK; printk(KERN_INFO "ioctl: Reverse Polarity, card %d\n", chan->chanpos - 1); } else { fxs->lasttxhook &= ~SLIC_LF_REVMASK; printk(KERN_INFO "ioctl: Normal Polarity, card %d\n", chan->chanpos - 1); } wctdm_setreg(wc, chan->chanpos - 1, LINE_STATE, fxs->lasttxhook); break; case DAHDI_VMWI_CONFIG: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; if (copy_from_user(&(fxs->vmwisetting), (__user void *) data, sizeof(fxs->vmwisetting))) return -EFAULT; set_vmwi(wc, chan->chanpos - 1); break; case DAHDI_VMWI: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; if (0 > x) return -EFAULT; fxs->vmwi_active_messages = x; set_vmwi(wc, chan->chanpos - 1); break; case WCTDM_GET_STATS: if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376; stats.ringvolt = wctdm_getreg(wc, chan->chanpos - 1, 81) * -376; stats.batvolt = wctdm_getreg(wc, chan->chanpos - 1, 82) * -376; } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { stats.tipvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; stats.ringvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; stats.batvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000; } else return -EINVAL; if (copy_to_user((__user void *)data, &stats, sizeof(stats))) return -EFAULT; break; case WCTDM_GET_REGS: if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { for (x=0;xchanpos -1, x); for (x=0;xchanpos - 1, x); } else { memset(®s, 0, sizeof(regs)); for (x=0;xchanpos - 1, x); } if (copy_to_user((__user void *)data, ®s, sizeof(regs))) return -EFAULT; break; case WCTDM_SET_REG: if (copy_from_user(®op, (__user void *) data, sizeof(regop))) return -EFAULT; if (regop.indirect) { if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; printk(KERN_INFO "Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); } else { regop.val &= 0xff; printk(KERN_INFO "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); } break; case WCTDM_SET_ECHOTUNE: printk(KERN_INFO "-- Setting echo registers: \n"); if (copy_from_user(&echoregs, (__user void *)data, sizeof(echoregs))) return -EFAULT; if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { /* Set the ACIM register */ wctdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim); /* Set the digital echo canceller registers */ wctdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1); wctdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2); wctdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3); wctdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4); wctdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5); wctdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6); wctdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7); wctdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8); printk(KERN_INFO "-- Set echo registers successfully\n"); break; } else { return -EINVAL; } break; case DAHDI_SET_HWGAIN: if (copy_from_user(&hwgain, (__user void *) data, sizeof(hwgain))) return -EFAULT; wctdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx); if (debug) printk(KERN_DEBUG "Setting hwgain on channel %d to %d for %s direction\n", chan->chanpos-1, hwgain.newgain, hwgain.tx ? "tx" : "rx"); break; default: return -ENOTTY; } return 0; } static int wctdm_open(struct dahdi_chan *chan) { struct wctdm *wc = chan->pvt; if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) return -ENODEV; if (wc->dead) return -ENODEV; wc->usecount++; return 0; } static inline struct wctdm *wctdm_from_span(struct dahdi_span *span) { return container_of(span, struct wctdm, span); } static int wctdm_watchdog(struct dahdi_span *span, int event) { printk(KERN_INFO "TDM: Restarting DMA\n"); wctdm_restart_dma(wctdm_from_span(span)); return 0; } static int wctdm_close(struct dahdi_chan *chan) { struct wctdm *wc = chan->pvt; struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; wc->usecount--; if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { int idlehookstate; idlehookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; fxs->idletxhookstate = idlehookstate; } /* If we're dead, release us now */ if (!wc->usecount && wc->dead) wctdm_release(wc); return 0; } static int wctdm_init_ring_generator_mode(struct wctdm *wc, int card) { wctdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ /* neon trapezoid timers */ wctdm_setreg(wc, card, 48, 0xe0); /* Active Timer low byte */ wctdm_setreg(wc, card, 49, 0x01); /* Active Timer high byte */ wctdm_setreg(wc, card, 50, 0xF0); /* Inactive Timer low byte */ wctdm_setreg(wc, card, 51, 0x05); /* Inactive Timer high byte */ wctdm_set_ring_generator_mode(wc, card, 0); return 0; } static int wctdm_set_ring_generator_mode(struct wctdm *wc, int card, int mode) { int reg20, reg21, reg74; /* RCO, RNGX, VBATH */ struct fxs *const fxs = &wc->mod[card].fxs; fxs->neonringing = mode; /* track ring generator mode */ if (mode) { /* Neon */ if (debug) printk(KERN_DEBUG "NEON ring on chan %d, " "lasttxhook was 0x%x\n", card, fxs->lasttxhook); /* Must be in FORWARD ACTIVE before setting ringer */ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; wctdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); wctdm_proslic_setreg_indirect(wc, card, 22, NEON_MWI_RNGY_PULSEWIDTH); wctdm_proslic_setreg_indirect(wc, card, 21, 0x7bef); /* RNGX (91.5Vpk) */ wctdm_proslic_setreg_indirect(wc, card, 20, 0x009f); /* RCO (RNGX, t rise)*/ wctdm_setreg(wc, card, 34, 0x19); /* Ringing Osc. Control */ wctdm_setreg(wc, card, 74, 0x3f); /* VBATH 94.5V */ wctdm_proslic_setreg_indirect(wc, card, 29, 0x4600); /* RPTP */ /* A write of 0x04 to register 64 will turn on the VM led */ } else { wctdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ /* RNGY Initial Phase */ wctdm_proslic_setreg_indirect(wc, card, 22, 0x0000); wctdm_proslic_setreg_indirect(wc, card, 29, 0x3600); /* RPTP */ /* A write of 0x04 to register 64 will turn on the ringer */ if (fastringer) { /* Speed up Ringer */ reg20 = 0x7e6d; reg74 = 0x32; /* Default */ /* Beef up Ringing voltage to 89V */ if (boostringer) { reg74 = 0x3f; reg21 = 0x0247; /* RNGX */ if (debug) printk(KERN_DEBUG "Boosting fast ringer" " on chan %d (89V peak)\n", card); } else if (lowpower) { reg21 = 0x014b; /* RNGX */ if (debug) printk(KERN_DEBUG "Reducing fast ring " "power on chan %d (50V peak)\n", card); } else if (fxshonormode && fxo_modes[_opermode].ring_x) { reg21 = fxo_modes[_opermode].ring_x; if (debug) printk(KERN_DEBUG "fxshonormode: fast " "ring_x power on chan %d\n", card); } else { reg21 = 0x01b9; if (debug) printk(KERN_DEBUG "Speeding up ringer " "on chan %d (25Hz)\n", card); } /* VBATH */ wctdm_setreg(wc, card, 74, reg74); /*RCO*/ wctdm_proslic_setreg_indirect(wc, card, 20, reg20); /*RNGX*/ wctdm_proslic_setreg_indirect(wc, card, 21, reg21); } else { /* Ringer Speed */ if (fxshonormode && fxo_modes[_opermode].ring_osc) { reg20 = fxo_modes[_opermode].ring_osc; if (debug) printk(KERN_DEBUG "fxshonormode: " "ring_osc speed on chan %d\n", card); } else { reg20 = 0x7ef0; /* Default */ } reg74 = 0x32; /* Default */ /* Beef up Ringing voltage to 89V */ if (boostringer) { reg74 = 0x3f; reg21 = 0x1d1; if (debug) printk(KERN_DEBUG "Boosting ringer on " "chan %d (89V peak)\n", card); } else if (lowpower) { reg21 = 0x108; if (debug) printk(KERN_DEBUG "Reducing ring power " "on chan %d (50V peak)\n", card); } else if (fxshonormode && fxo_modes[_opermode].ring_x) { reg21 = fxo_modes[_opermode].ring_x; if (debug) printk(KERN_DEBUG "fxshonormode: ring_x" " power on chan %d\n", card); } else { reg21 = 0x160; if (debug) printk(KERN_DEBUG "Normal ring power on" " chan %d\n", card); } /* VBATH */ wctdm_setreg(wc, card, 74, reg74); /* RCO */ wctdm_proslic_setreg_indirect(wc, card, 20, reg20); /* RNGX */ wctdm_proslic_setreg_indirect(wc, card, 21, reg21); } } return 0; } static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wctdm *wc = chan->pvt; int chan_entry = chan->chanpos - 1; if (wc->modtype[chan_entry] == MOD_TYPE_FXO) { /* XXX Enable hooksig for FXO XXX */ switch(txsig) { case DAHDI_TXSIG_START: case DAHDI_TXSIG_OFFHOOK: wc->mod[chan_entry].fxo.offhook = 1; wctdm_setreg(wc, chan_entry, 5, 0x9); break; case DAHDI_TXSIG_ONHOOK: wc->mod[chan_entry].fxo.offhook = 0; wctdm_setreg(wc, chan_entry, 5, 0x8); break; default: printk(KERN_NOTICE "wcfxo: Can't set tx state to %d\n", txsig); } } else { wctdm_fxs_hooksig(wc, chan_entry, txsig); } return 0; } static const struct dahdi_span_ops wctdm_span_ops = { .owner = THIS_MODULE, .hooksig = wctdm_hooksig, .open = wctdm_open, .close = wctdm_close, .ioctl = wctdm_ioctl, .watchdog = wctdm_watchdog, }; static int wctdm_initialize(struct wctdm *wc) { int x; /* DAHDI stuff */ sprintf(wc->span.name, "WCTDM/%d", wc->pos); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); wc->span.manufacturer = "Digium"; strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); if (alawoverride) { printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n"); wc->span.deflaw = DAHDI_LAW_ALAW; } else { wc->span.deflaw = DAHDI_LAW_MULAW; } for (x = 0; x < NUM_CARDS; x++) { sprintf(wc->chans[x]->name, "WCTDM/%d/%d", wc->pos, x); wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR; wc->chans[x]->sigcap |= DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR; wc->chans[x]->chanpos = x+1; wc->chans[x]->pvt = wc; } wc->span.chans = wc->chans; wc->span.channels = NUM_CARDS; wc->span.irq = wc->dev->irq; wc->span.flags = DAHDI_FLAG_RBS; wc->span.ops = &wctdm_span_ops; if (dahdi_register(&wc->span, 0)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } return 0; } static void wctdm_post_initialize(struct wctdm *wc) { int x; /* Finalize signalling */ for (x = 0; x < NUM_CARDS; x++) { if (wc->cardflag & (1 << x)) { if (wc->modtype[x] == MOD_TYPE_FXO) wc->chans[x]->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR; else wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR; } else if (!(wc->chans[x]->sigcap & DAHDI_SIG_BROKEN)) { wc->chans[x]->sigcap = 0; } } } static int wctdm_hardware_init(struct wctdm *wc) { /* Hardware stuff */ unsigned char ver; unsigned char x,y; int failed; /* Signal Reset */ outb(0x01, wc->ioaddr + WC_CNTL); /* Check Freshmaker chip */ x=inb(wc->ioaddr + WC_CNTL); ver = __wctdm_getcreg(wc, WC_VER); failed = 0; if (ver != 0x59) { printk(KERN_INFO "Freshmaker version: %02x\n", ver); for (x=0;x<255;x++) { /* Test registers */ if (ver >= 0x70) { __wctdm_setcreg(wc, WC_CS, x); y = __wctdm_getcreg(wc, WC_CS); } else { __wctdm_setcreg(wc, WC_TEST, x); y = __wctdm_getcreg(wc, WC_TEST); } if (x != y) { printk(KERN_INFO "%02x != %02x\n", x, y); failed++; } } if (!failed) { printk(KERN_INFO "Freshmaker passed register test\n"); } else { printk(KERN_NOTICE "Freshmaker failed register test\n"); return -1; } /* Go to half-duty FSYNC */ __wctdm_setcreg(wc, WC_SYNC, 0x01); y = __wctdm_getcreg(wc, WC_SYNC); } else { printk(KERN_INFO "No freshmaker chip\n"); } /* Reset PCI Interface chip and registers (and serial) */ outb(0x06, wc->ioaddr + WC_CNTL); /* Setup our proper outputs for when we switch for our "serial" port */ wc->ios = BIT_CS | BIT_SCLK | BIT_SDI; outb(wc->ios, wc->ioaddr + WC_AUXD); /* Set all to outputs except AUX 5, which is an input */ outb(0xdf, wc->ioaddr + WC_AUXC); /* Select alternate function for AUX0 */ outb(0x4, wc->ioaddr + WC_AUXFUNC); /* Wait 1/4 of a sec */ wait_just_a_bit(HZ/4); /* Back to normal, with automatic DMA wrap around */ outb(0x30 | 0x01, wc->ioaddr + WC_CNTL); /* Make sure serial port and DMA are out of reset */ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL); /* Configure serial port for MSB->LSB operation */ outb(0xc1, wc->ioaddr + WC_SERCTL); /* Delay FSC by 0 so it's properly aligned */ outb(0x0, wc->ioaddr + WC_FSCDELAY); /* Setup DMA Addresses */ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ outl(wc->writedma + DAHDI_CHUNKSIZE * 4 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ outl(wc->writedma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWE); /* End */ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ outl(wc->readdma + DAHDI_CHUNKSIZE * 4 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ outl(wc->readdma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARE); /* End */ /* Clear interrupts */ outb(0xff, wc->ioaddr + WC_INTSTAT); /* Wait 1/4 of a second more */ wait_just_a_bit(HZ/4); for (x = 0; x < NUM_CARDS; x++) { int sane=0,ret=0,readi=0; #if 1 /* Init with Auto Calibration */ if (!(ret=wctdm_init_proslic(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); if (debug) { readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); printk(KERN_DEBUG "Proslic module %d loop current is %dmA\n",x, ((readi*3)+20)); } printk(KERN_INFO "Module %d: Installed -- AUTO FXS/DPO\n",x); } else { if(ret!=-2) { sane=1; /* Init with Manual Calibration */ if (!wctdm_init_proslic(wc, x, 0, 1, sane)) { wc->cardflag |= (1 << x); if (debug) { readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); printk(KERN_DEBUG "Proslic module %d loop current is %dmA\n",x, ((readi*3)+20)); } printk(KERN_INFO "Module %d: Installed -- MANUAL FXS\n",x); } else { printk(KERN_NOTICE "Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC"); wc->chans[x]->sigcap = __DAHDI_SIG_FXO | DAHDI_SIG_BROKEN; } } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); printk(KERN_INFO "Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); } else printk(KERN_NOTICE "Module %d: Not installed\n", x); } #endif } /* Return error if nothing initialized okay. */ if (!wc->cardflag && !timingonly) return -1; __wctdm_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1); return 0; } static void wctdm_enable_interrupts(struct wctdm *wc) { /* Enable interrupts (we care about all of them) */ outb(0x3f, wc->ioaddr + WC_MASK0); /* No external interrupts */ outb(0x00, wc->ioaddr + WC_MASK1); } static void wctdm_restart_dma(struct wctdm *wc) { /* Reset Master and TDM */ outb(0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); } static void wctdm_start_dma(struct wctdm *wc) { /* Reset Master and TDM */ outb(0x0f, wc->ioaddr + WC_CNTL); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); outb(0x01, wc->ioaddr + WC_CNTL); outb(0x01, wc->ioaddr + WC_OPER); } static void wctdm_stop_dma(struct wctdm *wc) { outb(0x00, wc->ioaddr + WC_OPER); } static void wctdm_reset_tdm(struct wctdm *wc) { /* Reset TDM */ outb(0x0f, wc->ioaddr + WC_CNTL); } static void wctdm_disable_interrupts(struct wctdm *wc) { outb(0x00, wc->ioaddr + WC_MASK0); outb(0x00, wc->ioaddr + WC_MASK1); } static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res; struct wctdm *wc; struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data; int x; int y; for (x=0;x= WC_MAX_IFACES) { printk(KERN_NOTICE "Too many interfaces\n"); return -EIO; } if (pci_enable_device(pdev)) { res = -EIO; } else { wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL); if (wc) { int cardcount = 0; ifaces[x] = wc; memset(wc, 0, sizeof(struct wctdm)); for (x=0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); ++x) { wc->chans[x] = &wc->_chans[x]; } spin_lock_init(&wc->lock); wc->curcard = -1; wc->ioaddr = pci_resource_start(pdev, 0); wc->dev = pdev; wc->pos = x; wc->variety = d->name; for (y=0;yflags[y] = d->flags; /* Keep track of whether we need to free the region */ if (request_region(wc->ioaddr, 0xff, "wctdm")) wc->freeregion = 1; /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses 32 bits. Allocate an extra set just for control too */ wc->writechunk = pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma); if (!wc->writechunk) { printk(KERN_NOTICE "wctdm: Unable to allocate DMA-able memory\n"); if (wc->freeregion) release_region(wc->ioaddr, 0xff); return -ENOMEM; } wc->readchunk = wc->writechunk + DAHDI_MAX_CHUNKSIZE * 2; /* in doublewords */ wc->readdma = wc->writedma + DAHDI_MAX_CHUNKSIZE * 8; /* in bytes */ if (wctdm_initialize(wc)) { printk(KERN_NOTICE "wctdm: Unable to intialize FXS\n"); /* Set Reset Low */ x=inb(wc->ioaddr + WC_CNTL); outb((~0x1)&x, wc->ioaddr + WC_CNTL); /* Free Resources */ free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); kfree(wc); return -EIO; } /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, wctdm_interrupt, DAHDI_IRQ_SHARED, "wctdm", wc)) { printk(KERN_NOTICE "wctdm: Unable to request IRQ %d\n", pdev->irq); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); kfree(wc); return -EIO; } if (wctdm_hardware_init(wc)) { /* Set Reset Low */ x=inb(wc->ioaddr + WC_CNTL); outb((~0x1)&x, wc->ioaddr + WC_CNTL); /* Free Resources */ free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); dahdi_unregister(&wc->span); kfree(wc); return -EIO; } wctdm_post_initialize(wc); /* Enable interrupts */ wctdm_enable_interrupts(wc); /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 4); /* Start DMA */ wctdm_start_dma(wc); for (x = 0; x < NUM_CARDS; x++) { if (wc->cardflag & (1 << x)) cardcount++; } printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n", wc->variety, cardcount); res = 0; } else res = -ENOMEM; } return res; } static void wctdm_release(struct wctdm *wc) { dahdi_unregister(&wc->span); if (wc->freeregion) release_region(wc->ioaddr, 0xff); kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } static void __devexit wctdm_remove_one(struct pci_dev *pdev) { struct wctdm *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ wctdm_stop_dma(wc); wctdm_reset_tdm(wc); /* In case hardware is still there */ wctdm_disable_interrupts(wc); /* Immediately free resources */ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ outb(0x0e, wc->ioaddr + WC_CNTL); /* Release span, possibly delayed */ if (!wc->usecount) wctdm_release(wc); else wc->dead = 1; } } static DEFINE_PCI_DEVICE_TABLE(wctdm_pci_tbl) = { { 0xe159, 0x0001, 0xa159, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm }, { 0xe159, 0x0001, 0xe159, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm }, { 0xe159, 0x0001, 0xb100, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme }, { 0xe159, 0x0001, 0xb1d9, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi }, { 0xe159, 0x0001, 0xb118, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi }, { 0xe159, 0x0001, 0xb119, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi }, { 0xe159, 0x0001, 0xa9fd, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, { 0xe159, 0x0001, 0xa8fd, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, { 0xe159, 0x0001, 0xa800, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, { 0xe159, 0x0001, 0xa801, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, { 0xe159, 0x0001, 0xa908, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, { 0xe159, 0x0001, 0xa901, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, #ifdef TDM_REVH_MATCHALL { 0xe159, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh }, #endif { 0 } }; MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl); static int wctdm_suspend(struct pci_dev *pdev, pm_message_t state) { return -ENOSYS; } static struct pci_driver wctdm_driver = { .name = "wctdm", .probe = wctdm_init_one, .remove =__devexit_p(wctdm_remove_one), .suspend = wctdm_suspend, .id_table = wctdm_pci_tbl, }; static int __init wctdm_init(void) { int res; int x; for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) { if (!strcmp(fxo_modes[x].name, opermode)) break; } if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) { _opermode = x; } else { printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode); for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++) printk(KERN_INFO " %s\n", fxo_modes[x].name); printk(KERN_INFO "Note this option is CASE SENSITIVE!\n"); return -ENODEV; } if (!strcmp(opermode, "AUSTRALIA")) { boostringer = 1; fxshonormode = 1; } /* for the voicedaa_check_hook defaults, if the user has not overridden them by specifying them as module parameters, then get the values from the selected operating mode */ if (battdebounce == 0) { battdebounce = fxo_modes[_opermode].battdebounce; } if (battalarm == 0) { battalarm = fxo_modes[_opermode].battalarm; } if (battthresh == 0) { battthresh = fxo_modes[_opermode].battthresh; } res = dahdi_pci_module(&wctdm_driver); if (res) return -ENODEV; return 0; } static void __exit wctdm_cleanup(void) { pci_unregister_driver(&wctdm_driver); } module_param(debug, int, 0600); module_param(fxovoltage, int, 0600); module_param(loopcurrent, int, 0600); module_param(reversepolarity, int, 0600); module_param(robust, int, 0600); module_param(opermode, charp, 0600); module_param(timingonly, int, 0600); module_param(lowpower, int, 0600); module_param(boostringer, int, 0600); module_param(fastringer, int, 0600); module_param(fxshonormode, int, 0600); module_param(battdebounce, uint, 0600); module_param(battalarm, uint, 0600); module_param(battthresh, uint, 0600); module_param(ringdebounce, int, 0600); module_param(dialdebounce, int, 0600); module_param(fwringdetect, int, 0600); module_param(alawoverride, int, 0600); module_param(fastpickup, int, 0600); module_param(fxotxgain, int, 0600); module_param(fxorxgain, int, 0600); module_param(fxstxgain, int, 0600); module_param(fxsrxgain, int, 0600); MODULE_DESCRIPTION("Wildcard TDM400P Driver"); MODULE_AUTHOR("Mark Spencer "); MODULE_ALIAS("wcfxs"); MODULE_LICENSE("GPL v2"); module_init(wctdm_init); module_exit(wctdm_cleanup); dahdi-linux-2.5.0.1/drivers/dahdi/adt_lec.c0000644000175000017500000000335511261425376020312 0ustar tzafrirtzafrir/* * ADT Line Echo Canceller Parameter Parsing * * Copyright (C) 2008-2009 Digium, Inc. * * Kevin P. Fleming * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _ADT_LEC_C #define _ADT_LEC_C #include static inline void adt_lec_init_defaults(struct adt_lec_params *params, __u32 tap_length) { params->tap_length = tap_length; params->nlp_type = 0; params->nlp_max_suppress = 0; params->nlp_threshold = 0; } static int adt_lec_parse_params(struct adt_lec_params *params, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p) { unsigned int x; char *c; params->tap_length = ecp->tap_length; for (x = 0; x < ecp->param_count; x++) { for (c = p[x].name; *c; c++) *c = tolower(*c); if (!strcmp(p[x].name, "nlp_type")) { switch (p[x].value) { case ADT_LEC_NLP_OFF: case ADT_LEC_NLP_MUTE: case ADT_LEC_RANDOM_NOISE: case ADT_LEC_HOTH_NOISE: case ADT_LEC_SUPPRESS: params->nlp_type = p[x].value; break; default: return -EINVAL; } } else if (!strcmp(p[x].name, "nlp_thresh")) { params->nlp_threshold = p[x].value; } else if (!strcmp(p[x].name, "nlp_suppress")) { params->nlp_max_suppress = p[x].value; } else { return -EINVAL; } } return 0; } #endif /* _ADT_LEC_C */ dahdi-linux-2.5.0.1/drivers/dahdi/tor2-hw.h0000644000175000017500000001372711510412320020210 0ustar tzafrirtzafrir/* * Tormenta 2 Quad-T1 PCI Driver * * Written by Mark Spencer * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2008, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #ifndef _TOR2_HW_H #define _TOR2_HW_H /* * The Tormenta two consists of the following block architecture: * * [ Spartan ] --- [ DS 21Q352 ] -- Xfrms -- Span 1 * | | | | | | | * Local Bus +----- Span 2 * | | | | * [ PCI 9030 ] +----- Span 3 * | | | | | | * PCI BUS +----- Span 4 * * All communicatiosn to the framer (21Q352) are performed * through the PCI 9030 part using memory mapped I/O. * * The Tormenta 2 requires a 2 2k wondows memory space * which is mapped as follows: * * First (32 bit) space: * * 0x0000 -> 0x07FF: Memory map of Tx and Rx buffers. They are stored * with increasing channel number, with each span in * a byte of a 32-bit long word: * Bits 31-24: Span 1 * Bits 23-16: Span 2 * Bits 16- 8: Span 3 * Bits 7- 0: Span 4 * * * Second (8 bit) space: * * 0x0000 -> 0x00FF: Registers for Transceiver 1 * 0x0100 -> 0x01FF: Registers for Transceiver 2 * 0x0200 -> 0x02FF: Registers for Transceiver 3 * 0x0300 -> 0x03FF: Registers for Transceiver 4 * * 0x400 Write -> Firmware load location for Xilinx. This is the only valid * register until the Xilinx is programmed to decode * the remainder! * * 0x400 Write -> clkreg (sync source) * 0=free run, 1=span 1, 2=span 2, 3=span 3, 4=span 4. * * 0x400 Read -> statreg * bit 0 - Interrupt Enabled * bit 1 - Interrupt Active * bit 2 - Dallas Interrupt Active * * 0x401 Write -> ctlreg as follows: * bit 0 - Interrupt Enable * bit 1 - Drives "TEST1" signal ("Interrupt" outbit) * bit 2 - Dallas Interrupt Enable (Allows DINT signal to drive INT) * bit 3 - External Syncronization Enable (MASTER signal). * bit 4 - Select E1 Divisor Mode (0 for T1, 1 for E1). * bit 5 - Remote serial loopback (When set to 1, TSER is driven from RSER) * bit 6 - Local serial loopback (When set to 1, Rx buffers are driven from Tx buffers) * bit 7 - Interrupt Acknowledge (set to 1 to acknowledge interrupt) * * 0x402 Write -> LED register as follows: * bit 0 - Span 1 Green * bit 1 - Span 1 Red * bit 2 - Span 2 Green * bit 3 - Span 2 Red * bit 4 - Span 3 Green * bit 5 - Span 3 Red * bit 6 - Span 4 Green * bit 7 - Span 4 Red * NOTE: turning on both red and green yields yellow. * * 0x403 Write -> TEST2, writing to bit 0 drives TEST2 pin. * * 0x404 Write -> ctlreg1 as follows: * bit 0 - Non-REV.A Mode (Set this bit for Dallas chips later then Rev. A) */ #ifdef NEED_PCI_IDS /* * Provide routines for identifying a tormenta card */ #define PCI_VENDOR_ID_PLX 0x10b5 #ifdef __KERNEL__ static DEFINE_PCI_DEVICE_TABLE(tor2_pci_ids) = #else #define PCI_ANY_ID -1 static struct tor2_pci_id { int vendor; int device; int subvendor; int subdevice; int class; int classmask; unsigned long driver_data; } tor2_pci_ids[] = #endif /* __KERNEL__ */ { { PCI_VENDOR_ID_PLX, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"PLX 9030" }, /* PLX 9030 Development board */ { PCI_VENDOR_ID_PLX, 0x3001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"PLX Development Board" }, /* PLX 9030 Development board */ { PCI_VENDOR_ID_PLX, 0xD00D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"Tormenta 2 Quad T1/PRI or E1/PRA" }, /* Tormenta 2 */ { PCI_VENDOR_ID_PLX, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"Tormenta 2 Quad T1/E1 (non-Digium clone)" }, /* Tormenta 2 clone */ { 0, } }; #ifndef __KERNEL__ /* We provide a simple routine to match the given ID's */ static inline int tor2_pci_match(int vendorid, int deviceid, char **variant) { /* Returns 1 if this is a tormenta card or 0 if it isn't */ int x; for (x = 0; x< sizeof(tor2_pci_ids) / sizeof(tor2_pci_ids[0]); x++) if (((tor2_pci_ids[x].vendor == PCI_ANY_ID) || (tor2_pci_ids[x].vendor == vendorid)) && ((tor2_pci_ids[x].device == PCI_ANY_ID) || (tor2_pci_ids[x].device == deviceid))) { *variant = (char *)tor2_pci_ids[x].driver_data; return 1; } if (variant) *variant = NULL; return 0; } #endif /* __KERNEL__ */ #endif /* NEED_PCI_IDS */ /* * PLX PCI9030 PCI Configuration Registers * * This is not an all-inclusive list, just some interesting ones * that we need and that are not standard. * */ #define PLX_PCI_VPD_ADDR 0x4e /* Set address here */ #define PLX_PCI_VPD_DATA 0x50 /* Read/Write data here */ #define PLX_LOC_WP_BOUNDARY 0x4e /* Bits 6-0 here */ #define PLX_LOC_GPIOC 0x54 /* GPIO control register */ /* The 4 GPIO data bits we are interested in */ #define LOC_GPIOC_GPIO4 0x4000 /* GPIO4 data */ #define LOC_GPIOC_GPIO5 0x20000 /* GPIO5 data */ #define LOC_GPIOC_GPIO6 0x100000 /* GPIO6 data */ #define LOC_GPIOC_GPIO7 0x800000 /* GPIO7 data */ /* define the initialization of the GPIOC register */ #define LOC_GPIOC_INIT_VALUE 0x2036000 /* GPIO 4&5 in write and both high and GPIO 8 in write low */ /* The defines by what they actually do */ #define GPIO_WRITE LOC_GPIOC_GPIO4 #define GPIO_PROGRAM LOC_GPIOC_GPIO5 #define GPIO_INIT LOC_GPIOC_GPIO6 #define GPIO_DONE LOC_GPIOC_GPIO7 #endif /* _TOR2_HW_H */ dahdi-linux-2.5.0.1/drivers/dahdi/Kbuild0000644000175000017500000001221511532727335017704 0ustar tzafrirtzafrirobj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI) += dahdi.o #obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DUMMY) += dahdi_dummy.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC) += dahdi_dynamic.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_LOC) += dahdi_dynamic_loc.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_ETH) += dahdi_dynamic_eth.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_ETHMF) += dahdi_dynamic_ethmf.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TRANSCODE) += dahdi_transcode.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP) += wct4xxp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP) += wctc4xxp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP) += wctdm24xxp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM) += wctdm.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VOICEBUS) += voicebus/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCB4XXP) += wcb4xxp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT1XXP) += wct1xxp.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE11XP) += wcte11xp.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCFXO) += wcfxo.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TOR2) += tor2.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_PCIRADIO) += pciradio.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPP) += xpp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_JPAH) += dahdi_echocan_jpah.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE) += dahdi_echocan_sec.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE2) += dahdi_echocan_sec2.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_KB1) += dahdi_echocan_kb1.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_MG2) += dahdi_echocan_mg2.o obj-m += $(DAHDI_MODULES_EXTRA) # Only enable this if you think you know what you're doing. This is not # supported yet: #obj-m += dahdi_echocan_oslec.o # # A quick and dirty way to build OSLEC, if you happened to place it # yourself in the dahdi source tree. This is experimental. See README # regarding OSLEC. #obj-m += ../staging/echo/ CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(src) ifndef HOTPLUG_FIRMWARE ifneq (,$(filter y m,$(CONFIG_FW_LOADER))) HOTPLUG_FIRMWARE := yes else HOTPLUG_FIRMWARE := no endif export HOTPLUG_FIRMWARE endif # fix typo present in CentOS and RHEL 2.6.9 kernels BAD_KERNELS_VERS := 22 34 34.0.1 34.0.2 BAD_KERNELS := $(foreach ver,$(BAD_KERNELS_VERS),2.6.9-$(ver).EL 2.6.9-$(ver).ELsmp) ifneq (,$(filter $(KVERS),$(BAD_KERNELS))) EXTRA_CFLAGS+=-Drw_lock_t=rwlock_t endif # A number of Fedora 10 (9 also?) kernels backported hrtimer to 2.6.27 # as part of an ALSA backport. TODO: Any better way to detect that? ifeq (1,$(shell fgrep -q ' hrtimer_set_expires' include/linux/hrtimer.h 2>/dev/null && echo 1)) EXTRA_CFLAGS+=-DHAVE_HRTIMER_ACCESSORS=1 endif ifeq (1,$(shell fgrep -q 'wait_for_completion_timeout' include/linux/completion.h 2>/dev/null && echo 1)) CFLAGS_MODULE+=-DHAVE_WAIT_FOR_COMPLETION_TIMEOUT=1 endif # In 2.6.18 skb_linearize changed; however, some distros backported the change ifneq (,$(wildcard $(srctree)/include/linux/skbuff.h)) ifeq ($(shell grep "skb_linearize.*(.*, .* gfp)" $(srctree)/include/linux/skbuff.h),) CFLAGS_dahdi_dynamic_eth.o := -DNEW_SKB_LINEARIZE CFLAGS_dahdi_dynamic_ethmf.o := -DNEW_SKB_LINEARIZE endif endif dahdi-objs := dahdi-base.o dahdi-sysfs.o dahdi-version.o ############################################################################### # Find appropriate ARCH value for VPMADT032 and HPEC binary modules ############################################################################### ifeq ($(ARCH),i386) DAHDI_ARCH=x86_32 else ifeq ($(ARCH),x86_64) DAHDI_ARCH=x86_64 else ifeq ($(ARCH),x86) ifeq ($(CONFIG_X86_32),y) DAHDI_ARCH=x86_32 else DAHDI_ARCH=x86_64 endif else $(warning CPU Architecture '$(ARCH)' does not support VPMADT032 or HPEC. Skipping.) endif endif endif ############################################################################### # VPMADT032 Loader ############################################################################### dahdi_vpmadt032_loader-objs := vpmadt032_loader/dahdi_vpmadt032_loader.o ifneq ($(DAHDI_ARCH),) ifneq ($(wildcard $(src)/vpmadt032_loader/vpmadt032_$(DAHDI_ARCH).o_shipped),) VPMADT032_LOADER_PRESENT=yes dahdi_vpmadt032_loader-objs += vpmadt032_loader/vpmadt032_$(DAHDI_ARCH).o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VPMADT032_LOADER) += dahdi_vpmadt032_loader.o endif endif ############################################################################### # HPEC Support ############################################################################### dahdi_echocan_hpec-objs := hpec/dahdi_echocan_hpec.o CFLAGS_dahdi_echocan_hpec.o := -I$(src)/hpec ifneq ($(DAHDI_ARCH),) ifneq ($(wildcard $(src)/hpec/hpec_$(DAHDI_ARCH).o_shipped),) HPEC_PRESENT=yes dahdi_echocan_hpec-objs += hpec/hpec_$(DAHDI_ARCH).o endif endif ifeq ($(HPEC_PRESENT),yes) obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_HPEC) += dahdi_echocan_hpec.o endif $(obj)/pciradio.o: $(obj)/radfw.h $(obj)/tor2.o: $(obj)/tor2fw.h hostprogs-y := makefw $(obj)/tor2fw.h: $(src)/tormenta2.rbt $(obj)/makefw $(obj)/makefw $< tor2fw > $@ $(obj)/radfw.h: $(src)/pciradio.rbt $(obj)/makefw $(obj)/makefw $< radfw > $@ clean-files := radfw.h tor2fw.h dahdi-linux-2.5.0.1/drivers/dahdi/ecdis.h0000644000175000017500000000672211176115504020006 0ustar tzafrirtzafrir/* * SpanDSP - a series of DSP components for telephony * * ec_disable_detector.h - A detector which should eventually meet the * G.164/G.165 requirements for detecting the * 2100Hz echo cancellor disable tone. * * Written by Steve Underwood * * Copyright (C) 2001 Steve Underwood * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include "biquad.h" #define FALSE 0 #define TRUE (!FALSE) static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det) { /* Elliptic notch */ /* This is actually centred at 2095Hz, but gets the balance we want, due to the asymmetric walls of the notch */ biquad2_init (&det->notch, (int32_t) (-0.7600000*32768.0), (int32_t) (-0.1183852*32768.0), (int32_t) (-0.5104039*32768.0), (int32_t) ( 0.1567596*32768.0), (int32_t) ( 1.0000000*32768.0)); det->channel_level = 0; det->notch_level = 0; det->tone_present = FALSE; det->tone_cycle_duration = 0; det->good_cycles = 0; det->hit = 0; } /*- End of function --------------------------------------------------------*/ static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det, int16_t amp) { int16_t notched; notched = biquad2 (&det->notch, amp); /* Estimate the overall energy in the channel, and the energy in the notch (i.e. overall channel energy - tone energy => noise). Use abs instead of multiply for speed (is it really faster?). Damp the overall energy a little more for a stable result. Damp the notch energy a little less, so we don't damp out the blip every time the phase reverses */ det->channel_level += ((abs(amp) - det->channel_level) >> 5); det->notch_level += ((abs(notched) - det->notch_level) >> 4); if (det->channel_level >= 70) { /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ if (det->notch_level*6 < det->channel_level) { det->tone_cycle_duration++; /* The notch says yes, so we have the tone. */ if (!det->tone_present) { /* Do we get a kick every 450+-25ms? */ if ((det->tone_cycle_duration >= (425 * 8)) && (det->tone_cycle_duration <= (475 * 8))) { /* It's ANS/PR (CED with polarity reversals), so wait for at least three cycles before returning a hit. */ det->good_cycles++; if (det->good_cycles > 2) det->hit = TRUE; } det->tone_cycle_duration = 0; det->tone_present = TRUE; } else if (det->tone_cycle_duration >= 600 * 8) { /* It's ANS (CED without polarity reversals) so return a hit. */ det->hit = TRUE; } } else { det->tone_present = FALSE; } } else { det->tone_present = FALSE; det->tone_cycle_duration = 0; det->good_cycles = 0; } return det->hit; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_echocan_kb1.c0000644000175000017500000005557211500234716022205 0ustar tzafrirtzafrir/* * ECHO_CAN_KB1 * * by Kris Boutilier * * Based upon mec2.h * * Copyright (C) 2002, Digium, Inc. * * Additional background on the techniques used in this code can be found in: * * Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine; * Winship, Peter; "Digital Voice Echo Canceller with a TMS32020," * in Digital Signal Processing Applications with the TMS320 Family, * pp. 415-437, Texas Instruments, Inc., 1986. * * A pdf of which is available by searching on the document title at http://www.ti.com/ * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include static int debug; static int aggressive; #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #define debug_printk(level, fmt, args...) if (debug >= level) printk(KERN_DEBUG "%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args) /* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */ /* #define MEC2_STATS 4000 */ /* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */ /* #define MEC2_STATS_DETAILED */ /* Get optimized routines for math */ #include "arith.h" /* Important constants for tuning kb1 echo can */ /* Convergence (aka. adaptation) speed -- higher means slower */ #define DEFAULT_BETA1_I 2048 /* Constants for various power computations */ #define DEFAULT_SIGMA_LY_I 7 #define DEFAULT_SIGMA_LU_I 7 #define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */ #define DEFAULT_ALPHA_YT_I 5 #define DEFAULT_CUTOFF_I 128 /* Define the near-end speech hangover counter: if near-end speech * is declared, hcntr is set equal to hangt (see pg. 432) */ #define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */ /* define the residual error suppression threshold */ #define DEFAULT_SUPPR_I 16 /* 16 = -24db */ /* This is the minimum reference signal power estimate level * that will result in filter adaptation. * If this is too low then background noise will cause the filter * coefficients to constantly be updated. */ #define MIN_UPDATE_THRESH_I 4096 /* The number of samples used to update coefficients using the * the block update method (M). It should be related back to the * length of the echo can. * ie. it only updates coefficients when (sample number MOD default_m) = 0 * * Getting this wrong may cause an oops. Consider yourself warned! */ #define DEFAULT_M 16 /* every 16th sample */ /* If AGGRESSIVE supression is enabled, then we start cancelling residual * echos again even while there is potentially the very end of a near-side * signal present. * This defines how many samples of DEFAULT_HANGT can remain before we * kick back in */ #define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */ /***************************************************************/ /* The following knobs are not implemented in the current code */ /* we need a dynamic level of suppression varying with the ratio of the power of the echo to the power of the reference signal this is done so that we have a smoother background. we have a higher suppression when the power ratio is closer to suppr_ceil and reduces logarithmically as we approach suppr_floor. */ #define SUPPR_FLOOR -64 #define SUPPR_CEIL -24 /* in a second departure, we calculate the residual error suppression * as a percentage of the reference signal energy level. The threshold * is defined in terms of dB below the reference signal. */ #define RES_SUPR_FACTOR -20 #ifndef NULL #define NULL 0 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!FALSE) #endif /* Generic circular buffer definition */ typedef struct { /* Pointer to the relative 'start' of the buffer */ int idx_d; /* The absolute size of the buffer */ int size_d; /* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */ short *buf_d; } echo_can_cb_s; static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val); static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable); static const char *name = "KB1"; static const char *ec_name(const struct dahdi_chan *chan) { return name; } static const struct dahdi_echocan_factory my_factory = { .get_name = ec_name, .owner = THIS_MODULE, .echocan_create = echo_can_create, }; static const struct dahdi_echocan_features my_features = { .NLP_toggle = 1, }; static const struct dahdi_echocan_ops my_ops = { .echocan_free = echo_can_free, .echocan_process = echo_can_process, .echocan_traintap = echo_can_traintap, .echocan_NLP_toggle = echocan_NLP_toggle, }; struct ec_pvt { struct dahdi_echocan_state dahdi; /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */ int id; /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */ int i_d; /* Pre-computed constants */ /* ---------------------- */ /* Number of filter coefficents */ int N_d; /* Rate of adaptation of filter */ int beta2_i; /* Accumulators for power computations */ /* ----------------------------------- */ /* reference signal power estimate - aka. Average absolute value of y(k) */ int Ly_i; /* ... */ int Lu_i; /* Accumulators for signal detectors */ /* --------------------------------- */ /* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */ int s_tilde_i; /* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */ int y_tilde_i; /* Near end speech detection counter - stores Hangover counter time remaining, in samples */ int HCNTR_d; /* Circular buffers and coefficients */ /* --------------------------------- */ /* ... */ int *a_i; /* ... */ short *a_s; /* Reference samples of far-end receive signal */ echo_can_cb_s y_s; /* Reference samples of near-end signal */ echo_can_cb_s s_s; /* Reference samples of near-end signal minus echo estimate */ echo_can_cb_s u_s; /* Reference samples of far-end receive signal used to calculate short-time average */ echo_can_cb_s y_tilde_s; /* Peak far-end receive signal */ /* --------------------------- */ /* Highest y_tilde value in the sample buffer */ short max_y_tilde; /* Index of the sample containing the max_y_tilde value */ int max_y_tilde_pos; #ifdef MEC2_STATS /* Storage for performance statistics */ int cntr_nearend_speech_frames; int cntr_residualcorrected_frames; int cntr_residualcorrected_framesskipped; int cntr_coeff_updates; int cntr_coeff_missedupdates; int avg_Lu_i_toolow; int avg_Lu_i_ok; #endif unsigned int aggressive:1; int use_nlp; }; #define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi) static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where) { cb->buf_d = (short *)where; cb->idx_d = 0; cb->size_d = len; } static inline void add_cc_s(echo_can_cb_s *cb, short newval) { /* Can't use modulus because N+M isn't a power of two (generally) */ cb->idx_d--; if (cb->idx_d < (int)0) /* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */ cb->idx_d += cb->size_d; /* Load two copies into memory */ cb->buf_d[cb->idx_d] = newval; cb->buf_d[cb->idx_d + cb->size_d] = newval; } static inline short get_cc_s(echo_can_cb_s *cb, int pos) { /* Load two copies into memory */ return cb->buf_d[cb->idx_d + pos]; } static inline void init_cc(struct ec_pvt *pvt, int N, int maxy, int maxu) { char *ptr = (char *) pvt; unsigned long tmp; /* Double-word align past end of state */ ptr += sizeof(*pvt); tmp = (unsigned long)ptr; tmp += 3; tmp &= ~3L; ptr = (void *)tmp; /* Reset parameters */ pvt->N_d = N; pvt->beta2_i = DEFAULT_BETA1_I; /* Allocate coefficient memory */ pvt->a_i = (int *) ptr; ptr += (sizeof(int) * pvt->N_d); pvt->a_s = (short *) ptr; ptr += (sizeof(short) * pvt->N_d); /* Reset Y circular buffer (short version) */ init_cb_s(&pvt->y_s, maxy, ptr); ptr += (sizeof(short) * (maxy) * 2); /* Reset Sigma circular buffer (short version for FIR filter) */ init_cb_s(&pvt->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr); ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2); init_cb_s(&pvt->u_s, maxu, ptr); ptr += (sizeof(short) * maxu * 2); /* Allocate a buffer for the reference signal power computation */ init_cb_s(&pvt->y_tilde_s, pvt->N_d, ptr); /* Reset the absolute time index */ pvt->i_d = (int)0; /* Reset the power computations (for y and u) */ pvt->Ly_i = DEFAULT_CUTOFF_I; pvt->Lu_i = DEFAULT_CUTOFF_I; #ifdef MEC2_STATS /* set the identity */ pvt->id = (int)&ptr; /* Reset performance stats */ pvt->cntr_nearend_speech_frames = (int)0; pvt->cntr_residualcorrected_frames = (int)0; pvt->cntr_residualcorrected_framesskipped = (int)0; pvt->cntr_coeff_updates = (int)0; pvt->cntr_coeff_missedupdates = (int)0; pvt->avg_Lu_i_toolow = (int)0; pvt->avg_Lu_i_ok = (int)0; #endif /* Reset the near-end speech detector */ pvt->s_tilde_i = (int)0; pvt->y_tilde_i = (int)0; pvt->HCNTR_d = (int)0; } static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) { struct ec_pvt *pvt = dahdi_to_pvt(ec); kfree(pvt); } static inline short sample_update(struct ec_pvt *pvt, short iref, short isig) { /* Declare local variables that are used more than once */ /* ... */ int k; /* ... */ int rs; /* ... */ short u; /* ... */ int Py_i; /* ... */ int two_beta_i; /* flow A on pg. 428 */ /* eq. (16): high-pass filter the input to generate the next value; * push the current value into the circular buffer * * sdc_im1_d = sdc_d; * sdc_d = sig; * s_i_d = sdc_d; * s_d = s_i_d; * s_i_d = (float)(1.0 - gamma_d) * s_i_d * + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */ /* Update the Far-end receive signal circular buffers and accumulators */ /* ------------------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->y_tilde_i -= abs(get_cc_s(&pvt->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1)) >> DEFAULT_ALPHA_YT_I; /* Add the new sample to the power estimate accumulator */ pvt->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I; /* Push a copy of the new sample into its circular buffer */ add_cc_s(&pvt->y_s, iref); /* eq. (2): compute r in fixed-point */ rs = CONVOLVE2(pvt->a_s, pvt->y_s.buf_d + pvt->y_s.idx_d, pvt->N_d); rs >>= 15; /* eq. (3): compute the output value (see figure 3) and the error * note: the error is the same as the output signal when near-end * speech is not present */ u = isig - rs; /* Push a copy of the output value sample into its circular buffer */ add_cc_s(&pvt->u_s, u); /* Update the Near-end hybrid signal circular buffers and accumulators */ /* ------------------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->s_tilde_i -= abs(get_cc_s(&pvt->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1)); /* Add the new sample to the power estimate accumulator */ pvt->s_tilde_i += abs(isig); /* Push a copy of the new sample into it's circular buffer */ add_cc_s(&pvt->s_s, isig); /* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */ add_cc_s(&pvt->y_tilde_s, pvt->y_tilde_i); /* flow B on pg. 428 */ /* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */ if (!pvt->HCNTR_d) { Py_i = (pvt->Ly_i >> DEFAULT_SIGMA_LY_I) * (pvt->Ly_i >> DEFAULT_SIGMA_LY_I); Py_i >>= 15; } else { Py_i = (1 << 15); } #if 0 /* Vary rate of adaptation depending on position in the file * Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech * has begun of the file to allow the echo cancellor to estimate the * channel accurately * Still needs conversion! */ if (pvt->start_speech_d != 0) { if (pvt->i_d > (DEFAULT_T0 + pvt->start_speech_d)*(SAMPLE_FREQ)) { pvt->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((pvt->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - pvt->start_speech_d))); } } else { pvt->beta2_d = DEFAULT_BETA1; } #endif /* Fixed point, inverted */ pvt->beta2_i = DEFAULT_BETA1_I; /* Fixed point version, inverted */ two_beta_i = (pvt->beta2_i * Py_i) >> 15; if (!two_beta_i) two_beta_i++; /* Update the Suppressed signal power estimate accumulator */ /* ------------------------------------------------------- */ /* Delete the oldest sample from the power estimate accumulator */ pvt->Lu_i -= abs(get_cc_s(&pvt->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1)); /* Add the new sample to the power estimate accumulator */ pvt->Lu_i += abs(u); /* Update the Far-end reference signal power estimate accumulator */ /* -------------------------------------------------------------- */ /* eq. (10): update power estimate of the reference */ /* Delete the oldest sample from the power estimate accumulator */ pvt->Ly_i -= abs(get_cc_s(&pvt->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ; /* Add the new sample to the power estimate accumulator */ pvt->Ly_i += abs(iref); if (pvt->Ly_i < DEFAULT_CUTOFF_I) pvt->Ly_i = DEFAULT_CUTOFF_I; /* Update the Peak far-end receive signal detected */ /* ----------------------------------------------- */ if (pvt->y_tilde_i > pvt->max_y_tilde) { /* New highest y_tilde with full life */ pvt->max_y_tilde = pvt->y_tilde_i; pvt->max_y_tilde_pos = pvt->N_d - 1; } else if (--pvt->max_y_tilde_pos < 0) { /* Time to find new max y tilde... */ pvt->max_y_tilde = MAX16(pvt->y_tilde_s.buf_d + pvt->y_tilde_s.idx_d, pvt->N_d, &pvt->max_y_tilde_pos); } /* Determine if near end speech was detected in this sample */ /* -------------------------------------------------------- */ if (((pvt->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > pvt->max_y_tilde) && (pvt->max_y_tilde > 0)) { /* Then start the Hangover counter */ pvt->HCNTR_d = DEFAULT_HANGT; #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", pvt->s_tilde_i, (pvt->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), pvt->max_y_tilde); #endif #ifdef MEC2_STATS ++pvt->cntr_nearend_speech_frames; #endif } else if (pvt->HCNTR_d > (int)0) { /* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */ #ifdef MEC2_STATS ++pvt->cntr_nearend_speech_frames; #endif pvt->HCNTR_d--; } /* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0) * and we have enough signal to bother trying to update. * -------------------------------------------------------------------------- */ if (!pvt->HCNTR_d && /* no near-end speech present */ !(pvt->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */ if (pvt->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */ /* so loop over all the filter coefficients */ #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "updating coefficients with: pvt->Lu_i %9d\n", pvt->Lu_i); #endif #ifdef MEC2_STATS pvt->avg_Lu_i_ok = pvt->avg_Lu_i_ok + pvt->Lu_i; ++pvt->cntr_coeff_updates; #endif for (k = 0; k < pvt->N_d; k++) { /* eq. (7): compute an expectation over M_d samples */ int grad2; grad2 = CONVOLVE2(pvt->u_s.buf_d + pvt->u_s.idx_d, pvt->y_s.buf_d + pvt->y_s.idx_d + k, DEFAULT_M); /* eq. (7): update the coefficient */ pvt->a_i[k] += grad2 / two_beta_i; pvt->a_s[k] = pvt->a_i[k] >> 16; } } else { #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "insufficient signal to update coefficients pvt->Lu_i %5d < %5d\n", pvt->Lu_i, MIN_UPDATE_THRESH_I); #endif #ifdef MEC2_STATS pvt->avg_Lu_i_toolow = pvt->avg_Lu_i_toolow + pvt->Lu_i; ++pvt->cntr_coeff_missedupdates; #endif } } /* paragraph below eq. (15): if no near-end speech in the sample and * the reference signal power estimate > cutoff threshold * then perform residual error suppression */ #ifdef MEC2_STATS_DETAILED if (pvt->HCNTR_d == 0) printk(KERN_INFO "possibly correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d and expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifndef NO_ECHO_SUPPRESSOR if (pvt->use_nlp) { if (pvt->aggressive) { if ((pvt->HCNTR_d < AGGRESSIVE_HCNTR) && (pvt->Ly_i > (pvt->Lu_i << 1))) { for (k = 0; k < 2; k++) { u = u * (pvt->Lu_i >> DEFAULT_SIGMA_LU_I) / ((pvt->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1); } #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "aggresively correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifdef MEC2_STATS ++pvt->cntr_residualcorrected_frames; #endif } } else { if (pvt->HCNTR_d == 0) { if ((pvt->Ly_i/(pvt->Lu_i + 1)) > DEFAULT_SUPPR_I) { for (k = 0; k < 1; k++) { u = u * (pvt->Lu_i >> DEFAULT_SIGMA_LU_I) / ((pvt->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1); } #ifdef MEC2_STATS_DETAILED printk(KERN_INFO "correcting frame with pvt->Ly_i %9d pvt->Lu_i %9d expression %d\n", pvt->Ly_i, pvt->Lu_i, (pvt->Ly_i/(pvt->Lu_i + 1))); #endif #ifdef MEC2_STATS ++pvt->cntr_residualcorrected_frames; #endif } #ifdef MEC2_STATS else { ++pvt->cntr_residualcorrected_framesskipped; } #endif } } } #endif #if 0 /* This will generate a non-linear supression factor, once converted */ if ((pvt->HCNTR_d == 0) && ((pvt->Lu_d/pvt->Ly_d) < DEFAULT_SUPPR) && (pvt->Lu_d/pvt->Ly_d > EC_MIN_DB_VALUE)) { suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(pvt->Lu_d/pvt->Ly_d) - SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL); u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr; } #endif #ifdef MEC2_STATS /* Periodically dump performance stats */ if ((pvt->i_d % MEC2_STATS) == 0) { /* make sure to avoid div0's! */ if (pvt->cntr_coeff_missedupdates > 0) pvt->avg_Lu_i_toolow = (int)(pvt->avg_Lu_i_toolow / pvt->cntr_coeff_missedupdates); else pvt->avg_Lu_i_toolow = -1; if (pvt->cntr_coeff_updates > 0) pvt->avg_Lu_i_ok = (pvt->avg_Lu_i_ok / pvt->cntr_coeff_updates); else pvt->avg_Lu_i_ok = -1; printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", pvt->id, pvt->cntr_nearend_speech_frames, pvt->cntr_residualcorrected_frames, pvt->cntr_residualcorrected_framesskipped, pvt->cntr_coeff_updates, pvt->cntr_coeff_missedupdates, pvt->avg_Lu_i_ok, pvt->avg_Lu_i_toolow); pvt->cntr_nearend_speech_frames = 0; pvt->cntr_residualcorrected_frames = 0; pvt->cntr_residualcorrected_framesskipped = 0; pvt->cntr_coeff_updates = 0; pvt->cntr_coeff_missedupdates = 0; pvt->avg_Lu_i_ok = 0; pvt->avg_Lu_i_toolow = 0; } #endif /* Increment the sample index and return the corrected sample */ pvt->i_d++; return u; } static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size) { struct ec_pvt *pvt = dahdi_to_pvt(ec); u32 x; short result; for (x = 0; x < size; x++) { result = sample_update(pvt, *iref, *isig); *isig++ = result; ++iref; } } static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) { int maxy; int maxu; size_t size; unsigned int x; char *c; struct ec_pvt *pvt; maxy = ecp->tap_length + DEFAULT_M; maxu = DEFAULT_M; if (maxy < (1 << DEFAULT_ALPHA_YT_I)) maxy = (1 << DEFAULT_ALPHA_YT_I); if (maxy < (1 << DEFAULT_SIGMA_LY_I)) maxy = (1 << DEFAULT_SIGMA_LY_I); if (maxu < (1 << DEFAULT_SIGMA_LU_I)) maxu = (1 << DEFAULT_SIGMA_LU_I); size = sizeof(*ec) + 4 + /* align */ sizeof(int) * ecp->tap_length + /* a_i */ sizeof(short) * ecp->tap_length + /* a_s */ 2 * sizeof(short) * (maxy) + /* y_s */ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */ 2 * sizeof(short) * (maxu) + /* u_s */ 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */ pvt = kzalloc(size, GFP_KERNEL); if (!pvt) return -ENOMEM; pvt->dahdi.ops = &my_ops; pvt->aggressive = aggressive; pvt->dahdi.features = my_features; for (x = 0; x < ecp->param_count; x++) { for (c = p[x].name; *c; c++) *c = tolower(*c); if (!strcmp(p[x].name, "aggressive")) { pvt->aggressive = p[x].value ? 1 : 0; } else { printk(KERN_WARNING "Unknown parameter supplied to KB1 echo canceler: '%s'\n", p[x].name); kfree(pvt); return -EINVAL; } } init_cc(pvt, ecp->tap_length, maxy, maxu); /* Non-linear processor - a fancy way to say "zap small signals, to avoid accumulating noise". */ pvt->use_nlp = TRUE; *ec = &pvt->dahdi; return 0; } static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val) { struct ec_pvt *pvt = dahdi_to_pvt(ec); /* Set the hangover counter to the length of the can to * avoid adjustments occuring immediately after initial forced training */ pvt->HCNTR_d = pvt->N_d << 1; if (pos >= pvt->N_d) return 1; pvt->a_i[pos] = val << 17; pvt->a_s[pos] = val << 1; if (++pos >= pvt->N_d) return 1; return 0; } static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable) { struct ec_pvt *pvt = dahdi_to_pvt(ec); pvt->use_nlp = enable ? 1 : 0; } static int __init mod_init(void) { if (dahdi_register_echocan_factory(&my_factory)) { module_printk(KERN_ERR, "could not register with DAHDI core\n"); return -EPERM; } module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.get_name(NULL)); return 0; } static void __exit mod_exit(void) { dahdi_unregister_echocan_factory(&my_factory); } module_param(debug, int, S_IRUGO | S_IWUSR); module_param(aggressive, int, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("DAHDI 'KB1' Echo Canceler"); MODULE_AUTHOR("Kris Boutilier"); MODULE_LICENSE("GPL v2"); module_init(mod_init); module_exit(mod_exit); dahdi-linux-2.5.0.1/drivers/dahdi/dahdi.h0000644000175000017500000000215611532727335017774 0ustar tzafrirtzafrir#ifndef _DAHDI_H #define _DAHDI_H /* dahdi.h: headers intended only for the dahdi.ko module. * Not to be included elsewhere * * Written by Tzafrir Cohen * Copyright (C) 2011, Xorcom * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ extern int debug; extern const char *const dahdi_version; int dahdi_register_chardev(struct dahdi_chardev *dev); int dahdi_unregister_chardev(struct dahdi_chardev *dev); int span_sysfs_create(struct dahdi_span *span); void span_sysfs_remove(struct dahdi_span *span); int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops); void dahdi_sysfs_exit(void); #endif /* _DAHDI_H */ dahdi-linux-2.5.0.1/drivers/dahdi/proslic.h0000644000175000017500000001241111253526354020367 0ustar tzafrirtzafrir/* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ // ProSlic Header File typedef struct { unsigned char address; unsigned char altaddr; char *name; unsigned short initial; } alpha; typedef struct { unsigned char chip_number; unsigned char DTMF_digit; unsigned char interrupt_line; unsigned char hook_status; unsigned long half_pulses[20]; // Contains the time stamps of incomming half pulses. unsigned char half_pulses_detected; // Contains the number of half pulses detected. unsigned char Pulse_digit; unsigned long On_Hook_time; unsigned long Off_Hook_time; } chipStruct; // Defines #define LPT 0X378 /* Proslic Linefeed options for register 64 - Linefeed Control */ #define SLIC_LF_OPEN 0x0 #define SLIC_LF_ACTIVE_FWD 0x1 #define SLIC_LF_OHTRAN_FWD 0x2 /* Forward On Hook Transfer */ #define SLIC_LF_TIP_OPEN 0x3 #define SLIC_LF_RINGING 0x4 #define SLIC_LF_ACTIVE_REV 0x5 #define SLIC_LF_OHTRAN_REV 0x6 /* Reverse On Hook Transfer */ #define SLIC_LF_RING_OPEN 0x7 #define SLIC_LF_SETMASK 0x7 #define SLIC_LF_OPPENDING 0x10 /* Mask used to reverse the linefeed mode between forward and * reverse polarity. */ #define SLIC_LF_REVMASK 0x4 #define IDA_LO 28 #define IDA_HI 29 #define IAA 30 #define ID_ACCES_STATUS 31 #define IAS_BIT 1 #define I_STATUS 31 #define SPI_MODE 0 #define PCM_MODE 1 #define PCM_XMIT_START_COUNT_LSB 2 #define PCM_XMIT_START_COUNT_MSB 3 #define PCM_RCV_START_COUNT_LSB 4 #define PCM_RCV_START_COUNT_MSB 5 #define DIO 6 #define AUDIO_LOOPBACK 8 #define AUDIO_GAIN 9 #define LINE_IMPEDANCE 10 #define HYBRID 11 #define RESERVED12 12 #define RESERVED13 13 #define PWR_DOWN1 14 #define PWR_DOWN2 15 #define RESERVED16 16 #define RESERVED17 17 #define INTRPT_STATUS1 18 #define INTRPT_STATUS2 19 #define INTRPT_STATUS3 20 #define INTRPT_MASK1 21 #define INTRPT_MASK2 22 #define INTRPT_MASK3 23 #define DTMF_DIGIT 24 #define RESERVED25 25 #define RESERVED26 26 #define RESERVED27 27 #define I_DATA_LOW 28 #define I_DATA_HIGH 29 #define I_ADDRESS 30 #define I_STATUS 31 #define OSC1 32 #define OSC2 33 #define RING_OSC_CTL 34 #define PULSE_OSC 35 #define OSC1_ON__LO 36 #define OSC1_ON_HI 37 #define OSC1_OFF_LO 38 #define OSC1_OFF_HI 39 #define OSC2_ON__LO 40 #define OSC2_ON_HI 41 #define OSC2_OFF_LO 42 #define OSC2_OFF_HI 43 #define PULSE_ON__LO 44 #define PULSE_ON_HI 45 #define PULSE_OFF_LO 46 #define PULSE_OFF_HI 47 #define RING_ON__LO 48 #define RING_ON_HI 49 #define RING_OFF_LO 50 #define RING_OFF_HI 51 #define RESERVED52 52 #define RESERVED53 53 #define RESERVED54 54 #define RESERVED55 55 #define RESERVED56 56 #define RESERVED57 57 #define RESERVED58 58 #define RESERVED59 59 #define RESERVED60 60 #define RESERVED61 61 #define RESERVED62 62 #define RESERVED63 63 #define LINE_STATE 64 #define ACTIVATE_LINE 0x11 #define RING_LINE 0x44 #define BIAS_SQUELCH 65 #define BAT_FEED 66 #define AUTO_STATE 67 #define LOOP_STAT 68 #define LOOP_DEBOUCE 69 #define RT_DEBOUCE 70 #define LOOP_I_LIMIT 71 #define OFF_HOOK_V 72 #define COMMON_V 73 #define BAT_V_HI 74 #define BAT_V_LO 75 #define PWR_STAT_DEV 76 #define PWR_STAT 77 #define LOOP_V_SENSE 78 #define LOOP_I_SENSE 79 #define TIP_V_SENSE 80 #define RING_V_SENSE 81 #define BAT_V_HI_SENSE 82 #define BAT_V_LO_SENSE 83 #define IQ1 84 #define IQ2 85 #define IQ3 86 #define IQ4 87 #define IQ5 88 #define IQ6 89 #define RESERVED90 90 #define RESERVED91 91 #define DCDC_PWM_OFF 92 #define DCDC 93 #define DCDC_PW_OFF 94 #define RESERVED95 95 #define CALIBR1 96 #define CALIBRATE_LINE 0x78 #define NORMAL_CALIBRATION_COMPLETE 0x20 #define CALIBR2 97 #define RING_GAIN_CAL 98 #define TIP_GAIN_CAL 99 #define DIFF_I_CAL 100 #define COMMON_I_CAL 101 #define I_LIMIT_GAIN_CAL 102 #define ADC_OFFSET_CAL 103 #define DAC_ADC_OFFSET 104 #define DAC_OFFSET_CAL 105 #define COMMON_BAL_CAL 106 #define DC_PEAK_CAL 107 // Indirect Register (decimal) #define DTMF_ROW_0_PEAK 0 #define DTMF_ROW_1_PEAK 1 #define DTMF_ROW2_PEAK 2 #define DTMF_ROW3_PEAK 3 #define DTMF_COL1_PEAK 4 #define DTMF_FWD_TWIST 5 #define DTMF_RVS_TWIST 6 #define DTMF_ROW_RATIO_THRESH 7 #define DTMF_COL_RATIO_THRESH 8 #define DTMF_ROW_2ND_HARM 9 #define DTMF_COL_2ND_HARM 10 #define DTMF_PWR_MIN_THRESH 11 #define DTMF_HOT_LIM_THRESH 12 #define OSC1_COEF 13 #define OSC1X 14 #define OSC1Y 15 #define OSC2_COEF 16 #define OSC2X 17 #define OSC2Y 18 #define RING_V_OFF 19 #define RING_OSC_COEF 20 #define RING_X 21 #define RING_Y 22 #define PULSE_ENVEL 23 #define PULSE_X 24 #define PULSE_Y 25 #define RECV_DIGITAL_GAIN 26 #define XMIT_DIGITAL_GAIN 27 #define LOOP_CLOSE_THRESH 28 #define RING_TRIP_THRESH 29 #define COMMON_MIN_THRESH 30 #define COMMON_MAX_THRESH 31 #define PWR_ALARM_Q1Q2 32 #define PWR_ALARM_Q3Q4 33 #define PWR_ALARM_Q5Q6 34 #define LOOP_CLOSURE_FILTER 35 #define RING_TRIP_FILTER 36 #define THERM_LP_POLE_Q1Q2 37 #define THERM_LP_POLE_Q3Q4 38 #define THERM_LP_POLE_Q5Q6 39 #define CM_BIAS_RINGING 40 #define DCDC_MIN_V 41 #define DCDC_XTRA 42 dahdi-linux-2.5.0.1/drivers/dahdi/dahdi_dynamic.c0000644000175000017500000004766311621031742021474 0ustar tzafrirtzafrir/* * Dynamic Span Interface for DAHDI * * Written by Mark Spencer * * Copyright (C) 2001-2010, Digium, Inc. * * All rights reserved. * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #ifndef DAHDI_SYNC_TICK #error "Dynamic support depends on DAHDI_SYNC_TICK being enabled." #endif /* * Tasklets provide better system interactive response at the cost of the * possibility of losing a frame of data at very infrequent intervals. If * you are more concerned with the performance of your machine, enable the * tasklets. If you are strict about absolutely no drops, then do not enable * tasklets. */ #undef ENABLE_TASKLETS /* * Dynamic spans implemented using TDM over X with standard message * types. Message format is as follows: * * Byte #: Meaning * 0 Number of samples per channel * 1 Current flags on span * Bit 0: Yellow Alarm * Bit 1: Sig bits present * Bits 2-7: reserved for future use * 2-3 16-bit counter value for detecting drops, network byte order. * 4-5 Number of channels in the message, network byte order * 6... 16-bit words, containing sig bits for each * four channels, least significant 4 bits being * the least significant channel, network byte order. * the rest data for each channel, all samples per channel before moving to the next. */ #define DAHDI_DYNAMIC_FLAG_YELLOW_ALARM (1 << 0) #define DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT (1 << 1) #define DAHDI_DYNAMIC_FLAG_LOOPBACK (1 << 2) #define ERR_NSAMP (1 << 16) #define ERR_NCHAN (1 << 17) #define ERR_LEN (1 << 18) static int dahdi_dynamic_init(void); static void dahdi_dynamic_cleanup(void); #ifdef ENABLE_TASKLETS static int taskletrun; static int taskletsched; static int taskletpending; static int taskletexec; static int txerrors; static struct tasklet_struct dahdi_dynamic_tlet; static void dahdi_dynamic_tasklet(unsigned long data); #endif static DEFINE_MUTEX(dspan_mutex); static DEFINE_SPINLOCK(dspan_lock); static DEFINE_SPINLOCK(driver_lock); static LIST_HEAD(dspan_list); static LIST_HEAD(driver_list); static int debug = 0; static int hasmaster = 0; static void checkmaster(void) { int newhasmaster=0; int best = 9999999; struct dahdi_dynamic *d, *master = NULL; rcu_read_lock(); list_for_each_entry_rcu(d, &dspan_list, list) { if (d->timing) { d->master = 0; if (!(d->span.alarms & DAHDI_ALARM_RED) && (d->timing < best)) { /* If not in alarm and they're a better timing source, use them */ master = d; best = d->timing; newhasmaster = 1; } } } hasmaster = newhasmaster; /* Mark the new master if there is one */ if (master) master->master = 1; rcu_read_unlock(); if (master) printk(KERN_INFO "TDMoX: New master: %s\n", master->span.name); else printk(KERN_INFO "TDMoX: No master.\n"); } static void dahdi_dynamic_sendmessage(struct dahdi_dynamic *d) { unsigned char *buf = d->msgbuf; unsigned short bits; int msglen = 0; int x; int offset; /* Byte 0: Number of samples per channel */ *buf = DAHDI_CHUNKSIZE; buf++; msglen++; /* Byte 1: Flags */ *buf = 0; if (d->span.alarms & DAHDI_ALARM_RED) *buf |= DAHDI_DYNAMIC_FLAG_YELLOW_ALARM; *buf |= DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT; buf++; msglen++; /* Bytes 2-3: Transmit counter */ *((unsigned short *)buf) = htons((unsigned short)d->txcnt); d->txcnt++; buf++; msglen++; buf++; msglen++; /* Bytes 4-5: Number of channels */ *((unsigned short *)buf) = htons((unsigned short)d->span.channels); buf++; msglen++; buf++; msglen++; bits = 0; offset = 0; for (x = 0; x < d->span.channels; x++) { offset = x % 4; bits |= (d->chans[x]->txsig & 0xf) << (offset << 2); if (offset == 3) { /* Write the bits when we have four channels */ *((unsigned short *)buf) = htons(bits); buf++; msglen++; buf++; msglen++; bits = 0; } } if (offset != 3) { /* Finish it off if it's not done already */ *((unsigned short *)buf) = htons(bits); buf++; msglen++; buf++; msglen++; } for (x = 0; x < d->span.channels; x++) { memcpy(buf, d->chans[x]->writechunk, DAHDI_CHUNKSIZE); buf += DAHDI_CHUNKSIZE; msglen += DAHDI_CHUNKSIZE; } d->driver->transmit(d, d->msgbuf, msglen); } static void __dahdi_dynamic_run(void) { struct dahdi_dynamic *d; struct dahdi_dynamic_driver *drv; rcu_read_lock(); list_for_each_entry_rcu(d, &dspan_list, list) { dahdi_transmit(&d->span); /* Handle all transmissions now */ dahdi_dynamic_sendmessage(d); } list_for_each_entry_rcu(drv, &driver_list, list) { /* Flush any traffic still pending in the driver */ if (drv->flush) { drv->flush(); } } rcu_read_unlock(); } #ifdef ENABLE_TASKLETS static void dahdi_dynamic_run(void) { if (likely(!taskletpending)) { taskletpending = 1; taskletsched++; tasklet_hi_schedule(&dahdi_dynamic_tlet); } else { txerrors++; } } #else #define dahdi_dynamic_run __dahdi_dynamic_run #endif static inline struct dahdi_dynamic *dynamic_from_span(struct dahdi_span *span) { return container_of(span, struct dahdi_dynamic, span); } void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen) { struct dahdi_dynamic *dtd = dynamic_from_span(span); int newerr=0; int sflags; int xlen; int x, bits, sig; int nchans, master; int newalarm; unsigned short rxpos, rxcnt; rcu_read_lock(); if (unlikely(msglen < 6)) { rcu_read_unlock(); newerr = ERR_LEN; if (newerr != dtd->err) printk(KERN_NOTICE "Span %s: Insufficient samples for header (only %d)\n", span->name, msglen); dtd->err = newerr; return; } /* First, check the chunksize */ if (unlikely(*msg != DAHDI_CHUNKSIZE)) { rcu_read_unlock(); newerr = ERR_NSAMP | msg[0]; if (newerr != dtd->err) printk(KERN_NOTICE "Span %s: Expected %d samples, but receiving %d\n", span->name, DAHDI_CHUNKSIZE, msg[0]); dtd->err = newerr; return; } msg++; sflags = *msg; msg++; rxpos = ntohs(*((unsigned short *)msg)); msg++; msg++; nchans = ntohs(*((unsigned short *)msg)); if (unlikely(nchans != span->channels)) { rcu_read_unlock(); newerr = ERR_NCHAN | nchans; if (newerr != dtd->err) printk(KERN_NOTICE "Span %s: Expected %d channels, but receiving %d\n", span->name, span->channels, nchans); dtd->err = newerr; return; } msg++; msg++; /* Okay now we've accepted the header, lets check our message length... */ /* Start with header */ xlen = 6; /* Add samples of audio */ xlen += nchans * DAHDI_CHUNKSIZE; /* If RBS info is there, add that */ if (sflags & DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT) { /* Account for sigbits -- one short per 4 channels*/ xlen += ((nchans + 3) / 4) * 2; } if (unlikely(xlen != msglen)) { rcu_read_unlock(); newerr = ERR_LEN | xlen; if (newerr != dtd->err) printk(KERN_NOTICE "Span %s: Expected message size %d, but was %d instead\n", span->name, xlen, msglen); dtd->err = newerr; return; } bits = 0; /* Record sigbits if present */ if (sflags & DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT) { for (x=0;x> ((x % 4) << 2)) & 0xff; /* Update signalling if appropriate */ if (sig != span->chans[x]->rxsig) dahdi_rbsbits(span->chans[x], sig); } } /* Record data for channels */ for (x=0;xchans[x]->readchunk, msg, DAHDI_CHUNKSIZE); msg += DAHDI_CHUNKSIZE; } master = dtd->master; rxcnt = dtd->rxcnt; dtd->rxcnt = rxpos+1; /* Keep track of last received packet */ dtd->rxjif = jiffies; rcu_read_unlock(); /* Check for Yellow alarm */ newalarm = span->alarms & ~(DAHDI_ALARM_YELLOW | DAHDI_ALARM_RED); if (sflags & DAHDI_DYNAMIC_FLAG_YELLOW_ALARM) newalarm |= DAHDI_ALARM_YELLOW; if (newalarm != span->alarms) { span->alarms = newalarm; dahdi_alarm_notify(span); checkmaster(); } /* note if we had a missing packet */ if (unlikely(rxpos != rxcnt)) printk(KERN_NOTICE "Span %s: Expected seq no %d, but received %d instead\n", span->name, rxcnt, rxpos); dahdi_ec_span(span); dahdi_receive(span); /* If this is our master span, then run everything */ if (master) dahdi_dynamic_run(); } EXPORT_SYMBOL(dahdi_dynamic_receive); /** * dahdi_dynamic_release() - Free the memory associated with the dahdi_dynamic. * @kref: Pointer to kref embedded in dahdi_dynamic structure. * */ static void dahdi_dynamic_release(struct kref *kref) { struct dahdi_dynamic *d = container_of(kref, struct dahdi_dynamic, kref); unsigned int x; WARN_ON(test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags)); if (d->pvt) { if (d->driver && d->driver->destroy) { __module_get(d->driver->owner); d->driver->destroy(d); module_put(d->driver->owner); } else { WARN_ON(1); } } kfree(d->msgbuf); for (x = 0; x < d->span.channels; x++) kfree(d->chans[x]); kfree(d); } static inline int dynamic_put(struct dahdi_dynamic *d) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) kref_put(&d->kref, dahdi_dynamic_release); return 1; #else return kref_put(&d->kref, dahdi_dynamic_release); #endif } static inline void dynamic_get(struct dahdi_dynamic *d) { kref_get(&d->kref); } static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *dds) { struct dahdi_dynamic *d = NULL, *found = NULL; rcu_read_lock(); list_for_each_entry_rcu(d, &dspan_list, list) { if (!strcmp(d->dname, dds->driver) && !strcmp(d->addr, dds->addr)) { dynamic_get(d); found = d; break; } } rcu_read_unlock(); return found; } static struct dahdi_dynamic_driver *find_driver(const char *name) { struct dahdi_dynamic_driver *dtd, *found = NULL; rcu_read_lock(); list_for_each_entry_rcu(dtd, &driver_list, list) { /* here's our driver */ if (!strcmp(name, dtd->name)) { found = dtd; break; } } rcu_read_unlock(); return found; } static int _destroy_dynamic(struct dahdi_dynamic_span *dds) { unsigned long flags; struct dahdi_dynamic *d; d = find_dynamic(dds); if (unlikely(!d)) return -EINVAL; /* We shouldn't have more than the two references at this point. If * we do, there are probably channels that are still opened. */ if (atomic_read(&d->kref.refcount) > 2) { dynamic_put(d); return -EBUSY; } dahdi_unregister(&d->span); spin_lock_irqsave(&dspan_lock, flags); list_del_rcu(&d->list); spin_unlock_irqrestore(&dspan_lock, flags); synchronize_rcu(); /* One since we've removed the item from the list... */ dynamic_put(d); /* ...and one for find_dynamic. */ dynamic_put(d); return 0; } static int destroy_dynamic(struct dahdi_dynamic_span *dds) { int ret; mutex_lock(&dspan_mutex); ret = _destroy_dynamic(dds); mutex_unlock(&dspan_mutex); return ret; } static int dahdi_dynamic_rbsbits(struct dahdi_chan *chan, int bits) { /* Don't have to do anything */ return 0; } static int dahdi_dynamic_open(struct dahdi_chan *chan) { struct dahdi_dynamic *d = dynamic_from_span(chan->span); if (!try_module_get(d->driver->owner)) return -ENODEV; dynamic_get(d); return 0; } static int dahdi_dynamic_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) { return 0; } static int dahdi_dynamic_close(struct dahdi_chan *chan) { struct dahdi_dynamic *d = dynamic_from_span(chan->span); struct module *owner = d->driver->owner; dynamic_put(d); module_put(owner); return 0; } static void dahdi_dynamic_sync_tick(struct dahdi_span *span, int is_master) { struct dahdi_dynamic *head; struct dahdi_dynamic *d = dynamic_from_span(span); if (hasmaster) return; rcu_read_lock(); head = list_entry(dspan_list.next, struct dahdi_dynamic, list); rcu_read_unlock(); if (d == head) dahdi_dynamic_run(); return; } static const struct dahdi_span_ops dynamic_ops = { .owner = THIS_MODULE, .rbsbits = dahdi_dynamic_rbsbits, .open = dahdi_dynamic_open, .close = dahdi_dynamic_close, .chanconfig = dahdi_dynamic_chanconfig, .sync_tick = dahdi_dynamic_sync_tick, }; static int _create_dynamic(struct dahdi_dynamic_span *dds) { int res = 0; struct dahdi_dynamic *d; struct dahdi_dynamic_driver *dtd; unsigned long flags; int x; int bufsize; if (dds->numchans < 1) { printk(KERN_NOTICE "Can't be less than 1 channel (%d)!\n", dds->numchans); return -EINVAL; } if (dds->numchans >= ARRAY_SIZE(d->chans)) { printk(KERN_NOTICE "Can't create dynamic span with greater " "than %d channels. See dahdi_dynamic.c and increase " "DAHDI_DYNAMIC_MAX_CHANS\n", dds->numchans); return -EINVAL; } d = find_dynamic(dds); if (d) { dynamic_put(d); return -EEXIST; } d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; kref_init(&d->kref); for (x = 0; x < dds->numchans; x++) { d->chans[x] = kzalloc(sizeof(*d->chans[x]), GFP_KERNEL); if (!d->chans[x]) { dynamic_put(d); return -ENOMEM; } d->span.channels++; } /* Allocate message buffer with sample space and header space */ bufsize = dds->numchans * DAHDI_CHUNKSIZE + dds->numchans / 4 + 48; d->msgbuf = kzalloc(bufsize, GFP_KERNEL); if (!d->msgbuf) { dynamic_put(d); return -ENOMEM; } /* Setup parameters properly assuming we're going to be okay. */ strlcpy(d->dname, dds->driver, sizeof(d->dname)); strlcpy(d->addr, dds->addr, sizeof(d->addr)); d->timing = dds->timing; sprintf(d->span.name, "DYN/%s/%s", dds->driver, dds->addr); sprintf(d->span.desc, "Dynamic '%s' span at '%s'", dds->driver, dds->addr); d->span.deflaw = DAHDI_LAW_MULAW; d->span.flags |= DAHDI_FLAG_RBS; d->span.chans = d->chans; d->span.ops = &dynamic_ops; for (x = 0; x < d->span.channels; x++) { sprintf(d->chans[x]->name, "DYN/%s/%s/%d", dds->driver, dds->addr, x+1); d->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOKS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_DACS_RBS | DAHDI_SIG_CAS; d->chans[x]->chanpos = x + 1; d->chans[x]->pvt = d; } dtd = find_driver(dds->driver); if (!dtd) { request_module("dahdi_dynamic_%s", dds->driver); dtd = find_driver(dds->driver); } if (!dtd) { printk(KERN_NOTICE "No such driver '%s' for dynamic span\n", dds->driver); dynamic_put(d); return -EINVAL; } if (!try_module_get(dtd->owner)) { dynamic_put(d); return -ENODEV; } /* Remember the driver. We also give our reference to the driver to * the dahdi_dyanmic here. Do not access dtd directly now. */ d->driver = dtd; /* Create the stuff */ res = dtd->create(d, d->addr); if (res) { printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n", dtd->name, dtd->desc, d->addr); dynamic_put(d); module_put(dtd->owner); return res; } /* Whee! We're created. Now register the span */ if (dahdi_register(&d->span, 0)) { printk(KERN_NOTICE "Unable to register span '%s'\n", d->span.name); dynamic_put(d); module_put(dtd->owner); return -EINVAL; } x = d->span.spanno; /* Transfer our reference to the dspan_list. Do not touch d after * this point. It also must remain on the list while registered. */ spin_lock_irqsave(&dspan_lock, flags); list_add_rcu(&d->list, &dspan_list); spin_unlock_irqrestore(&dspan_lock, flags); checkmaster(); module_put(dtd->owner); return x; } static int create_dynamic(struct dahdi_dynamic_span *dds) { int ret; mutex_lock(&dspan_mutex); ret = _create_dynamic(dds); mutex_unlock(&dspan_mutex); return ret; } #ifdef ENABLE_TASKLETS static void dahdi_dynamic_tasklet(unsigned long data) { taskletrun++; if (taskletpending) { taskletexec++; __dahdi_dynamic_run(); } taskletpending = 0; } #endif static int dahdi_dynamic_ioctl(unsigned int cmd, unsigned long data) { struct dahdi_dynamic_span dds; int res; switch(cmd) { case DAHDI_DYNAMIC_CREATE: if (copy_from_user(&dds, (__user const void *)data, sizeof(dds))) return -EFAULT; if (debug) printk(KERN_DEBUG "Dynamic Create\n"); res = create_dynamic(&dds); if (res < 0) return res; dds.spanno = res; /* Let them know the new span number */ if (copy_to_user((__user void *) data, &dds, sizeof(dds))) return -EFAULT; return 0; case DAHDI_DYNAMIC_DESTROY: if (copy_from_user(&dds, (__user const void *)data, sizeof(dds))) return -EFAULT; if (debug) printk(KERN_DEBUG "Dynamic Destroy\n"); return destroy_dynamic(&dds); } return -ENOTTY; } int dahdi_dynamic_register_driver(struct dahdi_dynamic_driver *dri) { unsigned long flags; int res = 0; if (!dri->owner) return -EINVAL; if (find_driver(dri->name)) { res = -1; } else { spin_lock_irqsave(&driver_lock, flags); list_add_rcu(&dri->list, &driver_list); spin_unlock_irqrestore(&driver_lock, flags); } return res; } EXPORT_SYMBOL(dahdi_dynamic_register_driver); void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *dri) { struct dahdi_dynamic *d, *n; unsigned long flags; mutex_lock(&dspan_mutex); list_for_each_entry_safe(d, n, &dspan_list, list) { if (d->driver == dri) { if (d->pvt) { if (d->driver && d->driver->destroy) { __module_get(d->driver->owner); d->driver->destroy(d); module_put(d->driver->owner); } else { WARN_ON(1); } } dahdi_unregister(&d->span); spin_lock_irqsave(&dspan_lock, flags); list_del_rcu(&d->list); spin_unlock_irqrestore(&dspan_lock, flags); synchronize_rcu(); dynamic_put(d); } } spin_lock_irqsave(&driver_lock, flags); list_del_rcu(&dri->list); spin_unlock_irqrestore(&driver_lock, flags); synchronize_rcu(); mutex_unlock(&dspan_mutex); } EXPORT_SYMBOL(dahdi_dynamic_unregister_driver); static struct timer_list alarmcheck; static void check_for_red_alarm(unsigned long ignored) { int newalarm; int alarmchanged = 0; struct dahdi_dynamic *d; rcu_read_lock(); list_for_each_entry_rcu(d, &dspan_list, list) { newalarm = d->span.alarms & ~DAHDI_ALARM_RED; /* If nothing received for a second, consider that RED ALARM */ if ((jiffies - d->rxjif) > 1 * HZ) { newalarm |= DAHDI_ALARM_RED; if (d->span.alarms != newalarm) { d->span.alarms = newalarm; dahdi_alarm_notify(&d->span); alarmchanged++; } } } rcu_read_unlock(); if (alarmchanged) checkmaster(); /* Do the next one */ mod_timer(&alarmcheck, jiffies + 1 * HZ); } static int dahdi_dynamic_init(void) { dahdi_set_dynamic_ioctl(dahdi_dynamic_ioctl); /* Start process to check for RED ALARM */ init_timer(&alarmcheck); alarmcheck.expires = 0; alarmcheck.data = 0; alarmcheck.function = check_for_red_alarm; /* Check once per second */ mod_timer(&alarmcheck, jiffies + 1 * HZ); #ifdef ENABLE_TASKLETS tasklet_init(&dahdi_dynamic_tlet, dahdi_dynamic_tasklet, 0); #endif printk(KERN_INFO "DAHDI Dynamic Span support LOADED\n"); return 0; } static void dahdi_dynamic_cleanup(void) { #ifdef ENABLE_TASKLETS if (taskletpending) { tasklet_disable(&dahdi_dynamic_tlet); tasklet_kill(&dahdi_dynamic_tlet); } #endif dahdi_set_dynamic_ioctl(NULL); del_timer(&alarmcheck); printk(KERN_INFO "DAHDI Dynamic Span support unloaded\n"); } module_param(debug, int, 0600); MODULE_DESCRIPTION("DAHDI Dynamic Span Support"); MODULE_AUTHOR("Mark Spencer "); MODULE_LICENSE("GPL v2"); module_init(dahdi_dynamic_init); module_exit(dahdi_dynamic_cleanup);