#include "connect.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) #define AVM_LED_INTERNAL #include #undef AVM_LED_INTERNAL #endif #include "../hui_internal.h" extern void *button_event_handle; enum access_type access = access_type_plc_bridge; enum wlan_uplink uplink = wlan_uplink_down; unsigned int log_level = 0; static int boot_complete; int wlan_on = 0; //TODO Save async states more beautiful void store_async_state(int async_event, int val){ if(async_event == event_enable_debug){ log_level = val; return; } if(!val){ return; } switch(async_event){ case event_access_type_plc_bridge: CONNECT_LOG("[avm_connect]: PLC BRIDGE\n"); access = access_type_plc_bridge; connect_log_access_type(access); break; case event_access_type_wlan_bridge: CONNECT_LOG("[avm_connect]: WLAN BRIDGE\n"); access = access_type_wlan_bridge; connect_log_access_type(access); break; case event_access_type_lan_bridge: CONNECT_LOG("[avm_connect]: LAN BRIDGE\n"); access = access_type_lan_bridge; connect_log_access_type(access); break; case event_wlan_sta_register: CONNECT_LOG("[avm_connect]: WLAN UPLINK UP\n"); uplink = wlan_uplink_up; connect_log_uplink(uplink); break; case event_wlan_sta_unregister: case event_wlan_sta_stopping: CONNECT_LOG("[avm_connect]: WLAN UPLINK DOWN\n"); uplink = wlan_uplink_down; connect_log_uplink(uplink); break; case event_wlan_on: wlan_on = 1; boot_complete = 1; break; case event_wlan_error: case event_wlan_off: wlan_on = 0; boot_complete = 1; break; default: break; } } /* LED Events to State Machine Events */ int led_event_to_state_event(enum _led_event event) { switch (event) { case event_wlan_sta_wps_no_connect_start: return connect_event_wlan_sta_wps_no_connect_start; case event_wlan_sta_wps_no_connect_error: return connect_event_wlan_sta_wps_no_connect_error; case event_wlan_sta_wps_no_connect_timeout: return connect_event_wlan_sta_wps_no_connect_timeout; case event_wlan_sta_wps_no_connect_success: return connect_event_wlan_sta_wps_no_connect_success; case event_wlan_sta_wps_no_connect_done: return connect_event_wlan_sta_wps_no_connect_done; case event_nexus_pairing_start: return connect_event_nexus_pairing_start; case event_nexus_pairing_error: return connect_event_nexus_pairing_error; case event_nexus_pairing_success: return connect_event_nexus_pairing_success; case event_nexus_pairing_done: return connect_event_nexus_pairing_done; case event_nexus_pairing_timeout: return connect_event_nexus_pairing_timeout; case event_nexus_pairing_no_trustee_pending: return connect_event_nexus_pairing_no_trustee_pending; case event_plc_pairing_start: return connect_event_plc_pairing_start; case event_plc_pairing_stop: return connect_event_plc_pairing_stop; case event_plc_pairing_done: return connect_event_plc_pairing_done; case event_plc_pairing_error: return connect_event_plc_pairing_error; case event_plc_pairing_timeout: return connect_event_plc_pairing_timeout; case event_plc_pairing_success: return connect_event_plc_pairing_success; case event_plc_pairing_external_error: return connect_event_plc_pairing_external_error; case event_wps_start: return connect_event_wps_start; case event_wps_error: return connect_event_wps_error; case event_wps_timeout: return connect_event_wps_timeout; case event_wps_success: return connect_event_wps_success; case event_wps_done: return connect_event_wps_done; case event_wlan_sta_wps_start: return connect_event_wlan_sta_wps_start; case event_wlan_sta_wps_error: return connect_event_wlan_sta_wps_error; case event_wlan_sta_wps_timeout: return connect_event_wlan_sta_wps_timeout; case event_wlan_sta_wps_success: return connect_event_wlan_sta_wps_success; case event_wlan_sta_wps_done: return connect_event_wlan_sta_wps_done; case event_dect_stick_and_surf_start: return connect_event_dect_stick_and_surf_start; case event_dect_stick_and_surf_error: return connect_event_dect_stick_and_surf_error; case event_dect_stick_and_surf_success: return connect_event_dect_stick_and_surf_success; case event_dect_stick_and_surf_done: return connect_event_dect_stick_and_surf_done; case event_dect_stick_and_surf_timeout: return connect_event_dect_stick_and_surf_timeout; case event_lan_pairing_start: return connect_event_lan_pairing_start; case event_lan_pairing_error: return connect_event_lan_pairing_error; case event_lan_pairing_timeout: return connect_event_lan_pairing_timeout; case event_lan_pairing_success: return connect_event_lan_pairing_success; case event_lan_pairing_done: return connect_event_lan_pairing_done; case event_wlan_on: return connect_event_boot_complete; case event_wlan_error: return connect_event_boot_complete; case event_wlan_off: return connect_event_boot_complete; case event_button_events_disable: return connect_event_button_disable; default: return -1; } } int button_event_to_state_event(int event) { switch (event) { case avm_event_push_button_connect_methode1: return connect_event_methode1_start; case avm_event_push_button_connect_methode2: return connect_event_methode2_start; case avm_event_push_button_connect_methode3: return connect_event_methode3_start; case avm_event_push_button_connect_methode4: return connect_event_methode4_start; case avm_event_push_button_connect_methode5: return connect_event_methode5_start; case avm_event_push_button_connect_methode6: return connect_event_methode6_start; default: return -1; } } static inline const char* button_to_name(int button) { switch (button) { case avm_event_push_button_connect_methode1: return "push_button_connect_methode1"; case avm_event_push_button_connect_methode2: return "push_button_connect_methode2"; case avm_event_push_button_connect_methode3: return "push_button_connect_methode3"; case avm_event_push_button_connect_methode4: return "push_button_connect_methode4"; case avm_event_push_button_connect_methode5: return "push_button_connect_methode5"; case avm_event_push_button_connect_methode6: return "push_button_connect_methode6"; case avm_event_push_button_wlan_wps: return "push_button_wlan_wps"; case avm_event_push_button_wlan_wps_off: return "push_button_wlan_wps_off"; case avm_event_push_button_wlan_wps_station_off: return "avm_event_push_button_wlan_wps_station_off"; case avm_event_push_button_wlan_wps_station: return "avm_event_push_button_wlan_wps_station"; case avm_event_push_button_nexus_pairing: return "push_button_nexus_pairing"; case avm_event_push_button_nexus_pairing_off: return "push_button_nexus_pairing_off"; case avm_event_push_button_dect_pairing: return "push_button_dect_pairing"; case avm_event_push_button_dect_pairing_off: return "push_button_dect_pairing_off"; case avm_event_push_button_plc_pairing: return "push_button_plc_pairing"; case avm_event_push_button_plc_pairing_off: return "push_button_plc_pairing_off"; case avm_event_push_button_wlan_sta_wps_no_connect: return "push_button_wlan_sta_wps_no_connect"; case avm_event_push_button_wlan_sta_wps_no_connect_off: return "push_button_wlan_sta_wps_no_connect_off"; case avm_event_push_button_connect_off: return "push_button_connect_off"; case avm_event_push_button_connect_timeout: return "push_button_connect_timeout"; case avm_event_push_button_connect_error: return "push_button_connect_error"; case avm_event_push_button_connect_success: return "push_button_connect_success"; case avm_event_push_button_connect_started: return "push_button_connect_started"; case avm_event_push_button_lan_pairing: return "push_button_lan_pairing"; case avm_event_push_button_lan_pairing_off: return "push_button_lan_pairing_off"; default: return NULL; } }; /* selects currently active state machine (methode 1...6) */ struct connect_state * state_machine_ptr; /* points to currect state */ struct connect_state * state_machine_current_state; enum connect_state_label state_machine_current_state_label; void send_button_event(enum _avm_event_push_button_key push_button_id){ CONNECT_DEBUG(3, "[avm_connect] sending <%s(%d)>\n", button_to_name(push_button_id), push_button_id); avm_hui_send_button_event(push_button_id, 1); } void send_led_event(enum _led_event event, unsigned int value){ avm_hui_send_event(event, value); } /* State Definitions */ void state_machine_set_state_machine(enum connect_event new_state){ switch(new_state){ case connect_event_methode1_start: send_led_event(event_connect_methode, 1); state_machine_ptr = state_machine_methode1; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode1\n", __func__); break; case connect_event_methode2_start: send_led_event(event_connect_methode, 2); state_machine_ptr = state_machine_methode2; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode2\n", __func__); break; case connect_event_methode3_start: send_led_event(event_connect_methode, 3); state_machine_ptr = state_machine_methode3; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode3\n", __func__); break; case connect_event_methode4_start: send_led_event(event_connect_methode, 4); state_machine_ptr = state_machine_methode4; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode4\n", __func__); break; case connect_event_methode5_start: send_led_event(event_connect_methode, 5); state_machine_ptr = state_machine_methode5; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode5\n", __func__); break; case connect_event_methode6_start: send_led_event(event_connect_methode, 6); state_machine_ptr = state_machine_methode6; CONNECT_DEBUG(3, "[avm_connect][%s] activating methode6\n", __func__); break; default: break; } } /* Idle State Machine */ struct connect_state state_inactive = { .description = "idle", .post_func = state_machine_set_state_machine, .transitions = { {.event = connect_event_methode1_start, .next_state = connect_state_wait}, {.event = connect_event_methode2_start, .next_state = connect_state_wait}, {.event = connect_event_methode3_start, .next_state = connect_state_wait}, {.event = connect_event_methode4_start, .next_state = connect_state_wait}, {.event = connect_event_methode5_start, .next_state = connect_state_wait}, {.event = connect_event_methode6_start, .next_state = connect_state_wait}, } }; /* State Functions */ void connect_state_wait_pre_func(enum connect_event new_state) { // We've already booted, so just trigger away if (boot_complete) state_machine_queue_trigger_event(connect_event_boot_complete); } /* State Machine */ void state_machine_trigger_event(enum connect_event trigger){ int i,k; /* State Machine Ptr must be set */ if(state_machine_ptr){ /* Current State Ptr must be set */ if(state_machine_current_state){ /* Loop over all possible state transitions */ for(i = 0; i < MAX_STATE_TRANSITIONS; i++){ /* Did we find a match ? */ if(state_machine_current_state->transitions[i].event == trigger){ /* We found a match, delete possibly started timeouts */ state_machine_delete_delayed_trigger(); /* is the post func of the old state set? if yes execute */ if(state_machine_current_state->post_func) state_machine_current_state->post_func(trigger); /* Does the new state have a post led event set? if yes send */ if(state_machine_current_state->post_led_event) send_led_event(state_machine_current_state->post_led_event, 1); /* Send all post button events */ for(k = 0; k < MAX_STATE_TRANSITION_EVENTS; k++){ if(state_machine_current_state->post_button_events[k]) send_button_event(state_machine_current_state->post_button_events[k]); } if(state_machine_current_state->description && state_machine_ptr[state_machine_current_state->transitions[i].next_state].description){ CONNECT_LOG("[avm_connect] (%s): --> %s\n", state_machine_current_state->description, state_machine_ptr[state_machine_current_state->transitions[i].next_state].description); connect_log_new_state(state_machine_ptr[state_machine_current_state->transitions[i].next_state].description); } /* Set new state */ state_machine_current_state = &state_machine_ptr[state_machine_current_state->transitions[i].next_state]; /* Set new state Label*/ state_machine_current_state_label = state_machine_current_state->transitions[i].next_state; /* Does the new state have a pre led event set? if yes send */ if(state_machine_current_state->pre_led_event) send_led_event(state_machine_current_state->pre_led_event, 1); /* Send all pre button events */ for(k = 0; k < MAX_STATE_TRANSITION_EVENTS; k++){ if(state_machine_current_state->pre_button_events[k]) send_button_event(state_machine_current_state->pre_button_events[k]); } /* Does the new state have a pre_func set? if yes execute */ if(state_machine_current_state->pre_func) state_machine_current_state->pre_func(state_machine_current_state_label); /* Is an a auto_trigger_event set ?*/ if(state_machine_current_state->auto_trigger_event){ if(state_machine_current_state->timeout_auto_trigger_ms){ state_machine_trigger_event_delayed(state_machine_current_state->timeout_auto_trigger_ms, state_machine_current_state->auto_trigger_event); } else{ state_machine_queue_trigger_event(state_machine_current_state->auto_trigger_event); } } /* if new state does not have any transitions set, we reached final state */ /* execute post if set and reinit state_machine */ if(state_machine_current_state->transitions[0].event == unused){ if(state_machine_current_state->post_func) state_machine_current_state->post_func(trigger); /* Does the new state have a post led event set? if yes send */ if(state_machine_current_state->post_led_event) send_led_event(state_machine_current_state->post_led_event, 1); /* Send all post button events */ for(k = 0; k < MAX_STATE_TRANSITION_EVENTS; k++){ if(state_machine_current_state->post_button_events[k]) send_button_event(state_machine_current_state->post_button_events[k]); } if(state_machine_current_state->description && state_inactive.description){ CONNECT_LOG("[avm_connect] (%s): --> %s\n", state_machine_current_state->description, state_inactive.description); connect_log_new_state(state_inactive.description); } send_led_event(event_connect_methode, 0); send_button_event(avm_event_push_button_connect_off); state_machine_ptr = &state_inactive; state_machine_current_state = &state_inactive; state_machine_current_state_label = connect_state_inactive; } return; } } } else{ printk(KERN_ERR"[avm_connect][%s] current state ptr is not set\n", __func__); } } else{ printk(KERN_ERR"[avm_connect][%s] state ptr is not set\n", __func__); } } static struct task_struct *event_thread; static spinlock_t event_list_lock; struct list_head event_list; static struct timer_list timer_delayed_event; int event_worker_thread(void *unused __maybe_unused){ unsigned long flags = 0; while(!kthread_should_stop()){ /* wait for new cmd */ spin_lock_irqsave(&event_list_lock, flags); if(list_empty(&event_list)){ set_task_state(event_thread, TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&event_list_lock, flags); schedule(); } else{ spin_unlock_irqrestore(&event_list_lock, flags); } if(!list_empty(&event_list)){ enum connect_event trigger; struct event_list_item * trigger_item = list_first_entry(&event_list, struct event_list_item, list); trigger = trigger_item->trigger; spin_lock_irqsave(&event_list_lock, flags); list_del(&trigger_item->list); spin_unlock_irqrestore(&event_list_lock, flags); kfree(trigger_item); state_machine_trigger_event(trigger); } else{ printk(KERN_ERR"[avm_connect][%s] worker thread is running even though list is empty\n", __func__); } } printk(KERN_ERR"[avm_connect][%s]exiting\n", __func__); return 0; } /* Trigger State Event */ void state_machine_queue_trigger_event(enum connect_event trigger){ unsigned long flags = 0; struct event_list_item * trigger_item; trigger_item = kmalloc(sizeof(struct event_list_item), GFP_ATOMIC); if(!trigger_item){ printk(KERN_ERR"[avm_connect][%s] alloc of event_list_item failed\n", __func__); return; } trigger_item->trigger = trigger; /* append to list */ spin_lock_irqsave(&event_list_lock, flags); list_add_tail(&trigger_item->list, &event_list); spin_unlock_irqrestore(&event_list_lock, flags); /* kick thread */ wake_up_process(event_thread); } void delayed_trigger_callback(unsigned long data){ enum connect_event e = (enum connect_event) data; if(e){ state_machine_queue_trigger_event(e); } } void state_machine_delete_delayed_trigger(void){ del_timer_sync(&timer_delayed_event); } void state_machine_trigger_event_delayed(int delay_ms, enum connect_event trigger){ /*--- CONNECT_DEBUG(2, "[avm_connect][%s] event %d delay %d\n", __func__, trigger, delay_ms); ---*/ del_timer_sync(&timer_delayed_event); timer_delayed_event.function = delayed_trigger_callback; timer_delayed_event.data = trigger; timer_delayed_event.expires = jiffies + msecs_to_jiffies(delay_ms); add_timer(&timer_delayed_event); } /* Init */ void state_machine_init(void){ state_machine_ptr = &state_inactive; state_machine_current_state = &state_inactive; state_machine_current_state_label = connect_state_inactive; INIT_LIST_HEAD(&event_list); spin_lock_init(&event_list_lock); event_thread = kthread_create(event_worker_thread, NULL, "avm_connect_event"); init_timer(&timer_delayed_event); if(event_thread){ printk(KERN_INFO"[avm_connect][%s] starting event worker thread\n", __func__); wake_up_process(event_thread); } else{ printk(KERN_ERR"[avm_connect][%s] event worker thread not created\n", __func__); } } /* Event Registration */ static void * connect_led_event_handle; static void * connect_button_event_handle; static void connect_led_sink_handle(void *context __attribute__((unused)), unsigned char *buf, unsigned int len) { struct _avm_event_led_status event; int state_event; if(len < sizeof(event)) { printk(KERN_ERR"[avm_connect][%s] incompatible event len=%u sizeof=%u\n", __func__, len, sizeof(struct _avm_event_led_status)); return; } memcpy(&event, buf, sizeof(event)); if(event.header.id != avm_event_id_led_status) { printk(KERN_ERR"[avm_connect][%s] incompatible event (id=%u)\n", __func__, event.header.id); return; } state_event = led_event_to_state_event(event.led); if(state_event != -1 && (event.state != 0)){ CONNECT_LOG("[avm_connect] (%s): received <%s> state %d\n", state_machine_current_state->description, avm_hui_get_event_name(event.led), event.state); connect_log_led_event(event.led, event.state); state_machine_queue_trigger_event(state_event); } store_async_state(event.led, event.state); } static void connect_button_sink_handle(void *context __attribute__((unused)), unsigned char *buf, unsigned int len) { struct _avm_event_push_button event; int state_event; if(len < sizeof(event)) { printk(KERN_ERR"[avm_connect][%s] incompatible event len=%u sizeof=%u\n", __func__, len, sizeof(struct _avm_event_push_button)); return; } memcpy(&event, buf, sizeof(event)); state_event = button_event_to_state_event(event.key); if(state_event != -1){ CONNECT_LOG("[avm_connect] (%s): received <%s(%d)> with pressed %d\n", state_machine_current_state->description, button_to_name(event.key), event.key, event.pressed); connect_log_button_event(event.key, event.pressed); if(event.pressed > 0){ state_machine_queue_trigger_event(state_event); } /* When pressed == 0 send start events without starting the state machine -> LED Blinking */ else if(event.key == avm_event_push_button_connect_methode1){ send_led_event(event_connect_methode, 1); send_led_event(event_connect_pairing_start, 1); } else if(event.key == avm_event_push_button_connect_methode2){ send_led_event(event_connect_methode, 2); send_led_event(event_connect_pairing_start, 1); } else if(event.key == avm_event_push_button_connect_methode3){ send_led_event(event_connect_methode, 3); send_led_event(event_connect_pairing_start, 1); } else if(event.key == avm_event_push_button_connect_methode4){ send_led_event(event_connect_methode, 4); send_led_event(event_connect_pairing_start, 1); } else if(event.key == avm_event_push_button_connect_methode5){ send_led_event(event_connect_methode, 5); send_led_event(event_connect_pairing_start, 1); } else if(event.key == avm_event_push_button_connect_methode6){ send_led_event(event_connect_methode, 6); send_led_event(event_connect_pairing_start, 1); } } } struct connect_log connect_log_buf[CONNECT_MAX_LOG_ENTRIES]; uint32_t connect_log_buf_pos = 0; uint8_t connect_log_buf_overflow = 0; void connect_buf_inc(void){ connect_log_buf_pos++; if(connect_log_buf_pos >= CONNECT_MAX_LOG_ENTRIES){ connect_log_buf_pos = 0; connect_log_buf_overflow = 1; } } void connect_log_led_event(enum _led_event led_event, uint32_t state){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_led_event; connect_log_buf[connect_log_buf_pos].event = led_event; connect_log_buf[connect_log_buf_pos].param = state; connect_buf_inc(); } void connect_log_button_event(enum _avm_event_push_button_key push_button_id, uint32_t pressed){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_button_event; connect_log_buf[connect_log_buf_pos].event = push_button_id; connect_log_buf[connect_log_buf_pos].param = pressed; connect_buf_inc(); } void connect_log_connect_event(enum connect_event event){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_connect_event; connect_log_buf[connect_log_buf_pos].event = event; connect_buf_inc(); } void connect_log_new_state(char * new_state_desc){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_new_state; connect_log_buf[connect_log_buf_pos].new_state_desc = new_state_desc; connect_buf_inc(); } void connect_log_access_type(enum access_type acc){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_access; connect_log_buf[connect_log_buf_pos].event = acc; connect_buf_inc(); } void connect_log_uplink(enum wlan_uplink up){ struct timeval now; do_gettimeofday(&now); connect_log_buf[connect_log_buf_pos].totalsecs = now.tv_sec; connect_log_buf[connect_log_buf_pos].current_state_desc = state_machine_current_state->description; connect_log_buf[connect_log_buf_pos].log_type = log_type_uplink; connect_log_buf[connect_log_buf_pos].event = up; connect_buf_inc(); } static void proc_print_header(struct seq_file *seq, uint32_t index){ struct tm tm_val; time_to_tm(connect_log_buf[index].totalsecs, 0, &tm_val); seq_printf(seq, "[%lu-%02d-%02d %02d:%02d:%02d]", tm_val.tm_year + 1900, tm_val.tm_mon + 1, tm_val.tm_mday, tm_val.tm_hour, tm_val.tm_min, tm_val.tm_sec); seq_printf(seq, "(%s): ",connect_log_buf[index].current_state_desc ); } static void proc_print_entry(struct seq_file *seq, uint32_t index){ proc_print_header(seq, index); switch(connect_log_buf[index].log_type){ case log_type_led_event: seq_printf(seq, "received <%s> state %d\n", avm_hui_get_event_name(connect_log_buf[index].event), connect_log_buf[index].param); break; case log_type_button_event: seq_printf(seq, "received <%s(%d)> with pressed %d\n", button_to_name(connect_log_buf[index].event), connect_log_buf[index].event, connect_log_buf[index].param); break; case log_type_connect_event: seq_printf(seq, "event %d\n", connect_log_buf[index].event); break; case log_type_new_state: seq_printf(seq, "--> %s\n", connect_log_buf[index].new_state_desc); break; case log_type_access: if(connect_log_buf[index].event == access_type_lan_bridge){ seq_printf(seq, "LAN BRIDGE\n"); } else if(connect_log_buf[index].event == access_type_plc_bridge){ seq_printf(seq, "PLC BRIDGE\n"); } else{ seq_printf(seq, "WLAN BRIDGE\n"); } break; case log_type_uplink: if(connect_log_buf[index].event == wlan_uplink_up){ seq_printf(seq, "WLAN UPLINK UP\n"); } else{ seq_printf(seq, "WLAN UPLINK DOWN\n"); } break; default: break; } } static void proc_connect_log(struct seq_file *seq, void *priv __maybe_unused){ if((connect_log_buf_pos == 0) && (connect_log_buf_overflow == 0)){ seq_printf(seq, "No Entries\n"); return; } else{ uint32_t i; if(connect_log_buf_overflow){ for(i = connect_log_buf_pos; i < CONNECT_MAX_LOG_ENTRIES; i++){ proc_print_entry(seq, i); } } for(i = 0; i < connect_log_buf_pos; i++){ proc_print_entry(seq, i); } } } int connect_init(void){ struct _avm_event_id_mask id_mask; state_machine_init(); connect_led_event_handle = avm_event_sink_register("avm_led_event_notify", avm_event_build_id_mask(&id_mask, 1, avm_event_id_led_status), connect_led_sink_handle, NULL ); if(!connect_led_event_handle){ printk(KERN_ERR"[avm_connect][%s] Failed to register sink avm_led_event_notify. Connect System will not work\n", __func__); return -ENODEV; } connect_button_event_handle = avm_event_sink_register("avm_led_event_push_button_notify", avm_event_build_id_mask(&id_mask, 1, avm_event_id_push_button), connect_button_sink_handle, NULL ); if(!connect_button_event_handle){ printk(KERN_ERR"[avm_connect][%s] Failed to register sink avm_event_id_push_button. Connect System will not work\n", __func__); return -ENODEV; } add_simple_proc_file( "avm/connect_log", NULL, proc_connect_log, NULL); return 0; } int connect_exit(void){ if(connect_led_event_handle){ avm_event_sink_release(connect_led_event_handle); connect_led_event_handle = NULL; } if(connect_button_event_handle){ avm_event_sink_release(connect_button_event_handle); connect_button_event_handle = NULL; } if(event_thread){ kthread_stop(event_thread); } remove_simple_proc_file("avm/connect_log"); return 0; }