aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rfkill.h5
-rw-r--r--net/rfkill/rfkill.c53
2 files changed, 55 insertions, 3 deletions
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index ca89ae1b0219..844e96114861 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -61,6 +61,8 @@ enum rfkill_state {
61 * @data: Pointer to the RF button drivers private data which will be 61 * @data: Pointer to the RF button drivers private data which will be
62 * passed along when toggling radio state. 62 * passed along when toggling radio state.
63 * @toggle_radio(): Mandatory handler to control state of the radio. 63 * @toggle_radio(): Mandatory handler to control state of the radio.
64 * @get_state(): handler to read current radio state from hardware,
65 * may be called from atomic context, should return 0 on success.
64 * @led_trigger: A LED trigger for this button's LED. 66 * @led_trigger: A LED trigger for this button's LED.
65 * @dev: Device structure integrating the switch into device tree. 67 * @dev: Device structure integrating the switch into device tree.
66 * @node: Used to place switch into list of all switches known to the 68 * @node: Used to place switch into list of all switches known to the
@@ -80,6 +82,7 @@ struct rfkill {
80 82
81 void *data; 83 void *data;
82 int (*toggle_radio)(void *data, enum rfkill_state state); 84 int (*toggle_radio)(void *data, enum rfkill_state state);
85 int (*get_state)(void *data, enum rfkill_state *state);
83 86
84#ifdef CONFIG_RFKILL_LEDS 87#ifdef CONFIG_RFKILL_LEDS
85 struct led_trigger led_trigger; 88 struct led_trigger led_trigger;
@@ -95,6 +98,8 @@ void rfkill_free(struct rfkill *rfkill);
95int rfkill_register(struct rfkill *rfkill); 98int rfkill_register(struct rfkill *rfkill);
96void rfkill_unregister(struct rfkill *rfkill); 99void rfkill_unregister(struct rfkill *rfkill);
97 100
101int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
102
98/** 103/**
99 * rfkill_get_led_name - Get the LED trigger name for the button's LED. 104 * rfkill_get_led_name - Get the LED trigger name for the button's LED.
100 * This function might return a NULL pointer if registering of the 105 * This function might return a NULL pointer if registering of the
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
65static 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
65static int rfkill_toggle_radio(struct rfkill *rfkill, 77static 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}
106EXPORT_SYMBOL(rfkill_switch_all); 126EXPORT_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 */
140int 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}
152EXPORT_SYMBOL(rfkill_force_state);
153
108static ssize_t rfkill_name_show(struct device *dev, 154static 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