diff --git a/fm_hci/Android.mk b/fm_hci/Android.mk index 254690291a6db44510ff877e6186285270b8f05c..c1642354ee0d829da552a8929b0ca75200d3c0ad 100644 --- a/fm_hci/Android.mk +++ b/fm_hci/Android.mk @@ -16,7 +16,7 @@ BDROID_DIR:= system/bt LOCAL_CFLAGS += $(bdroid_CFLAGS) LOCAL_SRC_FILES := \ - fm_hci.c + fm_hci.c LOCAL_SHARED_LIBRARIES := \ libdl \ @@ -30,7 +30,8 @@ LOCAL_C_INCLUDES += \ $(BDROID_DIR)/hci/include \ $(BDROID_DIR)/stack/include \ $(BDROID_DIR)/osi/include \ - $(LOCAL_PATH)/../helium + $(LOCAL_PATH)/../helium \ + $(LOCAL_PATH)/fm_hci LOCAL_MODULE := libfm-hci LOCAL_MODULE_TAGS := optional diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c index d559b74ed01d1e0cebad79c6b0ad6bd79c0030c7..47932955a5732dff3ae316c2b302d5f916ace90f 100644 --- a/fm_hci/fm_hci.c +++ b/fm_hci/fm_hci.c @@ -39,7 +39,6 @@ #include "wcnss_hci.h" #include <stdlib.h> #include <dlfcn.h> -#include <sys/eventfd.h> #include <errno.h> #include <string.h> #include <sys/socket.h> @@ -50,260 +49,205 @@ #include <sys/stat.h> #include <sys/un.h> #include <cutils/properties.h> +#include <signal.h> -int fm_fd; static int fm_hal_fd =0; -fm_hal_cb *hal_cb; #define FM_VND_SERVICE_START "wc_transport.start_fmhci" #define WAIT_TIMEOUT 200000 /* 200*1000us */ -// The set of events one can send to the userial read thread. -// Note that the values must be >= 0x8000000000000000 to guarantee delivery -// of the message (see eventfd(2) for details on blocking behaviour). -enum { - USERIAL_RX_EXIT = 0x8000000000000000ULL -}; -bt_vendor_interface_t *fm_vnd_if = NULL; +static void fm_hci_exit(void *arg); -void event_notification(uint16_t event) +static void event_notification(struct fm_hci_t *hci, uint16_t event) { - pthread_mutex_lock(&fmHCIControlBlock.event_lock); - ready_events |= event; - pthread_cond_signal(&fmHCIControlBlock.event_cond); + pthread_mutex_lock(&hci->event_lock); ALOGI("%s: Notifying worker thread with event: %d", __func__, event); - pthread_mutex_unlock(&fmHCIControlBlock.event_lock); + ready_events |= event; + pthread_cond_broadcast(&hci->event_cond); + pthread_mutex_unlock(&hci->event_lock); } -void init_vnd_if() + +static void rx_thread_exit_handler(int sig) { - void *dlhandle; + ALOGD("%s: sig = 0x%x", __func__, sig); + if (sig == SIGUSR1) { + ALOGE("Got the signal.. exiting"); + pthread_exit(NULL); + } +} + +static int vendor_init(struct fm_hci_t *hci) +{ + void *dlhandle = hci->dlhandle = NULL; unsigned char bdaddr[] = {0xaa, 0xbb, 0xcc, 0x11, 0x22, 0x33}; dlhandle = dlopen("libbt-vendor.so", RTLD_NOW); - if (!dlhandle) - { + if (!dlhandle) { ALOGE("!!! Failed to load libbt-vendor.so !!!"); - return; + goto err; } - fm_vnd_if = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); - if (!fm_vnd_if) - { + hci->vendor = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); + if (!hci->vendor) { ALOGE("!!! Failed to get bt vendor interface !!!"); - return; + goto err; } ALOGI("FM-HCI: Registering the WCNSS HAL library by passing CBs and BD addr."); - fm_vnd_if->init(&fm_vendor_callbacks, bdaddr); -} + if (hci->vendor->init(&fm_vendor_callbacks, bdaddr) != + FM_HC_STATUS_SUCCESS) { + ALOGE("FM vendor interface init failed"); + goto err; + } + + return FM_HC_STATUS_SUCCESS; -volatile uint16_t command_credits; +err: + return FM_HC_STATUS_FAIL; +} -/* De-queues the FM CMD from the TX_Q */ -void dequeue_fm_tx_cmd() +static void vendor_close(struct fm_hci_t *hci) { - TX_Q *new_first, *new_last; - static int cmd_count = 0; - static uint8_t credits = 0; - uint8_t i; - uint8_t temp_1 = 0x11; - - if (cmd_count >= MAX_FM_CMD_CNT) { - ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n"); - lib_running = 0; - return; - } - /* - * Save the 'first' pointer and make it NULL. - * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q - * without having to contend for the 'tx_q_lock' with the FM-HCI thread. - * Once the pointer to the 'first' element in the TX_Q is available, - * send all the commands in the queue to WCNSS FILTER based on the - * command credits provided by the Controller. If command credits are - * not available, then wait for the same. - */ - pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); - if (!fmHCIControlBlock.first) { - ALOGI("No FM CMD available in the Q\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return; - } - else { - new_first = fmHCIControlBlock.first; - new_last = fmHCIControlBlock.last; - fmHCIControlBlock.first = fmHCIControlBlock.last = NULL; - } - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + void *dlhandle = hci->dlhandle; - //credits = command_credits; + if (hci->vendor) + hci->vendor->cleanup(); + if (dlhandle) { + dlclose(dlhandle); + dlhandle = NULL; + } + hci->vendor = NULL; +} - TX_Q *temp = new_first; - while(temp != NULL) { +/* De-queues the FM CMD from the struct transmit_queue_t */ +static void dequeue_fm_tx_cmd(struct fm_hci_t *hci) +{ + struct transmit_queue_t *temp; + uint16_t count = 0, len = 0; + + ALOGD("%s", __func__); + while (1) { + pthread_mutex_lock(&hci->tx_q_lock); + temp = hci->first; + if (!temp) { + ALOGI("No FM CMD available in the Queue\n"); + pthread_mutex_unlock(&hci->tx_q_lock); + return; + } else { + hci->first = temp->next; + } + pthread_mutex_unlock(&hci->tx_q_lock); wait_for_cmd_credits: - pthread_mutex_lock(&fmHCIControlBlock.credit_lock); - while (command_credits == 0) { - ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n"); - pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock); + pthread_mutex_lock(&hci->credit_lock); + while (hci->command_credits == 0) { + pthread_cond_wait(&hci->cmd_credits_cond, &hci->credit_lock); } - pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); + pthread_mutex_unlock(&hci->credit_lock); /* Check if we really got the command credits */ - //REVISIT this area - //if (credits) { - if (command_credits) { - ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode); - - if (temp->hdr->plen) { - ALOGI("%s: CMD-PARAMS:", __func__); - for (i = 0; i < temp->hdr->plen; i++) - ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]); - } else - ALOGE("%s: NO CMD-PARAMS available for this command", __func__); + if (hci->command_credits) { - ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr)); + len = sizeof(struct fm_command_header_t) + temp->hdr->len; +again: /* Use socket 'fd' to send the command down to WCNSS Filter */ - write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); - //write(fd, &temp_1, 1); + count = write(hci->fd, (uint8_t *)temp->hdr + count, len); - /* Decrement cmd credits by '1' after sending the cmd*/ - command_credits--; - - /* TODO: - * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the - * number of outstanding commands in the TX-Q ?? - */ - cmd_count--; + if (count < len) { + len -= count; + goto again; + } + count = 0; - /* Fetch the next cmd to be sent */ - temp = temp->next; + /* Decrement cmd credits by '1' after sending the cmd*/ + pthread_mutex_lock(&hci->credit_lock); + hci->command_credits--; + pthread_mutex_unlock(&hci->credit_lock); } else { if (!lib_running) break; - - ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n"); goto wait_for_cmd_credits; } } } - -static int event_fd = -1; - -static inline int add_event_fd(fd_set *set) { - if (event_fd == -1) { - event_fd = eventfd(0, 0); - if (event_fd == -1) { - ALOGE("%s unable to create event fd: %s", __func__, strerror(errno)); - return -1; - } +static int read_fm_event(struct fm_hci_t *hci, struct fm_event_header_t *pbuf, int len) +{ + fd_set readFds; + sigset_t sigmask, emptymask; + int n = 0, ret = -1, evt_len = -1; + volatile int fd = hci->fd; + struct sigaction action; + + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGUSR1); + if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) { + ALOGE("failed to sigprocmask"); } + memset(&action, 0, sizeof(struct sigaction)); + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = rx_thread_exit_handler; - FD_SET(event_fd, set); - return event_fd; -} - -static inline uint64_t read_event() { - assert(event_fd != -1); - - uint64_t value = 0; - 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); -} + sigemptyset(&emptymask); -static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) -{ - fd_set readFds; - int n = 0, ret = -1, evt_type = -1, evt_len = -1; + if (sigaction(SIGUSR1, &action, NULL) < 0) { + ALOGE("%s:sigaction failed", __func__); + } while (lib_running) { FD_ZERO(&readFds); FD_SET(fd, &readFds); - if (event_fd == -1) { - event_fd = eventfd(0, 0); - if (event_fd == -1) { - ALOGE("%s: unable to create event fd: %s", __func__, strerror(errno)); - return -1; - } - } - FD_SET(event_fd, &readFds); - int fd_max = (event_fd > fd ? event_fd : fd); - ALOGV("%s: Waiting for events from WCNSS FILTER...\n", __func__); /* Wait for event/data from WCNSS Filter */ - n = select(fd_max+1, &readFds, NULL, NULL, NULL); + n = pselect(fd+1, &readFds, NULL, NULL, NULL, &emptymask); if (n > 0) { /* Check if event is available or not */ if (FD_ISSET(fd, &readFds)) { - ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS)); + ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS)); if (0 == ret) { - ALOGD("%s: read() returned '0' bytes\n", __func__); + ALOGV("%s: read() returned '0' bytes\n", __func__); + break; } else { ALOGV("%s: read() returned %d bytes of FM event/data\n", __func__, ret); while (ret > 0) { + pthread_mutex_lock(&hci->credit_lock); if (pbuf->evt_code == FM_CMD_COMPLETE) { - ALOGI("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t" - "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", - __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[2], pbuf->cmd_params[1], - pbuf->cmd_params[0], pbuf->cmd_params[3]); - evt_type = FM_CMD_COMPLETE; + hci->command_credits = pbuf->params[0]; + pthread_cond_signal(&hci->cmd_credits_cond); } else if (pbuf->evt_code == FM_CMD_STATUS) { - ALOGI("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t" - "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", - __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; + hci->command_credits = pbuf->params[1]; + pthread_cond_signal(&hci->cmd_credits_cond); } 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; - fm_vnd_if->ssr_cleanup(0x22); + hci->vendor->ssr_cleanup(0x22); } else { - ALOGI("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); - evt_type = -1; + ALOGE("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); } + pthread_mutex_unlock(&hci->credit_lock); evt_len = pbuf->evt_len; - /* Notify 'fmHCITask' about availability of event or data */ - ALOGI("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__); - event_notification(HC_EVENT_RX); + /* Notify 'hci_tx_thread' about availability of event or data */ + ALOGI("%s: \nNotifying 'hci_tx_thread' availability of FM event or data...\n", __func__); + event_notification(hci, HC_EVENT_RX); - if (hal_cb && hal_cb->fm_evt_notify != NULL) - hal_cb->fm_evt_notify((uint8_t *)pbuf); + if (hci->cb && hci->cb->process_event) + hci->cb->process_event(hci->private_data, (uint8_t *)pbuf); else ALOGE("%s: ASSERT $$$$$$ Callback function NULL $$$$$", __func__); - if((evt_type == FM_CMD_STATUS) || (evt_type == FM_CMD_COMPLETE)) { - /* Provide command credits to allow fmHCITask to send cmds */ - pthread_mutex_lock(&fmHCIControlBlock.credit_lock); - if (evt_type == FM_CMD_COMPLETE) { - ALOGD("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0], - pbuf->cmd_params[2], pbuf->cmd_params[1]); - command_credits = pbuf->cmd_params[0]; - } else if (evt_type == FM_CMD_STATUS) { - ALOGI("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1], - pbuf->cmd_params[3], pbuf->cmd_params[2]); - command_credits = pbuf->cmd_params[1]; - } - pthread_cond_signal(&fmHCIControlBlock.cmd_credits_cond); - pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); - } - ret = ret - (evt_len + 3); ALOGD("%s: Length of available bytes @ HCI Layer: %d", __func__, ret); if (ret > 0) { - ALOGD("%s: Remaining bytes of event/data: %d", __func__, ret); - pbuf = (FM_EVT_HDR *)&pbuf->cmd_params[evt_len]; - ALOGD("%s: Protocol byte of next packet: 0x%2x", __func__, pbuf[0]); + ALOGE("%s: Remaining bytes of event/data: %d", __func__, ret); + pbuf = (struct fm_event_header_t *)&pbuf->params[evt_len]; } } } //end of processing the event @@ -322,19 +266,19 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) return ret; } -static void *userial_read_thread(void *arg) +static void *hci_read_thread(void *arg) { int length; + struct fm_hci_t *hci = (struct fm_hci_t *)arg; - FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + struct fm_event_header_t *evt_buf = (struct fm_event_header_t *) malloc(sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS); - ALOGD("%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); + length = read_fm_event(hci, evt_buf, sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS); ALOGD("length=%d\n",length); if(length <=0) { lib_running =0; } - ALOGD("%s: Leaving userial_read_thread()", __func__); + ALOGV("%s: Leaving hci_read_thread()", __func__); pthread_exit(NULL); return arg; } @@ -362,33 +306,39 @@ int connect_to_local_fmsocket(char* name) { } /* - * Reads the FM-CMDs from the TX_Q and sends it down to WCNSS Filter + * Reads the FM-CMDs from the struct transmit_queue_t and sends it down to WCNSS Filter * Reads events sent by the WCNSS Filter and copies onto RX_Q */ -static void* fmHCITask(void *arg) +static void* hci_tx_thread(void *arg) { - static uint16_t events; - uint16_t ret; + uint16_t events; + struct fm_hci_t *hci = (struct fm_hci_t *)arg; + while (lib_running) { - pthread_mutex_lock(&fmHCIControlBlock.event_lock); - while (ready_events == 0) { - pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock); - } + pthread_mutex_lock(&hci->event_lock); + pthread_cond_wait(&hci->event_cond, &hci->event_lock); + ALOGE("%s: ready_events= %d", __func__, ready_events); events = ready_events; - ready_events = 0; - pthread_mutex_unlock(&fmHCIControlBlock.event_lock); - - if ((events & 0xFFF8) == HC_EVENT_TX) { - ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n"); - dequeue_fm_tx_cmd(); + if (ready_events & HC_EVENT_TX) + ready_events &= (~HC_EVENT_TX); + if (ready_events & HC_EVENT_RX) + ready_events &= (~HC_EVENT_RX); + pthread_mutex_unlock(&hci->event_lock); + + if (events & HC_EVENT_TX) { + dequeue_fm_tx_cmd(hci); } - if ((events & 0xFFF4) == HC_EVENT_RX) { + if (events & HC_EVENT_RX) { ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n"); } + if (events & HC_EVENT_EXIT) { + ALOGE("GOT HC_EVENT_EXIT.. exiting"); + break; + } } - ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__); - return arg; + ALOGV("%s: ##### Exiting hci_tx_thread Worker thread!!! #####", __func__); + return NULL; } void stop_fmhal_service() { @@ -435,122 +385,193 @@ void start_fmhal_service() { ALOGI("%s: Exit ", __func__); } -int fm_hci_init(fm_hal_cb *p_cb) +static int start_tx_thread(struct fm_hci_t *hci) { - pthread_attr_t thread_attr; struct sched_param param; - int policy, result, hci_type; - - ALOGI("FM-HCI: init"); - start_fmhal_service(); - /* Save the FM-HAL event notofication callback func. */ - hal_cb = p_cb; - fm_hal_fd = connect_to_local_fmsocket("fmhal_sock"); - if(fm_hal_fd != -1) - { - ALOGI("FM hal service socket connect success.."); - } - ALOGI("fm_hal_fd = %d", fm_hal_fd); - //if(fm_hal_fd == -1) - // return FM_HC_STATUS_FAIL; - ALOGI("%s: Initializing FM-HCI layer...", __func__); - lib_running = 1; - ready_events = 0; - command_credits = 1; - - pthread_mutex_init(&fmHCIControlBlock.tx_q_lock, NULL); - pthread_mutex_init(&fmHCIControlBlock.credit_lock, NULL); - pthread_mutex_init(&fmHCIControlBlock.event_lock, NULL); - - pthread_cond_init(&fmHCIControlBlock.event_cond, NULL); - pthread_cond_init(&fmHCIControlBlock.cmd_credits_cond, NULL); - - pthread_attr_init(&thread_attr); + int policy, result; ALOGI("FM-HCI: Creating the FM-HCI TASK..."); - if (pthread_create(&fmHCIControlBlock.fmHCITaskThreadId, &thread_attr, \ - fmHCITask, NULL) != 0) + if (pthread_create(&hci->tx_thread, NULL, hci_tx_thread, hci) != 0) { ALOGE("pthread_create failed!"); lib_running = 0; return FM_HC_STATUS_FAIL; } - ALOGI("FM-HCI: Configuring the scheduling policy and priority of the FM HCI thread"); - if(pthread_getschedparam(fmHCIControlBlock.fmHCITaskThreadId, &policy, ¶m)==0) + if(pthread_getschedparam(hci->tx_thread, &policy, ¶m)==0) { policy = SCHED_NORMAL; #if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL) param.sched_priority = BTHC_MAIN_THREAD_PRIORITY; #endif - result = pthread_setschedparam(fmHCIControlBlock.fmHCITaskThreadId, policy, ¶m); + result = pthread_setschedparam(hci->tx_thread, policy, ¶m); if (result != 0) { - ALOGW("libbt-hci init: pthread_setschedparam failed (%s)", \ - strerror(result)); + ALOGW("libbt-hci init: pthread_setschedparam failed (%d)", \ + result); } } else ALOGI("FM-HCI: Failed to get the Scheduling parameters!!!"); - ALOGI("FM-HCI: Loading the WCNSS HAL library..."); - init_vnd_if(); return FM_HC_STATUS_SUCCESS; } +static void stop_tx_thread(struct fm_hci_t *hci) +{ + int ret; + + ALOGV("%s++", __func__); + if ((ret = pthread_kill(hci->tx_thread, SIGUSR1)) + == FM_HC_STATUS_SUCCESS) { + ALOGE("%s:pthread_join", __func__); + if ((ret = pthread_join(hci->tx_thread, NULL)) != FM_HC_STATUS_SUCCESS) + ALOGE("Error joining tx thread, error = %d (%s)", + ret, strerror(ret)); + } else { + ALOGE("Error killing tx thread, error = %d (%s)", + ret, strerror(ret)); + } +} -int fm_power(fm_power_state state) +static void *hci_mon_thread(void *arg) { - int i,opcode,ret; - int init_success = 0; - char value[PROPERTY_VALUE_MAX] = {'\0'}; - if (fm_hal_fd) - { - if (state) - opcode = 2; - else { - opcode = 1; + struct fm_hci_t *hci = (struct fm_hci_t *)arg; + uint16_t events; + ALOGV("%s", __func__); + + while (lib_running) { + pthread_mutex_lock(&hci->event_lock); + if (!(ready_events & HC_EVENT_EXIT)) + pthread_cond_wait(&hci->event_cond, &hci->event_lock); + events = ready_events; + if (ready_events & HC_EVENT_EXIT) + ready_events &= (~HC_EVENT_EXIT); + pthread_mutex_unlock(&hci->event_lock); + + ALOGD("events = 0x%x", events); + if (events & HC_EVENT_EXIT) { + ALOGD("Got Exit event.. Exiting HCI"); + fm_hci_exit(hci); + break; } - ALOGI("%s:opcode: %x", LOG_TAG, opcode); - ret = write(fm_hal_fd,&opcode, 1); - if (ret < 0) - { - ALOGE("failed to write fm hal socket"); - } } - else { - ALOGE("Connect to socket failed .."); - ret = -1; + ALOGV("%s--", __func__); + return NULL; +} + +static int start_mon_thread(struct fm_hci_t *hci) +{ + int ret = FM_HC_STATUS_SUCCESS; + ALOGD("%s", __func__); + if ((ret = pthread_create(&hci->mon_thread, NULL, + hci_mon_thread, hci)) !=0) { + ALOGE("pthread_create failed! status = %d (%s)", + ret, strerror(ret)); + lib_running = 0; } - if(state == FM_RADIO_DISABLE) { - for (i=0; i<10; i++) { - property_get("wc_transport.fm_power_status", value, "0"); - if (strcmp(value, "0") == 0) { - init_success = 1; - break; - } else { - usleep(WAIT_TIMEOUT); - } - } - ALOGI("fm power OFF status:%d after %f seconds \n", init_success, 0.2*i); - stop_fmhal_service(); + return ret; +} + +static void stop_mon_thread(struct fm_hci_t *hci) +{ + int ret; + ALOGV("%s++", __func__); + if ((ret = pthread_kill(hci->mon_thread, SIGUSR1)) + == FM_HC_STATUS_SUCCESS) { + ALOGE("%s:pthread_join", __func__); + if ((ret = pthread_join(hci->mon_thread, NULL)) != FM_HC_STATUS_SUCCESS) + ALOGE("Error joining mon thread, error = %d (%s)", + ret, strerror(ret)); + } else { + ALOGE("Error killing mon thread, error = %d (%s)", + ret, strerror(ret)); } - if (state == FM_RADIO_ENABLE) { - for (i=0; i<10; i++) { - property_get("wc_transport.fm_power_status", value, "0"); - if (strcmp(value, "1") == 0) { - init_success = 1; - break; - } else { - usleep(WAIT_TIMEOUT); - } - } - ALOGI("fm power ON status:%d after %f seconds \n", init_success, 0.2*i); +} + +static int start_rx_thread(struct fm_hci_t *hci) +{ + int ret = FM_HC_STATUS_SUCCESS; + ALOGV("%s++", __func__); + + ALOGD("%s: Starting the userial read thread....", __func__); + if ((ret = pthread_create(&hci->rx_thread, NULL, \ + hci_read_thread, hci)) != 0) { + ALOGE("pthread_create failed! status = %d (%s)", + ret, strerror(ret)); + lib_running = 0; + } + return ret; +} + +static void stop_rx_thread(struct fm_hci_t *hci) +{ + int ret; + ALOGV("%s++", __func__); + if ((ret = pthread_kill(hci->rx_thread, SIGUSR1)) + == FM_HC_STATUS_SUCCESS) { + ALOGE("%s:pthread_join", __func__); + if ((ret = pthread_join(hci->rx_thread, NULL)) != FM_HC_STATUS_SUCCESS) + ALOGE("Error joining rx thread, error = %d (%s)", + ret, strerror(ret)); + } else { + ALOGE("Error killing rx thread, error = %d (%s)", + ret, strerror(ret)); } - return ret; +} + +static int power(struct fm_hci_t *hci, fm_power_state_t state) +{ + int i,opcode,ret; + int init_success = 0; + char value[PROPERTY_VALUE_MAX] = {'\0'}; + if (fm_hal_fd) + { + if (state) + opcode = 2; + else { + opcode = 1; + } + ALOGI("%s:opcode: %x", LOG_TAG, opcode); + ret = write(fm_hal_fd,&opcode, 1); + if (ret < 0) { + ALOGE("failed to write fm hal socket"); + } else { + ret = FM_HC_STATUS_SUCCESS; + } + } else { + ALOGE("Connect to socket failed .."); + ret = -1; + } + if (state == FM_RADIO_DISABLE) { + for (i=0; i<10; i++) { + property_get("wc_transport.fm_power_status", value, "0"); + if (strcmp(value, "0") == 0) { + init_success = 1; + break; + } else { + usleep(WAIT_TIMEOUT); + } + } + ALOGI("fm power OFF status:%d after %f seconds \n", init_success, 0.2*i); + stop_fmhal_service(); + } + if (state == FM_RADIO_ENABLE) { + for (i=0; i<10; i++) { + property_get("wc_transport.fm_power_status", value, "0"); + if (strcmp(value, "1") == 0) { + init_success = 1; + break; + } else { + usleep(WAIT_TIMEOUT); + } + } + ALOGI("fm power ON status:%d after %f seconds \n", init_success, 0.2*i); + } + return ret; } #define CH_MAX 3 -int open_serial_port() +static int serial_port_init(struct fm_hci_t *hci) { int i, ret; int fd_array[CH_MAX]; @@ -559,110 +580,198 @@ int open_serial_port() fd_array[i] = -1; ALOGI("%s: Opening the TTy Serial port...", __func__); - ret = fm_vnd_if->op(BT_VND_OP_FM_USERIAL_OPEN, &fd_array); + ret = hci->vendor->op(BT_VND_OP_FM_USERIAL_OPEN, &fd_array); - fm_fd = fd_array[0]; - if (fm_fd == -1) { + if (fd_array[0] == -1) { ALOGE("%s unable to open TTY serial port", __func__); goto err; } + hci->fd = fd_array[0]; + + return FM_HC_STATUS_SUCCESS; - //TODO: Start the userial read thread here - ALOGE("%s: Starting the userial read thread....", __func__); - if (pthread_create(&fmHCIControlBlock.fmRxTaskThreadId, NULL, \ - userial_read_thread, NULL) != 0) - { - ALOGE("pthread_create failed!"); - lib_running = 0; - return FM_HC_STATUS_FAIL; - } - return 0; err: - ALOGI("%s: Closing the TTy Serial port due to error!!!", __func__); - ret = fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); - return -1; + return FM_HC_STATUS_FAIL; +} + +static void serial_port_close(struct fm_hci_t *hci) +{ + //TODO: what if hci/fm_vnd_if is null.. need to take lock and check + ALOGI("%s: Closing the TTy Serial port!!!", __func__); + hci->vendor->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); + hci->fd = -1; } -int enqueue_fm_tx_cmd(FM_HDR *pbuf) +static int enqueue_fm_tx_cmd(struct fm_hci_t *hci, struct fm_command_header_t *pbuf) { + struct transmit_queue_t *element = (struct transmit_queue_t *) malloc(sizeof(struct transmit_queue_t)); - pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); + if (!element) { + ALOGI("Failed to allocate memory for element!!\n"); + return FM_HC_STATUS_NOMEM; + } + element->hdr = pbuf; + element->next = NULL; - if (!fmHCIControlBlock.first) { - fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q)); - if (!fmHCIControlBlock.first) { - ALOGI("Failed to allocate memory for first!!\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return FM_HC_STATUS_NOMEM; - } - fmHCIControlBlock.first->hdr = pbuf; - fmHCIControlBlock.first->next = NULL; - fmHCIControlBlock.last = fmHCIControlBlock.first; - ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__); + pthread_mutex_lock(&hci->tx_q_lock); + + if (!hci->first) { + hci->last = hci->first = element; } else { - TX_Q *element = (TX_Q *) malloc(sizeof(TX_Q)); - if (!element) { - ALOGI("Failed to allocate memory for element!!\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return FM_HC_STATUS_NOMEM; - } - fmHCIControlBlock.last->next = element; - element->hdr = pbuf; - element->next = NULL; - fmHCIControlBlock.last = element; - ALOGI("%s: fm-cmd enqueued successfully", __func__); + hci->last->next = element; + hci->last = element; } + ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__); + + pthread_mutex_unlock(&hci->tx_q_lock); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); return FM_HC_STATUS_SUCCESS; } -/** Transmit frame */ -int transmit(FM_HDR *pbuf) +int fm_hci_transmit(void *hci, struct fm_command_header_t *buf) { int status = FM_HC_STATUS_FAIL; - if ((status = enqueue_fm_tx_cmd(pbuf)) == FM_HC_STATUS_SUCCESS) - event_notification(HC_EVENT_TX); - /* Cleanup Threads if Disable command sent */ - if ((pbuf->opcode == hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, - HCI_OCF_FM_DISABLE_RECV_REQ))) { - ALOGD("FM Disable cmd. Waiting for threads to finish"); - if ((status = pthread_join(fmHCIControlBlock.fmHCITaskThreadId, NULL))) - ALOGE("Failed to join HCI task thread. err = %d", status); - if ((status = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL))) - ALOGE("Failed to join HCI reader thread. err = %d", status); - pthread_cond_destroy(&fmHCIControlBlock.cmd_credits_cond); - pthread_cond_destroy(&fmHCIControlBlock.event_cond); - pthread_mutex_destroy(&fmHCIControlBlock.event_lock); - pthread_mutex_destroy(&fmHCIControlBlock.credit_lock); - pthread_mutex_destroy(&fmHCIControlBlock.tx_q_lock); - ALOGD("All Threads are done. Exiting."); + if (!hci || !buf) { + ALOGE("NULL input arguments"); + return FM_HC_STATUS_NULL_POINTER; } + if ((status = enqueue_fm_tx_cmd((struct fm_hci_t *)hci, buf)) + == FM_HC_STATUS_SUCCESS) + event_notification(hci, HC_EVENT_TX); + return status; } -void userial_close_reader(void) { - // Join the reader thread if it is still running. - if (lib_running) { - fm_send_event(USERIAL_RX_EXIT); - int result = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL); - if (result) - ALOGE("%s failed to join reader thread: %d", __func__, result); +void fm_hci_close(void *arg) { + + ALOGV("%s close fm userial ", __func__); + + struct fm_hci_t *hci = (struct fm_hci_t *)arg; + if (!hci) { + ALOGE("NULL arguments"); return; } - ALOGW("%s Already closed userial reader thread", __func__); + event_notification(hci, HC_EVENT_EXIT); +} + +int fm_hci_init(fm_hci_hal_t *hci_hal) +{ + int ret = FM_HC_STATUS_FAIL; + struct fm_hci_t *hci = NULL; + ALOGV("++%s", __func__); + + if (!hci_hal || !hci_hal->hal) { + ALOGE("NULL input argument"); + return FM_HC_STATUS_NULL_POINTER; + } + + hci = malloc(sizeof(struct fm_hci_t)); + if (!hci) { + ALOGE("Failed to malloc hci context"); + return FM_HC_STATUS_NOMEM; + } + memset(hci, 0, sizeof(struct fm_hci_t)); + + lib_running = 1; + ready_events = 0; + hci->command_credits = 1; + hci->fd = -1; + + pthread_mutex_init(&hci->tx_q_lock, NULL); + pthread_mutex_init(&hci->credit_lock, NULL); + pthread_mutex_init(&hci->event_lock, NULL); + + pthread_cond_init(&hci->event_cond, NULL); + pthread_cond_init(&hci->cmd_credits_cond, NULL); + + start_fmhal_service(); + fm_hal_fd = connect_to_local_fmsocket("fmhal_sock"); + if (fm_hal_fd == -1) { + ALOGI("FM hal service socket connect failed.."); + goto err_socket; + } + ALOGI("fm_hal_fd = %d", fm_hal_fd); + + ret = vendor_init(hci); + if (ret) + goto err_vendor; + ret = power(hci, FM_RADIO_ENABLE); + if (ret) + goto err_power; + ret = serial_port_init(hci); + if (ret) + goto err_serial; + ret = start_mon_thread(hci); + if (ret) + goto err_thread_mon; + ret = start_tx_thread(hci); + if (ret) + goto err_thread_tx; + ret = start_rx_thread(hci); + if (ret) + goto err_thread_rx; + + hci->cb = hci_hal->cb; + hci->private_data = hci_hal->hal; + hci_hal->hci = hci; + ALOGD("--%s success", __func__); + return FM_HC_STATUS_SUCCESS; + +err_thread_rx: + stop_rx_thread(hci); +err_thread_tx: + stop_tx_thread(hci); +err_thread_mon: + stop_mon_thread(hci); +err_serial: + serial_port_close(hci); +err_power: + power(hci, FM_RADIO_DISABLE); +err_vendor: + vendor_close(hci); +err_socket: + stop_fmhal_service(); + + pthread_mutex_destroy(&hci->tx_q_lock); + pthread_mutex_destroy(&hci->credit_lock); + pthread_mutex_destroy(&hci->event_lock); + pthread_cond_destroy(&hci->event_cond); + pthread_cond_destroy(&hci->cmd_credits_cond); + + lib_running = 0; + ready_events = 0; + hci->command_credits = 0; + free(hci); + + ALOGE("--%s fail", __func__); + return ret; } -void fm_userial_close(void) { +static void fm_hci_exit(void *arg) +{ + struct fm_hci_t *hci = (struct fm_hci_t *)arg; + ALOGE("%s", __func__); - ALOGD("%s close fm userial ", __func__); lib_running = 0; - fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); - fm_fd = -1; ready_events = HC_EVENT_EXIT; - pthread_cond_signal(&fmHCIControlBlock.event_cond); - pthread_cond_signal(&fmHCIControlBlock.cmd_credits_cond); - // Free all buffers still waiting in the RX queue. + hci->command_credits = 0; + serial_port_close(hci); + power(hci, FM_RADIO_DISABLE);//need to address this + vendor_close(hci); + pthread_cond_broadcast(&hci->event_cond); + pthread_cond_broadcast(&hci->cmd_credits_cond); + stop_rx_thread(hci); + stop_tx_thread(hci); + ALOGD("Tx, Rx Threads join done"); + pthread_mutex_destroy(&hci->tx_q_lock); + pthread_mutex_destroy(&hci->credit_lock); + pthread_mutex_destroy(&hci->event_lock); + pthread_cond_destroy(&hci->event_cond); + pthread_cond_destroy(&hci->cmd_credits_cond); + + free(hci); + hci = NULL; } + diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h index cfacb8433a8cd2919d47578ac0500c98cbe4741f..8818068e834201e01553eea38c6b23fe1574920e 100644 --- a/fm_hci/fm_hci.h +++ b/fm_hci/fm_hci.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -30,24 +30,9 @@ #ifndef __FM_HCI__ #define __FM_HCI__ -#pragma pack(1) - -#include <radio-helium.h> - -/** Host/Controller Library Return Status */ -typedef enum { - FM_HC_STATUS_SUCCESS, - FM_HC_STATUS_FAIL, - FM_HC_STATUS_NOT_READY, - FM_HC_STATUS_NOMEM, - FM_HC_STATUS_BUSY, - FM_HC_STATUS_CORRUPTED_BUFFER -} fm_hc_status_t; - -typedef enum { - FM_RADIO_DISABLE, - FM_RADIO_ENABLE -}fm_power_state; +#include "bt_hci_bdroid.h" +#include "bt_vendor_lib.h" +#include "fm_hci_api.h" /* Host/Controller lib internal event ID */ #define HC_EVENT_PRELOAD 0x0001 @@ -71,56 +56,46 @@ typedef enum { #define FM_CMD_STATUS 0x10 #define FM_HW_ERR_EVENT 0x1A -static pthread_mutex_t utils_mutex; - +/* TODO: move inside context */ static volatile uint8_t lib_running = 0; static volatile uint16_t ready_events = 0; -FILE *fd_wcnss_filter; - -typedef struct { - uint8_t protocol_byte; - uint16_t opcode; - uint8_t plen; - uint8_t cmd_params[]; -} FM_HDR; - -typedef struct { - uint8_t protocol_byte; - uint8_t evt_code; - uint8_t evt_len; - uint8_t cmd_params[]; -} FM_EVT_HDR; - -typedef struct hdr -{ - FM_HDR *hdr; - struct hdr *next; -} TX_Q; - -int transmit(FM_HDR *pbuf); -int fm_hci_init(fm_hal_cb *); -int fm_power(fm_power_state state); -int open_serial_port(void); -void fm_userial_close(void); - -typedef struct { - pthread_mutex_t tx_q_lock; +// The set of events one can send to the userial read thread. +// Note that the values must be >= 0x8000000000000000 to guarantee delivery +// of the message (see eventfd(2) for details on blocking behaviour). +enum { + USERIAL_RX_EXIT = 0x8000000000000000ULL +}; + +struct transmit_queue_t { + struct fm_command_header_t *hdr; + struct transmit_queue_t *next; +}; + +struct fm_hci_t { + int fd; pthread_mutex_t credit_lock; - pthread_mutex_t event_lock; + pthread_cond_t cmd_credits_cond; + pthread_mutex_t event_lock; pthread_cond_t event_cond; - pthread_cond_t cmd_credits_cond; - pthread_t fmHALTaskThreadId; - pthread_t fmHCITaskThreadId; - pthread_t fmRxTaskThreadId; + pthread_t hal_thread; + pthread_t tx_thread; + pthread_t rx_thread; + pthread_t mon_thread; - TX_Q *first; - TX_Q *last; + pthread_mutex_t tx_q_lock; + struct transmit_queue_t *first; + struct transmit_queue_t *last; -} fmHCIControlStructure; + void *dlhandle; + bt_vendor_interface_t *vendor; -fmHCIControlStructure fmHCIControlBlock; + struct fm_hci_callbacks_t *cb; + void *private_data; + volatile uint16_t command_credits; +}; #endif + diff --git a/fm_hci/fm_hci_api.h b/fm_hci/fm_hci_api.h new file mode 100644 index 0000000000000000000000000000000000000000..67a866baba7d92abea5e73bb6cbe6a17f8f116db --- /dev/null +++ b/fm_hci/fm_hci_api.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FM_HCI_API__ +#define __FM_HCI_API__ + + +/** Host/Controller Library Return Status */ +typedef enum { + FM_HC_STATUS_SUCCESS, + FM_HC_STATUS_FAIL, + FM_HC_STATUS_NOT_READY, + FM_HC_STATUS_NOMEM, + FM_HC_STATUS_BUSY, + FM_HC_STATUS_CORRUPTED_BUFFER, + FM_HC_STATUS_NULL_POINTER, +} fm_hc_status_t; + +static char *status_s[] = { + "Success", + "Failed, generic error", + "Not ready", + "Memory not available", + "Resource busy", + "Buffer is corrupted", + "NULL pointer dereference", +}; + +static inline char *fm_hci_status(int status) { + return status_s[status]; +} + +typedef enum { + FM_RADIO_DISABLE, + FM_RADIO_ENABLE +} fm_power_state_t; + +typedef int (*event_notification_cb_t)(void *hal, unsigned char *buf); + +struct fm_hci_callbacks_t { + event_notification_cb_t process_event; +}; + +typedef struct { + void *hci; + void *hal; + struct fm_hci_callbacks_t *cb; +}fm_hci_hal_t; + +struct fm_command_header_t { + uint8_t pi; /* packet indicator */ + uint16_t opcode; + uint8_t len; + uint8_t params[]; +}__attribute__((packed)); + +struct fm_event_header_t { + uint8_t pi; /* packet indicator */ + uint8_t evt_code; + uint8_t evt_len; + uint8_t params[]; +}__attribute__((packed)); + +int fm_hci_init(fm_hci_hal_t *hal_hci); +int fm_hci_transmit(void *hci, struct fm_command_header_t *buf); +void fm_hci_close(void *hci); +#endif diff --git a/helium/radio-helium.h b/helium/radio-helium.h index 30c3d0c442a2d241a12761a45266014a4940a007..a67c981b837aa8fb03cdbd9142cee9bb81f295e6 100644 --- a/helium/radio-helium.h +++ b/helium/radio-helium.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -27,14 +27,11 @@ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __UAPI_RADIO_HCI_CORE_H -#define __UAPI_RADIO_HCI_CORE_H - -#pragma pack(1) +#ifndef __RADIO_HELIUM_H__ +#define __RADIO_HELIUM_H__ #include <stdbool.h> -pthread_mutex_t fm_hal; #define MIN_TX_TONE_VAL 0x00 #define MAX_TX_TONE_VAL 0x07 #define MIN_HARD_MUTE_VAL 0x00 @@ -82,11 +79,6 @@ pthread_mutex_t fm_hal; #define MIN_BLEND_HI -128 #define MAX_BLEND_HI 127 - -/* ---- HCI Packet structures ---- */ -#define RADIO_HCI_COMMAND_HDR_SIZE sizeof(struct radio_hci_command_hdr) -#define RADIO_HCI_EVENT_HDR_SIZE sizeof(struct radio_hci_event_hdr) - /* HCI data types */ #define RADIO_HCI_COMMAND_PKT 0x11 #define RADIO_HCI_EVENT_PKT 0x14 @@ -198,12 +190,12 @@ typedef struct { ert_cb ert_update_cb; disable_cb disabled_cb; rds_grp_cntrs_cb rds_grp_cntrs_rsp_cb; - rds_grp_cntrs_ext_cb rds_grp_cntrs_ext_rsp_cb; + rds_grp_cntrs_ext_cb rds_grp_cntrs_ext_rsp_cb; fm_peek_cb fm_peek_rsp_cb; fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb; fm_agc_gain_cb fm_agc_gain_rsp_cb; fm_ch_det_th_cb fm_ch_det_th_rsp_cb; - fm_ecc_evt_cb ext_country_code_cb; + fm_ecc_evt_cb ext_country_code_cb; callback_thread_event thread_evt_cb; fm_sig_thr_cb fm_get_sig_thres_cb; fm_get_ch_det_thrs_cb fm_get_ch_det_thr_cb; @@ -214,46 +206,7 @@ typedef struct { fm_set_blnd_cb fm_set_blend_cb; fm_get_stn_prm_cb fm_get_station_param_cb; fm_get_stn_dbg_prm_cb fm_get_station_debug_param_cb; -} fm_vendor_callbacks_t; - -pthread_mutex_t radio_fm_cmd; -typedef struct { - int (*init)(const fm_vendor_callbacks_t *p_cb); - int (*set_fm_ctrl)(int opcode, int val); - void (*Get_fm_ctrl) (int opcode, int val); -} fm_interface_t; - -typedef int (*fm_evt_notify_cb)(unsigned char *p_buf); - -typedef struct { - fm_evt_notify_cb fm_evt_notify; -} fm_hal_cb; - -struct radio_hci_command_hdr { - short opcode; /* OCF & OGF */ - char plen; -} ; - -struct radio_hci_event_hdr { - char evt; - char plen; -} ; - -struct radio_hci_dev { - char name[8]; - unsigned long flags; - short id; - char bus; - char dev_type; - char dev_name[248]; - char dev_class[3]; - char features[8]; - char commands[64]; - unsigned int data_block_len; - unsigned long cmd_last_tx; - int req_status; - int req_result; -}; +} fm_hal_callbacks_t; /* Opcode OCF */ /* HCI recv control commands opcode */ @@ -384,7 +337,6 @@ struct hci_fm_trans_conf_req_struct { int band_high_limit; } ; - /* ----- HCI Command request ----- */ struct hci_fm_tx_ps { char ps_control; @@ -612,7 +564,7 @@ struct hci_ev_tune_status { char mute_mode; char sinr; char intf_det_th; -} ; +}__attribute__((packed)) ; struct rds_blk_data { char rdsMsb; @@ -653,25 +605,25 @@ struct hci_ev_af_list { short pi_code; char af_size; char af_list[FM_AF_LIST_MAX_SIZE]; -} ; +} __attribute__((packed)) ; struct hci_ev_cmd_complete { char num_hci_cmd_pkts; short cmd_opcode; -} ; +} __attribute((packed)); struct hci_ev_cmd_status { char status; char num_hci_cmd_pkts; short status_opcode; -} ; +} __attribute__((packed)); struct hci_ev_srch_st { int station_freq; char rds_cap; char pty; short status_opcode; -} ; +} __attribute__((packed)); struct hci_ev_rel_freq { char rel_freq_msb; @@ -687,18 +639,19 @@ struct hci_ev_srch_list_compl { struct hci_fm_conf_rsp { char status; struct hci_fm_recv_conf_req recv_conf_rsp; -} ; +} __attribute__((packed)); struct hci_fm_rds_grp_cntrs_rsp { char status; struct hci_fm_rds_grp_cntrs_params recv_rds_grp_cntrs_rsp; -} ; +} __attribute__((packed)); struct hci_fm_get_trans_conf_rsp { char status; struct hci_fm_trans_conf_req_struct trans_conf_rsp; -} ; +} __attribute__((packed)); + struct hci_fm_sig_threshold_rsp { char status; char sig_threshold; @@ -711,17 +664,17 @@ struct hci_fm_station_rsp { struct hci_fm_prgm_srv_rsp { char status; struct hci_ev_prg_service prg_srv; -} ; +} __attribute__((packed)); struct hci_fm_radio_txt_rsp { char status; struct hci_ev_radio_text rd_txt; -} ; +} __attribute__((packed)); struct hci_fm_af_list_rsp { char status; struct hci_ev_af_list rd_txt; -} ; +} __attribute__((packed)); struct hci_fm_data_rd_rsp { char data_len; @@ -763,8 +716,7 @@ struct hci_fm_spur_data { int freq[MAX_SPUR_FREQ_LIMIT]; char rmssi[MAX_SPUR_FREQ_LIMIT]; char enable[MAX_SPUR_FREQ_LIMIT]; -} ; - +} __attribute__((packed)); /* HCI dev events */ #define RADIO_HCI_DEV_REG 1 @@ -961,7 +913,6 @@ int hci_def_data_read(struct hci_fm_def_data_rd_req *arg, int hci_def_data_write(struct hci_fm_def_data_wr_req *arg, struct radio_hci_dev *hdev); int hci_fm_do_calibration(char *arg, struct radio_hci_dev *hdev); -int hci_fm_do_calibration(char *arg, struct radio_hci_dev *hdev); static inline int is_valid_tone(int tone) { @@ -1177,7 +1128,7 @@ static inline int is_valid_blend_value(int val) return 0; } -struct helium_device { +struct radio_helium_device { int tune_req; unsigned int mode; short pi; @@ -1212,7 +1163,7 @@ struct helium_device { struct hci_fm_ch_det_threshold ch_det_threshold; struct hci_fm_data_rd_rsp def_data; struct hci_fm_blend_table blend_tbl; -}; +} __attribute__((packed)); #define set_bit(flag, bit_pos) ((flag) |= (1 << (bit_pos))) #define clear_bit(flag, bit_pos) ((flag) &= (~(1 << (bit_pos)))) @@ -1281,4 +1232,17 @@ int hci_fm_default_data_write_req(struct hci_fm_def_data_wr_req * data_wrt); int hci_fm_get_station_dbg_param_req(); int hci_fm_get_station_cmd_param_req(); +struct fm_hal_t { + struct radio_helium_device *radio; + fm_hal_callbacks_t *jni_cb; + void *private_data; +}; + +struct fm_interface_t { + int (*init)(const fm_hal_callbacks_t *p_cb); + int (*set_fm_ctrl)(int opcode, int val); + void (*Get_fm_ctrl) (int opcode, int val); +}; + #endif /* __UAPI_RADIO_HCI_CORE_H */ + diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c index e6ab1b1901e015905a1aef665c78073ab6b1f21a..f22c6f56b86f221e23dbb5ac4c44729388973dd5 100644 --- a/helium/radio_helium_hal.c +++ b/helium/radio_helium_hal.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -34,15 +34,13 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <utils/Log.h> #include "radio-helium-commands.h" #include "radio-helium.h" -#include "fm_hci.h" +#include "fm_hci_api.h" #include <dlfcn.h> #include <errno.h> -fm_vendor_callbacks_t *jni_cb; int hci_fm_get_signal_threshold(); int hci_fm_enable_recv_req(); int hci_fm_mute_mode_req(struct hci_fm_mute_mode_req ); -struct helium_device *radio; static int oda_agt; static int grp_mask; static int rt_plus_carrier = -1; @@ -59,6 +57,7 @@ static uint32_t blend_tbl_mask_flag; static uint32_t station_param_mask_flag; static uint32_t station_dbg_param_mask_flag; uint64_t flag; +struct fm_hal_t *hal = NULL; #define LOG_TAG "radio_helium" static void radio_hci_req_complete(char result) @@ -80,11 +79,11 @@ static void hci_cc_fm_enable_rsp(char *ev_rsp) return; } rsp = (struct hci_fm_conf_rsp *)ev_rsp; - jni_cb->thread_evt_cb(0); + hal->jni_cb->thread_evt_cb(0); radio_hci_req_complete(rsp->status); - jni_cb->enabled_cb(); + hal->jni_cb->enabled_cb(); if (rsp->status == FM_HC_STATUS_SUCCESS) - radio->mode = FM_RECV; + hal->radio->mode = FM_RECV; } static void hci_cc_conf_rsp(char *ev_rsp) @@ -98,7 +97,7 @@ static void hci_cc_conf_rsp(char *ev_rsp) rsp = (struct hci_fm_conf_rsp *)ev_rsp; radio_hci_req_complete(rsp->status); if (!rsp->status) { - radio->recv_conf = rsp->recv_conf_rsp; + hal->radio->recv_conf = rsp->recv_conf_rsp; } } @@ -111,19 +110,15 @@ static void hci_cc_fm_disable_rsp(char *ev_buff) ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__); return; } - ALOGE("%s:enetred %s calling ", LOG_TAG, __func__); + ALOGV("%s++", __func__); status = (char) *ev_buff; radio_hci_req_complete(status); - if (radio->mode == FM_TURNING_OFF) { - radio->mode = FM_OFF; - jni_cb->disabled_cb(); - jni_cb->thread_evt_cb(1); - //close the userial port and power off the chip - ret = fm_power(FM_RADIO_DISABLE); - ALOGI("fm power off status = %d", ret); - ALOGI("%s:calling fm userial close\n", LOG_TAG ); - fm_userial_close(); - // fm_power(FM_RADIO_DISABLE); + if (hal->radio->mode == FM_TURNING_OFF) { + ALOGD("%s:calling fm close\n", LOG_TAG ); + fm_hci_close(hal->private_data); + hal->radio->mode = FM_OFF; + hal->jni_cb->disabled_cb(); + hal->jni_cb->thread_evt_cb(1); } } @@ -152,7 +147,7 @@ static void hci_cc_rds_grp_cntrs_rsp(char *ev_buff) if (status < 0) { ALOGE("%s:%s, read rds_grp_cntrs failed status=%d\n", LOG_TAG, __func__,status); } - jni_cb->rds_grp_cntrs_rsp_cb(&ev_buff[1]); + hal->jni_cb->rds_grp_cntrs_rsp_cb(&ev_buff[1]); } static void hci_cc_rds_grp_cntrs_ext_rsp(char *ev_buff) @@ -168,7 +163,7 @@ static void hci_cc_rds_grp_cntrs_ext_rsp(char *ev_buff) if (status < 0) { ALOGE("%s:%s, read rds_grp_cntrs_ext failed status=%d\n", LOG_TAG, __func__,status); } - jni_cb->rds_grp_cntrs_ext_rsp_cb(&ev_buff[1]); + hal->jni_cb->rds_grp_cntrs_ext_rsp_cb(&ev_buff[1]); } static void hci_cc_riva_peek_rsp(char *ev_buff) @@ -184,7 +179,7 @@ static void hci_cc_riva_peek_rsp(char *ev_buff) if (status < 0) { ALOGE("%s:%s, peek failed=%d\n", LOG_TAG, __func__, status); } - jni_cb->fm_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); + hal->jni_cb->fm_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); radio_hci_req_complete(status); } @@ -201,7 +196,7 @@ static void hci_cc_ssbi_peek_rsp(char *ev_buff) if (status < 0) { ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status); } - jni_cb->fm_ssbi_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); + hal->jni_cb->fm_ssbi_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); radio_hci_req_complete(status); } @@ -218,7 +213,7 @@ static void hci_cc_agc_rsp(char *ev_buff) if (status != 0) { ALOGE("%s:%s,agc gain failed=%d\n", LOG_TAG, __func__, status); } else { - jni_cb->fm_agc_gain_rsp_cb(&ev_buff[1]); + hal->jni_cb->fm_agc_gain_rsp_cb(&ev_buff[1]); } radio_hci_req_complete(status); } @@ -236,28 +231,28 @@ static void hci_cc_get_ch_det_threshold_rsp(char *ev_buff) if (status != 0) { ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status); } else { - memcpy(&radio->ch_det_threshold, &ev_buff[1], + memcpy(&hal->radio->ch_det_threshold, &ev_buff[1], sizeof(struct hci_fm_ch_det_threshold)); radio_hci_req_complete(status); if (test_bit(ch_det_th_mask_flag, CMD_CHDET_SINR_TH)) - val = radio->ch_det_threshold.sinr; + val = hal->radio->ch_det_threshold.sinr; else if (test_bit(ch_det_th_mask_flag, CMD_CHDET_SINR_SAMPLE)) - val = radio->ch_det_threshold.sinr_samples; + val = hal->radio->ch_det_threshold.sinr_samples; else if (test_bit(ch_det_th_mask_flag, CMD_CHDET_INTF_TH_LOW)) - val = radio->ch_det_threshold.low_th; + val = hal->radio->ch_det_threshold.low_th; else if (test_bit(ch_det_th_mask_flag, CMD_CHDET_INTF_TH_HIGH)) - val = radio->ch_det_threshold.high_th; + val = hal->radio->ch_det_threshold.high_th; } clear_all_bit(ch_det_th_mask_flag); - jni_cb->fm_get_ch_det_thr_cb(val, status); + hal->jni_cb->fm_get_ch_det_thr_cb(val, status); } static void hci_cc_set_ch_det_threshold_rsp(char *ev_buff) { int status = ev_buff[0]; - jni_cb->fm_set_ch_det_thr_cb(status); + hal->jni_cb->fm_set_ch_det_thr_cb(status); } static void hci_cc_sig_threshold_rsp(char *ev_buff) @@ -272,7 +267,7 @@ static void hci_cc_sig_threshold_rsp(char *ev_buff) } else { val = ev_buff[1]; } - jni_cb->fm_get_sig_thres_cb(val, status); + hal->jni_cb->fm_get_sig_thres_cb(val, status); } static void hci_cc_default_data_read_rsp(char *ev_buff) @@ -287,43 +282,43 @@ static void hci_cc_default_data_read_rsp(char *ev_buff) if (status == 0) { data_len = ev_buff[1]; ALOGV("hci_cc_default_data_read_rsp:data_len = %d", data_len); - memcpy(&radio->def_data, &ev_buff[1], data_len + sizeof(char)); + memcpy(&hal->radio->def_data, &ev_buff[1], data_len + sizeof(char)); if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_AF_RMSSI_TH)) { - val = radio->def_data.data[AF_RMSSI_TH_OFFSET]; + val = hal->radio->def_data.data[AF_RMSSI_TH_OFFSET]; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_AF_RMSSI_SAMPLE)) { - val = radio->def_data.data[AF_RMSSI_SAMPLES_OFFSET]; + val = hal->radio->def_data.data[AF_RMSSI_SAMPLES_OFFSET]; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_GD_CH_RMSSI_TH)) { - val = radio->def_data.data[GD_CH_RMSSI_TH_OFFSET]; + val = hal->radio->def_data.data[GD_CH_RMSSI_TH_OFFSET]; if (val > MAX_GD_CH_RMSSI_TH) val -= 256; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_SEARCH_ALGO)) { - val = radio->def_data.data[SRCH_ALGO_TYPE_OFFSET]; + val = hal->radio->def_data.data[SRCH_ALGO_TYPE_OFFSET]; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_SINR_FIRST_STAGE)) { - val = radio->def_data.data[SINRFIRSTSTAGE_OFFSET]; + val = hal->radio->def_data.data[SINRFIRSTSTAGE_OFFSET]; if (val > MAX_SINR_FIRSTSTAGE) val -= 256; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_RMSSI_FIRST_STAGE)) { - val = radio->def_data.data[RMSSIFIRSTSTAGE_OFFSET]; + val = hal->radio->def_data.data[RMSSIFIRSTSTAGE_OFFSET]; } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_CF0TH12)) { - val = (radio->def_data.data[CF0TH12_BYTE1_OFFSET] | - (radio->def_data.data[CF0TH12_BYTE2_OFFSET] << 8)); + val = (hal->radio->def_data.data[CF0TH12_BYTE1_OFFSET] | + (hal->radio->def_data.data[CF0TH12_BYTE2_OFFSET] << 8)); } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_TUNE_POWER)) { } else if (test_bit(def_data_rd_mask_flag, CMD_DEFRD_REPEATCOUNT)) { - val = radio->def_data.data[RX_REPEATE_BYTE_OFFSET]; + val = hal->radio->def_data.data[RX_REPEATE_BYTE_OFFSET]; } } else { ALOGE("%s: Error: Status= 0x%x", __func__, status); } clear_all_bit(def_data_rd_mask_flag); - jni_cb->fm_def_data_read_cb(val, status); + hal->jni_cb->fm_def_data_read_cb(val, status); } static void hci_cc_default_data_write_rsp(char *ev_buff) { int status = ev_buff[0]; - jni_cb->fm_def_data_write_cb(status); + hal->jni_cb->fm_def_data_write_cb(status); } static void hci_cc_get_blend_tbl_rsp(char *ev_buff) @@ -339,7 +334,7 @@ static void hci_cc_get_blend_tbl_rsp(char *ev_buff) if (status != 0) { ALOGE("%s: status = 0x%x", LOG_TAG, status); } else { - memcpy(&radio->blend_tbl, &ev_buff[1], + memcpy(&hal->radio->blend_tbl, &ev_buff[1], sizeof(struct hci_fm_blend_table)); ALOGE("hci_cc_get_blend_tbl_rsp: data"); @@ -347,20 +342,20 @@ static void hci_cc_get_blend_tbl_rsp(char *ev_buff) for (i = 0; i < 8; i++) ALOGE("data[%d] = 0x%x", i, ev_buff[1 + i]); if (test_bit(blend_tbl_mask_flag, CMD_BLENDTBL_SINR_HI)) { - val = radio->blend_tbl.BlendSinrHi; + val = hal->radio->blend_tbl.BlendSinrHi; } else if (test_bit(blend_tbl_mask_flag, CMD_BLENDTBL_RMSSI_HI)) { - val = radio->blend_tbl.BlendRmssiHi; + val = hal->radio->blend_tbl.BlendRmssiHi; } } clear_all_bit(blend_tbl_mask_flag); - jni_cb->fm_get_blend_cb(val, status); + hal->jni_cb->fm_get_blend_cb(val, status); } static void hci_cc_set_blend_tbl_rsp(char *ev_buff) { int status = ev_buff[0]; - jni_cb->fm_set_blend_cb(status); + hal->jni_cb->fm_set_blend_cb(status); } static void hci_cc_station_rsp(char *ev_buff) @@ -368,17 +363,17 @@ static void hci_cc_station_rsp(char *ev_buff) int val, status = ev_buff[0]; if (status == FM_HC_STATUS_SUCCESS) { - memcpy(&radio->fm_st_rsp.station_rsp.station_freq, &ev_buff[1], + memcpy(&hal->radio->fm_st_rsp.station_rsp.station_freq, &ev_buff[1], sizeof(struct hci_fm_station_rsp) - sizeof(char)); if (test_bit(station_param_mask_flag, CMD_STNPARAM_RSSI)) { - val = radio->fm_st_rsp.station_rsp.rssi; + val = hal->radio->fm_st_rsp.station_rsp.rssi; } else if (test_bit(station_param_mask_flag, CMD_STNPARAM_SINR)) { - val = radio->fm_st_rsp.station_rsp.sinr; + val = hal->radio->fm_st_rsp.station_rsp.sinr; } } ALOGE("hci_cc_station_rsp: val =%x, status = %x", val, status); - jni_cb->fm_get_station_param_cb(val, status); + hal->jni_cb->fm_get_station_param_cb(val, status); clear_all_bit(station_param_mask_flag); } @@ -387,16 +382,16 @@ static void hci_cc_dbg_param_rsp(char *ev_buff) int val, status = ev_buff[0]; if (status == FM_HC_STATUS_SUCCESS) { - memcpy(&radio->st_dbg_param, &ev_buff[1], + memcpy(&hal->radio->st_dbg_param, &ev_buff[1], sizeof(struct hci_fm_dbg_param_rsp)); if (test_bit(station_dbg_param_mask_flag, CMD_STNDBGPARAM_INFDETOUT)) { - val = radio->st_dbg_param.in_det_out; + val = hal->radio->st_dbg_param.in_det_out; } else if (test_bit(station_dbg_param_mask_flag, CMD_STNDBGPARAM_IOVERC)) { - val = radio->st_dbg_param.io_verc; + val = hal->radio->st_dbg_param.io_verc; } } ALOGE("hci_cc_dbg_param_rsp: val =%x, status = %x", val, status); - jni_cb->fm_get_station_debug_param_cb(val, status); + hal->jni_cb->fm_get_station_debug_param_cb(val, status); clear_all_bit(station_dbg_param_mask_flag); } @@ -549,27 +544,29 @@ static inline void hci_cmd_status_event(char *st_rsp) static inline void hci_ev_tune_status(char *buff) { - memcpy(&radio->fm_st_rsp.station_rsp, &buff[0], + memcpy(&hal->radio->fm_st_rsp.station_rsp, &buff[0], sizeof(struct hci_ev_tune_status)); - jni_cb->tune_cb(radio->fm_st_rsp.station_rsp.station_freq); + char *freq = &hal->radio->fm_st_rsp.station_rsp.station_freq; + ALOGD("freq = %d", hal->radio->fm_st_rsp.station_rsp.station_freq); + hal->jni_cb->tune_cb(hal->radio->fm_st_rsp.station_rsp.station_freq); - // if (radio->fm_st_rsp.station_rsp.serv_avble) + // if (hal->radio->fm_st_rsp.station_rsp.serv_avble) // todo callback for threshould - if (radio->fm_st_rsp.station_rsp.stereo_prg) - jni_cb->stereo_status_cb(true); - else if (radio->fm_st_rsp.station_rsp.stereo_prg == 0) - jni_cb->stereo_status_cb(false); + if (hal->radio->fm_st_rsp.station_rsp.stereo_prg) + hal->jni_cb->stereo_status_cb(true); + else if (hal->radio->fm_st_rsp.station_rsp.stereo_prg == 0) + hal->jni_cb->stereo_status_cb(false); - if (radio->fm_st_rsp.station_rsp.rds_sync_status) - jni_cb->rds_avail_status_cb(true); + if (hal->radio->fm_st_rsp.station_rsp.rds_sync_status) + hal->jni_cb->rds_avail_status_cb(true); else - jni_cb->rds_avail_status_cb(false); + hal->jni_cb->rds_avail_status_cb(false); } static inline void hci_ev_search_next(char *buff) { - jni_cb->scan_next_cb(); + hal->jni_cb->scan_next_cb(); } static inline void hci_ev_stereo_status(char *buff) @@ -582,9 +579,9 @@ static inline void hci_ev_stereo_status(char *buff) } st_status = buff[0]; if (st_status) - jni_cb->stereo_status_cb(true); + hal->jni_cb->stereo_status_cb(true); else - jni_cb->stereo_status_cb(false); + hal->jni_cb->stereo_status_cb(false); } static void hci_ev_rds_lock_status(char *buff) @@ -599,9 +596,9 @@ static void hci_ev_rds_lock_status(char *buff) rds_status = buff[0]; if (rds_status) - jni_cb->rds_avail_status_cb(true); + hal->jni_cb->rds_avail_status_cb(true); else - jni_cb->rds_avail_status_cb(false); + hal->jni_cb->rds_avail_status_cb(false); } static inline void hci_ev_program_service(char *buff) @@ -625,7 +622,7 @@ static inline void hci_ev_program_service(char *buff) memcpy(data+RDS_OFFSET, &buff[RDS_PS_DATA_OFFSET], len-RDS_OFFSET); ALOGE("SSK call ps-callback"); - jni_cb->ps_update_cb(data); + hal->jni_cb->ps_update_cb(data); free(data); } @@ -658,7 +655,7 @@ static inline void hci_ev_radio_text(char *buff) memcpy(data+RDS_OFFSET, &buff[RDS_OFFSET], len); data[len+RDS_OFFSET] = 0x00; - jni_cb->rt_update_cb(data); + hal->jni_cb->rt_update_cb(data); free(data); } @@ -679,7 +676,7 @@ static void hci_ev_af_list(char *buff) } memcpy(&ev.af_list[0], &buff[AF_LIST_OFFSET], ev.af_size * sizeof(int)); - jni_cb->af_list_update_cb(&ev); + hal->jni_cb->af_list_update_cb(&ev); } static inline void hci_ev_search_compl(char *buff) @@ -688,8 +685,8 @@ static inline void hci_ev_search_compl(char *buff) ALOGE("%s:%s,buffer is null\n", LOG_TAG, __func__); return; } - radio->search_on = 0; - jni_cb->seek_cmpl_cb(radio->fm_st_rsp.station_rsp.station_freq); + hal->radio->search_on = 0; + hal->jni_cb->seek_cmpl_cb(hal->radio->fm_st_rsp.station_rsp.station_freq); } static inline void hci_ev_srch_st_list_compl(char *buff) @@ -720,7 +717,7 @@ static inline void hci_ev_srch_st_list_compl(char *buff) cnt += PARAMS_PER_STATION, stn_num++) { abs_freq = *((int *)&buff[cnt]); - rel_freq = abs_freq - radio->recv_conf.band_low_limit; + rel_freq = abs_freq - hal->radio->recv_conf.band_low_limit; rel_freq = (rel_freq * 20) / KHZ_TO_MHZ; ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq); @@ -728,7 +725,7 @@ static inline void hci_ev_srch_st_list_compl(char *buff) } len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found); - jni_cb->srch_list_cb((char*)ev); + hal->jni_cb->srch_list_cb((char*)ev); free(ev); } @@ -772,7 +769,7 @@ static void hci_ev_rt_plus_tag(char *buff) data[4] = buff[3]; memcpy(&data[RDS_OFFSET], &buff[4], len-RDS_OFFSET); // data[len] = 0x00; - jni_cb->rt_plus_update_cb(data); + hal->jni_cb->rt_plus_update_cb(data); free(data); } else { ALOGE("%s:memory allocation failed\n", LOG_TAG); @@ -793,8 +790,7 @@ static void hci_ev_ext_country_code(char *buff) data[3] = buff[RDS_PID_HIGHER]; data[4] = buff[3]; memcpy(&data[RDS_OFFSET], &buff[4], len-RDS_OFFSET); - // data[len] = 0x00; - jni_cb->ext_country_code_cb(data); + hal->jni_cb->ext_country_code_cb(data); free(data); } else { ALOGE("%s:memory allocation failed\n", LOG_TAG); @@ -813,7 +809,7 @@ static void hci_ev_ert() data[1] = utf_8_flag; data[2] = formatting_dir; memcpy((data + 3), ert_buf, ert_len); - jni_cb->ert_update_cb(data); + hal->jni_cb->ert_update_cb(data); free(data); } } @@ -821,9 +817,9 @@ static void hci_ev_ert() static void hci_ev_hw_error(char *buff) { ALOGE("%s:%s: start", LOG_TAG, __func__); - jni_cb->disabled_cb(); - jni_cb->thread_evt_cb(1); - fm_userial_close(); + fm_hci_close(hal->private_data); + hal->jni_cb->disabled_cb(); + hal->jni_cb->thread_evt_cb(1); } static void hci_buff_ert(struct rds_grp_data *rds_buf) @@ -917,7 +913,7 @@ static void hci_ev_raw_rds_group_data(char *buff) formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb, ERT_FORMAT_DIR_BIT); if (ert_carrier != agt) - jni_cb->oda_update_cb(); + hal->jni_cb->oda_update_cb(); ert_carrier = agt; break; case RT_PLUS_AID: @@ -935,7 +931,7 @@ static void hci_ev_raw_rds_group_data(char *buff) rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb, RT_ERT_FLAG_BIT); if (rt_plus_carrier != agt) - jni_cb->oda_update_cb(); + hal->jni_cb->oda_update_cb(); rt_plus_carrier = agt; break; default: @@ -959,65 +955,65 @@ static void radio_hci_event_packet(char *evt_buf) char evt; ALOGE("%s:%s: Received %d bytes of HCI EVENT PKT from Controller", LOG_TAG, - __func__, ((FM_EVT_HDR *)evt_buf)->evt_len); - evt = ((FM_EVT_HDR *)evt_buf)->evt_code; + __func__, ((struct fm_event_header_t *)evt_buf)->evt_len); + evt = ((struct fm_event_header_t *)evt_buf)->evt_code; ALOGE("%s:evt: %d", LOG_TAG, evt); switch(evt) { case HCI_EV_TUNE_STATUS: - hci_ev_tune_status(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_tune_status(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_SEARCH_PROGRESS: case HCI_EV_SEARCH_RDS_PROGRESS: case HCI_EV_SEARCH_LIST_PROGRESS: - hci_ev_search_next(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_search_next(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_STEREO_STATUS: - hci_ev_stereo_status(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_stereo_status(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_RDS_LOCK_STATUS: - hci_ev_rds_lock_status(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_rds_lock_status(((struct fm_event_header_t *)evt_buf)->params); break; /* case HCI_EV_SERVICE_AVAILABLE: hci_ev_service_available(hdev, skb); break; */ case HCI_EV_RDS_RX_DATA: - hci_ev_raw_rds_group_data(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_raw_rds_group_data(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_PROGRAM_SERVICE: - hci_ev_program_service(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_program_service(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_RADIO_TEXT: - hci_ev_radio_text(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_radio_text(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_FM_AF_LIST: - hci_ev_af_list(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_af_list(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_CMD_COMPLETE: ALOGE("%s:%s: Received HCI_EV_CMD_COMPLETE", LOG_TAG, __func__); - hci_cmd_complete_event(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_cmd_complete_event(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_CMD_STATUS: - hci_cmd_status_event(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_cmd_status_event(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_SEARCH_COMPLETE: case HCI_EV_SEARCH_RDS_COMPLETE: - hci_ev_search_compl(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_search_compl(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_SEARCH_LIST_COMPLETE: - hci_ev_srch_st_list_compl(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_srch_st_list_compl(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_RADIO_TEXT_PLUS_ID: - hci_ev_rt_plus_id(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_rt_plus_id(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_RADIO_TEXT_PLUS_TAG: - hci_ev_rt_plus_tag(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_rt_plus_tag(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_EXT_COUNTRY_CODE: - hci_ev_ext_country_code(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_ext_country_code(((struct fm_event_header_t *)evt_buf)->params); break; case HCI_EV_HW_ERR_EVENT: - hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params); + hci_ev_hw_error(((struct fm_event_header_t *)evt_buf)->params); break; default: break; @@ -1025,10 +1021,10 @@ static void radio_hci_event_packet(char *evt_buf) } /* 'evt_buf' contains the event received from Controller */ -int fm_evt_notify(char *evt_buf) +int process_event(void *hal, unsigned char *evt_buf) { ALOGI("%s: %s: Received event notification from FM-HCI thread. EVT CODE: %d ", - LOG_TAG, __func__, ((FM_EVT_HDR *)evt_buf)->evt_code); + LOG_TAG, __func__, ((struct fm_event_header_t *)evt_buf)->evt_code); radio_hci_event_packet(evt_buf); return 0; } @@ -1040,9 +1036,9 @@ int helium_search_req(int on, int direct) int saved_val; int dir; - srch = radio->g_search_mode & SRCH_MODE; - saved_val = radio->search_on; - radio->search_on = on; + srch = hal->radio->g_search_mode & SRCH_MODE; + saved_val = hal->radio->search_on; + hal->radio->search_on = on; if (direct) dir = SRCH_DIR_UP; else @@ -1052,24 +1048,24 @@ int helium_search_req(int on, int direct) switch (srch) { case SCAN_FOR_STRONG: case SCAN_FOR_WEAK: - radio->srch_st_list.srch_list_dir = dir; - radio->srch_st_list.srch_list_mode = srch; - retval = helium_search_list(&radio->srch_st_list); + hal->radio->srch_st_list.srch_list_dir = dir; + hal->radio->srch_st_list.srch_list_mode = srch; + retval = helium_search_list(&hal->radio->srch_st_list); break; case RDS_SEEK_PTY: case RDS_SCAN_PTY: case RDS_SEEK_PI: srch = srch - SEARCH_RDS_STNS_MODE_OFFSET; - radio->srch_rds.srch_station.srch_mode = srch; - radio->srch_rds.srch_station.srch_dir = dir; - radio->srch_rds.srch_station.scan_time = radio->g_scan_time; - retval = helium_search_rds_stations(&radio->srch_rds); + hal->radio->srch_rds.srch_station.srch_mode = srch; + hal->radio->srch_rds.srch_station.srch_dir = dir; + hal->radio->srch_rds.srch_station.scan_time = hal->radio->g_scan_time; + retval = helium_search_rds_stations(&hal->radio->srch_rds); break; default: - radio->srch_st.srch_mode = srch; - radio->srch_st.scan_time = radio->g_scan_time; - radio->srch_st.srch_dir = dir; - retval = helium_search_stations(&radio->srch_st); + hal->radio->srch_st.srch_mode = srch; + hal->radio->srch_st.scan_time = hal->radio->g_scan_time; + hal->radio->srch_st.srch_dir = dir; + retval = helium_search_stations(&hal->radio->srch_st); break; } } else { @@ -1077,7 +1073,7 @@ int helium_search_req(int on, int direct) } if (retval < 0) - radio->search_on = saved_val; + hal->radio->search_on = saved_val; return retval; } @@ -1086,12 +1082,12 @@ int helium_recv_set_region(int req_region) int retval; int saved_val; - saved_val = radio->region; - radio->region = req_region; + saved_val = hal->radio->region; + hal->radio->region = req_region; - retval = hci_fm_set_recv_conf_req(&radio->recv_conf); + retval = hci_fm_set_recv_conf_req(&hal->radio->recv_conf); if (retval < 0) - radio->region = saved_val; + hal->radio->region = saved_val; return retval; } @@ -1100,10 +1096,10 @@ int set_low_power_mode(int lp_mode) int rds_grps_proc = 0x00; int retval = 0; - if (radio->power_mode != lp_mode) { + if (hal->radio->power_mode != lp_mode) { if (lp_mode) { - radio->event_mask = 0x00; - if (radio->af_jump_bit) + hal->radio->event_mask = 0x00; + if (hal->radio->af_jump_bit) rds_grps_proc = 0x00 | AF_JUMP_ENABLE; else rds_grps_proc = 0x00; @@ -1112,52 +1108,78 @@ int set_low_power_mode(int lp_mode) ALOGE("%s:Disable RDS failed", LOG_TAG); return retval; } - retval = helium_set_event_mask_req(radio->event_mask); + retval = helium_set_event_mask_req(hal->radio->event_mask); } else { - radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR; - retval = helium_set_event_mask_req(radio->event_mask); + hal->radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR; + retval = helium_set_event_mask_req(hal->radio->event_mask); if (retval < 0) { ALOGE("%s:Enable Async events failed", LOG_TAG); return retval; } - radio->g_rds_grp_proc_ps = 0x000000FF; - retval = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps); + hal->radio->g_rds_grp_proc_ps = 0x000000FF; + retval = helium_rds_grp_process_req(hal->radio->g_rds_grp_proc_ps); } - radio->power_mode = lp_mode; + hal->radio->power_mode = lp_mode; } return retval; } /* Callback function to be registered with FM-HCI for event notification */ -static fm_hal_cb hal_cb = { - fm_evt_notify +static struct fm_hci_callbacks_t hal_cb = { + process_event }; -int hal_init( fm_vendor_callbacks_t *p_cb) +int hal_init(fm_hal_callbacks_t *cb) { - int ret = -1; + int ret = -FM_HC_STATUS_FAIL; + fm_hci_hal_t hci_hal; - radio = malloc(sizeof(struct helium_device)); - if (!radio) { - ALOGE("%s:Failed to allocate memory for device", LOG_TAG); - return ret; - } - /* Save the JNI callback functions */ - jni_cb = p_cb; + ALOGD("++%s", __func__); + + memset(&hci_hal, 0, sizeof(fm_hci_hal_t)); + + hal = malloc(sizeof(struct fm_hal_t)); + if (!hal) { + ALOGE("%s:Failed to allocate memory", __func__); + ret = -FM_HC_STATUS_NOMEM; + goto out; + } + memset(hal, 0, sizeof(struct fm_hal_t)); + hal->jni_cb = cb; + hal->radio = malloc(sizeof(struct radio_helium_device)); + if (!hal->radio) { + ALOGE("%s:Failed to allocate memory for device", __func__); + goto out; + } + + memset(hal->radio, 0, sizeof(struct radio_helium_device)); + + hci_hal.hal = hal; + hci_hal.cb = &hal_cb; /* Initialize the FM-HCI */ - ALOGE("%s:%s: Initializing the event notification func with FM-HCI", LOG_TAG, __func__); - ret = fm_hci_init(&hal_cb); + ret = fm_hci_init(&hci_hal); + if (ret != FM_HC_STATUS_SUCCESS) { + ALOGE("%s:fm_hci_init failed", __func__); + goto out; + } + hal->private_data = hci_hal.hci; - ALOGE("%s:%s: Turning FM ON...", LOG_TAG, __func__); - ret = fm_power(FM_RADIO_ENABLE); + return FM_HC_STATUS_SUCCESS; - ALOGE("%s:%s: Firmware download and HCI Initialization in-progress...", LOG_TAG, __func__); - /* TODO : Start the preload timer */ - open_serial_port(); - pthread_mutex_init(&fm_hal, NULL); - return 0; +out: + ALOGV("--%s", __func__); + if (hal) { + if (hal->radio) { + free(hal->radio); + hal->radio = NULL; + } + hal->jni_cb = NULL; + free(hal); + hal = NULL; + } + return ret; } /* Called by the JNI for performing the FM operations */ @@ -1170,27 +1192,31 @@ static int set_fm_ctrl(int cmd, int val) char *data; struct hci_fm_def_data_wr_req def_data_wrt; - ALOGE("%s:cmd: %x, val: %d",LOG_TAG, cmd, val); + if (!hal) { + ALOGE("%s:ALERT: command sent before hal init", __func__); + return -FM_HC_STATUS_FAIL; + } + ALOGD("%s:cmd: %x, val: %d",LOG_TAG, cmd, val); switch (cmd) { case HCI_FM_HELIUM_AUDIO_MUTE: - saved_val = radio->mute_mode.hard_mute; - radio->mute_mode.hard_mute = val; - ret = hci_fm_mute_mode_req(radio->mute_mode); + saved_val = hal->radio->mute_mode.hard_mute; + hal->radio->mute_mode.hard_mute = val; + ret = hci_fm_mute_mode_req(hal->radio->mute_mode); if (ret < 0) { ALOGE("%s:Error while set FM hard mute %d", LOG_TAG, ret); - radio->mute_mode.hard_mute = saved_val; + hal->radio->mute_mode.hard_mute = saved_val; } break; case HCI_FM_HELIUM_SRCHMODE: if (is_valid_srch_mode(val)) - radio->g_search_mode = val; + hal->radio->g_search_mode = val; else ret = -EINVAL; break; case HCI_FM_HELIUM_SCANDWELL: if (is_valid_scan_dwell_prd(val)) - radio->g_scan_time = val; + hal->radio->g_scan_time = val; else ret = -EINVAL; break; @@ -1203,7 +1229,7 @@ static int set_fm_ctrl(int cmd, int val) ret = hci_fm_enable_recv_req(); break; case FM_OFF: - radio->mode = FM_TURNING_OFF; + hal->radio->mode = FM_TURNING_OFF; hci_fm_disable_recv_req(); break; default: @@ -1223,84 +1249,84 @@ static int set_fm_ctrl(int cmd, int val) break; case HCI_FM_HELIUM_SRCH_PTY: if (is_valid_pty(val)) { - radio->srch_rds.srch_pty = val; - radio->srch_st_list.srch_pty = val; + hal->radio->srch_rds.srch_pty = val; + hal->radio->srch_st_list.srch_pty = val; } else { ret = -EINVAL; } break; case HCI_FM_HELIUM_SRCH_PI: if (is_valid_pi(val)) - radio->srch_rds.srch_pi = val; + hal->radio->srch_rds.srch_pi = val; else ret = -EINVAL; break; case HCI_FM_HELIUM_SRCH_CNT: if (is_valid_srch_station_cnt(val)) - radio->srch_st_list.srch_list_max = val; + hal->radio->srch_st_list.srch_list_max = val; else ret = -EINVAL; break; case HCI_FM_HELIUM_SPACING: - saved_val = radio->recv_conf.ch_spacing; - radio->recv_conf.ch_spacing = val; - ret = hci_fm_set_recv_conf_req(&radio->recv_conf); + saved_val = hal->radio->recv_conf.ch_spacing; + hal->radio->recv_conf.ch_spacing = val; + ret = hci_fm_set_recv_conf_req(&hal->radio->recv_conf); if (ret < 0) { ALOGE("%s:Error in setting channel spacing", LOG_TAG); - radio->recv_conf.ch_spacing = saved_val; + hal->radio->recv_conf.ch_spacing = saved_val; goto end; } break; case HCI_FM_HELIUM_EMPHASIS: - saved_val = radio->recv_conf.emphasis; - radio->recv_conf.emphasis = val; - ret = hci_fm_set_recv_conf_req(&radio->recv_conf); + saved_val = hal->radio->recv_conf.emphasis; + hal->radio->recv_conf.emphasis = val; + ret = hci_fm_set_recv_conf_req(&hal->radio->recv_conf); if (ret < 0) { ALOGE("%s:Error in setting emphasis", LOG_TAG); - radio->recv_conf.emphasis = saved_val; + hal->radio->recv_conf.emphasis = saved_val; goto end; } break; case HCI_FM_HELIUM_RDS_STD: - saved_val = radio->recv_conf.rds_std; - radio->recv_conf.rds_std = val; - ret = hci_fm_set_recv_conf_req(&radio->recv_conf); + saved_val = hal->radio->recv_conf.rds_std; + hal->radio->recv_conf.rds_std = val; + ret = hci_fm_set_recv_conf_req(&hal->radio->recv_conf); if (ret < 0) { ALOGE("%s:Error in rds_std", LOG_TAG); - radio->recv_conf.rds_std = saved_val; + hal->radio->recv_conf.rds_std = saved_val; goto end; } break; case HCI_FM_HELIUM_RDSON: - saved_val = radio->recv_conf.rds_std; - radio->recv_conf.rds_std = val; - ret = hci_fm_set_recv_conf_req(&radio->recv_conf); + saved_val = hal->radio->recv_conf.rds_std; + hal->radio->recv_conf.rds_std = val; + ret = hci_fm_set_recv_conf_req(&hal->radio->recv_conf); if (ret < 0) { ALOGE("%s:Error in rds_std", LOG_TAG); - radio->recv_conf.rds_std = saved_val; + hal->radio->recv_conf.rds_std = saved_val; goto end; } break; case HCI_FM_HELIUM_RDSGROUP_MASK: - saved_val = radio->rds_grp.rds_grp_enable_mask; + saved_val = hal->radio->rds_grp.rds_grp_enable_mask; grp_mask = (grp_mask | oda_agt | val); - radio->rds_grp.rds_grp_enable_mask = grp_mask; - radio->rds_grp.rds_buf_size = 1; - radio->rds_grp.en_rds_change_filter = 0; - ret = helium_rds_grp_mask_req(&radio->rds_grp); + hal->radio->rds_grp.rds_grp_enable_mask = grp_mask; + hal->radio->rds_grp.rds_buf_size = 1; + hal->radio->rds_grp.en_rds_change_filter = 0; + ret = helium_rds_grp_mask_req(&hal->radio->rds_grp); if (ret < 0) { ALOGE("%s:error in setting group mask\n", LOG_TAG); - radio->rds_grp.rds_grp_enable_mask = saved_val; + hal->radio->rds_grp.rds_grp_enable_mask = saved_val; goto end; } break; case HCI_FM_HELIUM_RDSGROUP_PROC: - saved_val = radio->g_rds_grp_proc_ps; - rds_grps_proc = radio->g_rds_grp_proc_ps | (val & 0xFF); - radio->g_rds_grp_proc_ps = rds_grps_proc; - ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps); + saved_val = hal->radio->g_rds_grp_proc_ps; + rds_grps_proc = hal->radio->g_rds_grp_proc_ps | (val & 0xFF); + hal->radio->g_rds_grp_proc_ps = rds_grps_proc; + ret = helium_rds_grp_process_req(hal->radio->g_rds_grp_proc_ps); if (ret < 0) { - radio->g_rds_grp_proc_ps = saved_val; + hal->radio->g_rds_grp_proc_ps = saved_val; goto end; } break; @@ -1309,7 +1335,7 @@ static int set_fm_ctrl(int cmd, int val) ALOGD("%s: rds_grp counter read value=%d ", LOG_TAG,val); ret = hci_fm_get_rds_grpcounters_req(val); if (ret < 0) { - radio->g_rds_grp_proc_ps = saved_val; + hal->radio->g_rds_grp_proc_ps = saved_val; goto end; } break; @@ -1318,7 +1344,7 @@ static int set_fm_ctrl(int cmd, int val) ALOGD("%s: rds_grp counter read value=%d ", LOG_TAG,val); ret = hci_fm_get_rds_grpcounters_ext_req(val); if (ret < 0) { - radio->g_rds_grp_proc_ps = saved_val; + hal->radio->g_rds_grp_proc_ps = saved_val; goto end ; } break; @@ -1332,28 +1358,28 @@ static int set_fm_ctrl(int cmd, int val) break; case HCI_FM_HELIUM_RDSD_BUF: - radio->rds_grp.rds_buf_size = val; + hal->radio->rds_grp.rds_buf_size = val; break; case HCI_FM_HELIUM_PSALL: - saved_val = radio->g_rds_grp_proc_ps; + saved_val = hal->radio->g_rds_grp_proc_ps; rds_grps_proc = (val << RDS_CONFIG_OFFSET); - radio->g_rds_grp_proc_ps |= rds_grps_proc; - ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps); + hal->radio->g_rds_grp_proc_ps |= rds_grps_proc; + ret = helium_rds_grp_process_req(hal->radio->g_rds_grp_proc_ps); if (ret < 0) { - radio->g_rds_grp_proc_ps = saved_val; + hal->radio->g_rds_grp_proc_ps = saved_val; goto end; } break; case HCI_FM_HELIUM_AF_JUMP: - saved_val = radio->g_rds_grp_proc_ps; - radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET); - radio->af_jump_bit = val; + saved_val = hal->radio->g_rds_grp_proc_ps; + hal->radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET); + hal->radio->af_jump_bit = val; rds_grps_proc = 0x00; rds_grps_proc = (val << RDS_AF_JUMP_OFFSET); - radio->g_rds_grp_proc_ps |= rds_grps_proc; - ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps); + hal->radio->g_rds_grp_proc_ps |= rds_grps_proc; + ret = helium_rds_grp_process_req(hal->radio->g_rds_grp_proc_ps); if (ret < 0) { - radio->g_rds_grp_proc_ps = saved_val; + hal->radio->g_rds_grp_proc_ps = saved_val; goto end; } break; @@ -1367,15 +1393,15 @@ static int set_fm_ctrl(int cmd, int val) ALOGE("%s:Set Antenna failed retval = %x", LOG_TAG, ret); goto end; } - radio->g_antenna = val; + hal->radio->g_antenna = val; break; case HCI_FM_HELIUM_SOFT_MUTE: - saved_val = radio->mute_mode.soft_mute; - radio->mute_mode.soft_mute = val; - ret = helium_set_fm_mute_mode_req(&radio->mute_mode); + saved_val = hal->radio->mute_mode.soft_mute; + hal->radio->mute_mode.soft_mute = val; + ret = helium_set_fm_mute_mode_req(&hal->radio->mute_mode); if (ret < 0) { ALOGE("%s:Error while setting FM soft mute %d", LOG_TAG, ret); - radio->mute_mode.soft_mute = saved_val; + hal->radio->mute_mode.soft_mute = saved_val; goto end; } break; @@ -1386,21 +1412,21 @@ static int set_fm_ctrl(int cmd, int val) helium_search_req(1, val); break; case HCI_FM_HELIUM_UPPER_BAND: - radio->recv_conf.band_high_limit = val; + hal->radio->recv_conf.band_high_limit = val; break; case HCI_FM_HELIUM_LOWER_BAND: - radio->recv_conf.band_low_limit = val; + hal->radio->recv_conf.band_low_limit = val; break; case HCI_FM_HELIUM_AUDIO_MODE: - radio->stereo_mode.stereo_mode = ~val; - hci_set_fm_stereo_mode_req(&radio->stereo_mode); + hal->radio->stereo_mode.stereo_mode = ~val; + hci_set_fm_stereo_mode_req(&hal->radio->stereo_mode); break; case HCI_FM_HELIUM_RIVA_ACCS_ADDR: - radio->riva_data_req.cmd_params.start_addr = val; + hal->radio->riva_data_req.cmd_params.start_addr = val; break; case HCI_FM_HELIUM_RIVA_ACCS_LEN: if (is_valid_peek_len(val)) { - radio->riva_data_req.cmd_params.length = val; + hal->radio->riva_data_req.cmd_params.length = val; } else { ret = -1; ALOGE("%s: riva access len is not valid\n", LOG_TAG); @@ -1408,15 +1434,15 @@ static int set_fm_ctrl(int cmd, int val) } break; case HCI_FM_HELIUM_RIVA_PEEK: - radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE; - val = hci_peek_data(&radio->riva_data_req.cmd_params); + hal->radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE; + val = hci_peek_data(&hal->radio->riva_data_req.cmd_params); break; case HCI_FM_HELIUM_RIVA_POKE: - if (radio->riva_data_req.cmd_params.length <= + if (hal->radio->riva_data_req.cmd_params.length <= MAX_RIVA_PEEK_RSP_SIZE) { - radio->riva_data_req.cmd_params.subopcode = + hal->radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE; - ret = hci_poke_data(&radio->riva_data_req); + ret = hci_poke_data(&hal->radio->riva_data_req); } else { ALOGE("%s: riva access len is not valid for poke\n", LOG_TAG); ret = -1; @@ -1424,22 +1450,22 @@ static int set_fm_ctrl(int cmd, int val) } break; case HCI_FM_HELIUM_SSBI_ACCS_ADDR: - radio->ssbi_data_accs.start_addr = val; + hal->radio->ssbi_data_accs.start_addr = val; break; case HCI_FM_HELIUM_SSBI_POKE: - radio->ssbi_data_accs.data = val; - ret = hci_ssbi_poke_reg(&radio->ssbi_data_accs); + hal->radio->ssbi_data_accs.data = val; + ret = hci_ssbi_poke_reg(&hal->radio->ssbi_data_accs); break; case HCI_FM_HELIUM_SSBI_PEEK: - radio->ssbi_peek_reg.start_address = val; - hci_ssbi_peek_reg(&radio->ssbi_peek_reg); + hal->radio->ssbi_peek_reg.start_address = val; + hci_ssbi_peek_reg(&hal->radio->ssbi_peek_reg); break; case HCI_FM_HELIUM_AGC_UCCTRL: - radio->set_get_reset_agc.ucctrl = val; + hal->radio->set_get_reset_agc.ucctrl = val; break; case HCI_FM_HELIUM_AGC_GAIN_STATE: - radio->set_get_reset_agc.ucgainstate = val; - hci_get_set_reset_agc_req(&radio->set_get_reset_agc); + hal->radio->set_get_reset_agc.ucgainstate = val; + hci_get_set_reset_agc_req(&hal->radio->set_get_reset_agc); break; case HCI_FM_HELIUM_SINR_SAMPLES: if (!is_valid_sinr_samples(val)) { @@ -1447,8 +1473,8 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->ch_det_threshold.sinr_samples = val; - ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + hal->radio->ch_det_threshold.sinr_samples = val; + ret = set_ch_det_thresholds_req(&hal->radio->ch_det_threshold); if (ret < 0) { ALOGE("Failed to set SINR samples %d", ret); goto end; @@ -1460,8 +1486,8 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->ch_det_threshold.sinr = val; - ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + hal->radio->ch_det_threshold.sinr = val; + ret = set_ch_det_thresholds_req(&hal->radio->ch_det_threshold); break; case HCI_FM_HELIUM_INTF_LOW_THRESHOLD: if (!is_valid_intf_det_low_th(val)) { @@ -1469,8 +1495,8 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->ch_det_threshold.low_th = val; - ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + hal->radio->ch_det_threshold.low_th = val; + ret = set_ch_det_thresholds_req(&hal->radio->ch_det_threshold); break; case HCI_FM_HELIUM_INTF_HIGH_THRESHOLD: if (!is_valid_intf_det_hgh_th(val)) { @@ -1478,30 +1504,30 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->ch_det_threshold.high_th = val; - ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + hal->radio->ch_det_threshold.high_th = val; + ret = set_ch_det_thresholds_req(&hal->radio->ch_det_threshold); break; case HCI_FM_HELIUM_SINRFIRSTSTAGE: def_data_wrt.mode = FM_SRCH_CONFG_MODE; def_data_wrt.length = FM_SRCH_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[SINRFIRSTSTAGE_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_RMSSIFIRSTSTAGE: def_data_wrt.mode = FM_SRCH_CONFG_MODE; def_data_wrt.length = FM_SRCH_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[RMSSIFIRSTSTAGE_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_CF0TH12: def_data_wrt.mode = FM_SRCH_CONFG_MODE; def_data_wrt.length = FM_SRCH_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[CF0TH12_BYTE1_OFFSET] = (val & 0xFF); def_data_wrt.data[CF0TH12_BYTE2_OFFSET] = ((val >> 8) & 0xFF); ret = hci_fm_default_data_write_req(&def_data_wrt); @@ -1509,40 +1535,40 @@ static int set_fm_ctrl(int cmd, int val) case HCI_FM_HELIUM_SRCHALGOTYPE: def_data_wrt.mode = FM_SRCH_CONFG_MODE; def_data_wrt.length = FM_SRCH_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[SRCH_ALGO_TYPE_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_AF_RMSSI_TH: def_data_wrt.mode = FM_AFJUMP_CONFG_MODE; def_data_wrt.length = FM_AFJUMP_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[AF_RMSSI_TH_OFFSET] = (val & 0xFF); ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_GOOD_CH_RMSSI_TH: def_data_wrt.mode = FM_AFJUMP_CONFG_MODE; def_data_wrt.length = FM_AFJUMP_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[GD_CH_RMSSI_TH_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_AF_RMSSI_SAMPLES: def_data_wrt.mode = FM_AFJUMP_CONFG_MODE; def_data_wrt.length = FM_AFJUMP_CNFG_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[AF_RMSSI_SAMPLES_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; case HCI_FM_HELIUM_RXREPEATCOUNT: def_data_wrt.mode = RDS_PS0_XFR_MODE; def_data_wrt.length = RDS_PS0_LEN; - memcpy(&def_data_wrt.data, &radio->def_data.data, - radio->def_data.data_len); + memcpy(&def_data_wrt.data, &hal->radio->def_data.data, + hal->radio->def_data.data_len); def_data_wrt.data[AF_RMSSI_SAMPLES_OFFSET] = val; ret = hci_fm_default_data_write_req(&def_data_wrt); break; @@ -1552,8 +1578,8 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->blend_tbl.BlendSinrHi = val; - ret = hci_fm_set_blend_tbl_req(&radio->blend_tbl); + hal->radio->blend_tbl.BlendSinrHi = val; + ret = hci_fm_set_blend_tbl_req(&hal->radio->blend_tbl); break; case HCI_FM_HELIUM_BLEND_RMSSIHI: if (!is_valid_blend_value(val)) { @@ -1561,8 +1587,8 @@ static int set_fm_ctrl(int cmd, int val) ret = -1; goto end; } - radio->blend_tbl.BlendRmssiHi = val; - ret = hci_fm_set_blend_tbl_req(&radio->blend_tbl); + hal->radio->blend_tbl.BlendRmssiHi = val; + ret = hci_fm_set_blend_tbl_req(&hal->radio->blend_tbl); break; case HCI_FM_HELIUM_ENABLE_LPF: ALOGI("%s: val: %x", __func__, val); @@ -1586,16 +1612,21 @@ static int get_fm_ctrl(int cmd, int val) int ret = 0; struct hci_fm_def_data_rd_req def_data_rd; + if (!hal) { + ALOGE("%s:ALERT: command sent before hal_init", __func__); + return -FM_HC_STATUS_FAIL; + } + ALOGE("%s: cmd = 0x%x", __func__, cmd); switch(cmd) { case HCI_FM_HELIUM_FREQ: - val = radio->fm_st_rsp.station_rsp.station_freq; + val = hal->radio->fm_st_rsp.station_rsp.station_freq; break; case HCI_FM_HELIUM_UPPER_BAND: - val = radio->recv_conf.band_high_limit; + val = hal->radio->recv_conf.band_high_limit; break; case HCI_FM_HELIUM_LOWER_BAND: - val = radio->recv_conf.band_low_limit; + val = hal->radio->recv_conf.band_low_limit; break; case HCI_FM_HELIUM_SINR_SAMPLES: set_bit(ch_det_th_mask_flag, CMD_CHDET_SINR_SAMPLE); @@ -1699,7 +1730,7 @@ cmd: clear_bit(station_dbg_param_mask_flag, CMD_STNDBGPARAM_INFDETOUT); break; case HCI_FM_HELIUM_GET_SINR: - if (radio->mode == FM_RECV) { + if (hal->radio->mode == FM_RECV) { set_bit(station_param_mask_flag, CMD_STNPARAM_SINR); ret = hci_fm_get_station_cmd_param_req(); if (ret != FM_HC_STATUS_SUCCESS) @@ -1710,12 +1741,12 @@ cmd: } break; case HCI_FM_HELIUM_RMSSI: - if (radio->mode == FM_RECV) { + if (hal->radio->mode == FM_RECV) { set_bit(station_param_mask_flag, CMD_STNPARAM_RSSI); ret = hci_fm_get_station_cmd_param_req(); if (ret != FM_HC_STATUS_SUCCESS) clear_bit(station_param_mask_flag, CMD_STNPARAM_RSSI); - } else if (radio->mode == FM_TRANS) { + } else if (hal->radio->mode == FM_TRANS) { ALOGE("HCI_FM_HELIUM_RMSSI: radio is not in recv mode"); ret = -EINVAL; } @@ -1728,7 +1759,7 @@ cmd: return ret; } -const fm_interface_t FM_HELIUM_LIB_INTERFACE = { +const struct fm_interface_t FM_HELIUM_LIB_INTERFACE = { hal_init, set_fm_ctrl, get_fm_ctrl diff --git a/helium/radio_helium_hal_cmds.c b/helium/radio_helium_hal_cmds.c index 79450235e4b3b5a896e86a1e8a52529a10e4b431..520ec12793719c8fa40b1506623738900dbd1c99 100644 --- a/helium/radio_helium_hal_cmds.c +++ b/helium/radio_helium_hal_cmds.c @@ -34,9 +34,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <errno.h> #include "radio-helium-commands.h" #include "radio-helium.h" -#include "fm_hci.h" +#include "fm_hci_api.h" #include <dlfcn.h> #define LOG_TAG "radio_helium" +extern struct fm_hal_t *hal; static int send_fm_cmd_pkt(uint16_t opcode, uint32_t len, void *param) { @@ -44,7 +45,7 @@ static int send_fm_cmd_pkt(uint16_t opcode, uint32_t len, void *param) int ret = 0; ALOGV("Send_fm_cmd_pkt, opcode: %x", opcode); // pthread_mutex_lock(&fm_hal); - FM_HDR *hdr = (FM_HDR *) malloc(p_len); + struct fm_command_header_t *hdr = (struct fm_command_header_t *) malloc(p_len); if (!hdr) { ALOGE("%s:hdr allocation failed", LOG_TAG); return -FM_HC_STATUS_NOMEM; @@ -52,12 +53,13 @@ static int send_fm_cmd_pkt(uint16_t opcode, uint32_t len, void *param) ALOGV("%s:opcode: %x", LOG_TAG, opcode); - hdr->protocol_byte = RADIO_HCI_COMMAND_PKT; + hdr->pi = RADIO_HCI_COMMAND_PKT; hdr->opcode = opcode; - hdr->plen = len; + hdr->len = len; if (len) - memcpy(hdr->cmd_params, (uint8_t *)param, len); - ret = transmit(hdr); + memcpy(hdr->params, (uint8_t *)param, len); + ret = fm_hci_transmit(hal->private_data, hdr); + ALOGV("%s:transmit done. status = %d", __func__, ret); return ret; } diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp index 163ce9bcf7638a67b0064121d7616b5c75fa9791..d4d4e15ce0618ac335ed855ebc579b11c61be6ec 100644 --- a/jni/android_hardware_fm.cpp +++ b/jni/android_hardware_fm.cpp @@ -512,7 +512,6 @@ typedef struct { typedef struct { int (*hal_init)(fm_vendor_callbacks_t *p_cb); - int (*set_fm_ctrl)(int ioctl, int val); int (*get_fm_ctrl) (int ioctl, int val); } fm_interface_t; @@ -704,7 +703,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setControlNative int err; ALOGE("id(%x) value: %x\n", id, value); #ifdef FM_SOC_TYPE_CHEROKEE - err = vendor_interface->set_fm_ctrl(id, value); + err = vendor_interface->set_fm_ctrl(id, value); #else if ((fd >= 0) && (id >= 0)) { err = FmIoctlsInterface :: set_control(fd, id, value); @@ -928,7 +927,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative } else { err = freq; } - return err; + return err; #endif if (fd >= 0) { err = FmIoctlsInterface :: get_lowerband_limit(fd, freq); @@ -962,7 +961,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative } else { err = freq; } - return err; + return err; #endif if (fd >= 0) { err = FmIoctlsInterface :: get_upperband_limit(fd, freq); @@ -993,7 +992,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative } else { err = FM_JNI_SUCCESS; } - return err; + return err; #endif if (fd >= 0) { err = FmIoctlsInterface :: set_audio_mode(fd, (enum AUDIO_MODE)val);