Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / staging / ath6kl / os / linux / ar6000_android.c
1 //------------------------------------------------------------------------------
2 // Copyright (c) 2004-2010 Atheros Communications Inc.
3 // All rights reserved.
4 //
5 // 
6 //
7 // Permission to use, copy, modify, and/or distribute this software for any
8 // purpose with or without fee is hereby granted, provided that the above
9 // copyright notice and this permission notice appear in all copies.
10 //
11 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 //
19 //
20 //
21 // Author(s): ="Atheros"
22 //------------------------------------------------------------------------------
23 #include "ar6000_drv.h"
24 #include "htc.h"
25 #include <linux/vmalloc.h>
26 #include <linux/fs.h>
27
28 #ifdef CONFIG_HAS_WAKELOCK
29 #include <linux/wakelock.h>
30 #endif
31 #ifdef CONFIG_HAS_EARLYSUSPEND
32 #include <linux/earlysuspend.h>
33 #endif
34
35 A_BOOL enable_mmc_host_detect_change = 0;
36 static void ar6000_enable_mmchost_detect_change(int enable);
37
38
39 char fwpath[256] = "/system/wifi";
40 int wowledon;
41 unsigned int enablelogcat;
42
43 extern int bmienable;
44 extern struct net_device *ar6000_devices[];
45 extern char ifname[];
46
47 #ifdef CONFIG_HAS_WAKELOCK
48 extern struct wake_lock ar6k_wow_wake_lock;
49 struct wake_lock ar6k_init_wake_lock;
50 #endif
51
52 const char def_ifname[] = "wlan0";
53 module_param_string(fwpath, fwpath, sizeof(fwpath), 0644);
54 module_param(enablelogcat, uint, 0644);
55 module_param(wowledon, int, 0644);
56
57 #ifdef CONFIG_HAS_EARLYSUSPEND
58 static int screen_is_off;
59 static struct early_suspend ar6k_early_suspend;
60 #endif
61
62 static A_STATUS (*ar6000_avail_ev_p)(void *, void *);
63
64 #if defined(CONFIG_ANDROID_LOGGER) && (!defined(CONFIG_MMC_MSM))
65 int logger_write(const enum logidx index,
66                 const unsigned char prio,
67                 const char __kernel * const tag,
68                 const char __kernel * const fmt,
69                 ...)
70 {
71     int ret = 0;
72     va_list vargs;
73     struct file *filp = (struct file *)-ENOENT;
74     mm_segment_t oldfs;
75     struct iovec vec[3];
76     int tag_bytes = strlen(tag) + 1, msg_bytes;
77     char *msg;      
78     va_start(vargs, fmt);
79     msg = kvasprintf(GFP_ATOMIC, fmt, vargs);
80     va_end(vargs);
81     if (!msg)
82         return -ENOMEM;
83     if (in_interrupt()) {
84         /* we have no choice since aio_write may be blocked */
85         printk(KERN_ALERT "%s", msg);
86         goto out_free_message;
87     }
88     msg_bytes = strlen(msg) + 1;
89     if (msg_bytes <= 1) /* empty message? */
90         goto out_free_message; /* don't bother, then */
91     if ((msg_bytes + tag_bytes + 1) > 2048) {
92         ret = -E2BIG;
93         goto out_free_message;
94     }
95             
96     vec[0].iov_base  = (unsigned char *) &prio;
97     vec[0].iov_len    = 1;
98     vec[1].iov_base   = (void *) tag;
99     vec[1].iov_len    = strlen(tag) + 1;
100     vec[2].iov_base   = (void *) msg;
101     vec[2].iov_len    = strlen(msg) + 1; 
102
103     oldfs = get_fs();
104     set_fs(KERNEL_DS);
105     do {
106         filp = filp_open("/dev/log/main", O_WRONLY, S_IRUSR);
107         if (IS_ERR(filp) || !filp->f_op) {
108             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: filp_open /dev/log/main error\n", __FUNCTION__));
109             ret = -ENOENT;
110             break;
111         }
112
113         if (filp->f_op->aio_write) {
114             int nr_segs = sizeof(vec) / sizeof(vec[0]);
115             int len = vec[0].iov_len + vec[1].iov_len + vec[2].iov_len;
116             struct kiocb kiocb;
117             init_sync_kiocb(&kiocb, filp);
118             kiocb.ki_pos = 0;
119             kiocb.ki_left = len;
120             kiocb.ki_nbytes = len;
121             ret = filp->f_op->aio_write(&kiocb, vec, nr_segs, kiocb.ki_pos);
122         }
123         
124     } while (0);
125
126     if (!IS_ERR(filp)) {
127         filp_close(filp, NULL);
128     }
129     set_fs(oldfs);
130 out_free_message:
131     if (msg) {
132         kfree(msg);
133     }
134     return ret;
135 }
136 #endif
137
138 int android_logger_lv(void *module, int mask)
139 {
140     switch (mask) {
141     case ATH_DEBUG_ERR:
142         return 6;
143     case ATH_DEBUG_INFO:
144         return 4;
145     case ATH_DEBUG_WARN:
146         return 5; 
147     case ATH_DEBUG_TRC:        
148         return 3; 
149     default:
150 #ifdef DEBUG
151         if (!module) {
152             return 3;
153         } else if (module == &GET_ATH_MODULE_DEBUG_VAR_NAME(driver)) {
154             return (mask <=ATH_DEBUG_MAKE_MODULE_MASK(3)) ? 3 : 2;
155         } else if (module == &GET_ATH_MODULE_DEBUG_VAR_NAME(htc)) {
156             return 2;
157         } else {
158             return 3;
159         }
160 #else
161         return 3; /* DEBUG */
162 #endif
163     }
164 }
165
166 static int android_readwrite_file(const A_CHAR *filename, A_CHAR *rbuf, const A_CHAR *wbuf, size_t length)
167 {
168     int ret = 0;
169     struct file *filp = (struct file *)-ENOENT;
170     mm_segment_t oldfs;
171     oldfs = get_fs();
172     set_fs(KERNEL_DS);
173     do {
174         int mode = (wbuf) ? O_RDWR : O_RDONLY;
175         filp = filp_open(filename, mode, S_IRUSR);
176         if (IS_ERR(filp) || !filp->f_op) {
177             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: file %s filp_open error\n", __FUNCTION__, filename));
178             ret = -ENOENT;
179             break;
180         }
181     
182         if (length==0) {
183             /* Read the length of the file only */
184             struct inode    *inode;
185
186             inode = GET_INODE_FROM_FILEP(filp);
187             if (!inode) {
188                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Get inode from %s failed\n", __FUNCTION__, filename));
189                 ret = -ENOENT;
190                 break;
191             }
192             ret = i_size_read(inode->i_mapping->host);
193             break;
194         }
195
196         if (wbuf) {
197             if ( (ret=filp->f_op->write(filp, wbuf, length, &filp->f_pos)) < 0) {
198                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Write %u bytes to file %s error %d\n", __FUNCTION__, 
199                                 length, filename, ret));
200                 break;
201             }
202         } else {
203             if ( (ret=filp->f_op->read(filp, rbuf, length, &filp->f_pos)) < 0) {
204                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Read %u bytes from file %s error %d\n", __FUNCTION__,
205                                 length, filename, ret));
206                 break;
207             }
208         }
209     } while (0);
210
211     if (!IS_ERR(filp)) {
212         filp_close(filp, NULL);
213     }
214     set_fs(oldfs);
215
216     return ret;
217 }
218
219 int android_request_firmware(const struct firmware **firmware_p, const char *name,
220                      struct device *device)
221 {
222     int ret = 0;
223     struct firmware *firmware;
224     char filename[256];
225     const char *raw_filename = name;
226         *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
227     if (!firmware) 
228                 return -ENOMEM;
229         sprintf(filename, "%s/%s", fwpath, raw_filename);
230     do {
231         size_t length, bufsize, bmisize;
232
233         if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) {
234             break;
235         } else {
236             length = ret;
237         }
238     
239         bufsize = ALIGN(length, PAGE_SIZE);
240         bmisize = A_ROUND_UP(length, 4);
241         bufsize = max(bmisize, bufsize);
242         firmware->data = vmalloc(bufsize);
243         firmware->size = length;
244         if (!firmware->data) {
245             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmware\n", __FUNCTION__));
246             ret = -ENOMEM;
247             break;
248         }
249     
250         if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL, length)) != length) {
251             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request %d\n", __FUNCTION__, ret, length));
252             ret = -1;
253             break;
254         }
255     
256     } while (0);
257
258     if (ret<0) {
259         if (firmware) {
260             if (firmware->data)
261                 vfree(firmware->data);
262             kfree(firmware);
263         }
264         *firmware_p = NULL;
265     } else {
266         ret = 0;
267     }
268     return ret;    
269 }
270
271 void android_release_firmware(const struct firmware *firmware)
272 {
273         if (firmware) {
274         if (firmware->data)
275             vfree(firmware->data);
276         kfree(firmware);
277     }
278 }
279
280 static A_STATUS ar6000_android_avail_ev(void *context, void *hif_handle)
281 {
282     A_STATUS ret;    
283 #ifdef CONFIG_HAS_WAKELOCK
284     wake_lock(&ar6k_init_wake_lock);
285 #endif
286     ar6000_enable_mmchost_detect_change(0);
287     ret = ar6000_avail_ev_p(context, hif_handle);
288 #ifdef CONFIG_HAS_WAKELOCK
289     wake_unlock(&ar6k_init_wake_lock);
290 #endif
291     return ret;
292 }
293
294 /* Useful for qualcom platform to detect our wlan card for mmc stack */
295 static void ar6000_enable_mmchost_detect_change(int enable)
296 {
297 #ifdef CONFIG_MMC_MSM
298 #define MMC_MSM_DEV "msm_sdcc.1"
299     char buf[3];
300     int length;
301
302     if (!enable_mmc_host_detect_change) {
303         return;
304     }
305     length = snprintf(buf, sizeof(buf), "%d\n", enable ? 1 : 0);
306     if (android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/detect_change", 
307                                NULL, buf, length) < 0) {
308         /* fall back to polling */
309         android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/polling", NULL, buf, length);
310     }
311 #endif
312 }
313
314 #ifdef CONFIG_HAS_EARLYSUSPEND
315 static void android_early_suspend(struct early_suspend *h)
316 {
317     screen_is_off = 1;
318 }
319
320 static void android_late_resume(struct early_suspend *h)
321 {
322     screen_is_off = 0;
323 }
324 #endif
325
326 void android_module_init(OSDRV_CALLBACKS *osdrvCallbacks)
327 {
328     bmienable = 1;
329     if (ifname[0] == '\0')
330         strcpy(ifname, def_ifname);
331 #ifdef CONFIG_HAS_WAKELOCK
332     wake_lock_init(&ar6k_init_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_init");
333 #endif
334 #ifdef CONFIG_HAS_EARLYSUSPEND
335     ar6k_early_suspend.suspend = android_early_suspend;
336     ar6k_early_suspend.resume  = android_late_resume;
337     ar6k_early_suspend.level   = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
338     register_early_suspend(&ar6k_early_suspend);
339 #endif
340
341     ar6000_avail_ev_p = osdrvCallbacks->deviceInsertedHandler;
342     osdrvCallbacks->deviceInsertedHandler = ar6000_android_avail_ev;
343
344     ar6000_enable_mmchost_detect_change(1);
345 }
346
347 void android_module_exit(void)
348 {
349 #ifdef CONFIG_HAS_EARLYSUSPEND
350     unregister_early_suspend(&ar6k_early_suspend);
351 #endif
352 #ifdef CONFIG_HAS_WAKELOCK
353     wake_lock_destroy(&ar6k_init_wake_lock);
354 #endif
355     ar6000_enable_mmchost_detect_change(1);
356 }
357
358 #ifdef CONFIG_PM
359 void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL isEvent)
360 {
361     if (
362 #ifdef CONFIG_HAS_EARLYSUSPEND
363         screen_is_off && 
364 #endif 
365             skb && ar->arConnected) {
366         A_BOOL needWake = FALSE;
367         if (isEvent) {
368             if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) {
369                 A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb);
370                 switch (cmd) {
371                 case WMI_CONNECT_EVENTID:
372                 case WMI_DISCONNECT_EVENTID:
373                     needWake = TRUE;
374                     break;
375                 default:
376                     /* dont wake lock the system for other event */
377                     break;
378                 }
379             }
380         } else if (A_NETBUF_LEN(skb) >= sizeof(ATH_MAC_HDR)) {
381             ATH_MAC_HDR *datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb);
382             if (!IEEE80211_IS_MULTICAST(datap->dstMac)) {
383                 switch (A_BE2CPU16(datap->typeOrLen)) {
384                 case 0x0800: /* IP */
385                 case 0x888e: /* EAPOL */
386                 case 0x88c7: /* RSN_PREAUTH */
387                 case 0x88b4: /* WAPI */
388                      needWake = TRUE;
389                      break;
390                 case 0x0806: /* ARP is not important to hold wake lock */
391                 default:
392                     break;
393                 }
394             }
395         }
396         if (needWake) {
397             /* keep host wake up if there is any event and packate comming in*/
398 #ifdef CONFIG_HAS_WAKELOCK
399             wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ);
400 #endif
401             if (wowledon) {
402                 char buf[32];
403                 int len = sprintf(buf, "on");
404                 android_readwrite_file("/sys/power/state", NULL, buf, len);
405
406                 len = sprintf(buf, "%d", 127);
407                 android_readwrite_file("/sys/class/leds/lcd-backlight/brightness",
408                                        NULL, buf,len);
409             }
410         }
411     }
412 }
413 #endif /* CONFIG_PM */