]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/rt2x00/rt2500usb.c
rt2x00: Place mutex around USB register access
[linux-2.6] / drivers / net / wireless / rt2x00 / rt2500usb.c
index c89103786b1cba8d7d607bb8228b47ce6e00e7ff..a00420e9626b65fd4670bedd2e7b7b79f86a8073 100644 (file)
@@ -52,6 +52,8 @@
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
+ * If the usb_cache_mutex is already held then the _lock variants must
+ * be used instead.
  */
 static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
                                           const unsigned int offset,
@@ -64,6 +66,17 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
        *value = le16_to_cpu(reg);
 }
 
+static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+                                               const unsigned int offset,
+                                               u16 *value)
+{
+       __le16 reg;
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+                                      USB_VENDOR_REQUEST_IN, offset,
+                                      &reg, sizeof(u16), REGISTER_TIMEOUT);
+       *value = le16_to_cpu(reg);
+}
+
 static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
                                                const unsigned int offset,
                                                void *value, const u16 length)
@@ -84,6 +97,16 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
                                      &reg, sizeof(u16), REGISTER_TIMEOUT);
 }
 
+static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+                                                const unsigned int offset,
+                                                u16 value)
+{
+       __le16 reg = cpu_to_le16(value);
+       rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+                                      USB_VENDOR_REQUEST_OUT, offset,
+                                      &reg, sizeof(u16), REGISTER_TIMEOUT);
+}
+
 static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
                                                 const unsigned int offset,
                                                 void *value, const u16 length)
@@ -100,7 +123,7 @@ static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
        unsigned int i;
 
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg);
+               rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
                if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
                        break;
                udelay(REGISTER_BUSY_DELAY);
@@ -114,12 +137,15 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 {
        u16 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
        reg = rt2500usb_bbp_check(rt2x00dev);
        if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
@@ -131,7 +157,9 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
        rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -139,6 +167,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 {
        u16 reg;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        /*
         * Wait until the BBP becomes ready.
         */
@@ -155,7 +185,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
        rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
        /*
         * Wait until the BBP becomes ready.
@@ -164,11 +194,14 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
        if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
                ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
                *value = 0xff;
+               mutex_unlock(&rt2x00dev->usb_cache_mutex);
                return;
        }
 
-       rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg);
+       rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
        *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -180,20 +213,23 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
        if (!word)
                return;
 
+       mutex_lock(&rt2x00dev->usb_cache_mutex);
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg);
+               rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
                if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
                        goto rf_write;
                udelay(REGISTER_BUSY_DELAY);
        }
 
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
        ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
        return;
 
 rf_write:
        reg = 0;
        rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
-       rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
 
        reg = 0;
        rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
@@ -201,8 +237,10 @@ rf_write:
        rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
        rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
 
-       rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+       rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
        rt2x00_rf_write(rt2x00dev, word, value);
+
+       mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS