## oslec_zaptap by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
##
##  The zaptap device for sampling echo. Part of the oslec echo canceller.

diff -urNad zaptel-1.2.17.1.xpp.r3965~/zaptel-base.c zaptel-1.2.17.1.xpp.r3965/zaptel-base.c
--- zaptel-1.2.17.1.xpp.r3965~/kernel/zaptel-base.c	2007-06-16 07:10:17.000000000 +0300
+++ zaptel-1.2.17.1.xpp.r3965/kernel/zaptel-base.c	2007-06-16 07:55:33.000000000 +0300
@@ -5708,6 +5708,74 @@
 	spin_unlock_irqrestore(&chan->lock, flags);
 }
 
+#ifdef USE_ZAPTAP
+/* Zaptap code -----------------------------------------------------------*/
+
+#define SAMPLE_BUF_SZ  1000 
+#define SAMPLE_IDLE    0
+#define SAMPLE_PING    1
+#define SAMPLE_PONG    2
+
+DECLARE_WAIT_QUEUE_HEAD(sample_wait);
+static int sample_state = 0;
+static int samples = 0;
+static short *psample;
+static short ping[3*SAMPLE_BUF_SZ];
+static short pong[3*SAMPLE_BUF_SZ];
+static int sample_ch = 1;
+static int sample_impulse = 0;
+static int tmp1,tmp2;
+
+static inline void sample_echo_before(int channo, short rxlin, short txlin) {
+	/* Sample echo canceller signals
+	 * Notes:
+	 *   1. Samples are multiplexed in buffer:
+	 *        tx sample
+	 *        rx sample
+	 *        ec sample
+	 *   2. We needs to sample rx here before echo can as it is
+	 *      overwritten.
+	 */
+	tmp1++;
+	tmp2 = channo;
+	if ((sample_state != SAMPLE_IDLE) && (channo == sample_ch)) {
+		*psample++ = txlin;
+		*psample++ = rxlin;
+	}
+}
+
+static inline void sample_echo_after(int channo, short rxlin) {
+
+	if ((sample_state != SAMPLE_IDLE) && (channo == sample_ch)) {
+
+		*psample++ = rxlin;
+
+		/* sample collection ping-pong buffer logic */
+
+		samples++;
+		if (samples >= SAMPLE_BUF_SZ) {
+			/* time to swap buffers */
+			samples = 0;
+
+			if (sample_state == SAMPLE_PING) {
+				sample_state = SAMPLE_PONG;
+				psample = pong;
+			}
+			else {
+				sample_state = SAMPLE_PING;
+				psample = ping;
+			}
+			wake_up_interruptible(&sample_wait);
+		}
+	}
+}
+
+/* end Zaptap code -----------------------------------------------------*/
+#else /* USE_ZAPTAP */
+#define sample_echo_before(a,b,c)
+#define sample_echo_after(a,b)
+#endif /* USE_ZAPTAP */
+
 static inline void __zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
 {
 	short rxlin, txlin;
@@ -5758,7 +5826,9 @@
 #if !defined(ZT_EC_ARRAY_UPDATE)
 			for (x=0;x<ZT_CHUNKSIZE;x++) {
 				rxlin = ZT_XLAW(rxchunk[x], ss);
+				sample_echo_before(ss->channo, rxlin, ZT_XLAW(txchunk[x], ss)); /* Zaptap code */
 				rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin);
+				sample_echo_after(ss->channo, rxlin);                           /* Zaptap code */
 				rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
 			}
 #else /* defined(ZT_EC_ARRAY_UPDATE) */
@@ -6505,6 +6575,10 @@
 static void __zt_transmit_chunk(struct zt_chan *chan, unsigned char *buf)
 {
 	unsigned char silly[ZT_CHUNKSIZE];
+#ifdef USE_ZAPTAP
+	int x;
+#endif
+
 	/* Called with chan->lock locked */
 	if (!buf)
 		buf = silly;
@@ -6519,6 +6593,22 @@
 		kernel_fpu_end();
 #endif
 	}
+
+#ifdef USE_ZAPTAP
+	/* Start Zaptap code -----------------------------------------*/
+	if (sample_impulse && (samples == 0)) {
+
+		/* option impulse insertion, tx stream becomes one */
+                /* impulse followed by SAMPLE_BUF_SZ-1 0's         */
+
+		buf[0] = ZT_LIN2MU(10000);
+		for (x=1;x<ZT_CHUNKSIZE;x++) {
+		    buf[x] = ZT_LIN2MU(0);
+		}
+	}
+
+	/* End Zaptap code -----------------------------------------*/
+#endif USE_ZAPTAP
 }
 
 static inline void __zt_real_transmit(struct zt_chan *chan)
