---
 drivers/cbus/Kconfig      |    8 +++
 drivers/cbus/retu-user.c  |  117 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/cbus/tahvo-user.c |   75 +++++++++++++++++++++++++++++
 3 files changed, 198 insertions(+), 2 deletions(-)

--- linux-2.6.36-rc4.orig/drivers/cbus/Kconfig
+++ linux-2.6.36-rc4/drivers/cbus/Kconfig
@@ -28,6 +28,10 @@ config CBUS_TAHVO_USER
 	  If you want support for Tahvo's user space read/write etc. functions,
 	  you should say Y here.
 
+config CBUS_TAHVO_USER_DEBUG
+	depends on CBUS_TAHVO_USER
+	bool "Enable Tahvo user space interface debugging"
+
 config CBUS_TAHVO_USB
 	depends on CBUS_TAHVO && USB
 	tristate "Support for Tahvo USB transceiver"
@@ -56,6 +60,10 @@ config CBUS_RETU_USER
 	  If you want support for Retu's user space read/write etc. functions,
 	  you should say Y here.
 
+config CBUS_RETU_USER_DEBUG
+	depends on CBUS_RETU_USER
+	bool "Enable Retu user space interface debugging"
+
 config CBUS_RETU_POWERBUTTON
 	depends on CBUS_RETU
 	bool "Support for Retu power button"
--- linux-2.6.36-rc4.orig/drivers/cbus/retu-user.c
+++ linux-2.6.36-rc4/drivers/cbus/retu-user.c
@@ -46,6 +46,12 @@
 
 #define PFX			"retu-user: "
 
+#ifdef CONFIG_CBUS_RETU_USER_DEBUG
+# define dprintk(fmt, x...)	printk(KERN_DEBUG PFX fmt, x)
+#else
+# define dprintk(fmt, x...)	do { } while (0)
+#endif
+
 /* Bitmap for marking the interrupt sources as having the handlers */
 static u32 retu_irq_bits;
 
@@ -105,6 +111,94 @@ static const u8 retu_access_bits[] = {
 	3
 };
 
+#ifdef CONFIG_CBUS_RETU_USER_DEBUG
+static const char * reg_access_text(unsigned int reg)
+{
+	if (WARN_ON(reg >= ARRAY_SIZE(retu_access_bits)))
+		return "X";
+	switch (retu_access_bits[reg]) {
+	case READ_ONLY:
+		return "R";
+	case WRITE_ONLY:
+		return "W";
+	case READ_WRITE:
+		return "RW";
+	case TOGGLE:
+		return "T";
+	}
+	return "X";
+}
+
+static const char * reg_name(unsigned int reg)
+{
+	static const char *names[] = {
+		[RETU_REG_ASICR]	= "ASIC ID & revision",
+		[RETU_REG_IDR]		= "Interrupt ID",
+		[RETU_REG_IMR]		= "Interrupt mask",
+		[RETU_REG_RTCDSR]	= "RTC seconds register",
+		[RETU_REG_RTCHMR]	= "RTC hours and minutes register",
+		[RETU_REG_RTCHMAR]	= "hours and minutes alarm and time set register",
+		[RETU_REG_RTCCALR]	= "RTC calibration register",
+		[RETU_REG_ADCR]		= "ADC result",
+		[RETU_REG_ADCSCR]	= "ADC sample ctrl",
+		[RETU_REG_CC1]		= "Common control register 1",
+		[RETU_REG_CC2]		= "Common control register 2",
+		[RETU_REG_CTRL_CLR]	= "Regulator clear register",
+		[RETU_REG_CTRL_SET]	= "Regulator set register",
+		[RETU_REG_STATUS]	= "Status register",
+		[RETU_REG_WATCHDOG]	= "Watchdog register",
+		[RETU_REG_AUDTXR]	= "Audio Codec Tx register",
+		[0x14]			= "Charger detect?",
+	};
+	const char *name;
+
+	if (reg >= ARRAY_SIZE(names))
+		return "";
+	name = names[reg];
+	if (!name)
+		return "";
+	return name;
+}
+
+static const char * adc_chan_name(unsigned int chan)
+{
+	static const char *names[] = {
+		[0x05]		= "Headset hook detect",
+	};
+	const char *name;
+
+	if (chan >= ARRAY_SIZE(names))
+		return "";
+	name = names[chan];
+	if (!name)
+		return "";
+	return name;
+}
+
+static const char * retu_irq_name(unsigned int id)
+{
+	static const char *names[] = {
+		[RETU_INT_PWR]		= "Power",
+		[RETU_INT_CHAR]		= "Char",
+		[RETU_INT_RTCS]		= "RTCS",
+		[RETU_INT_RTCM]		= "RTCM",
+		[RETU_INT_RTCD]		= "RTCD",
+		[RETU_INT_RTCA]		= "RTCA",
+		[RETU_INT_HOOK]		= "Hook",
+		[RETU_INT_HEAD]		= "Head",
+		[RETU_INT_ADCS]		= "ADC timer",
+	};
+	const char *name;
+
+	if (id >= ARRAY_SIZE(names))
+		return "";
+	name = names[id];
+	if (!name)
+		return "";
+	return name;
+}
+#endif
+
 /*
  * The handler for all RETU interrupts.
  *
@@ -157,6 +251,8 @@ static int retu_user_subscribe_to_irq(in
 	/* Mark that this interrupt has a handler */
 	retu_irq_bits |= 1 << id;
 
