1fd4a641aSUwe Kleine-König // SPDX-License-Identifier: GPL-2.0
2fd4a641aSUwe Kleine-König
376675f69SFlorian Eckert #include <linux/completion.h>
4fd4a641aSUwe Kleine-König #include <linux/delay.h>
5fd4a641aSUwe Kleine-König #include <linux/leds.h>
6fd4a641aSUwe Kleine-König #include <linux/module.h>
7fd4a641aSUwe Kleine-König #include <linux/slab.h>
8fd4a641aSUwe Kleine-König #include <linux/tty.h>
9fd4a641aSUwe Kleine-König #include <uapi/linux/serial.h>
10fd4a641aSUwe Kleine-König
1173009457SMarek Behún #define LEDTRIG_TTY_INTERVAL 50
1273009457SMarek Behún
13fd4a641aSUwe Kleine-König struct ledtrig_tty_data {
14fd4a641aSUwe Kleine-König struct led_classdev *led_cdev;
15fd4a641aSUwe Kleine-König struct delayed_work dwork;
1676675f69SFlorian Eckert struct completion sysfs;
17fd4a641aSUwe Kleine-König const char *ttyname;
18fd4a641aSUwe Kleine-König struct tty_struct *tty;
19fd4a641aSUwe Kleine-König int rx, tx;
205b755ca6SFlorian Eckert bool mode_rx;
215b755ca6SFlorian Eckert bool mode_tx;
22*6dec6598SFlorian Eckert bool mode_cts;
23*6dec6598SFlorian Eckert bool mode_dsr;
24*6dec6598SFlorian Eckert bool mode_dcd;
25*6dec6598SFlorian Eckert bool mode_rng;
265b755ca6SFlorian Eckert };
275b755ca6SFlorian Eckert
285b755ca6SFlorian Eckert /* Indicates which state the LED should now display */
295b755ca6SFlorian Eckert enum led_trigger_tty_state {
305b755ca6SFlorian Eckert TTY_LED_BLINK,
31*6dec6598SFlorian Eckert TTY_LED_ENABLE,
325b755ca6SFlorian Eckert TTY_LED_DISABLE,
335b755ca6SFlorian Eckert };
345b755ca6SFlorian Eckert
355b755ca6SFlorian Eckert enum led_trigger_tty_modes {
365b755ca6SFlorian Eckert TRIGGER_TTY_RX = 0,
375b755ca6SFlorian Eckert TRIGGER_TTY_TX,
38*6dec6598SFlorian Eckert TRIGGER_TTY_CTS,
39*6dec6598SFlorian Eckert TRIGGER_TTY_DSR,
40*6dec6598SFlorian Eckert TRIGGER_TTY_DCD,
41*6dec6598SFlorian Eckert TRIGGER_TTY_RNG,
42fd4a641aSUwe Kleine-König };
43fd4a641aSUwe Kleine-König
ledtrig_tty_wait_for_completion(struct device * dev)4476675f69SFlorian Eckert static int ledtrig_tty_wait_for_completion(struct device *dev)
45fd4a641aSUwe Kleine-König {
4676675f69SFlorian Eckert struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
4776675f69SFlorian Eckert int ret;
4876675f69SFlorian Eckert
4976675f69SFlorian Eckert ret = wait_for_completion_timeout(&trigger_data->sysfs,
5076675f69SFlorian Eckert msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 20));
5176675f69SFlorian Eckert if (ret == 0)
5276675f69SFlorian Eckert return -ETIMEDOUT;
5376675f69SFlorian Eckert
5476675f69SFlorian Eckert return ret;
55fd4a641aSUwe Kleine-König }
56fd4a641aSUwe Kleine-König
ttyname_show(struct device * dev,struct device_attribute * attr,char * buf)57fd4a641aSUwe Kleine-König static ssize_t ttyname_show(struct device *dev,
58fd4a641aSUwe Kleine-König struct device_attribute *attr, char *buf)
59fd4a641aSUwe Kleine-König {
60fd4a641aSUwe Kleine-König struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
61fd4a641aSUwe Kleine-König ssize_t len = 0;
6276675f69SFlorian Eckert int completion;
63fd4a641aSUwe Kleine-König
6476675f69SFlorian Eckert reinit_completion(&trigger_data->sysfs);
6576675f69SFlorian Eckert completion = ledtrig_tty_wait_for_completion(dev);
6676675f69SFlorian Eckert if (completion < 0)
6776675f69SFlorian Eckert return completion;
68fd4a641aSUwe Kleine-König
69fd4a641aSUwe Kleine-König if (trigger_data->ttyname)
70fd4a641aSUwe Kleine-König len = sprintf(buf, "%s\n", trigger_data->ttyname);
71fd4a641aSUwe Kleine-König
72fd4a641aSUwe Kleine-König return len;
73fd4a641aSUwe Kleine-König }
74fd4a641aSUwe Kleine-König
ttyname_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)75fd4a641aSUwe Kleine-König static ssize_t ttyname_store(struct device *dev,
76fd4a641aSUwe Kleine-König struct device_attribute *attr, const char *buf,
77fd4a641aSUwe Kleine-König size_t size)
78fd4a641aSUwe Kleine-König {
79fd4a641aSUwe Kleine-König struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
80fd4a641aSUwe Kleine-König char *ttyname;
81fd4a641aSUwe Kleine-König ssize_t ret = size;
8276675f69SFlorian Eckert int completion;
83fd4a641aSUwe Kleine-König
84fd4a641aSUwe Kleine-König if (size > 0 && buf[size - 1] == '\n')
85fd4a641aSUwe Kleine-König size -= 1;
86fd4a641aSUwe Kleine-König
87fd4a641aSUwe Kleine-König if (size) {
88fd4a641aSUwe Kleine-König ttyname = kmemdup_nul(buf, size, GFP_KERNEL);
891487e7baSUwe Kleine-König if (!ttyname)
901487e7baSUwe Kleine-König return -ENOMEM;
91fd4a641aSUwe Kleine-König } else {
92fd4a641aSUwe Kleine-König ttyname = NULL;
93fd4a641aSUwe Kleine-König }
94fd4a641aSUwe Kleine-König
9576675f69SFlorian Eckert reinit_completion(&trigger_data->sysfs);
9676675f69SFlorian Eckert completion = ledtrig_tty_wait_for_completion(dev);
9776675f69SFlorian Eckert if (completion < 0)
9876675f69SFlorian Eckert return completion;
99fd4a641aSUwe Kleine-König
100fd4a641aSUwe Kleine-König kfree(trigger_data->ttyname);
101fd4a641aSUwe Kleine-König tty_kref_put(trigger_data->tty);
102fd4a641aSUwe Kleine-König trigger_data->tty = NULL;
103fd4a641aSUwe Kleine-König
104fd4a641aSUwe Kleine-König trigger_data->ttyname = ttyname;
105fd4a641aSUwe Kleine-König
106fd4a641aSUwe Kleine-König return ret;
107fd4a641aSUwe Kleine-König }
108fd4a641aSUwe Kleine-König static DEVICE_ATTR_RW(ttyname);
109fd4a641aSUwe Kleine-König
ledtrig_tty_attr_show(struct device * dev,char * buf,enum led_trigger_tty_modes attr)1105b755ca6SFlorian Eckert static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf,
1115b755ca6SFlorian Eckert enum led_trigger_tty_modes attr)
1125b755ca6SFlorian Eckert {
1135b755ca6SFlorian Eckert struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
1145b755ca6SFlorian Eckert bool state;
1155b755ca6SFlorian Eckert
1165b755ca6SFlorian Eckert switch (attr) {
1175b755ca6SFlorian Eckert case TRIGGER_TTY_RX:
1185b755ca6SFlorian Eckert state = trigger_data->mode_rx;
1195b755ca6SFlorian Eckert break;
1205b755ca6SFlorian Eckert case TRIGGER_TTY_TX:
1215b755ca6SFlorian Eckert state = trigger_data->mode_tx;
1225b755ca6SFlorian Eckert break;
123*6dec6598SFlorian Eckert case TRIGGER_TTY_CTS:
124*6dec6598SFlorian Eckert state = trigger_data->mode_cts;
125*6dec6598SFlorian Eckert break;
126*6dec6598SFlorian Eckert case TRIGGER_TTY_DSR:
127*6dec6598SFlorian Eckert state = trigger_data->mode_dsr;
128*6dec6598SFlorian Eckert break;
129*6dec6598SFlorian Eckert case TRIGGER_TTY_DCD:
130*6dec6598SFlorian Eckert state = trigger_data->mode_dcd;
131*6dec6598SFlorian Eckert break;
132*6dec6598SFlorian Eckert case TRIGGER_TTY_RNG:
133*6dec6598SFlorian Eckert state = trigger_data->mode_rng;
134*6dec6598SFlorian Eckert break;
1355b755ca6SFlorian Eckert }
1365b755ca6SFlorian Eckert
1375b755ca6SFlorian Eckert return sysfs_emit(buf, "%u\n", state);
1385b755ca6SFlorian Eckert }
1395b755ca6SFlorian Eckert
ledtrig_tty_attr_store(struct device * dev,const char * buf,size_t size,enum led_trigger_tty_modes attr)1405b755ca6SFlorian Eckert static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf,
1415b755ca6SFlorian Eckert size_t size, enum led_trigger_tty_modes attr)
1425b755ca6SFlorian Eckert {
1435b755ca6SFlorian Eckert struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
1445b755ca6SFlorian Eckert bool state;
1455b755ca6SFlorian Eckert int ret;
1465b755ca6SFlorian Eckert
1475b755ca6SFlorian Eckert ret = kstrtobool(buf, &state);
1485b755ca6SFlorian Eckert if (ret)
1495b755ca6SFlorian Eckert return ret;
1505b755ca6SFlorian Eckert
1515b755ca6SFlorian Eckert switch (attr) {
1525b755ca6SFlorian Eckert case TRIGGER_TTY_RX:
1535b755ca6SFlorian Eckert trigger_data->mode_rx = state;
1545b755ca6SFlorian Eckert break;
1555b755ca6SFlorian Eckert case TRIGGER_TTY_TX:
1565b755ca6SFlorian Eckert trigger_data->mode_tx = state;
1575b755ca6SFlorian Eckert break;
158*6dec6598SFlorian Eckert case TRIGGER_TTY_CTS:
159*6dec6598SFlorian Eckert trigger_data->mode_cts = state;
160*6dec6598SFlorian Eckert break;
161*6dec6598SFlorian Eckert case TRIGGER_TTY_DSR:
162*6dec6598SFlorian Eckert trigger_data->mode_dsr = state;
163*6dec6598SFlorian Eckert break;
164*6dec6598SFlorian Eckert case TRIGGER_TTY_DCD:
165*6dec6598SFlorian Eckert trigger_data->mode_dcd = state;
166*6dec6598SFlorian Eckert break;
167*6dec6598SFlorian Eckert case TRIGGER_TTY_RNG:
168*6dec6598SFlorian Eckert trigger_data->mode_rng = state;
169*6dec6598SFlorian Eckert break;
1705b755ca6SFlorian Eckert }
1715b755ca6SFlorian Eckert
1725b755ca6SFlorian Eckert return size;
1735b755ca6SFlorian Eckert }
1745b755ca6SFlorian Eckert
1755b755ca6SFlorian Eckert #define DEFINE_TTY_TRIGGER(trigger_name, trigger) \
1765b755ca6SFlorian Eckert static ssize_t trigger_name##_show(struct device *dev, \
1775b755ca6SFlorian Eckert struct device_attribute *attr, char *buf) \
1785b755ca6SFlorian Eckert { \
1795b755ca6SFlorian Eckert return ledtrig_tty_attr_show(dev, buf, trigger); \
1805b755ca6SFlorian Eckert } \
1815b755ca6SFlorian Eckert static ssize_t trigger_name##_store(struct device *dev, \
1825b755ca6SFlorian Eckert struct device_attribute *attr, const char *buf, size_t size) \
1835b755ca6SFlorian Eckert { \
1845b755ca6SFlorian Eckert return ledtrig_tty_attr_store(dev, buf, size, trigger); \
1855b755ca6SFlorian Eckert } \
1865b755ca6SFlorian Eckert static DEVICE_ATTR_RW(trigger_name)
1875b755ca6SFlorian Eckert
1885b755ca6SFlorian Eckert DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX);
1895b755ca6SFlorian Eckert DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX);
190*6dec6598SFlorian Eckert DEFINE_TTY_TRIGGER(cts, TRIGGER_TTY_CTS);
191*6dec6598SFlorian Eckert DEFINE_TTY_TRIGGER(dsr, TRIGGER_TTY_DSR);
192*6dec6598SFlorian Eckert DEFINE_TTY_TRIGGER(dcd, TRIGGER_TTY_DCD);
193*6dec6598SFlorian Eckert DEFINE_TTY_TRIGGER(rng, TRIGGER_TTY_RNG);
1945b755ca6SFlorian Eckert
ledtrig_tty_work(struct work_struct * work)195fd4a641aSUwe Kleine-König static void ledtrig_tty_work(struct work_struct *work)
196fd4a641aSUwe Kleine-König {
197fd4a641aSUwe Kleine-König struct ledtrig_tty_data *trigger_data =
198fd4a641aSUwe Kleine-König container_of(work, struct ledtrig_tty_data, dwork.work);
1995b755ca6SFlorian Eckert enum led_trigger_tty_state state = TTY_LED_DISABLE;
2005b755ca6SFlorian Eckert unsigned long interval = LEDTRIG_TTY_INTERVAL;
201*6dec6598SFlorian Eckert bool invert = false;
202*6dec6598SFlorian Eckert int status;
203fd4a641aSUwe Kleine-König int ret;
204fd4a641aSUwe Kleine-König
20576675f69SFlorian Eckert if (!trigger_data->ttyname)
20676675f69SFlorian Eckert goto out;
207fd4a641aSUwe Kleine-König
208fd4a641aSUwe Kleine-König /* try to get the tty corresponding to $ttyname */
209fd4a641aSUwe Kleine-König if (!trigger_data->tty) {
210fd4a641aSUwe Kleine-König dev_t devno;
211fd4a641aSUwe Kleine-König struct tty_struct *tty;
212fd4a641aSUwe Kleine-König int ret;
213fd4a641aSUwe Kleine-König
214fd4a641aSUwe Kleine-König ret = tty_dev_name_to_number(trigger_data->ttyname, &devno);
215fd4a641aSUwe Kleine-König if (ret < 0)
216fd4a641aSUwe Kleine-König /*
217fd4a641aSUwe Kleine-König * A device with this name might appear later, so keep
218fd4a641aSUwe Kleine-König * retrying.
219fd4a641aSUwe Kleine-König */
220fd4a641aSUwe Kleine-König goto out;
221fd4a641aSUwe Kleine-König
222fd4a641aSUwe Kleine-König tty = tty_kopen_shared(devno);
223fd4a641aSUwe Kleine-König if (IS_ERR(tty) || !tty)
224fd4a641aSUwe Kleine-König /* What to do? retry or abort */
225fd4a641aSUwe Kleine-König goto out;
226fd4a641aSUwe Kleine-König
227fd4a641aSUwe Kleine-König trigger_data->tty = tty;
228fd4a641aSUwe Kleine-König }
229fd4a641aSUwe Kleine-König
230*6dec6598SFlorian Eckert status = tty_get_tiocm(trigger_data->tty);
231*6dec6598SFlorian Eckert if (status > 0) {
232*6dec6598SFlorian Eckert if (trigger_data->mode_cts) {
233*6dec6598SFlorian Eckert if (status & TIOCM_CTS)
234*6dec6598SFlorian Eckert state = TTY_LED_ENABLE;
235*6dec6598SFlorian Eckert }
236*6dec6598SFlorian Eckert
237*6dec6598SFlorian Eckert if (trigger_data->mode_dsr) {
238*6dec6598SFlorian Eckert if (status & TIOCM_DSR)
239*6dec6598SFlorian Eckert state = TTY_LED_ENABLE;
240*6dec6598SFlorian Eckert }
241*6dec6598SFlorian Eckert
242*6dec6598SFlorian Eckert if (trigger_data->mode_dcd) {
243*6dec6598SFlorian Eckert if (status & TIOCM_CAR)
244*6dec6598SFlorian Eckert state = TTY_LED_ENABLE;
245*6dec6598SFlorian Eckert }
246*6dec6598SFlorian Eckert
247*6dec6598SFlorian Eckert if (trigger_data->mode_rng) {
248*6dec6598SFlorian Eckert if (status & TIOCM_RNG)
249*6dec6598SFlorian Eckert state = TTY_LED_ENABLE;
250*6dec6598SFlorian Eckert }
251*6dec6598SFlorian Eckert }
252*6dec6598SFlorian Eckert
253*6dec6598SFlorian Eckert /*
254*6dec6598SFlorian Eckert * The evaluation of rx/tx must be done after the evaluation
255*6dec6598SFlorian Eckert * of TIOCM_*, because rx/tx has priority.
256*6dec6598SFlorian Eckert */
2575b755ca6SFlorian Eckert if (trigger_data->mode_rx || trigger_data->mode_tx) {
2585b755ca6SFlorian Eckert struct serial_icounter_struct icount;
2595b755ca6SFlorian Eckert
260fd4a641aSUwe Kleine-König ret = tty_get_icount(trigger_data->tty, &icount);
26176675f69SFlorian Eckert if (ret)
26276675f69SFlorian Eckert goto out;
263fd4a641aSUwe Kleine-König
2645b755ca6SFlorian Eckert if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) {
265fd4a641aSUwe Kleine-König trigger_data->tx = icount.tx;
266*6dec6598SFlorian Eckert invert = state == TTY_LED_ENABLE;
2675b755ca6SFlorian Eckert state = TTY_LED_BLINK;
2685b755ca6SFlorian Eckert }
2695b755ca6SFlorian Eckert
2705b755ca6SFlorian Eckert if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) {
2715b755ca6SFlorian Eckert trigger_data->rx = icount.rx;
272*6dec6598SFlorian Eckert invert = state == TTY_LED_ENABLE;
2735b755ca6SFlorian Eckert state = TTY_LED_BLINK;
2745b755ca6SFlorian Eckert }
275fd4a641aSUwe Kleine-König }
276fd4a641aSUwe Kleine-König
277fd4a641aSUwe Kleine-König out:
2785b755ca6SFlorian Eckert switch (state) {
2795b755ca6SFlorian Eckert case TTY_LED_BLINK:
2805b755ca6SFlorian Eckert led_blink_set_oneshot(trigger_data->led_cdev, &interval,
281*6dec6598SFlorian Eckert &interval, invert);
282*6dec6598SFlorian Eckert break;
283*6dec6598SFlorian Eckert case TTY_LED_ENABLE:
284*6dec6598SFlorian Eckert led_set_brightness(trigger_data->led_cdev,
285*6dec6598SFlorian Eckert trigger_data->led_cdev->blink_brightness);
2865b755ca6SFlorian Eckert break;
2875b755ca6SFlorian Eckert case TTY_LED_DISABLE:
2885b755ca6SFlorian Eckert fallthrough;
2895b755ca6SFlorian Eckert default:
2905b755ca6SFlorian Eckert led_set_brightness(trigger_data->led_cdev, LED_OFF);
2915b755ca6SFlorian Eckert break;
2925b755ca6SFlorian Eckert }
2935b755ca6SFlorian Eckert
29476675f69SFlorian Eckert complete_all(&trigger_data->sysfs);
29573009457SMarek Behún schedule_delayed_work(&trigger_data->dwork,
29673009457SMarek Behún msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2));
297fd4a641aSUwe Kleine-König }
298fd4a641aSUwe Kleine-König
299fd4a641aSUwe Kleine-König static struct attribute *ledtrig_tty_attrs[] = {
300fd4a641aSUwe Kleine-König &dev_attr_ttyname.attr,
3015b755ca6SFlorian Eckert &dev_attr_rx.attr,
3025b755ca6SFlorian Eckert &dev_attr_tx.attr,
303*6dec6598SFlorian Eckert &dev_attr_cts.attr,
304*6dec6598SFlorian Eckert &dev_attr_dsr.attr,
305*6dec6598SFlorian Eckert &dev_attr_dcd.attr,
306*6dec6598SFlorian Eckert &dev_attr_rng.attr,
307fd4a641aSUwe Kleine-König NULL
308fd4a641aSUwe Kleine-König };
309fd4a641aSUwe Kleine-König ATTRIBUTE_GROUPS(ledtrig_tty);
310fd4a641aSUwe Kleine-König
ledtrig_tty_activate(struct led_classdev * led_cdev)311fd4a641aSUwe Kleine-König static int ledtrig_tty_activate(struct led_classdev *led_cdev)
312fd4a641aSUwe Kleine-König {
313fd4a641aSUwe Kleine-König struct ledtrig_tty_data *trigger_data;
314fd4a641aSUwe Kleine-König
315fd4a641aSUwe Kleine-König trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
316fd4a641aSUwe Kleine-König if (!trigger_data)
317fd4a641aSUwe Kleine-König return -ENOMEM;
318fd4a641aSUwe Kleine-König
3195b755ca6SFlorian Eckert /* Enable default rx/tx mode */
3205b755ca6SFlorian Eckert trigger_data->mode_rx = true;
3215b755ca6SFlorian Eckert trigger_data->mode_tx = true;
3225b755ca6SFlorian Eckert
323fd4a641aSUwe Kleine-König led_set_trigger_data(led_cdev, trigger_data);
324fd4a641aSUwe Kleine-König
325fd4a641aSUwe Kleine-König INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work);
326fd4a641aSUwe Kleine-König trigger_data->led_cdev = led_cdev;
32776675f69SFlorian Eckert init_completion(&trigger_data->sysfs);
32876675f69SFlorian Eckert
32976675f69SFlorian Eckert schedule_delayed_work(&trigger_data->dwork, 0);
330fd4a641aSUwe Kleine-König
331fd4a641aSUwe Kleine-König return 0;
332fd4a641aSUwe Kleine-König }
333fd4a641aSUwe Kleine-König
ledtrig_tty_deactivate(struct led_classdev * led_cdev)334fd4a641aSUwe Kleine-König static void ledtrig_tty_deactivate(struct led_classdev *led_cdev)
335fd4a641aSUwe Kleine-König {
336fd4a641aSUwe Kleine-König struct ledtrig_tty_data *trigger_data = led_get_trigger_data(led_cdev);
337fd4a641aSUwe Kleine-König
338fd4a641aSUwe Kleine-König cancel_delayed_work_sync(&trigger_data->dwork);
339fd4a641aSUwe Kleine-König
34025054b23SFlorian Eckert kfree(trigger_data->ttyname);
34125054b23SFlorian Eckert tty_kref_put(trigger_data->tty);
34225054b23SFlorian Eckert trigger_data->tty = NULL;
34325054b23SFlorian Eckert
344fd4a641aSUwe Kleine-König kfree(trigger_data);
345fd4a641aSUwe Kleine-König }
346fd4a641aSUwe Kleine-König
347fd4a641aSUwe Kleine-König static struct led_trigger ledtrig_tty = {
348fd4a641aSUwe Kleine-König .name = "tty",
349fd4a641aSUwe Kleine-König .activate = ledtrig_tty_activate,
350fd4a641aSUwe Kleine-König .deactivate = ledtrig_tty_deactivate,
351fd4a641aSUwe Kleine-König .groups = ledtrig_tty_groups,
352fd4a641aSUwe Kleine-König };
353fd4a641aSUwe Kleine-König module_led_trigger(ledtrig_tty);
354fd4a641aSUwe Kleine-König
355fd4a641aSUwe Kleine-König MODULE_AUTHOR("Uwe Kleine-König <u.kleine-koenig@pengutronix.de>");
356fd4a641aSUwe Kleine-König MODULE_DESCRIPTION("UART LED trigger");
357fd4a641aSUwe Kleine-König MODULE_LICENSE("GPL v2");
358