Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
[pandora-kernel.git] / drivers / net / wireless / zd1211rw / zd_netdev.c
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 */
76         strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
77         return 0;
78 }
79
80 static int iw_get_nick(struct net_device *netdev,
81                        struct iw_request_info *info,
82                        union iwreq_data *req, char *extra)
83 {
84         strcpy(extra, "zd1211");
85         req->data.length = strlen(extra);
86         req->data.flags = 1;
87         return 0;
88 }
89
90 static int iw_set_freq(struct net_device *netdev,
91                        struct iw_request_info *info,
92                        union iwreq_data *req, char *extra)
93 {
94         int r;
95         struct zd_mac *mac = zd_netdev_mac(netdev);
96         struct iw_freq *freq = &req->freq;
97         u8 channel;
98
99         r = zd_find_channel(&channel, freq);
100         if (r < 0)
101                 return r;
102         r = zd_mac_request_channel(mac, channel);
103         return r;
104 }
105
106 static int iw_get_freq(struct net_device *netdev,
107                    struct iw_request_info *info,
108                    union iwreq_data *req, char *extra)
109 {
110         int r;
111         struct zd_mac *mac = zd_netdev_mac(netdev);
112         struct iw_freq *freq = &req->freq;
113         u8 channel;
114         u8 flags;
115
116         r = zd_mac_get_channel(mac, &channel, &flags);
117         if (r)
118                 return r;
119
120         freq->flags = (flags & MAC_FIXED_CHANNEL) ?
121                       IW_FREQ_FIXED : IW_FREQ_AUTO;
122         dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
123                   (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
124         return zd_channel_to_freq(freq, channel);
125 }
126
127 static int iw_set_mode(struct net_device *netdev,
128                        struct iw_request_info *info,
129                        union iwreq_data *req, char *extra)
130 {
131         return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
132 }
133
134 static int iw_get_mode(struct net_device *netdev,
135                        struct iw_request_info *info,
136                        union iwreq_data *req, char *extra)
137 {
138         return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
139 }
140
141 static int iw_get_range(struct net_device *netdev,
142                        struct iw_request_info *info,
143                        union iwreq_data *req, char *extra)
144 {
145         struct iw_range *range = (struct iw_range *)extra;
146
147         dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
148         req->data.length = sizeof(*range);
149         return zd_mac_get_range(zd_netdev_mac(netdev), range);
150 }
151
152 static int iw_set_encode(struct net_device *netdev,
153                          struct iw_request_info *info,
154                          union iwreq_data *data,
155                          char *extra)
156 {
157         return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
158                 data, extra);
159 }
160
161 static int iw_get_encode(struct net_device *netdev,
162                          struct iw_request_info *info,
163                          union iwreq_data *data,
164                          char *extra)
165 {
166         return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
167                 data, extra);
168 }
169
170 static int iw_set_encodeext(struct net_device *netdev,
171                          struct iw_request_info *info,
172                          union iwreq_data *data,
173                          char *extra)
174 {
175         return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
176                 data, extra);
177 }
178
179 static int iw_get_encodeext(struct net_device *netdev,
180                          struct iw_request_info *info,
181                          union iwreq_data *data,
182                          char *extra)
183 {
184         return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
185                 data, extra);
186 }
187
188 #define WX(x) [(x)-SIOCIWFIRST]
189
190 static const iw_handler zd_standard_iw_handlers[] = {
191         WX(SIOCGIWNAME)         = iw_get_name,
192         WX(SIOCGIWNICKN)        = iw_get_nick,
193         WX(SIOCSIWFREQ)         = iw_set_freq,
194         WX(SIOCGIWFREQ)         = iw_get_freq,
195         WX(SIOCSIWMODE)         = iw_set_mode,
196         WX(SIOCGIWMODE)         = iw_get_mode,
197         WX(SIOCGIWRANGE)        = iw_get_range,
198         WX(SIOCSIWENCODE)       = iw_set_encode,
199         WX(SIOCGIWENCODE)       = iw_get_encode,
200         WX(SIOCSIWENCODEEXT)    = iw_set_encodeext,
201         WX(SIOCGIWENCODEEXT)    = iw_get_encodeext,
202         WX(SIOCSIWAUTH)         = ieee80211_wx_set_auth,
203         WX(SIOCGIWAUTH)         = ieee80211_wx_get_auth,
204         WX(SIOCSIWSCAN)         = ieee80211softmac_wx_trigger_scan,
205         WX(SIOCGIWSCAN)         = ieee80211softmac_wx_get_scan_results,
206         WX(SIOCSIWESSID)        = ieee80211softmac_wx_set_essid,
207         WX(SIOCGIWESSID)        = ieee80211softmac_wx_get_essid,
208         WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
209         WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
210         WX(SIOCSIWRATE)         = ieee80211softmac_wx_set_rate,
211         WX(SIOCGIWRATE)         = ieee80211softmac_wx_get_rate,
212         WX(SIOCSIWGENIE)        = ieee80211softmac_wx_set_genie,
213         WX(SIOCGIWGENIE)        = ieee80211softmac_wx_get_genie,
214         WX(SIOCSIWMLME)         = ieee80211softmac_wx_set_mlme,
215 };
216
217 static const struct iw_handler_def iw_handler_def = {
218         .standard               = zd_standard_iw_handlers,
219         .num_standard           = ARRAY_SIZE(zd_standard_iw_handlers),
220         .private                = zd_priv_handler,
221         .num_private            = ARRAY_SIZE(zd_priv_handler),
222         .private_args           = zd_priv_args,
223         .num_private_args       = ARRAY_SIZE(zd_priv_args),
224         .get_wireless_stats     = zd_mac_get_wireless_stats,
225 };
226
227 struct net_device *zd_netdev_alloc(struct usb_interface *intf)
228 {
229         int r;
230         struct net_device *netdev;
231         struct zd_mac *mac;
232
233         netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
234         if (!netdev) {
235                 dev_dbg_f(&intf->dev, "out of memory\n");
236                 return NULL;
237         }
238
239         mac = zd_netdev_mac(netdev);
240         r = zd_mac_init(mac, netdev, intf);
241         if (r) {
242                 usb_set_intfdata(intf, NULL);
243                 free_ieee80211(netdev);
244                 return NULL;
245         }
246
247         SET_MODULE_OWNER(netdev);
248         SET_NETDEV_DEV(netdev, &intf->dev);
249
250         dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
251         dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
252
253         netdev->open = zd_mac_open;
254         netdev->stop = zd_mac_stop;
255         /* netdev->get_stats = */
256         /* netdev->set_multicast_list = */
257         netdev->set_mac_address = zd_mac_set_mac_address;
258         netdev->wireless_handlers = &iw_handler_def;
259         /* netdev->ethtool_ops = */
260
261         return netdev;
262 }
263
264 void zd_netdev_free(struct net_device *netdev)
265 {
266         if (!netdev)
267                 return;
268
269         zd_mac_clear(zd_netdev_mac(netdev));
270         free_ieee80211(netdev);
271 }
272
273 void zd_netdev_disconnect(struct net_device *netdev)
274 {
275         unregister_netdev(netdev);
276 }