1/* 2 * LED ADM5120 Switch Port State Trigger 3 * 4 * Copyright (C) 2007 Bernhard Held <bernhard at bernhardheld.de> 5 * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> 6 * 7 * This file was based on: drivers/leds/ledtrig-timer.c 8 * Copyright 2005-2006 Openedhand Ltd. 9 * Author: Richard Purdie 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/init.h> 20#include <linux/device.h> 21 22#include <linux/gpio.h> 23 24#include "leds.h" 25 26#define DRV_NAME "port_state" 27#define DRV_DESC "LED ADM5120 Switch Port State Trigger" 28 29struct port_state { 30 char *name; 31 unsigned int value; 32}; 33 34#define PORT_STATE(n, v) {.name = (n), .value = (v)} 35 36static struct port_state port_states[] = { 37 PORT_STATE("off", LED_OFF), 38 PORT_STATE("on", LED_FULL), 39 PORT_STATE("flash", ADM5120_GPIO_FLASH), 40 PORT_STATE("link", ADM5120_GPIO_LINK), 41 PORT_STATE("speed", ADM5120_GPIO_SPEED), 42 PORT_STATE("duplex", ADM5120_GPIO_DUPLEX), 43 PORT_STATE("act", ADM5120_GPIO_ACT), 44 PORT_STATE("coll", ADM5120_GPIO_COLL), 45 PORT_STATE("link_act", ADM5120_GPIO_LINK_ACT), 46 PORT_STATE("duplex_coll", ADM5120_GPIO_DUPLEX_COLL), 47 PORT_STATE("10M_act", ADM5120_GPIO_10M_ACT), 48 PORT_STATE("100M_act", ADM5120_GPIO_100M_ACT), 49}; 50 51static ssize_t led_port_state_show(struct device *dev, 52 struct device_attribute *attr, char *buf) 53{ 54 struct led_classdev *led_cdev = dev_get_drvdata(dev); 55 struct port_state *state = led_cdev->trigger_data; 56 int len = 0; 57 int i; 58 59 *buf = '\0'; 60 for (i = 0; i < ARRAY_SIZE(port_states); i++) { 61 if (&port_states[i] == state) 62 len += sprintf(buf+len, "[%s] ", port_states[i].name); 63 else 64 len += sprintf(buf+len, "%s ", port_states[i].name); 65 } 66 len += sprintf(buf+len, "\n"); 67 68 return len; 69} 70 71static ssize_t led_port_state_store(struct device *dev, 72 struct device_attribute *attr, const char *buf, size_t size) 73{ 74 struct led_classdev *led_cdev = dev_get_drvdata(dev); 75 size_t len; 76 int i; 77 78 for (i = 0; i < ARRAY_SIZE(port_states); i++) { 79 len = strlen(port_states[i].name); 80 if (strncmp(port_states[i].name, buf, len) != 0) 81 continue; 82 83 if (buf[len] != '\0' && buf[len] != '\n') 84 continue; 85 86 led_cdev->trigger_data = &port_states[i]; 87 led_set_brightness(led_cdev, port_states[i].value); 88 return size; 89 } 90 91 return -EINVAL; 92} 93 94static DEVICE_ATTR(port_state, 0644, led_port_state_show, 95 led_port_state_store); 96 97static void adm5120_switch_trig_activate(struct led_classdev *led_cdev) 98{ 99 struct port_state *state = port_states; 100 int rc; 101 102 led_cdev->trigger_data = state; 103 104 rc = device_create_file(led_cdev->dev, &dev_attr_port_state); 105 if (rc) 106 goto err; 107 108 led_set_brightness(led_cdev, state->value); 109 110 return; 111err: 112 led_cdev->trigger_data = NULL; 113} 114 115static void adm5120_switch_trig_deactivate(struct led_classdev *led_cdev) 116{ 117 struct port_state *state = led_cdev->trigger_data; 118 119 if (!state) 120 return; 121 122 device_remove_file(led_cdev->dev, &dev_attr_port_state); 123 124} 125 126static struct led_trigger adm5120_switch_led_trigger = { 127 .name = DRV_NAME, 128 .activate = adm5120_switch_trig_activate, 129 .deactivate = adm5120_switch_trig_deactivate, 130}; 131 132static int __init adm5120_switch_trig_init(void) 133{ 134 led_trigger_register(&adm5120_switch_led_trigger); 135 return 0; 136} 137 138static void __exit adm5120_switch_trig_exit(void) 139{ 140 led_trigger_unregister(&adm5120_switch_led_trigger); 141} 142 143module_init(adm5120_switch_trig_init); 144module_exit(adm5120_switch_trig_exit); 145 146MODULE_AUTHOR("Bernhard Held <bernhard at bernhardheld.de>, " 147 "Gabor Juhos <juhosg@openwrt.org>"); 148MODULE_DESCRIPTION(DRV_DESC); 149MODULE_LICENSE("GPL v2"); 150