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 + -
显示快捷键?