diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/rfkill/rfkill.c | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 3edc585dcfa6..4ae4486c77ea 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -62,19 +62,39 @@ static void rfkill_led_trigger(struct rfkill *rfkill, | |||
62 | #endif /* CONFIG_RFKILL_LEDS */ | 62 | #endif /* CONFIG_RFKILL_LEDS */ |
63 | } | 63 | } |
64 | 64 | ||
65 | static void update_rfkill_state(struct rfkill *rfkill) | ||
66 | { | ||
67 | enum rfkill_state newstate; | ||
68 | |||
69 | if (rfkill->get_state) { | ||
70 | mutex_lock(&rfkill->mutex); | ||
71 | if (!rfkill->get_state(rfkill->data, &newstate)) | ||
72 | rfkill->state = newstate; | ||
73 | mutex_unlock(&rfkill->mutex); | ||
74 | } | ||
75 | } | ||
76 | |||
65 | static int rfkill_toggle_radio(struct rfkill *rfkill, | 77 | static int rfkill_toggle_radio(struct rfkill *rfkill, |
66 | enum rfkill_state state) | 78 | enum rfkill_state state) |
67 | { | 79 | { |
68 | int retval = 0; | 80 | int retval = 0; |
81 | enum rfkill_state oldstate, newstate; | ||
82 | |||
83 | oldstate = rfkill->state; | ||
84 | |||
85 | if (rfkill->get_state && | ||
86 | !rfkill->get_state(rfkill->data, &newstate)) | ||
87 | rfkill->state = newstate; | ||
69 | 88 | ||
70 | if (state != rfkill->state) { | 89 | if (state != rfkill->state) { |
71 | retval = rfkill->toggle_radio(rfkill->data, state); | 90 | retval = rfkill->toggle_radio(rfkill->data, state); |
72 | if (!retval) { | 91 | if (!retval) |
73 | rfkill->state = state; | 92 | rfkill->state = state; |
74 | rfkill_led_trigger(rfkill, state); | ||
75 | } | ||
76 | } | 93 | } |
77 | 94 | ||
95 | if (rfkill->state != oldstate) | ||
96 | rfkill_led_trigger(rfkill, rfkill->state); | ||
97 | |||
78 | return retval; | 98 | return retval; |
79 | } | 99 | } |
80 | 100 | ||
@@ -105,6 +125,32 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
105 | } | 125 | } |
106 | EXPORT_SYMBOL(rfkill_switch_all); | 126 | EXPORT_SYMBOL(rfkill_switch_all); |
107 | 127 | ||
128 | /** | ||
129 | * rfkill_force_state - Force the internal rfkill radio state | ||
130 | * @rfkill: pointer to the rfkill class to modify. | ||
131 | * @state: the current radio state the class should be forced to. | ||
132 | * | ||
133 | * This function updates the internal state of the radio cached | ||
134 | * by the rfkill class. It should be used when the driver gets | ||
135 | * a notification by the firmware/hardware of the current *real* | ||
136 | * state of the radio rfkill switch. | ||
137 | * | ||
138 | * It may not be called from an atomic context. | ||
139 | */ | ||
140 | int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) | ||
141 | { | ||
142 | if (state != RFKILL_STATE_OFF && | ||
143 | state != RFKILL_STATE_ON) | ||
144 | return -EINVAL; | ||
145 | |||
146 | mutex_lock(&rfkill->mutex); | ||
147 | rfkill->state = state; | ||
148 | mutex_unlock(&rfkill->mutex); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | EXPORT_SYMBOL(rfkill_force_state); | ||
153 | |||
108 | static ssize_t rfkill_name_show(struct device *dev, | 154 | static ssize_t rfkill_name_show(struct device *dev, |
109 | struct device_attribute *attr, | 155 | struct device_attribute *attr, |
110 | char *buf) | 156 | char *buf) |
@@ -147,6 +193,7 @@ static ssize_t rfkill_state_show(struct device *dev, | |||
147 | { | 193 | { |
148 | struct rfkill *rfkill = to_rfkill(dev); | 194 | struct rfkill *rfkill = to_rfkill(dev); |
149 | 195 | ||
196 | update_rfkill_state(rfkill); | ||
150 | return sprintf(buf, "%d\n", rfkill->state); | 197 | return sprintf(buf, "%d\n", rfkill->state); |
151 | } | 198 | } |
152 | 199 | ||