===================================================================
@@ -19,6 +19,7 @@
#include <linux/ssb/ssb_regs.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include "ssb_private.h"
@@ -613,6 +614,53 @@ static int sprom_extract(struct ssb_bus
return 0;
}
+static void ssb_vsprom_load_failed(void)
+{
+ printk(KERN_ERR "ssb: The BCM43XX device does not have an "
+ "SPROM built in, and the virtual SPROM file is not"
+ " available.\n");
+ printk(KERN_ERR "ssb: Please go to "
+ "http://wireless.kernel.org/en/users/Drivers/b43 "
+ "and download the utility to create the file.\n");
+}
+
+static void ssb_get_vsprom(const struct firmware *fw, void *context)
+{
+ /* Second part of asynchronous firmware load */
+ int i;
+ u16 *buf;
+ size_t size = SSB_SPROMSIZE_WORDS_R4;
+ struct ssb_bus *bus = context;
+
+ if (!fw) {
+ ssb_vsprom_load_failed();
+ return;
+ }
+ buf = kcalloc(size, sizeof(u16), GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "ssb: no memory for virtual sprom\n");
+ goto out;
+ }
+ if (fw->size != size * 2) {
+ printk(KERN_ERR "ssb: The virtual SPROM file has the wrong"
+ " size\n");
+ goto out_free;
+ }
+ for (i = 0; i < size; i++)
+ buf[i] = fw->data[2 * i + 1] << 8 | fw->data[2 * i];
+ if(sprom_check_crc(buf, size)) {
+ printk(KERN_ERR "ssb: Invalid CRC for virtual SPROM\n");
+ goto out_free;
+ }
+ sprom_extract(bus, &bus->sprom, buf, size);
+ printk(KERN_DEBUG "ssb: revision %d\n", bus->sprom.revision);
+
+out_free:
+ kfree(buf);
+out:
+ release_firmware(fw);
+}
+
static int ssb_pci_sprom_get(struct ssb_bus *bus,
struct ssb_sprom *sprom)
{
@@ -620,8 +668,17 @@ static int ssb_pci_sprom_get(struct ssb_
int err = -ENOMEM;
u16 *buf;
- if (!ssb_is_sprom_available(bus))
- return -ENODEV;
+ if (!ssb_is_sprom_available(bus)) {
+ /* This device has no SPROM. Try for a virtual version */
+ err = request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_HOTPLUG, "ssb/vsprom_image",
+ &bus->host_pci->dev, GFP_KERNEL, bus, ssb_get_vsprom);
+ if (err) {
+ ssb_vsprom_load_failed();
+ return err;
+ }
+ return 0;
+ }
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
===================================================================
@@ -4858,7 +4858,17 @@ static int b43_one_core_attach(struct ss
static void b43_sprom_fixup(struct ssb_bus *bus)
{
struct pci_dev *pdev;
+ int i;
+ /* The sprom contents may be loaded asynchronously. Check that the
+ * revision is set before proceeding */
+ for (i = 0; i < 1000; i++) {
+ if (bus->sprom.revision)
+ break;
+ msleep(1);
+ }
+ if (i == 1000)
+ printk(KERN_INFO "b43: No sprom image loaded\n");
/* boardflags workarounds */
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)