diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-03-10 16:26:32 (GMT) |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-13 23:32:32 (GMT) |
commit | e7ec2e3230633a858af1b0b359f6c4670dbeb997 (patch) | |
tree | c43dbd7f6cab0ac066c039697528312d802617ef /drivers/ssb/pci.c | |
parent | 068edceb7e73c05f77e204442ea8f86e238575da (diff) | |
download | linux-e7ec2e3230633a858af1b0b359f6c4670dbeb997.tar.xz |
ssb: Add SPROM/invariants support for PCMCIA devices
This adds support for reading/writing the SPROM invariants
for PCMCIA based devices.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/pci.c')
-rw-r--r-- | drivers/ssb/pci.c | 113 |
1 files changed, 10 insertions, 103 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 1facc76..f1514b3 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -227,7 +227,7 @@ static u8 ssb_sprom_crc(const u16 *sprom, u16 size) return crc; } -static int sprom_check_crc(const u16 *sprom, u16 size) +static int sprom_check_crc(const u16 *sprom, size_t size) { u8 crc; u8 expected_crc; @@ -242,12 +242,14 @@ static int sprom_check_crc(const u16 *sprom, u16 size) return 0; } -static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) +static int sprom_do_read(struct ssb_bus *bus, u16 *sprom) { int i; for (i = 0; i < bus->sprom_size; i++) sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2)); + + return 0; } static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) @@ -660,71 +662,18 @@ const struct ssb_bus_ops ssb_pci_ops = { .write32 = ssb_pci_write32, }; -static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size) -{ - int i, pos = 0; - - for (i = 0; i < size; i++) - pos += snprintf(buf + pos, buf_len - pos - 1, - "%04X", swab16(sprom[i]) & 0xFFFF); - pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); - - return pos + 1; -} - -static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size) -{ - char tmp[5] = { 0 }; - int cnt = 0; - unsigned long parsed; - - if (len < size * 2) - return -EINVAL; - - while (cnt < size) { - memcpy(tmp, dump, 4); - dump += 4; - parsed = simple_strtoul(tmp, NULL, 16); - sprom[cnt++] = swab16((u16)parsed); - } - - return 0; -} - static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); struct ssb_bus *bus; - u16 *sprom; - int err = -ENODEV; - ssize_t count = 0; bus = ssb_pci_dev_to_bus(pdev); if (!bus) - goto out; - err = -ENOMEM; - sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); - if (!sprom) - goto out; + return -ENODEV; - /* Use interruptible locking, as the SPROM write might - * be holding the lock for several seconds. So allow userspace - * to cancel operation. */ - err = -ERESTARTSYS; - if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) - goto out_kfree; - sprom_do_read(bus, sprom); - mutex_unlock(&bus->pci_sprom_mutex); - - count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size); - err = 0; - -out_kfree: - kfree(sprom); -out: - return err ? err : count; + return ssb_attr_sprom_show(bus, buf, sprom_do_read); } static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, @@ -733,55 +682,13 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, { struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); struct ssb_bus *bus; - u16 *sprom; - int res = 0, err = -ENODEV; bus = ssb_pci_dev_to_bus(pdev); if (!bus) - goto out; - err = -ENOMEM; - sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); - if (!sprom) - goto out; - err = hex2sprom(sprom, buf, count, bus->sprom_size); - if (err) { - err = -EINVAL; - goto out_kfree; - } - err = sprom_check_crc(sprom, bus->sprom_size); - if (err) { - err = -EINVAL; - goto out_kfree; - } + return -ENODEV; - /* Use interruptible locking, as the SPROM write might - * be holding the lock for several seconds. So allow userspace - * to cancel operation. */ - err = -ERESTARTSYS; - if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) - goto out_kfree; - err = ssb_devices_freeze(bus); - if (err == -EOPNOTSUPP) { - ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " - "No suspend support. Is CONFIG_PM enabled?\n"); - goto out_unlock; - } - if (err) { - ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); - goto out_unlock; - } - res = sprom_do_write(bus, sprom); - err = ssb_devices_thaw(bus); - if (err) - ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); -out_unlock: - mutex_unlock(&bus->pci_sprom_mutex); -out_kfree: - kfree(sprom); -out: - if (res) - return res; - return err ? err : count; + return ssb_attr_sprom_store(bus, buf, count, + sprom_check_crc, sprom_do_write); } static DEVICE_ATTR(ssb_sprom, 0600, @@ -808,7 +715,7 @@ int ssb_pci_init(struct ssb_bus *bus) return 0; pdev = bus->host_pci; - mutex_init(&bus->pci_sprom_mutex); + mutex_init(&bus->sprom_mutex); err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); if (err) goto out; |