From 9a5a262324ab55758ae0e55482563e97cbcbffab Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 14 Jul 2013 11:30:31 +0000
Subject: [PATCH] broadcom-diag: make it work with kernel 3.10

In kernel 3.10 the proc interface changed, this patch adds the changes needed for the new interface.

SVN-Revision: 37280
---
 package/kernel/broadcom-diag/src/diag.c | 240 ++++++++++++------------
 1 file changed, 121 insertions(+), 119 deletions(-)

diff --git a/package/kernel/broadcom-diag/src/diag.c b/package/kernel/broadcom-diag/src/diag.c
index ace44cce55..c87ca97458 100644
--- a/package/kernel/broadcom-diag/src/diag.c
+++ b/package/kernel/broadcom-diag/src/diag.c
@@ -45,9 +45,6 @@ static unsigned int gpiomask = 0;
 module_param(gpiomask, int, 0644);
 
 extern char *nvram_get(char *str);
-
-static void register_leds(struct led_t *l);
-static void unregister_leds(struct led_t *l);
 static void led_flash(unsigned long dummy);
 
 static struct platform_t platform;
@@ -56,8 +53,20 @@ static struct timer_list led_timer = TIMER_INITIALIZER(&led_flash, 0, 0);
 
 static struct proc_dir_entry *diag, *leds;
 
-static struct prochandler_t proc_model = { .type = PROC_MODEL };
-static struct prochandler_t proc_gpiomask = { .type = PROC_GPIOMASK };
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
+static inline struct inode *file_inode(struct file *f)
+{
+	return f->f_path.dentry->d_inode;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+static inline void *PDE_DATA(const struct inode *inode)
+{
+	return PDE(inode)->data;
+}
+#endif
+
 
 enum {
 	/* Linksys */
@@ -1586,122 +1595,65 @@ static void led_flash(unsigned long dummy) {
 	}
 }
 
-static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+static int diag_led_show(struct seq_file *m, void *v)
 {
-	struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
-	char *page;
-	int len = 0;
-
-	if ((page = kmalloc(1024, GFP_KERNEL)) == NULL)
-		return -ENOBUFS;
-
-	if (dent->data != NULL) {
-		struct prochandler_t *handler = (struct prochandler_t *) dent->data;
-		switch (handler->type) {
-			case PROC_LED: {
-				struct led_t * led = (struct led_t *) handler->ptr;
-				u8 p = (led->polarity == NORMAL ? 0 : 1);
-				if (led->flash) {
-					len = sprintf(page, "f\n");
-				} else if ((led->gpio & GPIO_TYPE_MASK) != GPIO_TYPE_NORMAL) {
-					len = sprintf(page, "%d\n", ((led->state ^ p) ? 1 : 0));
-				} else {
-					u32 in = (bcm47xx_gpio_in(~0) & led->gpio ? 1 : 0);
-					len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0));
-				}
-				break;
-			}
-			case PROC_MODEL:
-				len = sprintf(page, "%s\n", platform.name);
-				break;
-			case PROC_GPIOMASK:
-				len = sprintf(page, "0x%04x\n", gpiomask);
-				break;
-		}
-	}
-	len += 1;
+	struct led_t * led = m->private;
 
-	if (*ppos < len) {
-		len = min_t(int, len - *ppos, count);
-		if (copy_to_user(buf, (page + *ppos), len)) {
-			kfree(page);
-			return -EFAULT;
-		}
-		*ppos += len;
+	u8 p = (led->polarity == NORMAL ? 0 : 1);
+	if (led->flash) {
+		return seq_printf(m, "f\n");
+	} else if ((led->gpio & GPIO_TYPE_MASK) != GPIO_TYPE_NORMAL) {
+		return seq_printf(m, "%d\n", ((led->state ^ p) ? 1 : 0));
 	} else {
-		len = 0;
+		u32 in = (bcm47xx_gpio_in(~0) & led->gpio ? 1 : 0);
+		return seq_printf(m, "%d\n", ((in ^ p) ? 1 : 0));
 	}
-
-	kfree(page);
-	return len;
 }
 
+static int diag_led_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, diag_led_show, PDE_DATA(inode));
+}
 
-static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static ssize_t diag_led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
-	struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
-	char *page;
-	int ret = -EINVAL;
+	struct led_t *led = PDE_DATA(file_inode(file));
+	char cmd[5];
+	size_t len;
+	int p;
 
-	if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL)
-		return -ENOBUFS;
+	len = min(count, sizeof(cmd) - 1);
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
 
