2 * Copyright (C) 2007-2012 Siemens AG
5 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
7 * Based on the code from 'linux-zigbee.sourceforge.net' project.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/netdevice.h>
27 #include <net/netlink.h>
28 #include <linux/nl802154.h>
29 #include <net/mac802154.h>
30 #include <net/route.h>
31 #include <net/wpan-phy.h>
33 #include "mac802154.h"
35 int mac802154_slave_open(struct net_device
*dev
)
37 struct mac802154_sub_if_data
*priv
= netdev_priv(dev
);
38 struct mac802154_priv
*ipriv
= priv
->hw
;
41 if (ipriv
->open_count
++ == 0) {
42 res
= ipriv
->ops
->start(&ipriv
->hw
);
48 if (ipriv
->ops
->ieee_addr
) {
49 res
= ipriv
->ops
->ieee_addr(&ipriv
->hw
, dev
->dev_addr
);
53 mac802154_dev_set_ieee_addr(dev
);
56 netif_start_queue(dev
);
59 priv
->hw
->open_count
--;
64 int mac802154_slave_close(struct net_device
*dev
)
66 struct mac802154_sub_if_data
*priv
= netdev_priv(dev
);
67 struct mac802154_priv
*ipriv
= priv
->hw
;
69 netif_stop_queue(dev
);
71 if (!--ipriv
->open_count
)
72 ipriv
->ops
->stop(&ipriv
->hw
);
78 mac802154_netdev_register(struct wpan_phy
*phy
, struct net_device
*dev
)
80 struct mac802154_sub_if_data
*priv
;
81 struct mac802154_priv
*ipriv
;
84 ipriv
= wpan_phy_priv(phy
);
86 priv
= netdev_priv(dev
);
90 dev
->needed_headroom
= ipriv
->hw
.extra_tx_headroom
;
92 SET_NETDEV_DEV(dev
, &ipriv
->phy
->dev
);
94 mutex_lock(&ipriv
->slaves_mtx
);
95 if (!ipriv
->running
) {
96 mutex_unlock(&ipriv
->slaves_mtx
);
99 mutex_unlock(&ipriv
->slaves_mtx
);
101 err
= register_netdev(dev
);
106 mutex_lock(&ipriv
->slaves_mtx
);
107 list_add_tail_rcu(&priv
->list
, &ipriv
->slaves
);
108 mutex_unlock(&ipriv
->slaves_mtx
);
115 mac802154_del_iface(struct wpan_phy
*phy
, struct net_device
*dev
)
117 struct mac802154_sub_if_data
*sdata
;
120 sdata
= netdev_priv(dev
);
122 BUG_ON(sdata
->hw
->phy
!= phy
);
124 mutex_lock(&sdata
->hw
->slaves_mtx
);
125 list_del_rcu(&sdata
->list
);
126 mutex_unlock(&sdata
->hw
->slaves_mtx
);
129 unregister_netdevice(sdata
->dev
);
132 static struct net_device
*
133 mac802154_add_iface(struct wpan_phy
*phy
, const char *name
, int type
)
135 struct net_device
*dev
;
139 case IEEE802154_DEV_MONITOR
:
140 dev
= alloc_netdev(sizeof(struct mac802154_sub_if_data
),
141 name
, mac802154_monitor_setup
);
143 case IEEE802154_DEV_WPAN
:
144 dev
= alloc_netdev(sizeof(struct mac802154_sub_if_data
),
145 name
, mac802154_wpan_setup
);
155 err
= mac802154_netdev_register(phy
, dev
);
159 dev_hold(dev
); /* we return an incremented device refcount */
168 struct ieee802154_dev
*
169 ieee802154_alloc_device(size_t priv_data_len
, struct ieee802154_ops
*ops
)
171 struct wpan_phy
*phy
;
172 struct mac802154_priv
*priv
;
175 if (!ops
|| !ops
->xmit
|| !ops
->ed
|| !ops
->start
||
176 !ops
->stop
|| !ops
->set_channel
) {
178 "undefined IEEE802.15.4 device operations\n");
182 /* Ensure 32-byte alignment of our private data and hw private data.
183 * We use the wpan_phy priv data for both our mac802154_priv and for
184 * the driver's private data
186 * in memory it'll be like this:
188 * +-----------------------+
189 * | struct wpan_phy |
190 * +-----------------------+
191 * | struct mac802154_priv |
192 * +-----------------------+
193 * | driver's private data |
194 * +-----------------------+
196 * Due to ieee802154 layer isn't aware of driver and MAC structures,
197 * so lets allign them here.
200 priv_size
= ALIGN(sizeof(*priv
), NETDEV_ALIGN
) + priv_data_len
;
202 phy
= wpan_phy_alloc(priv_size
);
205 "failure to allocate master IEEE802.15.4 device\n");
209 priv
= wpan_phy_priv(phy
);
210 priv
->hw
.phy
= priv
->phy
= phy
;
211 priv
->hw
.priv
= (char *)priv
+ ALIGN(sizeof(*priv
), NETDEV_ALIGN
);
214 INIT_LIST_HEAD(&priv
->slaves
);
215 mutex_init(&priv
->slaves_mtx
);
219 EXPORT_SYMBOL(ieee802154_alloc_device
);
221 void ieee802154_free_device(struct ieee802154_dev
*hw
)
223 struct mac802154_priv
*priv
= mac802154_to_priv(hw
);
225 BUG_ON(!list_empty(&priv
->slaves
));
227 wpan_phy_free(priv
->phy
);
229 mutex_destroy(&priv
->slaves_mtx
);
231 EXPORT_SYMBOL(ieee802154_free_device
);
233 int ieee802154_register_device(struct ieee802154_dev
*dev
)
235 struct mac802154_priv
*priv
= mac802154_to_priv(dev
);
238 priv
->dev_workqueue
=
239 create_singlethread_workqueue(wpan_phy_name(priv
->phy
));
240 if (!priv
->dev_workqueue
)
243 wpan_phy_set_dev(priv
->phy
, priv
->hw
.parent
);
245 priv
->phy
->add_iface
= mac802154_add_iface
;
246 priv
->phy
->del_iface
= mac802154_del_iface
;
248 rc
= wpan_phy_register(priv
->phy
);
254 mutex_lock(&priv
->slaves_mtx
);
255 priv
->running
= MAC802154_DEVICE_RUN
;
256 mutex_unlock(&priv
->slaves_mtx
);
263 destroy_workqueue(priv
->dev_workqueue
);
267 EXPORT_SYMBOL(ieee802154_register_device
);
269 void ieee802154_unregister_device(struct ieee802154_dev
*dev
)
271 struct mac802154_priv
*priv
= mac802154_to_priv(dev
);
272 struct mac802154_sub_if_data
*sdata
, *next
;
274 flush_workqueue(priv
->dev_workqueue
);
275 destroy_workqueue(priv
->dev_workqueue
);
279 mutex_lock(&priv
->slaves_mtx
);
280 priv
->running
= MAC802154_DEVICE_STOPPED
;
281 mutex_unlock(&priv
->slaves_mtx
);
283 list_for_each_entry_safe(sdata
, next
, &priv
->slaves
, list
) {
284 mutex_lock(&sdata
->hw
->slaves_mtx
);
285 list_del(&sdata
->list
);
286 mutex_unlock(&sdata
->hw
->slaves_mtx
);
288 unregister_netdevice(sdata
->dev
);
293 wpan_phy_unregister(priv
->phy
);
295 EXPORT_SYMBOL(ieee802154_unregister_device
);
297 MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
298 MODULE_LICENSE("GPL v2");