/* File Open */ static int fm_v4l2_fops_open(struct file *file) { int ret; FMDRV_API_START(); /* Don't allow multiple open */ if (radio_disconnected) { FM_DRV_ERR("FM device is already opened\n"); FMDRV_API_EXIT(-EBUSY); return -EBUSY; } /* Request FM Core to link with FM ST */ ret = fm_core_setup_transport(); if (ret) { FM_DRV_ERR("Unable to setup FM Core transport"); FMDRV_API_EXIT(ret); return ret; } /* Initialize FM Core */ ret = fm_core_prepare(); if (ret) { FM_DRV_ERR("Unable to prepare FM CORE"); FMDRV_API_EXIT(ret); return ret; } FM_DRV_DBG("Load FM RX firmware.."); /* By default load FM RX firmware */ ret = fm_core_mode_set(FM_MODE_RX); if (ret) { FM_DRV_ERR("Unable to load FM RX firmware"); FMDRV_API_EXIT(ret); return ret; } radio_disconnected = 1; FM_DRV_DBG("FM CORE is ready"); FMDRV_API_EXIT(0); return 0; }
/* File Release */ static int fm_v4l2_fops_release(struct file *file) { int ret; FMDRV_API_START(); if (!radio_disconnected) { FM_DRV_DBG("FM device already closed,close called again?"); FMDRV_API_EXIT(0); return 0; } FM_DRV_DBG("Turning off.."); ret = fm_core_mode_set(FM_MODE_OFF); if (ret) { FM_DRV_ERR("Unable to turn off the chip"); FMDRV_API_EXIT(ret); return ret; } /* Request FM Core to unlink from ST driver */ ret = fm_core_release(); if (ret) { FM_DRV_ERR("FM CORE release failed"); FMDRV_API_EXIT(ret); return ret; } /* Release FM Core transport */ ret = fm_core_release_transport(); if (ret) { FM_DRV_ERR("Unable to setup FM Core transport"); FMDRV_API_EXIT(ret); return ret; } radio_disconnected = 0; FM_DRV_DBG("FM CORE released successfully"); FMDRV_API_EXIT(0); return 0; }
/* Called from FM Core and FM Char device interface to claim * FM ST. Who ever comes first, ownership of FM ST will be * given to them. */ int fm_st_claim(void) { FMDRV_API_START(); /* Give ownership of FM ST to first caller */ if (is_fm_st_claimed == FM_ST_NOT_CLAIMED) { is_fm_st_claimed = FM_ST_CLAIMED; FMDRV_API_EXIT(FM_ST_SUCCESS); return FM_ST_SUCCESS; } FM_DRV_DBG("FM ST claimed already"); FMDRV_API_EXIT(FM_ST_FAILED); return FM_ST_FAILED; }
/* Write RDS data */ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, size_t count, loff_t *ppos) { struct tx_rds rds; int ret; FMDRV_API_START(); ret = copy_from_user(&rds, buf, sizeof(rds)); FM_DRV_DBG("(%d)type: %d, text %s, af %d", ret, rds.text_type, rds.text, rds.af_freq); fm_core_tx_set_radio_text(rds.text, rds.text_type); fm_core_tx_set_af(rds.af_freq); FMDRV_API_EXIT(0); return 0; }
/* Called from V4L2 RADIO open function (fm_fops_open()) to * register FM driver with Shared Transport */ int fm_st_register(struct sk_buff_head *rx_q, struct tasklet_struct *rx_task) { static struct st_proto_s fm_st_proto; unsigned long timeleft; int ret; ret = 0; FMDRV_API_START(); /* Populate FM driver info required by ST */ memset(&fm_st_proto, 0, sizeof(fm_st_proto)); /* FM driver ID */ fm_st_proto.channelid = 8; /* Receive function which called from ST */ fm_st_proto.recv = fm_st_receive; /* Packet match function may used in future */ fm_st_proto.match_packet = NULL; /* Callback to be called when registration is pending */ fm_st_proto.reg_complete_cb = fm_st_registration_completion_cb; fm_st_proto.max_frame_size = 255; fm_st_proto.header_size = 3; fm_st_proto.length_offset = 1; fm_st_proto.length_size = 2; fm_st_proto.gpio_id = ST_GPIO_FM; /* Register with ST layer */ ret = st_register(&fm_st_proto); if (ret == ST_ERR_PENDING) { /* Prepare wait-for-completion handler data structures. * Needed to syncronize this and * fm_st_registration_completion_cb() functions. */ init_completion(&wait_for_fmdrv_reg_completion); /* Reset ST registration callback status flag. This value * will be updated in fm_st_registration_completion_cb() * function whenever it is called from ST driver. */ streg_cbdata = -EINPROGRESS; /* ST is busy with other protocol registration (may be busy with * firmware download). So, wait till the registration callback * (passed as a argument to st_register() function) getting * called from ST. */ FM_DRV_DBG(" %s waiting for reg completion signal from ST", __func__); timeleft = wait_for_completion_timeout(&wait_for_fmdrv_reg_completion, FM_ST_REGISTER_TIMEOUT); if (!timeleft) { FM_DRV_ERR("Timeout(%d sec), didn't get reg" "completion signal from ST", jiffies_to_msecs(FM_ST_REGISTER_TIMEOUT) / 1000); FMDRV_API_EXIT(-ETIMEDOUT); return -ETIMEDOUT; } /* Is ST registration callback called with ERROR value? */ if (streg_cbdata != 0) { FM_DRV_ERR("ST reg completion CB called with invalid" "status %d", streg_cbdata); FMDRV_API_EXIT(-EAGAIN); return -EAGAIN; } ret = 0; } else if (ret == ST_ERR_FAILURE) { FM_DRV_ERR("st_register failed %d", ret); FMDRV_API_EXIT(-EAGAIN); return -EAGAIN; } /* Store Rx Q and Rx tasklet pointers. This pointers should * already initialized by caller */ g_rx_task = rx_task; g_rx_q = rx_q; FMDRV_API_EXIT(ret); return ret; }