ev-layer.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,986 行 · 第 1/4 页
C
1,986 行
--count; } break;#endif case ACT_DEBUG: gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", __func__, ev->type, at_state->ConState); break; case ACT_WARN: dev_warn(cs->dev, "%s: resp_code %d in ConState %d!\n", __func__, ev->type, at_state->ConState); break; case ACT_ZCAU: dev_warn(cs->dev, "cause code %04x in connection state %d.\n", ev->parameter, at_state->ConState); break; /* events from the LL */ case ACT_DIAL: start_dial(at_state, ev->ptr, ev->parameter); break; case ACT_ACCEPT: start_accept(at_state); break; case ACT_PROTO_L2: gig_dbg(DEBUG_CMD, "set protocol to %u", (unsigned) ev->parameter); at_state->bcs->proto2 = ev->parameter; break; case ACT_HUP: at_state->pending_commands |= PC_HUP; atomic_set(&cs->commands_pending, 1); gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); break; /* hotplug events */ case ACT_STOP: do_stop(cs); break; case ACT_START: do_start(cs); break; /* events from the interface */ // FIXME without ACT_xxxx? case ACT_IF_LOCK: cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs); cs->waiting = 0; wake_up(&cs->waitqueue); break; case ACT_IF_VER: if (ev->parameter != 0) cs->cmd_result = -EINVAL; else if (cs->gotfwver != 1) { cs->cmd_result = -ENOENT; } else { memcpy(ev->arg, cs->fwver, sizeof cs->fwver); cs->cmd_result = 0; } cs->waiting = 0; wake_up(&cs->waitqueue); break; /* events from the proc file system */ // FIXME without ACT_xxxx? case ACT_PROC_CIDMODE: spin_lock_irqsave(&cs->lock, flags); if (ev->parameter != cs->cidmode) { cs->cidmode = ev->parameter; if (ev->parameter) { cs->at_state.pending_commands |= PC_CIDMODE; gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); } else { cs->at_state.pending_commands |= PC_UMMODE; gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); } atomic_set(&cs->commands_pending, 1); } spin_unlock_irqrestore(&cs->lock, flags); cs->waiting = 0; wake_up(&cs->waitqueue); break; /* events from the hardware drivers */ case ACT_NOTIFY_BC_DOWN: bchannel_down(bcs); break; case ACT_NOTIFY_BC_UP: bchannel_up(bcs); break; case ACT_SHUTDOWN: do_shutdown(cs); break; default: if (action >= ACT_CMD && action < ACT_CMD + AT_NUM) { *pp_command = at_state->bcs->commands[action - ACT_CMD]; if (!*pp_command) { *p_genresp = 1; *p_resp_code = RSP_NULL; } } else dev_err(cs->dev, "%s: action==%d!\n", __func__, action); }}/* State machine to do the calling and hangup procedure */static void process_event(struct cardstate *cs, struct event_t *ev){ struct bc_state *bcs; char *p_command = NULL; struct reply_t *rep; int rcode; int genresp = 0; int resp_code = RSP_ERROR; int sendcid; struct at_state_t *at_state; int index; int curact; unsigned long flags; if (ev->cid >= 0) { at_state = at_state_from_cid(cs, ev->cid); if (!at_state) { gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID, NULL, 0, NULL); return; } } else { at_state = ev->at_state; if (at_state_invalid(cs, at_state)) { gig_dbg(DEBUG_ANY, "event for invalid at_state %p", at_state); return; } } gig_dbg(DEBUG_CMD, "connection state %d, event %d", at_state->ConState, ev->type); bcs = at_state->bcs; sendcid = at_state->cid; /* Setting the pointer to the dial array */ rep = at_state->replystruct; spin_lock_irqsave(&cs->lock, flags); if (ev->type == EV_TIMEOUT) { if (ev->parameter != at_state->timer_index || !at_state->timer_active) { ev->type = RSP_NONE; /* old timeout */ gig_dbg(DEBUG_ANY, "old timeout"); } else if (!at_state->waiting) gig_dbg(DEBUG_ANY, "timeout occurred"); else gig_dbg(DEBUG_ANY, "stopped waiting"); } spin_unlock_irqrestore(&cs->lock, flags); /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */ if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) { index = ev->type - RSP_VAR; at_state->int_var[index] = ev->parameter; } else if (ev->type >= RSP_STR && ev->type < RSP_STR + STR_NUM) { index = ev->type - RSP_STR; kfree(at_state->str_var[index]); at_state->str_var[index] = ev->ptr; ev->ptr = NULL; /* prevent process_events() from deallocating ptr */ } if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING) at_state->getstring = 0; /* Search row in dial array which matches modem response and current constate */ for (;; rep++) { rcode = rep->resp_code; if (rcode == RSP_LAST) { /* found nothing...*/ dev_warn(cs->dev, "%s: rcode=RSP_LAST: " "resp_code %d in ConState %d!\n", __func__, ev->type, at_state->ConState); return; } if ((rcode == RSP_ANY || rcode == ev->type) && ((int) at_state->ConState >= rep->min_ConState) && (rep->max_ConState < 0 || (int) at_state->ConState <= rep->max_ConState) && (rep->parameter < 0 || rep->parameter == ev->parameter)) break; } p_command = rep->command; at_state->waiting = 0; for (curact = 0; curact < MAXACT; ++curact) { /* The row tells us what we should do .. */ do_action(rep->action[curact], cs, bcs, &at_state, &p_command, &genresp, &resp_code, ev); if (!at_state) break; /* may be freed after disconnect */ } if (at_state) { /* Jump to the next con-state regarding the array */ if (rep->new_ConState >= 0) at_state->ConState = rep->new_ConState; if (genresp) { spin_lock_irqsave(&cs->lock, flags); at_state->timer_expires = 0; //FIXME at_state->timer_active = 0; //FIXME spin_unlock_irqrestore(&cs->lock, flags); gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL); } else { /* Send command to modem if not NULL... */ if (p_command/*rep->command*/) { if (cs->connected) send_command(cs, p_command, sendcid, cs->dle, GFP_ATOMIC); else gigaset_add_event(cs, at_state, RSP_NODEV, NULL, 0, NULL); } spin_lock_irqsave(&cs->lock, flags); if (!rep->timeout) { at_state->timer_expires = 0; at_state->timer_active = 0; } else if (rep->timeout > 0) { /* new timeout */ at_state->timer_expires = rep->timeout * 10; at_state->timer_active = 1; ++at_state->timer_index; } spin_unlock_irqrestore(&cs->lock, flags); } }}static void schedule_sequence(struct cardstate *cs, struct at_state_t *at_state, int sequence){ cs->cur_at_seq = sequence; gigaset_add_event(cs, at_state, RSP_INIT, NULL, sequence, NULL);}static void process_command_flags(struct cardstate *cs){ struct at_state_t *at_state = NULL; struct bc_state *bcs; int i; int sequence; unsigned long flags; atomic_set(&cs->commands_pending, 0); if (cs->cur_at_seq) { gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy"); return; } gig_dbg(DEBUG_CMD, "searching scheduled commands"); sequence = SEQ_NONE; /* clear pending_commands and hangup channels on shutdown */ if (cs->at_state.pending_commands & PC_SHUTDOWN) { cs->at_state.pending_commands &= ~PC_CIDMODE; for (i = 0; i < cs->channels; ++i) { bcs = cs->bcs + i; at_state = &bcs->at_state; at_state->pending_commands &= ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); if (at_state->cid > 0) at_state->pending_commands |= PC_HUP; if (at_state->pending_commands & PC_CID) { at_state->pending_commands |= PC_NOCID; at_state->pending_commands &= ~PC_CID; } } } /* clear pending_commands and hangup channels on reset */ if (cs->at_state.pending_commands & PC_INIT) { cs->at_state.pending_commands &= ~PC_CIDMODE; for (i = 0; i < cs->channels; ++i) { bcs = cs->bcs + i; at_state = &bcs->at_state; at_state->pending_commands &= ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); if (at_state->cid > 0) at_state->pending_commands |= PC_HUP; if (atomic_read(&cs->mstate) == MS_RECOVER) { if (at_state->pending_commands & PC_CID) { at_state->pending_commands |= PC_NOCID; at_state->pending_commands &= ~PC_CID; } } } } /* only switch back to unimodem mode, if no commands are pending and no channels are up */ spin_lock_irqsave(&cs->lock, flags); if (cs->at_state.pending_commands == PC_UMMODE && !cs->cidmode && list_empty(&cs->temp_at_states) && atomic_read(&cs->mode) == M_CID) { sequence = SEQ_UMMODE; at_state = &cs->at_state; for (i = 0; i < cs->channels; ++i) { bcs = cs->bcs + i; if (bcs->at_state.pending_commands || bcs->at_state.cid > 0) { sequence = SEQ_NONE; break; } } } spin_unlock_irqrestore(&cs->lock, flags); cs->at_state.pending_commands &= ~PC_UMMODE; if (sequence != SEQ_NONE) { schedule_sequence(cs, at_state, sequence); return; } for (i = 0; i < cs->channels; ++i) { bcs = cs->bcs + i; if (bcs->at_state.pending_commands & PC_HUP) { bcs->at_state.pending_commands &= ~PC_HUP; if (bcs->at_state.pending_commands & PC_CID) { /* not yet dialing: PC_NOCID is sufficient */ bcs->at_state.pending_commands |= PC_NOCID; bcs->at_state.pending_commands &= ~PC_CID; } else { schedule_sequence(cs, &bcs->at_state, SEQ_HUP); return; } } if (bcs->at_state.pending_commands & PC_NOCID) { bcs->at_state.pending_commands &= ~PC_NOCID; cs->curchannel = bcs->channel; schedule_sequence(cs, &cs->at_state, SEQ_NOCID); return; } else if (bcs->at_state.pending_commands & PC_DLE0) { bcs->at_state.pending_commands &= ~PC_DLE0; cs->curchannel = bcs->channel; schedule_sequence(cs, &cs->at_state, SEQ_DLE0); return; } } list_for_each_entry(at_state, &cs->temp_at_states, list) if (at_state->pending_commands & PC_HUP) { at_state->pending_commands &= ~PC_HUP; schedule_sequence(cs, at_state, SEQ_HUP); return; } if (cs->at_state.pending_commands & PC_INIT) { cs->at_state.pending_commands &= ~PC_INIT; cs->dle = 0; //FIXME cs->inbuf->inputstate = INS_command; //FIXME reset card state (or -> LOCK0)? schedule_sequence(cs, &cs->at_state, SEQ_INIT); return; } if (cs->at_state.pending_commands & PC_SHUTDOWN) { cs->at_state.pending_commands &= ~PC_SHUTDOWN; schedule_sequence(cs, &cs->at_state, SEQ_SHUTDOWN); return; } if (cs->at_state.pending_commands & PC_CIDMODE) { cs->at_state.pending_commands &= ~PC_CIDMODE; if (atomic_read(&cs->mode) == M_UNIMODEM) { cs->retry_count = 1; schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE); return; } } for (i = 0; i < cs->channels; ++i) { bcs = cs->bcs + i; if (bcs->at_state.pending_commands & PC_DLE1) { bcs->at_state.pending_commands &= ~PC_DLE1; cs->curchannel = bcs->channel; schedule_sequence(cs, &cs->at_state, SEQ_DLE1); return; } if (bcs->at_state.pending_commands & PC_ACCEPT) { bcs->at_state.pending_commands &= ~PC_ACCEPT; schedule_sequence(cs, &bcs->at_state, SEQ_ACCEPT); return; } if (bcs->at_state.pending_commands & PC_DIAL) { bcs->at_state.pending_commands &= ~PC_DIAL; schedule_sequence(cs, &bcs->at_state, SEQ_DIAL); return; } if (bcs->at_state.pending_commands & PC_CID) { switch (atomic_read(&cs->mode)) { case M_UNIMODEM: cs->at_state.pending_commands |= PC_CIDMODE; gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); atomic_set(&cs->commands_pending, 1); return;#ifdef GIG_MAYINITONDIAL case M_UNKNOWN: schedule_init(cs, MS_INIT); return;#endif } bcs->at_state.pending_commands &= ~PC_CID; cs->curchannel = bcs->channel;#ifdef GIG_RETRYCID cs->retry_count = 2;#else cs->retry_count = 1;#endif schedule_sequence(cs, &cs->at_state, SEQ_CID); return; } }}static void process_events(struct cardstate *cs){ struct event_t *ev; unsigned head, tail; int i; int check_flags = 0; int was_busy; unsigned long flags; spin_lock_irqsave(&cs->ev_lock, flags); head = cs->ev_head; for (i = 0; i < 2 * MAX_EVENTS; ++i) { tail = cs->ev_tail; if (tail == head) { if (!check_flags && !atomic_read(&cs->commands_pending)) break; check_flags = 0; spin_unlock_irqrestore(&cs->ev_lock, flags); process_command_flags(cs); spin_lock_irqsave(&cs->ev_lock, flags); tail = cs->ev_tail; if (tail == head) { if (!atomic_read(&cs->commands_pending)) break; continue; } } ev = cs->events + head; was_busy = cs->cur_at_seq != SEQ_NONE; spin_unlock_irqrestore(&cs->ev_lock, flags); process_event(cs, ev); spin_lock_irqsave(&cs->ev_lock, flags); kfree(ev->ptr); ev->ptr = NULL; if (was_busy && cs->cur_at_seq == SEQ_NONE) check_flags = 1; head = (head + 1) % MAX_EVENTS; cs->ev_head = head; } spin_unlock_irqrestore(&cs->ev_lock, flags); if (i == 2 * MAX_EVENTS) { dev_err(cs->dev, "infinite loop in process_events; aborting.\n"); }}/* tasklet scheduled on any event received from the Gigaset device * parameter: * data ISDN controller state structure */void gigaset_handle_event(unsigned long data){ struct cardstate *cs = (struct cardstate *) data; /* handle incoming data on control/common channel */ if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) { gig_dbg(DEBUG_INTR, "processing new data"); cs->ops->handle_input(cs->inbuf); } process_events(cs);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?