]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/linux-3.10.39-add_libertas_uap.patch
Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into next-suricata
[ipfire-2.x.git] / src / patches / linux-3.10.39-add_libertas_uap.patch
CommitLineData
74fd06be
AF
1diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
2index f8f0156..42a0702 100644
3--- a/drivers/net/wireless/Kconfig
4+++ b/drivers/net/wireless/Kconfig
5@@ -51,6 +51,14 @@ config LIBERTAS_THINFIRM_USB
6 ---help---
7 A driver for Marvell Libertas 8388 USB devices using thinfirm.
8
9+config LIBERTAS_UAP
10+ tristate "Marvell 8xxx Libertas UAP"
11+ depends on MAC80211
12+ depends on MMC
13+ select FW_LOADER
14+ ---help---
15+ Driver for Marvell Libertas 8xxx micro AP.
16+
17 config AIRO
18 tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
19 depends on ISA_DMA_API && (PCI || BROKEN)
20diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
21index 67156ef..475a1b3 100644
22--- a/drivers/net/wireless/Makefile
23+++ b/drivers/net/wireless/Makefile
24@@ -37,6 +37,8 @@ obj-$(CONFIG_LIBERTAS) += libertas/
25
26 obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/
27
28+obj-$(CONFIG_LIBERTAS_UAP) += libertas_uap/
29+
30 obj-$(CONFIG_ADM8211) += adm8211.o
31
32 obj-$(CONFIG_MWL8K) += mwl8k.o
33diff --git a/drivers/net/wireless/libertas_uap/Makefile b/drivers/net/wireless/libertas_uap/Makefile
34new file mode 100644
35index 0000000..821f2a4
36--- /dev/null
37+++ b/drivers/net/wireless/libertas_uap/Makefile
38@@ -0,0 +1,6 @@
39+obj-$(CONFIG_LIBERTAS_UAP) += uap8xxx.o
40+
41+uap8xxx-y += uap_main.o uap_sdio_mmc.o
42+uap8xxx-$(CONFIG_PROC_FS) += uap_proc.o uap_debug.o
43+
44+EXTRA_CFLAGS += -DFPNUM='"52"' -DPXA3XX_DMA_ALIGN -DDEBUG_LEVEL1
45diff --git a/drivers/net/wireless/libertas_uap/uap_debug.c b/drivers/net/wireless/libertas_uap/uap_debug.c
46new file mode 100644
47index 0000000..a2f6dc9
48--- /dev/null
49+++ b/drivers/net/wireless/libertas_uap/uap_debug.c
50@@ -0,0 +1,260 @@
51+/** @file uap_debug.c
52+ * @brief This file contains functions for debug proc file.
53+ *
54+ * Copyright (C) 2008-2009, Marvell International Ltd.
55+ *
56+ * This software file (the "File") is distributed by Marvell International
57+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
58+ * (the "License"). You may use, redistribute and/or modify this File in
59+ * accordance with the terms and conditions of the License, a copy of which
60+ * is available along with the File in the gpl.txt file or by writing to
61+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
62+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
63+ *
64+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
65+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
66+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
67+ * this warranty disclaimer.
68+ *
69+ */
70+#ifdef CONFIG_PROC_FS
71+#include "uap_headers.h"
72+
73+/********************************************************
74+ Local Variables
75+********************************************************/
76+
77+#define item_size(n) (sizeof ((uap_adapter *)0)->n)
78+#define item_addr(n) ((u32) &((uap_adapter *)0)->n)
79+
80+#define item_dbg_size(n) (sizeof (((uap_adapter *)0)->dbg.n))
81+#define item_dbg_addr(n) ((u32) &(((uap_adapter *)0)->dbg.n))
82+
83+#define item_dev_size(n) (sizeof ((uap_dev_t *)0)->n)
84+#define item_dev_addr(n) ((u32) &((uap_dev_t *)0)->n)
85+
86+/** MicroAp device offset */
87+#define OFFSET_UAP_DEV 0x01
88+/** Bluetooth adapter offset */
89+#define OFFSET_UAP_ADAPTER 0x02
90+
91+struct debug_data
92+{
93+ /** Name */
94+ char name[32];
95+ /** Size */
96+ u32 size;
97+ /** Address */
98+ u32 addr;
99+ /** Offset */
100+ u32 offset;
101+ /** Flag */
102+ u32 flag;
103+};
104+
105+/* To debug any member of uap_adapter, simply add one line here.
106+ */
107+static struct debug_data items[] = {
108+ {"cmd_sent", item_dev_size(cmd_sent), 0, item_dev_addr(cmd_sent),
109+ OFFSET_UAP_DEV},
110+ {"data_sent", item_dev_size(data_sent), 0, item_dev_addr(data_sent),
111+ OFFSET_UAP_DEV},
112+ {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter),
113+ OFFSET_UAP_ADAPTER},
114+ {"cmd_pending", item_size(cmd_pending), 0, item_addr(cmd_pending),
115+ OFFSET_UAP_ADAPTER},
116+ {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
117+ item_dbg_addr(num_cmd_host_to_card_failure), OFFSET_UAP_ADAPTER},
118+ {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
119+ item_dbg_addr(num_tx_host_to_card_failure), OFFSET_UAP_ADAPTER},
120+ {"psmode", item_size(psmode), 0, item_addr(psmode), OFFSET_UAP_ADAPTER},
121+ {"ps_state", item_size(ps_state), 0, item_addr(ps_state),
122+ OFFSET_UAP_ADAPTER},
123+#ifdef DEBUG_LEVEL1
124+ {"drvdbg", sizeof(drvdbg), (u32) & drvdbg, 0, 0}
125+#endif
126+};
127+
128+static int num_of_items = sizeof(items) / sizeof(items[0]);
129+
130+/********************************************************
131+ Global Variables
132+********************************************************/
133+
134+/********************************************************
135+ Local Functions
136+********************************************************/
137+/**
138+ * @brief proc read function
139+ *
140+ * @param page pointer to buffer
141+ * @param s read data starting position
142+ * @param off offset
143+ * @param cnt counter
144+ * @param eof end of file flag
145+ * @param data data to output
146+ * @return number of output data
147+ */
148+static int uap_debug_proc_show(struct seq_file *s, void *data) {
149+ int val = 0;
150+ int i;
151+
152+ struct debug_data *d = (struct debug_data *)s->private;
153+
154+ if (MODULE_GET == 0)
155+ return UAP_STATUS_FAILURE;
156+
157+ for (i = 0; i < num_of_items; i++) {
158+ if (d[i].size == 1)
159+ val = *((u8 *) d[i].addr);
160+ else if (d[i].size == 2)
161+ val = *((u16 *) d[i].addr);
162+ else if (d[i].size == 4)
163+ val = *((u32 *) d[i].addr);
164+
165+ seq_printf(s, "%s=%d\n", d[i].name, val);
166+ }
167+ MODULE_PUT;
168+ return 0;
169+}
170+
171+static int uap_debug_proc_open(struct inode* inode, struct file* file) {
172+ return single_open(file, uap_debug_proc_show, PDE_DATA(inode));
173+}
174+
175+/**
176+ * @brief proc write function
177+ *
178+ * @param f file pointer
179+ * @param buf pointer to data buffer
180+ * @param cnt data number to write
181+ * @param data data to write
182+ * @return number of data
183+ */
184+static ssize_t uap_debug_proc_write(struct file *f, const char __user *buf, size_t cnt, loff_t *data) {
185+ int r, i;
186+ char *pdata;
187+ char *p;
188+ char *p0;
189+ char *p1;
190+ char *p2;
191+ struct debug_data *d = (struct debug_data *)PDE_DATA(file_inode(f));
192+
193+ if (MODULE_GET == 0)
194+ return UAP_STATUS_FAILURE;
195+
196+ pdata = (char *) kmalloc(cnt, GFP_KERNEL);
197+ if (pdata == NULL) {
198+ MODULE_PUT;
199+ return 0;
200+ }
201+
202+ if (copy_from_user(pdata, buf, cnt)) {
203+ PRINTM(INFO, "Copy from user failed\n");
204+ kfree(pdata);
205+ MODULE_PUT;
206+ return 0;
207+ }
208+
209+ p0 = pdata;
210+ for (i = 0; i < num_of_items; i++) {
211+ do {
212+ p = strstr(p0, d[i].name);
213+ if (p == NULL)
214+ break;
215+ p1 = strchr(p, '\n');
216+ if (p1 == NULL)
217+ break;
218+ p0 = p1++;
219+ p2 = strchr(p, '=');
220+ if (!p2)
221+ break;
222+ p2++;
223+ r = string_to_number(p2);
224+ if (d[i].size == 1)
225+ *((u8 *) d[i].addr) = (u8) r;
226+ else if (d[i].size == 2)
227+ *((u16 *) d[i].addr) = (u16) r;
228+ else if (d[i].size == 4)
229+ *((u32 *) d[i].addr) = (u32) r;
230+ break;
231+ } while (TRUE);
232+ }
233+ kfree(pdata);
234+#ifdef DEBUG_LEVEL1
235+ printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
236+ printk(KERN_ALERT "INFO (%08lx) %s\n", DBG_INFO,
237+ (drvdbg & DBG_INFO) ? "X" : "");
238+ printk(KERN_ALERT "WARN (%08lx) %s\n", DBG_WARN,
239+ (drvdbg & DBG_WARN) ? "X" : "");
240+ printk(KERN_ALERT "ENTRY (%08lx) %s\n", DBG_ENTRY,
241+ (drvdbg & DBG_ENTRY) ? "X" : "");
242+ printk(KERN_ALERT "CMD_D (%08lx) %s\n", DBG_CMD_D,
243+ (drvdbg & DBG_CMD_D) ? "X" : "");
244+ printk(KERN_ALERT "DAT_D (%08lx) %s\n", DBG_DAT_D,
245+ (drvdbg & DBG_DAT_D) ? "X" : "");
246+ printk(KERN_ALERT "CMND (%08lx) %s\n", DBG_CMND,
247+ (drvdbg & DBG_CMND) ? "X" : "");
248+ printk(KERN_ALERT "DATA (%08lx) %s\n", DBG_DATA,
249+ (drvdbg & DBG_DATA) ? "X" : "");
250+ printk(KERN_ALERT "ERROR (%08lx) %s\n", DBG_ERROR,
251+ (drvdbg & DBG_ERROR) ? "X" : "");
252+ printk(KERN_ALERT "FATAL (%08lx) %s\n", DBG_FATAL,
253+ (drvdbg & DBG_FATAL) ? "X" : "");
254+ printk(KERN_ALERT "MSG (%08lx) %s\n", DBG_MSG,
255+ (drvdbg & DBG_MSG) ? "X" : "");
256+#endif
257+ MODULE_PUT;
258+ return cnt;
259+}
260+
261+static const struct file_operations uap_debug_proc_fops = {
262+ .owner = THIS_MODULE,
263+ .open = uap_debug_proc_open,
264+ .read = seq_read,
265+ .llseek = seq_lseek,
266+ .release = single_release,
267+ .write = uap_debug_proc_write,
268+};
269+
270+/********************************************************
271+ Global Functions
272+********************************************************/
273+/**
274+ * @brief create debug proc file
275+ *
276+ * @param priv pointer uap_private
277+ * @param dev pointer net_device
278+ * @return N/A
279+ */
280+void
281+uap_debug_entry(uap_private * priv, struct net_device *dev)
282+{
283+ int i;
284+
285+ if (priv->proc_entry == NULL)
286+ return;
287+
288+ for (i = 0; i < num_of_items; i++) {
289+ if (items[i].flag & OFFSET_UAP_ADAPTER)
290+ items[i].addr = items[i].offset + (u32) priv->adapter;
291+ if (items[i].flag & OFFSET_UAP_DEV)
292+ items[i].addr = items[i].offset + (u32) & priv->uap_dev;
293+ }
294+ proc_create_data("debug", 0644, priv->proc_entry, &uap_debug_proc_fops,
295+ &items[0]);
296+}
297+
298+/**
299+ * @brief remove proc file
300+ *
301+ * @param priv pointer uap_private
302+ * @return N/A
303+ */
304+void
305+uap_debug_remove(uap_private * priv)
306+{
307+ remove_proc_entry("debug", priv->proc_entry);
308+}
309+
310+#endif
311diff --git a/drivers/net/wireless/libertas_uap/uap_drv.h b/drivers/net/wireless/libertas_uap/uap_drv.h
312new file mode 100644
313index 0000000..5aa009f
314--- /dev/null
315+++ b/drivers/net/wireless/libertas_uap/uap_drv.h
316@@ -0,0 +1,667 @@
317+/** @file uap_drv.h
318+ * @brief This file contains Linux OS related definitions and
319+ * declarations, uAP driver
320+ *
321+ * Copyright (C) 2008-2009, Marvell International Ltd.
322+ *
323+ * This software file (the "File") is distributed by Marvell International
324+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
325+ * (the "License"). You may use, redistribute and/or modify this File in
326+ * accordance with the terms and conditions of the License, a copy of which
327+ * is available along with the File in the gpl.txt file or by writing to
328+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
329+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
330+ *
331+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
332+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
333+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
334+ * this warranty disclaimer.
335+ *
336+ */
337+
338+#ifndef _UAP_DRV_H
339+#define _UAP_DRV_H
340+
341+/** Driver release version */
342+#define DRIVER_VERSION "26146"
343+
344+/** True */
345+#ifndef TRUE
346+#define TRUE 1
347+#endif
348+/** False */
349+#ifndef FALSE
350+#define FALSE 0
351+#endif
352+
353+/** Bit definitions */
354+#ifndef BIT
355+#define BIT(x) (1UL << (x))
356+#endif
357+
358+/** Dma addresses are 32-bits wide. */
359+#ifndef __ATTRIB_ALIGN__
360+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
361+#endif
362+
363+/** attribute pack */
364+#ifndef __ATTRIB_PACK__
365+#define __ATTRIB_PACK__ __attribute__ ((packed))
366+#endif
367+
368+/** Debug Macro definition*/
369+#ifdef DEBUG_LEVEL1
370+
371+extern u32 drvdbg;
372+
373+/** Debug message control bit definition for drvdbg */
374+/** Debug message */
375+#define DBG_MSG BIT(0)
376+/** Debug fatal message */
377+#define DBG_FATAL BIT(1)
378+/** Debug error message */
379+#define DBG_ERROR BIT(2)
380+/** Debug data message */
381+#define DBG_DATA BIT(3)
382+/** Debug command message */
383+#define DBG_CMND BIT(4)
384+
385+/** Debug data */
386+#define DBG_DAT_D BIT(16)
387+/** Debug command */
388+#define DBG_CMD_D BIT(17)
389+
390+/** Debug entry */
391+#define DBG_ENTRY BIT(28)
392+/** Debug warning */
393+#define DBG_WARN BIT(29)
394+/** Debug info */
395+#define DBG_INFO BIT(30)
396+
397+/** Print info */
398+#define PRINTM_INFO(msg...) {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
399+/** Print warn message */
400+#define PRINTM_WARN(msg...) {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
401+/** Print entry */
402+#define PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
403+/** Print cmd_d */
404+#define PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
405+/** Print data_d */
406+#define PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
407+/** Print command */
408+#define PRINTM_CMND(msg...) {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
409+/** Print data */
410+#define PRINTM_DATA(msg...) {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
411+/** Print error message */
412+#define PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
413+/** Print fatal message */
414+#define PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
415+/** Print message */
416+#define PRINTM_MSG(msg...) {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
417+/** Print level */
418+#define PRINTM(level,msg...) PRINTM_##level(msg)
419+
420+#else
421+
422+#define PRINTM(level,msg...) do {} while (0)
423+
424+#endif /* DEBUG_LEVEL1 */
425+
426+/** Wait until a condition becomes true */
427+#define ASSERT(cond) \
428+do { \
429+ if (!(cond)) \
430+ PRINTM(INFO, "ASSERT: %s, %s:%i\n", \
431+ __FUNCTION__, __FILE__, __LINE__); \
432+} while(0)
433+
434+/** Log enrty point for debugging */
435+#define ENTER() PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
436+ __FILE__, __LINE__)
437+/** Log exit point for debugging */
438+#define LEAVE() PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
439+ __FILE__, __LINE__)
440+
441+#ifdef DEBUG_LEVEL1
442+/** Dump buffer length */
443+#define DBG_DUMP_BUF_LEN 64
444+/** Maximum dump per line */
445+#define MAX_DUMP_PER_LINE 16
446+/** Data dump length */
447+#define DATA_DUMP_LEN 32
448+
449+static inline void
450+hexdump(char *prompt, u8 * buf, int len)
451+{
452+ int i;
453+ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
454+ char *ptr = dbgdumpbuf;
455+
456+ printk(KERN_DEBUG "%s:\n", prompt);
457+ for (i = 1; i <= len; i++) {
458+ ptr += sprintf(ptr, "%02x ", *buf);
459+ buf++;
460+ if (i % MAX_DUMP_PER_LINE == 0) {
461+ *ptr = 0;
462+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
463+ ptr = dbgdumpbuf;
464+ }
465+ }
466+ if (len % MAX_DUMP_PER_LINE) {
467+ *ptr = 0;
468+ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
469+ }
470+}
471+
472+/** Debug command */
473+#define DBG_HEXDUMP_CMD_D(x,y,z) {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
474+/** Debug data */
475+#define DBG_HEXDUMP_DAT_D(x,y,z) {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
476+/** Debug hexdump */
477+#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
478+/** hexdump */
479+#define HEXDUMP(x,y,z) {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
480+#else
481+/** Do nothing since debugging is not turned on */
482+#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
483+/** Do nothing since debugging is not turned on */
484+#define HEXDUMP(x,y,z) do {} while (0)
485+#endif
486+
487+/**
488+ * Typedefs
489+ */
490+/** Unsigned char */
491+typedef u8 BOOLEAN;
492+
493+/*
494+ * OS macro definitions
495+ */
496+/** OS macro to get time */
497+#define os_time_get() jiffies
498+
499+/** OS macro to update transfer start time */
500+#define UpdateTransStart(dev) { \
501+ dev->trans_start = jiffies; \
502+}
503+
504+/** Try to get a reference to the module */
505+#define MODULE_GET try_module_get(THIS_MODULE)
506+/** Decrease module reference count */
507+#define MODULE_PUT module_put(THIS_MODULE)
508+
509+/** OS macro to initialize semaphore */
510+#define OS_INIT_SEMAPHORE(x) sema_init(x,1)
511+/** OS macro to acquire blocking semaphore */
512+#define OS_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
513+/** OS macro to acquire non-blocking semaphore */
514+#define OS_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
515+/** OS macro to release semaphore */
516+#define OS_REL_SEMAPHORE(x) up(x)
517+
518+static inline void
519+os_sched_timeout(u32 millisec)
520+{
521+ set_current_state(TASK_INTERRUPTIBLE);
522+ schedule_timeout((millisec * HZ) / 1000);
523+}
524+
525+/** Maximum size of ethernet packet */
526+#define MRVDRV_MAXIMUM_ETH_PACKET_SIZE 1514
527+
528+/** Maximum size of multicast list */
529+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
530+
531+/** Find minimum */
532+#ifndef MIN
533+#define MIN(a,b) ((a) < (b) ? (a) : (b))
534+#endif
535+
536+/** Find maximum */
537+#ifndef MAX
538+#define MAX(a,b) ((a) > (b) ? (a) : (b))
539+#endif
540+
541+/** Find number of elements */
542+#ifndef NELEMENTS
543+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
544+#endif
545+
546+/** Buffer Constants */
547+
548+/** Size of command buffer */
549+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
550+
551+/** Length of device length */
552+#define DEV_NAME_LEN 32
553+
554+/** Length of ethernet address */
555+#ifndef ETH_ALEN
556+#define ETH_ALEN 6
557+#endif
558+
559+/** Default watchdog timeout */
560+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (2 * HZ)
561+
562+/** Success */
563+#define UAP_STATUS_SUCCESS (0)
564+/** Failure */
565+#define UAP_STATUS_FAILURE (-1)
566+/** Not accepted */
567+#define UAP_STATUS_NOT_ACCEPTED (-2)
568+
569+/** Max loop count (* 100ms) for waiting device ready at init time */
570+#define MAX_WAIT_DEVICE_READY_COUNT 50
571+
572+/** Tx high watermark. Stop Tx queue after this is crossed */
573+#define TX_HIGH_WATERMARK 4
574+/** Tx low watermark. Restart Tx queue after this is crossed */
575+#define TX_LOW_WATERMARK 2
576+
577+/** Netlink protocol number */
578+#define NETLINK_MARVELL (MAX_LINKS - 1)
579+/** Netlink maximum payload size */
580+#define NL_MAX_PAYLOAD 1024
581+/** Netlink multicast group number */
582+#define NL_MULTICAST_GROUP 1
583+
584+/** 20 seconds */
585+#define MRVDRV_TIMER_20S 20000
586+
587+/** Host Command option for wait till Send */
588+#define HostCmd_OPTION_WAITFORSEND 0x0001
589+/** Host Command option for wait for RSP */
590+#define HostCmd_OPTION_WAITFORRSP 0x0002
591+/** Host Command option for wait for RSP or Timeout */
592+#define HostCmd_OPTION_WAITFORRSP_TIMEOUT 0x0003
593+/** Host Command option for wait for RSP of sleep confirm */
594+#define HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM 0x0004
595+
596+/** Sleep until a condition gets true or a timeout elapses */
597+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
598+ wait_event_interruptible_timeout(waitq, cond, ((timeout) * HZ / 1000))
599+
600+/** Private command ID to Host command */
601+#define UAPHOSTCMD (SIOCDEVPRIVATE + 1)
602+
603+/** Private command ID to Power Mode */
604+#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3)
605+/** sleep_param */
606+typedef struct _ps_sleep_param
607+{
608+ /** control bitmap */
609+ u32 ctrl_bitmap;
610+ /** minimum sleep period (micro second) */
611+ u32 min_sleep;
612+ /** maximum sleep period (micro second) */
613+ u32 max_sleep;
614+} ps_sleep_param;
615+
616+/** inactivity sleep_param */
617+typedef struct _inact_sleep_param
618+{
619+ /** inactivity timeout (micro second) */
620+ u32 inactivity_to;
621+ /** miniumu awake period (micro second) */
622+ u32 min_awake;
623+ /** maximum awake period (micro second) */
624+ u32 max_awake;
625+} inact_sleep_param;
626+
627+/** flag for ps mode */
628+#define PS_FLAG_PS_MODE 1
629+/** flag for sleep param */
630+#define PS_FLAG_SLEEP_PARAM 2
631+/** flag for inactivity sleep param */
632+#define PS_FLAG_INACT_SLEEP_PARAM 4
633+
634+/** Disable power mode */
635+#define PS_MODE_DISABLE 0
636+/** Enable periodic dtim ps */
637+#define PS_MODE_PERIODIC_DTIM 1
638+/** Enable inactivity ps */
639+#define PS_MODE_INACTIVITY 2
640+
641+/** sleep parameter */
642+#define SLEEP_PARAMETER 1
643+/** inactivity sleep parameter */
644+#define INACTIVITY_SLEEP_PARAMETER 2
645+/** ps_mgmt */
646+typedef struct _ps_mgmt
647+{
648+ /** flags for valid field */
649+ u16 flags;
650+ /** power mode */
651+ u16 ps_mode;
652+ /** sleep param */
653+ ps_sleep_param sleep_param;
654+ /** inactivity sleep param */
655+ inact_sleep_param inact_param;
656+} ps_mgmt;
657+
658+/** Semaphore structure */
659+typedef struct semaphore SEMAPHORE;
660+
661+/** Global Varibale Declaration */
662+/** Private data structure of the device */
663+typedef struct _uap_private uap_private;
664+/** Adapter data structure of the device */
665+typedef struct _uap_adapter uap_adapter;
666+/** private structure */
667+extern uap_private *uappriv;
668+
669+/** ENUM definition*/
670+
671+/** Hardware status codes */
672+typedef enum _HARDWARE_STATUS
673+{
674+ HWReady,
675+ HWInitializing,
676+ HWReset,
677+ HWClosing,
678+ HWNotReady
679+} HARDWARE_STATUS;
680+
681+/** info for debug purpose */
682+typedef struct _uap_dbg
683+{
684+ /** Number of host to card command failures */
685+ u32 num_cmd_host_to_card_failure;
686+ /** Number of host to card Tx failures */
687+ u32 num_tx_host_to_card_failure;
688+} uap_dbg;
689+
690+/** Set thread state */
691+#define OS_SET_THREAD_STATE(x) set_current_state(x)
692+
693+typedef struct
694+{
695+ /** Task */
696+ struct task_struct *task;
697+ /** Queue */
698+ wait_queue_head_t waitQ;
699+ /** PID */
700+ pid_t pid;
701+ /** Private structure */
702+ void *priv;
703+} uap_thread;
704+
705+static inline void
706+uap_activate_thread(uap_thread * thr)
707+{
708+ /** Record the thread pid */
709+ thr->pid = current->pid;
710+
711+ /** Initialize the wait queue */
712+ init_waitqueue_head(&thr->waitQ);
713+}
714+
715+static inline void
716+uap_deactivate_thread(uap_thread * thr)
717+{
718+ thr->pid = 0;
719+ return;
720+}
721+
722+static inline void
723+uap_create_thread(int (*uapfunc) (void *), uap_thread * thr, char *name)
724+{
725+ thr->task = kthread_run(uapfunc, thr, "%s", name);
726+}
727+
728+static inline int
729+uap_terminate_thread(uap_thread * thr)
730+{
731+ /* Check if the thread is active or not */
732+ if (!thr->pid)
733+ return -1;
734+ kthread_stop(thr->task);
735+ return 0;
736+}
737+
738+/** Data structure for the Marvell uAP device */
739+typedef struct _uap_dev
740+{
741+ /** device name */
742+ char name[DEV_NAME_LEN];
743+ /** card pointer */
744+ void *card;
745+ /** IO port */
746+ u32 ioport;
747+ /** Rx unit */
748+ u8 rx_unit;
749+ /** Data sent:
750+ TRUE - Data is sent to fw, no Tx Done received
751+ FALSE - Tx done received for previous Tx */
752+ BOOLEAN data_sent;
753+ /** CMD sent:
754+ TRUE - CMD is sent to fw, no CMD Done received
755+ FALSE - CMD done received for previous CMD */
756+ BOOLEAN cmd_sent;
757+ /** netdev pointer */
758+ struct net_device *netdev;
759+} uap_dev_t, *puap_dev_t;
760+
761+/** Private structure for the MV device */
762+struct _uap_private
763+{
764+ /** Device open */
765+ int open;
766+
767+ /** Device adapter structure */
768+ uap_adapter *adapter;
769+ /** Device structure */
770+ uap_dev_t uap_dev;
771+
772+ /** Net device statistics structure */
773+ struct net_device_stats stats;
774+
775+ /** Number of Tx timeouts */
776+ u32 num_tx_timeout;
777+
778+ /** Media connection status */
779+ BOOLEAN MediaConnected;
780+
781+#ifdef CONFIG_PROC_FS
782+ struct proc_dir_entry *proc_uap;
783+ struct proc_dir_entry *proc_entry;
784+#endif /* CONFIG_PROC_FS */
785+
786+ /** Firmware helper */
787+ const struct firmware *fw_helper;
788+ /** Firmware */
789+ const struct firmware *firmware;
790+ /** Hotplug device */
791+ struct device *hotplug_device;
792+ /** thread to service interrupts */
793+ uap_thread MainThread;
794+ /** Driver lock */
795+ spinlock_t driver_lock;
796+ /** Driver lock flags */
797+ ulong driver_flags;
798+
799+};
800+
801+/** PS_CMD_ConfirmSleep */
802+typedef struct _PS_CMD_ConfirmSleep
803+{
804+ /** SDIO Length */
805+ u16 SDLen;
806+ /** SDIO Type */
807+ u16 SDType;
808+ /** Command */
809+ u16 Command;
810+ /** Size */
811+ u16 Size;
812+ /** Sequence number */
813+ u16 SeqNum;
814+ /** Result */
815+ u16 Result;
816+} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
817+
818+/** Wlan Adapter data structure*/
819+struct _uap_adapter
820+{
821+ /** Power save confirm sleep command */
822+ PS_CMD_ConfirmSleep PSConfirmSleep;
823+ /** Device status */
824+ HARDWARE_STATUS HardwareStatus;
825+ /** Interrupt counter */
826+ u32 IntCounter;
827+ /** Tx packet queue */
828+ struct sk_buff_head tx_queue;
829+ /** Cmd packet queue */
830+ struct sk_buff_head cmd_queue;
831+ /** Command sequence number */
832+ u16 SeqNum;
833+ /** Command buffer */
834+ u8 *CmdBuf;
835+ /** cmd pending flag */
836+ u8 cmd_pending;
837+ /** cmd wait option */
838+ u8 cmd_wait_option;
839+ /** Command buffer length */
840+ u32 CmdSize;
841+ /** Command wait queue */
842+ wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
843+ /** Command wait queue state flag */
844+ u8 CmdWaitQWoken;
845+ /** PnP support */
846+ BOOLEAN SurpriseRemoved;
847+ /** Debug */
848+ uap_dbg dbg;
849+ /** Netlink kernel socket */
850+ struct sock *nl_sk;
851+ /** Semaphore for CMD */
852+ SEMAPHORE CmdSem;
853+ /** Power Save mode */
854+ u8 psmode;
855+ /** Power Save state */
856+ u8 ps_state;
857+ /** Number of wakeup tries */
858+ u32 WakeupTries;
859+};
860+
861+static inline int
862+os_upload_rx_packet(uap_private * priv, struct sk_buff *skb)
863+{
864+ skb->dev = priv->uap_dev.netdev;
865+ skb->protocol = eth_type_trans(skb, priv->uap_dev.netdev);
866+ skb->ip_summed = CHECKSUM_UNNECESSARY;
867+ if (in_interrupt())
868+ netif_rx(skb);
869+ else
870+ netif_rx_ni(skb);
871+ return 0;
872+}
873+
874+/*
875+ * netif carrier_on/off and start(wake)/stop_queue handling
876+ */
877+static inline void
878+os_carrier_on(uap_private * priv)
879+{
880+ if (!netif_carrier_ok(priv->uap_dev.netdev) &&
881+ (priv->MediaConnected == TRUE)) {
882+ netif_carrier_on(priv->uap_dev.netdev);
883+ }
884+}
885+
886+static inline void
887+os_carrier_off(uap_private * priv)
888+{
889+ if (netif_carrier_ok(priv->uap_dev.netdev)) {
890+ netif_carrier_off(priv->uap_dev.netdev);
891+ }
892+}
893+
894+static inline void
895+os_start_queue(uap_private * priv)
896+{
897+ if (netif_queue_stopped(priv->uap_dev.netdev) &&
898+ (priv->MediaConnected == TRUE)) {
899+ netif_wake_queue(priv->uap_dev.netdev);
900+ }
901+}
902+
903+static inline void
904+os_stop_queue(uap_private * priv)
905+{
906+ if (!netif_queue_stopped(priv->uap_dev.netdev)) {
907+ netif_stop_queue(priv->uap_dev.netdev);
908+ }
909+}
910+
911+/** Interface specific header */
912+#define INTF_HEADER_LEN 4
913+
914+/** headroom alignment for tx packet */
915+#define HEADER_ALIGNMENT 8
916+
917+/** The number of times to try when polling for status bits */
918+#define MAX_POLL_TRIES 100
919+
920+/** Length of SNAP header */
921+#define MRVDRV_SNAP_HEADER_LEN 8
922+
923+/** Extra length of Tx packet buffer */
924+#define EXTRA_LEN 36
925+
926+/** Buffer size for ethernet Tx packets */
927+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
928+ (ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
929+
930+/** Buffer size for ethernet Rx packets */
931+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
932+ (ETH_FRAME_LEN + sizeof(RxPD) \
933+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
934+
935+/** Packet type: data, command & event */
936+typedef enum _mv_type
937+{
938+ MV_TYPE_DAT = 0,
939+ MV_TYPE_CMD = 1,
940+ MV_TYPE_EVENT = 3
941+} mv_type;
942+
943+/** Disable interrupt */
944+#define OS_INT_DISABLE spin_lock_irqsave(&priv->driver_lock, priv->driver_flags)
945+/** Enable interrupt */
946+#define OS_INT_RESTORE spin_unlock_irqrestore(&priv->driver_lock, priv->driver_flags)
947+
948+int uap_process_rx_packet(uap_private * priv, struct sk_buff *skb);
949+void uap_interrupt(uap_private * priv);
950+uap_private *uap_add_card(void *card);
951+int uap_remove_card(void *card);
952+int uap_process_event(uap_private * priv, u8 * payload, uint len);
953+int uap_soft_reset(uap_private * priv);
954+int uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len);
955+
956+#ifdef CONFIG_PROC_FS
957+/** The proc fs interface */
958+void uap_proc_entry(uap_private * priv, struct net_device *dev);
959+void uap_proc_remove(uap_private * priv);
960+int string_to_number(char *s);
961+void uap_debug_entry(uap_private * priv, struct net_device *dev);
962+void uap_debug_remove(uap_private * priv);
963+#endif /* CONFIG_PROC_FS */
964+
965+int sbi_register(void);
966+
967+void sbi_unregister(void);
968+int sbi_register_dev(uap_private * priv);
969+int sbi_unregister_dev(uap_private * priv);
970+int sbi_prog_fw_w_helper(uap_private *);
971+
972+int sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb);
973+int sbi_enable_host_int(uap_private * priv);
974+int sbi_disable_host_int(uap_private * priv);
975+
976+int sbi_get_int_status(uap_private * priv, u8 * ireg);
977+/** Check firmware status */
978+int sbi_check_fw_status(uap_private *, int);
979+int sbi_prog_helper(uap_private *);
980+
981+int sbi_wakeup_firmware(uap_private * priv);
982+
983+#endif /* _UAP_DRV_H */
984diff --git a/drivers/net/wireless/libertas_uap/uap_fw.h b/drivers/net/wireless/libertas_uap/uap_fw.h
985new file mode 100644
986index 0000000..23a40d6
987--- /dev/null
988+++ b/drivers/net/wireless/libertas_uap/uap_fw.h
989@@ -0,0 +1,359 @@
990+/** @file uap_fw.h
991+ *
992+ * @brief This file contains firmware specific defines.
993+ *
994+ * Copyright (C) 2008-2009, Marvell International Ltd.
995+ *
996+ * This software file (the "File") is distributed by Marvell International
997+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
998+ * (the "License"). You may use, redistribute and/or modify this File in
999+ * accordance with the terms and conditions of the License, a copy of which
1000+ * is available along with the File in the gpl.txt file or by writing to
1001+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1002+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
1003+ *
1004+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
1005+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
1006+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
1007+ * this warranty disclaimer.
1008+ *
1009+ */
1010+/********************************************************
1011+Change log:
1012+ 02/26/08: Initial creation
1013+********************************************************/
1014+
1015+#ifndef _UAP_FW_H
1016+#define _UAP_FW_H
1017+
1018+/** uap upload size */
1019+#define UAP_UPLD_SIZE 2312
1020+/** Packet type Micro AP */
1021+#define PKT_TYPE_MICROAP 1
1022+/** Packet type client */
1023+#define PKT_TYPE_CLIENT 0
1024+
1025+/** TxPD descriptor */
1026+typedef struct _TxPD
1027+{
1028+ /** Bss Type */
1029+ u8 BssType;
1030+ /** Bss num */
1031+ u8 BssNum;
1032+ /** Tx packet length */
1033+ u16 TxPktLength;
1034+ /** Tx packet offset */
1035+ u16 TxPktOffset;
1036+ /** Tx packet type */
1037+ u16 TxPktType;
1038+ /** Tx Control */
1039+ u32 TxControl;
1040+ /** reserved */
1041+ u32 reserved[2];
1042+} __ATTRIB_PACK__ TxPD, *PTxPD;
1043+
1044+/** RxPD Descriptor */
1045+typedef struct _RxPD
1046+{
1047+ /** Bss Type */
1048+ u8 BssType;
1049+ /** Bss Num */
1050+ u8 BssNum;
1051+ /** Tx packet length */
1052+ u16 RxPktLength;
1053+ /** Tx packet offset */
1054+ u16 RxPktOffset;
1055+} __ATTRIB_PACK__ RxPD, *PRxPD;
1056+
1057+#ifdef BIG_ENDIAN
1058+/** Convert from 16 bit little endian format to CPU format */
1059+#define uap_le16_to_cpu(x) le16_to_cpu(x)
1060+/** Convert from 32 bit little endian format to CPU format */
1061+#define uap_le32_to_cpu(x) le32_to_cpu(x)
1062+/** Convert from 64 bit little endian format to CPU format */
1063+#define uap_le64_to_cpu(x) le64_to_cpu(x)
1064+/** Convert to 16 bit little endian format from CPU format */
1065+#define uap_cpu_to_le16(x) cpu_to_le16(x)
1066+/** Convert to 32 bit little endian format from CPU format */
1067+#define uap_cpu_to_le32(x) cpu_to_le32(x)
1068+/** Convert to 64 bit little endian format from CPU format */
1069+#define uap_cpu_to_le64(x) cpu_to_le64(x)
1070+
1071+/** Convert TxPD to little endian format from CPU format */
1072+#define endian_convert_TxPD(x); \
1073+ { \
1074+ (x)->TxPktLength = uap_cpu_to_le16((x)->TxPktLength); \
1075+ (x)->TxPktOffset = uap_cpu_to_le32((x)->TxPktOffset); \
1076+ (x)->TxControl = uap_cpu_to_le32((x)->TxControl); \
1077+ (x)->TxPktType = uap_cpu_to_le32((x)->TxPktType); \
1078+ }
1079+
1080+/** Convert RxPD from little endian format to CPU format */
1081+#define endian_convert_RxPD(x); \
1082+ { \
1083+ (x)->RxPktLength = uap_le16_to_cpu((x)->RxPktLength); \
1084+ (x)->RxPktOffset = uap_le32_to_cpu((x)->RxPktOffset); \
1085+ }
1086+#else /* BIG_ENDIAN */
1087+/** Do nothing */
1088+#define uap_le16_to_cpu(x) x
1089+/** Do nothing */
1090+#define uap_le32_to_cpu(x) x
1091+/** Do nothing */
1092+#define uap_le64_to_cpu(x) x
1093+/** Do nothing */
1094+#define uap_cpu_to_le16(x) x
1095+/** Do nothing */
1096+#define uap_cpu_to_le32(x) x
1097+/** Do nothing */
1098+#define uap_cpu_to_le64(x) x
1099+
1100+/** Do nothing */
1101+#define endian_convert_TxPD(x)
1102+/** Do nothing */
1103+#define endian_convert_RxPD(x)
1104+#endif /* BIG_ENDIAN */
1105+
1106+/** Host Command ID : Function initialization */
1107+#define HostCmd_CMD_FUNC_INIT 0x00a9
1108+/** Host Command ID : Function shutdown */
1109+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
1110+
1111+/** Host Command id: SYS_INFO */
1112+#define HOST_CMD_APCMD_SYS_INFO 0x00ae
1113+/** Host Command id: SYS_RESET */
1114+#define HOST_CMD_APCMD_SYS_RESET 0x00af
1115+/** Host Command id: SYS_CONFIGURE */
1116+#define HOST_CMD_APCMD_SYS_CONFIGURE 0x00b0
1117+/** Host Command id: BSS_START */
1118+#define HOST_CMD_APCMD_BSS_START 0x00b1
1119+/** Host Command id: SYS_STOP */
1120+#define HOST_CMD_APCMD_BSS_STOP 0x00b2
1121+/** Host Command id: STA_LIST */
1122+#define HOST_CMD_APCMD_STA_LIST 0x00b3
1123+/** Host Command id: STA_FILTER_TABLE */
1124+#define HOST_CMD_APCMD_STA_FILTER_TABLE 0x00b4
1125+/** Host Command id: STA_DEAUTH */
1126+#define HOST_CMD_APCMD_STA_DEAUTH 0x00b5
1127+/** Host Command id: SOFT_RESET */
1128+#define HOST_CMD_APCMD_SOFT_RESET 0x00d5
1129+/** Host Command id: POWER_MGMT_EXT */
1130+#define HOST_CMD_POWER_MGMT_EXT 0x00ef
1131+/** Host Command id: SLEEP_CONFIRM*/
1132+#define HOST_CMD_SLEEP_CONFIRM 0x00d8
1133+
1134+/** TLV type : SSID */
1135+#define TLV_TYPE_SSID 0x0000
1136+/** TLV type : Rates */
1137+#define TLV_TYPE_RATES 0x0001
1138+/** TLV type : PHY DS */
1139+#define TLV_TYPE_PHY_DS 0x0003
1140+
1141+/** TLV Id : Base id */
1142+#define PROPRIETARY_TLV_BASE_ID 0x0100
1143+/** TLV Id : AP_MAC_ADDRESS */
1144+#define MRVL_AP_MAC_ADDRESS_TLV_ID (PROPRIETARY_TLV_BASE_ID + 43)
1145+/** TLV Id : Beacon period */
1146+#define MRVL_BEACON_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 44)
1147+/** TLV Id : Dtim period */
1148+#define MRVL_DTIM_PERIOD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 45)
1149+/** TLV Id : Basic rates */
1150+#define MRVL_BASIC_RATES_TLV_ID (PROPRIETARY_TLV_BASE_ID + 46)
1151+/** TLV Id : Tx Power */
1152+#define MRVL_TX_POWER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 47)
1153+/** TLV Id : Broadcast SSID control */
1154+#define MRVL_BCAST_SSID_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 48)
1155+/** TLV Id : Preamble control */
1156+#define MRVL_PREAMBLE_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 49)
1157+/** TLV Id : Antenna control */
1158+#define MRVL_ANTENNA_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 50)
1159+/** TLV Id : RTS threshold */
1160+#define MRVL_RTS_THRESHOLD_TLV_ID (PROPRIETARY_TLV_BASE_ID + 51)
1161+/** TLV Id : Radio control */
1162+#define MRVL_RADIO_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 52)
1163+/** TLV Id : TX data rate */
1164+#define MRVL_TX_DATA_RATE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 53)
1165+/** TLV Id : Packet forward control */
1166+#define MRVL_PKT_FWD_CTL_TLV_ID (PROPRIETARY_TLV_BASE_ID + 54)
1167+/** TLV Id : STA info */
1168+#define MRVL_STA_INFO_TLV_ID (PROPRIETARY_TLV_BASE_ID + 55)
1169+/** TLV Id : STA MAC address filter */
1170+#define MRVL_STA_MAC_ADDR_FILTER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 56)
1171+/** TLV Id : STA ageout timer */
1172+#define MRVL_STA_AGEOUT_TIMER_TLV_ID (PROPRIETARY_TLV_BASE_ID + 57)
1173+/** TLV Id : Security config */
1174+#define MRVL_SECURITY_CFG_TLV_ID (PROPRIETARY_TLV_BASE_ID + 58)
1175+/** TLV Id : WEP KEY */
1176+#define MRVL_WEP_KEY_TLV_ID (PROPRIETARY_TLV_BASE_ID + 59)
1177+/** TLV Id : WPA Passphrase */
1178+#define MRVL_WPA_PASSPHRASE_TLV_ID (PROPRIETARY_TLV_BASE_ID + 60)
1179+
1180+/** Action get */
1181+#define ACTION_GET 0
1182+/** Action set */
1183+#define ACTION_SET 1
1184+/** Length of ethernet address */
1185+#ifndef ETH_ALEN
1186+#define ETH_ALEN 6
1187+#endif
1188+
1189+/** HostCmd_DS_GEN */
1190+typedef struct
1191+{
1192+ /** Command */
1193+ u16 Command;
1194+ /** Size */
1195+ u16 Size;
1196+ /** Sequence number */
1197+ u16 SeqNum;
1198+ /** Result */
1199+ u16 Result;
1200+} __ATTRIB_PACK__ HostCmd_DS_GEN;
1201+
1202+/** Size of HostCmd_DS_GEN */
1203+#define S_DS_GEN sizeof(HostCmd_DS_GEN)
1204+
1205+/** _HostCmd_HEADER*/
1206+typedef struct
1207+{
1208+ /** Command Header : Command */
1209+ u16 Command;
1210+ /** Command Header : Size */
1211+ u16 Size;
1212+} __ATTRIB_PACK__ HostCmd_HEADER;
1213+
1214+/** HostCmd_SYS_CONFIG */
1215+typedef struct _HostCmd_SYS_CONFIG
1216+{
1217+ /** CMD Action GET/SET*/
1218+ u16 Action;
1219+ /** Tlv buffer */
1220+ u8 TlvBuffer[0];
1221+} __ATTRIB_PACK__ HostCmd_SYS_CONFIG;
1222+
1223+/** HostCmd_DS_POWER_MGMT_EXT */
1224+typedef struct _HostCmd_DS_POWER_MGMT_EXT
1225+{
1226+ /** CMD Action Get/Set*/
1227+ u16 action;
1228+ /** power mode */
1229+ u16 power_mode;
1230+} __ATTRIB_PACK__ HostCmd_DS_POWER_MGMT_EXT;
1231+
1232+/** _HostCmd_DS_COMMAND*/
1233+typedef struct _HostCmd_DS_COMMAND
1234+{
1235+
1236+ /** Command Header : Command */
1237+ u16 Command;
1238+ /** Command Header : Size */
1239+ u16 Size;
1240+ /** Command Header : Sequence number */
1241+ u16 SeqNum;
1242+ /** Command Header : Result */
1243+ u16 Result;
1244+ /** Command Body */
1245+ union
1246+ {
1247+ HostCmd_SYS_CONFIG sys_config;
1248+ HostCmd_DS_POWER_MGMT_EXT pm_cfg;
1249+
1250+ } params;
1251+} __ATTRIB_PACK__ HostCmd_DS_COMMAND;
1252+
1253+/** MrvlIEtypesHeader_*/
1254+typedef struct _MrvlIEtypesHeader
1255+{
1256+ /** Header type */
1257+ u16 Type;
1258+ /** Header length */
1259+ u16 Len;
1260+} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
1261+
1262+/** MrvlIEtypes_Data_t */
1263+typedef struct _MrvlIEtypes_Data_t
1264+{
1265+ /** Header */
1266+ MrvlIEtypesHeader_t Header;
1267+ /** Data */
1268+ u8 Data[1];
1269+} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
1270+
1271+/** MrvlIEtypes_ChanListParamSet_t */
1272+typedef struct _MrvlIEtypes_MacAddr_t
1273+{
1274+ /** Header */
1275+ MrvlIEtypesHeader_t Header;
1276+ /** AP MAC address */
1277+ u8 ApMacAddr[ETH_ALEN];
1278+} __ATTRIB_PACK__ MrvlIEtypes_MacAddr_t;
1279+
1280+/** Event ID: BSS started */
1281+#define MICRO_AP_EV_ID_BSS_START 46
1282+
1283+/** Event ID: BSS idle event */
1284+#define MICRO_AP_EV_BSS_IDLE 67
1285+
1286+/** Event ID: BSS active event */
1287+#define MICRO_AP_EV_BSS_ACTIVE 68
1288+
1289+/** Event ID: PS_AWAKE */
1290+#define EVENT_PS_AWAKE 0x0a
1291+
1292+/** Event ID: PS_SLEEP */
1293+#define EVENT_PS_SLEEP 0x0b
1294+
1295+/** PS_STATE */
1296+typedef enum _PS_STATE
1297+{
1298+ PS_STATE_AWAKE,
1299+ PS_STATE_PRE_SLEEP,
1300+ PS_STATE_SLEEP
1301+} PS_STATE;
1302+
1303+/** TLV type: AP Sleep param */
1304+#define TLV_TYPE_AP_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 106)
1305+/** TLV type: AP Inactivity Sleep param */
1306+#define TLV_TYPE_AP_INACT_SLEEP_PARAM (PROPRIETARY_TLV_BASE_ID + 107)
1307+
1308+/** MrvlIEtypes_sleep_param_t */
1309+typedef struct _MrvlIEtypes_sleep_param_t
1310+{
1311+ /** Header */
1312+ MrvlIEtypesHeader_t header;
1313+ /** control bitmap */
1314+ u32 ctrl_bitmap;
1315+ /** min_sleep */
1316+ u32 min_sleep;
1317+ /** max_sleep */
1318+ u32 max_sleep;
1319+} __ATTRIB_PACK__ MrvlIEtypes_sleep_param_t;
1320+
1321+/** MrvlIEtypes_inact_sleep_param_t */
1322+typedef struct _MrvlIEtypes_inact_sleep_param_t
1323+{
1324+ /** Header */
1325+ MrvlIEtypesHeader_t header;
1326+ /** inactivity timeout */
1327+ u32 inactivity_to;
1328+ /** min_awake */
1329+ u32 min_awake;
1330+ /** max_awake */
1331+ u32 max_awake;
1332+} __ATTRIB_PACK__ MrvlIEtypes_inact_sleep_param_t;
1333+
1334+/** AP_Event */
1335+typedef struct _AP_Event
1336+{
1337+ /** Event ID */
1338+ u32 EventId;
1339+ /*
1340+ * Reserved for STA_ASSOCIATED event and contains
1341+ * status information for the MIC_COUNTERMEASURES event.
1342+ */
1343+ /** Reserved/status */
1344+ u16 status;
1345+ /** AP MAC address */
1346+ u8 MacAddr[ETH_ALEN];
1347+} __ATTRIB_PACK__ AP_Event;
1348+#endif /* _UAP_FW_H */
1349diff --git a/drivers/net/wireless/libertas_uap/uap_headers.h b/drivers/net/wireless/libertas_uap/uap_headers.h
1350new file mode 100644
1351index 0000000..fa09af4
1352--- /dev/null
1353+++ b/drivers/net/wireless/libertas_uap/uap_headers.h
1354@@ -0,0 +1,64 @@
1355+/** @file uap_headers.h
1356+ *
1357+ * @brief This file contains all the necessary include file.
1358+ *
1359+ * Copyright (C) 2008-2009, Marvell International Ltd.
1360+ *
1361+ * This software file (the "File") is distributed by Marvell International
1362+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
1363+ * (the "License"). You may use, redistribute and/or modify this File in
1364+ * accordance with the terms and conditions of the License, a copy of which
1365+ * is available along with the File in the gpl.txt file or by writing to
1366+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1367+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
1368+ *
1369+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
1370+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
1371+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
1372+ * this warranty disclaimer.
1373+ *
1374+ */
1375+#ifndef _UAP_HEADERS_H
1376+#define _UAP_HEADERS_H
1377+
1378+/* Linux header files */
1379+#include <linux/kernel.h>
1380+#include <linux/module.h>
1381+#include <linux/init.h>
1382+#include <linux/version.h>
1383+#include <linux/param.h>
1384+#include <linux/types.h>
1385+#include <linux/interrupt.h>
1386+#include <linux/proc_fs.h>
1387+#include <linux/kthread.h>
1388+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
1389+#include <linux/semaphore.h>
1390+#else
1391+#include <asm/semaphore.h>
1392+#endif
1393+
1394+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
1395+#include <linux/config.h>
1396+#endif
1397+
1398+/* Net header files */
1399+#include <linux/netdevice.h>
1400+#include <linux/net.h>
1401+#include <linux/skbuff.h>
1402+#include <linux/if_ether.h>
1403+#include <linux/etherdevice.h>
1404+#include <net/sock.h>
1405+#include <linux/netlink.h>
1406+#include <linux/firmware.h>
1407+#include <linux/delay.h>
1408+
1409+#include "uap_drv.h"
1410+#include "uap_fw.h"
1411+
1412+#include <linux/mmc/sdio.h>
1413+#include <linux/mmc/sdio_ids.h>
1414+#include <linux/mmc/sdio_func.h>
1415+#include <linux/mmc/card.h>
1416+#include "uap_sdio_mmc.h"
1417+
1418+#endif /* _UAP_HEADERS_H */
1419diff --git a/drivers/net/wireless/libertas_uap/uap_main.c b/drivers/net/wireless/libertas_uap/uap_main.c
1420new file mode 100644
1421index 0000000..6ad8403
1422--- /dev/null
1423+++ b/drivers/net/wireless/libertas_uap/uap_main.c
1424@@ -0,0 +1,1817 @@
1425+/** @file uap_main.c
1426+ * @brief This file contains the major functions in uAP
1427+ * driver. It includes init, exit etc..
1428+ * This file also contains the initialization for SW,
1429+ * FW and HW
1430+ *
1431+ * Copyright (C) 2008-2009, Marvell International Ltd.
1432+ *
1433+ * This software file (the "File") is distributed by Marvell International
1434+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
1435+ * (the "License"). You may use, redistribute and/or modify this File in
1436+ * accordance with the terms and conditions of the License, a copy of which
1437+ * is available along with the File in the gpl.txt file or by writing to
1438+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1439+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
1440+ *
1441+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
1442+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
1443+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
1444+ * this warranty disclaimer.
1445+ *
1446+ */
1447+/**
1448+ * @mainpage uAP Linux Driver
1449+ *
1450+ * @section overview_sec Overview
1451+ *
1452+ * This is Linux reference driver for Marvell uAP.
1453+ *
1454+ * @section copyright_sec Copyright
1455+ *
1456+ * Copyright (C) 2008, Marvell International Ltd.
1457+ *
1458+ */
1459+
1460+#include "uap_headers.h"
1461+
1462+/**
1463+ * the global variable of a pointer to uap_private
1464+ * structure variable
1465+ */
1466+uap_private *uappriv = NULL;
1467+#ifdef DEBUG_LEVEL1
1468+#define DEFAULT_DEBUG_MASK (DBG_MSG | DBG_FATAL | DBG_ERROR)
1469+u32 drvdbg = DEFAULT_DEBUG_MASK;
1470+#endif
1471+/** Helper name */
1472+char *helper_name = NULL;
1473+/** Firmware name */
1474+char *fw_name = NULL;
1475+
1476+/** Semaphore for add/remove card */
1477+SEMAPHORE AddRemoveCardSem;
1478+
1479+/********************************************************
1480+ Local Functions
1481+********************************************************/
1482+/**
1483+ * @brief This function send sleep confirm command to firmware
1484+ *
1485+ * @param priv A pointer to uap_private structure
1486+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
1487+ */
1488+static int
1489+uap_dnld_sleep_confirm_cmd(uap_private * priv)
1490+{
1491+ uap_adapter *Adapter = priv->adapter;
1492+ int ret = UAP_STATUS_SUCCESS;
1493+ ENTER();
1494+ PRINTM(CMND, "Sleep confirm\n");
1495+ Adapter->cmd_pending = TRUE;
1496+ Adapter->cmd_wait_option = HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM;
1497+ ret =
1498+ sbi_host_to_card(priv, (u8 *) & Adapter->PSConfirmSleep,
1499+ sizeof(PS_CMD_ConfirmSleep));
1500+ if (ret != UAP_STATUS_SUCCESS) {
1501+ Adapter->ps_state = PS_STATE_AWAKE;
1502+ Adapter->cmd_pending = FALSE;
1503+ Adapter->cmd_wait_option = FALSE;
1504+ }
1505+ LEAVE();
1506+ return ret;
1507+}
1508+
1509+/**
1510+ * @brief This function process sleep confirm resp from firmware
1511+ *
1512+ * @param priv A pointer to uap_private structure
1513+ * @param resp A pointer to resp buf
1514+ * @param resp_len resp buf len
1515+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
1516+ */
1517+int
1518+uap_process_sleep_confirm_resp(uap_private * priv, u8 * resp, int resp_len)
1519+{
1520+ int ret = UAP_STATUS_SUCCESS;
1521+ HostCmd_DS_COMMAND *cmd;
1522+ uap_adapter *Adapter = priv->adapter;
1523+ ENTER();
1524+ PRINTM(CMND, "Sleep confirm resp\n");
1525+ if (!resp_len) {
1526+ PRINTM(ERROR, "Cmd Size is 0\n");
1527+ ret = -EFAULT;
1528+ goto done;
1529+ }
1530+ cmd = (HostCmd_DS_COMMAND *) resp;
1531+ cmd->Result = uap_le16_to_cpu(cmd->Result);
1532+ if (cmd->Result != UAP_STATUS_SUCCESS) {
1533+ PRINTM(ERROR, "HOST_CMD_APCMD_PS_SLEEP_CONFIRM fail=%x\n", cmd->Result);
1534+ ret = -EFAULT;
1535+ }
1536+ done:
1537+ if (ret == UAP_STATUS_SUCCESS)
1538+ Adapter->ps_state = PS_STATE_SLEEP;
1539+ else
1540+ Adapter->ps_state = PS_STATE_AWAKE;
1541+ LEAVE();
1542+ return ret;
1543+}
1544+
1545+/**
1546+ * @brief This function checks condition and prepares to
1547+ * send sleep confirm command to firmware if OK.
1548+ *
1549+ * @param priv A pointer to uap_private structure
1550+ * @return n/a
1551+ */
1552+static void
1553+uap_ps_cond_check(uap_private * priv)
1554+{
1555+ uap_adapter *Adapter = priv->adapter;
1556+
1557+ ENTER();
1558+ if (!priv->uap_dev.cmd_sent &&
1559+ !Adapter->cmd_pending && !Adapter->IntCounter) {
1560+ uap_dnld_sleep_confirm_cmd(priv);
1561+ } else {
1562+ PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
1563+ (priv->uap_dev.cmd_sent) ? "D" : "",
1564+ (Adapter->cmd_pending) ? "C" : "",
1565+ (Adapter->IntCounter) ? "I" : "");
1566+ }
1567+ LEAVE();
1568+}
1569+
1570+/**
1571+ * @brief This function add cmd to cmdQ and waiting for response
1572+ *
1573+ * @param priv A pointer to uap_private structure
1574+ * @param skb A pointer to the skb for process
1575+ * @param wait_option Wait option
1576+ * @return UAP_STATUS_SUCCESS for success otherwise UAP_STATUS_FAILURE
1577+ */
1578+static int
1579+uap_process_cmd(uap_private * priv, struct sk_buff *skb, u8 wait_option)
1580+{
1581+ uap_adapter *Adapter = priv->adapter;
1582+ int ret = UAP_STATUS_SUCCESS;
1583+ HostCmd_DS_COMMAND *cmd;
1584+ u8 *headptr;
1585+ ENTER();
1586+ if (Adapter->HardwareStatus != HWReady) {
1587+ PRINTM(ERROR, "Hw not ready, uap_process_cmd\n");
1588+ kfree(skb);
1589+ LEAVE();
1590+ return -EFAULT;
1591+ }
1592+ skb->cb[0] = wait_option;
1593+ headptr = skb->data;
1594+ *(u16 *) & headptr[0] = uap_cpu_to_le16(skb->len);
1595+ *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_CMD);
1596+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
1597+ Adapter->SeqNum++;
1598+ cmd->SeqNum = uap_cpu_to_le16(Adapter->SeqNum);
1599+ PRINTM(CMND, "process_cmd: %x\n", cmd->Command);
1600+ DBG_HEXDUMP(CMD_D, "process_cmd", (u8 *) cmd, cmd->Size);
1601+ if (!wait_option) {
1602+ skb_queue_tail(&priv->adapter->cmd_queue, skb);
1603+ wake_up_interruptible(&priv->MainThread.waitQ);
1604+ LEAVE();
1605+ return ret;
1606+ }
1607+ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->CmdSem)) {
1608+ PRINTM(ERROR, "Acquire semaphore error, uap_prepare_cmd\n");
1609+ kfree(skb);
1610+ LEAVE();
1611+ return -EBUSY;
1612+ }
1613+ skb_queue_tail(&priv->adapter->cmd_queue, skb);
1614+ Adapter->CmdWaitQWoken = FALSE;
1615+ wake_up_interruptible(&priv->MainThread.waitQ);
1616+ /* Sleep until response is generated by FW */
1617+ if (wait_option == HostCmd_OPTION_WAITFORRSP_TIMEOUT) {
1618+ if (!os_wait_interruptible_timeout
1619+ (Adapter->cmdwait_q, Adapter->CmdWaitQWoken, MRVDRV_TIMER_20S)) {
1620+ PRINTM(ERROR, "Cmd timeout\n");
1621+ Adapter->cmd_pending = FALSE;
1622+ ret = -EFAULT;
1623+ }
1624+ } else
1625+ wait_event_interruptible(Adapter->cmdwait_q, Adapter->CmdWaitQWoken);
1626+ OS_REL_SEMAPHORE(&Adapter->CmdSem);
1627+ LEAVE();
1628+ return ret;
1629+}
1630+
1631+/**
1632+ * @brief Inspect the response buffer for pointers to expected TLVs
1633+ *
1634+ *
1635+ * @param pTlv Pointer to the start of the TLV buffer to parse
1636+ * @param tlvBufSize Size of the TLV buffer
1637+ * @param reqTlvType request tlv's tlvtype
1638+ * @param ppTlv Output parameter: Pointer to the request TLV if found
1639+ *
1640+ * @return void
1641+ */
1642+static void
1643+uap_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv, int tlvBufSize,
1644+ u16 reqTlvType, MrvlIEtypes_Data_t ** ppTlv)
1645+{
1646+ MrvlIEtypes_Data_t *pCurrentTlv;
1647+ int tlvBufLeft;
1648+ u16 tlvType;
1649+ u16 tlvLen;
1650+
1651+ ENTER();
1652+ pCurrentTlv = pTlv;
1653+ tlvBufLeft = tlvBufSize;
1654+ *ppTlv = NULL;
1655+ PRINTM(INFO, "uap_get_tlv: tlvBufSize = %d, reqTlvType=%x\n", tlvBufSize,
1656+ reqTlvType);
1657+ while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
1658+ tlvType = uap_le16_to_cpu(pCurrentTlv->Header.Type);
1659+ tlvLen = uap_le16_to_cpu(pCurrentTlv->Header.Len);
1660+ if (reqTlvType == tlvType)
1661+ *ppTlv = (MrvlIEtypes_Data_t *) pCurrentTlv;
1662+ if (*ppTlv) {
1663+ HEXDUMP("TLV Buf", (u8 *) * ppTlv, tlvLen);
1664+ break;
1665+ }
1666+ tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
1667+ pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
1668+ } /* while */
1669+ LEAVE();
1670+}
1671+
1672+/**
1673+ * @brief This function get mac
1674+ *
1675+ * @param priv A pointer to uap_private structure
1676+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
1677+ */
1678+static int
1679+uap_get_mac_address(uap_private * priv)
1680+{
1681+ int ret = UAP_STATUS_SUCCESS;
1682+ u32 CmdSize;
1683+ HostCmd_DS_COMMAND *cmd;
1684+ uap_adapter *Adapter = priv->adapter;
1685+ struct sk_buff *skb;
1686+ MrvlIEtypes_MacAddr_t *pMacAddrTlv;
1687+ MrvlIEtypes_Data_t *pTlv;
1688+ u16 tlvBufSize;
1689+ ENTER();
1690+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
1691+ if (!skb) {
1692+ PRINTM(ERROR, "No free skb\n");
1693+ ret = -ENOMEM;
1694+ goto done;
1695+ }
1696+ CmdSize =
1697+ S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
1698+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
1699+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
1700+ cmd->Size = uap_cpu_to_le16(CmdSize);
1701+ cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_GET);
1702+ pMacAddrTlv =
1703+ (MrvlIEtypes_MacAddr_t *) (skb->data + INTF_HEADER_LEN + S_DS_GEN +
1704+ sizeof(HostCmd_SYS_CONFIG));
1705+ pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
1706+ pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
1707+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
1708+ if (UAP_STATUS_SUCCESS !=
1709+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
1710+ PRINTM(ERROR, "Fail to process cmd SYS_CONFIGURE Query\n");
1711+ ret = -EFAULT;
1712+ goto done;
1713+ }
1714+ if (!Adapter->CmdSize) {
1715+ PRINTM(ERROR, "Cmd Size is 0\n");
1716+ ret = -EFAULT;
1717+ goto done;
1718+ }
1719+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
1720+ cmd->Result = uap_le16_to_cpu(cmd->Result);
1721+ if (cmd->Result != UAP_STATUS_SUCCESS) {
1722+ PRINTM(ERROR, "uap_get_mac_address fail=%x\n", cmd->Result);
1723+ ret = -EFAULT;
1724+ goto done;
1725+ }
1726+ pTlv =
1727+ (MrvlIEtypes_Data_t *) (Adapter->CmdBuf + S_DS_GEN +
1728+ sizeof(HostCmd_SYS_CONFIG));
1729+ tlvBufSize = Adapter->CmdSize - S_DS_GEN - sizeof(HostCmd_SYS_CONFIG);
1730+ uap_get_tlv_ptrs(pTlv, tlvBufSize, MRVL_AP_MAC_ADDRESS_TLV_ID,
1731+ (MrvlIEtypes_Data_t **) & pMacAddrTlv);
1732+ if (pMacAddrTlv) {
1733+ memcpy(priv->uap_dev.netdev->dev_addr, pMacAddrTlv->ApMacAddr,
1734+ ETH_ALEN);
1735+ HEXDUMP("Original MAC addr", priv->uap_dev.netdev->dev_addr, ETH_ALEN);
1736+ }
1737+ done:
1738+ LEAVE();
1739+ return ret;
1740+}
1741+
1742+/**
1743+ * @brief This function checks the conditions and sends packet to device
1744+ *
1745+ * @param priv A pointer to uap_private structure
1746+ * @param skb A pointer to the skb for process
1747+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
1748+ */
1749+static int
1750+uap_process_tx(uap_private * priv, struct sk_buff *skb)
1751+{
1752+ uap_adapter *Adapter = priv->adapter;
1753+ int ret = UAP_STATUS_SUCCESS;
1754+ TxPD *pLocalTxPD;
1755+ u8 *headptr;
1756+ struct sk_buff *newskb;
1757+ int newheadlen;
1758+ ENTER();
1759+ ASSERT(skb);
1760+ if (!skb) {
1761+ LEAVE();
1762+ return UAP_STATUS_FAILURE;
1763+ }
1764+ if (skb_headroom(skb) < (sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT)) {
1765+ newheadlen = sizeof(TxPD) + INTF_HEADER_LEN + HEADER_ALIGNMENT;
1766+ PRINTM(WARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
1767+ /* Insufficient skb headroom - allocate a new skb */
1768+ newskb = skb_realloc_headroom(skb, newheadlen);
1769+ if (unlikely(newskb == NULL)) {
1770+ PRINTM(ERROR, "Tx: Cannot allocate skb\n");
1771+ ret = UAP_STATUS_FAILURE;
1772+ goto done;
1773+ }
1774+ kfree_skb(skb);
1775+ skb = newskb;
1776+ PRINTM(INFO, "new skb headroom %d\n", skb_headroom(skb));
1777+ }
1778+ /* headptr should be aligned */
1779+ headptr = skb->data - sizeof(TxPD) - INTF_HEADER_LEN;
1780+ headptr = (u8 *) ((u32) headptr & ~((u32) (HEADER_ALIGNMENT - 1)));
1781+
1782+ pLocalTxPD = (TxPD *) (headptr + INTF_HEADER_LEN);
1783+ memset(pLocalTxPD, 0, sizeof(TxPD));
1784+ pLocalTxPD->BssType = PKT_TYPE_MICROAP;
1785+ pLocalTxPD->TxPktLength = skb->len;
1786+ /* offset of actual data */
1787+ pLocalTxPD->TxPktOffset = (long) skb->data - (long) pLocalTxPD;
1788+ endian_convert_TxPD(pLocalTxPD);
1789+ *(u16 *) & headptr[0] =
1790+ uap_cpu_to_le16(skb->len + ((long) skb->data - (long) headptr));
1791+ *(u16 *) & headptr[2] = uap_cpu_to_le16(MV_TYPE_DAT);
1792+ ret =
1793+ sbi_host_to_card(priv, headptr,
1794+ skb->len + ((long) skb->data - (long) headptr));
1795+ if (ret) {
1796+ PRINTM(ERROR, "uap_process_tx Error: sbi_host_to_card failed: 0x%X\n",
1797+ ret);
1798+ Adapter->dbg.num_tx_host_to_card_failure++;
1799+ goto done;
1800+ }
1801+ PRINTM(DATA, "Data => FW\n");
1802+ DBG_HEXDUMP(DAT_D, "Tx", headptr,
1803+ MIN(skb->len + sizeof(TxPD), DATA_DUMP_LEN));
1804+ done:
1805+ /* Freed skb */
1806+ kfree_skb(skb);
1807+ LEAVE();
1808+ return ret;
1809+}
1810+
1811+static struct netlink_kernel_cfg cfg = {
1812+ .groups = NL_MULTICAST_GROUP,
1813+};
1814+
1815+/**
1816+ * @brief This function initializes the adapter structure
1817+ * and set default value to the member of adapter.
1818+ *
1819+ * @param priv A pointer to uap_private structure
1820+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
1821+ */
1822+static int
1823+uap_init_sw(uap_private * priv)
1824+{
1825+ uap_adapter *Adapter = priv->adapter;
1826+
1827+ ENTER();
1828+
1829+ if (!(Adapter->CmdBuf = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
1830+ PRINTM(INFO, "Failed to allocate command buffer!\n");
1831+ LEAVE();
1832+ return UAP_STATUS_FAILURE;
1833+ }
1834+
1835+ Adapter->cmd_pending = FALSE;
1836+ Adapter->CmdWaitQWoken = FALSE;
1837+ Adapter->ps_state = PS_STATE_AWAKE;
1838+ Adapter->WakeupTries = 0;
1839+
1840+ memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
1841+ /** SDIO header */
1842+ Adapter->PSConfirmSleep.SDLen =
1843+ uap_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
1844+ Adapter->PSConfirmSleep.SDType = uap_cpu_to_le16(MV_TYPE_CMD);
1845+ Adapter->PSConfirmSleep.SeqNum = 0;
1846+ Adapter->PSConfirmSleep.Command = uap_cpu_to_le16(HOST_CMD_SLEEP_CONFIRM);
1847+ Adapter->PSConfirmSleep.Size = uap_cpu_to_le16(sizeof(HostCmd_DS_GEN));
1848+ Adapter->PSConfirmSleep.Result = 0;
1849+
1850+ init_waitqueue_head(&Adapter->cmdwait_q);
1851+ OS_INIT_SEMAPHORE(&Adapter->CmdSem);
1852+
1853+ skb_queue_head_init(&Adapter->tx_queue);
1854+ skb_queue_head_init(&Adapter->cmd_queue);
1855+
1856+ /* Status variable */
1857+ Adapter->HardwareStatus = HWInitializing;
1858+
1859+ /* PnP support */
1860+ Adapter->SurpriseRemoved = FALSE;
1861+
1862+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
1863+ Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
1864+ NL_MULTICAST_GROUP, NULL,
1865+ THIS_MODULE);
1866+#else
1867+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
1868+ Adapter->nl_sk = netlink_kernel_create(NETLINK_MARVELL,
1869+ NL_MULTICAST_GROUP, NULL, NULL,
1870+ THIS_MODULE);
1871+#else
1872+ Adapter->nl_sk = netlink_kernel_create(&init_net, NETLINK_MARVELL, &cfg);
1873+#endif
1874+#endif
1875+ if (!Adapter->nl_sk) {
1876+ PRINTM(ERROR,
1877+ "Could not initialize netlink event passing mechanism!\n");
1878+ }
1879+ LEAVE();
1880+ return UAP_STATUS_SUCCESS;
1881+}
1882+
1883+/**
1884+ * @brief This function sends FUNC_INIT command to firmware
1885+ *
1886+ * @param priv A pointer to uap_private structure
1887+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
1888+ */
1889+static int
1890+uap_func_init(uap_private * priv)
1891+{
1892+ int ret = UAP_STATUS_SUCCESS;
1893+ u32 CmdSize;
1894+ HostCmd_DS_GEN *cmd;
1895+ uap_adapter *Adapter = priv->adapter;
1896+ struct sk_buff *skb;
1897+ ENTER();
1898+ if (Adapter->HardwareStatus != HWReady) {
1899+ PRINTM(ERROR, "uap_func_init:Hardware is not ready!\n");
1900+ ret = -EFAULT;
1901+ goto done;
1902+ }
1903+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
1904+ if (!skb) {
1905+ PRINTM(ERROR, "No free skb\n");
1906+ ret = -ENOMEM;
1907+ goto done;
1908+ }
1909+ CmdSize = sizeof(HostCmd_DS_GEN);
1910+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
1911+ cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_INIT);
1912+ cmd->Size = uap_cpu_to_le16(CmdSize);
1913+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
1914+ PRINTM(CMND, "HostCmd_CMD_FUNC_INIT\n");
1915+ if (UAP_STATUS_SUCCESS !=
1916+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
1917+ PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_INIT\n");
1918+ ret = -EFAULT;
1919+ goto done;
1920+ }
1921+ done:
1922+ LEAVE();
1923+ return ret;
1924+}
1925+
1926+/**
1927+ * @brief This function sends FUNC_SHUTDOWN command to firmware
1928+ *
1929+ * @param priv A pointer to uap_private structure
1930+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
1931+ */
1932+static int __exit
1933+uap_func_shutdown(uap_private * priv)
1934+{
1935+ int ret = UAP_STATUS_SUCCESS;
1936+ u32 CmdSize;
1937+ HostCmd_DS_GEN *cmd;
1938+ uap_adapter *Adapter = priv->adapter;
1939+ struct sk_buff *skb;
1940+ ENTER();
1941+ if (Adapter->HardwareStatus != HWReady) {
1942+ PRINTM(ERROR, "uap_func_shutdown:Hardware is not ready!\n");
1943+ ret = -EFAULT;
1944+ goto done;
1945+ }
1946+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
1947+ if (!skb) {
1948+ PRINTM(ERROR, "No free skb\n");
1949+ ret = -ENOMEM;
1950+ goto done;
1951+ }
1952+ CmdSize = sizeof(HostCmd_DS_GEN);
1953+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
1954+ cmd->Command = uap_cpu_to_le16(HostCmd_CMD_FUNC_SHUTDOWN);
1955+ cmd->Size = uap_cpu_to_le16(CmdSize);
1956+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
1957+ PRINTM(CMND, "HostCmd_CMD_FUNC_SHUTDOWN\n");
1958+ if (UAP_STATUS_SUCCESS !=
1959+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
1960+ PRINTM(ERROR, "Fail to process cmd HostCmd_CMD_FUNC_SHUTDOWN\n");
1961+ ret = -EFAULT;
1962+ goto done;
1963+ }
1964+ done:
1965+ LEAVE();
1966+ return ret;
1967+}
1968+
1969+/**
1970+ * @brief This function initializes firmware
1971+ *
1972+ * @param priv A pointer to uap_private structure
1973+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
1974+ */
1975+static int
1976+uap_init_fw(uap_private * priv)
1977+{
1978+ int ret = UAP_STATUS_SUCCESS;
1979+ ENTER();
1980+ sbi_disable_host_int(priv);
1981+ /* Check if firmware is already running */
1982+ if (sbi_check_fw_status(priv, 1) == UAP_STATUS_SUCCESS) {
1983+ PRINTM(MSG, "UAP FW already running! Skip FW download\n");
1984+ } else {
1985+ if ((ret = request_firmware(&priv->fw_helper, helper_name,
1986+ priv->hotplug_device)) < 0) {
1987+ PRINTM(FATAL,
1988+ "request_firmware() failed (helper), error code = %#x\n",
1989+ ret);
1990+ goto done;
1991+ }
1992+
1993+ /* Download the helper */
1994+ ret = sbi_prog_helper(priv);
1995+
1996+ if (ret) {
1997+ PRINTM(FATAL,
1998+ "Bootloader in invalid state! Helper download failed!\n");
1999+ ret = UAP_STATUS_FAILURE;
2000+ goto done;
2001+ }
2002+ if ((ret = request_firmware(&priv->firmware, fw_name,
2003+ priv->hotplug_device)) < 0) {
2004+ PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
2005+ goto done;
2006+ }
2007+
2008+ /* Download the main firmware via the helper firmware */
2009+ if (sbi_prog_fw_w_helper(priv)) {
2010+ PRINTM(FATAL, "UAP FW download failed!\n");
2011+ ret = UAP_STATUS_FAILURE;
2012+ goto done;
2013+ }
2014+ /* Check if the firmware is downloaded successfully or not */
2015+ if (sbi_check_fw_status(priv, MAX_FIRMWARE_POLL_TRIES) ==
2016+ UAP_STATUS_FAILURE) {
2017+ PRINTM(FATAL, "FW failed to be active in time!\n");
2018+ ret = UAP_STATUS_FAILURE;
2019+ goto done;
2020+ }
2021+ PRINTM(MSG, "UAP FW is active\n");
2022+ }
2023+ sbi_enable_host_int(priv);
2024+ priv->adapter->HardwareStatus = HWReady;
2025+ if (uap_func_init(priv) != UAP_STATUS_SUCCESS) {
2026+ ret = UAP_STATUS_FAILURE;
2027+ goto done;
2028+ }
2029+ done:
2030+ if (priv->fw_helper)
2031+ release_firmware(priv->fw_helper);
2032+ if (priv->firmware)
2033+ release_firmware(priv->firmware);
2034+ LEAVE();
2035+ return ret;
2036+
2037+}
2038+
2039+/**
2040+ * @brief This function frees the structure of adapter
2041+ *
2042+ * @param priv A pointer to uap_private structure
2043+ * @return n/a
2044+ */
2045+static void
2046+uap_free_adapter(uap_private * priv)
2047+{
2048+ uap_adapter *Adapter = priv->adapter;
2049+
2050+ ENTER();
2051+
2052+ if (Adapter) {
2053+ if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
2054+ sock_release((Adapter->nl_sk)->sk_socket);
2055+ Adapter->nl_sk = NULL;
2056+ }
2057+ if (Adapter->CmdBuf)
2058+ kfree(Adapter->CmdBuf);
2059+ skb_queue_purge(&priv->adapter->tx_queue);
2060+ skb_queue_purge(&priv->adapter->cmd_queue);
2061+ /* Free the adapter object itself */
2062+ kfree(Adapter);
2063+ priv->adapter = NULL;
2064+ }
2065+
2066+ LEAVE();
2067+}
2068+
2069+/**
2070+ * @brief This function handles the major job in uap driver.
2071+ * it handles the event generated by firmware, rx data received
2072+ * from firmware and tx data sent from kernel.
2073+ *
2074+ * @param data A pointer to uap_thread structure
2075+ * @return BT_STATUS_SUCCESS
2076+ */
2077+static int
2078+uap_service_main_thread(void *data)
2079+{
2080+ uap_thread *thread = data;
2081+ uap_private *priv = thread->priv;
2082+ uap_adapter *Adapter = priv->adapter;
2083+ wait_queue_t wait;
2084+ u8 ireg = 0;
2085+ struct sk_buff *skb;
2086+ ENTER();
2087+ uap_activate_thread(thread);
2088+ init_waitqueue_entry(&wait, current);
2089+ current->flags |= PF_NOFREEZE;
2090+
2091+ for (;;) {
2092+ add_wait_queue(&thread->waitQ, &wait);
2093+ OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
2094+ if ((Adapter->WakeupTries) ||
2095+ (!Adapter->IntCounter && Adapter->ps_state == PS_STATE_PRE_SLEEP) ||
2096+ (!priv->adapter->IntCounter
2097+ && (priv->uap_dev.data_sent ||
2098+ skb_queue_empty(&priv->adapter->tx_queue))
2099+ && (priv->uap_dev.cmd_sent || Adapter->cmd_pending ||
2100+ skb_queue_empty(&priv->adapter->cmd_queue))
2101+ )) {
2102+ PRINTM(INFO, "Main: Thread sleeping...\n");
2103+ schedule();
2104+ }
2105+ OS_SET_THREAD_STATE(TASK_RUNNING);
2106+ remove_wait_queue(&thread->waitQ, &wait);
2107+ if (kthread_should_stop() || Adapter->SurpriseRemoved) {
2108+ PRINTM(INFO, "main-thread: break from main thread: "
2109+ "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
2110+ /* Cancel pending command */
2111+ if (Adapter->cmd_pending == TRUE) {
2112+ /* Wake up cmd Q */
2113+ Adapter->CmdWaitQWoken = TRUE;
2114+ wake_up_interruptible(&Adapter->cmdwait_q);
2115+ }
2116+ break;
2117+ }
2118+
2119+ PRINTM(INFO, "Main: Thread waking up...\n");
2120+ if (priv->adapter->IntCounter) {
2121+ OS_INT_DISABLE;
2122+ Adapter->IntCounter = 0;
2123+ OS_INT_RESTORE;
2124+ sbi_get_int_status(priv, &ireg);
2125+ } else if ((priv->adapter->ps_state == PS_STATE_SLEEP) &&
2126+ (!skb_queue_empty(&priv->adapter->cmd_queue) ||
2127+ !skb_queue_empty(&priv->adapter->tx_queue))) {
2128+ priv->adapter->WakeupTries++;
2129+ PRINTM(CMND, "%lu : Wakeup device...\n", os_time_get());
2130+ sbi_wakeup_firmware(priv);
2131+ continue;
2132+ }
2133+ if (Adapter->ps_state == PS_STATE_PRE_SLEEP)
2134+ uap_ps_cond_check(priv);
2135+
2136+ /* The PS state is changed during processing of Sleep Request event
2137+ above */
2138+ if ((Adapter->ps_state == PS_STATE_SLEEP) ||
2139+ (Adapter->ps_state == PS_STATE_PRE_SLEEP))
2140+ continue;
2141+ /* Execute the next command */
2142+ if (!priv->uap_dev.cmd_sent && !Adapter->cmd_pending &&
2143+ (Adapter->HardwareStatus == HWReady)) {
2144+ if (!skb_queue_empty(&priv->adapter->cmd_queue)) {
2145+ skb = skb_dequeue(&priv->adapter->cmd_queue);
2146+ if (skb) {
2147+ Adapter->CmdSize = 0;
2148+ Adapter->cmd_pending = TRUE;
2149+ Adapter->cmd_wait_option = skb->cb[0];
2150+ if (sbi_host_to_card(priv, skb->data, skb->len)) {
2151+ PRINTM(ERROR, "Cmd:sbi_host_to_card failed!\n");
2152+ Adapter->cmd_pending = FALSE;
2153+ Adapter->dbg.num_cmd_host_to_card_failure++;
2154+ /* Wake up cmd Q */
2155+ Adapter->CmdWaitQWoken = TRUE;
2156+ wake_up_interruptible(&Adapter->cmdwait_q);
2157+ } else {
2158+ if (Adapter->cmd_wait_option ==
2159+ HostCmd_OPTION_WAITFORSEND) {
2160+ /* Wake up cmd Q */
2161+ Adapter->CmdWaitQWoken = TRUE;
2162+ wake_up_interruptible(&Adapter->cmdwait_q);
2163+ Adapter->cmd_wait_option = FALSE;
2164+ }
2165+ }
2166+ kfree_skb(skb);
2167+ }
2168+ }
2169+ }
2170+ if (!priv->uap_dev.data_sent && (Adapter->HardwareStatus == HWReady)) {
2171+ if (!skb_queue_empty(&priv->adapter->tx_queue)) {
2172+ skb = skb_dequeue(&priv->adapter->tx_queue);
2173+ if (skb) {
2174+ if (uap_process_tx(priv, skb)) {
2175+ priv->stats.tx_dropped++;
2176+ priv->stats.tx_errors++;
2177+ os_start_queue(priv);
2178+ } else {
2179+ priv->stats.tx_packets++;
2180+ priv->stats.tx_bytes += skb->len;
2181+ }
2182+
2183+ }
2184+ }
2185+ }
2186+ }
2187+ uap_deactivate_thread(thread);
2188+ LEAVE();
2189+ return UAP_STATUS_SUCCESS;
2190+}
2191+
2192+/**
2193+ * @brief uap hostcmd ioctl handler
2194+ *
2195+ * @param dev A pointer to net_device structure
2196+ * @param req A pointer to ifreq structure
2197+ * @return UAP_STATUS_SUCCESS --success, otherwise fail
2198+ */
2199+/********* format of ifr_data *************/
2200+/* buf_len + Hostcmd_body */
2201+/* buf_len: 4 bytes */
2202+/* the length of the buf which */
2203+/* can be used to return data */
2204+/* to application */
2205+/* Hostcmd_body */
2206+/*******************************************/
2207+static int
2208+uap_hostcmd_ioctl(struct net_device *dev, struct ifreq *req)
2209+{
2210+ u32 buf_len;
2211+ HostCmd_HEADER head;
2212+ uap_private *priv = (uap_private *) netdev_priv(dev);
2213+ uap_adapter *Adapter = priv->adapter;
2214+ int ret = UAP_STATUS_SUCCESS;
2215+ struct sk_buff *skb;
2216+
2217+ ENTER();
2218+
2219+ /* Sanity check */
2220+ if (req->ifr_data == NULL) {
2221+ PRINTM(ERROR, "uap_hostcmd_ioctl() corrupt data\n");
2222+ LEAVE();
2223+ return -EFAULT;
2224+ }
2225+ if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) {
2226+ PRINTM(ERROR, "Copy from user failed\n");
2227+ LEAVE();
2228+ return -EFAULT;
2229+ }
2230+ memset(&head, 0, sizeof(HostCmd_HEADER));
2231+ /* Get the command size from user space */
2232+ if (copy_from_user
2233+ (&head, req->ifr_data + sizeof(buf_len), sizeof(HostCmd_HEADER))) {
2234+ PRINTM(ERROR, "Copy from user failed\n");
2235+ LEAVE();
2236+ return -EFAULT;
2237+ }
2238+ head.Size = uap_le16_to_cpu(head.Size);
2239+ if (head.Size > MRVDRV_SIZE_OF_CMD_BUFFER) {
2240+ PRINTM(ERROR, "CmdSize too big=%d\n", head.Size);
2241+ LEAVE();
2242+ return -EFAULT;
2243+ }
2244+ PRINTM(CMND, "ioctl: hostcmd=%x, size=%d,buf_len=%d\n", head.Command,
2245+ head.Size, buf_len);
2246+ skb = dev_alloc_skb(head.Size + INTF_HEADER_LEN);
2247+ if (!skb) {
2248+ PRINTM(ERROR, "No free skb\n");
2249+ LEAVE();
2250+ return -ENOMEM;
2251+ }
2252+
2253+ /* Get the command from user space */
2254+ if (copy_from_user
2255+ (skb->data + INTF_HEADER_LEN, req->ifr_data + sizeof(buf_len),
2256+ head.Size)) {
2257+ PRINTM(ERROR, "Copy from user failed\n");
2258+ LEAVE();
2259+ return -EFAULT;
2260+ }
2261+ skb_put(skb, head.Size + INTF_HEADER_LEN);
2262+ if (UAP_STATUS_SUCCESS !=
2263+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
2264+ PRINTM(ERROR, "Fail to process cmd\n");
2265+ LEAVE();
2266+ return -EFAULT;
2267+ }
2268+ if (!Adapter->CmdSize) {
2269+ PRINTM(ERROR, "Cmd Size is 0\n");
2270+ LEAVE();
2271+ return -EFAULT;
2272+ }
2273+ if (Adapter->CmdSize > buf_len) {
2274+ PRINTM(ERROR, "buf_len is too small\n");
2275+ LEAVE();
2276+ return -EFAULT;
2277+ }
2278+ /* Copy to user */
2279+ if (copy_to_user
2280+ (req->ifr_data + sizeof(buf_len), Adapter->CmdBuf, Adapter->CmdSize)) {
2281+ PRINTM(ERROR, "Copy to user failed!\n");
2282+ LEAVE();
2283+ return -EFAULT;
2284+ }
2285+ LEAVE();
2286+ return ret;
2287+}
2288+
2289+/**
2290+ * @brief uap power mode ioctl handler
2291+ *
2292+ * @param dev A pointer to net_device structure
2293+ * @param req A pointer to ifreq structure
2294+ * @return UAP_STATUS_SUCCESS --success, otherwise fail
2295+ */
2296+static int
2297+uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
2298+{
2299+ ps_mgmt pm_cfg;
2300+ int ret = UAP_STATUS_SUCCESS;
2301+ uap_private *priv = (uap_private *) netdev_priv(dev);
2302+ uap_adapter *Adapter = priv->adapter;
2303+ struct sk_buff *skb = NULL;
2304+ HostCmd_DS_COMMAND *cmd;
2305+ u32 CmdSize;
2306+ u8 *tlv = NULL;
2307+ MrvlIEtypes_sleep_param_t *sleep_tlv = NULL;
2308+ MrvlIEtypes_inact_sleep_param_t *inact_tlv = NULL;
2309+ u16 tlv_buf_left = 0;
2310+ MrvlIEtypesHeader_t *tlvbuf = NULL;
2311+ u16 tlv_type = 0;
2312+ u16 tlv_len = 0;
2313+
2314+ ENTER();
2315+
2316+ /* Sanity check */
2317+ if (req->ifr_data == NULL) {
2318+ PRINTM(ERROR, "uap_power_mode_ioctl() corrupt data\n");
2319+ LEAVE();
2320+ return -EFAULT;
2321+ }
2322+
2323+ memset(&pm_cfg, 0, sizeof(ps_mgmt));
2324+ if (copy_from_user(&pm_cfg, req->ifr_data, sizeof(ps_mgmt))) {
2325+ PRINTM(ERROR, "Copy from user failed\n");
2326+ LEAVE();
2327+ return -EFAULT;
2328+ }
2329+ PRINTM(CMND,
2330+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
2331+ "inact_to=%d min_awake=%d max_awake=%d\n", pm_cfg.flags,
2332+ (int) pm_cfg.ps_mode, (int) pm_cfg.sleep_param.ctrl_bitmap,
2333+ (int) pm_cfg.sleep_param.min_sleep,
2334+ (int) pm_cfg.sleep_param.max_sleep,
2335+ (int) pm_cfg.inact_param.inactivity_to,
2336+ (int) pm_cfg.inact_param.min_awake,
2337+ (int) pm_cfg.inact_param.max_awake);
2338+
2339+ if (pm_cfg.
2340+ flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
2341+ PS_FLAG_INACT_SLEEP_PARAM)) {
2342+ PRINTM(ERROR, "Invalid parameter: flags = 0x%x\n", pm_cfg.flags);
2343+ ret = -EINVAL;
2344+ goto done;
2345+ }
2346+ if (pm_cfg.ps_mode > PS_MODE_INACTIVITY) {
2347+ PRINTM(ERROR, "Invalid parameter: ps_mode = %d\n", (int) pm_cfg.flags);
2348+ ret = -EINVAL;
2349+ goto done;
2350+ }
2351+
2352+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
2353+ if (!skb) {
2354+ PRINTM(INFO, "No free skb\n");
2355+ ret = -ENOMEM;
2356+ goto done;
2357+ }
2358+
2359+ CmdSize = S_DS_GEN + sizeof(HostCmd_DS_POWER_MGMT_EXT);
2360+
2361+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
2362+ cmd->Command = uap_cpu_to_le16(HOST_CMD_POWER_MGMT_EXT);
2363+ if (!pm_cfg.flags) {
2364+ cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_GET);
2365+ } else {
2366+ cmd->params.pm_cfg.action = uap_cpu_to_le16(ACTION_SET);
2367+ cmd->params.pm_cfg.power_mode = uap_cpu_to_le16(pm_cfg.ps_mode);
2368+ tlv = (u8 *) & cmd->params.pm_cfg + sizeof(HostCmd_DS_POWER_MGMT_EXT);
2369+
2370+ if ((pm_cfg.ps_mode) && (pm_cfg.flags & PS_FLAG_SLEEP_PARAM)) {
2371+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlv;
2372+ sleep_tlv->header.Type = uap_cpu_to_le16(TLV_TYPE_AP_SLEEP_PARAM);
2373+ sleep_tlv->header.Len =
2374+ uap_cpu_to_le16(sizeof(MrvlIEtypes_sleep_param_t) -
2375+ sizeof(MrvlIEtypesHeader_t));
2376+ sleep_tlv->ctrl_bitmap =
2377+ uap_cpu_to_le32(pm_cfg.sleep_param.ctrl_bitmap);
2378+ sleep_tlv->min_sleep =
2379+ uap_cpu_to_le32(pm_cfg.sleep_param.min_sleep);
2380+ sleep_tlv->max_sleep =
2381+ uap_cpu_to_le32(pm_cfg.sleep_param.max_sleep);
2382+ CmdSize += sizeof(MrvlIEtypes_sleep_param_t);
2383+ tlv += sizeof(MrvlIEtypes_sleep_param_t);
2384+ }
2385+ if ((pm_cfg.ps_mode == PS_MODE_INACTIVITY) &&
2386+ (pm_cfg.flags & PS_FLAG_INACT_SLEEP_PARAM)) {
2387+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlv;
2388+ inact_tlv->header.Type =
2389+ uap_cpu_to_le16(TLV_TYPE_AP_INACT_SLEEP_PARAM);
2390+ inact_tlv->header.Len =
2391+ uap_cpu_to_le16(sizeof(MrvlIEtypes_inact_sleep_param_t) -
2392+ sizeof(MrvlIEtypesHeader_t));
2393+ inact_tlv->inactivity_to =
2394+ uap_cpu_to_le32(pm_cfg.inact_param.inactivity_to);
2395+ inact_tlv->min_awake =
2396+ uap_cpu_to_le32(pm_cfg.inact_param.min_awake);
2397+ inact_tlv->max_awake =
2398+ uap_cpu_to_le32(pm_cfg.inact_param.max_awake);
2399+ CmdSize += sizeof(MrvlIEtypes_inact_sleep_param_t);
2400+ tlv += sizeof(MrvlIEtypes_inact_sleep_param_t);
2401+ }
2402+ }
2403+ cmd->Size = uap_cpu_to_le16(CmdSize);
2404+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
2405+ if (UAP_STATUS_SUCCESS !=
2406+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP)) {
2407+ PRINTM(ERROR, "Fail to process cmd POWER_MODE\n");
2408+ ret = -EFAULT;
2409+ goto done;
2410+ }
2411+ if (!Adapter->CmdSize) {
2412+ PRINTM(ERROR, "Cmd Size is 0\n");
2413+ ret = -EFAULT;
2414+ goto done;
2415+ }
2416+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
2417+ cmd->Result = uap_le16_to_cpu(cmd->Result);
2418+ if (cmd->Result != UAP_STATUS_SUCCESS) {
2419+ PRINTM(ERROR, "HOST_CMD_APCMD_POWER_MODE fail=%x\n", cmd->Result);
2420+ ret = -EFAULT;
2421+ goto done;
2422+ }
2423+ if (pm_cfg.flags) {
2424+ Adapter->psmode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
2425+ } else {
2426+ pm_cfg.flags = PS_FLAG_PS_MODE;
2427+ pm_cfg.ps_mode = uap_le16_to_cpu(cmd->params.pm_cfg.power_mode);
2428+ tlv_buf_left =
2429+ cmd->Size - (sizeof(HostCmd_DS_POWER_MGMT_EXT) + S_DS_GEN);
2430+ tlvbuf =
2431+ (MrvlIEtypesHeader_t *) ((u8 *) & cmd->params.pm_cfg +
2432+ sizeof(HostCmd_DS_POWER_MGMT_EXT));
2433+ while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
2434+ tlv_type = uap_le16_to_cpu(tlvbuf->Type);
2435+ tlv_len = uap_le16_to_cpu(tlvbuf->Len);
2436+ switch (tlv_type) {
2437+ case TLV_TYPE_AP_SLEEP_PARAM:
2438+ sleep_tlv = (MrvlIEtypes_sleep_param_t *) tlvbuf;
2439+ pm_cfg.flags |= PS_FLAG_SLEEP_PARAM;
2440+ pm_cfg.sleep_param.ctrl_bitmap =
2441+ uap_le32_to_cpu(sleep_tlv->ctrl_bitmap);
2442+ pm_cfg.sleep_param.min_sleep =
2443+ uap_le32_to_cpu(sleep_tlv->min_sleep);
2444+ pm_cfg.sleep_param.max_sleep =
2445+ uap_le32_to_cpu(sleep_tlv->max_sleep);
2446+ break;
2447+ case TLV_TYPE_AP_INACT_SLEEP_PARAM:
2448+ inact_tlv = (MrvlIEtypes_inact_sleep_param_t *) tlvbuf;
2449+ pm_cfg.flags |= PS_FLAG_INACT_SLEEP_PARAM;
2450+ pm_cfg.inact_param.inactivity_to =
2451+ uap_le32_to_cpu(inact_tlv->inactivity_to);
2452+ pm_cfg.inact_param.min_awake =
2453+ uap_le32_to_cpu(inact_tlv->min_awake);
2454+ pm_cfg.inact_param.max_awake =
2455+ uap_le32_to_cpu(inact_tlv->max_awake);
2456+ break;
2457+ }
2458+ tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
2459+ tlvbuf =
2460+ (MrvlIEtypesHeader_t *) ((u8 *) tlvbuf + tlv_len +
2461+ sizeof(MrvlIEtypesHeader_t));
2462+ }
2463+ /* Copy to user */
2464+ if (copy_to_user(req->ifr_data, &pm_cfg, sizeof(ps_mgmt))) {
2465+ PRINTM(ERROR, "Copy to user failed!\n");
2466+ LEAVE();
2467+ return -EFAULT;
2468+ }
2469+ }
2470+ done:
2471+ LEAVE();
2472+ return ret;
2473+}
2474+
2475+/**
2476+ * @brief This function send bss_stop command to firmware
2477+ *
2478+ * @param priv A pointer to uap_private structure
2479+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
2480+ */
2481+static int
2482+uap_bss_stop(uap_private * priv)
2483+{
2484+ int ret = UAP_STATUS_SUCCESS;
2485+ u32 CmdSize;
2486+ HostCmd_DS_GEN *cmd;
2487+ uap_adapter *Adapter = priv->adapter;
2488+ struct sk_buff *skb;
2489+ ENTER();
2490+ if (Adapter->HardwareStatus != HWReady) {
2491+ PRINTM(ERROR, "uap_bss_stop:Hardware is not ready!\n");
2492+ ret = -EFAULT;
2493+ goto done;
2494+ }
2495+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
2496+ if (!skb) {
2497+ PRINTM(ERROR, "No free skb\n");
2498+ ret = -ENOMEM;
2499+ goto done;
2500+ }
2501+ CmdSize = sizeof(HostCmd_DS_GEN);
2502+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
2503+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_BSS_STOP);
2504+ cmd->Size = uap_cpu_to_le16(CmdSize);
2505+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
2506+ PRINTM(CMND, "APCMD_BSS_STOP\n");
2507+ if (UAP_STATUS_SUCCESS !=
2508+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
2509+ PRINTM(ERROR, "Fail to process cmd BSS_STOP\n");
2510+ ret = -EFAULT;
2511+ goto done;
2512+ }
2513+ done:
2514+ LEAVE();
2515+ return ret;
2516+}
2517+
2518+/********************************************************
2519+ Global Functions
2520+********************************************************/
2521+/**
2522+ * @brief This function send soft_reset command to firmware
2523+ *
2524+ * @param priv A pointer to uap_private structure
2525+ * @return UAP_STATUS_SUCCESS on success, otherwise failure code
2526+ */
2527+int
2528+uap_soft_reset(uap_private * priv)
2529+{
2530+ int ret = UAP_STATUS_SUCCESS;
2531+ u32 CmdSize;
2532+ HostCmd_DS_GEN *cmd;
2533+ uap_adapter *Adapter = priv->adapter;
2534+ struct sk_buff *skb;
2535+ ENTER();
2536+ ret = uap_bss_stop(priv);
2537+ if (ret != UAP_STATUS_SUCCESS)
2538+ goto done;
2539+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
2540+ if (!skb) {
2541+ PRINTM(ERROR, "No free skb\n");
2542+ ret = -ENOMEM;
2543+ goto done;
2544+ }
2545+ CmdSize = sizeof(HostCmd_DS_GEN);
2546+ cmd = (HostCmd_DS_GEN *) (skb->data + INTF_HEADER_LEN);
2547+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SOFT_RESET);
2548+ cmd->Size = uap_cpu_to_le16(CmdSize);
2549+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
2550+ PRINTM(CMND, "APCMD_SOFT_RESET\n");
2551+ if (UAP_STATUS_SUCCESS !=
2552+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORSEND)) {
2553+ PRINTM(ERROR, "Fail to process cmd SOFT_RESET\n");
2554+ ret = -EFAULT;
2555+ goto done;
2556+ }
2557+ Adapter->SurpriseRemoved = TRUE;
2558+ /* delay to allow hardware complete reset */
2559+ os_sched_timeout(5);
2560+ if (priv->MediaConnected == TRUE) {
2561+ os_stop_queue(priv);
2562+ os_carrier_off(priv);
2563+ priv->MediaConnected = FALSE;
2564+ }
2565+ Adapter->CmdSize = 0;
2566+ Adapter->CmdWaitQWoken = TRUE;
2567+ wake_up_interruptible(&Adapter->cmdwait_q);
2568+ skb_queue_purge(&priv->adapter->tx_queue);
2569+ skb_queue_purge(&priv->adapter->cmd_queue);
2570+ done:
2571+ LEAVE();
2572+ return ret;
2573+}
2574+
2575+/**
2576+ * @brief This function processes received packet and forwards it
2577+ * to kernel/upper layer
2578+ *
2579+ * @param priv A pointer to uap_private
2580+ * @param skb A pointer to skb which includes the received packet
2581+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
2582+ */
2583+int
2584+uap_process_rx_packet(uap_private * priv, struct sk_buff *skb)
2585+{
2586+ int ret = UAP_STATUS_SUCCESS;
2587+ RxPD *pRxPD;
2588+ ENTER();
2589+ priv->adapter->ps_state = PS_STATE_AWAKE;
2590+ pRxPD = (RxPD *) skb->data;
2591+ endian_convert_RxPD(pRxPD);
2592+ DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
2593+ skb_pull(skb, pRxPD->RxPktOffset);
2594+ priv->stats.rx_packets++;
2595+ priv->stats.rx_bytes += skb->len;
2596+ os_upload_rx_packet(priv, skb);
2597+ LEAVE();
2598+ return ret;
2599+}
2600+
2601+/**
2602+ * @brief This function opens the network device
2603+ *
2604+ * @param dev A pointer to net_device structure
2605+ * @return UAP_STATUS_SUCCESS
2606+ */
2607+static int
2608+uap_open(struct net_device *dev)
2609+{
2610+ uap_private *priv = (uap_private *) (uap_private *) netdev_priv(dev);
2611+ uap_adapter *Adapter = priv->adapter;
2612+ int i = 0;
2613+
2614+ ENTER();
2615+
2616+ /* On some systems the device open handler will be called before HW ready. */
2617+ /* Use the following flag check and wait function to work around the issue. */
2618+ while ((Adapter->HardwareStatus != HWReady) &&
2619+ (i < MAX_WAIT_DEVICE_READY_COUNT)) {
2620+ i++;
2621+ os_sched_timeout(100);
2622+ }
2623+ if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
2624+ PRINTM(FATAL, "HW not ready, uap_open() return failure\n");
2625+ LEAVE();
2626+ return UAP_STATUS_FAILURE;
2627+ }
2628+
2629+ if (MODULE_GET == 0)
2630+ return UAP_STATUS_FAILURE;
2631+
2632+ priv->open = TRUE;
2633+ if (priv->MediaConnected == TRUE) {
2634+ os_carrier_on(priv);
2635+ os_start_queue(priv);
2636+ } else {
2637+ os_stop_queue(priv);
2638+ os_carrier_off(priv);
2639+ }
2640+ LEAVE();
2641+ return UAP_STATUS_SUCCESS;
2642+}
2643+
2644+/**
2645+ * @brief This function closes the network device
2646+ *
2647+ * @param dev A pointer to net_device structure
2648+ * @return UAP_STATUS_SUCCESS
2649+ */
2650+static int
2651+uap_close(struct net_device *dev)
2652+{
2653+ uap_private *priv = (uap_private *) netdev_priv(dev);
2654+
2655+ ENTER();
2656+ skb_queue_purge(&priv->adapter->tx_queue);
2657+ os_stop_queue(priv);
2658+ os_carrier_off(priv);
2659+
2660+ MODULE_PUT;
2661+ priv->open = FALSE;
2662+ LEAVE();
2663+ return UAP_STATUS_SUCCESS;
2664+}
2665+
2666+/**
2667+ * @brief This function returns the network statistics
2668+ *
2669+ * @param dev A pointer to uap_private structure
2670+ * @return A pointer to net_device_stats structure
2671+ */
2672+static struct net_device_stats *
2673+uap_get_stats(struct net_device *dev)
2674+{
2675+ uap_private *priv = (uap_private *) netdev_priv(dev);
2676+
2677+ return &priv->stats;
2678+}
2679+
2680+/**
2681+ * @brief This function sets the MAC address to firmware.
2682+ *
2683+ * @param dev A pointer to uap_private structure
2684+ * @param addr MAC address to set
2685+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
2686+ */
2687+static int
2688+uap_set_mac_address(struct net_device *dev, void *addr)
2689+{
2690+ int ret = UAP_STATUS_SUCCESS;
2691+ uap_private *priv = (uap_private *) netdev_priv(dev);
2692+ struct sockaddr *pHwAddr = (struct sockaddr *) addr;
2693+ u32 CmdSize;
2694+ HostCmd_DS_COMMAND *cmd;
2695+ MrvlIEtypes_MacAddr_t *pMacAddrTlv;
2696+ uap_adapter *Adapter = priv->adapter;
2697+ struct sk_buff *skb;
2698+
2699+ ENTER();
2700+
2701+ /* Dump MAC address */
2702+ DBG_HEXDUMP(CMD_D, "Original MAC addr", dev->dev_addr, ETH_ALEN);
2703+ DBG_HEXDUMP(CMD_D, "New MAC addr", pHwAddr->sa_data, ETH_ALEN);
2704+ if (priv->open && (priv->MediaConnected == TRUE)) {
2705+ os_carrier_on(priv);
2706+ os_start_queue(priv);
2707+ }
2708+ skb = dev_alloc_skb(MRVDRV_SIZE_OF_CMD_BUFFER);
2709+ if (!skb) {
2710+ PRINTM(ERROR, "No free skb\n");
2711+ LEAVE();
2712+ return -ENOMEM;
2713+ }
2714+ CmdSize =
2715+ S_DS_GEN + sizeof(HostCmd_SYS_CONFIG) + sizeof(MrvlIEtypes_MacAddr_t);
2716+ cmd = (HostCmd_DS_COMMAND *) (skb->data + INTF_HEADER_LEN);
2717+ cmd->Command = uap_cpu_to_le16(HOST_CMD_APCMD_SYS_CONFIGURE);
2718+ cmd->Size = uap_cpu_to_le16(CmdSize);
2719+ cmd->params.sys_config.Action = uap_cpu_to_le16(ACTION_SET);
2720+ pMacAddrTlv =
2721+ (MrvlIEtypes_MacAddr_t *) ((u8 *) cmd + S_DS_GEN +
2722+ sizeof(HostCmd_SYS_CONFIG));
2723+ pMacAddrTlv->Header.Type = uap_cpu_to_le16(MRVL_AP_MAC_ADDRESS_TLV_ID);
2724+ pMacAddrTlv->Header.Len = uap_cpu_to_le16(ETH_ALEN);
2725+ memcpy(pMacAddrTlv->ApMacAddr, pHwAddr->sa_data, ETH_ALEN);
2726+ skb_put(skb, CmdSize + INTF_HEADER_LEN);
2727+ PRINTM(CMND, "set_mac_address\n");
2728+ if (UAP_STATUS_SUCCESS !=
2729+ uap_process_cmd(priv, skb, HostCmd_OPTION_WAITFORRSP_TIMEOUT)) {
2730+ PRINTM(ERROR, "Fail to set mac address\n");
2731+ LEAVE();
2732+ return -EFAULT;
2733+ }
2734+ if (!Adapter->CmdSize) {
2735+ PRINTM(ERROR, "Cmd Size is 0\n");
2736+ LEAVE();
2737+ return -EFAULT;
2738+ }
2739+ cmd = (HostCmd_DS_COMMAND *) Adapter->CmdBuf;
2740+ cmd->Result = uap_cpu_to_le16(cmd->Result);
2741+ if (cmd->Result != UAP_STATUS_SUCCESS) {
2742+ PRINTM(ERROR, "set mac addrress fail,cmd result=%x\n", cmd->Result);
2743+ ret = -EFAULT;
2744+ } else
2745+ memcpy(dev->dev_addr, pHwAddr->sa_data, ETH_ALEN);
2746+ LEAVE();
2747+ return ret;
2748+}
2749+
2750+/**
2751+ * @brief This function handles the timeout of packet
2752+ * transmission
2753+ *
2754+ * @param dev A pointer to net_device structure
2755+ * @return n/a
2756+ */
2757+static void
2758+uap_tx_timeout(struct net_device *dev)
2759+{
2760+ uap_private *priv = (uap_private *) netdev_priv(dev);
2761+
2762+ ENTER();
2763+
2764+ PRINTM(DATA, "Tx timeout\n");
2765+ UpdateTransStart(dev);
2766+ priv->num_tx_timeout++;
2767+ priv->adapter->IntCounter++;
2768+ wake_up_interruptible(&priv->MainThread.waitQ);
2769+
2770+ LEAVE();
2771+}
2772+
2773+/**
2774+ * @brief This function handles packet transmission
2775+ *
2776+ * @param skb A pointer to sk_buff structure
2777+ * @param dev A pointer to net_device structure
2778+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
2779+ */
2780+static int
2781+uap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2782+{
2783+ uap_private *priv = (uap_private *) netdev_priv(dev);
2784+ int ret = UAP_STATUS_SUCCESS;
2785+
2786+ ENTER();
2787+ PRINTM(DATA, "Data <= kernel\n");
2788+ DBG_HEXDUMP(DAT_D, "Tx", skb->data, MIN(skb->len, DATA_DUMP_LEN));
2789+ /* skb sanity check */
2790+ if (!skb->len || (skb->len > MRVDRV_MAXIMUM_ETH_PACKET_SIZE)) {
2791+ PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
2792+ MRVDRV_MAXIMUM_ETH_PACKET_SIZE);
2793+ priv->stats.tx_dropped++;
2794+ kfree(skb);
2795+ goto done;
2796+ }
2797+ skb_queue_tail(&priv->adapter->tx_queue, skb);
2798+ wake_up_interruptible(&priv->MainThread.waitQ);
2799+ if (skb_queue_len(&priv->adapter->tx_queue) > TX_HIGH_WATERMARK) {
2800+ UpdateTransStart(dev);
2801+ os_stop_queue(priv);
2802+ }
2803+ done:
2804+ LEAVE();
2805+ return ret;
2806+}
2807+
2808+/**
2809+ * @brief ioctl function - entry point
2810+ *
2811+ * @param dev A pointer to net_device structure
2812+ * @param req A pointer to ifreq structure
2813+ * @param cmd command
2814+ * @return UAP_STATUS_SUCCESS--success, otherwise fail
2815+ */
2816+static int
2817+uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
2818+{
2819+ int ret = UAP_STATUS_SUCCESS;
2820+
2821+ ENTER();
2822+
2823+ PRINTM(CMND, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
2824+
2825+ switch (cmd) {
2826+ case UAPHOSTCMD:
2827+ ret = uap_hostcmd_ioctl(dev, req);
2828+ break;
2829+ case UAP_POWER_MODE:
2830+ ret = uap_power_mode_ioctl(dev, req);
2831+ break;
2832+ default:
2833+ ret = -EINVAL;
2834+ break;
2835+ }
2836+
2837+ LEAVE();
2838+ return ret;
2839+}
2840+
2841+/**
2842+ * @brief This function handles events generated by firmware
2843+ *
2844+ * @param priv A pointer to uap_private structure
2845+ * @param payload A pointer to payload buffer
2846+ * @param len Length of the payload
2847+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
2848+ */
2849+int
2850+uap_process_event(uap_private * priv, u8 * payload, uint len)
2851+{
2852+ int ret = UAP_STATUS_SUCCESS;
2853+ uap_adapter *Adapter = priv->adapter;
2854+ struct sk_buff *skb = NULL;
2855+ struct nlmsghdr *nlh = NULL;
2856+ struct sock *sk = Adapter->nl_sk;
2857+ AP_Event *pEvent;
2858+
2859+ ENTER();
2860+ Adapter->ps_state = PS_STATE_AWAKE;
2861+ if (len > NL_MAX_PAYLOAD) {
2862+ PRINTM(ERROR, "event size is too big!!! len=%d\n", len);
2863+ ret = UAP_STATUS_FAILURE;
2864+ goto done;
2865+ }
2866+ pEvent = (AP_Event *) payload;
2867+ PRINTM(CMND, "Event: %d\n", pEvent->EventId);
2868+ switch (pEvent->EventId) {
2869+ case MICRO_AP_EV_ID_BSS_START:
2870+ memcpy(priv->uap_dev.netdev->dev_addr, pEvent->MacAddr, ETH_ALEN);
2871+ DBG_HEXDUMP(CMD_D, "BSS MAC addr", priv->uap_dev.netdev->dev_addr,
2872+ ETH_ALEN);
2873+ break;
2874+ case MICRO_AP_EV_BSS_ACTIVE:
2875+ // carrier on
2876+ priv->MediaConnected = TRUE;
2877+ os_carrier_on(priv);
2878+ os_start_queue(priv);
2879+ break;
2880+ case MICRO_AP_EV_BSS_IDLE:
2881+ os_stop_queue(priv);
2882+ os_carrier_off(priv);
2883+ priv->MediaConnected = FALSE;
2884+ break;
2885+ case EVENT_PS_AWAKE:
2886+ PRINTM(CMND, "UAP: PS_AWAKE\n");
2887+ Adapter->ps_state = PS_STATE_AWAKE;
2888+ Adapter->WakeupTries = 0;
2889+ break;
2890+ case EVENT_PS_SLEEP:
2891+ PRINTM(CMND, "UAP: PS_SLEEP\n");
2892+ Adapter->ps_state = PS_STATE_PRE_SLEEP;
2893+ break;
2894+ default:
2895+ break;
2896+ }
2897+ if ((pEvent->EventId == EVENT_PS_AWAKE) ||
2898+ (pEvent->EventId == EVENT_PS_SLEEP))
2899+ goto done;
2900+ if (sk) {
2901+ /* Allocate skb */
2902+ if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) {
2903+ PRINTM(ERROR, "Could not allocate skb for netlink.\n");
2904+ ret = UAP_STATUS_FAILURE;
2905+ goto done;
2906+ }
2907+ nlh = (struct nlmsghdr *) skb->data;
2908+ nlh->nlmsg_len = NLMSG_SPACE(len);
2909+
2910+ /* From kernel */
2911+ nlh->nlmsg_pid = 0;
2912+ nlh->nlmsg_flags = 0;
2913+
2914+ /* Data */
2915+ skb_put(skb, nlh->nlmsg_len);
2916+ memcpy(NLMSG_DATA(nlh), payload, len);
2917+
2918+ /* From Kernel */
2919+ NETLINK_CB(skb).portid = 0;
2920+
2921+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
2922+ /* Multicast message */
2923+ NETLINK_CB(skb).dst_pid = 0;
2924+#endif
2925+
2926+ /* Multicast group number */
2927+ NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP;
2928+
2929+ /* Send message */
2930+ netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_KERNEL);
2931+
2932+ ret = UAP_STATUS_SUCCESS;
2933+ } else {
2934+ PRINTM(ERROR, "Could not send event through NETLINK. Link down.\n");
2935+ ret = UAP_STATUS_FAILURE;
2936+ }
2937+ done:
2938+ LEAVE();
2939+ return ret;
2940+}
2941+
2942+/**
2943+ * @brief This function handles the interrupt. it will change PS
2944+ * state if applicable. it will wake up main_thread to handle
2945+ * the interrupt event as well.
2946+ *
2947+ * @param priv A pointer to uap_private structure
2948+ * @return n/a
2949+ */
2950+void
2951+uap_interrupt(uap_private * priv)
2952+{
2953+ ENTER();
2954+ priv->adapter->IntCounter++;
2955+ priv->adapter->WakeupTries = 0;
2956+ PRINTM(INFO, "*\n");
2957+ wake_up_interruptible(&priv->MainThread.waitQ);
2958+
2959+ LEAVE();
2960+
2961+}
2962+
2963+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
2964+/** Network device handlers */
2965+static const struct net_device_ops uap_netdev_ops = {
2966+ .ndo_open = uap_open,
2967+ .ndo_start_xmit = uap_hard_start_xmit,
2968+ .ndo_stop = uap_close,
2969+ .ndo_do_ioctl = uap_do_ioctl,
2970+ .ndo_set_mac_address = uap_set_mac_address,
2971+ .ndo_tx_timeout = uap_tx_timeout,
2972+ .ndo_get_stats = uap_get_stats,
2973+};
2974+#endif
2975+
2976+/**
2977+ * @brief This function adds the card. it will probe the
2978+ * card, allocate the uap_priv and initialize the device.
2979+ *
2980+ * @param card A pointer to card
2981+ * @return A pointer to uap_private structure
2982+ */
2983+uap_private *
2984+uap_add_card(void *card)
2985+{
2986+ struct net_device *dev = NULL;
2987+ uap_private *priv = NULL;
2988+
2989+ ENTER();
2990+
2991+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
2992+ goto exit_sem_err;
2993+
2994+ /* Allocate an Ethernet device */
2995+ if (!(dev = alloc_etherdev(sizeof(uap_private)))) {
2996+ PRINTM(FATAL, "Init ethernet device failed!\n");
2997+ goto error;
2998+ }
2999+ priv = (uap_private *) netdev_priv(dev);
3000+
3001+ /* Allocate name */
3002+ if (dev_alloc_name(dev, "uap%d") < 0) {
3003+ PRINTM(ERROR, "Could not allocate device name!\n");
3004+ goto error;
3005+ }
3006+
3007+ /* Allocate buffer for uap_adapter */
3008+ if (!(priv->adapter = kmalloc(sizeof(uap_adapter), GFP_KERNEL))) {
3009+ PRINTM(FATAL, "Allocate buffer for uap_adapter failed!\n");
3010+ goto error;
3011+ }
3012+ memset(priv->adapter, 0, sizeof(uap_adapter));
3013+
3014+ priv->uap_dev.netdev = dev;
3015+ priv->uap_dev.card = card;
3016+ priv->MediaConnected = FALSE;
3017+ uappriv = priv;
3018+ ((struct sdio_mmc_card *) card)->priv = priv;
3019+
3020+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
3021+ SET_MODULE_OWNER(dev);
3022+#endif
3023+
3024+ /* Setup the OS Interface to our functions */
3025+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
3026+ dev->open = uap_open;
3027+ dev->stop = uap_close;
3028+ dev->hard_start_xmit = uap_hard_start_xmit;
3029+ dev->tx_timeout = uap_tx_timeout;
3030+ dev->get_stats = uap_get_stats;
3031+ dev->do_ioctl = uap_do_ioctl;
3032+ dev->set_mac_address = uap_set_mac_address;
3033+ dev->set_multicast_list = uap_set_multicast_list;
3034+#else
3035+ dev->netdev_ops = &uap_netdev_ops;
3036+#endif
3037+ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
3038+ dev->hard_header_len += sizeof(TxPD) + INTF_HEADER_LEN;
3039+ dev->hard_header_len += HEADER_ALIGNMENT;
3040+#define NETIF_F_DYNALLOC 16
3041+ dev->features |= NETIF_F_DYNALLOC;
3042+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
3043+
3044+ /* Init SW */
3045+ if (uap_init_sw(priv)) {
3046+ PRINTM(FATAL, "Software Init Failed\n");
3047+ goto error;
3048+ }
3049+
3050+ PRINTM(INFO, "Starting kthread...\n");
3051+ priv->MainThread.priv = priv;
3052+ spin_lock_init(&priv->driver_lock);
3053+ uap_create_thread(uap_service_main_thread, &priv->MainThread,
3054+ "uap_main_service");
3055+ while (priv->MainThread.pid == 0) {
3056+ os_sched_timeout(2);
3057+ }
3058+
3059+ /* Register the device */
3060+ if (sbi_register_dev(priv) < 0) {
3061+ PRINTM(FATAL, "Failed to register uap device!\n");
3062+ goto err_registerdev;
3063+ }
3064+#ifdef FW_DNLD_NEEDED
3065+ SET_NETDEV_DEV(dev, priv->hotplug_device);
3066+#endif
3067+
3068+ /* Init FW and HW */
3069+ if (uap_init_fw(priv)) {
3070+ PRINTM(FATAL, "Firmware Init Failed\n");
3071+ goto err_init_fw;
3072+ }
3073+
3074+ priv->uap_dev.cmd_sent = FALSE;
3075+ priv->uap_dev.data_sent = FALSE;
3076+
3077+ /* Get mac address from firmware */
3078+ if (uap_get_mac_address(priv)) {
3079+ PRINTM(FATAL, "Fail to get mac address\n");
3080+ goto err_init_fw;
3081+ }
3082+ /* Register network device */
3083+ if (register_netdev(dev)) {
3084+ printk(KERN_ERR "Cannot register network device!\n");
3085+ goto err_init_fw;
3086+ }
3087+#ifdef CONFIG_PROC_FS
3088+ uap_proc_entry(priv, dev);
3089+ uap_debug_entry(priv, dev);
3090+#endif /* CPNFIG_PROC_FS */
3091+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
3092+
3093+ LEAVE();
3094+ return priv;
3095+ err_init_fw:
3096+ sbi_unregister_dev(priv);
3097+ err_registerdev:
3098+ ((struct sdio_mmc_card *) card)->priv = NULL;
3099+ /* Stop the thread servicing the interrupts */
3100+ priv->adapter->SurpriseRemoved = TRUE;
3101+ wake_up_interruptible(&priv->MainThread.waitQ);
3102+ while (priv->MainThread.pid) {
3103+ os_sched_timeout(1);
3104+ }
3105+ error:
3106+ if (dev) {
3107+ if (dev->reg_state == NETREG_REGISTERED)
3108+ unregister_netdev(dev);
3109+ if (priv->adapter)
3110+ uap_free_adapter(priv);
3111+ free_netdev(dev);
3112+ uappriv = NULL;
3113+ }
3114+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
3115+ exit_sem_err:
3116+ LEAVE();
3117+ return NULL;
3118+}
3119+
3120+/**
3121+ * @brief This function removes the card.
3122+ *
3123+ * @param card A pointer to card
3124+ * @return UAP_STATUS_SUCCESS
3125+ */
3126+int
3127+uap_remove_card(void *card)
3128+{
3129+ uap_private *priv = uappriv;
3130+ uap_adapter *Adapter;
3131+ struct net_device *dev;
3132+
3133+ ENTER();
3134+
3135+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
3136+ goto exit_sem_err;
3137+
3138+ if (!priv || !(Adapter = priv->adapter)) {
3139+ goto exit_remove;
3140+ }
3141+ Adapter->SurpriseRemoved = TRUE;
3142+ if (Adapter->cmd_pending == TRUE) {
3143+ /* Wake up cmd Q */
3144+ Adapter->CmdWaitQWoken = TRUE;
3145+ wake_up_interruptible(&Adapter->cmdwait_q);
3146+ }
3147+ dev = priv->uap_dev.netdev;
3148+ if (priv->MediaConnected == TRUE) {
3149+ os_stop_queue(priv);
3150+ os_carrier_off(priv);
3151+ priv->MediaConnected = FALSE;
3152+ }
3153+ Adapter->CmdSize = 0;
3154+ Adapter->CmdWaitQWoken = TRUE;
3155+ wake_up_interruptible(&Adapter->cmdwait_q);
3156+ skb_queue_purge(&priv->adapter->tx_queue);
3157+ skb_queue_purge(&priv->adapter->cmd_queue);
3158+
3159+ /* Disable interrupts on the card */
3160+ sbi_disable_host_int(priv);
3161+ PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
3162+ (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
3163+ unregister_netdev(dev);
3164+ PRINTM(INFO, "Unregister finish\n");
3165+ wake_up_interruptible(&priv->MainThread.waitQ);
3166+ while (priv->MainThread.pid) {
3167+ os_sched_timeout(1);
3168+ }
3169+
3170+ if ((Adapter->nl_sk) && ((Adapter->nl_sk)->sk_socket)) {
3171+ sock_release((Adapter->nl_sk)->sk_socket);
3172+ Adapter->nl_sk = NULL;
3173+ }
3174+#ifdef CONFIG_PROC_FS
3175+ uap_debug_remove(priv);
3176+ uap_proc_remove(priv);
3177+#endif
3178+ sbi_unregister_dev(priv);
3179+ PRINTM(INFO, "Free Adapter\n");
3180+ uap_free_adapter(priv);
3181+ priv->uap_dev.netdev = NULL;
3182+ free_netdev(dev);
3183+ uappriv = NULL;
3184+
3185+ exit_remove:
3186+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
3187+ exit_sem_err:
3188+ LEAVE();
3189+ return UAP_STATUS_SUCCESS;
3190+}
3191+
3192+/**
3193+ * @brief This function initializes module.
3194+ *
3195+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3196+ */
3197+static int __init
3198+uap_init_module(void)
3199+{
3200+ int ret = UAP_STATUS_SUCCESS;
3201+ ENTER();
3202+
3203+ OS_INIT_SEMAPHORE(&AddRemoveCardSem);
3204+ ret = sbi_register();
3205+ LEAVE();
3206+ return ret;
3207+}
3208+
3209+/**
3210+ * @brief This function cleans module
3211+ *
3212+ * @return n/a
3213+ */
3214+static void __exit
3215+uap_cleanup_module(void)
3216+{
3217+ ENTER();
3218+
3219+ if (OS_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
3220+ goto exit_sem_err;
3221+
3222+ if ((uappriv) && (uappriv->adapter)) {
3223+ uap_func_shutdown(uappriv);
3224+ }
3225+ OS_REL_SEMAPHORE(&AddRemoveCardSem);
3226+ exit_sem_err:
3227+ sbi_unregister();
3228+ LEAVE();
3229+}
3230+
3231+module_init(uap_init_module);
3232+module_exit(uap_cleanup_module);
3233+module_param(helper_name, charp, 0);
3234+MODULE_PARM_DESC(helper_name, "Helper name");
3235+module_param(fw_name, charp, 0);
3236+MODULE_PARM_DESC(fw_name, "Firmware name");
3237+
3238+MODULE_DESCRIPTION("M-UAP Driver");
3239+MODULE_AUTHOR("Marvell International Ltd.");
3240+MODULE_VERSION(DRIVER_VERSION);
3241+MODULE_LICENSE("GPL");
3242diff --git a/drivers/net/wireless/libertas_uap/uap_proc.c b/drivers/net/wireless/libertas_uap/uap_proc.c
3243new file mode 100644
3244index 0000000..d673f56
3245--- /dev/null
3246+++ b/drivers/net/wireless/libertas_uap/uap_proc.c
3247@@ -0,0 +1,258 @@
3248+/** @file uap_proc.c
3249+ * @brief This file contains functions for proc file.
3250+ *
3251+ * Copyright (C) 2008-2009, Marvell International Ltd.
3252+ *
3253+ * This software file (the "File") is distributed by Marvell International
3254+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
3255+ * (the "License"). You may use, redistribute and/or modify this File in
3256+ * accordance with the terms and conditions of the License, a copy of which
3257+ * is available along with the File in the gpl.txt file or by writing to
3258+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
3259+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
3260+ *
3261+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
3262+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
3263+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
3264+ * this warranty disclaimer.
3265+ *
3266+ */
3267+#ifdef CONFIG_PROC_FS
3268+#include <linux/proc_fs.h>
3269+#include <linux/seq_file.h>
3270+#include "uap_headers.h"
3271+
3272+/** /proc directory root */
3273+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
3274+#define PROC_DIR NULL
3275+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
3276+#define PROC_DIR &proc_root
3277+#else
3278+#define PROC_DIR proc_net
3279+#endif
3280+
3281+/********************************************************
3282+ Local Variables
3283+********************************************************/
3284+
3285+/********************************************************
3286+ Global Variables
3287+********************************************************/
3288+
3289+/********************************************************
3290+ Local Functions
3291+********************************************************/
3292+
3293+static int uap_info_proc_show(struct seq_file *s, void *data) {
3294+ int i;
3295+ struct net_device *netdev = (struct net_device*)s->private;
3296+ struct netdev_hw_addr *ha;
3297+ uap_private *priv = (uap_private *) netdev_priv(netdev);
3298+
3299+ seq_printf(s, "driver_name = " "\"uap\"\n");
3300+ seq_printf(s, "driver_version = %s-(FP%s)", DRIVER_VERSION, FPNUM);
3301+ seq_printf(s, "\nInterfaceName=\"%s\"\n", netdev->name);
3302+
3303+ seq_printf(s, "State=\"%s\"\n",
3304+ ((priv->MediaConnected ==
3305+ FALSE) ? "Disconnected" : "Connected"));
3306+ seq_printf(s, "MACAddress=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
3307+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
3308+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
3309+ i = 0;
3310+ netdev_for_each_mc_addr(ha, netdev) {
3311+ ++i;
3312+ }
3313+ seq_printf(s, "MCCount=\"%d\"\n", i);
3314+
3315+ /*
3316+ * Put out the multicast list
3317+ */
3318+ i = 0;
3319+ netdev_for_each_mc_addr(ha, netdev) {
3320+ seq_printf(s,
3321+ "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
3322+ i++,
3323+ ha->addr[0], ha->addr[1],
3324+ ha->addr[2], ha->addr[3],
3325+ ha->addr[4], ha->addr[5]);
3326+ }
3327+
3328+ seq_printf(s, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
3329+ seq_printf(s, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
3330+ seq_printf(s, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
3331+ seq_printf(s, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
3332+ seq_printf(s, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
3333+ seq_printf(s, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
3334+ seq_printf(s, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
3335+ seq_printf(s, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
3336+ seq_printf(s, "num_tx_timeout = %u\n", priv->num_tx_timeout);
3337+ seq_printf(s, "carrier %s\n",
3338+ ((netif_carrier_ok(priv->uap_dev.netdev)) ? "on" : "off"));
3339+ seq_printf(s, "tx queue %s\n",
3340+ ((netif_queue_stopped(priv->uap_dev.netdev)) ? "stopped" :
3341+ "started"));
3342+
3343+ return 0;
3344+}
3345+
3346+static int uap_info_proc_open(struct inode *inode, struct file *file) {
3347+ return single_open(file, uap_info_proc_show, PDE_DATA(inode));
3348+}
3349+
3350+static int uap_hwstatus_proc_show(struct seq_file *s, void *data) {
3351+ struct net_device *netdev = (struct net_device*)s->private;
3352+ uap_private *priv = (uap_private *) netdev_priv(netdev);
3353+
3354+ MODULE_GET;
3355+ seq_printf(s, "%d\n", priv->adapter->HardwareStatus);
3356+ MODULE_PUT;
3357+
3358+ return 0;
3359+}
3360+
3361+static int uap_hwstatus_proc_open(struct inode *inode, struct file *file) {
3362+ return single_open(file, uap_hwstatus_proc_show, PDE_DATA(inode));
3363+}
3364+
3365+static ssize_t uap_hwstatus_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) {
3366+ struct net_device *netdev = (struct net_device *)PDE_DATA(file_inode(file));
3367+ uap_private *priv = (uap_private *) netdev_priv(netdev);
3368+
3369+ int hwstatus;
3370+ char value[10];
3371+
3372+ if (count > sizeof(value))
3373+ return count;
3374+
3375+ if (copy_from_user(&value, buffer, count))
3376+ return -EFAULT;
3377+
3378+ hwstatus = string_to_number(value);
3379+ switch (hwstatus) {
3380+ case HWReset:
3381+ PRINTM(MSG, "reset hw\n");
3382+ uap_soft_reset(priv);
3383+ priv->adapter->HardwareStatus = HWReset;
3384+ break;
3385+ default:
3386+ break;
3387+ }
3388+
3389+ MODULE_PUT;
3390+ return count;
3391+}
3392+
3393+static const struct file_operations uap_info_proc_fops = {
3394+ .owner = THIS_MODULE,
3395+ .open = uap_info_proc_open,
3396+ .read = seq_read,
3397+ .llseek = seq_lseek,
3398+ .release = single_release,
3399+};
3400+
3401+static const struct file_operations uap_hwstatus_proc_fops = {
3402+ .owner = THIS_MODULE,
3403+ .open = uap_hwstatus_proc_open,
3404+ .read = seq_read,
3405+ .llseek = seq_lseek,
3406+ .release = single_release,
3407+ .write = uap_hwstatus_proc_write,
3408+};
3409+
3410+/********************************************************
3411+ Global Functions
3412+********************************************************/
3413+/**
3414+ * @brief create uap proc file
3415+ *
3416+ * @param priv pointer uap_private
3417+ * @param dev pointer net_device
3418+ * @return N/A
3419+ */
3420+void
3421+uap_proc_entry(uap_private * priv, struct net_device *dev)
3422+{
3423+ PRINTM(INFO, "Creating Proc Interface\n");
3424+ /* Check if uap directory already exists */
3425+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
3426+ struct proc_dir_entry *r = PROC_DIR;
3427+
3428+ for (r = r->subdir; r; r = r->next) {
3429+ if (r->namelen && !strcmp("uap", r->name)) {
3430+ /* Directory exists */
3431+ PRINTM(WARN, "proc directory already exists!\n");
3432+ priv->proc_uap = r;
3433+ break;
3434+ }
3435+ }
3436+#endif
3437+ if (!priv->proc_uap) {
3438+ priv->proc_uap = proc_mkdir("uap", PROC_DIR);
3439+ if (!priv->proc_uap)
3440+ return;
3441+ }
3442+ priv->proc_entry = proc_mkdir(dev->name, priv->proc_uap);
3443+
3444+ if (priv->proc_entry) {
3445+ proc_create_data("info", 0644, priv->proc_entry, &uap_info_proc_fops, dev);
3446+ proc_create_data("hwinfo", 0644, priv->proc_entry, &uap_hwstatus_proc_fops, dev);
3447+ }
3448+}
3449+
3450+/**
3451+ * @brief remove proc file
3452+ *
3453+ * @param priv pointer uap_private
3454+ * @return N/A
3455+ */
3456+void
3457+uap_proc_remove(uap_private * priv)
3458+{
3459+ if (priv->proc_uap) {
3460+ if (priv->proc_entry) {
3461+ remove_proc_entry("info", priv->proc_entry);
3462+ remove_proc_entry("hwstatus", priv->proc_entry);
3463+ }
3464+ remove_proc_entry(priv->uap_dev.netdev->name, priv->proc_uap);
3465+ }
3466+}
3467+
3468+/**
3469+ * @brief convert string to number
3470+ *
3471+ * @param s pointer to numbered string
3472+ * @return converted number from string s
3473+ */
3474+int
3475+string_to_number(char *s)
3476+{
3477+ int r = 0;
3478+ int base = 0;
3479+ int pn = 1;
3480+
3481+ if (strncmp(s, "-", 1) == 0) {
3482+ pn = -1;
3483+ s++;
3484+ }
3485+ if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0)) {
3486+ base = 16;
3487+ s += 2;
3488+ } else
3489+ base = 10;
3490+
3491+ for (s = s; *s != 0; s++) {
3492+ if ((*s >= '0') && (*s <= '9'))
3493+ r = (r * base) + (*s - '0');
3494+ else if ((*s >= 'A') && (*s <= 'F'))
3495+ r = (r * base) + (*s - 'A' + 10);
3496+ else if ((*s >= 'a') && (*s <= 'f'))
3497+ r = (r * base) + (*s - 'a' + 10);
3498+ else
3499+ break;
3500+ }
3501+
3502+ return (r * pn);
3503+}
3504+
3505+#endif
3506diff --git a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c
3507new file mode 100644
3508index 0000000..86f55b5
3509--- /dev/null
3510+++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.c
3511@@ -0,0 +1,1428 @@
3512+/** @file uap_sdio_mmc.c
3513+ * @brief This file contains SDIO IF (interface) module
3514+ * related functions.
3515+ *
3516+ * Copyright (C) 2007-2009, Marvell International Ltd.
3517+ *
3518+ * This software file (the "File") is distributed by Marvell International
3519+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
3520+ * (the "License"). You may use, redistribute and/or modify this File in
3521+ * accordance with the terms and conditions of the License, a copy of which
3522+ * is available along with the File in the gpl.txt file or by writing to
3523+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
3524+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
3525+ *
3526+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
3527+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
3528+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
3529+ * this warranty disclaimer.
3530+ *
3531+ */
3532+/****************************************************
3533+Change log:
3534+****************************************************/
3535+
3536+#include "uap_sdio_mmc.h"
3537+
3538+#include <linux/firmware.h>
3539+
3540+/** define SDIO block size */
3541+/* We support up to 480-byte block size due to FW buffer limitation. */
3542+#define SD_BLOCK_SIZE 256
3543+
3544+/** define allocated buffer size */
3545+#define ALLOC_BUF_SIZE (((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
3546+ MRVDRV_SIZE_OF_CMD_BUFFER) + INTF_HEADER_LEN \
3547+ + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
3548+
3549+/** Max retry number of CMD53 write */
3550+#define MAX_WRITE_IOMEM_RETRY 2
3551+
3552+/********************************************************
3553+ Local Variables
3554+********************************************************/
3555+
3556+/** SDIO Rx unit */
3557+static u8 sdio_rx_unit = 0;
3558+
3559+/**Interrupt status */
3560+static u8 sd_ireg = 0;
3561+/********************************************************
3562+ Global Variables
3563+********************************************************/
3564+extern u8 *helper_name;
3565+extern u8 *fw_name;
3566+/** Default helper name */
3567+#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
3568+/** Default firmware name */
3569+#define DEFAULT_FW_NAME "mrvl/sd8688_ap.bin"
3570+
3571+/********************************************************
3572+ Local Functions
3573+********************************************************/
3574+/**
3575+ * @brief This function reads the IO register.
3576+ *
3577+ * @param priv A pointer to uap_private structure
3578+ * @param reg register to be read
3579+ * @param dat A pointer to variable that keeps returned value
3580+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3581+ */
3582+static int
3583+sbi_read_ioreg(uap_private * priv, u32 reg, u8 * dat)
3584+{
3585+ struct sdio_mmc_card *card;
3586+ int ret = UAP_STATUS_FAILURE;
3587+
3588+ ENTER();
3589+
3590+ card = priv->uap_dev.card;
3591+ if (!card || !card->func) {
3592+ PRINTM(ERROR, "sbi_read_ioreg(): card or function is NULL!\n");
3593+ goto done;
3594+ }
3595+
3596+ *dat = sdio_readb(card->func, reg, &ret);
3597+ if (ret) {
3598+ PRINTM(ERROR, "sbi_read_ioreg(): sdio_readb failed! ret=%d\n", ret);
3599+ goto done;
3600+ }
3601+
3602+ PRINTM(INFO, "sbi_read_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
3603+ card->func->num, reg, *dat);
3604+
3605+ done:
3606+ LEAVE();
3607+ return ret;
3608+}
3609+
3610+/**
3611+ * @brief This function writes the IO register.
3612+ *
3613+ * @param priv A pointer to uap_private structure
3614+ * @param reg register to be written
3615+ * @param dat the value to be written
3616+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3617+ */
3618+static int
3619+sbi_write_ioreg(uap_private * priv, u32 reg, u8 dat)
3620+{
3621+ struct sdio_mmc_card *card;
3622+ int ret = UAP_STATUS_FAILURE;
3623+
3624+ ENTER();
3625+
3626+ card = priv->uap_dev.card;
3627+ if (!card || !card->func) {
3628+ PRINTM(ERROR, "sbi_write_ioreg(): card or function is NULL!\n");
3629+ goto done;
3630+ }
3631+
3632+ PRINTM(INFO, "sbi_write_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
3633+ card->func->num, reg, dat);
3634+
3635+ sdio_writeb(card->func, dat, reg, &ret);
3636+ if (ret) {
3637+ PRINTM(ERROR, "sbi_write_ioreg(): sdio_readb failed! ret=%d\n", ret);
3638+ goto done;
3639+ }
3640+
3641+ done:
3642+ LEAVE();
3643+ return ret;
3644+}
3645+
3646+/**
3647+ * @brief This function get rx_unit value
3648+ *
3649+ * @param priv A pointer to uap_private structure
3650+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3651+ */
3652+static int
3653+sd_get_rx_unit(uap_private * priv)
3654+{
3655+ int ret = UAP_STATUS_SUCCESS;
3656+ u8 reg;
3657+
3658+ ENTER();
3659+
3660+ ret = sbi_read_ioreg(priv, CARD_RX_UNIT_REG, &reg);
3661+ if (ret == UAP_STATUS_SUCCESS)
3662+ sdio_rx_unit = reg;
3663+
3664+ LEAVE();
3665+ return ret;
3666+}
3667+
3668+/**
3669+ * @brief This function reads rx length
3670+ *
3671+ * @param priv A pointer to uap_private structure
3672+ * @param dat A pointer to keep returned data
3673+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3674+ */
3675+static int
3676+sd_read_rx_len(uap_private * priv, u16 * dat)
3677+{
3678+ int ret = UAP_STATUS_SUCCESS;
3679+ u8 reg;
3680+
3681+ ENTER();
3682+
3683+ ret = sbi_read_ioreg(priv, CARD_RX_LEN_REG, &reg);
3684+ if (ret == UAP_STATUS_SUCCESS)
3685+ *dat = (u16) reg << sdio_rx_unit;
3686+
3687+ LEAVE();
3688+ return ret;
3689+}
3690+
3691+/**
3692+ * @brief This function reads fw status registers
3693+ *
3694+ * @param priv A pointer to uap_private structure
3695+ * @param dat A pointer to keep returned data
3696+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3697+ */
3698+static int
3699+sd_read_firmware_status(uap_private * priv, u16 * dat)
3700+{
3701+ int ret = UAP_STATUS_SUCCESS;
3702+ u8 fws0;
3703+ u8 fws1;
3704+
3705+ ENTER();
3706+
3707+ ret = sbi_read_ioreg(priv, CARD_FW_STATUS0_REG, &fws0);
3708+ if (ret < 0) {
3709+ LEAVE();
3710+ return UAP_STATUS_FAILURE;
3711+ }
3712+
3713+ ret = sbi_read_ioreg(priv, CARD_FW_STATUS1_REG, &fws1);
3714+ if (ret < 0) {
3715+ LEAVE();
3716+ return UAP_STATUS_FAILURE;
3717+ }
3718+
3719+ *dat = (((u16) fws1) << 8) | fws0;
3720+
3721+ LEAVE();
3722+ return UAP_STATUS_SUCCESS;
3723+}
3724+
3725+/**
3726+ * @brief This function polls the card status register.
3727+ *
3728+ * @param priv A pointer to uap_private structure
3729+ * @param bits the bit mask
3730+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3731+ */
3732+static int
3733+mv_sdio_poll_card_status(uap_private * priv, u8 bits)
3734+{
3735+ int tries;
3736+ u8 cs;
3737+
3738+ ENTER();
3739+
3740+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
3741+ if (sbi_read_ioreg(priv, CARD_STATUS_REG, &cs) < 0)
3742+ break;
3743+ else if ((cs & bits) == bits) {
3744+ LEAVE();
3745+ return UAP_STATUS_SUCCESS;
3746+ }
3747+ udelay(10);
3748+ }
3749+
3750+ PRINTM(WARN, "mv_sdio_poll_card_status failed, tries = %d\n", tries);
3751+
3752+ LEAVE();
3753+ return UAP_STATUS_FAILURE;
3754+}
3755+
3756+/**
3757+ * @brief This function set the sdio bus width.
3758+ *
3759+ * @param priv A pointer to uap_private structure
3760+ * @param mode 1--1 bit mode, 4--4 bit mode
3761+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3762+ */
3763+#if 0
3764+static int
3765+sdio_set_bus_width(uap_private * priv, u8 mode)
3766+{
3767+ ENTER();
3768+ LEAVE();
3769+ return UAP_STATUS_SUCCESS;
3770+}
3771+#endif
3772+
3773+/**
3774+ * @brief This function reads data from the card.
3775+ *
3776+ * @param priv A pointer to uap_private structure
3777+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3778+ */
3779+static int
3780+sd_card_to_host(uap_private * priv)
3781+{
3782+ int ret = UAP_STATUS_SUCCESS;
3783+ u16 buf_len = 0;
3784+ int buf_block_len;
3785+ int blksz;
3786+ struct sk_buff *skb = NULL;
3787+ u16 type;
3788+ u8 *payload = NULL;
3789+ struct sdio_mmc_card *card = priv->uap_dev.card;
3790+
3791+ ENTER();
3792+
3793+ if (!card || !card->func) {
3794+ PRINTM(ERROR, "card or function is NULL!\n");
3795+ ret = UAP_STATUS_FAILURE;
3796+ goto exit;
3797+ }
3798+
3799+ /* Read the length of data to be transferred */
3800+ ret = sd_read_rx_len(priv, &buf_len);
3801+ if (ret < 0) {
3802+ PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
3803+ ret = UAP_STATUS_FAILURE;
3804+ goto exit;
3805+ }
3806+
3807+ /* Allocate buffer */
3808+ blksz = SD_BLOCK_SIZE;
3809+ buf_block_len = (buf_len + blksz - 1) / blksz;
3810+ if (buf_len <= INTF_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
3811+ PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
3812+ ret = UAP_STATUS_FAILURE;
3813+ goto exit;
3814+ }
3815+#ifdef PXA3XX_DMA_ALIGN
3816+ skb = dev_alloc_skb(buf_block_len * blksz + PXA3XX_DMA_ALIGNMENT);
3817+#else
3818+ skb = dev_alloc_skb(buf_block_len * blksz);
3819+#endif
3820+ if (skb == NULL) {
3821+ PRINTM(WARN, "No free skb\n");
3822+ goto exit;
3823+ }
3824+#ifdef PXA3XX_DMA_ALIGN
3825+ if ((u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1)) {
3826+ skb_put(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
3827+ skb_pull(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
3828+ }
3829+#endif /* PXA3XX_DMA_ALIGN */
3830+
3831+ payload = skb->tail;
3832+ ret = sdio_readsb(card->func, payload, priv->uap_dev.ioport,
3833+ buf_block_len * blksz);
3834+ if (ret < 0) {
3835+ PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
3836+ ret = UAP_STATUS_FAILURE;
3837+ goto exit;
3838+ }
3839+ HEXDUMP("SDIO Blk Rd", payload, blksz * buf_block_len);
3840+ /*
3841+ * This is SDIO specific header
3842+ * u16 length,
3843+ * u16 type (MV_TYPE_DAT = 0, MV_TYPE_CMD = 1, MV_TYPE_EVENT = 3)
3844+ */
3845+ buf_len = uap_le16_to_cpu(*(u16 *) & payload[0]);
3846+ type = uap_le16_to_cpu(*(u16 *) & payload[2]);
3847+ switch (type) {
3848+ case MV_TYPE_EVENT:
3849+ skb_put(skb, buf_len);
3850+ skb_pull(skb, INTF_HEADER_LEN);
3851+ uap_process_event(priv, skb->data, skb->len);
3852+ kfree_skb(skb);
3853+ skb = NULL;
3854+ break;
3855+ case MV_TYPE_CMD:
3856+ skb_put(skb, buf_len);
3857+ skb_pull(skb, INTF_HEADER_LEN);
3858+ priv->adapter->cmd_pending = FALSE;
3859+ if (priv->adapter->cmd_wait_option ==
3860+ HostCmd_OPTION_WAITFORRSP_SLEEPCONFIRM) {
3861+ priv->adapter->cmd_wait_option = FALSE;
3862+ uap_process_sleep_confirm_resp(priv, skb->data, skb->len);
3863+ } else if (priv->adapter->cmd_wait_option) {
3864+ memcpy(priv->adapter->CmdBuf, skb->data, skb->len);
3865+ priv->adapter->CmdSize = skb->len;
3866+ priv->adapter->cmd_wait_option = FALSE;
3867+ priv->adapter->CmdWaitQWoken = TRUE;
3868+ wake_up_interruptible(&priv->adapter->cmdwait_q);
3869+ }
3870+ kfree_skb(skb);
3871+ skb = NULL;
3872+ break;
3873+ case MV_TYPE_DAT:
3874+ skb_put(skb, buf_len);
3875+ skb_pull(skb, INTF_HEADER_LEN);
3876+ uap_process_rx_packet(priv, skb);
3877+ break;
3878+ default:
3879+ priv->stats.rx_errors++;
3880+ priv->stats.rx_dropped++;
3881+ /* Driver specified event and command resp should be handle here */
3882+ PRINTM(INFO, "Unknown PKT type:%d\n", type);
3883+ kfree_skb(skb);
3884+ skb = NULL;
3885+ break;
3886+ }
3887+ exit:
3888+ if (ret) {
3889+ if (skb)
3890+ kfree_skb(skb);
3891+ }
3892+
3893+ LEAVE();
3894+ return ret;
3895+}
3896+
3897+/**
3898+ * @brief This function enables the host interrupts mask
3899+ *
3900+ * @param priv A pointer to uap_private structure
3901+ * @param mask the interrupt mask
3902+ * @return UAP_STATUS_SUCCESS
3903+ */
3904+static int
3905+enable_host_int_mask(uap_private * priv, u8 mask)
3906+{
3907+ int ret = UAP_STATUS_SUCCESS;
3908+
3909+ ENTER();
3910+
3911+ /* Simply write the mask to the register */
3912+ ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, mask);
3913+
3914+ if (ret) {
3915+ PRINTM(WARN, "Unable to enable the host interrupt!\n");
3916+ ret = UAP_STATUS_FAILURE;
3917+ }
3918+
3919+ LEAVE();
3920+ return ret;
3921+}
3922+
3923+/** @brief This function disables the host interrupts mask.
3924+ *
3925+ * @param priv A pointer to uap_private structure
3926+ * @param mask the interrupt mask
3927+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
3928+ */
3929+static int
3930+disable_host_int_mask(uap_private * priv, u8 mask)
3931+{
3932+ int ret = UAP_STATUS_SUCCESS;
3933+ u8 host_int_mask;
3934+
3935+ ENTER();
3936+
3937+ /* Read back the host_int_mask register */
3938+ ret = sbi_read_ioreg(priv, HOST_INT_MASK_REG, &host_int_mask);
3939+ if (ret) {
3940+ ret = UAP_STATUS_FAILURE;
3941+ goto done;
3942+ }
3943+
3944+ /* Update with the mask and write back to the register */
3945+ host_int_mask &= ~mask;
3946+ ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, host_int_mask);
3947+ if (ret < 0) {
3948+ PRINTM(WARN, "Unable to diable the host interrupt!\n");
3949+ ret = UAP_STATUS_FAILURE;
3950+ goto done;
3951+ }
3952+
3953+ done:
3954+ LEAVE();
3955+ return ret;
3956+}
3957+
3958+/********************************************************
3959+ Global Functions
3960+********************************************************/
3961+
3962+/**
3963+ * @brief This function handles the interrupt.
3964+ *
3965+ * @param func A pointer to sdio_func structure.
3966+ * @return n/a
3967+ */
3968+static void
3969+sbi_interrupt(struct sdio_func *func)
3970+{
3971+ struct sdio_mmc_card *card;
3972+ uap_private *priv;
3973+ u8 ireg = 0;
3974+ int ret = UAP_STATUS_SUCCESS;
3975+
3976+ ENTER();
3977+
3978+ card = sdio_get_drvdata(func);
3979+ if (!card || !card->priv) {
3980+ PRINTM(MSG, "%s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
3981+ __FUNCTION__, func, card);
3982+ LEAVE();
3983+ return;
3984+ }
3985+ priv = card->priv;
3986+#ifdef FW_WAKEUP_TIME
3987+ if ((priv->adapter->wt_pwrup_sending != 0L) &&
3988+ (priv->adapter->wt_int == 0L))
3989+ priv->adapter->wt_int = get_utimeofday();
3990+#endif
3991+
3992+ ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
3993+ if (ret) {
3994+ PRINTM(WARN, "sdio_read_ioreg: read int status register failed\n");
3995+ goto done;
3996+ }
3997+ if (ireg != 0) {
3998+ /*
3999+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
4000+ * Clear the interrupt status register and re-enable the interrupt
4001+ */
4002+ PRINTM(INFO, "sdio_ireg = 0x%x\n", ireg);
4003+ sdio_writeb(card->func,
4004+ ~(ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS),
4005+ HOST_INTSTATUS_REG, &ret);
4006+ if (ret) {
4007+ PRINTM(WARN,
4008+ "sdio_write_ioreg: clear int status register failed\n");
4009+ goto done;
4010+ }
4011+ }
4012+ OS_INT_DISABLE;
4013+ sd_ireg |= ireg;
4014+ OS_INT_RESTORE;
4015+
4016+ uap_interrupt(priv);
4017+ done:
4018+ LEAVE();
4019+}
4020+
4021+/**
4022+ * @brief This function probe the card
4023+ *
4024+ * @param func A pointer to sdio_func structure
4025+ * @param id A pointer to structure sd_device_id
4026+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4027+ */
4028+static int
4029+uap_probe(struct sdio_func *func, const struct sdio_device_id *id)
4030+{
4031+ int ret = UAP_STATUS_FAILURE;
4032+ struct sdio_mmc_card *card = NULL;
4033+
4034+ ENTER();
4035+
4036+ PRINTM(MSG, "%s: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
4037+ __FUNCTION__, func->vendor, func->device, func->class, func->num);
4038+
4039+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
4040+ if (!card) {
4041+ ret = -ENOMEM;
4042+ goto done;
4043+ }
4044+
4045+ card->func = func;
4046+
4047+ if (!uap_add_card(card)) {
4048+ PRINTM(ERROR, "%s: uap_add_callback failed\n", __FUNCTION__);
4049+ kfree(card);
4050+ ret = UAP_STATUS_FAILURE;
4051+ goto done;
4052+ }
4053+
4054+ ret = UAP_STATUS_SUCCESS;
4055+
4056+ done:
4057+ LEAVE();
4058+ return ret;
4059+}
4060+
4061+/**
4062+ * @brief This function removes the card
4063+ *
4064+ * @param func A pointer to sdio_func structure
4065+ * @return N/A
4066+ */
4067+static void
4068+uap_remove(struct sdio_func *func)
4069+{
4070+ struct sdio_mmc_card *card;
4071+
4072+ ENTER();
4073+
4074+ if (func) {
4075+ card = sdio_get_drvdata(func);
4076+ if (card) {
4077+ uap_remove_card(card);
4078+ kfree(card);
4079+ }
4080+ }
4081+
4082+ LEAVE();
4083+}
4084+
4085+#ifdef CONFIG_PM
4086+/**
4087+ * @brief This function handles client driver suspend
4088+ *
4089+ * @param func A pointer to sdio_func structure
4090+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4091+ */
4092+int
4093+uap_suspend(struct sdio_func *func)
4094+{
4095+ ENTER();
4096+ LEAVE();
4097+ return 0;
4098+}
4099+
4100+/**
4101+ * @brief This function handles client driver resume
4102+ *
4103+ * @param func A pointer to sdio_func structure
4104+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4105+ */
4106+int
4107+uap_resume(struct sdio_func *func)
4108+{
4109+ ENTER();
4110+ LEAVE();
4111+ return 0;
4112+}
4113+#endif
4114+
4115+/** Device ID for SD8688 */
4116+#define SD_DEVICE_ID_8688_UAP 0x9104
4117+/** UAP IDs */
4118+static const struct sdio_device_id uap_ids[] = {
4119+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SD_DEVICE_ID_8688_UAP)},
4120+ {},
4121+};
4122+
4123+MODULE_DEVICE_TABLE(sdio, uap_ids);
4124+
4125+static struct sdio_driver uap_sdio = {
4126+ .name = "uap_sdio",
4127+ .id_table = uap_ids,
4128+ .probe = uap_probe,
4129+ .remove = uap_remove,
4130+#ifdef CONFIG_PM
4131+/* .suspend = uap_suspend, */
4132+/* .resume = uap_resume, */
4133+#endif
4134+
4135+};
4136+
4137+/**
4138+ * @brief This function registers the IF module in bus driver.
4139+ *
4140+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4141+ */
4142+int __init
4143+sbi_register()
4144+{
4145+ int ret = UAP_STATUS_SUCCESS;
4146+
4147+ ENTER();
4148+
4149+ /* SDIO Driver Registration */
4150+ if (sdio_register_driver(&uap_sdio) != 0) {
4151+ PRINTM(FATAL, "SDIO Driver Registration Failed \n");
4152+ ret = UAP_STATUS_FAILURE;
4153+ }
4154+
4155+ LEAVE();
4156+ return ret;
4157+}
4158+
4159+/**
4160+ * @brief This function de-registers the IF module in bus driver.
4161+ *
4162+ * @return n/a
4163+ */
4164+void __exit
4165+sbi_unregister(void)
4166+{
4167+ ENTER();
4168+
4169+ /* SDIO Driver Unregistration */
4170+ sdio_unregister_driver(&uap_sdio);
4171+
4172+ LEAVE();
4173+}
4174+
4175+/**
4176+ * @brief This function checks the interrupt status and handle it accordingly.
4177+ *
4178+ * @param priv A pointer to uap_private structure
4179+ * @param ireg A pointer to variable that keeps returned value
4180+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4181+ */
4182+int
4183+sbi_get_int_status(uap_private * priv, u8 * ireg)
4184+{
4185+ int ret = UAP_STATUS_SUCCESS;
4186+ u8 sdio_ireg = 0;
4187+ struct sdio_mmc_card *card = priv->uap_dev.card;
4188+
4189+ ENTER();
4190+
4191+ *ireg = 0;
4192+ OS_INT_DISABLE;
4193+ sdio_ireg = sd_ireg;
4194+ sd_ireg = 0;
4195+ OS_INT_RESTORE;
4196+
4197+ sdio_claim_host(card->func);
4198+
4199+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT */
4200+ if (!priv->uap_dev.cmd_sent) { /* tx_done already received */
4201+ PRINTM(INFO,
4202+ "warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
4203+ priv->uap_dev.cmd_sent, sdio_ireg);
4204+ } else {
4205+ priv->uap_dev.cmd_sent = FALSE;
4206+ priv->uap_dev.data_sent = FALSE;
4207+ if ( (priv->uap_dev.netdev->reg_state == NETREG_REGISTERED) && (skb_queue_len(&priv->adapter->tx_queue) < TX_LOW_WATERMARK)) {
4208+ os_start_queue(priv);
4209+ }
4210+ }
4211+ }
4212+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
4213+ sd_card_to_host(priv);
4214+ }
4215+
4216+ *ireg = sdio_ireg;
4217+ ret = UAP_STATUS_SUCCESS;
4218+ sdio_release_host(card->func);
4219+
4220+ LEAVE();
4221+ return ret;
4222+}
4223+
4224+/**
4225+ * @brief This function disables the host interrupts.
4226+ *
4227+ * @param priv A pointer to uap_private structure
4228+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4229+ */
4230+int
4231+sbi_disable_host_int(uap_private * priv)
4232+{
4233+ struct sdio_mmc_card *card = priv->uap_dev.card;
4234+ int ret;
4235+
4236+ ENTER();
4237+
4238+ sdio_claim_host(card->func);
4239+ ret = disable_host_int_mask(priv, HIM_DISABLE);
4240+ sdio_release_host(card->func);
4241+
4242+ LEAVE();
4243+ return ret;
4244+}
4245+
4246+/**
4247+ * @brief This function enables the host interrupts.
4248+ *
4249+ * @param priv A pointer to uap_private structure
4250+ * @return UAP_STATUS_SUCCESS
4251+ */
4252+int
4253+sbi_enable_host_int(uap_private * priv)
4254+{
4255+ struct sdio_mmc_card *card = priv->uap_dev.card;
4256+ int ret;
4257+
4258+ ENTER();
4259+
4260+ sdio_claim_host(card->func);
4261+ ret = enable_host_int_mask(priv, HIM_ENABLE);
4262+ sdio_release_host(card->func);
4263+
4264+ LEAVE();
4265+ return ret;
4266+}
4267+
4268+/**
4269+ * @brief This function de-registers the device.
4270+ *
4271+ * @param priv A pointer to uap_private structure
4272+ * @return UAP_STATUS_SUCCESS
4273+ */
4274+int
4275+sbi_unregister_dev(uap_private * priv)
4276+{
4277+ struct sdio_mmc_card *card = priv->uap_dev.card;
4278+
4279+ ENTER();
4280+
4281+ if (!card || !card->func) {
4282+ PRINTM(ERROR, "Error: card or function is NULL!\n");
4283+ goto done;
4284+ }
4285+
4286+ sdio_claim_host(card->func);
4287+ sdio_release_irq(card->func);
4288+ sdio_disable_func(card->func);
4289+ sdio_release_host(card->func);
4290+
4291+ sdio_set_drvdata(card->func, NULL);
4292+
4293+ done:
4294+ LEAVE();
4295+ return UAP_STATUS_SUCCESS;
4296+}
4297+
4298+/**
4299+ * @brief This function registers the device.
4300+ *
4301+ * @param priv A pointer to uap_private structure
4302+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4303+ */
4304+int
4305+sbi_register_dev(uap_private * priv)
4306+{
4307+ int ret = UAP_STATUS_FAILURE;
4308+ u8 reg;
4309+ struct sdio_mmc_card *card = priv->uap_dev.card;
4310+ struct sdio_func *func;
4311+
4312+ ENTER();
4313+
4314+ if (!card || !card->func) {
4315+ PRINTM(ERROR, "Error: card or function is NULL!\n");
4316+ goto done;
4317+ }
4318+
4319+ func = card->func;
4320+
4321+ /* Initialize the private structure */
4322+ priv->uap_dev.ioport = 0;
4323+
4324+ sdio_claim_host(func);
4325+
4326+ ret = sdio_enable_func(func);
4327+ if (ret) {
4328+ PRINTM(FATAL, "sdio_enable_func() failed: ret=%d\n", ret);
4329+ goto release_host;
4330+ }
4331+
4332+ ret = sdio_claim_irq(func, sbi_interrupt);
4333+ if (ret) {
4334+ PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
4335+ goto disable_func;
4336+ }
4337+
4338+ /* Read the IO port */
4339+ ret = sbi_read_ioreg(priv, IO_PORT_0_REG, &reg);
4340+ if (ret)
4341+ goto release_irq;
4342+ else
4343+ priv->uap_dev.ioport |= reg;
4344+
4345+ ret = sbi_read_ioreg(priv, IO_PORT_1_REG, &reg);
4346+ if (ret)
4347+ goto release_irq;
4348+ else
4349+ priv->uap_dev.ioport |= (reg << 8);
4350+
4351+ ret = sbi_read_ioreg(priv, IO_PORT_2_REG, &reg);
4352+ if (ret)
4353+ goto release_irq;
4354+ else
4355+ priv->uap_dev.ioport |= (reg << 16);
4356+
4357+ PRINTM(INFO, "SDIO FUNC #%d IO port: 0x%x\n", func->num,
4358+ priv->uap_dev.ioport);
4359+
4360+ ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
4361+ if (ret) {
4362+ PRINTM(ERROR, "%s: cannot set SDIO block size\n", __FUNCTION__);
4363+ ret = UAP_STATUS_FAILURE;
4364+ goto release_irq;
4365+ }
4366+ priv->hotplug_device = &func->dev;
4367+
4368+ if (helper_name == NULL) {
4369+ helper_name = DEFAULT_HELPER_NAME;
4370+ }
4371+ if (fw_name == NULL) {
4372+ fw_name = DEFAULT_FW_NAME;
4373+ }
4374+ sdio_release_host(func);
4375+
4376+ sdio_set_drvdata(func, card);
4377+
4378+ ret = UAP_STATUS_SUCCESS;
4379+ goto done;
4380+
4381+ release_irq:
4382+ sdio_release_irq(func);
4383+ disable_func:
4384+ sdio_disable_func(func);
4385+ release_host:
4386+ sdio_release_host(func);
4387+
4388+ done:
4389+ LEAVE();
4390+ return ret;
4391+}
4392+
4393+/**
4394+ * @brief This function sends data to the card.
4395+ *
4396+ * @param priv A pointer to uap_private structure
4397+ * @param payload A pointer to the data/cmd buffer
4398+ * @param nb the length of data/cmd
4399+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4400+ */
4401+int
4402+sbi_host_to_card(uap_private * priv, u8 * payload, u16 nb)
4403+{
4404+ struct sdio_mmc_card *card = priv->uap_dev.card;
4405+ int ret = UAP_STATUS_SUCCESS;
4406+ int buf_block_len;
4407+ int blksz;
4408+ int i = 0;
4409+ u8 *buf = NULL;
4410+#ifdef PXA3XX_DMA_ALIGN
4411+ void *tmpbuf = NULL;
4412+ int tmpbufsz;
4413+#endif
4414+
4415+ ENTER();
4416+
4417+ if (!card || !card->func) {
4418+ PRINTM(ERROR, "card or function is NULL!\n");
4419+ LEAVE();
4420+ return UAP_STATUS_FAILURE;
4421+ }
4422+ buf = payload;
4423+#ifdef PXA3XX_DMA_ALIGN
4424+ if ((u32) payload & (PXA3XX_DMA_ALIGNMENT - 1)) {
4425+ tmpbufsz = ALIGN_SZ(nb, PXA3XX_DMA_ALIGNMENT);
4426+ tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
4427+ memset(tmpbuf, 0, tmpbufsz);
4428+ /* Ensure 8-byte aligned CMD buffer */
4429+ buf = (u8 *) ALIGN_ADDR(tmpbuf, PXA3XX_DMA_ALIGNMENT);
4430+ memcpy(buf, payload, nb);
4431+ }
4432+#endif
4433+ /* Allocate buffer and copy payload */
4434+ blksz = SD_BLOCK_SIZE;
4435+ buf_block_len = (nb + blksz - 1) / blksz;
4436+ sdio_claim_host(card->func);
4437+#define MAX_WRITE_IOMEM_RETRY 2
4438+ priv->uap_dev.cmd_sent = TRUE;
4439+ priv->uap_dev.data_sent = TRUE;
4440+ do {
4441+ /* Transfer data to card */
4442+ ret = sdio_writesb(card->func, priv->uap_dev.ioport, buf,
4443+ buf_block_len * blksz);
4444+ if (ret < 0) {
4445+ i++;
4446+ PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
4447+ ret);
4448+ ret = UAP_STATUS_FAILURE;
4449+ if (i > MAX_WRITE_IOMEM_RETRY)
4450+ goto exit;
4451+ } else {
4452+ HEXDUMP("SDIO Blk Wr", payload, nb);
4453+ }
4454+ } while (ret == UAP_STATUS_FAILURE);
4455+ exit:
4456+ sdio_release_host(card->func);
4457+#ifdef PXA3XX_DMA_ALIGN
4458+ if (tmpbuf)
4459+ kfree(tmpbuf);
4460+#endif
4461+ if (ret == UAP_STATUS_FAILURE) {
4462+ priv->uap_dev.cmd_sent = FALSE;
4463+ priv->uap_dev.data_sent = FALSE;
4464+ }
4465+ LEAVE();
4466+ return ret;
4467+}
4468+
4469+/**
4470+ * @brief This function reads CIS information.
4471+ *
4472+ * @param priv A pointer to uap_private structure
4473+ * @param cisinfo A pointer to CIS information output buffer
4474+ * @param cislen A pointer to length of CIS info output buffer
4475+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4476+ */
4477+#if 0
4478+static int
4479+sbi_get_cis_info(uap_private * priv, void *cisinfo, int *cislen)
4480+{
4481+#define CIS_PTR (0x8000)
4482+ struct sdio_mmc_card *card = priv->uap_dev.card;
4483+ unsigned int i, cis_ptr = CIS_PTR;
4484+ int ret = UAP_STATUS_FAILURE;
4485+
4486+ ENTER();
4487+
4488+ if (!card || !card->func) {
4489+ PRINTM(ERROR, "sbi_get_cis_info(): card or function is NULL!\n");
4490+ goto exit;
4491+ }
4492+#define MAX_SDIO_CIS_INFO_LEN (256)
4493+ if (!cisinfo || (*cislen < MAX_SDIO_CIS_INFO_LEN)) {
4494+ PRINTM(WARN, "ERROR! get_cis_info: insufficient buffer passed\n");
4495+ goto exit;
4496+ }
4497+
4498+ *cislen = MAX_SDIO_CIS_INFO_LEN;
4499+
4500+ sdio_claim_host(card->func);
4501+
4502+ PRINTM(INFO, "cis_ptr=%#x\n", cis_ptr);
4503+
4504+ /* Read the Tuple Data */
4505+ for (i = 0; i < *cislen; i++) {
4506+ ((unsigned char *) cisinfo)[i] =
4507+ sdio_readb(card->func, cis_ptr + i, &ret);
4508+ if (ret) {
4509+ PRINTM(WARN, "get_cis_info error: ret=%d\n", ret);
4510+ ret = UAP_STATUS_FAILURE;
4511+ goto done;
4512+ }
4513+ PRINTM(INFO, "cisinfo[%d]=%#x\n", i, ((unsigned char *) cisinfo)[i]);
4514+ }
4515+
4516+ done:
4517+ sdio_release_host(card->func);
4518+ exit:
4519+ LEAVE();
4520+ return ret;
4521+}
4522+#endif
4523+/**
4524+ * @brief This function downloads helper image to the card.
4525+ *
4526+ * @param priv A pointer to uap_private structure
4527+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4528+ */
4529+int
4530+sbi_prog_helper(uap_private * priv)
4531+{
4532+ struct sdio_mmc_card *card = priv->uap_dev.card;
4533+ u8 *helper = NULL;
4534+ int helperlen;
4535+ int ret = UAP_STATUS_SUCCESS;
4536+ void *tmphlprbuf = NULL;
4537+ int tmphlprbufsz;
4538+ u8 *hlprbuf;
4539+ int hlprblknow;
4540+ u32 tx_len;
4541+#ifdef FW_DOWNLOAD_SPEED
4542+ u32 tv1, tv2;
4543+#endif
4544+
4545+ ENTER();
4546+
4547+ if (!card || !card->func) {
4548+ PRINTM(ERROR, "sbi_prog_helper(): card or function is NULL!\n");
4549+ goto done;
4550+ }
4551+
4552+ if (priv->fw_helper) {
4553+ helper = (u8 *) priv->fw_helper->data;
4554+ helperlen = priv->fw_helper->size;
4555+ } else {
4556+ PRINTM(MSG, "No helper image found! Terminating download.\n");
4557+ LEAVE();
4558+ return UAP_STATUS_FAILURE;
4559+ }
4560+
4561+ PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
4562+ helperlen, SD_BLOCK_SIZE);
4563+
4564+#ifdef FW_DOWNLOAD_SPEED
4565+ tv1 = get_utimeofday();
4566+#endif
4567+
4568+#ifdef PXA3XX_DMA_ALIGN
4569+ tmphlprbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
4570+#else /* !PXA3XX_DMA_ALIGN */
4571+ tmphlprbufsz = UAP_UPLD_SIZE;
4572+#endif /* !PXA3XX_DMA_ALIGN */
4573+ tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
4574+ if (!tmphlprbuf) {
4575+ PRINTM(ERROR,
4576+ "Unable to allocate buffer for helper. Terminating download\n");
4577+ ret = UAP_STATUS_FAILURE;
4578+ goto done;
4579+ }
4580+ memset(tmphlprbuf, 0, tmphlprbufsz);
4581+#ifdef PXA3XX_DMA_ALIGN
4582+ hlprbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, PXA3XX_DMA_ALIGNMENT);
4583+#else /* !PXA3XX_DMA_ALIGN */
4584+ hlprbuf = (u8 *) tmphlprbuf;
4585+#endif /* !PXA3XX_DMA_ALIGN */
4586+
4587+ sdio_claim_host(card->func);
4588+
4589+ /* Perform helper data transfer */
4590+ tx_len = (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE) - INTF_HEADER_LEN;
4591+ hlprblknow = 0;
4592+ do {
4593+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
4594+ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
4595+ if (ret < 0) {
4596+ PRINTM(FATAL, "Helper download poll status timeout @ %d\n",
4597+ hlprblknow);
4598+ goto done;
4599+ }
4600+
4601+ /* More data? */
4602+ if (hlprblknow >= helperlen)
4603+ break;
4604+
4605+ /* Set blocksize to transfer - checking for last block */
4606+ if (helperlen - hlprblknow < tx_len)
4607+ tx_len = helperlen - hlprblknow;
4608+
4609+ /* Set length to the 4-byte header */
4610+ *(u32 *) hlprbuf = uap_cpu_to_le32(tx_len);
4611+
4612+ /* Copy payload to buffer */
4613+ memcpy(&hlprbuf[INTF_HEADER_LEN], &helper[hlprblknow], tx_len);
4614+
4615+ PRINTM(INFO, ".");
4616+
4617+ /* Send data */
4618+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
4619+ hlprbuf, FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE);
4620+
4621+ if (ret < 0) {
4622+ PRINTM(FATAL, "IO error during helper download @ %d\n", hlprblknow);
4623+ goto done;
4624+ }
4625+
4626+ hlprblknow += tx_len;
4627+ } while (TRUE);
4628+
4629+#ifdef FW_DOWNLOAD_SPEED
4630+ tv2 = get_utimeofday();
4631+ PRINTM(INFO, "helper: %ld.%03ld.%03ld ", tv1 / 1000000,
4632+ (tv1 % 1000000) / 1000, tv1 % 1000);
4633+ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000,
4634+ tv2 % 1000);
4635+ tv2 -= tv1;
4636+ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000,
4637+ tv2 % 1000);
4638+#endif
4639+
4640+ /* Write last EOF data */
4641+ PRINTM(INFO, "\nTransferring helper image EOF block\n");
4642+ memset(hlprbuf, 0x0, SD_BLOCK_SIZE);
4643+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
4644+ hlprbuf, SD_BLOCK_SIZE);
4645+
4646+ if (ret < 0) {
4647+ PRINTM(FATAL, "IO error in writing helper image EOF block\n");
4648+ goto done;
4649+ }
4650+
4651+ ret = UAP_STATUS_SUCCESS;
4652+
4653+ done:
4654+ sdio_release_host(card->func);
4655+ if (tmphlprbuf)
4656+ kfree(tmphlprbuf);
4657+
4658+ LEAVE();
4659+ return ret;
4660+}
4661+
4662+/**
4663+ * @brief This function downloads firmware image to the card.
4664+ *
4665+ * @param priv A pointer to uap_private structure
4666+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4667+ */
4668+int
4669+sbi_prog_fw_w_helper(uap_private * priv)
4670+{
4671+ struct sdio_mmc_card *card = priv->uap_dev.card;
4672+ u8 *firmware = NULL;
4673+ int firmwarelen;
4674+ u8 base0;
4675+ u8 base1;
4676+ int ret = UAP_STATUS_SUCCESS;
4677+ int offset;
4678+ void *tmpfwbuf = NULL;
4679+ int tmpfwbufsz;
4680+ u8 *fwbuf;
4681+ u16 len;
4682+ int txlen = 0;
4683+ int tx_blocks = 0;
4684+ int i = 0;
4685+ int tries = 0;
4686+#ifdef FW_DOWNLOAD_SPEED
4687+ u32 tv1, tv2;
4688+#endif
4689+
4690+ ENTER();
4691+
4692+ if (!card || !card->func) {
4693+ PRINTM(ERROR, "sbi_prog_fw_w_helper(): card or function is NULL!\n");
4694+ goto done;
4695+ }
4696+
4697+ if (priv->firmware) {
4698+ firmware = (u8 *) priv->firmware->data;
4699+ firmwarelen = priv->firmware->size;
4700+ } else {
4701+ PRINTM(MSG, "No firmware image found! Terminating download.\n");
4702+ LEAVE();
4703+ return UAP_STATUS_FAILURE;
4704+ }
4705+
4706+ PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
4707+
4708+#ifdef FW_DOWNLOAD_SPEED
4709+ tv1 = get_utimeofday();
4710+#endif
4711+
4712+#ifdef PXA3XX_DMA_ALIGN
4713+ tmpfwbufsz = ALIGN_SZ(UAP_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
4714+#else /* PXA3XX_DMA_ALIGN */
4715+ tmpfwbufsz = UAP_UPLD_SIZE;
4716+#endif /* PXA3XX_DMA_ALIGN */
4717+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
4718+ if (!tmpfwbuf) {
4719+ PRINTM(ERROR,
4720+ "Unable to allocate buffer for firmware. Terminating download.\n");
4721+ ret = UAP_STATUS_FAILURE;
4722+ goto done;
4723+ }
4724+ memset(tmpfwbuf, 0, tmpfwbufsz);
4725+#ifdef PXA3XX_DMA_ALIGN
4726+ /* Ensure 8-byte aligned firmware buffer */
4727+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT);
4728+#else /* PXA3XX_DMA_ALIGN */
4729+ fwbuf = (u8 *) tmpfwbuf;
4730+#endif /* PXA3XX_DMA_ALIGN */
4731+
4732+ sdio_claim_host(card->func);
4733+
4734+ /* Perform firmware data transfer */
4735+ offset = 0;
4736+ do {
4737+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
4738+ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
4739+ if (ret < 0) {
4740+ PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n",
4741+ offset);
4742+ goto done;
4743+ }
4744+
4745+ /* More data? */
4746+ if (offset >= firmwarelen)
4747+ break;
4748+
4749+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
4750+ if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_0, &base0)) < 0) {
4751+ PRINTM(WARN, "Dev BASE0 register read failed:"
4752+ " base0=0x%04X(%d). Terminating download.\n", base0,
4753+ base0);
4754+ ret = UAP_STATUS_FAILURE;
4755+ goto done;
4756+ }
4757+ if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_1, &base1)) < 0) {
4758+ PRINTM(WARN, "Dev BASE1 register read failed:"
4759+ " base1=0x%04X(%d). Terminating download.\n", base1,
4760+ base1);
4761+ ret = UAP_STATUS_FAILURE;
4762+ goto done;
4763+ }
4764+ len = (((u16) base1) << 8) | base0;
4765+
4766+ /* For SD8688 wait until the length is not 0, 1 or 2 before
4767+ downloading the first FW block, since BOOT code writes the
4768+ register to indicate the helper/FW download winner, the value
4769+ could be 1 or 2 (Func1 or Func2). */
4770+ if ((len && offset) || (len > 2))
4771+ break;
4772+ udelay(10);
4773+ }
4774+
4775+ if (len == 0)
4776+ break;
4777+ else if (len > UAP_UPLD_SIZE) {
4778+ PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
4779+ offset, len);
4780+ ret = UAP_STATUS_FAILURE;
4781+ goto done;
4782+ }
4783+
4784+ txlen = len;
4785+
4786+ if (len & BIT(0)) {
4787+ i++;
4788+ if (i > MAX_WRITE_IOMEM_RETRY) {
4789+ PRINTM(FATAL,
4790+ "FW download failure @ %d, over max retry count\n",
4791+ offset);
4792+ ret = UAP_STATUS_FAILURE;
4793+ goto done;
4794+ }
4795+ PRINTM(ERROR, "FW CRC error indicated by the helper:"
4796+ " len = 0x%04X, txlen = %d\n", len, txlen);
4797+ len &= ~BIT(0);
4798+ /* Setting this to 0 to resend from same offset */
4799+ txlen = 0;
4800+ } else {
4801+ i = 0;
4802+
4803+ /* Set blocksize to transfer - checking for last block */
4804+ if (firmwarelen - offset < txlen) {
4805+ txlen = firmwarelen - offset;
4806+ }
4807+ PRINTM(INFO, ".");
4808+
4809+ tx_blocks = (txlen + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE;
4810+
4811+ /* Copy payload to buffer */
4812+ memcpy(fwbuf, &firmware[offset], txlen);
4813+ }
4814+
4815+ /* Send data */
4816+ ret = sdio_writesb(card->func, priv->uap_dev.ioport,
4817+ fwbuf, tx_blocks * SD_BLOCK_SIZE);
4818+
4819+ if (ret < 0) {
4820+ PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
4821+ offset);
4822+ if (sbi_write_ioreg(priv, CONFIGURATION_REG, 0x04) < 0) {
4823+ PRINTM(ERROR, "write ioreg failed (CFG)\n");
4824+ }
4825+ }
4826+
4827+ offset += txlen;
4828+ } while (TRUE);
4829+
4830+ PRINTM(INFO, "\nFW download over, size %d bytes\n", offset);
4831+
4832+ ret = UAP_STATUS_SUCCESS;
4833+ done:
4834+#ifdef FW_DOWNLOAD_SPEED
4835+ tv2 = get_utimeofday();
4836+ PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
4837+ (tv1 % 1000000) / 1000, tv1 % 1000);
4838+ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
4839+ (tv2 % 1000000) / 1000, tv2 % 1000);
4840+ tv2 -= tv1;
4841+ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
4842+ (tv2 % 1000000) / 1000, tv2 % 1000);
4843+#endif
4844+ sdio_release_host(card->func);
4845+ if (tmpfwbuf)
4846+ kfree(tmpfwbuf);
4847+
4848+ LEAVE();
4849+ return ret;
4850+}
4851+
4852+/**
4853+ * @brief This function checks if the firmware is ready to accept
4854+ * command or not.
4855+ *
4856+ * @param priv A pointer to uap_private structure
4857+ * @param pollnum Poll number
4858+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4859+ */
4860+int
4861+sbi_check_fw_status(uap_private * priv, int pollnum)
4862+{
4863+ struct sdio_mmc_card *card = priv->uap_dev.card;
4864+ int ret = UAP_STATUS_SUCCESS;
4865+ u16 firmwarestat;
4866+ int tries;
4867+
4868+ ENTER();
4869+
4870+ sdio_claim_host(card->func);
4871+
4872+ /* Wait for firmware initialization event */
4873+ for (tries = 0; tries < pollnum; tries++) {
4874+ if ((ret = sd_read_firmware_status(priv, &firmwarestat)) < 0)
4875+ continue;
4876+ if (firmwarestat == FIRMWARE_READY) {
4877+ ret = UAP_STATUS_SUCCESS;
4878+ break;
4879+ } else {
4880+ mdelay(10);
4881+ ret = UAP_STATUS_FAILURE;
4882+ }
4883+ }
4884+
4885+ if (ret < 0)
4886+ goto done;
4887+
4888+ ret = UAP_STATUS_SUCCESS;
4889+ sd_get_rx_unit(priv);
4890+
4891+ done:
4892+ sdio_release_host(card->func);
4893+
4894+ LEAVE();
4895+ return ret;
4896+}
4897+
4898+/**
4899+ * @brief This function set bus clock on/off
4900+ *
4901+ * @param priv A pointer to uap_private structure
4902+ * @param option TRUE--on , FALSE--off
4903+ * @return UAP_STATUS_SUCCESS
4904+ */
4905+#if 0
4906+static int
4907+sbi_set_bus_clock(uap_private * priv, u8 option)
4908+{
4909+ ENTER();
4910+ LEAVE();
4911+ return UAP_STATUS_SUCCESS;
4912+}
4913+#endif
4914+
4915+/**
4916+ * @brief This function wakeup firmware
4917+ *
4918+ * @param priv A pointer to uap_private structure
4919+ * @return UAP_STATUS_SUCCESS or UAP_STATUS_FAILURE
4920+ */
4921+int
4922+sbi_wakeup_firmware(uap_private * priv)
4923+{
4924+ struct sdio_mmc_card *card = priv->uap_dev.card;
4925+ int ret = UAP_STATUS_SUCCESS;
4926+
4927+ ENTER();
4928+
4929+ if (!card || !card->func) {
4930+ PRINTM(ERROR, "card or function is NULL!\n");
4931+ LEAVE();
4932+ return UAP_STATUS_FAILURE;
4933+ }
4934+ sdio_claim_host(card->func);
4935+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
4936+ sdio_release_host(card->func);
4937+ LEAVE();
4938+ return ret;
4939+}
4940diff --git a/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h
4941new file mode 100644
4942index 0000000..191c67f
4943--- /dev/null
4944+++ b/drivers/net/wireless/libertas_uap/uap_sdio_mmc.h
4945@@ -0,0 +1,136 @@
4946+/** @file uap_sdio_mmc.h
4947+ * @brief This file contains SDIO IF (interface) module
4948+ * related macros, enum, and structure.
4949+ *
4950+ * Copyright (C) 2007-2009, Marvell International Ltd.
4951+ *
4952+ * This software file (the "File") is distributed by Marvell International
4953+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
4954+ * (the "License"). You may use, redistribute and/or modify this File in
4955+ * accordance with the terms and conditions of the License, a copy of which
4956+ * is available along with the File in the gpl.txt file or by writing to
4957+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
4958+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
4959+ *
4960+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
4961+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
4962+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
4963+ * this warranty disclaimer.
4964+ *
4965+ */
4966+/****************************************************
4967+Change log:
4968+ 10/10/07: initial version
4969+****************************************************/
4970+
4971+#ifndef _UAP_SDIO_MMC_H
4972+#define _UAP_SDIO_MMC_H
4973+
4974+#include <linux/mmc/sdio.h>
4975+#include <linux/mmc/sdio_ids.h>
4976+#include <linux/mmc/sdio_func.h>
4977+#include <linux/mmc/card.h>
4978+
4979+#include "uap_headers.h"
4980+
4981+/** The number of times to try when waiting for downloaded firmware to
4982+ become active. (polling the scratch register). */
4983+#define MAX_FIRMWARE_POLL_TRIES 100
4984+
4985+/** Firmware ready */
4986+#define FIRMWARE_READY 0xfedc
4987+
4988+/** Number of firmware blocks to transfer */
4989+#define FIRMWARE_TRANSFER_NBLOCK 2
4990+
4991+/* Host Control Registers */
4992+/** Host Control Registers : I/O port 0 */
4993+#define IO_PORT_0_REG 0x00
4994+/** Host Control Registers : I/O port 1 */
4995+#define IO_PORT_1_REG 0x01
4996+/** Host Control Registers : I/O port 2 */
4997+#define IO_PORT_2_REG 0x02
4998+
4999+/** Host Control Registers : Configuration */
5000+#define CONFIGURATION_REG 0x03
5001+/** Host Control Registers : Host without Command 53 finish host */
5002+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
5003+/** Host Control Registers : Host power up */
5004+#define HOST_POWER_UP (0x1U << 1)
5005+/** Host Control Registers : Host power down */
5006+#define HOST_POWER_DOWN (0x1U << 0)
5007+
5008+/** Host Control Registers : Host interrupt mask */
5009+#define HOST_INT_MASK_REG 0x04
5010+/** Host Control Registers : Upload host interrupt mask */
5011+#define UP_LD_HOST_INT_MASK (0x1U)
5012+/** Host Control Registers : Download host interrupt mask */
5013+#define DN_LD_HOST_INT_MASK (0x2U)
5014+/** Enable Host interrupt mask */
5015+#define HIM_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
5016+/** Disable Host interrupt mask */
5017+#define HIM_DISABLE 0xff
5018+
5019+/** Host Control Registers : Host interrupt status */
5020+#define HOST_INTSTATUS_REG 0x05
5021+/** Host Control Registers : Upload host interrupt status */
5022+#define UP_LD_HOST_INT_STATUS (0x1U)
5023+/** Host Control Registers : Download host interrupt status */
5024+#define DN_LD_HOST_INT_STATUS (0x2U)
5025+
5026+/** Host F1 read base 0 */
5027+#define HOST_F1_RD_BASE_0 0x10
5028+/** Host F1 read base 1 */
5029+#define HOST_F1_RD_BASE_1 0x11
5030+
5031+/** Card Control Registers : Card status register */
5032+#define CARD_STATUS_REG 0x20
5033+/** Card Control Registers : Card I/O ready */
5034+#define CARD_IO_READY (0x1U << 3)
5035+/** Card Control Registers : CIS card ready */
5036+#define CIS_CARD_RDY (0x1U << 2)
5037+/** Card Control Registers : Upload card ready */
5038+#define UP_LD_CARD_RDY (0x1U << 1)
5039+/** Card Control Registers : Download card ready */
5040+#define DN_LD_CARD_RDY (0x1U << 0)
5041+
5042+/** Card Control Registers : Card OCR 0 register */
5043+#define CARD_OCR_0_REG 0x34
5044+/** Card Control Registers : Card OCR 1 register */
5045+#define CARD_OCR_1_REG 0x35
5046+
5047+/** Firmware status 0 register */
5048+#define CARD_FW_STATUS0_REG 0x40
5049+/** Firmware status 1 register */
5050+#define CARD_FW_STATUS1_REG 0x41
5051+/** Rx length register */
5052+#define CARD_RX_LEN_REG 0x42
5053+/** Rx unit register */
5054+#define CARD_RX_UNIT_REG 0x43
5055+
5056+/** Chip Id Register 0 */
5057+#define CARD_CHIP_ID_0_REG 0x801c
5058+/** Chip Id Register 1 */
5059+#define CARD_CHIP_ID_1_REG 0x801d
5060+
5061+#ifdef PXA3XX_DMA_ALIGN
5062+/** DMA alignment value for PXA3XX platforms */
5063+#define PXA3XX_DMA_ALIGNMENT 8
5064+/** Macros for Data Alignment : size */
5065+#define ALIGN_SZ(p, a) \
5066+ (((p) + ((a) - 1)) & ~((a) - 1))
5067+
5068+/** Macros for Data Alignment : address */
5069+#define ALIGN_ADDR(p, a) \
5070+ ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1))
5071+#endif /* PXA3XX_DMA_ALIGN */
5072+
5073+struct sdio_mmc_card
5074+{
5075+ /** sdio_func structure pointer */
5076+ struct sdio_func *func;
5077+ /** uap_private structure pointer */
5078+ uap_private *priv;
5079+};
5080+
5081+#endif /* _UAP_SDIO_MMC_H */