summaryrefslogtreecommitdiffstats
path: root/drivers/ssb/pci.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-03-10 17:26:32 +0100
committerJohn W. Linville <linville@tuxdriver.com>2008-03-13 19:32:32 -0400
commite7ec2e3230633a858af1b0b359f6c4670dbeb997 (patch)
treec43dbd7f6cab0ac066c039697528312d802617ef /drivers/ssb/pci.c
parent068edceb7e73c05f77e204442ea8f86e238575da (diff)
downloadlinux-stable-e7ec2e3230633a858af1b0b359f6c4670dbeb997.tar.gz
linux-stable-e7ec2e3230633a858af1b0b359f6c4670dbeb997.tar.bz2
linux-stable-e7ec2e3230633a858af1b0b359f6c4670dbeb997.zip
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.c113
1 files changed, 10 insertions, 103 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 1facc7620fc8..f1514b33cfae 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;