xref: /openbmc/linux/drivers/net/ieee802154/fakelb.c (revision db3f5d0df9af1e5965e64595595a6a719c42fcf3)
1 /*
2  * Loopback IEEE 802.15.4 interface
3  *
4  * Copyright 2007-2012 Siemens AG
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * Written by:
16  * Sergey Lapin <slapin@ossfans.org>
17  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
18  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
19  */
20 
21 #include <linux/module.h>
22 #include <linux/timer.h>
23 #include <linux/platform_device.h>
24 #include <linux/netdevice.h>
25 #include <linux/device.h>
26 #include <linux/spinlock.h>
27 #include <net/mac802154.h>
28 #include <net/cfg802154.h>
29 
30 static int numlbs = 2;
31 
32 struct fakelb_phy {
33 	struct ieee802154_hw *hw;
34 
35 	struct list_head list;
36 	struct fakelb_priv *fake;
37 
38 	spinlock_t lock;
39 	bool working;
40 };
41 
42 struct fakelb_priv {
43 	struct list_head list;
44 	rwlock_t lock;
45 };
46 
47 static int
48 fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
49 {
50 	BUG_ON(!level);
51 	*level = 0xbe;
52 
53 	return 0;
54 }
55 
56 static int
57 fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
58 {
59 	pr_debug("set channel to %d\n", channel);
60 
61 	return 0;
62 }
63 
64 static void
65 fakelb_hw_deliver(struct fakelb_phy *phy, struct sk_buff *skb)
66 {
67 	struct sk_buff *newskb;
68 
69 	spin_lock(&phy->lock);
70 	if (phy->working) {
71 		newskb = pskb_copy(skb, GFP_ATOMIC);
72 		if (newskb)
73 			ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc);
74 	}
75 	spin_unlock(&phy->lock);
76 }
77 
78 static int
79 fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
80 {
81 	struct fakelb_phy *current_phy = hw->priv;
82 	struct fakelb_priv *fake = current_phy->fake;
83 
84 	read_lock_bh(&fake->lock);
85 	if (current_phy->list.next == current_phy->list.prev) {
86 		/* we are the only one device */
87 		fakelb_hw_deliver(current_phy, skb);
88 	} else {
89 		struct fakelb_phy *phy;
90 
91 		list_for_each_entry(phy, &current_phy->fake->list, list) {
92 			if (current_phy != phy &&
93 			    (phy->hw->phy->current_channel ==
94 			     current_phy->hw->phy->current_channel))
95 				fakelb_hw_deliver(phy, skb);
96 		}
97 	}
98 	read_unlock_bh(&fake->lock);
99 
100 	return 0;
101 }
102 
103 static int
104 fakelb_hw_start(struct ieee802154_hw *hw) {
105 	struct fakelb_phy *phy = hw->priv;
106 	int ret = 0;
107 
108 	spin_lock(&phy->lock);
109 	if (phy->working)
110 		ret = -EBUSY;
111 	else
112 		phy->working = 1;
113 	spin_unlock(&phy->lock);
114 
115 	return ret;
116 }
117 
118 static void
119 fakelb_hw_stop(struct ieee802154_hw *hw) {
120 	struct fakelb_phy *phy = hw->priv;
121 
122 	spin_lock(&phy->lock);
123 	phy->working = 0;
124 	spin_unlock(&phy->lock);
125 }
126 
127 static const struct ieee802154_ops fakelb_ops = {
128 	.owner = THIS_MODULE,
129 	.xmit_sync = fakelb_hw_xmit,
130 	.ed = fakelb_hw_ed,
131 	.set_channel = fakelb_hw_channel,
132 	.start = fakelb_hw_start,
133 	.stop = fakelb_hw_stop,
134 };
135 
136 /* Number of dummy devices to be set up by this module. */
137 module_param(numlbs, int, 0);
138 MODULE_PARM_DESC(numlbs, " number of pseudo devices");
139 
140 static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
141 {
142 	struct fakelb_phy *phy;
143 	int err;
144 	struct ieee802154_hw *hw;
145 
146 	hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops);
147 	if (!hw)
148 		return -ENOMEM;
149 
150 	phy = hw->priv;
151 	phy->hw = hw;
152 
153 	/* 868 MHz BPSK	802.15.4-2003 */
154 	hw->phy->supported.channels[0] |= 1;
155 	/* 915 MHz BPSK	802.15.4-2003 */
156 	hw->phy->supported.channels[0] |= 0x7fe;
157 	/* 2.4 GHz O-QPSK 802.15.4-2003 */
158 	hw->phy->supported.channels[0] |= 0x7FFF800;
159 	/* 868 MHz ASK 802.15.4-2006 */
160 	hw->phy->supported.channels[1] |= 1;
161 	/* 915 MHz ASK 802.15.4-2006 */
162 	hw->phy->supported.channels[1] |= 0x7fe;
163 	/* 868 MHz O-QPSK 802.15.4-2006 */
164 	hw->phy->supported.channels[2] |= 1;
165 	/* 915 MHz O-QPSK 802.15.4-2006 */
166 	hw->phy->supported.channels[2] |= 0x7fe;
167 	/* 2.4 GHz CSS 802.15.4a-2007 */
168 	hw->phy->supported.channels[3] |= 0x3fff;
169 	/* UWB Sub-gigahertz 802.15.4a-2007 */
170 	hw->phy->supported.channels[4] |= 1;
171 	/* UWB Low band 802.15.4a-2007 */
172 	hw->phy->supported.channels[4] |= 0x1e;
173 	/* UWB High band 802.15.4a-2007 */
174 	hw->phy->supported.channels[4] |= 0xffe0;
175 	/* 750 MHz O-QPSK 802.15.4c-2009 */
176 	hw->phy->supported.channels[5] |= 0xf;
177 	/* 750 MHz MPSK 802.15.4c-2009 */
178 	hw->phy->supported.channels[5] |= 0xf0;
179 	/* 950 MHz BPSK 802.15.4d-2009 */
180 	hw->phy->supported.channels[6] |= 0x3ff;
181 	/* 950 MHz GFSK 802.15.4d-2009 */
182 	hw->phy->supported.channels[6] |= 0x3ffc00;
183 
184 	INIT_LIST_HEAD(&phy->list);
185 	phy->fake = fake;
186 
187 	spin_lock_init(&phy->lock);
188 
189 	hw->parent = dev;
190 
191 	err = ieee802154_register_hw(hw);
192 	if (err)
193 		goto err_reg;
194 
195 	write_lock_bh(&fake->lock);
196 	list_add_tail(&phy->list, &fake->list);
197 	write_unlock_bh(&fake->lock);
198 
199 	return 0;
200 
201 err_reg:
202 	ieee802154_free_hw(phy->hw);
203 	return err;
204 }
205 
206 static void fakelb_del(struct fakelb_phy *phy)
207 {
208 	write_lock_bh(&phy->fake->lock);
209 	list_del(&phy->list);
210 	write_unlock_bh(&phy->fake->lock);
211 
212 	ieee802154_unregister_hw(phy->hw);
213 	ieee802154_free_hw(phy->hw);
214 }
215 
216 static int fakelb_probe(struct platform_device *pdev)
217 {
218 	struct fakelb_priv *priv;
219 	struct fakelb_phy *phy, *tmp;
220 	int err = -ENOMEM;
221 	int i;
222 
223 	priv = devm_kzalloc(&pdev->dev, sizeof(struct fakelb_priv),
224 			    GFP_KERNEL);
225 	if (!priv)
226 		goto err_alloc;
227 
228 	INIT_LIST_HEAD(&priv->list);
229 	rwlock_init(&priv->lock);
230 
231 	for (i = 0; i < numlbs; i++) {
232 		err = fakelb_add_one(&pdev->dev, priv);
233 		if (err < 0)
234 			goto err_slave;
235 	}
236 
237 	platform_set_drvdata(pdev, priv);
238 	dev_info(&pdev->dev, "added ieee802154 hardware\n");
239 	return 0;
240 
241 err_slave:
242 	list_for_each_entry_safe(phy, tmp, &priv->list, list)
243 		fakelb_del(phy);
244 err_alloc:
245 	return err;
246 }
247 
248 static int fakelb_remove(struct platform_device *pdev)
249 {
250 	struct fakelb_priv *priv = platform_get_drvdata(pdev);
251 	struct fakelb_phy *phy, *temp;
252 
253 	list_for_each_entry_safe(phy, temp, &priv->list, list)
254 		fakelb_del(phy);
255 
256 	return 0;
257 }
258 
259 static struct platform_device *ieee802154fake_dev;
260 
261 static struct platform_driver ieee802154fake_driver = {
262 	.probe = fakelb_probe,
263 	.remove = fakelb_remove,
264 	.driver = {
265 			.name = "ieee802154fakelb",
266 	},
267 };
268 
269 static __init int fakelb_init_module(void)
270 {
271 	ieee802154fake_dev = platform_device_register_simple(
272 			     "ieee802154fakelb", -1, NULL, 0);
273 	return platform_driver_register(&ieee802154fake_driver);
274 }
275 
276 static __exit void fake_remove_module(void)
277 {
278 	platform_driver_unregister(&ieee802154fake_driver);
279 	platform_device_unregister(ieee802154fake_dev);
280 }
281 
282 module_init(fakelb_init_module);
283 module_exit(fake_remove_module);
284 MODULE_LICENSE("GPL");
285