ev-layer.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,986 行 · 第 1/4 页

C
1,986
字号
					// FIXME 2: only after init sequence	cs->waiting = 0;	wake_up(&cs->waitqueue);}static void finish_shutdown(struct cardstate *cs){	if (atomic_read(&cs->mstate) != MS_LOCKED) {		atomic_set(&cs->mstate, MS_UNINITIALIZED);		atomic_set(&cs->mode, M_UNKNOWN);	}	/* Tell the LL that the device is not available .. */	if (cs->isdn_up) {		cs->isdn_up = 0;		gigaset_i4l_cmd(cs, ISDN_STAT_STOP);	}	/* The rest is done by cleanup_cs () in user mode. */	cs->cmd_result = -ENODEV;	cs->waiting = 0;	wake_up_interruptible(&cs->waitqueue);}static void do_shutdown(struct cardstate *cs){	gigaset_block_channels(cs);	if (atomic_read(&cs->mstate) == MS_READY) {		atomic_set(&cs->mstate, MS_SHUTDOWN);		cs->at_state.pending_commands |= PC_SHUTDOWN;		atomic_set(&cs->commands_pending, 1);		gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");	} else		finish_shutdown(cs);}static void do_stop(struct cardstate *cs){	unsigned long flags;	spin_lock_irqsave(&cs->lock, flags);	cs->connected = 0;	spin_unlock_irqrestore(&cs->lock, flags);	do_shutdown(cs);}/* Entering cid mode or getting a cid failed: * try to initialize the device and try again. * * channel >= 0: getting cid for the channel failed * channel < 0:  entering cid mode failed * * returns 0 on failure */static int reinit_and_retry(struct cardstate *cs, int channel){	int i;	if (--cs->retry_count <= 0)		return 0;	for (i = 0; i < cs->channels; ++i)		if (cs->bcs[i].at_state.cid > 0)			return 0;	if (channel < 0)		dev_warn(cs->dev,		    "Could not enter cid mode. Reinit device and try again.\n");	else {		dev_warn(cs->dev,		    "Could not get a call id. Reinit device and try again.\n");		cs->bcs[channel].at_state.pending_commands |= PC_CID;	}	schedule_init(cs, MS_INIT);	return 1;}static int at_state_invalid(struct cardstate *cs,			    struct at_state_t *test_ptr){	unsigned long flags;	unsigned channel;	struct at_state_t *at_state;	int retval = 0;	spin_lock_irqsave(&cs->lock, flags);	if (test_ptr == &cs->at_state)		goto exit;	list_for_each_entry(at_state, &cs->temp_at_states, list)		if (at_state == test_ptr)			goto exit;	for (channel = 0; channel < cs->channels; ++channel)		if (&cs->bcs[channel].at_state == test_ptr)			goto exit;	retval = 1;exit:	spin_unlock_irqrestore(&cs->lock, flags);	return retval;}static void handle_icall(struct cardstate *cs, struct bc_state *bcs,			 struct at_state_t **p_at_state){	int retval;	struct at_state_t *at_state = *p_at_state;	retval = gigaset_isdn_icall(at_state);	switch (retval) {	case ICALL_ACCEPT:		break;	default:		dev_err(cs->dev, "internal error: disposition=%d\n", retval);		/* --v-- fall through --v-- */	case ICALL_IGNORE:	case ICALL_REJECT:		/* hang up actively		 * Device doc says that would reject the call.		 * In fact it doesn't.		 */		at_state->pending_commands |= PC_HUP;		atomic_set(&cs->commands_pending, 1);		break;	}}static int do_lock(struct cardstate *cs){	int mode;	int i;	switch (atomic_read(&cs->mstate)) {	case MS_UNINITIALIZED:	case MS_READY:		if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||		    cs->at_state.pending_commands)			return -EBUSY;		for (i = 0; i < cs->channels; ++i)			if (cs->bcs[i].at_state.pending_commands)				return -EBUSY;		if (!gigaset_get_channels(cs))			return -EBUSY;		break;	case MS_LOCKED:		//retval = -EACCES;		break;	default:		return -EBUSY;	}	mode = atomic_read(&cs->mode);	atomic_set(&cs->mstate, MS_LOCKED);	atomic_set(&cs->mode, M_UNKNOWN);	return mode;}static int do_unlock(struct cardstate *cs){	if (atomic_read(&cs->mstate) != MS_LOCKED)		return -EINVAL;	atomic_set(&cs->mstate, MS_UNINITIALIZED);	atomic_set(&cs->mode, M_UNKNOWN);	gigaset_free_channels(cs);	if (cs->connected)		schedule_init(cs, MS_INIT);	return 0;}static void do_action(int action, struct cardstate *cs,		      struct bc_state *bcs,		      struct at_state_t **p_at_state, char **pp_command,		      int *p_genresp, int *p_resp_code,		      struct event_t *ev){	struct at_state_t *at_state = *p_at_state;	struct at_state_t *at_state2;	unsigned long flags;	int channel;	unsigned char *s, *e;	int i;	unsigned long val;	switch (action) {	case ACT_NOTHING:		break;	case ACT_TIMEOUT:		at_state->waiting = 1;		break;	case ACT_INIT:		cs->at_state.pending_commands &= ~PC_INIT;		cs->cur_at_seq = SEQ_NONE;		atomic_set(&cs->mode, M_UNIMODEM);		spin_lock_irqsave(&cs->lock, flags);		if (!cs->cidmode) {			spin_unlock_irqrestore(&cs->lock, flags);			gigaset_free_channels(cs);			atomic_set(&cs->mstate, MS_READY);			break;		}		spin_unlock_irqrestore(&cs->lock, flags);		cs->at_state.pending_commands |= PC_CIDMODE;		atomic_set(&cs->commands_pending, 1);		gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");		break;	case ACT_FAILINIT:		dev_warn(cs->dev, "Could not initialize the device.\n");		cs->dle = 0;		init_failed(cs, M_UNKNOWN);		cs->cur_at_seq = SEQ_NONE;		break;	case ACT_CONFIGMODE:		init_failed(cs, M_CONFIG);		cs->cur_at_seq = SEQ_NONE;		break;	case ACT_SETDLE1:		cs->dle = 1;		/* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */		cs->inbuf[0].inputstate &=			~(INS_command | INS_DLE_command);		break;	case ACT_SETDLE0:		cs->dle = 0;		cs->inbuf[0].inputstate =			(cs->inbuf[0].inputstate & ~INS_DLE_command)			| INS_command;		break;	case ACT_CMODESET:		if (atomic_read(&cs->mstate) == MS_INIT ||		    atomic_read(&cs->mstate) == MS_RECOVER) {			gigaset_free_channels(cs);			atomic_set(&cs->mstate, MS_READY);		}		atomic_set(&cs->mode, M_CID);		cs->cur_at_seq = SEQ_NONE;		break;	case ACT_UMODESET:		atomic_set(&cs->mode, M_UNIMODEM);		cs->cur_at_seq = SEQ_NONE;		break;	case ACT_FAILCMODE:		cs->cur_at_seq = SEQ_NONE;		if (atomic_read(&cs->mstate) == MS_INIT ||		    atomic_read(&cs->mstate) == MS_RECOVER) {			init_failed(cs, M_UNKNOWN);			break;		}		if (!reinit_and_retry(cs, -1))			schedule_init(cs, MS_RECOVER);		break;	case ACT_FAILUMODE:		cs->cur_at_seq = SEQ_NONE;		schedule_init(cs, MS_RECOVER);		break;	case ACT_HUPMODEM:		/* send "+++" (hangup in unimodem mode) */		cs->ops->write_cmd(cs, "+++", 3, NULL);		break;	case ACT_RING:		/* get fresh AT state structure for new CID */		at_state2 = get_free_channel(cs, ev->parameter);		if (!at_state2) {			dev_warn(cs->dev,			"RING ignored: could not allocate channel structure\n");			break;		}		/* initialize AT state structure		 * note that bcs may be NULL if no B channel is free		 */		at_state2->ConState = 700;		kfree(at_state2->str_var[STR_NMBR]);		at_state2->str_var[STR_NMBR] = NULL;		kfree(at_state2->str_var[STR_ZCPN]);		at_state2->str_var[STR_ZCPN] = NULL;		kfree(at_state2->str_var[STR_ZBC]);		at_state2->str_var[STR_ZBC] = NULL;		kfree(at_state2->str_var[STR_ZHLC]);		at_state2->str_var[STR_ZHLC] = NULL;		at_state2->int_var[VAR_ZCTP] = -1;		spin_lock_irqsave(&cs->lock, flags);		at_state2->timer_expires = RING_TIMEOUT;		at_state2->timer_active = 1;		spin_unlock_irqrestore(&cs->lock, flags);		break;	case ACT_ICALL:		handle_icall(cs, bcs, p_at_state);		at_state = *p_at_state;		break;	case ACT_FAILSDOWN:		dev_warn(cs->dev, "Could not shut down the device.\n");		/* fall through */	case ACT_FAKESDOWN:	case ACT_SDOWN:		cs->cur_at_seq = SEQ_NONE;		finish_shutdown(cs);		break;	case ACT_CONNECT:		if (cs->onechannel) {			at_state->pending_commands |= PC_DLE1;			atomic_set(&cs->commands_pending, 1);			break;		}		bcs->chstate |= CHS_D_UP;		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);		cs->ops->init_bchannel(bcs);		break;	case ACT_DLE1:		cs->cur_at_seq = SEQ_NONE;		bcs = cs->bcs + cs->curchannel;		bcs->chstate |= CHS_D_UP;		gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);		cs->ops->init_bchannel(bcs);		break;	case ACT_FAKEHUP:		at_state->int_var[VAR_ZSAU] = ZSAU_NULL;		/* fall through */	case ACT_DISCONNECT:		cs->cur_at_seq = SEQ_NONE;		at_state->cid = -1;		if (bcs && cs->onechannel && cs->dle) {			/* Check for other open channels not needed:			 * DLE only used for M10x with one B channel.			 */			at_state->pending_commands |= PC_DLE0;			atomic_set(&cs->commands_pending, 1);		} else {			disconnect(p_at_state);			at_state = *p_at_state;		}		break;	case ACT_FAKEDLE0:		at_state->int_var[VAR_ZDLE] = 0;		cs->dle = 0;		/* fall through */	case ACT_DLE0:		cs->cur_at_seq = SEQ_NONE;		at_state2 = &cs->bcs[cs->curchannel].at_state;		disconnect(&at_state2);		break;	case ACT_ABORTHUP:		cs->cur_at_seq = SEQ_NONE;		dev_warn(cs->dev, "Could not hang up.\n");		at_state->cid = -1;		if (bcs && cs->onechannel)			at_state->pending_commands |= PC_DLE0;		else {			disconnect(p_at_state);			at_state = *p_at_state;		}		schedule_init(cs, MS_RECOVER);		break;	case ACT_FAILDLE0:		cs->cur_at_seq = SEQ_NONE;		dev_warn(cs->dev, "Could not leave DLE mode.\n");		at_state2 = &cs->bcs[cs->curchannel].at_state;		disconnect(&at_state2);		schedule_init(cs, MS_RECOVER);		break;	case ACT_FAILDLE1:		cs->cur_at_seq = SEQ_NONE;		dev_warn(cs->dev,			 "Could not enter DLE mode. Trying to hang up.\n");		channel = cs->curchannel;		cs->bcs[channel].at_state.pending_commands |= PC_HUP;		atomic_set(&cs->commands_pending, 1);		break;	case ACT_CID: /* got cid; start dialing */		cs->cur_at_seq = SEQ_NONE;		channel = cs->curchannel;		if (ev->parameter > 0 && ev->parameter <= 65535) {			cs->bcs[channel].at_state.cid = ev->parameter;			cs->bcs[channel].at_state.pending_commands |=				PC_DIAL;			atomic_set(&cs->commands_pending, 1);			break;		}		/* fall through */	case ACT_FAILCID:		cs->cur_at_seq = SEQ_NONE;		channel = cs->curchannel;		if (!reinit_and_retry(cs, channel)) {			dev_warn(cs->dev,				 "Could not get a call ID. Cannot dial.\n");			at_state2 = &cs->bcs[channel].at_state;			disconnect(&at_state2);		}		break;	case ACT_ABORTCID:		cs->cur_at_seq = SEQ_NONE;		at_state2 = &cs->bcs[cs->curchannel].at_state;		disconnect(&at_state2);		break;	case ACT_DIALING:	case ACT_ACCEPTED:		cs->cur_at_seq = SEQ_NONE;		break;	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL processing */		disconnect(p_at_state);		at_state = *p_at_state;		break;	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */		cs->cur_at_seq = SEQ_NONE;		at_state->pending_commands |= PC_HUP;		atomic_set(&cs->commands_pending, 1);		break;	case ACT_REMOTEREJECT:	/* DISCONNECT_IND after dialling */	case ACT_CONNTIMEOUT:	/* timeout waiting for ZSAU=ACTIVE */	case ACT_REMOTEHUP:	/* DISCONNECT_IND with established connection */		at_state->pending_commands |= PC_HUP;		atomic_set(&cs->commands_pending, 1);		break;	case ACT_GETSTRING: /* warning: RING, ZDLE, ...			       are not handled properly anymore */		at_state->getstring = 1;		break;	case ACT_SETVER:		if (!ev->ptr) {			*p_genresp = 1;			*p_resp_code = RSP_ERROR;			break;		}		s = ev->ptr;		if (!strcmp(s, "OK")) {			*p_genresp = 1;			*p_resp_code = RSP_ERROR;			break;		}		for (i = 0; i < 4; ++i) {			val = simple_strtoul(s, (char **) &e, 10);			if (val > INT_MAX || e == s)				break;			if (i == 3) {				if (*e)					break;			} else if (*e != '.')				break;			else				s = e + 1;			cs->fwver[i] = val;		}		if (i != 4) {			*p_genresp = 1;			*p_resp_code = RSP_ERROR;			break;		}		/*at_state->getstring = 1;*/		cs->gotfwver = 0;		break;	case ACT_GOTVER:		if (cs->gotfwver == 0) {			cs->gotfwver = 1;			gig_dbg(DEBUG_ANY,				"firmware version %02d.%03d.%02d.%02d",				cs->fwver[0], cs->fwver[1],				cs->fwver[2], cs->fwver[3]);			break;		}		/* fall through */	case ACT_FAILVER:		cs->gotfwver = -1;		dev_err(cs->dev, "could not read firmware version.\n");		break;#ifdef CONFIG_GIGASET_DEBUG	case ACT_ERROR:		*p_genresp = 1;		*p_resp_code = RSP_ERROR;		break;	case ACT_TEST:		{			static int count = 3; //2; //1;			*p_genresp = 1;			*p_resp_code = count ? RSP_ERROR : RSP_OK;			if (count > 0)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?