From 8a34ad3c81b3fc1b5912a202831e9a0f0318a9ed Mon Sep 17 00:00:00 2001 From: Satish kumar sugasi <ssugasi@qca.qualcomm.com> Date: Mon, 19 Oct 2015 18:09:49 -0700 Subject: [PATCH] FM: Add SSR support for cherokee This provide hardware error event to FM module during SOC failure and resets FM gracefully. Change-Id: Ic4345e02c8a1cba218414afdfcf3e76734c314b0 --- fm_hci/fm_hci.c | 82 +++++++++++++++++++++------------ fm_hci/fm_hci.h | 1 + helium/radio-helium.h | 2 + helium/radio_helium_hal.c | 13 ++++++ qcom/fmradio/FmReceiverJNI.java | 16 +++++-- 5 files changed, 81 insertions(+), 33 deletions(-) diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c index fec8bc7..1394565 100644 --- a/fm_hci/fm_hci.c +++ b/fm_hci/fm_hci.c @@ -43,7 +43,7 @@ #include <sys/eventfd.h> #include <errno.h> -int fd; +int fm_fd; fm_hal_cb *hal_cb; void event_notification(uint16_t event) @@ -146,7 +146,7 @@ wait_for_cmd_credits: ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr)); /* Use socket 'fd' to send the command down to WCNSS Filter */ - write(fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); + write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); //write(fd, &temp_1, 1); /* Decrement cmd credits by '1' after sending the cmd*/ @@ -193,6 +193,10 @@ static inline uint64_t read_event() { eventfd_read(event_fd, &value); return value; } +static inline void fm_send_event(uint64_t event_id) { + assert(event_fd != -1); + eventfd_write(event_fd, event_id); +} static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) { @@ -242,6 +246,12 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[3], pbuf->cmd_params[2], pbuf->cmd_params[1], pbuf->cmd_params[0]); evt_type = FM_CMD_STATUS; + } else if (pbuf->evt_code == FM_HW_ERR_EVENT) { + ALOGI("%s: FM H/w Err Event Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); + lib_running =0; + // commented till bt vendor include added + // fm_vnd_if->ssr_cleanup(); + } else { ALOGI("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); evt_type = -1; @@ -290,8 +300,10 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) ALOGE("%s: No data available, though select returned!!!\n", __func__); #endif } - else if (n < 0) - ALOGE("%s: select() failed with return value: %d", __func__, ret); + else if (n < 0) { + ALOGE("%s: select() failed with return value: %d", __func__, ret); + lib_running =0; + } else if (n == 0) ALOGE("%s: select() timeout!!!", __func__); } @@ -303,29 +315,17 @@ static void *userial_read_thread(void *arg) { int length; - while(lib_running) { - - FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); - - ALOGE("%s: Wait for events from the WCNSS Filter", __func__); - length = read_fm_event(fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); - -#if 0 - if (length > 0) { - //TODO: Copy the data to the RX-Q - //TODO: Notify event/data availability - ALOGE("%s: FM Event or RDS data available: Notify FM-HAL Layer", __func__); - event_notification(HC_EVENT_RX); - } else - ALOGE("%s: return value from read_fm_event(): %d", __func__, length); -#endif - //TODO: Have condition for breaking from the loop! - } - lib_running = 0; - ALOGE("%s: Leaving userial_read_thread()", __func__); - pthread_exit(NULL); - - return arg; + FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + + ALOGE("%s: Wait for events from the WCNSS Filter", __func__); + length = read_fm_event(fm_fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + ALOGE("length=%d\n",length); + if(length <=0){ + lib_running =0; + } + ALOGE("%s: Leaving userial_read_thread()", __func__); + pthread_exit(NULL); + return arg; } /* @@ -443,8 +443,8 @@ int open_serial_port() ALOGI("%s: Opening the TTy Serial port...", __func__); ret = fm_vnd_if->op(BT_VND_OP_FM_USERIAL_OPEN, &fd_array); - fd = fd_array[0]; - if (fd == -1) { + fm_fd = fd_array[0]; + if (fm_fd == -1) { ALOGE("%s unable to open TTY serial port", __func__); goto err; } @@ -506,3 +506,27 @@ void transmit(FM_HDR *pbuf) enqueue_fm_tx_cmd(pbuf); event_notification(HC_EVENT_TX); } + +void userial_close_reader(void) { + // Join the reader thread if it is still running. + if (lib_running) { + // send_event(USERIAL_RX_EXIT); + int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL); + if (result) + ALOGE("%s failed to join reader thread: %d", __func__, result); + return; + } + ALOGW("%s Already closed userial reader thread", __func__); +} + +void fm_userial_close(void) { + if (lib_running) { + int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL); + if (result) + ALOGE("%s failed to join reader thread: %d", __func__, result); + } + fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); + // Free all buffers still waiting in the RX queue. + // TODO: use list data structure and clean this up. + fm_fd = -1; +} diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h index 585411e..431179b 100644 --- a/fm_hci/fm_hci.h +++ b/fm_hci/fm_hci.h @@ -69,6 +69,7 @@ typedef enum { #define FM_CMD_COMPLETE 0x0f #define FM_CMD_STATUS 0x10 +#define FM_HW_ERR_EVENT 0x1A static pthread_mutex_t utils_mutex; diff --git a/helium/radio-helium.h b/helium/radio-helium.h index 9952884..8599316 100644 --- a/helium/radio-helium.h +++ b/helium/radio-helium.h @@ -497,6 +497,8 @@ struct hci_fm_blend_table { #define HCI_EV_SEARCH_LIST_COMPLETE 0x14 #define HCI_EV_RADIO_TEXT_PLUS_ID 0x18 #define HCI_EV_RADIO_TEXT_PLUS_TAG 0x19 +#define HCI_EV_HW_ERR_EVENT 0x1A + #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c index 0c68972..a9aa9f0 100644 --- a/helium/radio_helium_hal.c +++ b/helium/radio_helium_hal.c @@ -103,6 +103,9 @@ static void hci_cc_fm_disable_rsp(char *ev_buff) if (radio->mode == FM_TURNING_OFF) { jni_cb->disabled_cb(); radio->mode = FM_OFF; + //close the userial port and power off the chip + fm_userial_close(); + fm_power(FM_RADIO_DISABLE); } } @@ -514,6 +517,13 @@ static void hci_ev_ert() } } +static void hci_ev_hw_error(char *buff) +{ + ALOGE("%s:%s: start", LOG_TAG, __func__); + jni_cb->disabled_cb(); + fm_userial_close(); +} + static void hci_buff_ert(struct rds_grp_data *rds_buf) { int i; @@ -701,6 +711,9 @@ void radio_hci_event_packet(char *evt_buf) case HCI_EV_RADIO_TEXT_PLUS_TAG: hci_ev_rt_plus_tag(((FM_EVT_HDR *)evt_buf)->cmd_params); break; + case HCI_EV_HW_ERR_EVENT: + hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params); + break; default: break; } diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java index 8a2be0f..d8743e8 100644 --- a/qcom/fmradio/FmReceiverJNI.java +++ b/qcom/fmradio/FmReceiverJNI.java @@ -202,10 +202,18 @@ class FmReceiverJNI { public void disableCallback() { Log.e(TAG, "disableCallback enter"); - FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); - Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); - FmReceiver.mCallback.FmRxEvDisableReceiver(); - Log.e(TAG, "disableCallback exit"); + if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) { + /*Set the state as FMOff */ + FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); + Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); + FmReceiver.mCallback.FmRxEvDisableReceiver(); + } else { + FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); + Log.d(TAG, "Unexpected RADIO_DISABLED recvd"); + Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxOn ---> NEW-STATE : FMOff"); + FmReceiver.mCallback.FmRxEvRadioReset(); + Log.e(TAG, "disableCallback exit"); + } } public FmReceiverJNI(FmRxEvCallbacks callback) { -- GitLab