1
1
// SPDX-License-Identifier: GPL-2.0
2
2
3
+ #include <linux/completion.h>
3
4
#include <linux/delay.h>
4
5
#include <linux/leds.h>
5
6
#include <linux/module.h>
12
13
struct ledtrig_tty_data {
13
14
struct led_classdev * led_cdev ;
14
15
struct delayed_work dwork ;
15
- struct mutex mutex ;
16
+ struct completion sysfs ;
16
17
const char * ttyname ;
17
18
struct tty_struct * tty ;
18
19
int rx , tx ;
19
20
};
20
21
21
- static void ledtrig_tty_restart (struct ledtrig_tty_data * trigger_data )
22
+ static int ledtrig_tty_wait_for_completion (struct device * dev )
22
23
{
23
- schedule_delayed_work (& trigger_data -> dwork , 0 );
24
+ struct ledtrig_tty_data * trigger_data = led_trigger_get_drvdata (dev );
25
+ int ret ;
26
+
27
+ ret = wait_for_completion_timeout (& trigger_data -> sysfs ,
28
+ msecs_to_jiffies (LEDTRIG_TTY_INTERVAL * 20 ));
29
+ if (ret == 0 )
30
+ return - ETIMEDOUT ;
31
+
32
+ return ret ;
24
33
}
25
34
26
35
static ssize_t ttyname_show (struct device * dev ,
27
36
struct device_attribute * attr , char * buf )
28
37
{
29
38
struct ledtrig_tty_data * trigger_data = led_trigger_get_drvdata (dev );
30
39
ssize_t len = 0 ;
40
+ int completion ;
31
41
32
- mutex_lock (& trigger_data -> mutex );
42
+ reinit_completion (& trigger_data -> sysfs );
43
+ completion = ledtrig_tty_wait_for_completion (dev );
44
+ if (completion < 0 )
45
+ return completion ;
33
46
34
47
if (trigger_data -> ttyname )
35
48
len = sprintf (buf , "%s\n" , trigger_data -> ttyname );
36
49
37
- mutex_unlock (& trigger_data -> mutex );
38
-
39
50
return len ;
40
51
}
41
52
@@ -46,7 +57,7 @@ static ssize_t ttyname_store(struct device *dev,
46
57
struct ledtrig_tty_data * trigger_data = led_trigger_get_drvdata (dev );
47
58
char * ttyname ;
48
59
ssize_t ret = size ;
49
- bool running ;
60
+ int completion ;
50
61
51
62
if (size > 0 && buf [size - 1 ] == '\n' )
52
63
size -= 1 ;
@@ -59,21 +70,17 @@ static ssize_t ttyname_store(struct device *dev,
59
70
ttyname = NULL ;
60
71
}
61
72
62
- mutex_lock (& trigger_data -> mutex );
63
-
64
- running = trigger_data -> ttyname != NULL ;
73
+ reinit_completion (& trigger_data -> sysfs );
74
+ completion = ledtrig_tty_wait_for_completion (dev );
75
+ if (completion < 0 )
76
+ return completion ;
65
77
66
78
kfree (trigger_data -> ttyname );
67
79
tty_kref_put (trigger_data -> tty );
68
80
trigger_data -> tty = NULL ;
69
81
70
82
trigger_data -> ttyname = ttyname ;
71
83
72
- mutex_unlock (& trigger_data -> mutex );
73
-
74
- if (ttyname && !running )
75
- ledtrig_tty_restart (trigger_data );
76
-
77
84
return ret ;
78
85
}
79
86
static DEVICE_ATTR_RW (ttyname );
@@ -85,13 +92,8 @@ static void ledtrig_tty_work(struct work_struct *work)
85
92
struct serial_icounter_struct icount ;
86
93
int ret ;
87
94
88
- mutex_lock (& trigger_data -> mutex );
89
-
90
- if (!trigger_data -> ttyname ) {
91
- /* exit without rescheduling */
92
- mutex_unlock (& trigger_data -> mutex );
93
- return ;
94
- }
95
+ if (!trigger_data -> ttyname )
96
+ goto out ;
95
97
96
98
/* try to get the tty corresponding to $ttyname */
97
99
if (!trigger_data -> tty ) {
@@ -116,11 +118,8 @@ static void ledtrig_tty_work(struct work_struct *work)
116
118
}
117
119
118
120
ret = tty_get_icount (trigger_data -> tty , & icount );
119
- if (ret ) {
120
- dev_info (trigger_data -> tty -> dev , "Failed to get icount, stopped polling\n" );
121
- mutex_unlock (& trigger_data -> mutex );
122
- return ;
123
- }
121
+ if (ret )
122
+ goto out ;
124
123
125
124
if (icount .rx != trigger_data -> rx ||
126
125
icount .tx != trigger_data -> tx ) {
@@ -134,7 +133,7 @@ static void ledtrig_tty_work(struct work_struct *work)
134
133
}
135
134
136
135
out :
137
- mutex_unlock (& trigger_data -> mutex );
136
+ complete_all (& trigger_data -> sysfs );
138
137
schedule_delayed_work (& trigger_data -> dwork ,
139
138
msecs_to_jiffies (LEDTRIG_TTY_INTERVAL * 2 ));
140
139
}
@@ -157,7 +156,9 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev)
157
156
158
157
INIT_DELAYED_WORK (& trigger_data -> dwork , ledtrig_tty_work );
159
158
trigger_data -> led_cdev = led_cdev ;
160
- mutex_init (& trigger_data -> mutex );
159
+ init_completion (& trigger_data -> sysfs );
160
+
161
+ schedule_delayed_work (& trigger_data -> dwork , 0 );
161
162
162
163
return 0 ;
163
164
}
0 commit comments