Skip to content

Instantly share code, notes, and snippets.

@d-k-c
Created September 7, 2018 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d-k-c/d2c0bef86811dcd92f15014abb334018 to your computer and use it in GitHub Desktop.
Save d-k-c/d2c0bef86811dcd92f15014abb334018 to your computer and use it in GitHub Desktop.
From b67d4b91fb477e7931ecfc4628e6e052bdf0f3d0 Mon Sep 17 00:00:00 2001
From: Damien Riegel <damien.riegel@savoirfairelinux.com>
Date: Mon, 31 Jul 2017 12:35:46 -0400
Subject: [PATCH 2/4] get it into a compile state
---
drivers/media/radio/radio-iris-transport.c | 195 ++++++++++-------------------
drivers/media/radio/radio-iris-v4l2.c | 66 ++++++----
include/uapi/media/radio-hci.h | 88 +++++++++++++
include/uapi/media/radio-iris.h | 47 +------
4 files changed, 197 insertions(+), 199 deletions(-)
create mode 100644 include/uapi/media/radio-hci.h
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 88133ce5cae8..c1008992040d 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -24,130 +24,67 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/skbuff.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
+#include <linux/string.h>
#include <linux/workqueue.h>
-#include <soc/qcom/smd.h>
-#include <media/radio-iris.h>
+#include <media/radio-hci.h>
struct radio_data {
struct radio_hci_dev *hdev;
- struct tasklet_struct rx_task;
- struct smd_channel *fm_channel;
+
+ void *wcnss;
+ struct qcom_smd_channel *fm_channel;
};
-struct radio_data hs;
-static struct work_struct *reset_worker;
+struct radio_data *radio_data;
static void radio_hci_smd_destruct(struct radio_hci_dev *hdev)
{
- radio_hci_unregister_dev(hs.hdev);
-}
-
-
-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_ATOMIC);
- if (!skb) {
- FMDERR("Memory not allocated for the socket");
- return;
- }
-
- buf = kmalloc(len, GFP_ATOMIC);
- if (!buf) {
- kfree_skb(skb);
- FMDERR("Error in allocating buffer memory");
- return;
- }
-
- rc = smd_read(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);
- }
+ radio_hci_unregister_dev(hdev);
}
-static int radio_hci_smd_send_frame(struct sk_buff *skb)
+static int radio_hci_smd_send_frame(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
- int len = 0;
+ struct radio_data *hsmd = radio_hci_get_drvdata(hdev);
+ int ret;
- len = smd_write(hs.fm_channel, skb->data, skb->len);
- if (len < skb->len) {
- FMDERR("Failed to write Data %d", len);
- kfree_skb(skb);
- return -ENODEV;
- }
+ pr_info("%s, sending %d bytes. ret: %d\n", __func__, skb->len, ret);
+ pr_info("datasent : %*ph\n", skb->len, skb->data);
+ ret = qcom_smd_send(hsmd->fm_channel, skb->data, skb->len);
kfree_skb(skb);
- return 0;
-}
+ return ret;
+}
-static void send_disable_event(struct work_struct *worker)
+static int radio_hci_smd_rcv(struct radio_hci_dev *hdev, const void *data,
+ size_t count)
{
struct sk_buff *skb;
- unsigned char buf[6] = { 0x0f, 0x04, 0x01, 0x02, 0x4c, 0x00 };
- int len = sizeof(buf);
+ pr_info("%s, received %d bytes\n", __func__, count);
+ pr_info("data received: %*ph\n", count, data);
- skb = alloc_skb(len, GFP_ATOMIC);
+ /* Use GFP_ATOMIC as we're in IRQ context */
+ skb = alloc_skb(count, GFP_ATOMIC);
if (!skb) {
- FMDERR("Memory not allocated for the socket");
- kfree(worker);
- return;
+ return -ENOMEM;
}
- FMDERR("FM INSERT DISABLE Rx Event");
-
- memcpy(skb_put(skb, len), buf, len);
-
+ memcpy(skb_put(skb, count), data, count);
skb_orphan(skb);
- skb->dev = (struct net_device *)hs.hdev;
+ skb->dev = (struct net_device*)hdev;
- radio_hci_recv_frame(skb);
- kfree(worker);
+ return radio_hci_recv_frame(skb);
}
-static void radio_hci_smd_notify_cmd(void *data, unsigned int event)
+static int radio_iris_smd_callback(struct qcom_smd_channel *channel,
+ const void *data,
+ size_t count)
{
- struct radio_hci_dev *hdev = hs.hdev;
-
- if (!hdev) {
- FMDERR("Frame for unknown HCI device (hdev=NULL)");
- return;
- }
+ struct radio_data *radio_data = qcom_smd_get_drvdata(channel);
- 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;
- }
+ return radio_hci_smd_rcv(radio_data->hdev, data, count);
}
static int radio_hci_smd_register_dev(struct radio_data *hsmd)
@@ -155,61 +92,61 @@ static int radio_hci_smd_register_dev(struct radio_data *hsmd)
struct radio_hci_dev *hdev;
int rc;
- if (hsmd == NULL)
- return -ENODEV;
-
hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
- if (hdev == NULL)
- return -ENODEV;
+ if (!hdev)
+ return -ENOMEM;
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");
- hsmd->hdev = NULL;
- kfree(hdev);
- return -ENODEV;
+ hsmd->fm_channel = qcom_wcnss_open_channel(hsmd->wcnss, "APPS_FM",
+ radio_iris_smd_callback);
+ if (IS_ERR(hsmd->fm_channel)) {
+ pr_err("failed to open SMD channel \n");
+ return PTR_ERR(hsmd->fm_channel);
}
- smd_disable_read_intr(hsmd->fm_channel);
+ qcom_smd_set_drvdata(hsmd->fm_channel, hsmd);
+ radio_hci_set_drvdata(hdev, hsmd);
- if (radio_hci_register_dev(hdev) < 0) {
- FMDERR("Can't register HCI device");
- smd_close(hsmd->fm_channel);
+ /* Open the SMD Channel and device and register the callback function */
+ rc = radio_hci_register_dev(hdev);
+ if (rc < 0) {
+ pr_err("radio-iris-transport: Can't register HCI device");
hsmd->hdev = NULL;
kfree(hdev);
- return -ENODEV;
+ return rc;
}
return 0;
}
-static void radio_hci_smd_deregister(void)
+static void radio_hci_smd_deregister(struct radio_data *hsmd)
{
- smd_close(hs.fm_channel);
- hs.fm_channel = 0;
+ hsmd->fm_channel = 0;
+ radio_hci_unregister_dev(hsmd->hdev);
+ kfree(hsmd->hdev);
}
-static int radio_hci_smd_init(void)
+int radio_iris_smd_init(void *wcnss)
{
- return radio_hci_smd_register_dev(&hs);
+ if (radio_data)
+ return -EBUSY;
+
+ radio_data = kmalloc(sizeof(radio_data), GFP_KERNEL);
+ if (!radio_data)
+ return -ENOMEM;
+
+ radio_data->wcnss = wcnss;
+ return radio_hci_smd_register_dev(radio_data);
}
-module_init(radio_hci_smd_init);
-static void __exit radio_hci_smd_exit(void)
+int radio_iris_smd_release(void)
{
- radio_hci_smd_deregister();
-}
-module_exit(radio_hci_smd_exit);
+ radio_hci_smd_deregister(radio_data);
+ kfree(radio_data);
+ radio_data = NULL;
-MODULE_DESCRIPTION("Bluetooth SMD driver");
-MODULE_AUTHOR("Ankur Nandwani <ankurn@codeaurora.org>");
-MODULE_LICENSE("GPL v2");
+ return 0;
+}
diff --git a/drivers/media/radio/radio-iris-v4l2.c b/drivers/media/radio/radio-iris-v4l2.c
index e027aaac2441..cb832729631d 100644
--- a/drivers/media/radio/radio-iris-v4l2.c
+++ b/drivers/media/radio/radio-iris-v4l2.c
@@ -34,6 +34,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/radio-iris.h>
#include <asm/unaligned.h>
@@ -63,6 +64,10 @@ static void radio_hci_rx_task(unsigned long arg);
static struct video_device *video_get_dev(void);
static DEFINE_RWLOCK(hci_task_lock);
+/* SMD related routines */
+int radio_iris_smd_init(void *wcnss);
+int radio_iris_smd_release(void);
+
struct iris_device {
struct device *dev;
struct kfifo data_buf[IRIS_BUF_MAX];
@@ -88,6 +93,7 @@ struct iris_device {
struct radio_hci_dev *fm_hdev;
+ struct v4l2_device v4l2_dev;
struct v4l2_capability g_cap;
struct v4l2_control *g_ctl;
@@ -123,6 +129,8 @@ struct iris_device {
struct hci_fm_blend_table blend_tbl;
};
+struct iris_device;
+
static struct video_device *priv_videodev;
static int iris_do_calibration(struct iris_device *radio);
static void hci_buff_ert(struct iris_device *radio,
@@ -527,7 +535,7 @@ static int hci_send_frame(struct sk_buff *skb)
__net_timestamp(skb);
skb_orphan(skb);
- return hdev->send(skb);
+ return hdev->send(hdev, skb);
}
static void radio_hci_cmd_task(unsigned long arg)
@@ -609,7 +617,6 @@ int radio_hci_register_dev(struct radio_hci_dev *hdev)
return 0;
}
-EXPORT_SYMBOL(radio_hci_register_dev);
int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
{
@@ -629,7 +636,6 @@ int radio_hci_unregister_dev(struct radio_hci_dev *hdev)
return 0;
}
-EXPORT_SYMBOL(radio_hci_unregister_dev);
int radio_hci_recv_frame(struct sk_buff *skb)
{
@@ -655,7 +661,7 @@ int radio_hci_recv_frame(struct sk_buff *skb)
EXPORT_SYMBOL(radio_hci_recv_frame);
int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
- void *param)
+ void *param)
{
int len = RADIO_HCI_COMMAND_HDR_SIZE + plen;
struct radio_hci_command_hdr *hdr;
@@ -1300,9 +1306,9 @@ static int radio_hci_err(__u32 code)
}
static int __radio_hci_request(struct radio_hci_dev *hdev,
- int (*req)(struct radio_hci_dev *hdev,
- unsigned long param),
- unsigned long param, __u32 timeout)
+ int (*req)(struct radio_hci_dev *hdev,
+ unsigned long param),
+ unsigned long param, __u32 timeout)
{
int err = 0;
DECLARE_WAITQUEUE(wait, current);
@@ -1346,9 +1352,9 @@ static int __radio_hci_request(struct radio_hci_dev *hdev,
}
static inline int radio_hci_request(struct radio_hci_dev *hdev,
- int (*req)(struct
- radio_hci_dev * hdev, unsigned long param),
- unsigned long param, __u32 timeout)
+ int (*req)(struct radio_hci_dev * hdev,
+ unsigned long param),
+ unsigned long param, u32 timeout)
{
int ret = 0;
@@ -5008,8 +5014,11 @@ static int iris_vidioc_g_tuner(struct file *file, void *priv,
radio->trans_conf.band_high_limit * TUNE_PARAM;
}
- } else
+ } else {
+ FMDERR("radio in a non working mode\n");
return -EINVAL;
+ }
+
return 0;
}
@@ -5193,13 +5202,6 @@ static int iris_vidioc_dqbuf(struct file *file, void *priv,
return retval;
}
-static int iris_vidioc_g_fmt_type_private(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- return 0;
-
-}
-
static int iris_vidioc_s_hw_freq_seek(struct file *file, void *priv,
const struct v4l2_hw_freq_seek *seek)
{
@@ -5238,7 +5240,9 @@ static int iris_vidioc_querycap(struct file *file, void *priv,
strlcpy(radio->g_cap.card, DRIVER_CARD, sizeof(radio->g_cap.card));
radio->g_cap.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- capability->capabilities = radio->g_cap.capabilities;
+ capability->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ capability->capabilities = radio->g_cap.capabilities | V4L2_CAP_DEVICE_CAPS;
+
return 0;
}
@@ -5338,7 +5342,6 @@ static const struct v4l2_ioctl_ops iris_ioctl_ops = {
.vidioc_s_frequency = iris_vidioc_s_frequency,
.vidioc_s_hw_freq_seek = iris_vidioc_s_hw_freq_seek,
.vidioc_dqbuf = iris_vidioc_dqbuf,
- .vidioc_g_fmt_type_private = iris_vidioc_g_fmt_type_private,
.vidioc_s_ext_ctrls = iris_vidioc_s_ext_ctrls,
.vidioc_g_ext_ctrls = iris_vidioc_g_ext_ctrls,
};
@@ -5366,7 +5369,9 @@ static struct video_device *video_get_dev(void)
static int __init iris_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct iris_device *radio;
+ void *wcnss;
int retval;
int radio_nr = -1;
int i;
@@ -5392,9 +5397,17 @@ static int __init iris_probe(struct platform_device *pdev)
return -ENOMEM;
}
+
memcpy(radio->videodev, &iris_viddev_template,
sizeof(iris_viddev_template));
+ radio->videodev->v4l2_dev = &radio->v4l2_dev;
+ retval = v4l2_device_register(dev, radio->videodev->v4l2_dev);
+ if (retval) {
+ dev_err(dev, "failed to register v4l2 device %d\n", retval);
+ return retval;
+ }
+
for (i = 0; i < IRIS_BUF_MAX; i++) {
int kfifo_alloc_rc = 0;
spin_lock_init(&radio->buf_lock[i]);
@@ -5429,9 +5442,6 @@ static int __init iris_probe(struct platform_device *pdev)
video_set_drvdata(radio->videodev, radio);
- if (NULL == video_get_drvdata(radio->videodev))
- FMDERR(": video_get_drvdata failed\n");
-
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
radio_nr);
if (retval) {
@@ -5455,6 +5465,14 @@ static int __init iris_probe(struct platform_device *pdev)
kfree(radio);
}
}
+
+ wcnss = dev_get_drvdata(pdev->dev.parent);
+ retval = radio_iris_smd_init(wcnss);
+ if (retval) {
+ dev_err(dev, "failed to initialize smd %d\n", retval);
+ return retval;
+ }
+
return 0;
}
@@ -5481,7 +5499,7 @@ static int iris_remove(struct platform_device *pdev)
}
static const struct of_device_id iris_fm_match[] = {
- {.compatible = "qcom,iris_fm"},
+ {.compatible = "qcom,wcnss-radio"},
{}
};
diff --git a/include/uapi/media/radio-hci.h b/include/uapi/media/radio-hci.h
new file mode 100644
index 000000000000..6af2c0b8b37b
--- /dev/null
+++ b/include/uapi/media/radio-hci.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 - Savoir-faire Linux, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+ * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ * SOFTWARE IS DISCLAIMED.
+ */
+
+#ifndef _RADIO_HCI_H
+#define _RADIO_HCI_H
+
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
+
+struct radio_hci_dev {
+ char name[8];
+ unsigned long flags;
+ __u16 id;
+ __u8 bus;
+ __u8 dev_type;
+ __u8 dev_name[248];
+ __u8 dev_class[3];
+ __u8 features[8];
+ __u8 commands[64];
+
+ unsigned int data_block_len;
+ unsigned long cmd_last_tx;
+
+ struct sk_buff *sent_cmd;
+
+ __u32 req_status;
+ __u32 req_result;
+ atomic_t cmd_cnt;
+
+ struct tasklet_struct cmd_task;
+ struct tasklet_struct rx_task;
+ struct tasklet_struct tx_task;
+
+ struct sk_buff_head rx_q;
+ struct sk_buff_head raw_q;
+ struct sk_buff_head cmd_q;
+
+ struct mutex req_lock;
+ wait_queue_head_t req_wait_q;
+
+ int (*open)(struct radio_hci_dev *hdev);
+ int (*close)(struct radio_hci_dev *hdev);
+ int (*flush)(struct radio_hci_dev *hdev);
+ int (*send)(struct radio_hci_dev *hdev, struct sk_buff *skb);
+ void (*destruct)(struct radio_hci_dev *hdev);
+ void (*notify)(struct radio_hci_dev *hdev, unsigned int evt);
+
+ void *drvdata;
+};
+
+int radio_hci_register_dev(struct radio_hci_dev *hdev);
+int radio_hci_unregister_dev(struct radio_hci_dev *hdev);
+int radio_hci_recv_frame(struct sk_buff *skb);
+int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
+ void *param);
+void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb);
+
+static inline void* radio_hci_get_drvdata(struct radio_hci_dev *hdev)
+{
+ return hdev->drvdata;
+}
+
+static inline void radio_hci_set_drvdata(struct radio_hci_dev *hdev, void *data)
+{
+ hdev->drvdata = data;
+}
+
+#endif /* _RADIO_HCI_H */
diff --git a/include/uapi/media/radio-iris.h b/include/uapi/media/radio-iris.h
index 03ae828724be..bb6732e15c6b 100644
--- a/include/uapi/media/radio-iris.h
+++ b/include/uapi/media/radio-iris.h
@@ -32,6 +32,7 @@
#include <linux/mutex.h>
#include <linux/atomic.h>
#include <media/radio-iris-commands.h>
+#include <media/radio-hci.h>
const unsigned char MIN_TX_TONE_VAL = 0x00;
const unsigned char MAX_TX_TONE_VAL = 0x07;
@@ -146,52 +147,6 @@ struct radio_hci_event_hdr {
__u8 plen;
} __packed;
-struct radio_hci_dev {
- char name[8];
- unsigned long flags;
- __u16 id;
- __u8 bus;
- __u8 dev_type;
- __u8 dev_name[248];
- __u8 dev_class[3];
- __u8 features[8];
- __u8 commands[64];
-
- unsigned int data_block_len;
- unsigned long cmd_last_tx;
-
- struct sk_buff *sent_cmd;
-
- __u32 req_status;
- __u32 req_result;
- atomic_t cmd_cnt;
-
- struct tasklet_struct cmd_task;
- struct tasklet_struct rx_task;
- struct tasklet_struct tx_task;
-
- struct sk_buff_head rx_q;
- struct sk_buff_head raw_q;
- struct sk_buff_head cmd_q;
-
- struct mutex req_lock;
- wait_queue_head_t req_wait_q;
-
- int (*open)(struct radio_hci_dev *hdev);
- int (*close)(struct radio_hci_dev *hdev);
- int (*flush)(struct radio_hci_dev *hdev);
- int (*send)(struct sk_buff *skb);
- void (*destruct)(struct radio_hci_dev *hdev);
- void (*notify)(struct radio_hci_dev *hdev, unsigned int evt);
-};
-
-int radio_hci_register_dev(struct radio_hci_dev *hdev);
-int radio_hci_unregister_dev(struct radio_hci_dev *hdev);
-int radio_hci_recv_frame(struct sk_buff *skb);
-int radio_hci_send_cmd(struct radio_hci_dev *hdev, __u16 opcode, __u32 plen,
- void *param);
-void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb);
-
/* Opcode OCF */
/* HCI recv control commands opcode */
#define HCI_OCF_FM_ENABLE_RECV_REQ 0x0001
--
2.13.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment