mirror of https://github.com/hak5/openwrt.git
325 lines
8.6 KiB
Diff
325 lines
8.6 KiB
Diff
---
|
|
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)
|