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