static int radio_hci_smd_register_dev(struct radio_data *hsmd)
{
	struct radio_hci_dev *hdev;
	int rc;

	hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
	hsmd->hdev = hdev;
	tasklet_init(&hsmd->rx_task, radio_hci_smd_recv_event,
		(unsigned long) hsmd);
	hdev->send  = radio_hci_smd_send_frame;
	hdev->destruct = radio_hci_smd_destruct;

	/* Open the SMD Channel and device and register the callback function */
	rc = smd_named_open_on_edge("APPS_FM", SMD_APPS_WCNSS,
		&hsmd->fm_channel, hdev, radio_hci_smd_notify_cmd);

	if (rc < 0) {
		FMDERR("Cannot open the command channel");
		return -ENODEV;
	}

	smd_disable_read_intr(hsmd->fm_channel);

	if (radio_hci_register_dev(hdev) < 0) {
		FMDERR("Can't register HCI device");
		return -ENODEV;
	}

	return 0;
}
Exemple #2
0
static void radio_hci_smd_notify_cmd(void *data, unsigned int event)
{
	struct radio_hci_dev *hdev = hs.hdev;

	if (!hdev) {
		FMDERR("Frame for unknown HCI device (hdev=NULL)");
		return;
	}

	switch (event) {
	case SMD_EVENT_DATA:
		tasklet_schedule(&hs.rx_task);
		break;
	case SMD_EVENT_OPEN:
		break;
	case SMD_EVENT_CLOSE:
		reset_worker = kzalloc(sizeof(*reset_worker), GFP_ATOMIC);
		if (!reset_worker) {
			FMDERR("Out of memory");
			break;
		}
		INIT_WORK(reset_worker, send_disable_event);
		schedule_work(reset_worker);
		break;
	default:
		break;
	}
}
static ssize_t fm_sinr_samples_write(struct file *filp, const char __user *userbuf,
						size_t count, loff_t *ppos)
{
	char sinr_samples[10] = {0};

	FMDBG("fm_sinr_samples_write  enter.  count:%d\n", (int)count);

	if (NULL == userbuf)
	{
		FMDERR("[%s]: Invlid value.line:%d\n",__FUNCTION__,__LINE__);
		return -EFAULT;
	}

	if ( 10 < count)
	{
		FMDERR("count value too much.");
		return -EFAULT;
	}

	if (copy_from_user(sinr_samples, userbuf, count))
		return -EFAULT;

	g_sinr_samples = simple_strtol(sinr_samples, NULL, 10);
	FMDBG("fm_sinr_samples_write exit  g_sinr_samples:%d\n", g_sinr_samples);
	return count;
}
static char *get_bt_fm_device_name(void)
{  
	int i = 0;
	int arry_size = sizeof(bt_device_array)/sizeof(bt_device_array[0]);
	const char *bt_fm_chip_type = "BT_FM_UNKNOWN_DEVICE";

	/* get bt/fm chip type from the device feature configuration (.xml file) */
	bt_fm_chip_type = get_bt_fm_device_type();
	FMDBG("get_bt_fm_device_name bt_fm_chip_type:%s", bt_fm_chip_type);
	
	if (NULL == bt_fm_chip_type)
	{
		FMDERR("BT-FM, Get chip type fail.\n");
		return bt_device_array[arry_size - 1].dev_name;
	}
	/* lookup bt_device_model in bt_device_array[] */
	for (i = 0; i < arry_size; i++)
	{
		if (0 == strncmp(bt_fm_chip_type,bt_device_array[i].chip_type,strlen(bt_device_array[i].chip_type)))
		{
			break; 
		}
	}
	/* If we get invalid type name, return "Unknown".*/
	if ( i == arry_size)
	{
		FMDERR("BT-FM, Get chip type fail.\n");

		return bt_device_array[arry_size - 1].dev_name;
	}

	return bt_device_array[i].dev_name;
}
static int fm_sinr_threshold_proc_show(struct seq_file *m, void *v)
{
	int sinr_threshold = FM_SINR_MAX;
	int ret ;
	
	FMDBG("fm_sinr_threshold_proc_show  enter\n");
	ret = get_fm_sinr_threshold_string(&sinr_threshold);
	if (-1 == ret)
	{
		// 7 is the default value
		FMDERR("Get FM Sinr Threshold failed and will use default value 7.\n");
		sinr_threshold = FM_SINR_7;
	}
	
	FMDBG("fm_sinr_threshold_proc_show g_sinr_threshold = %d .\n",g_sinr_threshold);	
	/* if we changed the sinr value, get the new value. used for debug */
	if (FM_SINR_MAX != g_sinr_threshold)
	{
		sinr_threshold = g_sinr_threshold;
	}

	FMDBG("fm_sinr_threshold_proc_show ,g_sinr_threshold = %d, sinr_threshold:%d\n", g_sinr_threshold, sinr_threshold);

	seq_printf(m, "%d", sinr_threshold);
	return 0;
}
static int radio_hci_smd_send_frame(struct sk_buff *skb)
{
	int len = 0;

	len = smd_write(hs.fm_channel, skb->data, skb->len);
	if (len < skb->len) {
		FMDERR("Failed to write Data %d", len);
		return -ENODEV;
	}
	return 0;
}
const void *get_bt_fm_device_type(void)
{
	int chip_type_len;
	struct device_node *dp = NULL;
	dp = of_find_node_by_path("/huawei_bt_info");
	if (!of_device_is_available(dp))
	{
		FMDERR("device is not available!\n");
		return NULL;
	}
	return  of_get_property(dp,"bt,chiptype", &chip_type_len);
}
Exemple #8
0
static void send_disable_event(struct work_struct *worker)
{
	struct sk_buff *skb;
	unsigned char buf[6] = { 0x0f, 0x04, 0x01, 0x02, 0x4c, 0x00 };
	int len = sizeof(buf);

	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
		FMDERR("Memory not allocated for the socket");
		return;
	}

	FMDERR("FM INSERT DISABLE Rx Event");

	memcpy(skb_put(skb, len), buf, len);

	skb_orphan(skb);
	skb->dev = (struct net_device   *)hs.hdev;

	radio_hci_recv_frame(skb);
	kfree(worker);
}
int get_fm_sinr_samples(int *sinr)
{
	int sinr_samples_len;
	struct device_node *dp = NULL;
	const char *psinr_samples = NULL;
	int sinr_samples;
	
	dp = of_find_node_by_path("/huawei_fm_info");
	if (!dp)
	{
		FMDERR("device is not available!\n");
		return -1;
	}
	
	psinr_samples = of_get_property(dp,"fm,sinr_samples", &sinr_samples_len);
	if (NULL == psinr_samples)
	{
		FMDERR("get sinr threshold value failed .\n");
		return -1;
	}
	sinr_samples = simple_strtol(psinr_samples,NULL,10);
	*sinr = sinr_samples;
	return 0;
}
static void radio_hci_smd_recv_event(unsigned long temp)
{
	int len;
	int rc;
	struct sk_buff *skb;
	unsigned  char *buf;
	struct radio_data *hsmd = &hs;
	len = smd_read_avail(hsmd->fm_channel);

	while (len) {
		skb = alloc_skb(len, GFP_KERNEL);
		if (!skb) {
			FMDERR("Memory not allocated for the socket");
			return;
		}

		buf = kmalloc(len, GFP_KERNEL);
		if (!buf) {
			kfree_skb(skb);
			FMDERR("Error in allocating buffer memory");
			return;
		}

		rc = smd_read_from_cb(hsmd->fm_channel, (void *)buf, len);

		memcpy(skb_put(skb, len), buf, len);

		skb_orphan(skb);
		skb->dev = (struct net_device   *)hs.hdev;

		rc = radio_hci_recv_frame(skb);

		kfree(buf);
		len = smd_read_avail(hsmd->fm_channel);
	}
}
static int bt_power_level_proc_show(struct seq_file *m, void *v)
{
	const char *bt_power_level = NULL;

	bt_power_level = get_bt_power_level();

	if (NULL != bt_power_level)
	{
		FMDBG("%s enter bt_power_level:%s;\n", __func__, bt_power_level);
		seq_printf(m, "%s", bt_power_level);
	}
	else
	{
		FMDERR("%s get bt_power_level failed;\n", __func__);
	}
	return 0;
}
const void *get_bt_power_level(void)
{
	int bt_power_level_len;
	struct device_node *dp = NULL;
	dp = of_find_node_by_path("/huawei_bt_info");
	if (!dp)
	{
		 FMDERR("device is not available!\n");
		 return NULL;
	}
	else
	{
		 FMDBG("%s:dp->name:%s,dp->full_name:%s;\n", __func__, dp->name, dp->full_name);
	}
	   
	return  of_get_property(dp,"bt,power_level", &bt_power_level_len);
}
static int bt_fm_ver_proc_show(struct seq_file *m, void *v)
{
	const char *bt_fm_fw_ver = NULL;

	bt_fm_fw_ver = get_bt_fm_fw_ver();

	if ( NULL != bt_fm_fw_ver )
	{
		FMDBG("%s enter wifi_device_type:%s;\n", __func__,bt_fm_fw_ver);
		seq_printf(m,"%s",bt_fm_fw_ver);
	}
	else
	{
		FMDERR("%s get bt_fm_fw_ver failed;\n", __func__);
	}
	return 0;
}
static int radio_hci_smd_init(void)
{
	int ret;

	if (chan_opened) {
		FMDBG("Channel is already opened");
		return 0;
	}

	/* this should be called with fm_smd_enable lock held */
	ret = radio_hci_smd_register_dev(&hs);
	if (ret < 0) {
		FMDERR("Failed to register smd device");
		chan_opened = false;
		return ret;
	}
	chan_opened = true;
	return ret;
}
static void radio_hci_smd_notify_cmd(void *data, unsigned int event)
{
	struct radio_hci_dev *hdev = hs.hdev;

	if (!hdev) {
		FMDERR("Frame for unknown HCI device (hdev=NULL)");
		return;
	}

	switch (event) {
	case SMD_EVENT_DATA:
		tasklet_schedule(&hs.rx_task);
		break;
	case SMD_EVENT_OPEN:
	case SMD_EVENT_CLOSE:
		break;
	default:
		break;
	}
}
static int fm_sinr_samples_proc_show(struct seq_file *m, void *v)
{
	unsigned int sinr_samples = FM_SINR_SAMPLES_MAX;
	int ret;
	
	FMDBG("fm_sinr_samples_proc_show enter.\n");
	ret = get_fm_sinr_samples(&sinr_samples);
	if (-1 == ret)
	{
		FMDERR("Get FM Sinr Samples failed and will use default value 10.\n");
		sinr_samples = FM_SINR_SAMPLES_10;
	}
	
	if (FM_SINR_SAMPLES_MAX != g_sinr_samples)
	{
		sinr_samples = g_sinr_samples;
	}
	
	FMDBG("fm_sinr_samples_proc_show ,g_sinr_samples = %d, sinr_samples:%d\n", g_sinr_samples, sinr_samples);

	seq_printf(m, "%d", sinr_samples);
	return 0;
}
/**
 * Initializes the module.
 * @return On success, 0. On error, -1, and <code>errno</code> is set
 * appropriately.
 */