-	if (copy_from_user(page, buf, count)) {
-		kfree(page);
-		return -EINVAL;
-	}
-	page[count] = 0;
-
-	if (dent->data != NULL) {
-		struct prochandler_t *handler = (struct prochandler_t *) dent->data;
-		switch (handler->type) {
-			case PROC_LED: {
-				struct led_t *led = (struct led_t *) handler->ptr;
-				int p = (led->polarity == NORMAL ? 0 : 1);
-
-				if (page[0] == 'f') {
-					led->flash = 1;
-					led_flash(0);
-				} else {
-					led->flash = 0;
-					if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_EXTIF) {
-						led->state = p ^ ((page[0] == '1') ? 1 : 0);
-						set_led_extif(led);
-					} else if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_SHIFT) {
-						led->state = p ^ ((page[0] == '1') ? 1 : 0);
-						set_led_shift(led);
-					} else {
-						bcm47xx_gpio_outen(led->gpio, led->gpio);
-						bcm47xx_gpio_control(led->gpio, 0);
-						bcm47xx_gpio_out(led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0));
-					}
-				}
-				break;
-			}
-			case PROC_GPIOMASK:
-				gpiomask = simple_strtoul(page, NULL, 0);
-
-				if (platform.buttons) {
-					unregister_buttons(platform.buttons);
-					register_buttons(platform.buttons);
-				}
-
-				if (platform.leds) {
-					unregister_leds(platform.leds);
-					register_leds(platform.leds);
-				}
-				break;
+	cmd[len] = 0;
+
+	p = (led->polarity == NORMAL ? 0 : 1);
+	if (cmd[0] == 'f') {
+		led->flash = 1;
+		led_flash(0);
+	} else {
+		led->flash = 0;
+		if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_EXTIF) {
+			led->state = p ^ ((cmd[0] == '1') ? 1 : 0);
+			set_led_extif(led);
+		} else if ((led->gpio & GPIO_TYPE_MASK) == GPIO_TYPE_SHIFT) {
+			led->state = p ^ ((cmd[0] == '1') ? 1 : 0);
+			set_led_shift(led);
+		} else {
+			bcm47xx_gpio_outen(led->gpio, led->gpio);
+			bcm47xx_gpio_control(led->gpio, 0);
+			bcm47xx_gpio_out(led->gpio, ((p ^ (cmd[0] == '1')) ? led->gpio : 0));
 		}
-		ret = count;
 	}
-
-	kfree(page);
-	return ret;
+	return count;
 }
 
-static struct file_operations diag_proc_fops = {
-	read: diag_proc_read,
-	write: diag_proc_write
+static const struct file_operations diag_led_fops = {
+	.open = diag_led_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = diag_led_write
 };
 
 static void register_leds(struct led_t *l)
@@ -1740,12 +1692,7 @@ static void register_leds(struct led_t *l)
 
 		if (l->polarity == INPUT) continue;
 
-		if ((p = create_proc_entry(l->name, S_IRUSR, leds))) {
-			l->proc.type = PROC_LED;
-			l->proc.ptr = l;
-			p->data = (void *) &l->proc;
-			p->proc_fops = &diag_proc_fops;
-		}
+		p = proc_create_data(l->name, S_IRUSR, leds, &diag_led_fops, l);
 	}
 
 	bcm47xx_gpio_outen(mask, oe_mask);
@@ -1762,6 +1709,58 @@ static void unregister_leds(struct led_t *l)
 	remove_proc_entry("led", diag);
 }
 
+static int diag_model_show(struct seq_file *m, void *v)
+{
+	return seq_printf(m, "%s\n", platform.name);
+}
+
+static int diag_model_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, diag_model_show, PDE_DATA(inode));
+}
+
+static const struct file_operations diag_model_fops = {
+	.open = diag_model_open,
+	.read = seq_read,
+	.llseek = seq_lseek
+};
+
+static int diag_gpiomask_show(struct seq_file *m, void *v)
+{
+	return seq_printf(m, "0x%04x\n", gpiomask);
+}
+
+static int diag_gpiomask_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, diag_gpiomask_show, PDE_DATA(inode));
+}
+
+static ssize_t diag_gpiomask_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	int err = kstrtouint_from_user(buf, count, 0, &gpiomask);
+	if (err)
+		return err;
+
+	if (platform.buttons) {
+		unregister_buttons(platform.buttons);
+		register_buttons(platform.buttons);
+	}
+
+	if (platform.leds) {
+		unregister_leds(platform.leds);
+		register_leds(platform.leds);
+	}
+
+	return count;
+}
+
+static const struct file_operations diag_gpiomask_fops = {
+	.open = diag_gpiomask_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = diag_gpiomask_write
+};
+
 static int __init diag_init(void)
 {
 	static struct proc_dir_entry *p;
@@ -1784,14 +1783,17 @@ static int __init diag_init(void)
 		return -EINVAL;
 	}
 
-	if ((p = create_proc_entry("model", S_IRUSR, diag))) {
-		p->data = (void *) &proc_model;
-		p->proc_fops = &diag_proc_fops;
+	p = proc_create("model", S_IRUSR, diag, &diag_model_fops);
+	if (!p) {
+		remove_proc_entry("diag", NULL);
+		return -EINVAL;
 	}
 
-	if ((p = create_proc_entry("gpiomask", S_IRUSR | S_IWUSR, diag))) {
-		p->data = (void *) &proc_gpiomask;
-		p->proc_fops = &diag_proc_fops;
+	p = proc_create("gpiomask", S_IRUSR | S_IWUSR, diag, &diag_gpiomask_fops);
+	if (!p) {
+		remove_proc_entry("model", diag);
+		remove_proc_entry("diag", NULL);
+		return -EINVAL;
 	}
 
 	if (platform.buttons)
-- 
2.30.2