fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / wireless / bcm43xx / bcm43xx_sysfs.c
index b438f48..c71b998 100644 (file)
@@ -120,12 +120,14 @@ 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)
                err = sprom2hex(sprom, buf, PAGE_SIZE);
-       bcm43xx_unlock_mmio(bcm, flags);
+       mmiowb();
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&bcm->mutex);
        kfree(sprom);
 
        return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
        err = hex2sprom(sprom, buf, count);
        if (err)
                goto out_kfree;
-       bcm43xx_lock_mmio(bcm, flags);
-       assert(bcm->initialized);
+       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);
 
@@ -170,15 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
                                            char *buf)
 {
        struct bcm43xx_private *bcm = dev_to_bcm(dev);
-       unsigned long flags;
-       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:
@@ -193,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
        default:
                assert(0);
        }
-       err = 0;
 
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
-       return err ? err : count;
+       return count;
 
 }
 
@@ -231,16 +233,17 @@ 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;
 }
@@ -254,25 +257,21 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
                                          char *buf)
 {
        struct bcm43xx_private *bcm = dev_to_bcm(dev);
-       unsigned long flags;
-       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");
        else
                count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
-       err = 0;
-       bcm43xx_unlock(bcm, flags);
+       mutex_unlock(&bcm->mutex);
 
-       return err ? err : count;
+       return count;
 }
 
 static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
@@ -281,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
 {
        struct bcm43xx_private *bcm = dev_to_bcm(dev);
        unsigned long flags;
-       int err;
        int value;
 
        if (!capable(CAP_NET_ADMIN))
@@ -290,27 +288,147 @@ 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;
+       return 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;
+       }
+
+       bcm43xx_periodic_tasks_delete(bcm);
+       mutex_lock(&(bcm)->mutex);
+       err = bcm43xx_select_wireless_core(bcm, phytype);
+       if (!err)
+               bcm43xx_periodic_tasks_setup(bcm);
+       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);
+
+static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       unsigned long flags;
+       struct bcm43xx_private *bcm = dev_to_bcm(dev);
+       ssize_t count = 0;
+       u16 status;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       mutex_lock(&(bcm)->mutex);
+       spin_lock_irqsave(&bcm->irq_lock, flags);
+       status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+                                   BCM43xx_UCODE_STATUS);
+
+       spin_unlock_irqrestore(&bcm->irq_lock, flags);
+       mutex_unlock(&(bcm)->mutex);
+       switch (status) {
+       case 0x0000:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
+                                status);
+               break;
+       case 0x0001:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
+                                status);
+               break;
+       case 0x0002:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
+                                status);
+               break;
+       case 0x0003:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
+                                status);
+               break;
+       case 0x0004:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
+                                status);
+               break;
+       default:
+               count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
+                                status);
+               break;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(microcodestatus, 0444,
+                  bcm43xx_attr_microcode_show,
+                  NULL);
+
 int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
 {
        struct device *dev = &bcm->pci_dev->dev;
        int err;
 
-       assert(bcm->initialized);
+       assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
        err = device_create_file(dev, &dev_attr_sprom);
        if (err)
@@ -321,9 +439,19 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
        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;
+       err = device_create_file(dev, &dev_attr_microcodestatus);
+       if (err)
+               goto err_remove_phymode;
 
 out:
        return err;
+err_remove_phymode:
+       device_remove_file(dev, &dev_attr_phymode);
+err_remove_shortpreamble:
+       device_remove_file(dev, &dev_attr_shortpreamble);
 err_remove_interfmode:
        device_remove_file(dev, &dev_attr_interference);
 err_remove_sprom:
@@ -335,6 +463,8 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
 {
        struct device *dev = &bcm->pci_dev->dev;
 
+       device_remove_file(dev, &dev_attr_microcodestatus);
+       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);