aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c178
1 files changed, 157 insertions, 21 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index 6a23bdc7541..c71b998a369 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
120 GFP_KERNEL); 120 GFP_KERNEL);
121 if (!sprom) 121 if (!sprom)
122 return -ENOMEM; 122 return -ENOMEM;
123 bcm43xx_lock_irqsafe(bcm, flags); 123 mutex_lock(&bcm->mutex);
124 spin_lock_irqsave(&bcm->irq_lock, flags);
124 err = bcm43xx_sprom_read(bcm, sprom); 125 err = bcm43xx_sprom_read(bcm, sprom);
125 if (!err) 126 if (!err)
126 err = sprom2hex(sprom, buf, PAGE_SIZE); 127 err = sprom2hex(sprom, buf, PAGE_SIZE);
127 mmiowb(); 128 mmiowb();
128 bcm43xx_unlock_irqsafe(bcm, flags); 129 spin_unlock_irqrestore(&bcm->irq_lock, flags);
130 mutex_unlock(&bcm->mutex);
129 kfree(sprom); 131 kfree(sprom);
130 132
131 return err; 133 return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
150 err = hex2sprom(sprom, buf, count); 152 err = hex2sprom(sprom, buf, count);
151 if (err) 153 if (err)
152 goto out_kfree; 154 goto out_kfree;
153 bcm43xx_lock_irqsafe(bcm, flags); 155 mutex_lock(&bcm->mutex);
156 spin_lock_irqsave(&bcm->irq_lock, flags);
157 spin_lock(&bcm->leds_lock);
154 err = bcm43xx_sprom_write(bcm, sprom); 158 err = bcm43xx_sprom_write(bcm, sprom);
155 mmiowb(); 159 mmiowb();
156 bcm43xx_unlock_irqsafe(bcm, flags); 160 spin_unlock(&bcm->leds_lock);
161 spin_unlock_irqrestore(&bcm->irq_lock, flags);
162 mutex_unlock(&bcm->mutex);
157out_kfree: 163out_kfree:
158 kfree(sprom); 164 kfree(sprom);
159 165
@@ -170,13 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
170 char *buf) 176 char *buf)
171{ 177{
172 struct bcm43xx_private *bcm = dev_to_bcm(dev); 178 struct bcm43xx_private *bcm = dev_to_bcm(dev);
173 int err;
174 ssize_t count = 0; 179 ssize_t count = 0;
175 180
176 if (!capable(CAP_NET_ADMIN)) 181 if (!capable(CAP_NET_ADMIN))
177 return -EPERM; 182 return -EPERM;
178 183
179 bcm43xx_lock_noirq(bcm); 184 mutex_lock(&bcm->mutex);
180 185
181 switch (bcm43xx_current_radio(bcm)->interfmode) { 186 switch (bcm43xx_current_radio(bcm)->interfmode) {
182 case BCM43xx_RADIO_INTERFMODE_NONE: 187 case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -191,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
191 default: 196 default:
192 assert(0); 197 assert(0);
193 } 198 }
194 err = 0;
195 199
196 bcm43xx_unlock_noirq(bcm); 200 mutex_unlock(&bcm->mutex);
197 201
198 return err ? err : count; 202 return count;
199 203
200} 204}
201 205
@@ -229,7 +233,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
229 return -EINVAL; 233 return -EINVAL;
230 } 234 }
231 235
232 bcm43xx_lock_irqsafe(bcm, flags); 236 mutex_lock(&bcm->mutex);
237 spin_lock_irqsave(&bcm->irq_lock, flags);
233 238
234 err = bcm43xx_radio_set_interference_mitigation(bcm, mode); 239 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
235 if (err) { 240 if (err) {
@@ -237,7 +242,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
237 "supported by device\n"); 242 "supported by device\n");
238 } 243 }
239 mmiowb(); 244 mmiowb();
240 bcm43xx_unlock_irqsafe(bcm, flags); 245 spin_unlock_irqrestore(&bcm->irq_lock, flags);
246 mutex_unlock(&bcm->mutex);
241 247
242 return err ? err : count; 248 return err ? err : count;
243} 249}
@@ -251,23 +257,21 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
251 char *buf) 257 char *buf)
252{ 258{
253 struct bcm43xx_private *bcm = dev_to_bcm(dev); 259 struct bcm43xx_private *bcm = dev_to_bcm(dev);
254 int err;
255 ssize_t count; 260 ssize_t count;
256 261
257 if (!capable(CAP_NET_ADMIN)) 262 if (!capable(CAP_NET_ADMIN))
258 return -EPERM; 263 return -EPERM;
259 264
260 bcm43xx_lock_noirq(bcm); 265 mutex_lock(&bcm->mutex);
261 266
262 if (bcm->short_preamble) 267 if (bcm->short_preamble)
263 count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); 268 count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
264 else 269 else
265 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); 270 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
266 271
267 err = 0; 272 mutex_unlock(&bcm->mutex);
268 bcm43xx_unlock_noirq(bcm);
269 273
270 return err ? err : count; 274 return count;
271} 275}
272 276
273static ssize_t bcm43xx_attr_preamble_store(struct device *dev, 277static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
@@ -276,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
276{ 280{
277 struct bcm43xx_private *bcm = dev_to_bcm(dev); 281 struct bcm43xx_private *bcm = dev_to_bcm(dev);
278 unsigned long flags; 282 unsigned long flags;
279 int err;
280 int value; 283 int value;
281 284
282 if (!capable(CAP_NET_ADMIN)) 285 if (!capable(CAP_NET_ADMIN))
@@ -285,20 +288,141 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
285 value = get_boolean(buf, count); 288 value = get_boolean(buf, count);
286 if (value < 0) 289 if (value < 0)
287 return value; 290 return value;
288 bcm43xx_lock_irqsafe(bcm, flags); 291 mutex_lock(&bcm->mutex);
292 spin_lock_irqsave(&bcm->irq_lock, flags);
289 293
290 bcm->short_preamble = !!value; 294 bcm->short_preamble = !!value;
291 295
292 err = 0; 296 spin_unlock_irqrestore(&bcm->irq_lock, flags);
293 bcm43xx_unlock_irqsafe(bcm, flags); 297 mutex_unlock(&bcm->mutex);
294 298
295 return err ? err : count; 299 return count;
296} 300}
297 301
298static DEVICE_ATTR(shortpreamble, 0644, 302static DEVICE_ATTR(shortpreamble, 0644,
299 bcm43xx_attr_preamble_show, 303 bcm43xx_attr_preamble_show,
300 bcm43xx_attr_preamble_store); 304 bcm43xx_attr_preamble_store);
301 305
306static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
307 struct device_attribute *attr,
308 const char *buf, size_t count)
309{
310 struct bcm43xx_private *bcm = dev_to_bcm(dev);
311 int phytype;
312 int err = -EINVAL;
313
314 if (count < 1)
315 goto out;
316 switch (buf[0]) {
317 case 'a': case 'A':
318 phytype = BCM43xx_PHYTYPE_A;
319 break;
320 case 'b': case 'B':
321 phytype = BCM43xx_PHYTYPE_B;
322 break;
323 case 'g': case 'G':
324 phytype = BCM43xx_PHYTYPE_G;
325 break;
326 default:
327 goto out;
328 }
329
330 bcm43xx_periodic_tasks_delete(bcm);
331 mutex_lock(&(bcm)->mutex);
332 err = bcm43xx_select_wireless_core(bcm, phytype);
333 if (!err)
334 bcm43xx_periodic_tasks_setup(bcm);
335 mutex_unlock(&(bcm)->mutex);
336 if (err == -ESRCH)
337 err = -ENODEV;
338
339out:
340 return err ? err : count;
341}
342
343static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
344 struct device_attribute *attr,
345 char *buf)
346{
347 struct bcm43xx_private *bcm = dev_to_bcm(dev);
348 ssize_t count = 0;
349
350 mutex_lock(&(bcm)->mutex);
351 switch (bcm43xx_current_phy(bcm)->type) {
352 case BCM43xx_PHYTYPE_A:
353 snprintf(buf, PAGE_SIZE, "A");
354 break;
355 case BCM43xx_PHYTYPE_B:
356 snprintf(buf, PAGE_SIZE, "B");
357 break;
358 case BCM43xx_PHYTYPE_G:
359 snprintf(buf, PAGE_SIZE, "G");
360 break;
361 default:
362 assert(0);
363 }
364 mutex_unlock(&(bcm)->mutex);
365
366 return count;
367}
368
369static DEVICE_ATTR(phymode, 0644,
370 bcm43xx_attr_phymode_show,
371 bcm43xx_attr_phymode_store);
372
373static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
374 struct device_attribute *attr,
375 char *buf)
376{
377 unsigned long flags;
378 struct bcm43xx_private *bcm = dev_to_bcm(dev);
379 ssize_t count = 0;
380 u16 status;
381
382 if (!capable(CAP_NET_ADMIN))
383 return -EPERM;
384
385 mutex_lock(&(bcm)->mutex);
386 spin_lock_irqsave(&bcm->irq_lock, flags);
387 status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
388 BCM43xx_UCODE_STATUS);
389
390 spin_unlock_irqrestore(&bcm->irq_lock, flags);
391 mutex_unlock(&(bcm)->mutex);
392 switch (status) {
393 case 0x0000:
394 count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
395 status);
396 break;
397 case 0x0001:
398 count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
399 status);
400 break;
401 case 0x0002:
402 count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
403 status);
404 break;
405 case 0x0003:
406 count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
407 status);
408 break;
409 case 0x0004:
410 count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
411 status);
412 break;
413 default:
414 count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
415 status);
416 break;
417 }
418
419 return count;
420}
421
422static DEVICE_ATTR(microcodestatus, 0444,
423 bcm43xx_attr_microcode_show,
424 NULL);
425
302int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) 426int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
303{ 427{
304 struct device *dev = &bcm->pci_dev->dev; 428 struct device *dev = &bcm->pci_dev->dev;
@@ -315,9 +439,19 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
315 err = device_create_file(dev, &dev_attr_shortpreamble); 439 err = device_create_file(dev, &dev_attr_shortpreamble);
316 if (err) 440 if (err)
317 goto err_remove_interfmode; 441 goto err_remove_interfmode;
442 err = device_create_file(dev, &dev_attr_phymode);
443 if (err)
444 goto err_remove_shortpreamble;
445 err = device_create_file(dev, &dev_attr_microcodestatus);
446 if (err)
447 goto err_remove_phymode;
318 448
319out: 449out:
320 return err; 450 return err;
451err_remove_phymode:
452 device_remove_file(dev, &dev_attr_phymode);
453err_remove_shortpreamble:
454 device_remove_file(dev, &dev_attr_shortpreamble);
321err_remove_interfmode: 455err_remove_interfmode:
322 device_remove_file(dev, &dev_attr_interference); 456 device_remove_file(dev, &dev_attr_interference);
323err_remove_sprom: 457err_remove_sprom:
@@ -329,6 +463,8 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
329{ 463{
330 struct device *dev = &bcm->pci_dev->dev; 464 struct device *dev = &bcm->pci_dev->dev;
331 465
466 device_remove_file(dev, &dev_attr_microcodestatus);
467 device_remove_file(dev, &dev_attr_phymode);
332 device_remove_file(dev, &dev_attr_shortpreamble); 468 device_remove_file(dev, &dev_attr_shortpreamble);
333 device_remove_file(dev, &dev_attr_interference); 469 device_remove_file(dev, &dev_attr_interference);
334 device_remove_file(dev, &dev_attr_sprom); 470 device_remove_file(dev, &dev_attr_sprom);