]> err.no Git - linux-2.6/blob - net/ieee80211/softmac/ieee80211softmac_event.c
[PATCH] softmac: convert to use global workqueue
[linux-2.6] / net / ieee80211 / softmac / ieee80211softmac_event.c
1 #include "ieee80211softmac_priv.h"
2
3 /*
4  * Event system
5  * Also see comments in public header file
6  *
7  * Each event has associated to it
8  *  - an event type (see constants in public header)
9  *  - an event context (see below)
10  *  - the function to be called
11  *  - a context (extra parameter to call the function with)
12  *  - and the softmac struct
13  *
14  * The event context is private and can only be used from
15  * within this module. Its meaning varies with the event
16  * type:
17  *  SCAN_FINISHED:      no special meaning
18  *  ASSOCIATED,
19  *  ASSOCIATE_FAILED,
20  *  ASSOCIATE_TIMEOUT,
21  *  AUTHENTICATED,
22  *  AUTH_FAILED,
23  *  AUTH_TIMEOUT:       a pointer to the network struct
24  * ...
25  * Code within this module can use the event context to be only
26  * called when the event is true for that specific context
27  * as per above table.
28  * If the event context is NULL, then the notification is always called,
29  * regardless of the event context. The event context is not passed to
30  * the callback, it is assumed that the context suffices.
31  *
32  * You can also use the event context only by setting the event type
33  * to -1 (private use only), in which case you'll be notified
34  * whenever the event context matches.
35  */
36
37 static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
38         "scan finished",
39         "associated",
40         "associating failed",
41         "associating timed out",
42         "authenticated",
43         "authenticating failed",
44         "authenticating timed out",
45         "associating failed because no suitable network was found",
46 };
47
48
49 static void
50 ieee80211softmac_notify_callback(void *d)
51 {
52         struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
53         kfree(d);
54         
55         event.fun(event.mac->dev, event.context);
56 }
57
58 int
59 ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
60         int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
61 {
62         struct ieee80211softmac_event *eventptr;
63         unsigned long flags;
64
65         if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
66                 return -ENOSYS;
67         
68         if (!fun)
69                 return -EINVAL;
70         
71         eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
72         if (!eventptr)
73                 return -ENOMEM;
74         
75         eventptr->event_type = event;
76         INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
77         eventptr->fun = fun;
78         eventptr->context = context;
79         eventptr->mac = mac;
80         eventptr->event_context = event_context;
81
82         spin_lock_irqsave(&mac->lock, flags);
83         list_add(&eventptr->list, &mac->events);
84         spin_unlock_irqrestore(&mac->lock, flags);
85
86         return 0;
87 }
88
89 int
90 ieee80211softmac_notify_gfp(struct net_device *dev,
91         int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
92 {
93         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
94
95         if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
96                 return -ENOSYS;
97         
98         return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
99 }
100 EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
101
102 /* private -- calling all callbacks that were specified */
103 void
104 ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
105 {
106         struct ieee80211softmac_event *eventptr, *tmp;
107         union iwreq_data wrqu;
108         char *msg;
109         
110         if (event >= 0) {
111                 msg = event_descriptions[event];
112                 wrqu.data.length = strlen(msg);
113                 wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg);
114         }
115
116         if (!list_empty(&mac->events))
117                 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
118                         if ((eventptr->event_type == event || eventptr->event_type == -1)
119                                 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
120                                 list_del(&eventptr->list);
121                                 schedule_work(&eventptr->work);
122                         }
123                 }
124 }
125
126 void
127 ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
128 {
129         unsigned long flags;
130
131         spin_lock_irqsave(&mac->lock, flags);
132         ieee80211softmac_call_events_locked(mac, event, event_ctx);
133
134         spin_unlock_irqrestore(&mac->lock, flags);
135 }