+	dprintk("Subscribed to IRQ %d (%s)\n", id, retu_irq_name(id));
+
 	return 0;
 }
 
@@ -216,6 +312,10 @@ static int retu_user_write_with_mask(u32
 
 	/* Generate new value */
 	tmp = (tmp & ~MASK(field)) | (value & MASK(field));
+
+	dprintk("{WRITE %s} 0x%02X(%s) <= msk 0x%04X, val 0x%04X ==> res 0x%04X\n",
+		reg_name(reg), reg, reg_access_text(reg), MASK(field), value, tmp);
+
 	/* Write data to RETU */
 	retu_write_reg(reg, tmp);
 	spin_unlock_irqrestore(&retu_lock, flags);
@@ -244,6 +344,9 @@ static u32 retu_user_read_with_mask(u32
 	/* Read the register */
 	value = retu_read_reg(reg) & mask;
 
+	dprintk("{READ %s} 0x%02X(%s) <= msk 0x%04X ==> res 0x%04X\n",
+		reg_name(reg), reg, reg_access_text(reg), mask, value);
+
 	/* Right justify value */
 	while (!(mask & 1)) {
 		value = value >> 1;
@@ -273,7 +376,7 @@ static int retu_close(struct inode *inod
 static long retu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct retu_tahvo_write_parms par;
-	int ret;
+	int ret, result;
 
 	switch (cmd) {
 	case URT_IOCT_IRQ_SUBSCR:
@@ -290,7 +393,15 @@ static long retu_ioctl(struct file *filp
 			printk(KERN_ERR "copy_to_user failed: %d\n", ret);
 		break;
 	case RETU_IOCH_ADC_READ:
-		return retu_read_adc(arg);
+		result = retu_read_adc(arg);
+		if (result >= 0) {
+			dprintk("{READ-ADC %s} chan 0x%02lX ==> result 0x%04X\n",
+				adc_chan_name(arg), arg, result);
+		} else {
+			dprintk("{READ-ADC %s} chan 0x%02lX ==> failed %d\n",
+				adc_chan_name(arg), arg, result);
+		}
+		return result;
 	default:
 		return -ENOIOCTLCMD;
 	}
@@ -332,6 +443,8 @@ static ssize_t retu_read(struct file *fi
 		list_move(&irq->node, &retu_irqs_reserve);
 		spin_unlock_irqrestore(&retu_irqs_lock, flags);
 
+		dprintk("{IRQ %s} %d delivered\n", retu_irq_name(irq_id), (int)irq_id);
+
 		ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
 				   sizeof(irq_id));
 		if (ret)
--- linux-2.6.36-rc4.orig/drivers/cbus/tahvo-user.c
+++ linux-2.6.36-rc4/drivers/cbus/tahvo-user.c
@@ -46,6 +46,12 @@
 
 #define PFX			"tahvo-user: "
 
+#ifdef CONFIG_CBUS_TAHVO_USER_DEBUG
+# define dprintk(fmt, x...)	printk(KERN_DEBUG PFX fmt, x)
+#else
+# define dprintk(fmt, x...)	do { } while (0)
+#endif
+
 /* Bitmap for marking the interrupt sources as having the handlers */
 static u32 tahvo_irq_bits;
 
@@ -87,6 +93,64 @@ static const u8 tahvo_access_bits[] = {
 	1
 };
 
+#ifdef CONFIG_CBUS_TAHVO_USER_DEBUG
+static const char * reg_access_text(unsigned int reg)
+{
+	if (WARN_ON(reg >= ARRAY_SIZE(tahvo_access_bits)))
+		return "X";
+	switch (tahvo_access_bits[reg]) {
+	case READ_ONLY:
+		return "R";
+	case WRITE_ONLY:
+		return "W";
+	case READ_WRITE:
+		return "RW";
+	case TOGGLE:
+		return "T";
+	}
+	return "X";
+}
+
+static const char * reg_name(unsigned int reg)
+{
+	static const char *names[] = {
+		[TAHVO_REG_ASICR]	= "ASIC ID & revision",
+		[TAHVO_REG_IDR]		= "Interrupt ID",
+		[TAHVO_REG_IDSR]	= "Interrupt status",
+		[TAHVO_REG_IMR]		= "Interrupt mask",
+		[TAHVO_REG_LEDPWMR]	= "LED PWM",
+		[TAHVO_REG_USBR]	= "USB control",
+		[0x04]			= "Charge current control?",
+		[0x08]			= "Charge ctl 1?",
+		[0x0C]			= "Charge ctl 2?",
+		[0x0D]			= "Battery current ADC?",
+	};
+	const char *name;
+
+	if (reg >= ARRAY_SIZE(names))
+		return "";
+	name = names[reg];
+	if (!name)
+		return "";
+	return name;
+}
+
+static const char * tahvo_irq_name(unsigned int id)
+{
+	static const char *names[] = {
+		[TAHVO_INT_VBUSON]	= "VBUSON",
+	};
+	const char *name;
+
+	if (id >= ARRAY_SIZE(names))
+		return "";
+	name = names[id];
+	if (!name)
+		return "";
+	return name;
+}
+#endif
+
 /*
  * The handler for all TAHVO interrupts.
  *
@@ -142,6 +206,8 @@ static int tahvo_user_subscribe_to_irq(i
 	/* Mark that this interrupt has a handler */
 	tahvo_irq_bits |= 1 << id;
 
+	dprintk("Subscribed to IRQ %d (%s)\n", id, tahvo_irq_name(id));
+
 	return 0;
 }
 
@@ -200,6 +266,10 @@ static int tahvo_user_write_with_mask(u3
 	}
 	/* Generate a new value */
 	tmp = (tmp & ~MASK(field)) | (value & MASK(field));
+
+	dprintk("{WRITE %s} 0x%02X(%s) <= msk 0x%04X, val 0x%04X ==> res 0x%04X\n",
+		reg_name(reg), reg, reg_access_text(reg), MASK(field), value, tmp);
+
 	/* Write data to TAHVO */
 	tahvo_write_reg(reg, tmp);
 	spin_unlock_irqrestore(&tahvo_lock, flags);
@@ -228,6 +298,9 @@ static u32 tahvo_user_read_with_mask(u32
 	/* Read the register */
 	value = tahvo_read_reg(reg) & mask;
 
+	dprintk("{READ %s} 0x%02X(%s) <= msk 0x%04X ==> res 0x%04X\n",
+		reg_name(reg), reg, reg_access_text(reg), mask, value);
+
 	/* Right justify value */
 	while (!(mask & 1)) {
 		value = value >> 1;
@@ -314,6 +387,8 @@ static ssize_t tahvo_read(struct file *f
 		list_move(&irq->node, &tahvo_irqs_reserve);
 		spin_unlock_irqrestore(&tahvo_irqs_lock, flags);
 
+		dprintk("{IRQ %s} %d delivered\n", tahvo_irq_name(irq_id), (int)irq_id);
+
 		ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
                                   sizeof(irq_id));
 		if (ret)
