diff options
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 32 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 154 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.h | 7 |
3 files changed, 149 insertions, 44 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a53c378e7484..9e0da212f8ce 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -655,10 +655,39 @@ struct b43_wl { | |||
655 | struct work_struct txpower_adjust_work; | 655 | struct work_struct txpower_adjust_work; |
656 | }; | 656 | }; |
657 | 657 | ||
658 | /* The type of the firmware file. */ | ||
659 | enum b43_firmware_file_type { | ||
660 | B43_FWTYPE_PROPRIETARY, | ||
661 | B43_FWTYPE_OPENSOURCE, | ||
662 | B43_NR_FWTYPES, | ||
663 | }; | ||
664 | |||
665 | /* Context data for fetching firmware. */ | ||
666 | struct b43_request_fw_context { | ||
667 | /* The device we are requesting the fw for. */ | ||
668 | struct b43_wldev *dev; | ||
669 | /* The type of firmware to request. */ | ||
670 | enum b43_firmware_file_type req_type; | ||
671 | /* Error messages for each firmware type. */ | ||
672 | char errors[B43_NR_FWTYPES][128]; | ||
673 | /* Temporary buffer for storing the firmware name. */ | ||
674 | char fwname[64]; | ||
675 | /* A fatal error occured while requesting. Firmware reqest | ||
676 | * can not continue, as any other reqest will also fail. */ | ||
677 | int fatal_failure; | ||
678 | }; | ||
679 | |||
658 | /* In-memory representation of a cached microcode file. */ | 680 | /* In-memory representation of a cached microcode file. */ |
659 | struct b43_firmware_file { | 681 | struct b43_firmware_file { |
660 | const char *filename; | 682 | const char *filename; |
661 | const struct firmware *data; | 683 | const struct firmware *data; |
684 | /* Type of the firmware file name. Note that this does only indicate | ||
685 | * the type by the firmware name. NOT the file contents. | ||
686 | * If you want to check for proprietary vs opensource, use (struct b43_firmware)->opensource | ||
687 | * instead! The (struct b43_firmware)->opensource flag is derived from the actual firmware | ||
688 | * binary code, not just the filename. | ||
689 | */ | ||
690 | enum b43_firmware_file_type type; | ||
662 | }; | 691 | }; |
663 | 692 | ||
664 | /* Pointers to the firmware data and meta information about it. */ | 693 | /* Pointers to the firmware data and meta information about it. */ |
@@ -677,7 +706,8 @@ struct b43_firmware { | |||
677 | /* Firmware patchlevel */ | 706 | /* Firmware patchlevel */ |
678 | u16 patch; | 707 | u16 patch; |
679 | 708 | ||
680 | /* Set to true, if we are using an opensource firmware. */ | 709 | /* Set to true, if we are using an opensource firmware. |
710 | * Use this to check for proprietary vs opensource. */ | ||
681 | bool opensource; | 711 | bool opensource; |
682 | /* Set to true, if the core needs a PCM firmware, but | 712 | /* Set to true, if the core needs a PCM firmware, but |
683 | * we failed to load one. This is always false for | 713 | * we failed to load one. This is always false for |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 675a73a98072..cbb3d45f6fc9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -1934,7 +1934,7 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) | |||
1934 | return ret; | 1934 | return ret; |
1935 | } | 1935 | } |
1936 | 1936 | ||
1937 | static void do_release_fw(struct b43_firmware_file *fw) | 1937 | void b43_do_release_fw(struct b43_firmware_file *fw) |
1938 | { | 1938 | { |
1939 | release_firmware(fw->data); | 1939 | release_firmware(fw->data); |
1940 | fw->data = NULL; | 1940 | fw->data = NULL; |
@@ -1943,10 +1943,10 @@ static void do_release_fw(struct b43_firmware_file *fw) | |||
1943 | 1943 | ||
1944 | static void b43_release_firmware(struct b43_wldev *dev) | 1944 | static void b43_release_firmware(struct b43_wldev *dev) |
1945 | { | 1945 | { |
1946 | do_release_fw(&dev->fw.ucode); | 1946 | b43_do_release_fw(&dev->fw.ucode); |
1947 | do_release_fw(&dev->fw.pcm); | 1947 | b43_do_release_fw(&dev->fw.pcm); |
1948 | do_release_fw(&dev->fw.initvals); | 1948 | b43_do_release_fw(&dev->fw.initvals); |
1949 | do_release_fw(&dev->fw.initvals_band); | 1949 | b43_do_release_fw(&dev->fw.initvals_band); |
1950 | } | 1950 | } |
1951 | 1951 | ||
1952 | static void b43_print_fw_helptext(struct b43_wl *wl, bool error) | 1952 | static void b43_print_fw_helptext(struct b43_wl *wl, bool error) |
@@ -1963,12 +1963,10 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) | |||
1963 | b43warn(wl, text); | 1963 | b43warn(wl, text); |
1964 | } | 1964 | } |
1965 | 1965 | ||
1966 | static int do_request_fw(struct b43_wldev *dev, | 1966 | int b43_do_request_fw(struct b43_request_fw_context *ctx, |
1967 | const char *name, | 1967 | const char *name, |
1968 | struct b43_firmware_file *fw, | 1968 | struct b43_firmware_file *fw) |
1969 | bool silent) | ||
1970 | { | 1969 | { |
1971 | char path[sizeof(modparam_fwpostfix) + 32]; | ||
1972 | const struct firmware *blob; | 1970 | const struct firmware *blob; |
1973 | struct b43_fw_header *hdr; | 1971 | struct b43_fw_header *hdr; |
1974 | u32 size; | 1972 | u32 size; |
@@ -1976,29 +1974,49 @@ static int do_request_fw(struct b43_wldev *dev, | |||
1976 | 1974 | ||
1977 | if (!name) { | 1975 | if (!name) { |
1978 | /* Don't fetch anything. Free possibly cached firmware. */ | 1976 | /* Don't fetch anything. Free possibly cached firmware. */ |
1979 | do_release_fw(fw); | 1977 | /* FIXME: We should probably keep it anyway, to save some headache |
1978 | * on suspend/resume with multiband devices. */ | ||
1979 | b43_do_release_fw(fw); | ||
1980 | return 0; | 1980 | return 0; |
1981 | } | 1981 | } |
1982 | if (fw->filename) { | 1982 | if (fw->filename) { |
1983 | if (strcmp(fw->filename, name) == 0) | 1983 | if ((fw->type == ctx->req_type) && |
1984 | (strcmp(fw->filename, name) == 0)) | ||
1984 | return 0; /* Already have this fw. */ | 1985 | return 0; /* Already have this fw. */ |
1985 | /* Free the cached firmware first. */ | 1986 | /* Free the cached firmware first. */ |
1986 | do_release_fw(fw); | 1987 | /* FIXME: We should probably do this later after we successfully |
1988 | * got the new fw. This could reduce headache with multiband devices. | ||
1989 | * We could also redesign this to cache the firmware for all possible | ||
1990 | * bands all the time. */ | ||
1991 | b43_do_release_fw(fw); | ||
1992 | } | ||
1993 | |||
1994 | switch (ctx->req_type) { | ||
1995 | case B43_FWTYPE_PROPRIETARY: | ||
1996 | snprintf(ctx->fwname, sizeof(ctx->fwname), | ||
1997 | "b43%s/%s.fw", | ||
1998 | modparam_fwpostfix, name); | ||
1999 | break; | ||
2000 | case B43_FWTYPE_OPENSOURCE: | ||
2001 | snprintf(ctx->fwname, sizeof(ctx->fwname), | ||
2002 | "b43-open%s/%s.fw", | ||
2003 | modparam_fwpostfix, name); | ||
2004 | break; | ||
2005 | default: | ||
2006 | B43_WARN_ON(1); | ||
2007 | return -ENOSYS; | ||
1987 | } | 2008 | } |
1988 | 2009 | err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); | |
1989 | snprintf(path, ARRAY_SIZE(path), | ||
1990 | "b43%s/%s.fw", | ||
1991 | modparam_fwpostfix, name); | ||
1992 | err = request_firmware(&blob, path, dev->dev->dev); | ||
1993 | if (err == -ENOENT) { | 2010 | if (err == -ENOENT) { |
1994 | if (!silent) { | 2011 | snprintf(ctx->errors[ctx->req_type], |
1995 | b43err(dev->wl, "Firmware file \"%s\" not found\n", | 2012 | sizeof(ctx->errors[ctx->req_type]), |
1996 | path); | 2013 | "Firmware file \"%s\" not found\n", ctx->fwname); |
1997 | } | ||
1998 | return err; | 2014 | return err; |
1999 | } else if (err) { | 2015 | } else if (err) { |
2000 | b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", | 2016 | snprintf(ctx->errors[ctx->req_type], |
2001 | path, err); | 2017 | sizeof(ctx->errors[ctx->req_type]), |
2018 | "Firmware file \"%s\" request failed (err=%d)\n", | ||
2019 | ctx->fwname, err); | ||
2002 | return err; | 2020 | return err; |
2003 | } | 2021 | } |
2004 | if (blob->size < sizeof(struct b43_fw_header)) | 2022 | if (blob->size < sizeof(struct b43_fw_header)) |
@@ -2021,20 +2039,24 @@ static int do_request_fw(struct b43_wldev *dev, | |||
2021 | 2039 | ||
2022 | fw->data = blob; | 2040 | fw->data = blob; |
2023 | fw->filename = name; | 2041 | fw->filename = name; |
2042 | fw->type = ctx->req_type; | ||
2024 | 2043 | ||
2025 | return 0; | 2044 | return 0; |
2026 | 2045 | ||
2027 | err_format: | 2046 | err_format: |
2028 | b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); | 2047 | snprintf(ctx->errors[ctx->req_type], |
2048 | sizeof(ctx->errors[ctx->req_type]), | ||
2049 | "Firmware file \"%s\" format error.\n", ctx->fwname); | ||
2029 | release_firmware(blob); | 2050 | release_firmware(blob); |
2030 | 2051 | ||
2031 | return -EPROTO; | 2052 | return -EPROTO; |
2032 | } | 2053 | } |
2033 | 2054 | ||
2034 | static int b43_request_firmware(struct b43_wldev *dev) | 2055 | static int b43_try_request_fw(struct b43_request_fw_context *ctx) |
2035 | { | 2056 | { |
2036 | struct b43_firmware *fw = &dev->fw; | 2057 | struct b43_wldev *dev = ctx->dev; |
2037 | const u8 rev = dev->dev->id.revision; | 2058 | struct b43_firmware *fw = &ctx->dev->fw; |
2059 | const u8 rev = ctx->dev->dev->id.revision; | ||
2038 | const char *filename; | 2060 | const char *filename; |
2039 | u32 tmshigh; | 2061 | u32 tmshigh; |
2040 | int err; | 2062 | int err; |
@@ -2049,7 +2071,7 @@ static int b43_request_firmware(struct b43_wldev *dev) | |||
2049 | filename = "ucode13"; | 2071 | filename = "ucode13"; |
2050 | else | 2072 | else |
2051 | goto err_no_ucode; | 2073 | goto err_no_ucode; |
2052 | err = do_request_fw(dev, filename, &fw->ucode, 0); | 2074 | err = b43_do_request_fw(ctx, filename, &fw->ucode); |
2053 | if (err) | 2075 | if (err) |
2054 | goto err_load; | 2076 | goto err_load; |
2055 | 2077 | ||
@@ -2061,7 +2083,7 @@ static int b43_request_firmware(struct b43_wldev *dev) | |||
2061 | else | 2083 | else |
2062 | goto err_no_pcm; | 2084 | goto err_no_pcm; |
2063 | fw->pcm_request_failed = 0; | 2085 | fw->pcm_request_failed = 0; |
2064 | err = do_request_fw(dev, filename, &fw->pcm, 1); | 2086 | err = b43_do_request_fw(ctx, filename, &fw->pcm); |
2065 | if (err == -ENOENT) { | 2087 | if (err == -ENOENT) { |
2066 | /* We did not find a PCM file? Not fatal, but | 2088 | /* We did not find a PCM file? Not fatal, but |
2067 | * core rev <= 10 must do without hwcrypto then. */ | 2089 | * core rev <= 10 must do without hwcrypto then. */ |
@@ -2097,7 +2119,7 @@ static int b43_request_firmware(struct b43_wldev *dev) | |||
2097 | default: | 2119 | default: |
2098 | goto err_no_initvals; | 2120 | goto err_no_initvals; |
2099 | } | 2121 | } |
2100 | err = do_request_fw(dev, filename, &fw->initvals, 0); | 2122 | err = b43_do_request_fw(ctx, filename, &fw->initvals); |
2101 | if (err) | 2123 | if (err) |
2102 | goto err_load; | 2124 | goto err_load; |
2103 | 2125 | ||
@@ -2131,30 +2153,34 @@ static int b43_request_firmware(struct b43_wldev *dev) | |||
2131 | default: | 2153 | default: |
2132 | goto err_no_initvals; | 2154 | goto err_no_initvals; |
2133 | } | 2155 | } |
2134 | err = do_request_fw(dev, filename, &fw->initvals_band, 0); | 2156 | err = b43_do_request_fw(ctx, filename, &fw->initvals_band); |
2135 | if (err) | 2157 | if (err) |
2136 | goto err_load; | 2158 | goto err_load; |
2137 | 2159 | ||
2138 | return 0; | 2160 | return 0; |
2139 | 2161 | ||
2140 | err_load: | ||
2141 | b43_print_fw_helptext(dev->wl, 1); | ||
2142 | goto error; | ||
2143 | |||
2144 | err_no_ucode: | 2162 | err_no_ucode: |
2145 | err = -ENODEV; | 2163 | err = ctx->fatal_failure = -EOPNOTSUPP; |
2146 | b43err(dev->wl, "No microcode available for core rev %u\n", rev); | 2164 | b43err(dev->wl, "The driver does not know which firmware (ucode) " |
2165 | "is required for your device (wl-core rev %u)\n", rev); | ||
2147 | goto error; | 2166 | goto error; |
2148 | 2167 | ||
2149 | err_no_pcm: | 2168 | err_no_pcm: |
2150 | err = -ENODEV; | 2169 | err = ctx->fatal_failure = -EOPNOTSUPP; |
2151 | b43err(dev->wl, "No PCM available for core rev %u\n", rev); | 2170 | b43err(dev->wl, "The driver does not know which firmware (PCM) " |
2171 | "is required for your device (wl-core rev %u)\n", rev); | ||
2152 | goto error; | 2172 | goto error; |
2153 | 2173 | ||
2154 | err_no_initvals: | 2174 | err_no_initvals: |
2155 | err = -ENODEV; | 2175 | err = ctx->fatal_failure = -EOPNOTSUPP; |
2156 | b43err(dev->wl, "No Initial Values firmware file for PHY %u, " | 2176 | b43err(dev->wl, "The driver does not know which firmware (initvals) " |
2157 | "core rev %u\n", dev->phy.type, rev); | 2177 | "is required for your device (wl-core rev %u)\n", rev); |
2178 | goto error; | ||
2179 | |||
2180 | err_load: | ||
2181 | /* We failed to load this firmware image. The error message | ||
2182 | * already is in ctx->errors. Return and let our caller decide | ||
2183 | * what to do. */ | ||
2158 | goto error; | 2184 | goto error; |
2159 | 2185 | ||
2160 | error: | 2186 | error: |
@@ -2162,6 +2188,48 @@ error: | |||
2162 | return err; | 2188 | return err; |
2163 | } | 2189 | } |
2164 | 2190 | ||
2191 | static int b43_request_firmware(struct b43_wldev *dev) | ||
2192 | { | ||
2193 | struct b43_request_fw_context *ctx; | ||
2194 | unsigned int i; | ||
2195 | int err; | ||
2196 | const char *errmsg; | ||
2197 | |||
2198 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
2199 | if (!ctx) | ||
2200 | return -ENOMEM; | ||
2201 | ctx->dev = dev; | ||
2202 | |||
2203 | ctx->req_type = B43_FWTYPE_PROPRIETARY; | ||
2204 | err = b43_try_request_fw(ctx); | ||
2205 | if (!err) | ||
2206 | goto out; /* Successfully loaded it. */ | ||
2207 | err = ctx->fatal_failure; | ||
2208 | if (err) | ||
2209 | goto out; | ||
2210 | |||
2211 | ctx->req_type = B43_FWTYPE_OPENSOURCE; | ||
2212 | err = b43_try_request_fw(ctx); | ||
2213 | if (!err) | ||
2214 | goto out; /* Successfully loaded it. */ | ||
2215 | err = ctx->fatal_failure; | ||
2216 | if (err) | ||
2217 | goto out; | ||
2218 | |||
2219 | /* Could not find a usable firmware. Print the errors. */ | ||
2220 | for (i = 0; i < B43_NR_FWTYPES; i++) { | ||
2221 | errmsg = ctx->errors[i]; | ||
2222 | if (strlen(errmsg)) | ||
2223 | b43err(dev->wl, errmsg); | ||
2224 | } | ||
2225 | b43_print_fw_helptext(dev->wl, 1); | ||
2226 | err = -ENOENT; | ||
2227 | |||
2228 | out: | ||
2229 | kfree(ctx); | ||
2230 | return err; | ||
2231 | } | ||
2232 | |||
2165 | static int b43_upload_microcode(struct b43_wldev *dev) | 2233 | static int b43_upload_microcode(struct b43_wldev *dev) |
2166 | { | 2234 | { |
2167 | const size_t hdr_len = sizeof(struct b43_fw_header); | 2235 | const size_t hdr_len = sizeof(struct b43_fw_header); |
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index f871a252cb55..e6d90f377d9b 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h | |||
@@ -121,4 +121,11 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); | |||
121 | void b43_mac_suspend(struct b43_wldev *dev); | 121 | void b43_mac_suspend(struct b43_wldev *dev); |
122 | void b43_mac_enable(struct b43_wldev *dev); | 122 | void b43_mac_enable(struct b43_wldev *dev); |
123 | 123 | ||
124 | |||
125 | struct b43_request_fw_context; | ||
126 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | ||
127 | const char *name, | ||
128 | struct b43_firmware_file *fw); | ||
129 | void b43_do_release_fw(struct b43_firmware_file *fw); | ||
130 | |||
124 | #endif /* B43_MAIN_H_ */ | 131 | #endif /* B43_MAIN_H_ */ |