diff options
author | Michael Buesch <mb@bu3sch.de> | 2009-01-23 15:21:51 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:01:30 -0500 |
commit | 1a9f509368ceb24fc66be961be15c69966f5eb5d (patch) | |
tree | c038db8330a52ad757ef630cbe8738e1f5afc1ca /drivers/net/wireless/b43/main.c | |
parent | 2f47690ed42a85820783dee7f16ae47edadf8fad (diff) |
b43: Automatically probe for opensource firmware
First probe for proprietary firmware and then probe for opensource firmware.
This way around it's a win-win situation.
1) If proprietary fw is available, it will work.
2) If opensource firmware is available, but no proprietary (Distros can only ship open fw)
it might work.
3) If both open and proprietary are available, it will work, because it selects
the proprietary. We currently don't prefer the open fw in this case, because it doesn't
work on all devices. It would introduce a regression otherwise.
The remaining FIXMEs in this patch are harmless, because they only matter on multiband
devices, which are not implemented yet anyway.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 154 |
1 files changed, 111 insertions, 43 deletions
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); |