radio: iris: adding support for RDS program service and radio text
This patch adds support for RDS program service and radio text
so that RDS data is displayed in the UI
Signed-off-by: Ankur Nandwani <ankurn@codeaurora.org>
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index fe53ca8..47e23e5 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1503,6 +1503,80 @@
iris_q_event(radio, IRIS_EVT_MONO);
}
+
+static void iris_q_rds_data(struct iris_device *radio,
+ char *data, int len, int event)
+{
+ struct kfifo *data_b = &radio->data_buf[event];
+
+ if (kfifo_in_locked(data_b, data, len, &radio->buf_lock[event]))
+ wake_up_interruptible(&radio->event_queue);
+}
+
+
+static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct iris_device *radio = video_get_drvdata(video_get_dev());
+ int len;
+ char *data;
+
+ len = (skb->data[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
+ iris_q_event(radio, IRIS_EVT_NEW_PS_RDS);
+ data = kmalloc(len, GFP_ATOMIC);
+ if (!data) {
+ FMDERR("Failed to allocate memory");
+ return;
+ }
+
+ data[0] = skb->data[RDS_PS_LENGTH_OFFSET];
+ data[1] = skb->data[RDS_PTYPE];
+ data[2] = skb->data[RDS_PID_LOWER];
+ data[3] = skb->data[RDS_PID_HIGHER];
+ data[4] = 0;
+
+ memcpy(data+RDS_OFFSET, &skb->data[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
+
+ iris_q_rds_data(radio, data, len, IRIS_BUF_PS_RDS);
+
+ kfree(data);
+}
+
+
+static inline void hci_ev_radio_text(struct radio_hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct iris_device *radio = video_get_drvdata(video_get_dev());
+ int len = 0;
+ char *data;
+
+ iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
+
+ while (skb->data[len+RDS_OFFSET] != 0x0d)
+ len++;
+ len++;
+
+ data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
+ if (!data) {
+ FMDERR("Failed to allocate memory");
+ return;
+ }
+
+ data[0] = len;
+ data[1] = skb->data[RDS_PTYPE];
+ data[2] = skb->data[RDS_PID_LOWER];
+ data[3] = skb->data[RDS_PID_HIGHER];
+ data[4] = 0;
+
+ memcpy(data+RDS_OFFSET, &skb->data[RDS_OFFSET], len);
+ data[len+RDS_OFFSET] = 0x00;
+
+ iris_q_rds_data(radio, data, len+RDS_OFFSET, IRIS_BUF_RT_RDS);
+
+ kfree(data);
+}
+
+
void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
{
struct radio_hci_event_hdr *hdr = (void *) skb->data;
@@ -1525,8 +1599,13 @@
case HCI_EV_RDS_LOCK_STATUS:
case HCI_EV_SERVICE_AVAILABLE:
case HCI_EV_RDS_RX_DATA:
+ break;
case HCI_EV_PROGRAM_SERVICE:
+ hci_ev_program_service(hdev, skb);
+ break;
case HCI_EV_RADIO_TEXT:
+ hci_ev_radio_text(hdev, skb);
+ break;
case HCI_EV_FM_AF_LIST:
case HCI_EV_TX_RDS_GRP_COMPL:
case HCI_EV_TX_RDS_CONT_GRP_COMPL:
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 9bb2d89..5499754 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -408,6 +408,15 @@
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
+/* FM RDS */
+#define RDS_PTYPE 0
+#define RDS_PID_LOWER 2
+#define RDS_PID_HIGHER 3
+#define RDS_OFFSET 5
+#define RDS_PS_LENGTH_OFFSET 7
+#define RDS_STRING 8
+#define RDS_PS_DATA_OFFSET 8
+
/*FM states*/
enum radio_state_t {