summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-08-01 22:08:51 -0700
committerDavid S. Miller <davem@davemloft.net>2008-08-01 22:08:51 -0700
commite9e80ea5f2129e135e3a6fa260314b1c6d99b19a (patch)
treedb20dc85b0e620ea3fcaf86a9026d6df7cb2e168 /net
parent2b12a4c524812fb3f6ee590a02e65b95c8c32229 (diff)
parent56decd3c5758b0d776c073f65f777beb7a05ac0a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/tx.c17
-rw-r--r--net/mac80211/util.c1
-rw-r--r--net/rfkill/rfkill-input.c54
-rw-r--r--net/rfkill/rfkill.c15
5 files changed, 67 insertions, 21 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a4f9a832722..a2e200f9811 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -586,6 +586,7 @@ struct ieee80211_local {
struct timer_list sta_cleanup;
unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+ unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 69019e94387..771ec68b848 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1060,13 +1060,14 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_info *info;
int ret, i;
- if (netif_subqueue_stopped(local->mdev, skb))
- return IEEE80211_TX_AGAIN;
-
if (skb) {
+ if (netif_subqueue_stopped(local->mdev, skb))
+ return IEEE80211_TX_AGAIN;
+ info = IEEE80211_SKB_CB(skb);
+
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver", skb);
ret = local->ops->tx(local_to_hw(local), skb);
@@ -1215,6 +1216,7 @@ retry:
if (ret == IEEE80211_TX_FRAG_AGAIN)
skb = NULL;
+
set_bit(queue, local->queues_pending);
smp_mb();
/*
@@ -1708,14 +1710,19 @@ void ieee80211_tx_pending(unsigned long data)
netif_tx_lock_bh(dev);
for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
/* Check that this queue is ok */
- if (__netif_subqueue_stopped(local->mdev, i))
+ if (__netif_subqueue_stopped(local->mdev, i) &&
+ !test_bit(i, local->queues_pending_run))
continue;
if (!test_bit(i, local->queues_pending)) {
+ clear_bit(i, local->queues_pending_run);
ieee80211_wake_queue(&local->hw, i);
continue;
}
+ clear_bit(i, local->queues_pending_run);
+ netif_start_subqueue(local->mdev, i);
+
store = &local->pending_packet[i];
tx.extra_frag = store->extra_frag;
tx.num_extra_frag = store->num_extra_frag;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 19f85e1b369..0d463c80c40 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -361,6 +361,7 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
struct ieee80211_local *local = hw_to_local(hw);
if (test_bit(queue, local->queues_pending)) {
+ set_bit(queue, local->queues_pending_run);
tasklet_schedule(&local->tx_pending_tasklet);
} else {
netif_wake_subqueue(local->mdev, queue);
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 8aa82273014..e5b69556bb5 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -109,6 +109,25 @@ static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
+static void rfkill_schedule_evsw_rfkillall(int state)
+{
+ /* EVERY radio type. state != 0 means radios ON */
+ /* handle EPO (emergency power off) through shortcut */
+ if (state) {
+ rfkill_schedule_set(&rfkill_wwan,
+ RFKILL_STATE_UNBLOCKED);
+ rfkill_schedule_set(&rfkill_wimax,
+ RFKILL_STATE_UNBLOCKED);
+ rfkill_schedule_set(&rfkill_uwb,
+ RFKILL_STATE_UNBLOCKED);
+ rfkill_schedule_set(&rfkill_bt,
+ RFKILL_STATE_UNBLOCKED);
+ rfkill_schedule_set(&rfkill_wlan,
+ RFKILL_STATE_UNBLOCKED);
+ } else
+ rfkill_schedule_epo();
+}
+
static void rfkill_event(struct input_handle *handle, unsigned int type,
unsigned int code, int data)
{
@@ -132,21 +151,7 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
} else if (type == EV_SW) {
switch (code) {
case SW_RFKILL_ALL:
- /* EVERY radio type. data != 0 means radios ON */
- /* handle EPO (emergency power off) through shortcut */
- if (data) {
- rfkill_schedule_set(&rfkill_wwan,
- RFKILL_STATE_UNBLOCKED);
- rfkill_schedule_set(&rfkill_wimax,
- RFKILL_STATE_UNBLOCKED);
- rfkill_schedule_set(&rfkill_uwb,
- RFKILL_STATE_UNBLOCKED);
- rfkill_schedule_set(&rfkill_bt,
- RFKILL_STATE_UNBLOCKED);
- rfkill_schedule_set(&rfkill_wlan,
- RFKILL_STATE_UNBLOCKED);
- } else
- rfkill_schedule_epo();
+ rfkill_schedule_evsw_rfkillall(data);
break;
default:
break;
@@ -168,6 +173,7 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
handle->handler = handler;
handle->name = "rfkill";
+ /* causes rfkill_start() to be called */
error = input_register_handle(handle);
if (error)
goto err_free_handle;
@@ -185,6 +191,23 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
return error;
}
+static void rfkill_start(struct input_handle *handle)
+{
+ /* Take event_lock to guard against configuration changes, we
+ * should be able to deal with concurrency with rfkill_event()
+ * just fine (which event_lock will also avoid). */
+ spin_lock_irq(&handle->dev->event_lock);
+
+ if (test_bit(EV_SW, handle->dev->evbit)) {
+ if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
+ rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
+ handle->dev->sw));
+ /* add resync for further EV_SW events here */
+ }
+
+ spin_unlock_irq(&handle->dev->event_lock);
+}
+
static void rfkill_disconnect(struct input_handle *handle)
{
input_close_device(handle);
@@ -225,6 +248,7 @@ static struct input_handler rfkill_handler = {
.event = rfkill_event,
.connect = rfkill_connect,
.disconnect = rfkill_disconnect,
+ .start = rfkill_start,
.name = "rfkill",
.id_table = rfkill_ids,
};
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index c6f2f388cb7..d2d45655cd1 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -105,6 +105,16 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
#endif /* CONFIG_RFKILL_LEDS */
}
+#ifdef CONFIG_RFKILL_LEDS
+static void rfkill_led_trigger_activate(struct led_classdev *led)
+{
+ struct rfkill *rfkill = container_of(led->trigger,
+ struct rfkill, led_trigger);
+
+ rfkill_led_trigger(rfkill, rfkill->state);
+}
+#endif /* CONFIG_RFKILL_LEDS */
+
static void notify_rfkill_state_change(struct rfkill *rfkill)
{
blocking_notifier_call_chain(&rfkill_notifier_list,
@@ -589,7 +599,10 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill)
#ifdef CONFIG_RFKILL_LEDS
int error;
- rfkill->led_trigger.name = rfkill->dev.bus_id;
+ if (!rfkill->led_trigger.name)
+ rfkill->led_trigger.name = rfkill->dev.bus_id;
+ if (!rfkill->led_trigger.activate)
+ rfkill->led_trigger.activate = rfkill_led_trigger_activate;
error = led_trigger_register(&rfkill->led_trigger);
if (error)
rfkill->led_trigger.name = NULL;