diff options
-rw-r--r-- | include/linux/rfkill.h | 5 | ||||
-rw-r--r-- | net/rfkill/rfkill.c | 53 |
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); | |||
95 | int rfkill_register(struct rfkill *rfkill); | 98 | int rfkill_register(struct rfkill *rfkill); |
96 | void rfkill_unregister(struct rfkill *rfkill); | 99 | void rfkill_unregister(struct rfkill *rfkill); |
97 | 100 | ||
101 | int 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 | ||
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 | ||