--- base.c	2008-04-04 19:47:58.000000000 +0200
+++ base.c-mod	2008-05-03 10:59:42.000000000 +0200
@@ -196,6 +196,10 @@
 #ifdef VPM_SUPPORT
 static int vpmsupport = 1;
 static int vpmdtmfsupport = 0;
+static int cidbeforering = 0;
+static int cidbuflen = 3000;    /* in msec, default 3000 */
+static int cidtimeout = 6*1000; /* in msec, default 6000 */
+
 #define VPM_DEFAULT_DTMFTHRESHOLD 1250
 static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
 /*
@@ -875,6 +879,55 @@
 
 		readchunk += (EFRAME_SIZE + EFRAME_GAP);
 	}
+
+        if(cidbeforering)
+        {
+                for(x=0; x<wc->max_cards; x++)
+                {
+                        if (wc->modtype[wc->chans[x].chanpos - 1] == MOD_TYPE_FXO)
+                                if(wc->mods[wc->chans[x].chanpos - 1].fxo.offhook == 0)
+                                {
+                                        /*unsigned int *p_readchunk, *p_cid_history;
+                                        
+                                        p_readchunk = (unsigned int*)wc->chans[x].readchunk;
+                                        p_cid_history = (unsigned int*)(wc->cid_history_buf[x] + wc->cid_history_ptr[x]);*/
+                                        
+                                        if(wc->cid_state[x] == CID_STATE_IDLE)  /* we need copy data to the cid voice buffer */
+                                        {
+                                                memcpy(wc->cid_history_buf[x] + wc->cid_history_ptr[x], wc->chans[x].readchunk, ZT_CHUNKSIZE);
+                                                wc->cid_history_ptr[x] = (wc->cid_history_ptr[x] + ZT_CHUNKSIZE)%(cidbuflen * ZT_MAX_CHUNKSIZE);
+                                        }
+                                        else if (wc->cid_state[x] == CID_STATE_RING_ON)
+                                                wc->cid_history_clone_cnt[x] = cidbuflen;
+                                        else if (wc->cid_state[x] == CID_STATE_RING_OFF)
+                                        { 
+                                                if(wc->cid_history_clone_cnt[x])
+                                                {       
+                                                        memcpy(wc->chans[x].readchunk, wc->cid_history_buf[x] + wc->cid_history_ptr[x], ZT_MAX_CHUNKSIZE);
+                                                        wc->cid_history_clone_cnt[x]--;
+                                                        wc->cid_history_ptr[x] = (wc->cid_history_ptr[x] + ZT_MAX_CHUNKSIZE)%(cidbuflen * ZT_MAX_CHUNKSIZE);
+                                                }
+                                                else
+                                                {
+                                                        wc->cid_state[x] = CID_STATE_WAIT_RING_FINISH;
+                                                        wc->cid_history_clone_cnt[x] = cidtimeout; /* wait 6 sec, if no ring, return to idle */
+                                                }
+                                        }
+                                        else if(wc->cid_state[x] == CID_STATE_WAIT_RING_FINISH)
+                                        {
+                                                if(wc->cid_history_clone_cnt[x] > 0)
+                                                        wc->cid_history_clone_cnt[x]--;
+                                                else
+                                                {
+                                                        wc->cid_state[x] = CID_STATE_IDLE;
+                                                        wc->cid_history_ptr[x] = 0;
+                                                        wc->cid_history_clone_cnt[x] = 0;
+                                                }
+                                        }
+                                }
+                }               
+        }
+
 	/* XXX We're wasting 8 taps.  We should get closer :( */
 	if (likely(wc->initialized)) {
 		for (x=0;x<wc->type;x++) {
@@ -1150,7 +1203,15 @@
 						fxo->wasringing = 1;
 						if (debug)
 							printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
-						zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+                                                if(cidbeforering)
+                                                {
+                                                        if(wc->cid_state[card] == CID_STATE_IDLE)
+                                                                wc->cid_state[card] = CID_STATE_RING_ON;
+                                                        else
+                                                                zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+                                                }
+                                                else
+							zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
 					}
 					fxo->lastrdtx = res;
 					fxo->ringdebounce = 10;
@@ -1159,7 +1220,22 @@
 						fxo->wasringing = 0;
 						if (debug)
 							printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
-						zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+                                                if(cidbeforering)
+                                                {
+                                                        if(wc->cid_state[card] == CID_STATE_RING_ON)
+                                                        {
+                                                                zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+                                                                wc->cid_state[card] = CID_STATE_RING_OFF;
+                                                        }
+                                                        else 
+                                                        {
+                                                                if(wc->cid_state[card] == CID_STATE_WAIT_RING_FINISH)
+                                                                        wc->cid_history_clone_cnt[card] = cidtimeout;
+                                                                zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+                                                        }
+                                                }
+                                                else
+							zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
 					}
 				}
 			} else if (res && (fxo->battery == BATTERY_PRESENT)) {
@@ -1173,7 +1249,15 @@
 				if (fxo->ringdebounce >= ZT_CHUNKSIZE * ringdebounce) {
 					if (!fxo->wasringing) {
 						fxo->wasringing = 1;
-						zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+                                                if(cidbeforering)
+                                                {
+                                                        if(wc->cid_state[card] == CID_STATE_IDLE)
+                                                                wc->cid_state[card] = CID_STATE_RING_ON;
+                                                        else
+                                                                zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+                                                }
+                                                else
+							zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
 						if (debug)
 							printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
 					}
@@ -1184,7 +1268,22 @@
 				if (fxo->ringdebounce <= 0) {
 					if (fxo->wasringing) {
 						fxo->wasringing = 0;
-						zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+                                                if(cidbeforering)
+                                                {
+                                                        if(wc->cid_state[card] == CID_STATE_RING_ON)
+                                                        {
+                                                                zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+                                                                wc->cid_state[card] = CID_STATE_RING_OFF;
+                                                        }
+                                                        else 
+                                                        {
+                                                                if(wc->cid_state[card] == CID_STATE_WAIT_RING_FINISH)
+                                                                        wc->cid_history_clone_cnt[card] = cidtimeout;
+                                                                zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+                                                        }
+                                                }
+                                                else
+							zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
 						if (debug)
 							printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
 					}
@@ -2684,6 +2783,13 @@
 		case ZT_TXSIG_OFFHOOK:
 			wc->mods[chan->chanpos - 1].fxo.offhook = 1;
 			wc->sethook[chan->chanpos - 1] = CMD_WR(5, 0x9);
+                        if(cidbeforering)
+                        {
+                                wc->cid_state[chan->chanpos - 1] = CID_STATE_IDLE;
+                                wc->cid_history_clone_cnt[chan->chanpos - 1] = 0;
+                                wc->cid_history_ptr[chan->chanpos - 1] = 0;
+                                //memset(wc->cid_history_buf[chan->chanpos - 1], ZT_LIN2X(0, chan), cidbuflen * ZT_MAX_CHUNKSIZE);
+                        }
 			/* wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9); */
 			break;
 		case ZT_TXSIG_ONHOOK:
@@ -3760,6 +3866,7 @@
 	struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
 	int i;
 	int y;
+	int x;
 	int ret;
 
 retry:
@@ -3837,6 +3944,21 @@
 		wctdm_release(wc);
 		goto retry;
 	}
+
+                        if(cidbeforering) 
+                        {               
+                                int len = cidbuflen * ZT_MAX_CHUNKSIZE;
+                                if(debug)
+                                        printk("cidbeforering support enabled, length is %d msec\n", cidbuflen);
+                                for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) 
+                                {
+                                        wc->cid_history_buf[x] = kmalloc(len, GFP_KERNEL);
+                                        wc->cid_history_ptr[x] = 0;
+                                        wc->cid_history_clone_cnt[x] = 0;
+                                        wc->cid_state[x] = CID_STATE_IDLE;
+                                }
+                        }
+
 	
 	/* Final initialization */
 	wctdm_post_initialize(wc);
@@ -3872,6 +3994,13 @@
 			break;
 	ifaces[i] = NULL;
 	spin_unlock(&ifacelock);
+
+        if(cidbeforering) 
+        {
+                int x;
+                for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) 
+                        kfree(wc->cid_history_buf[x]);
+        }
 	
 	kfree(wc);
 }
@@ -4012,6 +4141,9 @@
 module_param(ringdebounce, int, 0600);
 module_param(fwringdetect, int, 0600);
 module_param(latency, int, 0600);
+module_param(cidbeforering, int, 0600);
+module_param(cidbuflen, int, 0600);
+module_param(cidtimeout, int, 0600);
 #ifdef VPM_SUPPORT
 module_param(vpmsupport, int, 0600);
 module_param(vpmdtmfsupport, int, 0600);
@@ -4041,6 +4173,9 @@
 MODULE_PARM(fxsrxgain, "i");
 MODULE_PARM(ringdebounce, "i");
 MODULE_PARM(fwringdetect, "i");
+MODULE_PARM(cidbeforering, "i");
+MODULE_PARM(cidbuflen, "i");
+MODULE_PARM(cidtimeout, "i");
 #ifdef VPM_SUPPORT
 MODULE_PARM(vpmsupport, "i");
 MODULE_PARM(vpmdtmfsupport, "i");
