|
|
|
@ -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) |
|
|
|
|