diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:40 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:48 -0500 |
commit | 39d89cd34d9900cd2415f46e179b91cdd14b15fe (patch) | |
tree | 73e7e7978a9926d7d10aeb5de69defdedb4abc23 /drivers/net/wireless/ath9k/debug.c | |
parent | f98c3bd24161e9aaa73b9cd4dc6b1742c085ac17 (diff) |
ath9k: Add a debugfs interface for controlling virtual wiphys
debugfs ath9k/phy#/wiphy can be used to show the current list of
virtual wiphys and to add/remove virtual wiphys. Eventually, this
interface could be replaced with a cfg80211/nl80211 command that is
passed through mac80211.
For example:
# cat /debug/ath9k/phy0/wiphy
primary: phy0
# echo add > /debug/ath9k/phy0/wiphy
# cat /debug/ath9k/phy0/wiphy
primary: phy0
secondary: phy1
# echo del=phy1 > /debug/ath9k/phy0/wiphy
# cat /debug/ath9k/phy0/wiphy
primary: phy0
In addition, following commands can be used to test pausing and
unpausing of the virtual wiphys:
pause=phy1
unpause=phy1
select=phy1
(select pauses and unpauses wiphys automatically based on channel)
schedule=500
(set wiphy scheduling interval in msec; 0 = disable; default value: 500)
Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/debug.c')
-rw-r--r-- | drivers/net/wireless/ath9k/debug.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index 0c422c50e4f0..8d91422106d9 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c | |||
@@ -330,6 +330,163 @@ static const struct file_operations fops_rcstat = { | |||
330 | .owner = THIS_MODULE | 330 | .owner = THIS_MODULE |
331 | }; | 331 | }; |
332 | 332 | ||
333 | static const char * ath_wiphy_state_str(enum ath_wiphy_state state) | ||
334 | { | ||
335 | switch (state) { | ||
336 | case ATH_WIPHY_INACTIVE: | ||
337 | return "INACTIVE"; | ||
338 | case ATH_WIPHY_ACTIVE: | ||
339 | return "ACTIVE"; | ||
340 | case ATH_WIPHY_PAUSING: | ||
341 | return "PAUSING"; | ||
342 | case ATH_WIPHY_PAUSED: | ||
343 | return "PAUSED"; | ||
344 | case ATH_WIPHY_SCAN: | ||
345 | return "SCAN"; | ||
346 | } | ||
347 | return "?"; | ||
348 | } | ||
349 | |||
350 | static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, | ||
351 | size_t count, loff_t *ppos) | ||
352 | { | ||
353 | struct ath_softc *sc = file->private_data; | ||
354 | char buf[512]; | ||
355 | unsigned int len = 0; | ||
356 | int i; | ||
357 | u8 addr[ETH_ALEN]; | ||
358 | |||
359 | len += snprintf(buf + len, sizeof(buf) - len, | ||
360 | "primary: %s (%s chan=%d ht=%d)\n", | ||
361 | wiphy_name(sc->pri_wiphy->hw->wiphy), | ||
362 | ath_wiphy_state_str(sc->pri_wiphy->state), | ||
363 | sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); | ||
364 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
365 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
366 | if (aphy == NULL) | ||
367 | continue; | ||
368 | len += snprintf(buf + len, sizeof(buf) - len, | ||
369 | "secondary: %s (%s chan=%d ht=%d)\n", | ||
370 | wiphy_name(aphy->hw->wiphy), | ||
371 | ath_wiphy_state_str(aphy->state), | ||
372 | aphy->chan_idx, aphy->chan_is_ht); | ||
373 | } | ||
374 | |||
375 | put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); | ||
376 | put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); | ||
377 | len += snprintf(buf + len, sizeof(buf) - len, | ||
378 | "addr: %pM\n", addr); | ||
379 | put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); | ||
380 | put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); | ||
381 | len += snprintf(buf + len, sizeof(buf) - len, | ||
382 | "addrmask: %pM\n", addr); | ||
383 | |||
384 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
385 | } | ||
386 | |||
387 | static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) | ||
388 | { | ||
389 | int i; | ||
390 | if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) | ||
391 | return sc->pri_wiphy; | ||
392 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
393 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
394 | if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) | ||
395 | return aphy; | ||
396 | } | ||
397 | return NULL; | ||
398 | } | ||
399 | |||
400 | static int del_wiphy(struct ath_softc *sc, const char *name) | ||
401 | { | ||
402 | struct ath_wiphy *aphy = get_wiphy(sc, name); | ||
403 | if (!aphy) | ||
404 | return -ENOENT; | ||
405 | return ath9k_wiphy_del(aphy); | ||
406 | } | ||
407 | |||
408 | static int pause_wiphy(struct ath_softc *sc, const char *name) | ||
409 | { | ||
410 | struct ath_wiphy *aphy = get_wiphy(sc, name); | ||
411 | if (!aphy) | ||
412 | return -ENOENT; | ||
413 | return ath9k_wiphy_pause(aphy); | ||
414 | } | ||
415 | |||
416 | static int unpause_wiphy(struct ath_softc *sc, const char *name) | ||
417 | { | ||
418 | struct ath_wiphy *aphy = get_wiphy(sc, name); | ||
419 | if (!aphy) | ||
420 | return -ENOENT; | ||
421 | return ath9k_wiphy_unpause(aphy); | ||
422 | } | ||
423 | |||
424 | static int select_wiphy(struct ath_softc *sc, const char *name) | ||
425 | { | ||
426 | struct ath_wiphy *aphy = get_wiphy(sc, name); | ||
427 | if (!aphy) | ||
428 | return -ENOENT; | ||
429 | return ath9k_wiphy_select(aphy); | ||
430 | } | ||
431 | |||
432 | static int schedule_wiphy(struct ath_softc *sc, const char *msec) | ||
433 | { | ||
434 | ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, | ||
439 | size_t count, loff_t *ppos) | ||
440 | { | ||
441 | struct ath_softc *sc = file->private_data; | ||
442 | char buf[50]; | ||
443 | size_t len; | ||
444 | |||
445 | len = min(count, sizeof(buf) - 1); | ||
446 | if (copy_from_user(buf, user_buf, len)) | ||
447 | return -EFAULT; | ||
448 | buf[len] = '\0'; | ||
449 | if (len > 0 && buf[len - 1] == '\n') | ||
450 | buf[len - 1] = '\0'; | ||
451 | |||
452 | if (strncmp(buf, "add", 3) == 0) { | ||
453 | int res = ath9k_wiphy_add(sc); | ||
454 | if (res < 0) | ||
455 | return res; | ||
456 | } else if (strncmp(buf, "del=", 4) == 0) { | ||
457 | int res = del_wiphy(sc, buf + 4); | ||
458 | if (res < 0) | ||
459 | return res; | ||
460 | } else if (strncmp(buf, "pause=", 6) == 0) { | ||
461 | int res = pause_wiphy(sc, buf + 6); | ||
462 | if (res < 0) | ||
463 | return res; | ||
464 | } else if (strncmp(buf, "unpause=", 8) == 0) { | ||
465 | int res = unpause_wiphy(sc, buf + 8); | ||
466 | if (res < 0) | ||
467 | return res; | ||
468 | } else if (strncmp(buf, "select=", 7) == 0) { | ||
469 | int res = select_wiphy(sc, buf + 7); | ||
470 | if (res < 0) | ||
471 | return res; | ||
472 | } else if (strncmp(buf, "schedule=", 9) == 0) { | ||
473 | int res = schedule_wiphy(sc, buf + 9); | ||
474 | if (res < 0) | ||
475 | return res; | ||
476 | } else | ||
477 | return -EOPNOTSUPP; | ||
478 | |||
479 | return count; | ||
480 | } | ||
481 | |||
482 | static const struct file_operations fops_wiphy = { | ||
483 | .read = read_file_wiphy, | ||
484 | .write = write_file_wiphy, | ||
485 | .open = ath9k_debugfs_open, | ||
486 | .owner = THIS_MODULE | ||
487 | }; | ||
488 | |||
489 | |||
333 | int ath9k_init_debug(struct ath_softc *sc) | 490 | int ath9k_init_debug(struct ath_softc *sc) |
334 | { | 491 | { |
335 | sc->debug.debug_mask = ath9k_debug; | 492 | sc->debug.debug_mask = ath9k_debug; |
@@ -362,6 +519,12 @@ int ath9k_init_debug(struct ath_softc *sc) | |||
362 | if (!sc->debug.debugfs_rcstat) | 519 | if (!sc->debug.debugfs_rcstat) |
363 | goto err; | 520 | goto err; |
364 | 521 | ||
522 | sc->debug.debugfs_wiphy = debugfs_create_file( | ||
523 | "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, | ||
524 | &fops_wiphy); | ||
525 | if (!sc->debug.debugfs_wiphy) | ||
526 | goto err; | ||
527 | |||
365 | return 0; | 528 | return 0; |
366 | err: | 529 | err: |
367 | ath9k_exit_debug(sc); | 530 | ath9k_exit_debug(sc); |
@@ -370,6 +533,7 @@ err: | |||
370 | 533 | ||
371 | void ath9k_exit_debug(struct ath_softc *sc) | 534 | void ath9k_exit_debug(struct ath_softc *sc) |
372 | { | 535 | { |
536 | debugfs_remove(sc->debug.debugfs_wiphy); | ||
373 | debugfs_remove(sc->debug.debugfs_rcstat); | 537 | debugfs_remove(sc->debug.debugfs_rcstat); |
374 | debugfs_remove(sc->debug.debugfs_interrupt); | 538 | debugfs_remove(sc->debug.debugfs_interrupt); |
375 | debugfs_remove(sc->debug.debugfs_dma); | 539 | debugfs_remove(sc->debug.debugfs_dma); |