--- ../linux-2.6.28/drivers/media/radio/radio-bcm2048.c	2010-02-18 00:59:33.000000000 +0100
+++ kernel-2.6.28/drivers/media/radio/radio-bcm2048.c	2010-05-24 22:59:54.000000000 +0200
@@ -6,6 +6,8 @@
  * Copyright (C) Nokia Corporation
  * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
  *
+ * Copyright (C) Nicole Faerber <nicole.faerber@dpin.de>
+ *
  * 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.
@@ -21,6 +23,16 @@
  * 02110-1301 USA
  */
 
+/*
+ * History:
+ *		Eero Nurkkala <ext-eero.nurkkala@nokia.com>
+ *		Version 0.0.1
+ *		- Initial implementation
+ * 2010-02-21	Nicole Faerber <nicole.faerber@dpin.de>
+ *		Version 0.0.2
+ *		- Add support for interrupt driven rds data reading
+ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -283,6 +295,12 @@
 	u8 fifo_size;
 	u8 scan_state;
 	u8 mute_state;
+
+	/* for rds data device read */
+	wait_queue_head_t read_queue;
+	unsigned int users;
+	unsigned char rds_data_available;
+	unsigned int rd_index;
 };
 
 static int radio_nr = -1;	/* radio device minor (-1 ==> auto assign) */
@@ -1756,6 +1774,8 @@
 	bcm2048_parse_rds_ps(bdev);
 
 	mutex_unlock(&bdev->mutex);
+
+	wake_up_interruptible(&bdev->read_queue);
 }
 
 static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data)
@@ -1869,6 +1889,11 @@
 
 	err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
 
+	init_waitqueue_head(&bdev->read_queue);
+	bdev->rds_data_available = 0;
+	bdev->rd_index = 0;
+	bdev->users = 0;
+
 unlock:
 	return err;
 }
@@ -1903,7 +1928,8 @@
 			bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
 						flags);
 		}
-
+		bdev->rds_data_available = 1;
+		bdev->rd_index = 0; /* new data, new start */
 	}
 }
 
@@ -2139,6 +2165,100 @@
 	return err;
 }
 
+
+static int bcm2048_fops_open(struct inode *inode, struct file *file)
+{
+	struct bcm2048_device *bdev = video_drvdata(file);
+
+	bdev->users++;
+	bdev->rd_index = 0;
+	bdev->rds_data_available = 0;
+
+return 0;
+}
+
+static int bcm2048_fops_release(struct inode *inode, struct file *file)
+{
+	struct bcm2048_device *bdev = video_drvdata(file);
+
+	bdev->users--;
+
+return 0;
+}
+
+static unsigned int bcm2048_fops_poll(struct file *file,
+		struct poll_table_struct *pts)
+{
+	struct bcm2048_device *bdev = video_drvdata(file);
+	int retval = 0;
+
+	poll_wait(file, &bdev->read_queue, pts);
+
+	if (bdev->rds_data_available) {
+		retval = POLLIN | POLLRDNORM;
+	}
+
+	return retval;
+}
+
+static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	struct bcm2048_device *bdev = video_drvdata(file);
+	int i;
+	int retval = 0;
+
+	/* we return at least 3 bytes, one block */
+	count = (count / 3) * 3; /* only multiples of 3 */
+	if (count < 3)
+		return -ENOBUFS;
+
+	while (!bdev->rds_data_available) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
+		//interruptible_sleep_on(&bdev->read_queue);
+		if (wait_event_interruptible(bdev->read_queue,
+			bdev->rds_data_available) < 0) {
+			retval = -EINTR;
+			goto done;
+		}
+	}
+
+	mutex_lock(&bdev->mutex);
+	/* copy data to userspace */
+	i = bdev->fifo_size - bdev->rd_index;
+	if (count > i)
+		count = (i / 3) * 3;
+
+	i = 0;
+	while (i < count) {
+		unsigned char tmpbuf[3];
+		tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index+i+2];
+		tmpbuf[i+1] = bdev->rds_info.radio_text[bdev->rd_index+i+1];
+		tmpbuf[i+2] = ((bdev->rds_info.radio_text[bdev->rd_index+i] & 0xf0) >> 4);
+		if  ((bdev->rds_info.radio_text[bdev->rd_index+i] & BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE)
+			tmpbuf[i+2] |= 0x80;
+		if (copy_to_user(buf+i, tmpbuf, 3)) {
+			retval = -EFAULT;
+			break;
+		};
+		i += 3;
+	}
+
+	bdev->rd_index += i;
+	if (bdev->rd_index >= bdev->fifo_size)
+		bdev->rds_data_available = 0;
+
+	mutex_unlock(&bdev->mutex);
+	if (retval == 0)
+		retval = i;
+
+done:
+	return retval;
+}
+
 /*
  *	bcm2048_fops - file operations interface
  */
@@ -2147,6 +2267,11 @@
 	.llseek		= no_llseek,
 	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
+	/* for RDS read support */
+	.open		= bcm2048_fops_open,
+	.release	= bcm2048_fops_release,
+	.read		= bcm2048_fops_read,
+	.poll		= bcm2048_fops_poll
 };
 
 /*
@@ -2609,4 +2734,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR(BCM2048_DRIVER_AUTHOR);
 MODULE_DESCRIPTION(BCM2048_DRIVER_DESC);
-MODULE_VERSION("0.0.1");
+MODULE_VERSION("0.0.2");