static int __init featuretransfer_init(void)
{
	int retval = 0;
	struct proc_dir_entry *ent = NULL;

	FMDBG("BT DEVICE FEATURE VERSION: %s", VERSION);

	/* Driver Register */
	retval = platform_driver_register(&featuretransfer_driver);
	if (0 != retval)
	{
		FMDERR("[%s],featurntransfer driver register fail.",LOG_TAG);
		return retval;
	}

	/* create device_feature directory for bt chip info */
	device_dir = proc_mkdir("device_feature", NULL);
	if (NULL == device_dir)
	{
		FMDERR("Unable to create /proc/device_feature directory");
		return -ENOMEM;
	}

	/* create bt_feature for bluetooth feature */
	bt_dir = proc_mkdir("bt_feature", device_dir);
	if (NULL == bt_dir)
	{
		FMDERR("Unable to create /proc/%s directory", PROC_DIR);
		return -ENOMEM;
	}

	/* Creating read/write "chiptype" entry for bluetooth chip type*/
	ent = proc_create("chiptype", 0, bt_dir, &chiptype_proc_fops);
	if (NULL == ent) 
	{
		FMDERR("Unable to create /proc/%s/chiptype entry", PROC_DIR);
		retval = -ENOMEM;
		goto fail;
	}

	/* Creating read/write "bt_fm_fw_ver" entry */
	ent = proc_create("bt_fm_fw_ver", 0, bt_dir, &bt_fm_ver_proc_fops);
	if (NULL == ent) 
	{
		FMDERR("Unable to create /proc/%s/bt_fm_fw_ver entry", PROC_DIR);
		retval = -ENOMEM;
		goto fail;
	}

	/* Creating read/write "bt_power_level" entry */
	ent = proc_create("power_level", 0, bt_dir, &bt_power_level_proc_fops);
	if (NULL == ent)
	{
		FMDERR("Unable to create /proc/%s/power_level entry", PROC_DIR);
		retval = -ENOMEM;
		goto fail;
	}

	/* create fm_feature for fm feature */
	fm_dir = proc_mkdir("fm_feature", device_dir);
	if (NULL == fm_dir)
	{
		FMDERR("Unable to create /proc/%s directory", PROC_DIR);
		return -ENOMEM;
	}

	/* Creating read/write "sinr" entry for bluetooth chip type*/
	ent = proc_create("sinr_threshold", 0, fm_dir, &fm_sinr_threshold_proc_fops);
	if (NULL == ent) 
	{
		FMDERR("Unable to create /proc/%s/sinr_threshold entry", PROC_DIR);
		retval = -ENOMEM;
		goto fail;
	}

	/* Creating read/write "rssi" entry for bcm4330 fm*/
	ent = proc_create("sinr_samples", 0, fm_dir, &fm_sinr_samples_proc_fops);
	if (NULL == ent) 
	{
		FMDERR("Unable to create /proc/%s/sinr_samples entry", PROC_DIR);
		retval = -ENOMEM;
		goto fail;
	}

	
	return 0;

fail:
	remove_proc_entry("chiptype", bt_dir);
	remove_proc_entry("bt_fm_fw_ver", bt_dir);
	remove_proc_entry("power_level", bt_dir);
	remove_proc_entry("sinr_threshold", fm_dir);
	remove_proc_entry("sinr_samples", fm_dir);
	remove_proc_entry("bt_feature", device_dir);
	remove_proc_entry("fm_feature", device_dir);
	remove_proc_entry("device_feature", 0);
	return retval;
}