Merge branch 'for-linus' into next
[cascardo/linux.git] / drivers / staging / rtl8712 / rtl871x_ioctl_rtl.c
1 /******************************************************************************
2  * rtl871x_ioctl_rtl.c
3  *
4  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5  * Linux device driver for RTL8192SU
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * Modifications for inclusion into the Linux staging tree are
21  * Copyright(c) 2010 Larry Finger. All rights reserved.
22  *
23  * Contact information:
24  * WLAN FAE <wlanfae@realtek.com>
25  * Larry Finger <Larry.Finger@lwfinger.net>
26  *
27  ******************************************************************************/
28
29 #define  _RTL871X_IOCTL_RTL_C_
30
31 #include <linux/rndis.h>
32 #include "osdep_service.h"
33 #include "drv_types.h"
34 #include "wlan_bssdef.h"
35 #include "wifi.h"
36 #include "rtl871x_ioctl.h"
37 #include "rtl871x_ioctl_set.h"
38 #include "rtl871x_ioctl_rtl.h"
39 #include "mp_custom_oid.h"
40 #include "rtl871x_mp.h"
41 #include "rtl871x_mp_ioctl.h"
42
43 uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv)
44 {
45         if (poid_par_priv->type_of_oid != QUERY_OID)
46                 return RNDIS_STATUS_NOT_ACCEPTED;
47         return RNDIS_STATUS_SUCCESS;
48 }
49
50 uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
51 {
52         struct _adapter *padapter = poid_par_priv->adapter_context;
53
54         if (poid_par_priv->type_of_oid != QUERY_OID)
55                 return RNDIS_STATUS_NOT_ACCEPTED;
56         if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
57                 *(u32 *)poid_par_priv->information_buf =
58                                 padapter->recvpriv.rx_smallpacket_crcerr;
59                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
60         } else {
61                 return RNDIS_STATUS_INVALID_LENGTH;
62         }
63         return RNDIS_STATUS_SUCCESS;
64 }
65
66 uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
67 {
68         struct _adapter *padapter = poid_par_priv->adapter_context;
69
70         if (poid_par_priv->type_of_oid != QUERY_OID)
71                 return RNDIS_STATUS_NOT_ACCEPTED;
72         if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
73                 *(u32 *)poid_par_priv->information_buf =
74                                 padapter->recvpriv.rx_middlepacket_crcerr;
75                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
76         } else {
77                 return RNDIS_STATUS_INVALID_LENGTH;
78         }
79         return RNDIS_STATUS_SUCCESS;
80 }
81
82 uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
83 {
84         struct _adapter *padapter = poid_par_priv->adapter_context;
85
86         if (poid_par_priv->type_of_oid != QUERY_OID)
87                 return RNDIS_STATUS_NOT_ACCEPTED;
88         if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
89                 *(u32 *)poid_par_priv->information_buf =
90                                  padapter->recvpriv.rx_largepacket_crcerr;
91                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
92         } else {
93                 return RNDIS_STATUS_INVALID_LENGTH;
94         }
95         return RNDIS_STATUS_SUCCESS;
96 }
97
98 uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv)
99 {
100         if (poid_par_priv->type_of_oid != QUERY_OID)
101                 return RNDIS_STATUS_NOT_ACCEPTED;
102         return RNDIS_STATUS_SUCCESS;
103 }
104
105 uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv)
106 {
107         if (poid_par_priv->type_of_oid != QUERY_OID)
108                 return RNDIS_STATUS_NOT_ACCEPTED;
109         *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
110         return RNDIS_STATUS_SUCCESS;
111 }
112
113 uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv)
114 {
115         struct _adapter *padapter = poid_par_priv->adapter_context;
116
117         if (poid_par_priv->type_of_oid != QUERY_OID)
118                 return RNDIS_STATUS_NOT_ACCEPTED;
119         if (poid_par_priv->information_buf_len >=  sizeof(u32)) {
120                 *(u32 *)poid_par_priv->information_buf =
121                                          padapter->recvpriv.rx_pkts +
122                                          padapter->recvpriv.rx_drop;
123                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
124         } else {
125                 return RNDIS_STATUS_INVALID_LENGTH;
126         }
127         return RNDIS_STATUS_SUCCESS;
128 }
129
130 uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv)
131 {
132         if (poid_par_priv->type_of_oid != QUERY_OID)
133                 return RNDIS_STATUS_NOT_ACCEPTED;
134         return RNDIS_STATUS_SUCCESS;
135 }
136
137 uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv)
138 {
139         if (poid_par_priv->type_of_oid != QUERY_OID)
140                 return RNDIS_STATUS_NOT_ACCEPTED;
141         return RNDIS_STATUS_SUCCESS;
142 }
143
144 uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv)
145 {
146         struct _adapter *padapter = poid_par_priv->adapter_context;
147
148         if (poid_par_priv->type_of_oid != QUERY_OID)
149                 return RNDIS_STATUS_NOT_ACCEPTED;
150         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
151                 *(uint *)poid_par_priv->information_buf =
152                                          padapter->recvpriv.rx_icv_err;
153                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
154         } else {
155                 return RNDIS_STATUS_INVALID_LENGTH;
156         }
157         return RNDIS_STATUS_SUCCESS;
158 }
159
160 uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv
161                                                 *poid_par_priv)
162 {
163         if (poid_par_priv->type_of_oid != SET_OID)
164                 return RNDIS_STATUS_NOT_ACCEPTED;
165         return RNDIS_STATUS_SUCCESS;
166 }
167
168 uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv)
169 {
170         struct _adapter *padapter = poid_par_priv->adapter_context;
171         u32 preamblemode = 0;
172
173         if (poid_par_priv->type_of_oid != QUERY_OID)
174                 return RNDIS_STATUS_NOT_ACCEPTED;
175         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
176                 if (padapter->registrypriv.preamble == PREAMBLE_LONG)
177                         preamblemode = 0;
178                 else if (padapter->registrypriv.preamble == PREAMBLE_AUTO)
179                         preamblemode = 1;
180                 else if (padapter->registrypriv.preamble == PREAMBLE_SHORT)
181                         preamblemode = 2;
182                 *(u32 *)poid_par_priv->information_buf = preamblemode;
183                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
184         } else {
185                 return RNDIS_STATUS_INVALID_LENGTH;
186         }
187         return RNDIS_STATUS_SUCCESS;
188 }
189
190 uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv)
191 {
192         if (poid_par_priv->type_of_oid != QUERY_OID)
193                 return RNDIS_STATUS_NOT_ACCEPTED;
194         return RNDIS_STATUS_SUCCESS;
195 }
196
197 uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv)
198 {
199         struct _adapter *padapter = poid_par_priv->adapter_context;
200         struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
201
202         if (poid_par_priv->type_of_oid != QUERY_OID)
203                 return RNDIS_STATUS_NOT_ACCEPTED;
204         *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
205         *(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan;
206         return RNDIS_STATUS_SUCCESS;
207 }
208
209 uint oid_rt_set_channelplan_hdl(struct oid_par_priv
210                                        *poid_par_priv)
211 {
212         struct _adapter *padapter = poid_par_priv->adapter_context;
213         struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
214
215         if (poid_par_priv->type_of_oid != SET_OID)
216                 return RNDIS_STATUS_NOT_ACCEPTED;
217         peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf;
218         return RNDIS_STATUS_SUCCESS;
219 }
220
221 uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv
222                                          *poid_par_priv)
223 {
224         struct _adapter *padapter = poid_par_priv->adapter_context;
225         u32 preamblemode = 0;
226
227         if (poid_par_priv->type_of_oid != SET_OID)
228                 return RNDIS_STATUS_NOT_ACCEPTED;
229         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
230                 preamblemode = *(u32 *)poid_par_priv->information_buf;
231                 if (preamblemode == 0)
232                         padapter->registrypriv.preamble = PREAMBLE_LONG;
233                 else if (preamblemode == 1)
234                         padapter->registrypriv.preamble = PREAMBLE_AUTO;
235                 else if (preamblemode == 2)
236                         padapter->registrypriv.preamble = PREAMBLE_SHORT;
237                 *(u32 *)poid_par_priv->information_buf = preamblemode;
238                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
239         } else {
240                 return RNDIS_STATUS_INVALID_LENGTH;
241         }
242         return RNDIS_STATUS_SUCCESS;
243 }
244
245 uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv)
246 {
247         if (poid_par_priv->type_of_oid != SET_OID)
248                 return RNDIS_STATUS_NOT_ACCEPTED;
249         return RNDIS_STATUS_SUCCESS;
250 }
251
252 uint oid_rt_dedicate_probe_hdl(struct oid_par_priv
253                                       *poid_par_priv)
254 {
255         return RNDIS_STATUS_SUCCESS;
256 }
257
258 uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv
259                                           *poid_par_priv)
260 {
261         struct _adapter *padapter = poid_par_priv->adapter_context;
262
263         if (poid_par_priv->type_of_oid != QUERY_OID)
264                 return RNDIS_STATUS_NOT_ACCEPTED;
265         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
266                 *(u32 *)poid_par_priv->information_buf =
267                                                  padapter->xmitpriv.tx_bytes;
268                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
269         } else {
270                 return RNDIS_STATUS_INVALID_LENGTH;
271         }
272         return RNDIS_STATUS_SUCCESS;
273 }
274
275 uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv
276                                           *poid_par_priv)
277 {
278         struct _adapter *padapter = poid_par_priv->adapter_context;
279
280         if (poid_par_priv->type_of_oid != QUERY_OID)
281                 return RNDIS_STATUS_NOT_ACCEPTED;
282         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
283                 *(u32 *)poid_par_priv->information_buf =
284                                            padapter->recvpriv.rx_bytes;
285                 *poid_par_priv->bytes_rw = poid_par_priv->
286                                            information_buf_len;
287         } else {
288                 return RNDIS_STATUS_INVALID_LENGTH;
289         }
290         return RNDIS_STATUS_SUCCESS;
291 }
292
293 uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv
294                                               *poid_par_priv)
295 {
296         return RNDIS_STATUS_SUCCESS;
297 }
298
299 uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv
300                                                   *poid_par_priv)
301 {
302         if (poid_par_priv->type_of_oid != QUERY_OID)
303                 return RNDIS_STATUS_NOT_ACCEPTED;
304         return RNDIS_STATUS_SUCCESS;
305 }
306
307 uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv
308                                                *poid_par_priv)
309 {
310         if (poid_par_priv->type_of_oid != QUERY_OID)
311                 return RNDIS_STATUS_NOT_ACCEPTED;
312         return RNDIS_STATUS_SUCCESS;
313 }
314
315 uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv)
316 {
317         struct _adapter *padapter = poid_par_priv->adapter_context;
318         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
319         struct NDIS_802_11_CONFIGURATION *pnic_Config;
320         u32   channelnum;
321
322         if (poid_par_priv->type_of_oid != QUERY_OID)
323                 return RNDIS_STATUS_NOT_ACCEPTED;
324         if (check_fwstate(pmlmepriv, _FW_LINKED) ||
325             check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
326                 pnic_Config = &pmlmepriv->cur_network.network.Configuration;
327         else
328                 pnic_Config = &padapter->registrypriv.dev_network.
329                               Configuration;
330         channelnum = pnic_Config->DSConfig;
331         *(u32 *)poid_par_priv->information_buf = channelnum;
332         *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
333         return RNDIS_STATUS_SUCCESS;
334 }
335
336 uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv
337                          *poid_par_priv)
338 {
339         if (poid_par_priv->type_of_oid != QUERY_OID)
340                 return RNDIS_STATUS_NOT_ACCEPTED;
341         return RNDIS_STATUS_SUCCESS;
342 }
343
344 uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv)
345 {
346         if (poid_par_priv->type_of_oid != QUERY_OID)
347                 return RNDIS_STATUS_NOT_ACCEPTED;
348         return RNDIS_STATUS_SUCCESS;
349 }
350
351 uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv
352                                                *poid_par_priv)
353 {
354         u32 ulInfo = 0;
355
356         if (poid_par_priv->type_of_oid != QUERY_OID)
357                 return RNDIS_STATUS_NOT_ACCEPTED;
358         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
359                 ulInfo |= 0x0100; /* WIRELESS_MODE_B */
360                 ulInfo |= 0x0200; /* WIRELESS_MODE_G */
361                 ulInfo |= 0x0400; /* WIRELESS_MODE_A */
362                 *(u32 *) poid_par_priv->information_buf = ulInfo;
363                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
364         } else {
365                 return RNDIS_STATUS_INVALID_LENGTH;
366         }
367         return RNDIS_STATUS_SUCCESS;
368 }
369
370 uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv)
371 {
372         if (poid_par_priv->type_of_oid != QUERY_OID)
373                 return RNDIS_STATUS_NOT_ACCEPTED;
374         return RNDIS_STATUS_SUCCESS;
375 }
376
377 uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv)
378 {
379         if (poid_par_priv->type_of_oid != QUERY_OID)
380                 return RNDIS_STATUS_NOT_ACCEPTED;
381         return RNDIS_STATUS_SUCCESS;
382 }
383
384
385 uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv)
386 {
387         return RNDIS_STATUS_SUCCESS;
388 }
389
390 uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv
391                                                    *poid_par_priv)
392 {
393         return RNDIS_STATUS_SUCCESS;
394 }
395
396 uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv
397                                              *poid_par_priv)
398 {
399         if (poid_par_priv->type_of_oid != QUERY_OID)
400                 return RNDIS_STATUS_NOT_ACCEPTED;
401         return RNDIS_STATUS_SUCCESS;
402 }
403
404 uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv
405                                               *poid_par_priv)
406 {
407         return RNDIS_STATUS_SUCCESS;
408 }
409
410 uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv
411                                                       *poid_par_priv)
412 {
413         if (poid_par_priv->type_of_oid != QUERY_OID)
414                 return RNDIS_STATUS_NOT_ACCEPTED;
415         return RNDIS_STATUS_SUCCESS;
416 }
417
418 uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv*
419                                               poid_par_priv)
420 {
421         return RNDIS_STATUS_SUCCESS;
422 }
423
424 uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv)
425 {
426         return RNDIS_STATUS_SUCCESS;
427 }
428
429 uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv)
430 {
431         if (poid_par_priv->type_of_oid != SET_OID)
432                 return RNDIS_STATUS_NOT_ACCEPTED;
433         return RNDIS_STATUS_SUCCESS;
434 }
435
436 uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv*
437                                              poid_par_priv)
438 {
439         uint status = RNDIS_STATUS_SUCCESS;
440         struct _adapter *Adapter = poid_par_priv->adapter_context;
441
442         if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
443                 return RNDIS_STATUS_NOT_ACCEPTED;
444         if (poid_par_priv->information_buf_len ==
445            (sizeof(unsigned long) * 3)) {
446                 if (!r8712_setrfreg_cmd(Adapter,
447                         *(unsigned char *)poid_par_priv->information_buf,
448                         (unsigned long)(*((unsigned long *)
449                                         poid_par_priv->information_buf + 2))))
450                         status = RNDIS_STATUS_NOT_ACCEPTED;
451         } else {
452                 status = RNDIS_STATUS_INVALID_LENGTH;
453         }
454         return status;
455 }
456
457 uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv)
458 {
459         uint status = RNDIS_STATUS_SUCCESS;
460         struct _adapter *Adapter = poid_par_priv->adapter_context;
461
462         if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
463                 return RNDIS_STATUS_NOT_ACCEPTED;
464         if (poid_par_priv->information_buf_len == (sizeof(unsigned long) *
465                                                    3)) {
466                 if (Adapter->mppriv.act_in_progress) {
467                         status = RNDIS_STATUS_NOT_ACCEPTED;
468                 } else {
469                         /* init workparam */
470                         Adapter->mppriv.act_in_progress = true;
471                         Adapter->mppriv.workparam.bcompleted = false;
472                         Adapter->mppriv.workparam.act_type = MPT_READ_RF;
473                         Adapter->mppriv.workparam.io_offset = *(unsigned long *)
474                                                 poid_par_priv->information_buf;
475                         Adapter->mppriv.workparam.io_value = 0xcccccccc;
476
477                 /* RegOffsetValue       - The offset of RF register to read.
478                  * RegDataWidth - The data width of RF register to read.
479                  * RegDataValue - The value to read.
480                  * RegOffsetValue = *((unsigned long *)InformationBuffer);
481                  * RegDataWidth = *((unsigned long *)InformationBuffer+1);
482                  * RegDataValue =  *((unsigned long *)InformationBuffer+2);
483                  */
484                         if (!r8712_getrfreg_cmd(Adapter,
485                             *(unsigned char *)poid_par_priv->information_buf,
486                             (unsigned char *)&Adapter->mppriv.workparam.
487                             io_value))
488                                 status = RNDIS_STATUS_NOT_ACCEPTED;
489                 }
490         } else {
491                 status = RNDIS_STATUS_INVALID_LENGTH;
492         }
493         return status;
494 }
495
496 enum _CONNECT_STATE_ {
497         CHECKINGSTATUS,
498         ASSOCIATED,
499         ADHOCMODE,
500         NOTASSOCIATED
501 };
502
503 uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv)
504 {
505         struct _adapter *padapter = poid_par_priv->adapter_context;
506         struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
507         u32 ulInfo;
508
509         if (poid_par_priv->type_of_oid != QUERY_OID)
510                 return RNDIS_STATUS_NOT_ACCEPTED;
511         /* nStatus==0   CheckingStatus
512          * nStatus==1   Associated
513          * nStatus==2   AdHocMode
514          * nStatus==3   NotAssociated
515          */
516         if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
517                 ulInfo = CHECKINGSTATUS;
518         else if (check_fwstate(pmlmepriv, _FW_LINKED))
519                 ulInfo = ASSOCIATED;
520         else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
521                 ulInfo = ADHOCMODE;
522         else
523                 ulInfo = NOTASSOCIATED;
524         *(u32 *)poid_par_priv->information_buf = ulInfo;
525         *poid_par_priv->bytes_rw =  poid_par_priv->information_buf_len;
526         return RNDIS_STATUS_SUCCESS;
527 }
528
529 uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv)
530 {
531         if (poid_par_priv->type_of_oid != SET_OID)
532                 return RNDIS_STATUS_NOT_ACCEPTED;
533         return RNDIS_STATUS_SUCCESS;
534 }