static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) { struct rmnet_mhi_private *rmnet_mhi_ptr; struct mhi_result *result; enum MHI_STATUS r = MHI_STATUS_SUCCESS; if (NULL != cb_info && NULL != cb_info->result) { result = cb_info->result; rmnet_mhi_ptr = result->user_data; } else { rmnet_log(MSG_CRITICAL, "Invalid data in MHI callback, quitting\n"); } switch (cb_info->cb_reason) { case MHI_CB_MHI_DISABLED: rmnet_log(MSG_CRITICAL, "Got MHI_DISABLED notification. Stopping stack\n"); if (rmnet_mhi_ptr->mhi_enabled) { rmnet_mhi_disable(rmnet_mhi_ptr); rmnet_mhi_disable_iface(rmnet_mhi_ptr); } break; case MHI_CB_MHI_ENABLED: rmnet_log(MSG_CRITICAL, "Got MHI_ENABLED notification. Starting stack\n"); if (IS_INBOUND(cb_info->chan)) rmnet_mhi_ptr->rx_enabled = 1; else rmnet_mhi_ptr->tx_enabled = 1; if (rmnet_mhi_ptr->tx_enabled && rmnet_mhi_ptr->rx_enabled) { rmnet_log(MSG_INFO, "Both RX/TX are enabled, enabling iface.\n"); r = rmnet_mhi_enable_iface(rmnet_mhi_ptr); if (r) rmnet_log(MSG_CRITICAL, "Failed to enable iface for chan %d\n", cb_info->chan); else rmnet_log(MSG_INFO, "Enabled iface for chan %d\n", cb_info->chan); } break; case MHI_CB_XFER: if (IS_INBOUND(cb_info->chan)) rmnet_mhi_rx_cb(cb_info->result); else rmnet_mhi_tx_cb(cb_info->result); break; default: break; } }
static void rmnet_mhi_cb(struct mhi_cb_info *cb_info) { struct rmnet_mhi_private *rmnet_mhi_ptr; struct mhi_result *result; enum MHI_STATUS r = MHI_STATUS_SUCCESS; if (NULL != cb_info && NULL != cb_info->result) { result = cb_info->result; rmnet_mhi_ptr = result->user_data; } else { rmnet_log(MSG_CRITICAL, "Invalid data in MHI callback, quitting\n"); } switch (cb_info->cb_reason) { case MHI_CB_MHI_DISABLED: rmnet_log(MSG_CRITICAL, "Got MHI_DISABLED notification. Stopping stack\n"); if (rmnet_mhi_ptr->mhi_enabled) { rmnet_mhi_ptr->mhi_enabled = 0; /* Ensure MHI is disabled before other mem ops */ wmb(); while (atomic_read(&rmnet_mhi_ptr->pending_data)) { rmnet_log(MSG_CRITICAL, "Waiting for channels to stop.\n"); msleep(25); } rmnet_mhi_disable(rmnet_mhi_ptr); } break; case MHI_CB_MHI_ENABLED: rmnet_log(MSG_CRITICAL, "Got MHI_ENABLED notification. Starting stack\n"); if (IS_INBOUND(cb_info->chan)) rmnet_mhi_ptr->rx_enabled = 1; else rmnet_mhi_ptr->tx_enabled = 1; if (rmnet_mhi_ptr->tx_enabled && rmnet_mhi_ptr->rx_enabled) { rmnet_log(MSG_INFO, "Both RX/TX are enabled, enabling iface.\n"); r = rmnet_mhi_enable_iface(rmnet_mhi_ptr); if (r) rmnet_log(MSG_CRITICAL, "Failed to enable iface for chan %d\n", cb_info->chan); else rmnet_log(MSG_INFO, "Enabled iface for chan %d\n", cb_info->chan); } break; case MHI_CB_XFER: atomic_inc(&rmnet_mhi_ptr->pending_data); /* Flush pending data is set before any other mem operations */ wmb(); if (rmnet_mhi_ptr->mhi_enabled) { if (IS_INBOUND(cb_info->chan)) rmnet_mhi_rx_cb(cb_info->result); else rmnet_mhi_tx_cb(cb_info->result); } atomic_dec(&rmnet_mhi_ptr->pending_data); break; default: break; } }