xref: /linux/drivers/leds/trigger/ledtrig-tty.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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