]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ssb/pci.c
ssb: Add SPROM/invariants support for PCMCIA devices
[linux-2.6-omap-h63xx.git] / drivers / ssb / pci.c
index 1facc7620fc804a2b66f72ecd726fffa742b361d..f1514b33cfae442ecdce8702aec55654a41dd2ed 100644 (file)
@@ -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;