X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fbcm43xx%2Fbcm43xx_sysfs.c;h=ece335178f6a7483e81f142d2a24ef5128d0094d;hb=699a71238856b19091503c671bac8abb1e3f9a3a;hp=c44d890b949b149f5346ea7d0205f2bd08b3fd12;hpb=064c94f9da8845f12446ab37142aa10f3c6f66ac;p=pandora-kernel.git diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index c44d890b949b..ece335178f6a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -71,14 +71,46 @@ static int get_boolean(const char *buf, size_t count) return -EINVAL; } +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ + int i, pos = 0; + + for (i = 0; i < BCM43xx_SPROM_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) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) + return -EINVAL; + + while (cnt < BCM43xx_SPROM_SIZE) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + static ssize_t bcm43xx_attr_sprom_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + struct bcm43xx_private *bcm = dev_to_bcm(dev); u16 *sprom; unsigned long flags; - int i, err; + int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -88,67 +120,69 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, GFP_KERNEL); if (!sprom) return -ENOMEM; - bcm43xx_lock_mmio(bcm, flags); - assert(bcm->initialized); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); err = bcm43xx_sprom_read(bcm, sprom); - if (!err) { - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - buf[i * 2] = sprom[i] & 0x00FF; - buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; - } - } - bcm43xx_unlock_mmio(bcm, flags); + if (!err) + err = sprom2hex(sprom, buf, PAGE_SIZE); + mmiowb(); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); kfree(sprom); - return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); + return err; } static ssize_t bcm43xx_attr_sprom_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + struct bcm43xx_private *bcm = dev_to_bcm(dev); u16 *sprom; unsigned long flags; - int i, err; + int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) - return -EINVAL; sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), GFP_KERNEL); if (!sprom) return -ENOMEM; - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - sprom[i] = buf[i * 2] & 0xFF; - sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; - } - bcm43xx_lock_mmio(bcm, flags); - assert(bcm->initialized); + err = hex2sprom(sprom, buf, count); + if (err) + goto out_kfree; + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); + spin_lock(&bcm->leds_lock); err = bcm43xx_sprom_write(bcm, sprom); - bcm43xx_unlock_mmio(bcm, flags); + mmiowb(); + spin_unlock(&bcm->leds_lock); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); +out_kfree: kfree(sprom); return err ? err : count; } +static DEVICE_ATTR(sprom, 0600, + bcm43xx_attr_sprom_show, + bcm43xx_attr_sprom_store); + static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); - unsigned long flags; + struct bcm43xx_private *bcm = dev_to_bcm(dev); int err; ssize_t count = 0; if (!capable(CAP_NET_ADMIN)) return -EPERM; - bcm43xx_lock(bcm, flags); - assert(bcm->initialized); + mutex_lock(&bcm->mutex); switch (bcm43xx_current_radio(bcm)->interfmode) { case BCM43xx_RADIO_INTERFMODE_NONE: @@ -165,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, } err = 0; - bcm43xx_unlock(bcm, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; @@ -175,7 +209,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; int mode; @@ -201,34 +235,37 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, return -EINVAL; } - bcm43xx_lock_mmio(bcm, flags); - assert(bcm->initialized); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); err = bcm43xx_radio_set_interference_mitigation(bcm, mode); if (err) { printk(KERN_ERR PFX "Interference Mitigation not " "supported by device\n"); } - - bcm43xx_unlock_mmio(bcm, flags); + mmiowb(); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; } +static DEVICE_ATTR(interference, 0644, + bcm43xx_attr_interfmode_show, + bcm43xx_attr_interfmode_store); + static ssize_t bcm43xx_attr_preamble_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); - unsigned long flags; + struct bcm43xx_private *bcm = dev_to_bcm(dev); int err; ssize_t count; if (!capable(CAP_NET_ADMIN)) return -EPERM; - bcm43xx_lock(bcm, flags); - assert(bcm->initialized); + mutex_lock(&bcm->mutex); if (bcm->short_preamble) count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); @@ -236,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); err = 0; - bcm43xx_unlock(bcm, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; } @@ -245,7 +282,7 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; int value; @@ -256,67 +293,123 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, value = get_boolean(buf, count); if (value < 0) return value; - bcm43xx_lock(bcm, flags); - assert(bcm->initialized); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm->short_preamble = !!value; err = 0; - bcm43xx_unlock(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; } +static DEVICE_ATTR(shortpreamble, 0644, + bcm43xx_attr_preamble_show, + bcm43xx_attr_preamble_store); + +static ssize_t bcm43xx_attr_phymode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = dev_to_bcm(dev); + int phytype; + int err = -EINVAL; + + if (count < 1) + goto out; + switch (buf[0]) { + case 'a': case 'A': + phytype = BCM43xx_PHYTYPE_A; + break; + case 'b': case 'B': + phytype = BCM43xx_PHYTYPE_B; + break; + case 'g': case 'G': + phytype = BCM43xx_PHYTYPE_G; + break; + default: + goto out; + } + + mutex_lock(&(bcm)->mutex); + err = bcm43xx_select_wireless_core(bcm, phytype); + mutex_unlock(&(bcm)->mutex); + if (err == -ESRCH) + err = -ENODEV; + +out: + return err ? err : count; +} + +static ssize_t bcm43xx_attr_phymode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = dev_to_bcm(dev); + ssize_t count = 0; + + mutex_lock(&(bcm)->mutex); + switch (bcm43xx_current_phy(bcm)->type) { + case BCM43xx_PHYTYPE_A: + snprintf(buf, PAGE_SIZE, "A"); + break; + case BCM43xx_PHYTYPE_B: + snprintf(buf, PAGE_SIZE, "B"); + break; + case BCM43xx_PHYTYPE_G: + snprintf(buf, PAGE_SIZE, "G"); + break; + default: + assert(0); + } + mutex_unlock(&(bcm)->mutex); + + return count; +} + +static DEVICE_ATTR(phymode, 0644, + bcm43xx_attr_phymode_show, + bcm43xx_attr_phymode_store); + int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) { struct device *dev = &bcm->pci_dev->dev; - struct bcm43xx_sysfs *sysfs = &bcm->sysfs; int err; - assert(bcm->initialized); + assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - sysfs->attr_sprom.attr.name = "sprom"; - sysfs->attr_sprom.attr.owner = THIS_MODULE; - sysfs->attr_sprom.attr.mode = 0600; - sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; - sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; - err = device_create_file(dev, &sysfs->attr_sprom); + err = device_create_file(dev, &dev_attr_sprom); if (err) goto out; - - sysfs->attr_interfmode.attr.name = "interference"; - sysfs->attr_interfmode.attr.owner = THIS_MODULE; - sysfs->attr_interfmode.attr.mode = 0600; - sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; - sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; - err = device_create_file(dev, &sysfs->attr_interfmode); + err = device_create_file(dev, &dev_attr_interference); if (err) goto err_remove_sprom; - - sysfs->attr_preamble.attr.name = "shortpreamble"; - sysfs->attr_preamble.attr.owner = THIS_MODULE; - sysfs->attr_preamble.attr.mode = 0600; - sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; - sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; - err = device_create_file(dev, &sysfs->attr_preamble); + err = device_create_file(dev, &dev_attr_shortpreamble); if (err) goto err_remove_interfmode; + err = device_create_file(dev, &dev_attr_phymode); + if (err) + goto err_remove_shortpreamble; out: return err; +err_remove_shortpreamble: + device_remove_file(dev, &dev_attr_shortpreamble); err_remove_interfmode: - device_remove_file(dev, &sysfs->attr_interfmode); + device_remove_file(dev, &dev_attr_interference); err_remove_sprom: - device_remove_file(dev, &sysfs->attr_sprom); + device_remove_file(dev, &dev_attr_sprom); goto out; } void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) { struct device *dev = &bcm->pci_dev->dev; - struct bcm43xx_sysfs *sysfs = &bcm->sysfs; - device_remove_file(dev, &sysfs->attr_preamble); - device_remove_file(dev, &sysfs->attr_interfmode); - device_remove_file(dev, &sysfs->attr_sprom); + device_remove_file(dev, &dev_attr_phymode); + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); + device_remove_file(dev, &dev_attr_sprom); }