diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_netdev.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_netdev.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c new file mode 100644 index 000000000000..9df232c2c863 --- /dev/null +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* zd_netdev.c | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation; either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | |||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/skbuff.h> | ||
21 | #include <net/ieee80211.h> | ||
22 | #include <net/ieee80211softmac.h> | ||
23 | #include <net/ieee80211softmac_wx.h> | ||
24 | #include <net/iw_handler.h> | ||
25 | |||
26 | #include "zd_def.h" | ||
27 | #include "zd_netdev.h" | ||
28 | #include "zd_mac.h" | ||
29 | #include "zd_ieee80211.h" | ||
30 | |||
31 | /* Region 0 means reset regdomain to default. */ | ||
32 | static int zd_set_regdomain(struct net_device *netdev, | ||
33 | struct iw_request_info *info, | ||
34 | union iwreq_data *req, char *extra) | ||
35 | { | ||
36 | const u8 *regdomain = (u8 *)req; | ||
37 | return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain); | ||
38 | } | ||
39 | |||
40 | static int zd_get_regdomain(struct net_device *netdev, | ||
41 | struct iw_request_info *info, | ||
42 | union iwreq_data *req, char *extra) | ||
43 | { | ||
44 | u8 *regdomain = (u8 *)req; | ||
45 | if (!regdomain) | ||
46 | return -EINVAL; | ||
47 | *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev)); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static const struct iw_priv_args zd_priv_args[] = { | ||
52 | { | ||
53 | .cmd = ZD_PRIV_SET_REGDOMAIN, | ||
54 | .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | ||
55 | .name = "set_regdomain", | ||
56 | }, | ||
57 | { | ||
58 | .cmd = ZD_PRIV_GET_REGDOMAIN, | ||
59 | .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | ||
60 | .name = "get_regdomain", | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | #define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV] | ||
65 | |||
66 | static const iw_handler zd_priv_handler[] = { | ||
67 | PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain, | ||
68 | PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain, | ||
69 | }; | ||
70 | |||
71 | static int iw_get_name(struct net_device *netdev, | ||
72 | struct iw_request_info *info, | ||
73 | union iwreq_data *req, char *extra) | ||
74 | { | ||
75 | /* FIXME: check whether 802.11a will also supported, add also | ||
76 | * zd1211B, if we support it. | ||
77 | */ | ||
78 | strlcpy(req->name, "802.11g zd1211", IFNAMSIZ); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int iw_set_freq(struct net_device *netdev, | ||
83 | struct iw_request_info *info, | ||
84 | union iwreq_data *req, char *extra) | ||
85 | { | ||
86 | int r; | ||
87 | struct zd_mac *mac = zd_netdev_mac(netdev); | ||
88 | struct iw_freq *freq = &req->freq; | ||
89 | u8 channel; | ||
90 | |||
91 | r = zd_find_channel(&channel, freq); | ||
92 | if (r < 0) | ||
93 | return r; | ||
94 | r = zd_mac_request_channel(mac, channel); | ||
95 | return r; | ||
96 | } | ||
97 | |||
98 | static int iw_get_freq(struct net_device *netdev, | ||
99 | struct iw_request_info *info, | ||
100 | union iwreq_data *req, char *extra) | ||
101 | { | ||
102 | int r; | ||
103 | struct zd_mac *mac = zd_netdev_mac(netdev); | ||
104 | struct iw_freq *freq = &req->freq; | ||
105 | u8 channel; | ||
106 | u8 flags; | ||
107 | |||
108 | r = zd_mac_get_channel(mac, &channel, &flags); | ||
109 | if (r) | ||
110 | return r; | ||
111 | |||
112 | freq->flags = (flags & MAC_FIXED_CHANNEL) ? | ||
113 | IW_FREQ_FIXED : IW_FREQ_AUTO; | ||
114 | dev_dbg_f(zd_mac_dev(mac), "channel %s\n", | ||
115 | (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto"); | ||
116 | return zd_channel_to_freq(freq, channel); | ||
117 | } | ||
118 | |||
119 | static int iw_set_mode(struct net_device *netdev, | ||
120 | struct iw_request_info *info, | ||
121 | union iwreq_data *req, char *extra) | ||
122 | { | ||
123 | return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode); | ||
124 | } | ||
125 | |||
126 | static int iw_get_mode(struct net_device *netdev, | ||
127 | struct iw_request_info *info, | ||
128 | union iwreq_data *req, char *extra) | ||
129 | { | ||
130 | return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode); | ||
131 | } | ||
132 | |||
133 | static int iw_get_range(struct net_device *netdev, | ||
134 | struct iw_request_info *info, | ||
135 | union iwreq_data *req, char *extra) | ||
136 | { | ||
137 | struct iw_range *range = (struct iw_range *)extra; | ||
138 | |||
139 | dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); | ||
140 | req->data.length = sizeof(*range); | ||
141 | return zd_mac_get_range(zd_netdev_mac(netdev), range); | ||
142 | } | ||
143 | |||
144 | static int iw_set_encode(struct net_device *netdev, | ||
145 | struct iw_request_info *info, | ||
146 | union iwreq_data *data, | ||
147 | char *extra) | ||
148 | { | ||
149 | return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info, | ||
150 | data, extra); | ||
151 | } | ||
152 | |||
153 | static int iw_get_encode(struct net_device *netdev, | ||
154 | struct iw_request_info *info, | ||
155 | union iwreq_data *data, | ||
156 | char *extra) | ||
157 | { | ||
158 | return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info, | ||
159 | data, extra); | ||
160 | } | ||
161 | |||
162 | static int iw_set_encodeext(struct net_device *netdev, | ||
163 | struct iw_request_info *info, | ||
164 | union iwreq_data *data, | ||
165 | char *extra) | ||
166 | { | ||
167 | return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info, | ||
168 | data, extra); | ||
169 | } | ||
170 | |||
171 | static int iw_get_encodeext(struct net_device *netdev, | ||
172 | struct iw_request_info *info, | ||
173 | union iwreq_data *data, | ||
174 | char *extra) | ||
175 | { | ||
176 | return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info, | ||
177 | data, extra); | ||
178 | } | ||
179 | |||
180 | #define WX(x) [(x)-SIOCIWFIRST] | ||
181 | |||
182 | static const iw_handler zd_standard_iw_handlers[] = { | ||
183 | WX(SIOCGIWNAME) = iw_get_name, | ||
184 | WX(SIOCSIWFREQ) = iw_set_freq, | ||
185 | WX(SIOCGIWFREQ) = iw_get_freq, | ||
186 | WX(SIOCSIWMODE) = iw_set_mode, | ||
187 | WX(SIOCGIWMODE) = iw_get_mode, | ||
188 | WX(SIOCGIWRANGE) = iw_get_range, | ||
189 | WX(SIOCSIWENCODE) = iw_set_encode, | ||
190 | WX(SIOCGIWENCODE) = iw_get_encode, | ||
191 | WX(SIOCSIWENCODEEXT) = iw_set_encodeext, | ||
192 | WX(SIOCGIWENCODEEXT) = iw_get_encodeext, | ||
193 | WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, | ||
194 | WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, | ||
195 | WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, | ||
196 | WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, | ||
197 | WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, | ||
198 | WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, | ||
199 | WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, | ||
200 | WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, | ||
201 | WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, | ||
202 | WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, | ||
203 | WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, | ||
204 | WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, | ||
205 | WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme, | ||
206 | }; | ||
207 | |||
208 | static const struct iw_handler_def iw_handler_def = { | ||
209 | .standard = zd_standard_iw_handlers, | ||
210 | .num_standard = ARRAY_SIZE(zd_standard_iw_handlers), | ||
211 | .private = zd_priv_handler, | ||
212 | .num_private = ARRAY_SIZE(zd_priv_handler), | ||
213 | .private_args = zd_priv_args, | ||
214 | .num_private_args = ARRAY_SIZE(zd_priv_args), | ||
215 | .get_wireless_stats = zd_mac_get_wireless_stats, | ||
216 | }; | ||
217 | |||
218 | struct net_device *zd_netdev_alloc(struct usb_interface *intf) | ||
219 | { | ||
220 | int r; | ||
221 | struct net_device *netdev; | ||
222 | struct zd_mac *mac; | ||
223 | |||
224 | netdev = alloc_ieee80211softmac(sizeof(struct zd_mac)); | ||
225 | if (!netdev) { | ||
226 | dev_dbg_f(&intf->dev, "out of memory\n"); | ||
227 | return NULL; | ||
228 | } | ||
229 | |||
230 | mac = zd_netdev_mac(netdev); | ||
231 | r = zd_mac_init(mac, netdev, intf); | ||
232 | if (r) { | ||
233 | usb_set_intfdata(intf, NULL); | ||
234 | free_ieee80211(netdev); | ||
235 | return NULL; | ||
236 | } | ||
237 | |||
238 | SET_MODULE_OWNER(netdev); | ||
239 | SET_NETDEV_DEV(netdev, &intf->dev); | ||
240 | |||
241 | dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags); | ||
242 | dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features); | ||
243 | |||
244 | netdev->open = zd_mac_open; | ||
245 | netdev->stop = zd_mac_stop; | ||
246 | /* netdev->get_stats = */ | ||
247 | /* netdev->set_multicast_list = */ | ||
248 | netdev->set_mac_address = zd_mac_set_mac_address; | ||
249 | netdev->wireless_handlers = &iw_handler_def; | ||
250 | /* netdev->ethtool_ops = */ | ||
251 | |||
252 | return netdev; | ||
253 | } | ||
254 | |||
255 | void zd_netdev_free(struct net_device *netdev) | ||
256 | { | ||
257 | if (!netdev) | ||
258 | return; | ||
259 | |||
260 | zd_mac_clear(zd_netdev_mac(netdev)); | ||
261 | free_ieee80211(netdev); | ||
262 | } | ||
263 | |||
264 | void zd_netdev_disconnect(struct net_device *netdev) | ||
265 | { | ||
266 | unregister_netdev(netdev); | ||
267 | } | ||