@@ -6931,6 +7021,108 @@
 
 #endif
 
+#ifdef USE_ZAPTAP
+/* Zaptap code -----------------------------------------------------*/
+
+static int sample_open (struct inode *inode, struct file *file) {
+	printk("sample_open:\n");
+	tmp1 = tmp2 = -1;
+
+	psample = ping;
+	samples = 0;
+	sample_state = SAMPLE_PING;
+
+	return 0;
+}
+
+static int sample_release (struct inode *inode, struct file *file) {
+	printk("sample_release: tmp1 = %d tmp2 = %d\n", tmp1, tmp2);
+
+	sample_state = SAMPLE_IDLE;
+	sample_impulse = 0;
+	samples = 0;
+
+	return 0;
+}
+
+static ssize_t sample_read(struct file *file, char *buf,
+		size_t count, loff_t *ppos) {
+	int    err, len;
+	short *pread;
+
+	/* wait for next buffer to be prepared by ISR, we read
+           alternate buffer just after transition.
+         */
+	interruptible_sleep_on(&sample_wait);
+
+	if (sample_state == SAMPLE_PING) {
+	  pread = pong;
+	}
+	else {
+	  pread = ping;
+	}
+
+	len = 3*sizeof(short)*SAMPLE_BUF_SZ;
+	err = copy_to_user(buf, pread, len);
+
+	if (err != 0)
+		return -EFAULT;
+
+	return len;
+}
+
+/* ioctls for sample */
+
+#define SAMPLE_SET_CHANNEL 0
+#define SAMPLE_TX_IMPULSE  1
+
+static int sample_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg) {
+	int retval = 0;
+
+	switch ( cmd ) {
+		case SAMPLE_SET_CHANNEL:
+		  if (copy_from_user(&sample_ch, (int *)arg, sizeof(int)))
+		    return -EFAULT;
+	          printk("sample_ioctl: sample_ch = %d\n", sample_ch);
+		  break;
+		case SAMPLE_TX_IMPULSE:
+		  sample_impulse = 1;
+		  printk("sample_ioctl: under impulse power\n");
+		  break;
+		default:
+		  retval = -EINVAL;
+        }
+
+	return retval;
+}
+
+// define which file operations are supported
+struct file_operations sample_fops = {
+	.owner	=	THIS_MODULE,
+	.llseek	=	NULL,
+	.read	=	sample_read,
+	.write	=	NULL,
+	.readdir=	NULL,
+	.poll	=	NULL,
+	.ioctl	=	sample_ioctl,
+	.mmap	=	NULL,
+	.open	=	sample_open,
+	.flush	=	NULL,
+	.release=	sample_release,
+	.fsync	=	NULL,
+	.fasync	=	NULL,
+	.lock	=	NULL,
+	.readv	=	NULL,
+	.writev	=	NULL,
+};
+
+#define SAMPLE_NAME  "sample"
+#define SAMPLE_MAJOR 33
+
+/* end Zaptap code -----------------------------------------------------*/
+#endif USE_ZAPTAP
+
 static int __init zt_init(void) {
 	int res = 0;
 
@@ -6977,12 +7169,28 @@
 #ifdef CONFIG_ZAPTEL_WATCHDOG
 	watchdog_init();
 #endif	
+
+#ifdef USE_ZAPTAP
+	/* start Zaptap code ----------------------------------------*/
+	sample_state = SAMPLE_IDLE;
+	sample_impulse = 0;
+	if ((res = register_chrdev (SAMPLE_MAJOR, SAMPLE_NAME, &sample_fops))) {
+	  printk(KERN_ERR "Zaptap unable to register 'sample' char driver on %d\n", SAMPLE_MAJOR);
+	  return res;
+	}
+	printk("Zaptap registered 'sample' char driver on major %d\n", SAMPLE_MAJOR);
+	/* end Zaptap code ------------------------------------------*/
+#endif /* USE_ZAPTAP */
+
 	return res;
 }
 
 static void __exit zt_cleanup(void) {
 	int x;
 
+#ifdef USE_ZAPTAP
+	unregister_chrdev (SAMPLE_MAJOR, SAMPLE_NAME); /* Zaptap code */
+#endif
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("zaptel", NULL);
 #endif
