Esempio n. 1
0
static int faxgen_generate(struct cw_channel *chan, void *data, int samples)
{
    int len;
    fax_state_t *fax;
    struct cw_frame outf;

    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET];
    uint8_t *buf = __buf + CW_FRIENDLY_OFFSET;
    
    fax = (fax_state_t*) data;

    samples = (samples <= MAX_BLOCK_SIZE)  ?  samples  :  MAX_BLOCK_SIZE;
    if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0)
    {
        cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX");
        outf.datalen = len*sizeof(int16_t);
        outf.samples = len;
        outf.data = &buf[CW_FRIENDLY_OFFSET];
        outf.offset = CW_FRIENDLY_OFFSET;

        if (cw_write(chan, &outf) < 0)
            cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
    }

    return 0;
}
Esempio n. 2
0
static int linear_generator(struct cw_channel *chan, void *data, int samples)
{
	struct cw_frame f;
	short buf[2048 + CW_FRIENDLY_OFFSET / 2];
	struct linear_state *ls = data;
	int res, len;

	len = samples*sizeof(int16_t);
	if (len > sizeof(buf) - CW_FRIENDLY_OFFSET)
    {
		cw_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
		len = sizeof(buf) - CW_FRIENDLY_OFFSET;
	}
	memset(&f, 0, sizeof(f));
	res = read(ls->fd, buf + CW_FRIENDLY_OFFSET/2, len);
	if (res > 0)
    {
        cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL);
		f.data = buf + CW_FRIENDLY_OFFSET/sizeof(int16_t);
		f.datalen = res;
		f.samples = res/sizeof(int16_t);
		f.offset = CW_FRIENDLY_OFFSET;
		cw_write(chan, &f);
		if (res == len)
			return 0;
	}
	return -1;
}
static int cw_quickstart(struct cw_battery *cw_bat)
{
        int ret = 0;
        u8 reg_val = MODE_QUICK_START;

        ret = cw_write(cw_bat->client, REG_MODE, &reg_val);     //(MODE_QUICK_START | MODE_NORMAL));  // 0x30
        if(ret < 0) {
                dev_err(&cw_bat->client->dev, "Error quick start1\n");
                return ret;
        }
        
        reg_val = MODE_NORMAL;
        ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
        if(ret < 0) {
                dev_err(&cw_bat->client->dev, "Error quick start2\n");
                return ret;
        }
        return 1;
}
Esempio n. 4
0
static int playtones_generator(struct cw_channel *chan, void *data, int samples)
{
	struct playtones_state *ps = data;
	struct playtones_item *pi;
	int len;
    int x;

	/*
	 * We need to prepare a frame with 16 * timelen samples as we're 
	 * generating SLIN audio
	 */
	len = samples + samples;
	if (len > sizeof(ps->data)/sizeof(int16_t) - 1)
    {
		cw_log(LOG_WARNING, "Can't generate that much data!\n");
		return -1;
	}

    x = tone_gen(&ps->tone_state, ps->data, samples);
	pi = &ps->items[ps->npos];

	/* Assemble frame */
	cw_fr_init_ex(&ps->f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL);
	ps->f.datalen = len;
	ps->f.samples = samples;
	ps->f.offset = CW_FRIENDLY_OFFSET;
	ps->f.data = ps->data;
	cw_write(chan, &ps->f);

	ps->pos += x;
	if (pi->duration  &&  ps->pos >= pi->duration*8)
    {
    	/* item finished? */
		ps->pos = 0;					/* start new item */
		ps->npos++;
		if (ps->npos >= ps->nitems)
        {
            /* last item */
			if (ps->reppos == -1)			/* repeat set? */
				return -1;
			ps->npos = ps->reppos;			/* redo from top */
		}

		/* Prepare the tone generator for more */
		pi = &ps->items[ps->npos];
		tone_setup(ps, pi);
	}
	return 0;
}
Esempio n. 5
0
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
{
    struct cw_frame outf;
    struct cw_channel *chan;

    chan = (struct cw_channel *) user_data;

    cw_fr_init_ex(&outf, CW_FRAME_MODEM, CW_MODEM_T38, "FAX");
    outf.datalen = len;
    outf.data = (char *) buf;
    outf.tx_copies = count;
    if (cw_write(chan, &outf) < 0)
        cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
    return 0;
}
Esempio n. 6
0
int cw_dtmf_stream(struct cw_channel *chan,struct cw_channel *peer,char *digits,int between) 
{
	char *ptr;
	int res = 0;
	struct cw_frame f;
	if (!between)
		between = 100;

	if (peer)
		res = cw_autoservice_start(peer);

	if (!res) {
		res = cw_waitfor(chan,100);
		if (res > -1) {
			for (ptr=digits; *ptr; ptr++) {
				if (*ptr == 'w') {
					res = cw_safe_sleep(chan, 500);
					if (res) 
						break;
					continue;
				}
                cw_fr_init_ex(&f, CW_FRAME_DTMF, *ptr, NULL);
				f.src = "cw_dtmf_stream";
				if (strchr("0123456789*#abcdABCD",*ptr) == NULL)
                {
					cw_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
				}
                else
                {
					res = cw_write(chan, &f);
					if (res) 
						break;
					/* pause between digits */
					res = cw_safe_sleep(chan,between);
					if (res) 
						break;
				}
			}
		}
		if (peer)
			res = cw_autoservice_stop(peer);
	}
	return res;
}
Esempio n. 7
0
// process outgoing frames for the channel, playing either normal conference audio,
// or requested sounds
static int process_outgoing( struct cw_conf_member *member, int samples )
{

    int res;
    struct cw_frame *cf = NULL;

    cw_mutex_lock(&member->lock);

    cf=get_outgoing_frame( member->conf, member, samples ) ;

    cw_mutex_unlock(&member->lock);

/*
    cw_log(LOG_WARNING,
	    "OURGen: samples %d - conf %s - speak: %d - format: %d\n", 
	    samples, member->chan->name, member->is_speaking , cf->frametype
    );
*/

    // if there's no frames exit the loop.
    if( cf == NULL ) {
        cw_log( LOG_ERROR, "Nothing to write to the conference, channel => %s\n", member->channel_name ) ;
	return 0;
    }

    // send the voice frame
    res = cw_write( member->chan, cf );

    if ( ( res != 0) )
    {
        // log 'dropped' outgoing frame
        cw_log( LOG_ERROR, "unable to write voice frame to channel, channel => %s, samples %d \n", member->channel_name, samples ) ;
    }

    // clean up frame
    cw_fr_free(cf);

    return 0;
}
static int cw_get_alt(struct cw_battery *cw_bat)
{
        int ret = 0;
        u8 reg_val;
        u8 value8 = 0;
        int alrt;
        
        ret = cw_read(cw_bat->client, REG_RRT_ALERT, &reg_val);
        if (ret < 0)
                return ret;
        value8 = reg_val;
        alrt = value8 >>7;
        
        //dev_info(&cw_bat->client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16);
        value8 = value8&0x7f;
        reg_val = value8;
        ret = cw_write(cw_bat->client, REG_RRT_ALERT, &reg_val);
        if(ret < 0) {
                dev_err(&cw_bat->client->dev, "Error clear ALRT\n");
                return ret;
        }
        
        return alrt;
}
Esempio n. 9
0
static int pipe_exec(struct cw_channel *chan, int argc, char **argv)
{
	int res=0;
	struct localuser *u;
	int fds[2];
	int ms = -1;
	int pid = -1;
	int owriteformat;
	int oreadformat;
	int timeout = 2000;
	struct timeval last;
	struct cw_frame *f;
	struct myframe {
		struct cw_frame f;
		char offset[CW_FRIENDLY_OFFSET];
		short frdata[160];
	} myf;

	last.tv_usec = 0;
	last.tv_sec = 0;

	if (argc < 2 || argc > 3) {
		cw_log(LOG_ERROR, "Syntax: %s\n", pipe_syntax);
		return -1;
	}

	LOCAL_USER_ADD(u);

	if (pipe(fds)) {
		cw_log(LOG_WARNING, "Unable to create pipe\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

// MOC: Setting non blocking doesn't seem to change anything
//	flags = fcntl(fds[1], F_GETFL);
//	fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);

//	flags = fcntl(fds[0], F_GETFL);
//	fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);

	cw_stopstream(chan);

	if (chan->_state != CW_STATE_UP)
		res = cw_answer(chan);
		
	if (res) {
		close(fds[0]);
		close(fds[1]);
		cw_log(LOG_WARNING, "Answer failed!\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	oreadformat = chan->readformat;
	res = cw_set_read_format(chan, CW_FORMAT_SLINEAR);

	owriteformat = chan->writeformat;
	res += cw_set_write_format(chan, CW_FORMAT_SLINEAR);

	if (res < 0) {
		close(fds[0]);
		close(fds[1]);
		cw_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	res = pipeencode(argv[1], argv[2], fds[0], fds[1]);

	if (res >= 0) {
	   last = cw_tvnow();
	   last.tv_sec += 1;

		pid = res;
		for (;;) {
			/* Wait for audio, and stream */
			if (argv[0][0] == '0') {
				/* START WRITE TO FD */
				ms = cw_waitfor(chan, 10);
				if (ms < 0) {
					cw_log(LOG_DEBUG, "Hangup detected\n");
					res = -1;
					break;
				} else if (ms > 0) {
					f = cw_read(chan);
					if (!f) {
						cw_log(LOG_DEBUG, "Null frame == hangup() detected\n");
						res = -1;
						break;
					}
					if (f->frametype == CW_FRAME_DTMF) {
						cw_log(LOG_DEBUG, "User pressed a key\n");
						cw_fr_free(f);
						res = 0;
						break;
					}
					if (f->frametype == CW_FRAME_VOICE) {
						res = write(fds[1], f->data, f->datalen);
						if (res < 0) {
							if (errno != EAGAIN) {
								cw_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
                                cw_fr_free(f);
								res = -1;
								break;
							}
						}
					}
					cw_fr_free(f);
				} /* END WRITE TO FD */
			} else {
				/* START WRITE CHANNEL */
				ms = cw_tvdiff_ms(last, cw_tvnow());
				if (ms <= 0) {
					res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
					if (res > 0) {
                        cw_fr_init_ex(&myf.f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__);
						myf.f.datalen = res;
						myf.f.samples = res/sizeof(int16_t);
						myf.f.offset = CW_FRIENDLY_OFFSET;
						myf.f.data = myf.frdata;
						if (cw_write(chan, &myf.f) < 0)
                        {
							res = -1;
							break;
						}
					} else {
						cw_log(LOG_DEBUG, "No more stream\n");
						res = 0;
						break;
					}
					last = cw_tvadd(last, cw_samp2tv(myf.f.samples, 8000));
				} else {
					ms = cw_waitfor(chan, ms);
					if (ms < 0) {
						cw_log(LOG_DEBUG, "Hangup detected\n");
						res = -1;
						break;
					}
					if (ms) {
						f = cw_read(chan);
						if (!f) {
							cw_log(LOG_DEBUG, "Null frame == hangup() detected\n");
							res = -1;
							break;
						}
						if (f->frametype == CW_FRAME_DTMF) {
							cw_log(LOG_DEBUG, "User pressed a key\n");
							cw_fr_free(f);
							res = 0;
							break;
						}
						cw_fr_free(f);
					}
				}
				/* END WRITE CHANNEL */
			}
		}
	}
	close(fds[0]);
	close(fds[1]);

	LOCAL_USER_REMOVE(u);
	if (pid > -1)
		kill(pid, SIGKILL);
	if (!res && oreadformat)
		cw_set_read_format(chan, oreadformat);
	if (!res && owriteformat)
		cw_set_write_format(chan, owriteformat);

	return res;
}
Esempio n. 10
0
static int fax_audio(struct cw_channel *chan, fax_state_t *fax, const char *file, int calling_party, int verbose)
{
    char *x;
    struct cw_frame *inf = NULL;
    struct cw_frame outf;
    int ready = 1;
    int samples = 0;
    int res = 0;
    int len = 0;
    int generator_mode = 0;
    uint64_t begin = 0;
    uint64_t received_frames = 0;
    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET];
    uint8_t *buf = __buf + CW_FRIENDLY_OFFSET;
#if 0
    struct cw_frame *dspf = NULL;
    struct cw_dsp *dsp = NULL;
#endif
    uint64_t voice_frames;
    t30_state_t *t30;

    memset(fax, 0, sizeof(*fax));
    if (fax_init(fax, calling_party) == NULL)
    {
        cw_log(LOG_WARNING, "Unable to start FAX\n");
        return -1;
    }
    t30 = fax_get_t30_state(fax);
    fax_set_transmit_on_idle(fax, TRUE);
    span_log_set_message_handler(&fax->logging, span_message);
    span_log_set_message_handler(&t30->logging, span_message);
    if (verbose)
    {
        span_log_set_level(&fax->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
        span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    }

    fax_set_common(chan, t30, file, calling_party, verbose);
    fax_set_transmit_on_idle(fax, TRUE);

    if (calling_party)
    {
        voice_frames = 0;
    }
    else
    {
#if 0
        /* Initializing the DSP */
        if ((dsp = cw_dsp_new()) == NULL)
        {
            cw_log(LOG_WARNING, "Unable to allocate DSP!\n");
        }
        else
        {
            cw_dsp_set_threshold(dsp, 256); 
            cw_dsp_set_features(dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_CNG_DETECT);
            cw_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
        }
#endif
        voice_frames = 1;
    }

    /* This is the main loop */
    begin = nowis();
    while (ready  &&  ready_to_talk(chan))
    {
        if (chan->t38_status == T38_NEGOTIATED)
            break;

        if ((res = cw_waitfor(chan, 20)) < 0)
        {
            ready = 0;
            break;
        }

        if (!t30_call_active(t30))
            break;

        if ((inf = cw_read(chan)) == NULL)
        {
            ready = 0;
            break;
        }

        /* We got a frame */
        if (inf->frametype == CW_FRAME_VOICE)
        {
#if 0
            if (dsp)
            {
                if ((dspf = cw_frdup(inf)))
                    dspf = cw_dsp_process(chan, dsp, dspf);

                if (dspf)
                {
                    if (dspf->frametype == CW_FRAME_DTMF)
                    {
                        if (dspf->subclass == 'f')
                        {
                            cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n");
                            cw_app_request_t38(chan);
                            /* Prevent any further attempts to negotiate T.38 */
                            cw_dsp_free(dsp);
                            dsp = NULL;
                    
                        }
                    }
                    cw_fr_free(dspf);
                    dspf = NULL;
                }
            }
#else
            if (voice_frames)
            {
                /* Wait a little before trying to switch to T.38, as some things don't seem
                   to like entirely missing the audio. */
                if (++voice_frames == 100)
                {
                    cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n");
                    cw_app_request_t38(chan);
                    voice_frames = 0;
                }
            }
#endif
            received_frames++;

            if (fax_rx(fax, inf->data, inf->samples))
                break;

            samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
            if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0)
            {
                cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX");
                outf.datalen = len*sizeof(int16_t);
                outf.samples = len;
                outf.data = &buf[CW_FRIENDLY_OFFSET];
                outf.offset = CW_FRIENDLY_OFFSET;

                if (cw_write(chan, &outf) < 0)
                {
                    cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
                    break;
                }
            }
        }
        else
        {
            if ((nowis() - begin) > 1000000)
            {
                if (received_frames < 20)
                {
                    /* Just to be sure we have had no frames ... */
                    cw_log(LOG_NOTICE, "Switching to generator mode\n");
                    generator_mode = 1;
                    break;
                }
            }
        }
        cw_fr_free(inf);
        inf = NULL;
    }

    if (inf)
    {
        cw_fr_free(inf);
        inf = NULL;
    }
    if (generator_mode)
    {
        /* This is activated when we don't receive any frame for X seconds (see above)... */
        cw_log(LOG_NOTICE, "Starting generator\n");
#if 0
        if (dsp)
            cw_dsp_reset(dsp);
#endif
        cw_generator_activate(chan, &faxgen, fax);

        while (ready  &&  ready_to_talk(chan))
        {
            if (chan->t38_status == T38_NEGOTIATED)
                break;

            if ((res = cw_waitfor(chan, 20)) < 0)
            {
                ready = 0;
                break;
            }

            if (!t30_call_active(t30))
                break;

            if ((inf = cw_read(chan)) == NULL)
            {
                ready = 0;
                break;
            }

            /* We got a frame */
            if (inf->frametype == CW_FRAME_VOICE)
            {
#if 0
                if (dsp)
                {
                    if ((dspf = cw_frdup(inf)))
                        dspf = cw_dsp_process(chan, dsp, dspf);

                    if (dspf)
                    {
                        if (dspf->frametype == CW_FRAME_DTMF)
                        {
                            if (dspf->subclass == 'f')
                            {
                                cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n");
                                cw_app_request_t38(chan);
                                /* Prevent any further attempts to negotiate T.38 */
                                cw_dsp_free(dsp);
                                dsp = NULL;
                            }
                        }
                        cw_fr_free(dspf);
                        dspf = NULL;
                    }
                }
#else
                if (voice_frames)
                {
                    if (++voice_frames == 100)
                    {
                        cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n");
                        cw_app_request_t38(chan);
                        voice_frames = 0;
                    }
                }
#endif
                if (fax_rx(fax, inf->data, inf->samples))
                {
                    ready = 0;
                    break;
                }
            }

            cw_fr_free(inf);
            inf = NULL;
        }

        if (inf)
        {
            cw_fr_free(inf);
            inf = NULL;
        }
        cw_log(LOG_NOTICE, "Stopping generator\n");
        cw_generator_deactivate(chan);
    }
#if 0
    if (dsp)
        cw_dsp_free(dsp);
#endif
    return ready;
}
static int cw_get_capacity(struct cw_battery *cw_bat)
{
        int cw_capacity;
        int ret;
        u8 reg_val[2];

        struct timespec ts;
        long new_run_time;
        long new_sleep_time;
        long capacity_or_aconline_time;
        int allow_change;
        int allow_capacity;
        static int if_quickstart = 0;
        static int jump_flag =0;
        int charge_time;


        // ret = cw_read(cw_bat->client, REG_SOC, &reg_val);
        ret = cw_read_word(cw_bat->client, REG_SOC, reg_val);
        if (ret < 0)
                return ret;

        cw_capacity = reg_val[0];
        if ((cw_capacity < 0) || (cw_capacity > 100)) {
                dev_err(&cw_bat->client->dev, "get cw_capacity error; cw_capacity = %d\n", cw_capacity);
                return cw_capacity;
        } 

        if (cw_capacity == 0) 
                dev_dbg(&cw_bat->client->dev, "the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
        else 
                dev_dbg(&cw_bat->client->dev, "the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__);

        // ret = cw_read(cw_bat->client, REG_SOC + 1, &reg_val);

        ktime_get_ts(&ts);
        new_run_time = ts.tv_sec;

        get_monotonic_boottime(&ts);
        new_sleep_time = ts.tv_sec - new_run_time;

        if ((cw_bat->charger_mode > 0) && (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) {     // avoid no charge full

                capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start;
                capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start;
                allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_UP_MAX_CHANGE;
                if (allow_change > 0) {
                        allow_capacity = cw_bat->capacity + allow_change; 
                        cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
                        jump_flag =1;
                } else if (cw_capacity <= cw_bat->capacity) {
                        cw_capacity = cw_bat->capacity; 
                }

        } else if (((cw_bat->charger_mode > 0) && (cw_capacity == (cw_bat->capacity - 1)))
                        || ((cw_bat->charger_mode == 0) && (cw_capacity == (cw_bat->capacity + 1)))) {             // modify battery level swing

                if (!(cw_capacity == 0 && cw_bat->capacity == 1)) {			
		        cw_capacity = cw_bat->capacity;
		}
				

        } else if ((cw_capacity == 0) && (cw_bat->capacity > 1)) {              // avoid battery level jump to 0% at a moment from more than 2%
                allow_change = ((new_run_time - cw_bat->run_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_RUN);
                allow_change += ((new_sleep_time - cw_bat->sleep_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_SLEEP);

                allow_capacity = cw_bat->capacity - allow_change;
                cw_capacity = (allow_capacity >= cw_capacity) ? allow_capacity: cw_capacity;
                reg_val[0] = MODE_NORMAL;
                ret = cw_write(cw_bat->client, REG_MODE, reg_val);
                if (ret < 0)
                        return ret;

        } else if ((cw_bat->charger_mode == 0) && (cw_capacity <= cw_bat->capacity ) && (cw_capacity >= 90) && (jump_flag == 1)) {     // avoid battery level jump to CW_BAT
                capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start;
                capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start;
                allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_DOWN_CHANGE;
                if (allow_change > 0) {
                        allow_capacity = cw_bat->capacity - allow_change; 
                        if (cw_capacity >= allow_capacity){
                        	jump_flag =0;
                        }
                        else{
                                cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
                        }
                } else if (cw_capacity <= cw_bat->capacity) {
                        cw_capacity = cw_bat->capacity;
                }
        }
 
#if 1	
	if((cw_bat->charger_mode > 0) &&(cw_capacity == 0))
	{		  
                charge_time = new_sleep_time + new_run_time - cw_bat->sleep_time_charge_start - cw_bat->run_time_charge_start;
                if ((charge_time > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE) && (if_quickstart == 0)) {
        		cw_quickstart(cw_bat);      // if the cw_capacity = 0 the cw2015 will qstrt
                        if_quickstart = 1;
                }
	} else if ((if_quickstart == 1)&&(cw_bat->charger_mode == 0)) {
    		if_quickstart = 0;
        }

#endif

#if 0
        if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) {
                if(gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level) {
                        if (cw_capacity == 100) {
                                cw_capacity = 99;
                        }
                } else {
                        if (cw_bat->charger_mode > 0) {
                                cw_capacity = 100;
                        }
                }
        }
#endif

#ifdef SYSTEM_SHUTDOWN_VOLTAGE
        if ((cw_bat->charger_mode == 0) && (cw_capacity <= 10) && (cw_bat->voltage <= SYSTEM_SHUTDOWN_VOLTAGE)){      	     
                if (if_quickstart == 10){       	      	
                        cw_quickstart(cw_bat);
                        if_quickstart = 12;
                        cw_capacity = 0;
                } else if (if_quickstart <= 10)
                        if_quickstart =if_quickstart+2;
                dev_info(&cw_bat->client->dev, "the cw201x voltage is less than SYSTEM_SHUTDOWN_VOLTAGE !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
        } else if ((cw_bat->charger_mode > 0)&& (if_quickstart <= 12)) {
                if_quickstart = 0;
        }
#endif
        return cw_capacity;
}
static int cw_init(struct cw_battery *cw_bat)
{
        int ret;
        int i;
        u8 reg_val = MODE_SLEEP;
#if 0
        ret = cw_read(cw_bat->client, REG_MODE, &reg_val);
        if (ret < 0)
                return ret;
#endif
        if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
                reg_val = MODE_NORMAL;
                ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
                if (ret < 0) 
                        return ret;
        }

        ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
        if (ret < 0)
                return ret;

        if ((reg_val & 0xf8) != ATHD) {
                dev_info(&cw_bat->client->dev, "the new ATHD have not set\n");
                reg_val &= 0x07;    /* clear ATHD */
                reg_val |= ATHD;    /* set ATHD */
                ret = cw_write(cw_bat->client, REG_CONFIG, &reg_val);
                if (ret < 0)
                        return ret;
        }

        ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
        if (ret < 0) 
                return ret;

        if (!(reg_val & CONFIG_UPDATE_FLG)) {
                dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n");
                ret = cw_update_config_info(cw_bat);
                if (ret < 0)
                        return ret;
        } else {
                for(i = 0; i < SIZE_BATINFO; i++) { 
                        ret = cw_read(cw_bat->client, (REG_BATINFO + i), &reg_val);
                        if (ret < 0)
                                return ret;
                        
                        if (cw_bat->plat_data->cw_bat_config_info[i] != reg_val)
                                break;
                }

                if (i != SIZE_BATINFO) {
                        dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n"); 
                        ret = cw_update_config_info(cw_bat);
                        if (ret < 0)
                                return ret;
                }
        }

        for (i = 0; i < 30; i++) {
                ret = cw_read(cw_bat->client, REG_SOC, &reg_val);
                if (ret < 0)
                        return ret;
                else if (ret != 0xff) 
                        break;
                
                msleep(100);
                if (i > 25)
                        dev_err(&cw_bat->client->dev, "cw2015/cw2013 input unvalid power error\n");

        }
        
        return 0;
}
static int cw_update_config_info(struct cw_battery *cw_bat)
{
        int ret;
        u8 reg_val;
        int i;
        u8 reset_val;

        dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
        
        /* make sure no in sleep mode */
        ret = cw_read(cw_bat->client, REG_MODE, &reg_val);
        if (ret < 0)
                return ret;

        reset_val = reg_val;
        if((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
                dev_err(&cw_bat->client->dev, "Error, device in sleep mode, cannot update battery info\n");
                return -1;
        }

        /* update new battery info */
        for (i = 0; i < SIZE_BATINFO; i++) {
                dev_info(&cw_bat->client->dev, "cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \
                                cw_bat->plat_data->cw_bat_config_info[i]);
                ret = cw_write(cw_bat->client, REG_BATINFO + i, &cw_bat->plat_data->cw_bat_config_info[i]);

                if (ret < 0) 
                        return ret;
        }

        /* readback & check */
        for (i = 0; i < SIZE_BATINFO; i++) {
                ret = cw_read(cw_bat->client, REG_BATINFO + i, &reg_val);
                if (reg_val != cw_bat->plat_data->cw_bat_config_info[i])
                        return -1;
        }
        
        /* set cw2015/cw2013 to use new battery info */
        ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
        if (ret < 0)
                return ret;

        reg_val |= CONFIG_UPDATE_FLG;   /* set UPDATE_FLAG */
        reg_val &= 0x07;                /* clear ATHD */
        reg_val |= ATHD;                /* set ATHD */
        ret = cw_write(cw_bat->client, REG_CONFIG, &reg_val);
        if (ret < 0)
                return ret;

        /* check 2015/cw2013 for ATHD & update_flag */ 
        ret = cw_read(cw_bat->client, REG_CONFIG, &reg_val);
        if (ret < 0)
                return ret;
        
        if (!(reg_val & CONFIG_UPDATE_FLG)) {
                dev_info(&cw_bat->client->dev, "update flag for new battery info have not set..\n");
        }

        if ((reg_val & 0xf8) != ATHD) {
                dev_info(&cw_bat->client->dev, "the new ATHD have not set..\n");
        }

        /* reset */
        reset_val &= ~(MODE_RESTART);
        reg_val = reset_val | MODE_RESTART;
        ret = cw_write(cw_bat->client, REG_MODE, &reg_val);
        if (ret < 0)
                return ret;

        msleep(10);
        ret = cw_write(cw_bat->client, REG_MODE, &reset_val);
        if (ret < 0)
                return ret;
        
        return 0;
}