diff options
-rw-r--r-- | drivers/net/ieee802154/at86rf230.c | 433 | ||||
-rw-r--r-- | include/linux/nl802154.h | 12 | ||||
-rw-r--r-- | include/net/mac802154.h | 35 | ||||
-rw-r--r-- | include/net/wpan-phy.h | 19 | ||||
-rw-r--r-- | net/ieee802154/ieee802154.h | 1 | ||||
-rw-r--r-- | net/ieee802154/netlink.c | 1 | ||||
-rw-r--r-- | net/ieee802154/nl-phy.c | 198 | ||||
-rw-r--r-- | net/ieee802154/nl_policy.c | 10 | ||||
-rw-r--r-- | net/ieee802154/wpan-class.c | 10 | ||||
-rw-r--r-- | net/mac802154/ieee802154_dev.c | 67 |
10 files changed, 668 insertions, 118 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index ab31544bc254..34bf011584fb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c | |||
@@ -37,7 +37,6 @@ | |||
37 | 37 | ||
38 | struct at86rf230_local { | 38 | struct at86rf230_local { |
39 | struct spi_device *spi; | 39 | struct spi_device *spi; |
40 | int rstn, slp_tr, dig2; | ||
41 | 40 | ||
42 | u8 part; | 41 | u8 part; |
43 | u8 vers; | 42 | u8 vers; |
@@ -53,8 +52,16 @@ struct at86rf230_local { | |||
53 | spinlock_t lock; | 52 | spinlock_t lock; |
54 | bool irq_busy; | 53 | bool irq_busy; |
55 | bool is_tx; | 54 | bool is_tx; |
55 | bool tx_aret; | ||
56 | |||
57 | int rssi_base_val; | ||
56 | }; | 58 | }; |
57 | 59 | ||
60 | static inline int is_rf212(struct at86rf230_local *local) | ||
61 | { | ||
62 | return local->part == 7; | ||
63 | } | ||
64 | |||
58 | #define RG_TRX_STATUS (0x01) | 65 | #define RG_TRX_STATUS (0x01) |
59 | #define SR_TRX_STATUS 0x01, 0x1f, 0 | 66 | #define SR_TRX_STATUS 0x01, 0x1f, 0 |
60 | #define SR_RESERVED_01_3 0x01, 0x20, 5 | 67 | #define SR_RESERVED_01_3 0x01, 0x20, 5 |
@@ -100,7 +107,10 @@ struct at86rf230_local { | |||
100 | #define SR_SFD_VALUE 0x0b, 0xff, 0 | 107 | #define SR_SFD_VALUE 0x0b, 0xff, 0 |
101 | #define RG_TRX_CTRL_2 (0x0c) | 108 | #define RG_TRX_CTRL_2 (0x0c) |
102 | #define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 | 109 | #define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 |
103 | #define SR_RESERVED_0c_2 0x0c, 0x7c, 2 | 110 | #define SR_SUB_MODE 0x0c, 0x04, 2 |
111 | #define SR_BPSK_QPSK 0x0c, 0x08, 3 | ||
112 | #define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 | ||
113 | #define SR_RESERVED_0c_5 0x0c, 0x60, 5 | ||
104 | #define SR_RX_SAFE_MODE 0x0c, 0x80, 7 | 114 | #define SR_RX_SAFE_MODE 0x0c, 0x80, 7 |
105 | #define RG_ANT_DIV (0x0d) | 115 | #define RG_ANT_DIV (0x0d) |
106 | #define SR_ANT_CTRL 0x0d, 0x03, 0 | 116 | #define SR_ANT_CTRL 0x0d, 0x03, 0 |
@@ -145,7 +155,7 @@ struct at86rf230_local { | |||
145 | #define SR_RESERVED_17_5 0x17, 0x08, 3 | 155 | #define SR_RESERVED_17_5 0x17, 0x08, 3 |
146 | #define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 | 156 | #define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 |
147 | #define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 | 157 | #define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 |
148 | #define SR_RESERVED_17_2 0x17, 0x40, 6 | 158 | #define SR_CSMA_LBT_MODE 0x17, 0x40, 6 |
149 | #define SR_RESERVED_17_1 0x17, 0x80, 7 | 159 | #define SR_RESERVED_17_1 0x17, 0x80, 7 |
150 | #define RG_FTN_CTRL (0x18) | 160 | #define RG_FTN_CTRL (0x18) |
151 | #define SR_RESERVED_18_2 0x18, 0x7f, 0 | 161 | #define SR_RESERVED_18_2 0x18, 0x7f, 0 |
@@ -244,6 +254,57 @@ struct at86rf230_local { | |||
244 | #define STATE_TRANSITION_IN_PROGRESS 0x1F | 254 | #define STATE_TRANSITION_IN_PROGRESS 0x1F |
245 | 255 | ||
246 | static int | 256 | static int |
257 | __at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part, | ||
258 | u8 *version) | ||
259 | { | ||
260 | u8 data[4]; | ||
261 | u8 *buf = kmalloc(2, GFP_KERNEL); | ||
262 | int status; | ||
263 | struct spi_message msg; | ||
264 | struct spi_transfer xfer = { | ||
265 | .len = 2, | ||
266 | .tx_buf = buf, | ||
267 | .rx_buf = buf, | ||
268 | }; | ||
269 | u8 reg; | ||
270 | |||
271 | if (!buf) | ||
272 | return -ENOMEM; | ||
273 | |||
274 | for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) { | ||
275 | buf[0] = (reg & CMD_REG_MASK) | CMD_REG; | ||
276 | buf[1] = 0xff; | ||
277 | dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); | ||
278 | spi_message_init(&msg); | ||
279 | spi_message_add_tail(&xfer, &msg); | ||
280 | |||
281 | status = spi_sync(spi, &msg); | ||
282 | dev_vdbg(&spi->dev, "status = %d\n", status); | ||
283 | if (msg.status) | ||
284 | status = msg.status; | ||
285 | |||
286 | dev_vdbg(&spi->dev, "status = %d\n", status); | ||
287 | dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); | ||
288 | dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]); | ||
289 | |||
290 | if (status == 0) | ||
291 | data[reg - RG_PART_NUM] = buf[1]; | ||
292 | else | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | if (status == 0) { | ||
297 | *part = data[0]; | ||
298 | *version = data[1]; | ||
299 | *man_id = (data[3] << 8) | data[2]; | ||
300 | } | ||
301 | |||
302 | kfree(buf); | ||
303 | |||
304 | return status; | ||
305 | } | ||
306 | |||
307 | static int | ||
247 | __at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data) | 308 | __at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data) |
248 | { | 309 | { |
249 | u8 *buf = lp->buf; | 310 | u8 *buf = lp->buf; |
@@ -489,7 +550,9 @@ at86rf230_state(struct ieee802154_dev *dev, int state) | |||
489 | } while (val == STATE_TRANSITION_IN_PROGRESS); | 550 | } while (val == STATE_TRANSITION_IN_PROGRESS); |
490 | 551 | ||
491 | 552 | ||
492 | if (val == desired_status) | 553 | if (val == desired_status || |
554 | (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) || | ||
555 | (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK)) | ||
493 | return 0; | 556 | return 0; |
494 | 557 | ||
495 | pr_err("unexpected state change: %d, asked for %d\n", val, state); | 558 | pr_err("unexpected state change: %d, asked for %d\n", val, state); |
@@ -510,7 +573,11 @@ at86rf230_start(struct ieee802154_dev *dev) | |||
510 | if (rc) | 573 | if (rc) |
511 | return rc; | 574 | return rc; |
512 | 575 | ||
513 | return at86rf230_state(dev, STATE_RX_ON); | 576 | rc = at86rf230_state(dev, STATE_FORCE_TX_ON); |
577 | if (rc) | ||
578 | return rc; | ||
579 | |||
580 | return at86rf230_state(dev, STATE_RX_AACK_ON); | ||
514 | } | 581 | } |
515 | 582 | ||
516 | static void | 583 | static void |
@@ -520,6 +587,39 @@ at86rf230_stop(struct ieee802154_dev *dev) | |||
520 | } | 587 | } |
521 | 588 | ||
522 | static int | 589 | static int |
590 | at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel) | ||
591 | { | ||
592 | lp->rssi_base_val = -91; | ||
593 | |||
594 | return at86rf230_write_subreg(lp, SR_CHANNEL, channel); | ||
595 | } | ||
596 | |||
597 | static int | ||
598 | at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel) | ||
599 | { | ||
600 | int rc; | ||
601 | |||
602 | if (channel == 0) | ||
603 | rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0); | ||
604 | else | ||
605 | rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1); | ||
606 | if (rc < 0) | ||
607 | return rc; | ||
608 | |||
609 | if (page == 0) { | ||
610 | rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0); | ||
611 | lp->rssi_base_val = -100; | ||
612 | } else { | ||
613 | rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1); | ||
614 | lp->rssi_base_val = -98; | ||
615 | } | ||
616 | if (rc < 0) | ||
617 | return rc; | ||
618 | |||
619 | return at86rf230_write_subreg(lp, SR_CHANNEL, channel); | ||
620 | } | ||
621 | |||
622 | static int | ||
523 | at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) | 623 | at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) |
524 | { | 624 | { |
525 | struct at86rf230_local *lp = dev->priv; | 625 | struct at86rf230_local *lp = dev->priv; |
@@ -527,14 +627,22 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) | |||
527 | 627 | ||
528 | might_sleep(); | 628 | might_sleep(); |
529 | 629 | ||
530 | if (page != 0 || channel < 11 || channel > 26) { | 630 | if (page < 0 || page > 31 || |
631 | !(lp->dev->phy->channels_supported[page] & BIT(channel))) { | ||
531 | WARN_ON(1); | 632 | WARN_ON(1); |
532 | return -EINVAL; | 633 | return -EINVAL; |
533 | } | 634 | } |
534 | 635 | ||
535 | rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel); | 636 | if (is_rf212(lp)) |
637 | rc = at86rf212_set_channel(lp, page, channel); | ||
638 | else | ||
639 | rc = at86rf230_set_channel(lp, page, channel); | ||
640 | if (rc < 0) | ||
641 | return rc; | ||
642 | |||
536 | msleep(1); /* Wait for PLL */ | 643 | msleep(1); /* Wait for PLL */ |
537 | dev->phy->current_channel = channel; | 644 | dev->phy->current_channel = channel; |
645 | dev->phy->current_page = page; | ||
538 | 646 | ||
539 | return 0; | 647 | return 0; |
540 | } | 648 | } |
@@ -568,6 +676,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) | |||
568 | if (rc) | 676 | if (rc) |
569 | goto err_rx; | 677 | goto err_rx; |
570 | 678 | ||
679 | if (lp->tx_aret) { | ||
680 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON); | ||
681 | if (rc) | ||
682 | goto err_rx; | ||
683 | } | ||
684 | |||
571 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX); | 685 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX); |
572 | if (rc) | 686 | if (rc) |
573 | goto err_rx; | 687 | goto err_rx; |
@@ -668,6 +782,98 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, | |||
668 | return 0; | 782 | return 0; |
669 | } | 783 | } |
670 | 784 | ||
785 | static int | ||
786 | at86rf212_set_txpower(struct ieee802154_dev *dev, int db) | ||
787 | { | ||
788 | struct at86rf230_local *lp = dev->priv; | ||
789 | int rc; | ||
790 | |||
791 | /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five | ||
792 | * bits decrease power in 1dB steps. 0x60 represents extra PA gain of | ||
793 | * 0dB. | ||
794 | * thus, supported values for db range from -26 to 5, for 31dB of | ||
795 | * reduction to 0dB of reduction. | ||
796 | */ | ||
797 | if (db > 5 || db < -26) | ||
798 | return -EINVAL; | ||
799 | |||
800 | db = -(db - 5); | ||
801 | |||
802 | rc = __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db); | ||
803 | if (rc) | ||
804 | return rc; | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int | ||
810 | at86rf212_set_lbt(struct ieee802154_dev *dev, bool on) | ||
811 | { | ||
812 | struct at86rf230_local *lp = dev->priv; | ||
813 | |||
814 | return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on); | ||
815 | } | ||
816 | |||
817 | static int | ||
818 | at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode) | ||
819 | { | ||
820 | struct at86rf230_local *lp = dev->priv; | ||
821 | |||
822 | return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); | ||
823 | } | ||
824 | |||
825 | static int | ||
826 | at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) | ||
827 | { | ||
828 | struct at86rf230_local *lp = dev->priv; | ||
829 | int desens_steps; | ||
830 | |||
831 | if (level < lp->rssi_base_val || level > 30) | ||
832 | return -EINVAL; | ||
833 | |||
834 | desens_steps = (level - lp->rssi_base_val) * 100 / 207; | ||
835 | |||
836 | return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps); | ||
837 | } | ||
838 | |||
839 | static int | ||
840 | at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be, | ||
841 | u8 retries) | ||
842 | { | ||
843 | struct at86rf230_local *lp = dev->priv; | ||
844 | int rc; | ||
845 | |||
846 | if (min_be > max_be || max_be > 8 || retries > 5) | ||
847 | return -EINVAL; | ||
848 | |||
849 | rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be); | ||
850 | if (rc) | ||
851 | return rc; | ||
852 | |||
853 | rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be); | ||
854 | if (rc) | ||
855 | return rc; | ||
856 | |||
857 | return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be); | ||
858 | } | ||
859 | |||
860 | static int | ||
861 | at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries) | ||
862 | { | ||
863 | struct at86rf230_local *lp = dev->priv; | ||
864 | int rc = 0; | ||
865 | |||
866 | if (retries < -1 || retries > 15) | ||
867 | return -EINVAL; | ||
868 | |||
869 | lp->tx_aret = retries >= 0; | ||
870 | |||
871 | if (retries >= 0) | ||
872 | rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries); | ||
873 | |||
874 | return rc; | ||
875 | } | ||
876 | |||
671 | static struct ieee802154_ops at86rf230_ops = { | 877 | static struct ieee802154_ops at86rf230_ops = { |
672 | .owner = THIS_MODULE, | 878 | .owner = THIS_MODULE, |
673 | .xmit = at86rf230_xmit, | 879 | .xmit = at86rf230_xmit, |
@@ -678,6 +884,22 @@ static struct ieee802154_ops at86rf230_ops = { | |||
678 | .set_hw_addr_filt = at86rf230_set_hw_addr_filt, | 884 | .set_hw_addr_filt = at86rf230_set_hw_addr_filt, |
679 | }; | 885 | }; |
680 | 886 | ||
887 | static struct ieee802154_ops at86rf212_ops = { | ||
888 | .owner = THIS_MODULE, | ||
889 | .xmit = at86rf230_xmit, | ||
890 | .ed = at86rf230_ed, | ||
891 | .set_channel = at86rf230_channel, | ||
892 | .start = at86rf230_start, | ||
893 | .stop = at86rf230_stop, | ||
894 | .set_hw_addr_filt = at86rf230_set_hw_addr_filt, | ||
895 | .set_txpower = at86rf212_set_txpower, | ||
896 | .set_lbt = at86rf212_set_lbt, | ||
897 | .set_cca_mode = at86rf212_set_cca_mode, | ||
898 | .set_cca_ed_level = at86rf212_set_cca_ed_level, | ||
899 | .set_csma_params = at86rf212_set_csma_params, | ||
900 | .set_frame_retries = at86rf212_set_frame_retries, | ||
901 | }; | ||
902 | |||
681 | static void at86rf230_irqwork(struct work_struct *work) | 903 | static void at86rf230_irqwork(struct work_struct *work) |
682 | { | 904 | { |
683 | struct at86rf230_local *lp = | 905 | struct at86rf230_local *lp = |
@@ -752,22 +974,15 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) | |||
752 | struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; | 974 | struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; |
753 | int rc, irq_pol; | 975 | int rc, irq_pol; |
754 | u8 status; | 976 | u8 status; |
977 | u8 csma_seed[2]; | ||
755 | 978 | ||
756 | rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); | 979 | rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); |
757 | if (rc) | 980 | if (rc) |
758 | return rc; | 981 | return rc; |
759 | 982 | ||
760 | dev_info(&lp->spi->dev, "Status: %02x\n", status); | 983 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF); |
761 | if (status == STATE_P_ON) { | 984 | if (rc) |
762 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF); | 985 | return rc; |
763 | if (rc) | ||
764 | return rc; | ||
765 | msleep(1); | ||
766 | rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); | ||
767 | if (rc) | ||
768 | return rc; | ||
769 | dev_info(&lp->spi->dev, "Status: %02x\n", status); | ||
770 | } | ||
771 | 986 | ||
772 | /* configure irq polarity, defaults to high active */ | 987 | /* configure irq polarity, defaults to high active */ |
773 | if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) | 988 | if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) |
@@ -783,6 +998,14 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) | |||
783 | if (rc) | 998 | if (rc) |
784 | return rc; | 999 | return rc; |
785 | 1000 | ||
1001 | get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed)); | ||
1002 | rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]); | ||
1003 | if (rc) | ||
1004 | return rc; | ||
1005 | rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]); | ||
1006 | if (rc) | ||
1007 | return rc; | ||
1008 | |||
786 | /* CLKM changes are applied immediately */ | 1009 | /* CLKM changes are applied immediately */ |
787 | rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); | 1010 | rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); |
788 | if (rc) | 1011 | if (rc) |
@@ -795,16 +1018,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) | |||
795 | /* Wait the next SLEEP cycle */ | 1018 | /* Wait the next SLEEP cycle */ |
796 | msleep(100); | 1019 | msleep(100); |
797 | 1020 | ||
798 | rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON); | ||
799 | if (rc) | ||
800 | return rc; | ||
801 | msleep(1); | ||
802 | |||
803 | rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); | ||
804 | if (rc) | ||
805 | return rc; | ||
806 | dev_info(&lp->spi->dev, "Status: %02x\n", status); | ||
807 | |||
808 | rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status); | 1021 | rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status); |
809 | if (rc) | 1022 | if (rc) |
810 | return rc; | 1023 | return rc; |
@@ -824,26 +1037,18 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) | |||
824 | return 0; | 1037 | return 0; |
825 | } | 1038 | } |
826 | 1039 | ||
827 | static void at86rf230_fill_data(struct spi_device *spi) | ||
828 | { | ||
829 | struct at86rf230_local *lp = spi_get_drvdata(spi); | ||
830 | struct at86rf230_platform_data *pdata = spi->dev.platform_data; | ||
831 | |||
832 | lp->rstn = pdata->rstn; | ||
833 | lp->slp_tr = pdata->slp_tr; | ||
834 | lp->dig2 = pdata->dig2; | ||
835 | } | ||
836 | |||
837 | static int at86rf230_probe(struct spi_device *spi) | 1040 | static int at86rf230_probe(struct spi_device *spi) |
838 | { | 1041 | { |
839 | struct at86rf230_platform_data *pdata; | 1042 | struct at86rf230_platform_data *pdata; |
840 | struct ieee802154_dev *dev; | 1043 | struct ieee802154_dev *dev; |
841 | struct at86rf230_local *lp; | 1044 | struct at86rf230_local *lp; |
842 | u8 man_id_0, man_id_1, status; | 1045 | u16 man_id = 0; |
1046 | u8 part = 0, version = 0, status; | ||
843 | irq_handler_t irq_handler; | 1047 | irq_handler_t irq_handler; |
844 | work_func_t irq_worker; | 1048 | work_func_t irq_worker; |
845 | int rc, supported = 0; | 1049 | int rc; |
846 | const char *chip; | 1050 | const char *chip; |
1051 | struct ieee802154_ops *ops = NULL; | ||
847 | 1052 | ||
848 | if (!spi->irq) { | 1053 | if (!spi->irq) { |
849 | dev_err(&spi->dev, "no IRQ specified\n"); | 1054 | dev_err(&spi->dev, "no IRQ specified\n"); |
@@ -856,116 +1061,117 @@ static int at86rf230_probe(struct spi_device *spi) | |||
856 | return -EINVAL; | 1061 | return -EINVAL; |
857 | } | 1062 | } |
858 | 1063 | ||
859 | dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops); | 1064 | rc = gpio_request(pdata->rstn, "rstn"); |
860 | if (!dev) | ||
861 | return -ENOMEM; | ||
862 | |||
863 | lp = dev->priv; | ||
864 | lp->dev = dev; | ||
865 | |||
866 | lp->spi = spi; | ||
867 | |||
868 | dev->parent = &spi->dev; | ||
869 | dev->extra_tx_headroom = 0; | ||
870 | /* We do support only 2.4 Ghz */ | ||
871 | dev->phy->channels_supported[0] = 0x7FFF800; | ||
872 | dev->flags = IEEE802154_HW_OMIT_CKSUM; | ||
873 | |||
874 | if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { | ||
875 | irq_worker = at86rf230_irqwork; | ||
876 | irq_handler = at86rf230_isr; | ||
877 | } else { | ||
878 | irq_worker = at86rf230_irqwork_level; | ||
879 | irq_handler = at86rf230_isr_level; | ||
880 | } | ||
881 | |||
882 | mutex_init(&lp->bmux); | ||
883 | INIT_WORK(&lp->irqwork, irq_worker); | ||
884 | spin_lock_init(&lp->lock); | ||
885 | init_completion(&lp->tx_complete); | ||
886 | |||
887 | spi_set_drvdata(spi, lp); | ||
888 | |||
889 | at86rf230_fill_data(spi); | ||
890 | |||
891 | rc = gpio_request(lp->rstn, "rstn"); | ||
892 | if (rc) | 1065 | if (rc) |
893 | goto err_rstn; | 1066 | return rc; |
894 | 1067 | ||
895 | if (gpio_is_valid(lp->slp_tr)) { | 1068 | if (gpio_is_valid(pdata->slp_tr)) { |
896 | rc = gpio_request(lp->slp_tr, "slp_tr"); | 1069 | rc = gpio_request(pdata->slp_tr, "slp_tr"); |
897 | if (rc) | 1070 | if (rc) |
898 | goto err_slp_tr; | 1071 | goto err_slp_tr; |
899 | } | 1072 | } |
900 | 1073 | ||
901 | rc = gpio_direction_output(lp->rstn, 1); | 1074 | rc = gpio_direction_output(pdata->rstn, 1); |
902 | if (rc) | 1075 | if (rc) |
903 | goto err_gpio_dir; | 1076 | goto err_gpio_dir; |
904 | 1077 | ||
905 | if (gpio_is_valid(lp->slp_tr)) { | 1078 | if (gpio_is_valid(pdata->slp_tr)) { |
906 | rc = gpio_direction_output(lp->slp_tr, 0); | 1079 | rc = gpio_direction_output(pdata->slp_tr, 0); |
907 | if (rc) | 1080 | if (rc) |
908 | goto err_gpio_dir; | 1081 | goto err_gpio_dir; |
909 | } | 1082 | } |
910 | 1083 | ||
911 | /* Reset */ | 1084 | /* Reset */ |
912 | msleep(1); | 1085 | msleep(1); |
913 | gpio_set_value(lp->rstn, 0); | 1086 | gpio_set_value(pdata->rstn, 0); |
914 | msleep(1); | 1087 | msleep(1); |
915 | gpio_set_value(lp->rstn, 1); | 1088 | gpio_set_value(pdata->rstn, 1); |
916 | msleep(1); | 1089 | msleep(1); |
917 | 1090 | ||
918 | rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0); | 1091 | rc = __at86rf230_detect_device(spi, &man_id, &part, &version); |
919 | if (rc) | 1092 | if (rc < 0) |
920 | goto err_gpio_dir; | ||
921 | rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1); | ||
922 | if (rc) | ||
923 | goto err_gpio_dir; | 1093 | goto err_gpio_dir; |
924 | 1094 | ||
925 | if (man_id_1 != 0x00 || man_id_0 != 0x1f) { | 1095 | if (man_id != 0x001f) { |
926 | dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", | 1096 | dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", |
927 | man_id_1, man_id_0); | 1097 | man_id >> 8, man_id & 0xFF); |
928 | rc = -EINVAL; | 1098 | rc = -EINVAL; |
929 | goto err_gpio_dir; | 1099 | goto err_gpio_dir; |
930 | } | 1100 | } |
931 | 1101 | ||
932 | rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part); | 1102 | switch (part) { |
933 | if (rc) | ||
934 | goto err_gpio_dir; | ||
935 | |||
936 | rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers); | ||
937 | if (rc) | ||
938 | goto err_gpio_dir; | ||
939 | |||
940 | switch (lp->part) { | ||
941 | case 2: | 1103 | case 2: |
942 | chip = "at86rf230"; | 1104 | chip = "at86rf230"; |
943 | /* supported = 1; FIXME: should be easy to support; */ | 1105 | /* FIXME: should be easy to support; */ |
944 | break; | 1106 | break; |
945 | case 3: | 1107 | case 3: |
946 | chip = "at86rf231"; | 1108 | chip = "at86rf231"; |
947 | supported = 1; | 1109 | ops = &at86rf230_ops; |
1110 | break; | ||
1111 | case 7: | ||
1112 | chip = "at86rf212"; | ||
1113 | if (version == 1) | ||
1114 | ops = &at86rf212_ops; | ||
948 | break; | 1115 | break; |
949 | default: | 1116 | default: |
950 | chip = "UNKNOWN"; | 1117 | chip = "UNKNOWN"; |
951 | break; | 1118 | break; |
952 | } | 1119 | } |
953 | 1120 | ||
954 | dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers); | 1121 | dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version); |
955 | if (!supported) { | 1122 | if (!ops) { |
956 | rc = -ENOTSUPP; | 1123 | rc = -ENOTSUPP; |
957 | goto err_gpio_dir; | 1124 | goto err_gpio_dir; |
958 | } | 1125 | } |
959 | 1126 | ||
1127 | dev = ieee802154_alloc_device(sizeof(*lp), ops); | ||
1128 | if (!dev) { | ||
1129 | rc = -ENOMEM; | ||
1130 | goto err_gpio_dir; | ||
1131 | } | ||
1132 | |||
1133 | lp = dev->priv; | ||
1134 | lp->dev = dev; | ||
1135 | lp->part = part; | ||
1136 | lp->vers = version; | ||
1137 | |||
1138 | lp->spi = spi; | ||
1139 | |||
1140 | dev->parent = &spi->dev; | ||
1141 | dev->extra_tx_headroom = 0; | ||
1142 | dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK; | ||
1143 | |||
1144 | if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { | ||
1145 | irq_worker = at86rf230_irqwork; | ||
1146 | irq_handler = at86rf230_isr; | ||
1147 | } else { | ||
1148 | irq_worker = at86rf230_irqwork_level; | ||
1149 | irq_handler = at86rf230_isr_level; | ||
1150 | } | ||
1151 | |||
1152 | mutex_init(&lp->bmux); | ||
1153 | INIT_WORK(&lp->irqwork, irq_worker); | ||
1154 | spin_lock_init(&lp->lock); | ||
1155 | init_completion(&lp->tx_complete); | ||
1156 | |||
1157 | spi_set_drvdata(spi, lp); | ||
1158 | |||
1159 | if (is_rf212(lp)) { | ||
1160 | dev->phy->channels_supported[0] = 0x00007FF; | ||
1161 | dev->phy->channels_supported[2] = 0x00007FF; | ||
1162 | } else { | ||
1163 | dev->phy->channels_supported[0] = 0x7FFF800; | ||
1164 | } | ||
1165 | |||
960 | rc = at86rf230_hw_init(lp); | 1166 | rc = at86rf230_hw_init(lp); |
961 | if (rc) | 1167 | if (rc) |
962 | goto err_gpio_dir; | 1168 | goto err_hw_init; |
963 | 1169 | ||
964 | rc = request_irq(spi->irq, irq_handler, | 1170 | rc = request_irq(spi->irq, irq_handler, |
965 | IRQF_SHARED | pdata->irq_type, | 1171 | IRQF_SHARED | pdata->irq_type, |
966 | dev_name(&spi->dev), lp); | 1172 | dev_name(&spi->dev), lp); |
967 | if (rc) | 1173 | if (rc) |
968 | goto err_gpio_dir; | 1174 | goto err_hw_init; |
969 | 1175 | ||
970 | /* Read irq status register to reset irq line */ | 1176 | /* Read irq status register to reset irq line */ |
971 | rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); | 1177 | rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); |
@@ -980,30 +1186,33 @@ static int at86rf230_probe(struct spi_device *spi) | |||
980 | 1186 | ||
981 | err_irq: | 1187 | err_irq: |
982 | free_irq(spi->irq, lp); | 1188 | free_irq(spi->irq, lp); |
1189 | err_hw_init: | ||
983 | flush_work(&lp->irqwork); | 1190 | flush_work(&lp->irqwork); |
984 | err_gpio_dir: | 1191 | spi_set_drvdata(spi, NULL); |
985 | if (gpio_is_valid(lp->slp_tr)) | ||
986 | gpio_free(lp->slp_tr); | ||
987 | err_slp_tr: | ||
988 | gpio_free(lp->rstn); | ||
989 | err_rstn: | ||
990 | mutex_destroy(&lp->bmux); | 1192 | mutex_destroy(&lp->bmux); |
991 | ieee802154_free_device(lp->dev); | 1193 | ieee802154_free_device(lp->dev); |
1194 | |||
1195 | err_gpio_dir: | ||
1196 | if (gpio_is_valid(pdata->slp_tr)) | ||
1197 | gpio_free(pdata->slp_tr); | ||
1198 | err_slp_tr: | ||
1199 | gpio_free(pdata->rstn); | ||
992 | return rc; | 1200 | return rc; |
993 | } | 1201 | } |
994 | 1202 | ||
995 | static int at86rf230_remove(struct spi_device *spi) | 1203 | static int at86rf230_remove(struct spi_device *spi) |
996 | { | 1204 | { |
997 | struct at86rf230_local *lp = spi_get_drvdata(spi); | 1205 | struct at86rf230_local *lp = spi_get_drvdata(spi); |
1206 | struct at86rf230_platform_data *pdata = spi->dev.platform_data; | ||
998 | 1207 | ||
999 | ieee802154_unregister_device(lp->dev); | 1208 | ieee802154_unregister_device(lp->dev); |
1000 | 1209 | ||
1001 | free_irq(spi->irq, lp); | 1210 | free_irq(spi->irq, lp); |
1002 | flush_work(&lp->irqwork); | 1211 | flush_work(&lp->irqwork); |
1003 | 1212 | ||
1004 | if (gpio_is_valid(lp->slp_tr)) | 1213 | if (gpio_is_valid(pdata->slp_tr)) |
1005 | gpio_free(lp->slp_tr); | 1214 | gpio_free(pdata->slp_tr); |
1006 | gpio_free(lp->rstn); | 1215 | gpio_free(pdata->rstn); |
1007 | 1216 | ||
1008 | mutex_destroy(&lp->bmux); | 1217 | mutex_destroy(&lp->bmux); |
1009 | ieee802154_free_device(lp->dev); | 1218 | ieee802154_free_device(lp->dev); |
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index fd4f2d1cdf6c..e110b8c266f5 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h | |||
@@ -70,6 +70,16 @@ enum { | |||
70 | IEEE802154_ATTR_PHY_NAME, | 70 | IEEE802154_ATTR_PHY_NAME, |
71 | IEEE802154_ATTR_DEV_TYPE, | 71 | IEEE802154_ATTR_DEV_TYPE, |
72 | 72 | ||
73 | IEEE802154_ATTR_TXPOWER, | ||
74 | IEEE802154_ATTR_LBT_ENABLED, | ||
75 | IEEE802154_ATTR_CCA_MODE, | ||
76 | IEEE802154_ATTR_CCA_ED_LEVEL, | ||
77 | IEEE802154_ATTR_CSMA_RETRIES, | ||
78 | IEEE802154_ATTR_CSMA_MIN_BE, | ||
79 | IEEE802154_ATTR_CSMA_MAX_BE, | ||
80 | |||
81 | IEEE802154_ATTR_FRAME_RETRIES, | ||
82 | |||
73 | __IEEE802154_ATTR_MAX, | 83 | __IEEE802154_ATTR_MAX, |
74 | }; | 84 | }; |
75 | 85 | ||
@@ -122,6 +132,8 @@ enum { | |||
122 | IEEE802154_ADD_IFACE, | 132 | IEEE802154_ADD_IFACE, |
123 | IEEE802154_DEL_IFACE, | 133 | IEEE802154_DEL_IFACE, |
124 | 134 | ||
135 | IEEE802154_SET_PHYPARAMS, | ||
136 | |||
125 | __IEEE802154_CMD_MAX, | 137 | __IEEE802154_CMD_MAX, |
126 | }; | 138 | }; |
127 | 139 | ||
diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 807d6b7a943f..8ca3d04e7558 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h | |||
@@ -113,6 +113,32 @@ struct ieee802154_dev { | |||
113 | * Set radio for listening on specific address. | 113 | * Set radio for listening on specific address. |
114 | * Set the device for listening on specified address. | 114 | * Set the device for listening on specified address. |
115 | * Returns either zero, or negative errno. | 115 | * Returns either zero, or negative errno. |
116 | * | ||
117 | * set_txpower: | ||
118 | * Set radio transmit power in dB. Called with pib_lock held. | ||
119 | * Returns either zero, or negative errno. | ||
120 | * | ||
121 | * set_lbt | ||
122 | * Enables or disables listen before talk on the device. Called with | ||
123 | * pib_lock held. | ||
124 | * Returns either zero, or negative errno. | ||
125 | * | ||
126 | * set_cca_mode | ||
127 | * Sets the CCA mode used by the device. Called with pib_lock held. | ||
128 | * Returns either zero, or negative errno. | ||
129 | * | ||
130 | * set_cca_ed_level | ||
131 | * Sets the CCA energy detection threshold in dBm. Called with pib_lock | ||
132 | * held. | ||
133 | * Returns either zero, or negative errno. | ||
134 | * | ||
135 | * set_csma_params | ||
136 | * Sets the CSMA parameter set for the PHY. Called with pib_lock held. | ||
137 | * Returns either zero, or negative errno. | ||
138 | * | ||
139 | * set_frame_retries | ||
140 | * Sets the retransmission attempt limit. Called with pib_lock held. | ||
141 | * Returns either zero, or negative errno. | ||
116 | */ | 142 | */ |
117 | struct ieee802154_ops { | 143 | struct ieee802154_ops { |
118 | struct module *owner; | 144 | struct module *owner; |
@@ -129,6 +155,15 @@ struct ieee802154_ops { | |||
129 | unsigned long changed); | 155 | unsigned long changed); |
130 | int (*ieee_addr)(struct ieee802154_dev *dev, | 156 | int (*ieee_addr)(struct ieee802154_dev *dev, |
131 | u8 addr[IEEE802154_ADDR_LEN]); | 157 | u8 addr[IEEE802154_ADDR_LEN]); |
158 | int (*set_txpower)(struct ieee802154_dev *dev, int db); | ||
159 | int (*set_lbt)(struct ieee802154_dev *dev, bool on); | ||
160 | int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode); | ||
161 | int (*set_cca_ed_level)(struct ieee802154_dev *dev, | ||
162 | s32 level); | ||
163 | int (*set_csma_params)(struct ieee802154_dev *dev, | ||
164 | u8 min_be, u8 max_be, u8 retries); | ||
165 | int (*set_frame_retries)(struct ieee802154_dev *dev, | ||
166 | s8 retries); | ||
132 | }; | 167 | }; |
133 | 168 | ||
134 | /* Basic interface to register ieee802154 device */ | 169 | /* Basic interface to register ieee802154 device */ |
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h index b52bda8d13b1..10ab0fc6d4f7 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h | |||
@@ -37,15 +37,22 @@ struct wpan_phy { | |||
37 | struct mutex pib_lock; | 37 | struct mutex pib_lock; |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * This is a PIB according to 802.15.4-2006. | 40 | * This is a PIB according to 802.15.4-2011. |
41 | * We do not provide timing-related variables, as they | 41 | * We do not provide timing-related variables, as they |
42 | * aren't used outside of driver | 42 | * aren't used outside of driver |
43 | */ | 43 | */ |
44 | u8 current_channel; | 44 | u8 current_channel; |
45 | u8 current_page; | 45 | u8 current_page; |
46 | u32 channels_supported[32]; | 46 | u32 channels_supported[32]; |
47 | u8 transmit_power; | 47 | s8 transmit_power; |
48 | u8 cca_mode; | 48 | u8 cca_mode; |
49 | u8 min_be; | ||
50 | u8 max_be; | ||
51 | u8 csma_retries; | ||
52 | s8 frame_retries; | ||
53 | |||
54 | bool lbt; | ||
55 | s32 cca_ed_level; | ||
49 | 56 | ||
50 | struct device dev; | 57 | struct device dev; |
51 | int idx; | 58 | int idx; |
@@ -54,6 +61,14 @@ struct wpan_phy { | |||
54 | const char *name, int type); | 61 | const char *name, int type); |
55 | void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); | 62 | void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); |
56 | 63 | ||
64 | int (*set_txpower)(struct wpan_phy *phy, int db); | ||
65 | int (*set_lbt)(struct wpan_phy *phy, bool on); | ||
66 | int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode); | ||
67 | int (*set_cca_ed_level)(struct wpan_phy *phy, int level); | ||
68 | int (*set_csma_params)(struct wpan_phy *phy, u8 min_be, u8 max_be, | ||
69 | u8 retries); | ||
70 | int (*set_frame_retries)(struct wpan_phy *phy, s8 retries); | ||
71 | |||
57 | char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); | 72 | char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); |
58 | }; | 73 | }; |
59 | 74 | ||
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index cee4425b9956..6cbc8965be91 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h | |||
@@ -53,6 +53,7 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info); | |||
53 | int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb); | 53 | int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb); |
54 | int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info); | 54 | int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info); |
55 | int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info); | 55 | int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info); |
56 | int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info); | ||
56 | 57 | ||
57 | enum ieee802154_mcgrp_ids { | 58 | enum ieee802154_mcgrp_ids { |
58 | IEEE802154_COORD_MCGRP, | 59 | IEEE802154_COORD_MCGRP, |
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 43f1b2bf469f..67c151bf4b91 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c | |||
@@ -115,6 +115,7 @@ static const struct genl_ops ieee8021154_ops[] = { | |||
115 | ieee802154_dump_phy), | 115 | ieee802154_dump_phy), |
116 | IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), | 116 | IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), |
117 | IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), | 117 | IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), |
118 | IEEE802154_OP(IEEE802154_SET_PHYPARAMS, ieee802154_set_phyparams), | ||
118 | /* see nl-mac.c */ | 119 | /* see nl-mac.c */ |
119 | IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), | 120 | IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), |
120 | IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), | 121 | IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), |
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 89b265aea151..c9dfd6f59e34 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c | |||
@@ -55,7 +55,15 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, | |||
55 | mutex_lock(&phy->pib_lock); | 55 | mutex_lock(&phy->pib_lock); |
56 | if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || | 56 | if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || |
57 | nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || | 57 | nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || |
58 | nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel)) | 58 | nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) || |
59 | nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) || | ||
60 | nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) || | ||
61 | nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode) || | ||
62 | nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL, phy->cca_ed_level) || | ||
63 | nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES, phy->csma_retries) || | ||
64 | nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE, phy->min_be) || | ||
65 | nla_put_u8(msg, IEEE802154_ATTR_CSMA_MAX_BE, phy->max_be) || | ||
66 | nla_put_s8(msg, IEEE802154_ATTR_FRAME_RETRIES, phy->frame_retries)) | ||
59 | goto nla_put_failure; | 67 | goto nla_put_failure; |
60 | for (i = 0; i < 32; i++) { | 68 | for (i = 0; i < 32; i++) { |
61 | if (phy->channels_supported[i]) | 69 | if (phy->channels_supported[i]) |
@@ -354,3 +362,191 @@ out_dev: | |||
354 | 362 | ||
355 | return rc; | 363 | return rc; |
356 | } | 364 | } |
365 | |||
366 | static int phy_set_txpower(struct wpan_phy *phy, struct genl_info *info) | ||
367 | { | ||
368 | int txpower = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]); | ||
369 | int rc; | ||
370 | |||
371 | rc = phy->set_txpower(phy, txpower); | ||
372 | if (rc < 0) | ||
373 | return rc; | ||
374 | |||
375 | phy->transmit_power = txpower; | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int phy_set_lbt(struct wpan_phy *phy, struct genl_info *info) | ||
381 | { | ||
382 | u8 on = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]); | ||
383 | int rc; | ||
384 | |||
385 | rc = phy->set_lbt(phy, on); | ||
386 | if (rc < 0) | ||
387 | return rc; | ||
388 | |||
389 | phy->lbt = on; | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int phy_set_cca_mode(struct wpan_phy *phy, struct genl_info *info) | ||
395 | { | ||
396 | u8 mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]); | ||
397 | int rc; | ||
398 | |||
399 | if (mode > 3) | ||
400 | return -EINVAL; | ||
401 | |||
402 | rc = phy->set_cca_mode(phy, mode); | ||
403 | if (rc < 0) | ||
404 | return rc; | ||
405 | |||
406 | phy->cca_mode = mode; | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int phy_set_cca_ed_level(struct wpan_phy *phy, struct genl_info *info) | ||
412 | { | ||
413 | s32 level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]); | ||
414 | int rc; | ||
415 | |||
416 | rc = phy->set_cca_ed_level(phy, level); | ||
417 | if (rc < 0) | ||
418 | return rc; | ||
419 | |||
420 | phy->cca_ed_level = level; | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int phy_set_csma_params(struct wpan_phy *phy, struct genl_info *info) | ||
426 | { | ||
427 | int rc; | ||
428 | u8 min_be = phy->min_be; | ||
429 | u8 max_be = phy->max_be; | ||
430 | u8 retries = phy->csma_retries; | ||
431 | |||
432 | if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES]) | ||
433 | retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]); | ||
434 | if (info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]) | ||
435 | min_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]); | ||
436 | if (info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]) | ||
437 | max_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]); | ||
438 | |||
439 | if (retries > 5 || max_be > 8 || min_be > max_be || | ||
440 | retries < -1 || retries > 7) | ||
441 | return -EINVAL; | ||
442 | |||
443 | rc = phy->set_csma_params(phy, min_be, max_be, retries); | ||
444 | if (rc < 0) | ||
445 | return rc; | ||
446 | |||
447 | phy->min_be = min_be; | ||
448 | phy->max_be = max_be; | ||
449 | phy->csma_retries = retries; | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int phy_set_frame_retries(struct wpan_phy *phy, struct genl_info *info) | ||
455 | { | ||
456 | s8 retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]); | ||
457 | int rc; | ||
458 | |||
459 | rc = phy->set_frame_retries(phy, retries); | ||
460 | if (rc < 0) | ||
461 | return rc; | ||
462 | |||
463 | phy->frame_retries = retries; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info) | ||
469 | { | ||
470 | struct wpan_phy *phy; | ||
471 | const char *name; | ||
472 | int rc = -ENOTSUPP; | ||
473 | |||
474 | pr_debug("%s\n", __func__); | ||
475 | |||
476 | if (!info->attrs[IEEE802154_ATTR_PHY_NAME] && | ||
477 | !info->attrs[IEEE802154_ATTR_LBT_ENABLED] && | ||
478 | !info->attrs[IEEE802154_ATTR_CCA_MODE] && | ||
479 | !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] && | ||
480 | !info->attrs[IEEE802154_ATTR_CSMA_RETRIES] && | ||
481 | !info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] && | ||
482 | !info->attrs[IEEE802154_ATTR_CSMA_MAX_BE] && | ||
483 | !info->attrs[IEEE802154_ATTR_FRAME_RETRIES]) | ||
484 | return -EINVAL; | ||
485 | |||
486 | name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); | ||
487 | if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') | ||
488 | return -EINVAL; /* phy name should be null-terminated */ | ||
489 | |||
490 | phy = wpan_phy_find(name); | ||
491 | if (!phy) | ||
492 | return -ENODEV; | ||
493 | |||
494 | if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) || | ||
495 | (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) || | ||
496 | (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) || | ||
497 | (!phy->set_cca_ed_level && | ||
498 | info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL])) | ||
499 | goto out; | ||
500 | |||
501 | mutex_lock(&phy->pib_lock); | ||
502 | |||
503 | if (info->attrs[IEEE802154_ATTR_TXPOWER]) { | ||
504 | rc = phy_set_txpower(phy, info); | ||
505 | if (rc < 0) | ||
506 | goto error; | ||
507 | } | ||
508 | |||
509 | if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) { | ||
510 | rc = phy_set_lbt(phy, info); | ||
511 | if (rc < 0) | ||
512 | goto error; | ||
513 | } | ||
514 | |||
515 | if (info->attrs[IEEE802154_ATTR_CCA_MODE]) { | ||
516 | rc = phy_set_cca_mode(phy, info); | ||
517 | if (rc < 0) | ||
518 | goto error; | ||
519 | } | ||
520 | |||
521 | if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) { | ||
522 | rc = phy_set_cca_ed_level(phy, info); | ||
523 | if (rc < 0) | ||
524 | goto error; | ||
525 | } | ||
526 | |||
527 | if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] || | ||
528 | info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] || | ||
529 | info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]) { | ||
530 | rc = phy_set_csma_params(phy, info); | ||
531 | if (rc < 0) | ||
532 | goto error; | ||
533 | } | ||
534 | |||
535 | if (info->attrs[IEEE802154_ATTR_FRAME_RETRIES]) { | ||
536 | rc = phy_set_frame_retries(phy, info); | ||
537 | if (rc < 0) | ||
538 | goto error; | ||
539 | } | ||
540 | |||
541 | mutex_unlock(&phy->pib_lock); | ||
542 | |||
543 | wpan_phy_put(phy); | ||
544 | |||
545 | return 0; | ||
546 | |||
547 | error: | ||
548 | mutex_unlock(&phy->pib_lock); | ||
549 | out: | ||
550 | wpan_phy_put(phy); | ||
551 | return rc; | ||
552 | } | ||
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 6adda4d46f95..fd7be5e45cef 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c | |||
@@ -52,5 +52,15 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { | |||
52 | [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, | 52 | [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, |
53 | [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, | 53 | [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, |
54 | [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, }, | 54 | [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, }, |
55 | |||
56 | [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, }, | ||
57 | [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, }, | ||
58 | [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, | ||
59 | [IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, }, | ||
60 | [IEEE802154_ATTR_CSMA_RETRIES] = { .type = NLA_U8, }, | ||
61 | [IEEE802154_ATTR_CSMA_MIN_BE] = { .type = NLA_U8, }, | ||
62 | [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, }, | ||
63 | |||
64 | [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, }, | ||
55 | }; | 65 | }; |
56 | 66 | ||
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 4dd37615a749..edd0962d55f9 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c | |||
@@ -44,9 +44,7 @@ static DEVICE_ATTR_RO(name); | |||
44 | 44 | ||
45 | MASTER_SHOW(current_channel, "%d"); | 45 | MASTER_SHOW(current_channel, "%d"); |
46 | MASTER_SHOW(current_page, "%d"); | 46 | MASTER_SHOW(current_page, "%d"); |
47 | MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", | 47 | MASTER_SHOW(transmit_power, "%d +- 1 dB"); |
48 | ((signed char) (phy->transmit_power << 2)) >> 2, | ||
49 | (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1); | ||
50 | MASTER_SHOW(cca_mode, "%d"); | 48 | MASTER_SHOW(cca_mode, "%d"); |
51 | 49 | ||
52 | static ssize_t channels_supported_show(struct device *dev, | 50 | static ssize_t channels_supported_show(struct device *dev, |
@@ -171,6 +169,12 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) | |||
171 | phy->current_channel = -1; /* not initialised */ | 169 | phy->current_channel = -1; /* not initialised */ |
172 | phy->current_page = 0; /* for compatibility */ | 170 | phy->current_page = 0; /* for compatibility */ |
173 | 171 | ||
172 | /* defaults per 802.15.4-2011 */ | ||
173 | phy->min_be = 3; | ||
174 | phy->max_be = 5; | ||
175 | phy->csma_retries = 4; | ||
176 | phy->frame_retries = -1; /* for compatibility, actual default is 3 */ | ||
177 | |||
174 | return phy; | 178 | return phy; |
175 | 179 | ||
176 | out: | 180 | out: |
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index 52ae6646a411..b75bb01e5c6b 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c | |||
@@ -165,6 +165,67 @@ err: | |||
165 | return ERR_PTR(err); | 165 | return ERR_PTR(err); |
166 | } | 166 | } |
167 | 167 | ||
168 | static int mac802154_set_txpower(struct wpan_phy *phy, int db) | ||
169 | { | ||
170 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
171 | |||
172 | if (!priv->ops->set_txpower) | ||
173 | return -ENOTSUPP; | ||
174 | |||
175 | return priv->ops->set_txpower(&priv->hw, db); | ||
176 | } | ||
177 | |||
178 | static int mac802154_set_lbt(struct wpan_phy *phy, bool on) | ||
179 | { | ||
180 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
181 | |||
182 | if (!priv->ops->set_lbt) | ||
183 | return -ENOTSUPP; | ||
184 | |||
185 | return priv->ops->set_lbt(&priv->hw, on); | ||
186 | } | ||
187 | |||
188 | static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode) | ||
189 | { | ||
190 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
191 | |||
192 | if (!priv->ops->set_cca_mode) | ||
193 | return -ENOTSUPP; | ||
194 | |||
195 | return priv->ops->set_cca_mode(&priv->hw, mode); | ||
196 | } | ||
197 | |||
198 | static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level) | ||
199 | { | ||
200 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
201 | |||
202 | if (!priv->ops->set_cca_ed_level) | ||
203 | return -ENOTSUPP; | ||
204 | |||
205 | return priv->ops->set_cca_ed_level(&priv->hw, level); | ||
206 | } | ||
207 | |||
208 | static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be, | ||
209 | u8 max_be, u8 retries) | ||
210 | { | ||
211 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
212 | |||
213 | if (!priv->ops->set_csma_params) | ||
214 | return -ENOTSUPP; | ||
215 | |||
216 | return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries); | ||
217 | } | ||
218 | |||
219 | static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries) | ||
220 | { | ||
221 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
222 | |||
223 | if (!priv->ops->set_frame_retries) | ||
224 | return -ENOTSUPP; | ||
225 | |||
226 | return priv->ops->set_frame_retries(&priv->hw, retries); | ||
227 | } | ||
228 | |||
168 | struct ieee802154_dev * | 229 | struct ieee802154_dev * |
169 | ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) | 230 | ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) |
170 | { | 231 | { |
@@ -242,6 +303,12 @@ int ieee802154_register_device(struct ieee802154_dev *dev) | |||
242 | 303 | ||
243 | priv->phy->add_iface = mac802154_add_iface; | 304 | priv->phy->add_iface = mac802154_add_iface; |
244 | priv->phy->del_iface = mac802154_del_iface; | 305 | priv->phy->del_iface = mac802154_del_iface; |
306 | priv->phy->set_txpower = mac802154_set_txpower; | ||
307 | priv->phy->set_lbt = mac802154_set_lbt; | ||
308 | priv->phy->set_cca_mode = mac802154_set_cca_mode; | ||
309 | priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; | ||
310 | priv->phy->set_csma_params = mac802154_set_csma_params; | ||
311 | priv->phy->set_frame_retries = mac802154_set_frame_retries; | ||
245 | 312 | ||
246 | rc = wpan_phy_register(priv->phy); | 313 | rc = wpan_phy_register(priv->phy); |
247 | if (rc < 0) | 314 | if (rc < 0) |