24b267a5be5caa5afd097498bbe409e358bf27c9
[compat-rdma/compat.git] / compat / compat-2.6.37.c
1 /*
2  * Copyright 2010    Hauke Mehrtens <hauke@hauke-m.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Compatibility file for Linux wireless for kernels 2.6.37.
9  */
10
11 #include <linux/compat.h>
12 #include <linux/netdevice.h>
13 #include <net/sock.h>
14 #include <linux/nsproxy.h>
15 #include <linux/vmalloc.h>
16
17 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
18 static const void *net_current_ns(void)
19 {
20         return current->nsproxy->net_ns;
21 }
22
23 static const void *net_initial_ns(void)
24 {
25         return &init_net;
26 }
27
28 static const void *net_netlink_ns(struct sock *sk)
29 {
30         return sock_net(sk);
31 }
32
33 struct kobj_ns_type_operations net_ns_type_operations = {
34         .type = KOBJ_NS_TYPE_NET,
35         .current_ns = net_current_ns,
36         .netlink_ns = net_netlink_ns,
37         .initial_ns = net_initial_ns,
38 };
39 EXPORT_SYMBOL_GPL(net_ns_type_operations);
40
41 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)*/ 
42
43 #undef genl_info
44 #undef genl_unregister_family
45
46 static LIST_HEAD(compat_nl_fam);
47
48 static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
49 {
50         struct genl_ops *ops;
51
52         list_for_each_entry(ops, &family->family.ops_list, ops.ops_list)
53                 if (ops->cmd == cmd)
54                         return ops;
55
56         return NULL;
57 }
58
59
60 static int nl_doit_wrapper(struct sk_buff *skb, struct genl_info *info)
61 {
62         struct compat_genl_info compat_info;
63         struct genl_family *family;
64         struct genl_ops *ops;
65         int err;
66
67         list_for_each_entry(family, &compat_nl_fam, list) {
68                 if (family->id == info->nlhdr->nlmsg_type)
69                         goto found;
70         }
71         return -ENOENT;
72
73 found:
74         ops = genl_get_cmd(info->genlhdr->cmd, family);
75         if (!ops)
76                 return -ENOENT;
77
78         memset(&compat_info.user_ptr, 0, sizeof(compat_info.user_ptr));
79         compat_info.info = info;
80 #define __copy(_field) compat_info._field = info->_field
81         __copy(snd_seq);
82         __copy(snd_pid);
83         __copy(genlhdr);
84         __copy(attrs);
85 #undef __copy
86         if (family->pre_doit) {
87                 err = family->pre_doit(ops, skb, &compat_info);
88                 if (err)
89                         return err;
90         }
91
92         err = ops->doit(skb, &compat_info);
93
94         if (family->post_doit)
95                 family->post_doit(ops, skb, &compat_info);
96
97         return err;
98 }
99
100 int compat_genl_register_family_with_ops(struct genl_family *family,
101                                          struct genl_ops *ops, size_t n_ops)
102 {
103         int i, ret;
104
105 #define __copy(_field) family->family._field = family->_field
106         __copy(id);
107         __copy(hdrsize);
108         __copy(version);
109         __copy(maxattr);
110         strncpy(family->family.name, family->name, sizeof(family->family.name));
111 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
112         __copy(netnsok);
113 #endif
114 #undef __copy
115
116         ret = genl_register_family(&family->family);
117         if (ret < 0)
118                 return ret;
119
120         family->attrbuf = family->family.attrbuf;
121         family->id = family->family.id;
122
123         for (i = 0; i < n_ops; i++) {
124 #define __copy(_field) ops[i].ops._field = ops[i]._field
125                 __copy(cmd);
126                 __copy(flags);
127                 __copy(policy);
128                 __copy(dumpit);
129                 __copy(done);
130 #undef __copy
131                 if (ops[i].doit)
132                         ops[i].ops.doit = nl_doit_wrapper;
133                 ret = genl_register_ops(&family->family, &ops[i].ops);
134                 if (ret < 0)
135                         goto error_ops;
136         }
137         list_add(&family->list, &compat_nl_fam);
138
139         return ret;
140
141 error_ops:
142         compat_genl_unregister_family(family);
143         return ret;
144 }
145 EXPORT_SYMBOL_GPL(compat_genl_register_family_with_ops);
146
147 int compat_genl_unregister_family(struct genl_family *family)
148 {
149         int err;
150         err = genl_unregister_family(&family->family);
151         list_del(&family->list);
152         return err;
153 }
154 EXPORT_SYMBOL_GPL(compat_genl_unregister_family);
155
156 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
157
158 #undef led_brightness_set
159 #undef led_classdev_unregister
160
161 static DEFINE_SPINLOCK(led_lock);
162 static LIST_HEAD(led_timers);
163
164 struct led_timer {
165         struct list_head list;
166         struct led_classdev *cdev;
167         struct timer_list blink_timer;
168         unsigned long blink_delay_on;
169         unsigned long blink_delay_off;
170         int blink_brightness;
171 };
172
173 static void led_brightness_set(struct led_classdev *led_cdev,
174                                enum led_brightness brightness)
175 {
176         led_cdev->brightness = brightness;
177         led_cdev->brightness_set(led_cdev, brightness);
178 }
179
180 static struct led_timer *led_get_timer(struct led_classdev *led_cdev)
181 {
182         struct led_timer *p;
183         unsigned long flags;
184
185         spin_lock_irqsave(&led_lock, flags);
186         list_for_each_entry(p, &led_timers, list) {
187                 if (p->cdev == led_cdev)
188                         goto found;
189         }
190         p = NULL;
191 found:
192         spin_unlock_irqrestore(&led_lock, flags);
193         return p;
194 }
195
196 static void led_stop_software_blink(struct led_timer *led)
197 {
198         del_timer_sync(&led->blink_timer);
199         led->blink_delay_on = 0;
200         led->blink_delay_off = 0;
201 }
202
203 static void led_timer_function(unsigned long data)
204 {
205         struct led_timer *led = (struct led_timer *)data;
206         unsigned long brightness;
207         unsigned long delay;
208
209         if (!led->blink_delay_on || !led->blink_delay_off) {
210                 led->cdev->brightness_set(led->cdev, LED_OFF);
211                 return;
212         }
213
214         brightness = led->cdev->brightness;
215         if (!brightness) {
216                 /* Time to switch the LED on. */
217                 brightness = led->blink_brightness;
218                 delay = led->blink_delay_on;
219         } else {
220                 /* Store the current brightness value to be able
221                  * to restore it when the delay_off period is over.
222                  */
223                 led->blink_brightness = brightness;
224                 brightness = LED_OFF;
225                 delay = led->blink_delay_off;
226         }
227
228         led_brightness_set(led->cdev, brightness);
229         mod_timer(&led->blink_timer, jiffies + msecs_to_jiffies(delay));
230 }
231
232 static struct led_timer *led_new_timer(struct led_classdev *led_cdev)
233 {
234         struct led_timer *led;
235         unsigned long flags;
236
237         led = kzalloc(sizeof(struct led_timer), GFP_ATOMIC);
238         if (!led)
239                 return NULL;
240
241         led->cdev = led_cdev;
242         init_timer(&led->blink_timer);
243         led->blink_timer.function = led_timer_function;
244         led->blink_timer.data = (unsigned long) led;
245
246         spin_lock_irqsave(&led_lock, flags);
247         list_add(&led->list, &led_timers);
248         spin_unlock_irqrestore(&led_lock, flags);
249
250         return led;
251 }
252
253 void led_blink_set(struct led_classdev *led_cdev,
254                    unsigned long *delay_on,
255                    unsigned long *delay_off)
256 {
257         struct led_timer *led;
258         int current_brightness;
259
260 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
261         if (led_cdev->blink_set &&
262             !led_cdev->blink_set(led_cdev, delay_on, delay_off))
263                 return;
264 #endif
265
266         led = led_get_timer(led_cdev);
267         if (!led) {
268                 led = led_new_timer(led_cdev);
269                 if (!led)
270                         return;
271         }
272
273         /* blink with 1 Hz as default if nothing specified */
274         if (!*delay_on && !*delay_off)
275                 *delay_on = *delay_off = 500;
276
277         if (led->blink_delay_on == *delay_on &&
278             led->blink_delay_off == *delay_off)
279                 return;
280
281         current_brightness = led_cdev->brightness;
282         if (current_brightness)
283                 led->blink_brightness = current_brightness;
284         if (!led->blink_brightness)
285 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
286                 led->blink_brightness = led_cdev->max_brightness;
287 #else
288                 led->blink_brightness = LED_FULL;
289 #endif
290
291         led_stop_software_blink(led);
292         led->blink_delay_on = *delay_on;
293         led->blink_delay_off = *delay_off;
294
295         /* never on - don't blink */
296         if (!*delay_on)
297                 return;
298
299         /* never off - just set to brightness */
300         if (!*delay_off) {
301                 led_brightness_set(led_cdev, led->blink_brightness);
302                 return;
303         }
304
305         mod_timer(&led->blink_timer, jiffies + 1);
306 }
307 EXPORT_SYMBOL_GPL(led_blink_set);
308
309 void compat_led_brightness_set(struct led_classdev *led_cdev,
310                                enum led_brightness brightness)
311 {
312         struct led_timer *led = led_get_timer(led_cdev);
313
314         if (led)
315                 led_stop_software_blink(led);
316
317         return led_cdev->brightness_set(led_cdev, brightness);
318 }
319 EXPORT_SYMBOL_GPL(compat_led_brightness_set);
320
321 void compat_led_classdev_unregister(struct led_classdev *led_cdev)
322 {
323         struct led_timer *led = led_get_timer(led_cdev);
324         unsigned long flags;
325
326         if (led) {
327                 del_timer_sync(&led->blink_timer);
328                 spin_lock_irqsave(&led_lock, flags);
329                 list_del(&led->list);
330                 spin_unlock_irqrestore(&led_lock, flags);
331                 kfree(led);
332         }
333
334         led_classdev_unregister(led_cdev);
335 }
336 EXPORT_SYMBOL_GPL(compat_led_classdev_unregister);
337
338 /**
339  *      vzalloc - allocate virtually contiguous memory with zero fill
340  *      @size:  allocation size
341  *      Allocate enough pages to cover @size from the page level
342  *      allocator and map them into contiguous kernel virtual space.
343  *      The memory allocated is set to zero.
344  *
345  *      For tight control over page level allocator and protection flags
346  *      use __vmalloc() instead.
347  */
348 void *compat_vzalloc(unsigned long size)
349 {
350         void *buf;
351         buf = vmalloc(size);
352         if (buf)
353                 memset(buf, 0, size);
354         return buf;
355 }
356 EXPORT_SYMBOL_GPL(compat_vzalloc);
357
358 #endif