diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-07-12 13:44:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-07-12 13:44:50 -0400 |
commit | 38a00840638b4932152bca48098dbfa069d942a2 (patch) | |
tree | dd12897854f6df8aac237d5fd46551c74be8153a /drivers/misc | |
parent | 391e5c22f5f4e55817f8ba18a08ea717ed2d4a1f (diff) | |
parent | 2f8684ce7a47c91da7e0ccba2686277c103d02b6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/Kconfig | 20 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/Makefile | 29 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/debugfs.c | 137 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/debugfs.h | 58 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/fw-download.c | 358 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/fw-msg.h | 113 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/iwmc3200top.h | 205 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/log.c | 348 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/log.h | 171 | ||||
-rw-r--r-- | drivers/misc/iwmc3200top/main.c | 662 |
12 files changed, 0 insertions, 2103 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2661f6e366f9..154f3ef07631 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -511,7 +511,6 @@ config USB_SWITCH_FSA9480 | |||
511 | source "drivers/misc/c2port/Kconfig" | 511 | source "drivers/misc/c2port/Kconfig" |
512 | source "drivers/misc/eeprom/Kconfig" | 512 | source "drivers/misc/eeprom/Kconfig" |
513 | source "drivers/misc/cb710/Kconfig" | 513 | source "drivers/misc/cb710/Kconfig" |
514 | source "drivers/misc/iwmc3200top/Kconfig" | ||
515 | source "drivers/misc/ti-st/Kconfig" | 514 | source "drivers/misc/ti-st/Kconfig" |
516 | source "drivers/misc/lis3lv02d/Kconfig" | 515 | source "drivers/misc/lis3lv02d/Kconfig" |
517 | source "drivers/misc/carma/Kconfig" | 516 | source "drivers/misc/carma/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 456972faaeb3..b88df7a350b8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -36,7 +36,6 @@ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o | |||
36 | obj-$(CONFIG_DS1682) += ds1682.o | 36 | obj-$(CONFIG_DS1682) += ds1682.o |
37 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o | 37 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o |
38 | obj-$(CONFIG_C2PORT) += c2port/ | 38 | obj-$(CONFIG_C2PORT) += c2port/ |
39 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ | ||
40 | obj-$(CONFIG_HMC6352) += hmc6352.o | 39 | obj-$(CONFIG_HMC6352) += hmc6352.o |
41 | obj-y += eeprom/ | 40 | obj-y += eeprom/ |
42 | obj-y += cb710/ | 41 | obj-y += cb710/ |
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig deleted file mode 100644 index 9e4b88fb57f1..000000000000 --- a/drivers/misc/iwmc3200top/Kconfig +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | config IWMC3200TOP | ||
2 | tristate "Intel Wireless MultiCom Top Driver" | ||
3 | depends on MMC && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | ---help--- | ||
6 | Intel Wireless MultiCom 3200 Top driver is responsible for | ||
7 | for firmware load and enabled coms enumeration | ||
8 | |||
9 | config IWMC3200TOP_DEBUG | ||
10 | bool "Enable full debug output of iwmc3200top Driver" | ||
11 | depends on IWMC3200TOP | ||
12 | ---help--- | ||
13 | Enable full debug output of iwmc3200top Driver | ||
14 | |||
15 | config IWMC3200TOP_DEBUGFS | ||
16 | bool "Enable Debugfs debugging interface for iwmc3200top" | ||
17 | depends on IWMC3200TOP | ||
18 | ---help--- | ||
19 | Enable creation of debugfs files for iwmc3200top | ||
20 | |||
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile deleted file mode 100644 index fbf53fb4634e..000000000000 --- a/drivers/misc/iwmc3200top/Makefile +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | # iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
2 | # drivers/misc/iwmc3200top/Makefile | ||
3 | # | ||
4 | # Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of the GNU General Public License version | ||
8 | # 2 as published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | # 02110-1301, USA. | ||
19 | # | ||
20 | # | ||
21 | # Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
22 | # - | ||
23 | # | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o | ||
27 | iwmc3200top-objs := main.o fw-download.o | ||
28 | iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o | ||
29 | iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o | ||
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c deleted file mode 100644 index 62fbaec48207..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.c +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/debufs.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include <linux/mmc/sdio_func.h> | ||
32 | #include <linux/mmc/sdio.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | |||
35 | #include "iwmc3200top.h" | ||
36 | #include "fw-msg.h" | ||
37 | #include "log.h" | ||
38 | #include "debugfs.h" | ||
39 | |||
40 | |||
41 | |||
42 | /* Constants definition */ | ||
43 | #define HEXADECIMAL_RADIX 16 | ||
44 | |||
45 | /* Functions definition */ | ||
46 | |||
47 | |||
48 | #define DEBUGFS_ADD(name, parent) do { \ | ||
49 | dbgfs->dbgfs_##parent##_files.file_##name = \ | ||
50 | debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ | ||
51 | &iwmct_dbgfs_##name##_ops); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define DEBUGFS_RM(name) do { \ | ||
55 | debugfs_remove(name); \ | ||
56 | name = NULL; \ | ||
57 | } while (0) | ||
58 | |||
59 | #define DEBUGFS_READ_FUNC(name) \ | ||
60 | ssize_t iwmct_dbgfs_##name##_read(struct file *file, \ | ||
61 | char __user *user_buf, \ | ||
62 | size_t count, loff_t *ppos); | ||
63 | |||
64 | #define DEBUGFS_WRITE_FUNC(name) \ | ||
65 | ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ | ||
66 | const char __user *user_buf, \ | ||
67 | size_t count, loff_t *ppos); | ||
68 | |||
69 | #define DEBUGFS_READ_FILE_OPS(name) \ | ||
70 | DEBUGFS_READ_FUNC(name) \ | ||
71 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | ||
72 | .read = iwmct_dbgfs_##name##_read, \ | ||
73 | .open = iwmct_dbgfs_open_file_generic, \ | ||
74 | .llseek = generic_file_llseek, \ | ||
75 | }; | ||
76 | |||
77 | #define DEBUGFS_WRITE_FILE_OPS(name) \ | ||
78 | DEBUGFS_WRITE_FUNC(name) \ | ||
79 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | ||
80 | .write = iwmct_dbgfs_##name##_write, \ | ||
81 | .open = iwmct_dbgfs_open_file_generic, \ | ||
82 | .llseek = generic_file_llseek, \ | ||
83 | }; | ||
84 | |||
85 | #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ | ||
86 | DEBUGFS_READ_FUNC(name) \ | ||
87 | DEBUGFS_WRITE_FUNC(name) \ | ||
88 | static const struct file_operations iwmct_dbgfs_##name##_ops = {\ | ||
89 | .write = iwmct_dbgfs_##name##_write, \ | ||
90 | .read = iwmct_dbgfs_##name##_read, \ | ||
91 | .open = iwmct_dbgfs_open_file_generic, \ | ||
92 | .llseek = generic_file_llseek, \ | ||
93 | }; | ||
94 | |||
95 | |||
96 | /* Debugfs file ops definitions */ | ||
97 | |||
98 | /* | ||
99 | * Create the debugfs files and directories | ||
100 | * | ||
101 | */ | ||
102 | void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) | ||
103 | { | ||
104 | struct iwmct_debugfs *dbgfs; | ||
105 | |||
106 | dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL); | ||
107 | if (!dbgfs) { | ||
108 | LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n", | ||
109 | sizeof(struct iwmct_debugfs)); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | priv->dbgfs = dbgfs; | ||
114 | dbgfs->name = name; | ||
115 | dbgfs->dir_drv = debugfs_create_dir(name, NULL); | ||
116 | if (!dbgfs->dir_drv) { | ||
117 | LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n"); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | return; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * Remove the debugfs files and directories | ||
126 | * | ||
127 | */ | ||
128 | void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) | ||
129 | { | ||
130 | if (!dbgfs) | ||
131 | return; | ||
132 | |||
133 | DEBUGFS_RM(dbgfs->dir_drv); | ||
134 | kfree(dbgfs); | ||
135 | dbgfs = NULL; | ||
136 | } | ||
137 | |||
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h deleted file mode 100644 index 71d45759b40f..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/debufs.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __DEBUGFS_H__ | ||
28 | #define __DEBUGFS_H__ | ||
29 | |||
30 | |||
31 | #ifdef CONFIG_IWMC3200TOP_DEBUGFS | ||
32 | |||
33 | struct iwmct_debugfs { | ||
34 | const char *name; | ||
35 | struct dentry *dir_drv; | ||
36 | struct dir_drv_files { | ||
37 | } dbgfs_drv_files; | ||
38 | }; | ||
39 | |||
40 | void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name); | ||
41 | void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs); | ||
42 | |||
43 | #else /* CONFIG_IWMC3200TOP_DEBUGFS */ | ||
44 | |||
45 | struct iwmct_debugfs; | ||
46 | |||
47 | static inline void | ||
48 | iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) | ||
49 | {} | ||
50 | |||
51 | static inline void | ||
52 | iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) | ||
53 | {} | ||
54 | |||
55 | #endif /* CONFIG_IWMC3200TOP_DEBUGFS */ | ||
56 | |||
57 | #endif /* __DEBUGFS_H__ */ | ||
58 | |||
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c deleted file mode 100644 index e27afde6e99f..000000000000 --- a/drivers/misc/iwmc3200top/fw-download.c +++ /dev/null | |||
@@ -1,358 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/fw-download.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/firmware.h> | ||
28 | #include <linux/mmc/sdio_func.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <asm/unaligned.h> | ||
31 | |||
32 | #include "iwmc3200top.h" | ||
33 | #include "log.h" | ||
34 | #include "fw-msg.h" | ||
35 | |||
36 | #define CHECKSUM_BYTES_NUM sizeof(u32) | ||
37 | |||
38 | /** | ||
39 | init parser struct with file | ||
40 | */ | ||
41 | static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, | ||
42 | size_t file_size, size_t block_size) | ||
43 | { | ||
44 | struct iwmct_parser *parser = &priv->parser; | ||
45 | struct iwmct_fw_hdr *fw_hdr = &parser->versions; | ||
46 | |||
47 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
48 | |||
49 | LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); | ||
50 | |||
51 | parser->file = file; | ||
52 | parser->file_size = file_size; | ||
53 | parser->cur_pos = 0; | ||
54 | parser->entry_point = 0; | ||
55 | parser->buf = kzalloc(block_size, GFP_KERNEL); | ||
56 | if (!parser->buf) { | ||
57 | LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | parser->buf_size = block_size; | ||
61 | |||
62 | /* extract fw versions */ | ||
63 | memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr)); | ||
64 | LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n" | ||
65 | "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n", | ||
66 | fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision, | ||
67 | fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision, | ||
68 | fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision, | ||
69 | fw_hdr->tic_name); | ||
70 | |||
71 | parser->cur_pos += sizeof(struct iwmct_fw_hdr); | ||
72 | |||
73 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static bool iwmct_checksum(struct iwmct_priv *priv) | ||
78 | { | ||
79 | struct iwmct_parser *parser = &priv->parser; | ||
80 | __le32 *file = (__le32 *)parser->file; | ||
81 | int i, pad, steps; | ||
82 | u32 accum = 0; | ||
83 | u32 checksum; | ||
84 | u32 mask = 0xffffffff; | ||
85 | |||
86 | pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4; | ||
87 | steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4; | ||
88 | |||
89 | LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps); | ||
90 | |||
91 | for (i = 0; i < steps; i++) | ||
92 | accum += le32_to_cpu(file[i]); | ||
93 | |||
94 | if (pad) { | ||
95 | mask <<= 8 * (4 - pad); | ||
96 | accum += le32_to_cpu(file[steps]) & mask; | ||
97 | } | ||
98 | |||
99 | checksum = get_unaligned_le32((__le32 *)(parser->file + | ||
100 | parser->file_size - CHECKSUM_BYTES_NUM)); | ||
101 | |||
102 | LOG_INFO(priv, FW_DOWNLOAD, | ||
103 | "compare checksum accum=0x%x to checksum=0x%x\n", | ||
104 | accum, checksum); | ||
105 | |||
106 | return checksum == accum; | ||
107 | } | ||
108 | |||
109 | static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, | ||
110 | size_t *sec_size, __le32 *sec_addr) | ||
111 | { | ||
112 | struct iwmct_parser *parser = &priv->parser; | ||
113 | struct iwmct_dbg *dbg = &priv->dbg; | ||
114 | struct iwmct_fw_sec_hdr *sec_hdr; | ||
115 | |||
116 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
117 | |||
118 | while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) | ||
119 | <= parser->file_size) { | ||
120 | |||
121 | sec_hdr = (struct iwmct_fw_sec_hdr *) | ||
122 | (parser->file + parser->cur_pos); | ||
123 | parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr); | ||
124 | |||
125 | LOG_INFO(priv, FW_DOWNLOAD, | ||
126 | "sec hdr: type=%s addr=0x%x size=%d\n", | ||
127 | sec_hdr->type, sec_hdr->target_addr, | ||
128 | sec_hdr->data_size); | ||
129 | |||
130 | if (strcmp(sec_hdr->type, "ENT") == 0) | ||
131 | parser->entry_point = le32_to_cpu(sec_hdr->target_addr); | ||
132 | else if (strcmp(sec_hdr->type, "LBL") == 0) | ||
133 | strcpy(dbg->label_fw, parser->file + parser->cur_pos); | ||
134 | else if (((strcmp(sec_hdr->type, "TOP") == 0) && | ||
135 | (priv->barker & BARKER_DNLOAD_TOP_MSK)) || | ||
136 | ((strcmp(sec_hdr->type, "GPS") == 0) && | ||
137 | (priv->barker & BARKER_DNLOAD_GPS_MSK)) || | ||
138 | ((strcmp(sec_hdr->type, "BTH") == 0) && | ||
139 | (priv->barker & BARKER_DNLOAD_BT_MSK))) { | ||
140 | *sec_addr = sec_hdr->target_addr; | ||
141 | *sec_size = le32_to_cpu(sec_hdr->data_size); | ||
142 | *p_sec = parser->file + parser->cur_pos; | ||
143 | parser->cur_pos += le32_to_cpu(sec_hdr->data_size); | ||
144 | return 1; | ||
145 | } else if (strcmp(sec_hdr->type, "LOG") != 0) | ||
146 | LOG_WARNING(priv, FW_DOWNLOAD, | ||
147 | "skipping section type %s\n", | ||
148 | sec_hdr->type); | ||
149 | |||
150 | parser->cur_pos += le32_to_cpu(sec_hdr->data_size); | ||
151 | LOG_INFO(priv, FW_DOWNLOAD, | ||
152 | "finished with section cur_pos=%zd\n", parser->cur_pos); | ||
153 | } | ||
154 | |||
155 | LOG_TRACE(priv, INIT, "<--\n"); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, | ||
160 | size_t sec_size, __le32 addr) | ||
161 | { | ||
162 | struct iwmct_parser *parser = &priv->parser; | ||
163 | struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; | ||
164 | const u8 *cur_block = p_sec; | ||
165 | size_t sent = 0; | ||
166 | int cnt = 0; | ||
167 | int ret = 0; | ||
168 | u32 cmd = 0; | ||
169 | |||
170 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
171 | LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", | ||
172 | addr, sec_size); | ||
173 | |||
174 | while (sent < sec_size) { | ||
175 | int i; | ||
176 | u32 chksm = 0; | ||
177 | u32 reset = atomic_read(&priv->reset); | ||
178 | /* actual FW data */ | ||
179 | u32 data_size = min(parser->buf_size - sizeof(*hdr), | ||
180 | sec_size - sent); | ||
181 | /* Pad to block size */ | ||
182 | u32 trans_size = (data_size + sizeof(*hdr) + | ||
183 | IWMC_SDIO_BLK_SIZE - 1) & | ||
184 | ~(IWMC_SDIO_BLK_SIZE - 1); | ||
185 | ++cnt; | ||
186 | |||
187 | /* in case of reset, interrupt FW DOWNLAOD */ | ||
188 | if (reset) { | ||
189 | LOG_INFO(priv, FW_DOWNLOAD, | ||
190 | "Reset detected. Abort FW download!!!"); | ||
191 | ret = -ECANCELED; | ||
192 | goto exit; | ||
193 | } | ||
194 | |||
195 | memset(parser->buf, 0, parser->buf_size); | ||
196 | cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS; | ||
197 | cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; | ||
198 | cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS; | ||
199 | cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS; | ||
200 | hdr->data_size = cpu_to_le32(data_size); | ||
201 | hdr->target_addr = addr; | ||
202 | |||
203 | /* checksum is allowed for sizes divisible by 4 */ | ||
204 | if (data_size & 0x3) | ||
205 | cmd &= ~CMD_HDR_USE_CHECKSUM_MSK; | ||
206 | |||
207 | memcpy(hdr->data, cur_block, data_size); | ||
208 | |||
209 | |||
210 | if (cmd & CMD_HDR_USE_CHECKSUM_MSK) { | ||
211 | |||
212 | chksm = data_size + le32_to_cpu(addr) + cmd; | ||
213 | for (i = 0; i < data_size >> 2; i++) | ||
214 | chksm += ((u32 *)cur_block)[i]; | ||
215 | |||
216 | hdr->block_chksm = cpu_to_le32(chksm); | ||
217 | LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n", | ||
218 | hdr->block_chksm); | ||
219 | } | ||
220 | |||
221 | LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, " | ||
222 | "sec_size=%zd, startAddress 0x%X\n", | ||
223 | cnt, trans_size, sent, sec_size, addr); | ||
224 | |||
225 | if (priv->dbg.dump) | ||
226 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size); | ||
227 | |||
228 | |||
229 | hdr->cmd = cpu_to_le32(cmd); | ||
230 | /* send it down */ | ||
231 | /* TODO: add more proper sending and error checking */ | ||
232 | ret = iwmct_tx(priv, parser->buf, trans_size); | ||
233 | if (ret != 0) { | ||
234 | LOG_INFO(priv, FW_DOWNLOAD, | ||
235 | "iwmct_tx returned %d\n", ret); | ||
236 | goto exit; | ||
237 | } | ||
238 | |||
239 | addr = cpu_to_le32(le32_to_cpu(addr) + data_size); | ||
240 | sent += data_size; | ||
241 | cur_block = p_sec + sent; | ||
242 | |||
243 | if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) { | ||
244 | LOG_INFO(priv, FW_DOWNLOAD, | ||
245 | "Block number limit is reached [%d]\n", | ||
246 | priv->dbg.blocks); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if (sent < sec_size) | ||
252 | ret = -EINVAL; | ||
253 | exit: | ||
254 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) | ||
259 | { | ||
260 | struct iwmct_parser *parser = &priv->parser; | ||
261 | struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; | ||
262 | int ret; | ||
263 | u32 cmd; | ||
264 | |||
265 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
266 | |||
267 | memset(parser->buf, 0, parser->buf_size); | ||
268 | cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; | ||
269 | if (jump) { | ||
270 | cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS; | ||
271 | hdr->target_addr = cpu_to_le32(parser->entry_point); | ||
272 | LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n", | ||
273 | parser->entry_point); | ||
274 | } else { | ||
275 | cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS; | ||
276 | LOG_INFO(priv, FW_DOWNLOAD, "last command\n"); | ||
277 | } | ||
278 | |||
279 | hdr->cmd = cpu_to_le32(cmd); | ||
280 | |||
281 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); | ||
282 | /* send it down */ | ||
283 | /* TODO: add more proper sending and error checking */ | ||
284 | ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE); | ||
285 | if (ret) | ||
286 | LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); | ||
287 | |||
288 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | int iwmct_fw_load(struct iwmct_priv *priv) | ||
293 | { | ||
294 | const u8 *fw_name = FW_NAME(FW_API_VER); | ||
295 | const struct firmware *raw; | ||
296 | const u8 *pdata; | ||
297 | size_t len; | ||
298 | __le32 addr; | ||
299 | int ret; | ||
300 | |||
301 | |||
302 | LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n", | ||
303 | priv->barker); | ||
304 | LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n", | ||
305 | (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); | ||
306 | LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n", | ||
307 | (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); | ||
308 | LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n", | ||
309 | (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); | ||
310 | |||
311 | |||
312 | /* get the firmware */ | ||
313 | ret = request_firmware(&raw, fw_name, &priv->func->dev); | ||
314 | if (ret < 0) { | ||
315 | LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n", | ||
316 | fw_name, ret); | ||
317 | goto exit; | ||
318 | } | ||
319 | |||
320 | if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) { | ||
321 | LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n", | ||
322 | fw_name, sizeof(struct iwmct_fw_sec_hdr), raw->size); | ||
323 | goto exit; | ||
324 | } | ||
325 | |||
326 | LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); | ||
327 | |||
328 | /* clear parser struct */ | ||
329 | ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); | ||
330 | if (ret < 0) { | ||
331 | LOG_ERROR(priv, FW_DOWNLOAD, | ||
332 | "iwmct_parser_init failed: Reason %d\n", ret); | ||
333 | goto exit; | ||
334 | } | ||
335 | |||
336 | if (!iwmct_checksum(priv)) { | ||
337 | LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); | ||
338 | ret = -EINVAL; | ||
339 | goto exit; | ||
340 | } | ||
341 | |||
342 | /* download firmware to device */ | ||
343 | while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { | ||
344 | ret = iwmct_download_section(priv, pdata, len, addr); | ||
345 | if (ret) { | ||
346 | LOG_ERROR(priv, FW_DOWNLOAD, | ||
347 | "%s download section failed\n", fw_name); | ||
348 | goto exit; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); | ||
353 | |||
354 | exit: | ||
355 | kfree(priv->parser.buf); | ||
356 | release_firmware(raw); | ||
357 | return ret; | ||
358 | } | ||
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h deleted file mode 100644 index 9e26b75bd482..000000000000 --- a/drivers/misc/iwmc3200top/fw-msg.h +++ /dev/null | |||
@@ -1,113 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/fw-msg.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __FWMSG_H__ | ||
28 | #define __FWMSG_H__ | ||
29 | |||
30 | #define COMM_TYPE_D2H 0xFF | ||
31 | #define COMM_TYPE_H2D 0xEE | ||
32 | |||
33 | #define COMM_CATEGORY_OPERATIONAL 0x00 | ||
34 | #define COMM_CATEGORY_DEBUG 0x01 | ||
35 | #define COMM_CATEGORY_TESTABILITY 0x02 | ||
36 | #define COMM_CATEGORY_DIAGNOSTICS 0x03 | ||
37 | |||
38 | #define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A) | ||
39 | |||
40 | #define FW_LOG_SRC_MAX 32 | ||
41 | #define FW_LOG_SRC_ALL 255 | ||
42 | |||
43 | #define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000) | ||
44 | |||
45 | #define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001) | ||
46 | #define CMD_TST_DEV_RESET cpu_to_le16(0x0060) | ||
47 | #define CMD_TST_FUNC_RESET cpu_to_le16(0x0062) | ||
48 | #define CMD_TST_IFACE_RESET cpu_to_le16(0x0064) | ||
49 | #define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065) | ||
50 | #define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080) | ||
51 | #define CMD_TST_WAKEUP cpu_to_le16(0x0081) | ||
52 | #define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082) | ||
53 | #define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083) | ||
54 | #define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096) | ||
55 | |||
56 | #define OP_OPR_ALIVE cpu_to_le16(0x0010) | ||
57 | #define OP_OPR_CMD_ACK cpu_to_le16(0x001F) | ||
58 | #define OP_OPR_CMD_NACK cpu_to_le16(0x0020) | ||
59 | #define OP_TST_MEM_DUMP cpu_to_le16(0x0043) | ||
60 | |||
61 | #define CMD_FLAG_PADDING_256 0x80 | ||
62 | |||
63 | #define FW_HCMD_BLOCK_SIZE 256 | ||
64 | |||
65 | struct msg_hdr { | ||
66 | u8 type; | ||
67 | u8 category; | ||
68 | __le16 opcode; | ||
69 | u8 seqnum; | ||
70 | u8 flags; | ||
71 | __le16 length; | ||
72 | } __attribute__((__packed__)); | ||
73 | |||
74 | struct log_hdr { | ||
75 | __le32 timestamp; | ||
76 | u8 severity; | ||
77 | u8 logsource; | ||
78 | __le16 reserved; | ||
79 | } __attribute__((__packed__)); | ||
80 | |||
81 | struct mdump_hdr { | ||
82 | u8 dmpid; | ||
83 | u8 frag; | ||
84 | __le16 size; | ||
85 | __le32 addr; | ||
86 | } __attribute__((__packed__)); | ||
87 | |||
88 | struct top_msg { | ||
89 | struct msg_hdr hdr; | ||
90 | union { | ||
91 | /* D2H messages */ | ||
92 | struct { | ||
93 | struct log_hdr log_hdr; | ||
94 | u8 data[1]; | ||
95 | } __attribute__((__packed__)) log; | ||
96 | |||
97 | struct { | ||
98 | struct log_hdr log_hdr; | ||
99 | struct mdump_hdr md_hdr; | ||
100 | u8 data[1]; | ||
101 | } __attribute__((__packed__)) mdump; | ||
102 | |||
103 | /* H2D messages */ | ||
104 | struct { | ||
105 | u8 logsource; | ||
106 | u8 sevmask; | ||
107 | } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX]; | ||
108 | struct mdump_hdr mdump_req; | ||
109 | } u; | ||
110 | } __attribute__((__packed__)); | ||
111 | |||
112 | |||
113 | #endif /* __FWMSG_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h deleted file mode 100644 index 620973ed8bf9..000000000000 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/iwmc3200top.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __IWMC3200TOP_H__ | ||
28 | #define __IWMC3200TOP_H__ | ||
29 | |||
30 | #include <linux/workqueue.h> | ||
31 | |||
32 | #define DRV_NAME "iwmc3200top" | ||
33 | #define FW_API_VER 1 | ||
34 | #define _FW_NAME(api) DRV_NAME "." #api ".fw" | ||
35 | #define FW_NAME(api) _FW_NAME(api) | ||
36 | |||
37 | #define IWMC_SDIO_BLK_SIZE 256 | ||
38 | #define IWMC_DEFAULT_TR_BLK 64 | ||
39 | #define IWMC_SDIO_DATA_ADDR 0x0 | ||
40 | #define IWMC_SDIO_INTR_ENABLE_ADDR 0x14 | ||
41 | #define IWMC_SDIO_INTR_STATUS_ADDR 0x13 | ||
42 | #define IWMC_SDIO_INTR_CLEAR_ADDR 0x13 | ||
43 | #define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C | ||
44 | |||
45 | #define COMM_HUB_HEADER_LENGTH 16 | ||
46 | #define LOGGER_HEADER_LENGTH 10 | ||
47 | |||
48 | |||
49 | #define BARKER_DNLOAD_BT_POS 0 | ||
50 | #define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS) | ||
51 | #define BARKER_DNLOAD_GPS_POS 1 | ||
52 | #define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS) | ||
53 | #define BARKER_DNLOAD_TOP_POS 2 | ||
54 | #define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS) | ||
55 | #define BARKER_DNLOAD_RESERVED1_POS 3 | ||
56 | #define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS) | ||
57 | #define BARKER_DNLOAD_JUMP_POS 4 | ||
58 | #define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS) | ||
59 | #define BARKER_DNLOAD_SYNC_POS 5 | ||
60 | #define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS) | ||
61 | #define BARKER_DNLOAD_RESERVED2_POS 6 | ||
62 | #define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS) | ||
63 | #define BARKER_DNLOAD_BARKER_POS 8 | ||
64 | #define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS) | ||
65 | |||
66 | #define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS) | ||
67 | /* whole field barker */ | ||
68 | #define IWMC_BARKER_ACK 0xfeedbabe | ||
69 | |||
70 | #define IWMC_CMD_SIGNATURE 0xcbbc | ||
71 | |||
72 | #define CMD_HDR_OPCODE_POS 0 | ||
73 | #define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS) | ||
74 | #define CMD_HDR_RESPONSE_CODE_POS 4 | ||
75 | #define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS) | ||
76 | #define CMD_HDR_USE_CHECKSUM_POS 8 | ||
77 | #define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS) | ||
78 | #define CMD_HDR_RESPONSE_REQUIRED_POS 9 | ||
79 | #define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS) | ||
80 | #define CMD_HDR_DIRECT_ACCESS_POS 10 | ||
81 | #define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS) | ||
82 | #define CMD_HDR_RESERVED_POS 11 | ||
83 | #define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS) | ||
84 | #define CMD_HDR_SIGNATURE_POS 16 | ||
85 | #define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS) | ||
86 | |||
87 | enum { | ||
88 | IWMC_OPCODE_PING = 0, | ||
89 | IWMC_OPCODE_READ = 1, | ||
90 | IWMC_OPCODE_WRITE = 2, | ||
91 | IWMC_OPCODE_JUMP = 3, | ||
92 | IWMC_OPCODE_REBOOT = 4, | ||
93 | IWMC_OPCODE_PERSISTENT_WRITE = 5, | ||
94 | IWMC_OPCODE_PERSISTENT_READ = 6, | ||
95 | IWMC_OPCODE_READ_MODIFY_WRITE = 7, | ||
96 | IWMC_OPCODE_LAST_COMMAND = 15 | ||
97 | }; | ||
98 | |||
99 | struct iwmct_fw_load_hdr { | ||
100 | __le32 cmd; | ||
101 | __le32 target_addr; | ||
102 | __le32 data_size; | ||
103 | __le32 block_chksm; | ||
104 | u8 data[0]; | ||
105 | }; | ||
106 | |||
107 | /** | ||
108 | * struct iwmct_fw_hdr | ||
109 | * holds all sw components versions | ||
110 | */ | ||
111 | struct iwmct_fw_hdr { | ||
112 | u8 top_major; | ||
113 | u8 top_minor; | ||
114 | u8 top_revision; | ||
115 | u8 gps_major; | ||
116 | u8 gps_minor; | ||
117 | u8 gps_revision; | ||
118 | u8 bt_major; | ||
119 | u8 bt_minor; | ||
120 | u8 bt_revision; | ||
121 | u8 tic_name[31]; | ||
122 | }; | ||
123 | |||
124 | /** | ||
125 | * struct iwmct_fw_sec_hdr | ||
126 | * @type: function type | ||
127 | * @data_size: section's data size | ||
128 | * @target_addr: download address | ||
129 | */ | ||
130 | struct iwmct_fw_sec_hdr { | ||
131 | u8 type[4]; | ||
132 | __le32 data_size; | ||
133 | __le32 target_addr; | ||
134 | }; | ||
135 | |||
136 | /** | ||
137 | * struct iwmct_parser | ||
138 | * @file: fw image | ||
139 | * @file_size: fw size | ||
140 | * @cur_pos: position in file | ||
141 | * @buf: temp buf for download | ||
142 | * @buf_size: size of buf | ||
143 | * @entry_point: address to jump in fw kick-off | ||
144 | */ | ||
145 | struct iwmct_parser { | ||
146 | const u8 *file; | ||
147 | size_t file_size; | ||
148 | size_t cur_pos; | ||
149 | u8 *buf; | ||
150 | size_t buf_size; | ||
151 | u32 entry_point; | ||
152 | struct iwmct_fw_hdr versions; | ||
153 | }; | ||
154 | |||
155 | |||
156 | struct iwmct_work_struct { | ||
157 | struct list_head list; | ||
158 | ssize_t iosize; | ||
159 | }; | ||
160 | |||
161 | struct iwmct_dbg { | ||
162 | int blocks; | ||
163 | bool dump; | ||
164 | bool jump; | ||
165 | bool direct; | ||
166 | bool checksum; | ||
167 | bool fw_download; | ||
168 | int block_size; | ||
169 | int download_trans_blks; | ||
170 | |||
171 | char label_fw[256]; | ||
172 | }; | ||
173 | |||
174 | struct iwmct_debugfs; | ||
175 | |||
176 | struct iwmct_priv { | ||
177 | struct sdio_func *func; | ||
178 | struct iwmct_debugfs *dbgfs; | ||
179 | struct iwmct_parser parser; | ||
180 | atomic_t reset; | ||
181 | atomic_t dev_sync; | ||
182 | u32 trans_len; | ||
183 | u32 barker; | ||
184 | struct iwmct_dbg dbg; | ||
185 | |||
186 | /* drivers work items */ | ||
187 | struct work_struct bus_rescan_worker; | ||
188 | struct work_struct isr_worker; | ||
189 | |||
190 | /* drivers wait queue */ | ||
191 | wait_queue_head_t wait_q; | ||
192 | |||
193 | /* rx request list */ | ||
194 | struct list_head read_req_list; | ||
195 | }; | ||
196 | |||
197 | extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count); | ||
198 | extern int iwmct_fw_load(struct iwmct_priv *priv); | ||
199 | |||
200 | extern void iwmct_dbg_init_params(struct iwmct_priv *drv); | ||
201 | extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv); | ||
202 | extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv); | ||
203 | extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len); | ||
204 | |||
205 | #endif /* __IWMC3200TOP_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c deleted file mode 100644 index a36a55a49cac..000000000000 --- a/drivers/misc/iwmc3200top/log.c +++ /dev/null | |||
@@ -1,348 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/log.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/mmc/sdio_func.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include "fw-msg.h" | ||
32 | #include "iwmc3200top.h" | ||
33 | #include "log.h" | ||
34 | |||
35 | /* Maximal hexadecimal string size of the FW memdump message */ | ||
36 | #define LOG_MSG_SIZE_MAX 12400 | ||
37 | |||
38 | /* iwmct_logdefs is a global used by log macros */ | ||
39 | u8 iwmct_logdefs[LOG_SRC_MAX]; | ||
40 | static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX]; | ||
41 | |||
42 | |||
43 | static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask) | ||
44 | { | ||
45 | int i; | ||
46 | |||
47 | if (src < size) | ||
48 | logdefs[src] = logmask; | ||
49 | else if (src == LOG_SRC_ALL) | ||
50 | for (i = 0; i < size; i++) | ||
51 | logdefs[i] = logmask; | ||
52 | else | ||
53 | return -1; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | int iwmct_log_set_filter(u8 src, u8 logmask) | ||
60 | { | ||
61 | return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask); | ||
62 | } | ||
63 | |||
64 | |||
65 | int iwmct_log_set_fw_filter(u8 src, u8 logmask) | ||
66 | { | ||
67 | return _log_set_log_filter(iwmct_fw_logdefs, | ||
68 | FW_LOG_SRC_MAX, src, logmask); | ||
69 | } | ||
70 | |||
71 | |||
72 | static int log_msg_format_hex(char *str, int slen, u8 *ibuf, | ||
73 | int ilen, char *pref) | ||
74 | { | ||
75 | int pos = 0; | ||
76 | int i; | ||
77 | int len; | ||
78 | |||
79 | for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++) | ||
80 | str[pos] = pref[i]; | ||
81 | |||
82 | for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++) | ||
83 | len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]); | ||
84 | |||
85 | if (i < ilen) | ||
86 | return -1; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* NOTE: This function is not thread safe. | ||
92 | Currently it's called only from sdio rx worker - no race there | ||
93 | */ | ||
94 | void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len) | ||
95 | { | ||
96 | struct top_msg *msg; | ||
97 | static char logbuf[LOG_MSG_SIZE_MAX]; | ||
98 | |||
99 | msg = (struct top_msg *)buf; | ||
100 | |||
101 | if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) { | ||
102 | LOG_ERROR(priv, FW_MSG, "Log message from TOP " | ||
103 | "is too short %d (expected %zd)\n", | ||
104 | len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] & | ||
109 | BIT(msg->u.log.log_hdr.severity)) || | ||
110 | !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity))) | ||
111 | return; | ||
112 | |||
113 | switch (msg->hdr.category) { | ||
114 | case COMM_CATEGORY_TESTABILITY: | ||
115 | if (!(iwmct_logdefs[LOG_SRC_TST] & | ||
116 | BIT(msg->u.log.log_hdr.severity))) | ||
117 | return; | ||
118 | if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, | ||
119 | le16_to_cpu(msg->hdr.length) + | ||
120 | sizeof(msg->hdr), "<TST>")) | ||
121 | LOG_WARNING(priv, TST, | ||
122 | "TOP TST message is too long, truncating..."); | ||
123 | LOG_WARNING(priv, TST, "%s\n", logbuf); | ||
124 | break; | ||
125 | case COMM_CATEGORY_DEBUG: | ||
126 | if (msg->hdr.opcode == OP_DBG_ZSTR_MSG) | ||
127 | LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>", | ||
128 | ((u8 *)msg) + sizeof(msg->hdr) | ||
129 | + sizeof(msg->u.log.log_hdr)); | ||
130 | else { | ||
131 | if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, | ||
132 | le16_to_cpu(msg->hdr.length) | ||
133 | + sizeof(msg->hdr), | ||
134 | "<DBG>")) | ||
135 | LOG_WARNING(priv, FW_MSG, | ||
136 | "TOP DBG message is too long," | ||
137 | "truncating..."); | ||
138 | LOG_WARNING(priv, FW_MSG, "%s\n", logbuf); | ||
139 | } | ||
140 | break; | ||
141 | default: | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size) | ||
147 | { | ||
148 | int i, pos, len; | ||
149 | for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) { | ||
150 | len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,", | ||
151 | i, logdefs[i]); | ||
152 | pos += len; | ||
153 | } | ||
154 | buf[pos-1] = '\n'; | ||
155 | buf[pos] = '\0'; | ||
156 | |||
157 | if (i < logdefsz) | ||
158 | return -1; | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | int log_get_filter_str(char *buf, int size) | ||
163 | { | ||
164 | return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size); | ||
165 | } | ||
166 | |||
167 | int log_get_fw_filter_str(char *buf, int size) | ||
168 | { | ||
169 | return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size); | ||
170 | } | ||
171 | |||
172 | #define HEXADECIMAL_RADIX 16 | ||
173 | #define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */ | ||
174 | |||
175 | ssize_t show_iwmct_log_level(struct device *d, | ||
176 | struct device_attribute *attr, char *buf) | ||
177 | { | ||
178 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
179 | char *str_buf; | ||
180 | int buf_size; | ||
181 | ssize_t ret; | ||
182 | |||
183 | buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1; | ||
184 | str_buf = kzalloc(buf_size, GFP_KERNEL); | ||
185 | if (!str_buf) { | ||
186 | LOG_ERROR(priv, DEBUGFS, | ||
187 | "failed to allocate %d bytes\n", buf_size); | ||
188 | ret = -ENOMEM; | ||
189 | goto exit; | ||
190 | } | ||
191 | |||
192 | if (log_get_filter_str(str_buf, buf_size) < 0) { | ||
193 | ret = -EINVAL; | ||
194 | goto exit; | ||
195 | } | ||
196 | |||
197 | ret = sprintf(buf, "%s", str_buf); | ||
198 | |||
199 | exit: | ||
200 | kfree(str_buf); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | ssize_t store_iwmct_log_level(struct device *d, | ||
205 | struct device_attribute *attr, | ||
206 | const char *buf, size_t count) | ||
207 | { | ||
208 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
209 | char *token, *str_buf = NULL; | ||
210 | long val; | ||
211 | ssize_t ret = count; | ||
212 | u8 src, mask; | ||
213 | |||
214 | if (!count) | ||
215 | goto exit; | ||
216 | |||
217 | str_buf = kzalloc(count, GFP_KERNEL); | ||
218 | if (!str_buf) { | ||
219 | LOG_ERROR(priv, DEBUGFS, | ||
220 | "failed to allocate %zd bytes\n", count); | ||
221 | ret = -ENOMEM; | ||
222 | goto exit; | ||
223 | } | ||
224 | |||
225 | memcpy(str_buf, buf, count); | ||
226 | |||
227 | while ((token = strsep(&str_buf, ",")) != NULL) { | ||
228 | while (isspace(*token)) | ||
229 | ++token; | ||
230 | if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { | ||
231 | LOG_ERROR(priv, DEBUGFS, | ||
232 | "failed to convert string to long %s\n", | ||
233 | token); | ||
234 | ret = -EINVAL; | ||
235 | goto exit; | ||
236 | } | ||
237 | |||
238 | mask = val & 0xFF; | ||
239 | src = (val & 0XFF00) >> 8; | ||
240 | iwmct_log_set_filter(src, mask); | ||
241 | } | ||
242 | |||
243 | exit: | ||
244 | kfree(str_buf); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | ssize_t show_iwmct_log_level_fw(struct device *d, | ||
249 | struct device_attribute *attr, char *buf) | ||
250 | { | ||
251 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
252 | char *str_buf; | ||
253 | int buf_size; | ||
254 | ssize_t ret; | ||
255 | |||
256 | buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2; | ||
257 | |||
258 | str_buf = kzalloc(buf_size, GFP_KERNEL); | ||
259 | if (!str_buf) { | ||
260 | LOG_ERROR(priv, DEBUGFS, | ||
261 | "failed to allocate %d bytes\n", buf_size); | ||
262 | ret = -ENOMEM; | ||
263 | goto exit; | ||
264 | } | ||
265 | |||
266 | if (log_get_fw_filter_str(str_buf, buf_size) < 0) { | ||
267 | ret = -EINVAL; | ||
268 | goto exit; | ||
269 | } | ||
270 | |||
271 | ret = sprintf(buf, "%s", str_buf); | ||
272 | |||
273 | exit: | ||
274 | kfree(str_buf); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | ssize_t store_iwmct_log_level_fw(struct device *d, | ||
279 | struct device_attribute *attr, | ||
280 | const char *buf, size_t count) | ||
281 | { | ||
282 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
283 | struct top_msg cmd; | ||
284 | char *token, *str_buf = NULL; | ||
285 | ssize_t ret = count; | ||
286 | u16 cmdlen = 0; | ||
287 | int i; | ||
288 | long val; | ||
289 | u8 src, mask; | ||
290 | |||
291 | if (!count) | ||
292 | goto exit; | ||
293 | |||
294 | str_buf = kzalloc(count, GFP_KERNEL); | ||
295 | if (!str_buf) { | ||
296 | LOG_ERROR(priv, DEBUGFS, | ||
297 | "failed to allocate %zd bytes\n", count); | ||
298 | ret = -ENOMEM; | ||
299 | goto exit; | ||
300 | } | ||
301 | |||
302 | memcpy(str_buf, buf, count); | ||
303 | |||
304 | cmd.hdr.type = COMM_TYPE_H2D; | ||
305 | cmd.hdr.category = COMM_CATEGORY_DEBUG; | ||
306 | cmd.hdr.opcode = CMD_DBG_LOG_LEVEL; | ||
307 | |||
308 | for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) && | ||
309 | (i < FW_LOG_SRC_MAX); i++) { | ||
310 | |||
311 | while (isspace(*token)) | ||
312 | ++token; | ||
313 | |||
314 | if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { | ||
315 | LOG_ERROR(priv, DEBUGFS, | ||
316 | "failed to convert string to long %s\n", | ||
317 | token); | ||
318 | ret = -EINVAL; | ||
319 | goto exit; | ||
320 | } | ||
321 | |||
322 | mask = val & 0xFF; /* LSB */ | ||
323 | src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */ | ||
324 | iwmct_log_set_fw_filter(src, mask); | ||
325 | |||
326 | cmd.u.logdefs[i].logsource = src; | ||
327 | cmd.u.logdefs[i].sevmask = mask; | ||
328 | } | ||
329 | |||
330 | cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0])); | ||
331 | cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr)); | ||
332 | |||
333 | ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen); | ||
334 | if (ret) { | ||
335 | LOG_ERROR(priv, DEBUGFS, | ||
336 | "Failed to send %d bytes of fwcmd, ret=%zd\n", | ||
337 | cmdlen, ret); | ||
338 | goto exit; | ||
339 | } else | ||
340 | LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen); | ||
341 | |||
342 | ret = count; | ||
343 | |||
344 | exit: | ||
345 | kfree(str_buf); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h deleted file mode 100644 index 4434bb16cea7..000000000000 --- a/drivers/misc/iwmc3200top/log.h +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/log.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __LOG_H__ | ||
28 | #define __LOG_H__ | ||
29 | |||
30 | |||
31 | /* log severity: | ||
32 | * The log levels here match FW log levels | ||
33 | * so values need to stay as is */ | ||
34 | #define LOG_SEV_CRITICAL 0 | ||
35 | #define LOG_SEV_ERROR 1 | ||
36 | #define LOG_SEV_WARNING 2 | ||
37 | #define LOG_SEV_INFO 3 | ||
38 | #define LOG_SEV_INFOEX 4 | ||
39 | |||
40 | /* Log levels not defined for FW */ | ||
41 | #define LOG_SEV_TRACE 5 | ||
42 | #define LOG_SEV_DUMP 6 | ||
43 | |||
44 | #define LOG_SEV_FW_FILTER_ALL \ | ||
45 | (BIT(LOG_SEV_CRITICAL) | \ | ||
46 | BIT(LOG_SEV_ERROR) | \ | ||
47 | BIT(LOG_SEV_WARNING) | \ | ||
48 | BIT(LOG_SEV_INFO) | \ | ||
49 | BIT(LOG_SEV_INFOEX)) | ||
50 | |||
51 | #define LOG_SEV_FILTER_ALL \ | ||
52 | (BIT(LOG_SEV_CRITICAL) | \ | ||
53 | BIT(LOG_SEV_ERROR) | \ | ||
54 | BIT(LOG_SEV_WARNING) | \ | ||
55 | BIT(LOG_SEV_INFO) | \ | ||
56 | BIT(LOG_SEV_INFOEX) | \ | ||
57 | BIT(LOG_SEV_TRACE) | \ | ||
58 | BIT(LOG_SEV_DUMP)) | ||
59 | |||
60 | /* log source */ | ||
61 | #define LOG_SRC_INIT 0 | ||
62 | #define LOG_SRC_DEBUGFS 1 | ||
63 | #define LOG_SRC_FW_DOWNLOAD 2 | ||
64 | #define LOG_SRC_FW_MSG 3 | ||
65 | #define LOG_SRC_TST 4 | ||
66 | #define LOG_SRC_IRQ 5 | ||
67 | |||
68 | #define LOG_SRC_MAX 6 | ||
69 | #define LOG_SRC_ALL 0xFF | ||
70 | |||
71 | /** | ||
72 | * Default intitialization runtime log level | ||
73 | */ | ||
74 | #ifndef LOG_SEV_FILTER_RUNTIME | ||
75 | #define LOG_SEV_FILTER_RUNTIME \ | ||
76 | (BIT(LOG_SEV_CRITICAL) | \ | ||
77 | BIT(LOG_SEV_ERROR) | \ | ||
78 | BIT(LOG_SEV_WARNING)) | ||
79 | #endif | ||
80 | |||
81 | #ifndef FW_LOG_SEV_FILTER_RUNTIME | ||
82 | #define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL | ||
83 | #endif | ||
84 | |||
85 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
86 | /** | ||
87 | * Log macros | ||
88 | */ | ||
89 | |||
90 | #define priv2dev(priv) (&(priv->func)->dev) | ||
91 | |||
92 | #define LOG_CRITICAL(priv, src, fmt, args...) \ | ||
93 | do { \ | ||
94 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \ | ||
95 | dev_crit(priv2dev(priv), "%s %d: " fmt, \ | ||
96 | __func__, __LINE__, ##args); \ | ||
97 | } while (0) | ||
98 | |||
99 | #define LOG_ERROR(priv, src, fmt, args...) \ | ||
100 | do { \ | ||
101 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \ | ||
102 | dev_err(priv2dev(priv), "%s %d: " fmt, \ | ||
103 | __func__, __LINE__, ##args); \ | ||
104 | } while (0) | ||
105 | |||
106 | #define LOG_WARNING(priv, src, fmt, args...) \ | ||
107 | do { \ | ||
108 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \ | ||
109 | dev_warn(priv2dev(priv), "%s %d: " fmt, \ | ||
110 | __func__, __LINE__, ##args); \ | ||
111 | } while (0) | ||
112 | |||
113 | #define LOG_INFO(priv, src, fmt, args...) \ | ||
114 | do { \ | ||
115 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \ | ||
116 | dev_info(priv2dev(priv), "%s %d: " fmt, \ | ||
117 | __func__, __LINE__, ##args); \ | ||
118 | } while (0) | ||
119 | |||
120 | #define LOG_TRACE(priv, src, fmt, args...) \ | ||
121 | do { \ | ||
122 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \ | ||
123 | dev_dbg(priv2dev(priv), "%s %d: " fmt, \ | ||
124 | __func__, __LINE__, ##args); \ | ||
125 | } while (0) | ||
126 | |||
127 | #define LOG_HEXDUMP(src, ptr, len) \ | ||
128 | do { \ | ||
129 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \ | ||
130 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ | ||
131 | 16, 1, ptr, len, false); \ | ||
132 | } while (0) | ||
133 | |||
134 | void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len); | ||
135 | |||
136 | extern u8 iwmct_logdefs[]; | ||
137 | |||
138 | int iwmct_log_set_filter(u8 src, u8 logmask); | ||
139 | int iwmct_log_set_fw_filter(u8 src, u8 logmask); | ||
140 | |||
141 | ssize_t show_iwmct_log_level(struct device *d, | ||
142 | struct device_attribute *attr, char *buf); | ||
143 | ssize_t store_iwmct_log_level(struct device *d, | ||
144 | struct device_attribute *attr, | ||
145 | const char *buf, size_t count); | ||
146 | ssize_t show_iwmct_log_level_fw(struct device *d, | ||
147 | struct device_attribute *attr, char *buf); | ||
148 | ssize_t store_iwmct_log_level_fw(struct device *d, | ||
149 | struct device_attribute *attr, | ||
150 | const char *buf, size_t count); | ||
151 | |||
152 | #else | ||
153 | |||
154 | #define LOG_CRITICAL(priv, src, fmt, args...) | ||
155 | #define LOG_ERROR(priv, src, fmt, args...) | ||
156 | #define LOG_WARNING(priv, src, fmt, args...) | ||
157 | #define LOG_INFO(priv, src, fmt, args...) | ||
158 | #define LOG_TRACE(priv, src, fmt, args...) | ||
159 | #define LOG_HEXDUMP(src, ptr, len) | ||
160 | |||
161 | static inline void iwmct_log_top_message(struct iwmct_priv *priv, | ||
162 | u8 *buf, int len) {} | ||
163 | static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; } | ||
164 | static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; } | ||
165 | |||
166 | #endif /* CONFIG_IWMC3200TOP_DEBUG */ | ||
167 | |||
168 | int log_get_filter_str(char *buf, int size); | ||
169 | int log_get_fw_filter_str(char *buf, int size); | ||
170 | |||
171 | #endif /* __LOG_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c deleted file mode 100644 index 701eb600b127..000000000000 --- a/drivers/misc/iwmc3200top/main.c +++ /dev/null | |||
@@ -1,662 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/main.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/debugfs.h> | ||
32 | #include <linux/mmc/sdio_ids.h> | ||
33 | #include <linux/mmc/sdio_func.h> | ||
34 | #include <linux/mmc/sdio.h> | ||
35 | |||
36 | #include "iwmc3200top.h" | ||
37 | #include "log.h" | ||
38 | #include "fw-msg.h" | ||
39 | #include "debugfs.h" | ||
40 | |||
41 | |||
42 | #define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver" | ||
43 | #define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation." | ||
44 | |||
45 | #define DRIVER_VERSION "0.1.62" | ||
46 | |||
47 | MODULE_DESCRIPTION(DRIVER_DESCRIPTION); | ||
48 | MODULE_VERSION(DRIVER_VERSION); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | MODULE_AUTHOR(DRIVER_COPYRIGHT); | ||
51 | MODULE_FIRMWARE(FW_NAME(FW_API_VER)); | ||
52 | |||
53 | |||
54 | static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
55 | { | ||
56 | return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count); | ||
57 | |||
58 | } | ||
59 | int iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
60 | { | ||
61 | int ret; | ||
62 | sdio_claim_host(priv->func); | ||
63 | ret = __iwmct_tx(priv, src, count); | ||
64 | sdio_release_host(priv->func); | ||
65 | return ret; | ||
66 | } | ||
67 | /* | ||
68 | * This workers main task is to wait for OP_OPR_ALIVE | ||
69 | * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. | ||
70 | * When OP_OPR_ALIVE received it will issue | ||
71 | * a call to "bus_rescan_devices". | ||
72 | */ | ||
73 | static void iwmct_rescan_worker(struct work_struct *ws) | ||
74 | { | ||
75 | struct iwmct_priv *priv; | ||
76 | int ret; | ||
77 | |||
78 | priv = container_of(ws, struct iwmct_priv, bus_rescan_worker); | ||
79 | |||
80 | LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n"); | ||
81 | |||
82 | ret = bus_rescan_devices(priv->func->dev.bus); | ||
83 | if (ret < 0) | ||
84 | LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n"); | ||
85 | } | ||
86 | |||
87 | static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) | ||
88 | { | ||
89 | switch (msg->hdr.opcode) { | ||
90 | case OP_OPR_ALIVE: | ||
91 | LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n"); | ||
92 | schedule_work(&priv->bus_rescan_worker); | ||
93 | break; | ||
94 | default: | ||
95 | LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n", | ||
96 | msg->hdr.opcode); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len) | ||
103 | { | ||
104 | struct top_msg *msg; | ||
105 | |||
106 | msg = (struct top_msg *)buf; | ||
107 | |||
108 | if (msg->hdr.type != COMM_TYPE_D2H) { | ||
109 | LOG_ERROR(priv, FW_MSG, | ||
110 | "Message from TOP with invalid message type 0x%X\n", | ||
111 | msg->hdr.type); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | if (len < sizeof(msg->hdr)) { | ||
116 | LOG_ERROR(priv, FW_MSG, | ||
117 | "Message from TOP is too short for message header " | ||
118 | "received %d bytes, expected at least %zd bytes\n", | ||
119 | len, sizeof(msg->hdr)); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) { | ||
124 | LOG_ERROR(priv, FW_MSG, | ||
125 | "Message length (%d bytes) is shorter than " | ||
126 | "in header (%d bytes)\n", | ||
127 | len, le16_to_cpu(msg->hdr.length)); | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | switch (msg->hdr.category) { | ||
132 | case COMM_CATEGORY_OPERATIONAL: | ||
133 | op_top_message(priv, (struct top_msg *)buf); | ||
134 | break; | ||
135 | |||
136 | case COMM_CATEGORY_DEBUG: | ||
137 | case COMM_CATEGORY_TESTABILITY: | ||
138 | case COMM_CATEGORY_DIAGNOSTICS: | ||
139 | iwmct_log_top_message(priv, buf, len); | ||
140 | break; | ||
141 | |||
142 | default: | ||
143 | LOG_ERROR(priv, FW_MSG, | ||
144 | "Message from TOP with unknown category 0x%X\n", | ||
145 | msg->hdr.category); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) | ||
151 | { | ||
152 | int ret; | ||
153 | u8 *buf; | ||
154 | |||
155 | LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n"); | ||
156 | |||
157 | /* add padding to 256 for IWMC */ | ||
158 | ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; | ||
159 | |||
160 | LOG_HEXDUMP(FW_MSG, cmd, len); | ||
161 | |||
162 | if (len > FW_HCMD_BLOCK_SIZE) { | ||
163 | LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n", | ||
164 | len, FW_HCMD_BLOCK_SIZE); | ||
165 | return -1; | ||
166 | } | ||
167 | |||
168 | buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL); | ||
169 | if (!buf) { | ||
170 | LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n", | ||
171 | FW_HCMD_BLOCK_SIZE); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | memcpy(buf, cmd, len); | ||
176 | ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE); | ||
177 | |||
178 | kfree(buf); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void iwmct_irq_read_worker(struct work_struct *ws) | ||
184 | { | ||
185 | struct iwmct_priv *priv; | ||
186 | struct iwmct_work_struct *read_req; | ||
187 | __le32 *buf = NULL; | ||
188 | int ret; | ||
189 | int iosize; | ||
190 | u32 barker; | ||
191 | bool is_barker; | ||
192 | |||
193 | priv = container_of(ws, struct iwmct_priv, isr_worker); | ||
194 | |||
195 | LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); | ||
196 | |||
197 | /* --------------------- Handshake with device -------------------- */ | ||
198 | sdio_claim_host(priv->func); | ||
199 | |||
200 | /* all list manipulations have to be protected by | ||
201 | * sdio_claim_host/sdio_release_host */ | ||
202 | if (list_empty(&priv->read_req_list)) { | ||
203 | LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n"); | ||
204 | goto exit_release; | ||
205 | } | ||
206 | |||
207 | read_req = list_entry(priv->read_req_list.next, | ||
208 | struct iwmct_work_struct, list); | ||
209 | |||
210 | list_del(&read_req->list); | ||
211 | iosize = read_req->iosize; | ||
212 | kfree(read_req); | ||
213 | |||
214 | buf = kzalloc(iosize, GFP_KERNEL); | ||
215 | if (!buf) { | ||
216 | LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize); | ||
217 | goto exit_release; | ||
218 | } | ||
219 | |||
220 | LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n", | ||
221 | iosize, buf, priv->func->num); | ||
222 | |||
223 | /* read from device */ | ||
224 | ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize); | ||
225 | if (ret) { | ||
226 | LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret); | ||
227 | goto exit_release; | ||
228 | } | ||
229 | |||
230 | LOG_HEXDUMP(IRQ, (u8 *)buf, iosize); | ||
231 | |||
232 | barker = le32_to_cpu(buf[0]); | ||
233 | |||
234 | /* Verify whether it's a barker and if not - treat as regular Rx */ | ||
235 | if (barker == IWMC_BARKER_ACK || | ||
236 | (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) { | ||
237 | |||
238 | /* Valid Barker is equal on first 4 dwords */ | ||
239 | is_barker = (buf[1] == buf[0]) && | ||
240 | (buf[2] == buf[0]) && | ||
241 | (buf[3] == buf[0]); | ||
242 | |||
243 | if (!is_barker) { | ||
244 | LOG_WARNING(priv, IRQ, | ||
245 | "Potentially inconsistent barker " | ||
246 | "%08X_%08X_%08X_%08X\n", | ||
247 | le32_to_cpu(buf[0]), le32_to_cpu(buf[1]), | ||
248 | le32_to_cpu(buf[2]), le32_to_cpu(buf[3])); | ||
249 | } | ||
250 | } else { | ||
251 | is_barker = false; | ||
252 | } | ||
253 | |||
254 | /* Handle Top CommHub message */ | ||
255 | if (!is_barker) { | ||
256 | sdio_release_host(priv->func); | ||
257 | handle_top_message(priv, (u8 *)buf, iosize); | ||
258 | goto exit; | ||
259 | } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */ | ||
260 | if (atomic_read(&priv->dev_sync) == 0) { | ||
261 | LOG_ERROR(priv, IRQ, | ||
262 | "ACK barker arrived out-of-sync\n"); | ||
263 | goto exit_release; | ||
264 | } | ||
265 | |||
266 | /* Continuing to FW download (after Sync is completed)*/ | ||
267 | atomic_set(&priv->dev_sync, 0); | ||
268 | LOG_INFO(priv, IRQ, "ACK barker arrived " | ||
269 | "- starting FW download\n"); | ||
270 | } else { /* REBOOT barker */ | ||
271 | LOG_INFO(priv, IRQ, "Received reboot barker: %x\n", barker); | ||
272 | priv->barker = barker; | ||
273 | |||
274 | if (barker & BARKER_DNLOAD_SYNC_MSK) { | ||
275 | /* Send the same barker back */ | ||
276 | ret = __iwmct_tx(priv, buf, iosize); | ||
277 | if (ret) { | ||
278 | LOG_ERROR(priv, IRQ, | ||
279 | "error %d echoing barker\n", ret); | ||
280 | goto exit_release; | ||
281 | } | ||
282 | LOG_INFO(priv, IRQ, "Echoing barker to device\n"); | ||
283 | atomic_set(&priv->dev_sync, 1); | ||
284 | goto exit_release; | ||
285 | } | ||
286 | |||
287 | /* Continuing to FW download (without Sync) */ | ||
288 | LOG_INFO(priv, IRQ, "No sync requested " | ||
289 | "- starting FW download\n"); | ||
290 | } | ||
291 | |||
292 | sdio_release_host(priv->func); | ||
293 | |||
294 | if (priv->dbg.fw_download) | ||
295 | iwmct_fw_load(priv); | ||
296 | else | ||
297 | LOG_ERROR(priv, IRQ, "FW download not allowed\n"); | ||
298 | |||
299 | goto exit; | ||
300 | |||
301 | exit_release: | ||
302 | sdio_release_host(priv->func); | ||
303 | exit: | ||
304 | kfree(buf); | ||
305 | LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n"); | ||
306 | } | ||
307 | |||
308 | static void iwmct_irq(struct sdio_func *func) | ||
309 | { | ||
310 | struct iwmct_priv *priv; | ||
311 | int val, ret; | ||
312 | int iosize; | ||
313 | int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR; | ||
314 | struct iwmct_work_struct *read_req; | ||
315 | |||
316 | priv = sdio_get_drvdata(func); | ||
317 | |||
318 | LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); | ||
319 | |||
320 | /* read the function's status register */ | ||
321 | val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); | ||
322 | |||
323 | LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); | ||
324 | |||
325 | if (!val) { | ||
326 | LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); | ||
327 | goto exit_clear_intr; | ||
328 | } | ||
329 | |||
330 | |||
331 | /* | ||
332 | * read 2 bytes of the transaction size | ||
333 | * IMPORTANT: sdio transaction size has to be read before clearing | ||
334 | * sdio interrupt!!! | ||
335 | */ | ||
336 | val = sdio_readb(priv->func, addr++, &ret); | ||
337 | iosize = val; | ||
338 | val = sdio_readb(priv->func, addr++, &ret); | ||
339 | iosize += val << 8; | ||
340 | |||
341 | LOG_INFO(priv, IRQ, "READ size %d\n", iosize); | ||
342 | |||
343 | if (iosize == 0) { | ||
344 | LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize); | ||
345 | goto exit_clear_intr; | ||
346 | } | ||
347 | |||
348 | /* allocate a work structure to pass iosize to the worker */ | ||
349 | read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL); | ||
350 | if (!read_req) { | ||
351 | LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n"); | ||
352 | goto exit_clear_intr; | ||
353 | } | ||
354 | |||
355 | INIT_LIST_HEAD(&read_req->list); | ||
356 | read_req->iosize = iosize; | ||
357 | |||
358 | list_add_tail(&priv->read_req_list, &read_req->list); | ||
359 | |||
360 | /* clear the function's interrupt request bit (write 1 to clear) */ | ||
361 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); | ||
362 | |||
363 | schedule_work(&priv->isr_worker); | ||
364 | |||
365 | LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); | ||
366 | |||
367 | return; | ||
368 | |||
369 | exit_clear_intr: | ||
370 | /* clear the function's interrupt request bit (write 1 to clear) */ | ||
371 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); | ||
372 | } | ||
373 | |||
374 | |||
375 | static int blocks; | ||
376 | module_param(blocks, int, 0604); | ||
377 | MODULE_PARM_DESC(blocks, "max_blocks_to_send"); | ||
378 | |||
379 | static bool dump; | ||
380 | module_param(dump, bool, 0604); | ||
381 | MODULE_PARM_DESC(dump, "dump_hex_content"); | ||
382 | |||
383 | static bool jump = 1; | ||
384 | module_param(jump, bool, 0604); | ||
385 | |||
386 | static bool direct = 1; | ||
387 | module_param(direct, bool, 0604); | ||
388 | |||
389 | static bool checksum = 1; | ||
390 | module_param(checksum, bool, 0604); | ||
391 | |||
392 | static bool fw_download = 1; | ||
393 | module_param(fw_download, bool, 0604); | ||
394 | |||
395 | static int block_size = IWMC_SDIO_BLK_SIZE; | ||
396 | module_param(block_size, int, 0404); | ||
397 | |||
398 | static int download_trans_blks = IWMC_DEFAULT_TR_BLK; | ||
399 | module_param(download_trans_blks, int, 0604); | ||
400 | |||
401 | static bool rubbish_barker; | ||
402 | module_param(rubbish_barker, bool, 0604); | ||
403 | |||
404 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
405 | static int log_level[LOG_SRC_MAX]; | ||
406 | static unsigned int log_level_argc; | ||
407 | module_param_array(log_level, int, &log_level_argc, 0604); | ||
408 | MODULE_PARM_DESC(log_level, "log_level"); | ||
409 | |||
410 | static int log_level_fw[FW_LOG_SRC_MAX]; | ||
411 | static unsigned int log_level_fw_argc; | ||
412 | module_param_array(log_level_fw, int, &log_level_fw_argc, 0604); | ||
413 | MODULE_PARM_DESC(log_level_fw, "log_level_fw"); | ||
414 | #endif | ||
415 | |||
416 | void iwmct_dbg_init_params(struct iwmct_priv *priv) | ||
417 | { | ||
418 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
419 | int i; | ||
420 | |||
421 | for (i = 0; i < log_level_argc; i++) { | ||
422 | dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n", | ||
423 | i, log_level[i]); | ||
424 | iwmct_log_set_filter((log_level[i] >> 8) & 0xFF, | ||
425 | log_level[i] & 0xFF); | ||
426 | } | ||
427 | for (i = 0; i < log_level_fw_argc; i++) { | ||
428 | dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n", | ||
429 | i, log_level_fw[i]); | ||
430 | iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF, | ||
431 | log_level_fw[i] & 0xFF); | ||
432 | } | ||
433 | #endif | ||
434 | |||
435 | priv->dbg.blocks = blocks; | ||
436 | LOG_INFO(priv, INIT, "blocks=%d\n", blocks); | ||
437 | priv->dbg.dump = (bool)dump; | ||
438 | LOG_INFO(priv, INIT, "dump=%d\n", dump); | ||
439 | priv->dbg.jump = (bool)jump; | ||
440 | LOG_INFO(priv, INIT, "jump=%d\n", jump); | ||
441 | priv->dbg.direct = (bool)direct; | ||
442 | LOG_INFO(priv, INIT, "direct=%d\n", direct); | ||
443 | priv->dbg.checksum = (bool)checksum; | ||
444 | LOG_INFO(priv, INIT, "checksum=%d\n", checksum); | ||
445 | priv->dbg.fw_download = (bool)fw_download; | ||
446 | LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download); | ||
447 | priv->dbg.block_size = block_size; | ||
448 | LOG_INFO(priv, INIT, "block_size=%d\n", block_size); | ||
449 | priv->dbg.download_trans_blks = download_trans_blks; | ||
450 | LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks); | ||
451 | } | ||
452 | |||
453 | /***************************************************************************** | ||
454 | * | ||
455 | * sysfs attributes | ||
456 | * | ||
457 | *****************************************************************************/ | ||
458 | static ssize_t show_iwmct_fw_version(struct device *d, | ||
459 | struct device_attribute *attr, char *buf) | ||
460 | { | ||
461 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
462 | return sprintf(buf, "%s\n", priv->dbg.label_fw); | ||
463 | } | ||
464 | static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL); | ||
465 | |||
466 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
467 | static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO, | ||
468 | show_iwmct_log_level, store_iwmct_log_level); | ||
469 | static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO, | ||
470 | show_iwmct_log_level_fw, store_iwmct_log_level_fw); | ||
471 | #endif | ||
472 | |||
473 | static struct attribute *iwmct_sysfs_entries[] = { | ||
474 | &dev_attr_cc_label_fw.attr, | ||
475 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
476 | &dev_attr_log_level.attr, | ||
477 | &dev_attr_log_level_fw.attr, | ||
478 | #endif | ||
479 | NULL | ||
480 | }; | ||
481 | |||
482 | static struct attribute_group iwmct_attribute_group = { | ||
483 | .name = NULL, /* put in device directory */ | ||
484 | .attrs = iwmct_sysfs_entries, | ||
485 | }; | ||
486 | |||
487 | |||
488 | static int iwmct_probe(struct sdio_func *func, | ||
489 | const struct sdio_device_id *id) | ||
490 | { | ||
491 | struct iwmct_priv *priv; | ||
492 | int ret; | ||
493 | int val = 1; | ||
494 | int addr = IWMC_SDIO_INTR_ENABLE_ADDR; | ||
495 | |||
496 | dev_dbg(&func->dev, "enter iwmct_probe\n"); | ||
497 | |||
498 | dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n", | ||
499 | jiffies_to_msecs(2147483647), HZ); | ||
500 | |||
501 | priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL); | ||
502 | if (!priv) { | ||
503 | dev_err(&func->dev, "kzalloc error\n"); | ||
504 | return -ENOMEM; | ||
505 | } | ||
506 | priv->func = func; | ||
507 | sdio_set_drvdata(func, priv); | ||
508 | |||
509 | INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker); | ||
510 | INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker); | ||
511 | |||
512 | init_waitqueue_head(&priv->wait_q); | ||
513 | |||
514 | sdio_claim_host(func); | ||
515 | /* FIXME: Remove after it is fixed in the Boot ROM upgrade */ | ||
516 | func->enable_timeout = 10; | ||
517 | |||
518 | /* In our HW, setting the block size also wakes up the boot rom. */ | ||
519 | ret = sdio_set_block_size(func, priv->dbg.block_size); | ||
520 | if (ret) { | ||
521 | LOG_ERROR(priv, INIT, | ||
522 | "sdio_set_block_size() failure: %d\n", ret); | ||
523 | goto error_sdio_enable; | ||
524 | } | ||
525 | |||
526 | ret = sdio_enable_func(func); | ||
527 | if (ret) { | ||
528 | LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret); | ||
529 | goto error_sdio_enable; | ||
530 | } | ||
531 | |||
532 | /* init reset and dev_sync states */ | ||
533 | atomic_set(&priv->reset, 0); | ||
534 | atomic_set(&priv->dev_sync, 0); | ||
535 | |||
536 | /* init read req queue */ | ||
537 | INIT_LIST_HEAD(&priv->read_req_list); | ||
538 | |||
539 | /* process configurable parameters */ | ||
540 | iwmct_dbg_init_params(priv); | ||
541 | ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group); | ||
542 | if (ret) { | ||
543 | LOG_ERROR(priv, INIT, "Failed to register attributes and " | ||
544 | "initialize module_params\n"); | ||
545 | goto error_dev_attrs; | ||
546 | } | ||
547 | |||
548 | iwmct_dbgfs_register(priv, DRV_NAME); | ||
549 | |||
550 | if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) { | ||
551 | LOG_INFO(priv, INIT, | ||
552 | "Reducing transaction to 8 blocks = 2K (from %d)\n", | ||
553 | priv->dbg.download_trans_blks); | ||
554 | priv->dbg.download_trans_blks = 8; | ||
555 | } | ||
556 | priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size; | ||
557 | LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len); | ||
558 | |||
559 | ret = sdio_claim_irq(func, iwmct_irq); | ||
560 | if (ret) { | ||
561 | LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret); | ||
562 | goto error_claim_irq; | ||
563 | } | ||
564 | |||
565 | |||
566 | /* Enable function's interrupt */ | ||
567 | sdio_writeb(priv->func, val, addr, &ret); | ||
568 | if (ret) { | ||
569 | LOG_ERROR(priv, INIT, "Failure writing to " | ||
570 | "Interrupt Enable Register (%d): %d\n", addr, ret); | ||
571 | goto error_enable_int; | ||
572 | } | ||
573 | |||
574 | sdio_release_host(func); | ||
575 | |||
576 | LOG_INFO(priv, INIT, "exit iwmct_probe\n"); | ||
577 | |||
578 | return ret; | ||
579 | |||
580 | error_enable_int: | ||
581 | sdio_release_irq(func); | ||
582 | error_claim_irq: | ||
583 | sdio_disable_func(func); | ||
584 | error_dev_attrs: | ||
585 | iwmct_dbgfs_unregister(priv->dbgfs); | ||
586 | sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); | ||
587 | error_sdio_enable: | ||
588 | sdio_release_host(func); | ||
589 | return ret; | ||
590 | } | ||
591 | |||
592 | static void iwmct_remove(struct sdio_func *func) | ||
593 | { | ||
594 | struct iwmct_work_struct *read_req; | ||
595 | struct iwmct_priv *priv = sdio_get_drvdata(func); | ||
596 | |||
597 | LOG_INFO(priv, INIT, "enter\n"); | ||
598 | |||
599 | sdio_claim_host(func); | ||
600 | sdio_release_irq(func); | ||
601 | sdio_release_host(func); | ||
602 | |||
603 | /* Make sure works are finished */ | ||
604 | flush_work_sync(&priv->bus_rescan_worker); | ||
605 | flush_work_sync(&priv->isr_worker); | ||
606 | |||
607 | sdio_claim_host(func); | ||
608 | sdio_disable_func(func); | ||
609 | sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); | ||
610 | iwmct_dbgfs_unregister(priv->dbgfs); | ||
611 | sdio_release_host(func); | ||
612 | |||
613 | /* free read requests */ | ||
614 | while (!list_empty(&priv->read_req_list)) { | ||
615 | read_req = list_entry(priv->read_req_list.next, | ||
616 | struct iwmct_work_struct, list); | ||
617 | |||
618 | list_del(&read_req->list); | ||
619 | kfree(read_req); | ||
620 | } | ||
621 | |||
622 | kfree(priv); | ||
623 | } | ||
624 | |||
625 | |||
626 | static const struct sdio_device_id iwmct_ids[] = { | ||
627 | /* Intel Wireless MultiCom 3200 Top Driver */ | ||
628 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1404)}, | ||
629 | { }, /* Terminating entry */ | ||
630 | }; | ||
631 | |||
632 | MODULE_DEVICE_TABLE(sdio, iwmct_ids); | ||
633 | |||
634 | static struct sdio_driver iwmct_driver = { | ||
635 | .probe = iwmct_probe, | ||
636 | .remove = iwmct_remove, | ||
637 | .name = DRV_NAME, | ||
638 | .id_table = iwmct_ids, | ||
639 | }; | ||
640 | |||
641 | static int __init iwmct_init(void) | ||
642 | { | ||
643 | int rc; | ||
644 | |||
645 | /* Default log filter settings */ | ||
646 | iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); | ||
647 | iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL); | ||
648 | iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); | ||
649 | |||
650 | rc = sdio_register_driver(&iwmct_driver); | ||
651 | |||
652 | return rc; | ||
653 | } | ||
654 | |||
655 | static void __exit iwmct_exit(void) | ||
656 | { | ||
657 | sdio_unregister_driver(&iwmct_driver); | ||
658 | } | ||
659 | |||
660 | module_init(iwmct_init); | ||
661 | module_exit(iwmct_exit); | ||
662 | |||