1010f540 |
1 | /* |
2 | * Copyright (C) 2007-2012 Siemens AG |
3 | * |
4 | * Written by: |
5 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> |
6 | * |
7 | * Based on the code from 'linux-zigbee.sourceforge.net' project. |
8 | * |
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. |
12 | * |
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. |
17 | * |
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. |
21 | */ |
22 | |
23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> |
25 | #include <linux/netdevice.h> |
26 | |
27 | #include <net/mac802154.h> |
28 | #include <net/route.h> |
29 | #include <net/wpan-phy.h> |
30 | |
31 | #include "mac802154.h" |
32 | |
33 | struct ieee802154_dev * |
34 | ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) |
35 | { |
36 | struct wpan_phy *phy; |
37 | struct mac802154_priv *priv; |
38 | size_t priv_size; |
39 | |
40 | if (!ops || !ops->xmit || !ops->ed || !ops->start || |
41 | !ops->stop || !ops->set_channel) { |
42 | printk(KERN_ERR |
43 | "undefined IEEE802.15.4 device operations\n"); |
44 | return NULL; |
45 | } |
46 | |
47 | /* Ensure 32-byte alignment of our private data and hw private data. |
48 | * We use the wpan_phy priv data for both our mac802154_priv and for |
49 | * the driver's private data |
50 | * |
51 | * in memory it'll be like this: |
52 | * |
53 | * +-----------------------+ |
54 | * | struct wpan_phy | |
55 | * +-----------------------+ |
56 | * | struct mac802154_priv | |
57 | * +-----------------------+ |
58 | * | driver's private data | |
59 | * +-----------------------+ |
60 | * |
61 | * Due to ieee802154 layer isn't aware of driver and MAC structures, |
62 | * so lets allign them here. |
63 | */ |
64 | |
65 | priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_data_len; |
66 | |
67 | phy = wpan_phy_alloc(priv_size); |
68 | if (!phy) { |
69 | printk(KERN_ERR |
70 | "failure to allocate master IEEE802.15.4 device\n"); |
71 | return NULL; |
72 | } |
73 | |
74 | priv = wpan_phy_priv(phy); |
75 | priv->hw.phy = priv->phy = phy; |
76 | priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN); |
77 | priv->ops = ops; |
78 | |
79 | INIT_LIST_HEAD(&priv->slaves); |
80 | mutex_init(&priv->slaves_mtx); |
81 | |
82 | return &priv->hw; |
83 | } |
84 | EXPORT_SYMBOL(ieee802154_alloc_device); |
85 | |
86 | void ieee802154_free_device(struct ieee802154_dev *hw) |
87 | { |
88 | struct mac802154_priv *priv = mac802154_to_priv(hw); |
89 | |
90 | wpan_phy_free(priv->phy); |
91 | |
92 | mutex_destroy(&priv->slaves_mtx); |
93 | } |
94 | EXPORT_SYMBOL(ieee802154_free_device); |
95 | |
96 | int ieee802154_register_device(struct ieee802154_dev *dev) |
97 | { |
98 | struct mac802154_priv *priv = mac802154_to_priv(dev); |
99 | int rc = -ENOMEM; |
100 | |
101 | priv->dev_workqueue = |
102 | create_singlethread_workqueue(wpan_phy_name(priv->phy)); |
103 | if (!priv->dev_workqueue) |
104 | goto out; |
105 | |
106 | wpan_phy_set_dev(priv->phy, priv->hw.parent); |
107 | |
108 | rc = wpan_phy_register(priv->phy); |
109 | if (rc < 0) |
110 | goto out_wq; |
111 | |
112 | rtnl_lock(); |
113 | |
114 | mutex_lock(&priv->slaves_mtx); |
115 | priv->running = MAC802154_DEVICE_RUN; |
116 | mutex_unlock(&priv->slaves_mtx); |
117 | |
118 | rtnl_unlock(); |
119 | |
120 | return 0; |
121 | |
122 | out_wq: |
123 | destroy_workqueue(priv->dev_workqueue); |
124 | out: |
125 | return rc; |
126 | } |
127 | EXPORT_SYMBOL(ieee802154_register_device); |
128 | |
129 | void ieee802154_unregister_device(struct ieee802154_dev *dev) |
130 | { |
131 | struct mac802154_priv *priv = mac802154_to_priv(dev); |
132 | |
133 | flush_workqueue(priv->dev_workqueue); |
134 | destroy_workqueue(priv->dev_workqueue); |
135 | |
136 | rtnl_lock(); |
137 | |
138 | mutex_lock(&priv->slaves_mtx); |
139 | priv->running = MAC802154_DEVICE_STOPPED; |
140 | mutex_unlock(&priv->slaves_mtx); |
141 | |
142 | rtnl_unlock(); |
143 | |
144 | wpan_phy_unregister(priv->phy); |
145 | } |
146 | EXPORT_SYMBOL(ieee802154_unregister_device); |
147 | |
148 | MODULE_DESCRIPTION("IEEE 802.15.4 implementation"); |
149 | MODULE_LICENSE("GPL v2"); |