staging: r8712u: Add the new driver to the mainline kernel
[pandora-kernel.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 "osdep_service.h"
32 #include "drv_types.h"
33 #include "wlan_bssdef.h"
34 #include "wifi.h"
35 #include "rtl871x_ioctl.h"
36 #include "rtl871x_ioctl_set.h"
37 #include "rtl871x_ioctl_rtl.h"
38 #include "mp_custom_oid.h"
39 #include "rtl871x_mp.h"
40 #include "rtl871x_mp_ioctl.h"
41
42 uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv)
43 {
44         if (poid_par_priv->type_of_oid != QUERY_OID)
45                 return NDIS_STATUS_NOT_ACCEPTED;
46         return NDIS_STATUS_SUCCESS;
47 }
48
49 uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
50 {
51         struct _adapter *padapter = (struct _adapter *)
52                                     (poid_par_priv->adapter_context);
53
54         if (poid_par_priv->type_of_oid != QUERY_OID)
55                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH;
62         return NDIS_STATUS_SUCCESS;
63 }
64
65 uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
66 {
67         struct _adapter *padapter = (struct _adapter *)
68                                     (poid_par_priv->adapter_context);
69
70         if (poid_par_priv->type_of_oid != QUERY_OID)
71                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH;
78         return NDIS_STATUS_SUCCESS;
79 }
80
81 uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv)
82 {
83         struct _adapter *padapter = (struct _adapter *)
84                                     (poid_par_priv->adapter_context);
85
86         if (poid_par_priv->type_of_oid != QUERY_OID)
87                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH;
94         return NDIS_STATUS_SUCCESS;
95 }
96
97 uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv)
98 {
99         if (poid_par_priv->type_of_oid != QUERY_OID)
100                 return NDIS_STATUS_NOT_ACCEPTED;
101         return NDIS_STATUS_SUCCESS;
102 }
103
104 uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv)
105 {
106         if (poid_par_priv->type_of_oid != QUERY_OID)
107                 return NDIS_STATUS_NOT_ACCEPTED;
108         *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
109         return NDIS_STATUS_SUCCESS;
110 }
111
112 uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv)
113 {
114         struct _adapter *padapter = (struct _adapter *)
115                                     (poid_par_priv->adapter_context);
116
117         if (poid_par_priv->type_of_oid != QUERY_OID)
118                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH;
126         return NDIS_STATUS_SUCCESS;
127 }
128
129 uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv)
130 {
131         if (poid_par_priv->type_of_oid != QUERY_OID)
132                 return NDIS_STATUS_NOT_ACCEPTED;
133         return NDIS_STATUS_SUCCESS;
134 }
135
136 uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv)
137 {
138         if (poid_par_priv->type_of_oid != QUERY_OID)
139                 return NDIS_STATUS_NOT_ACCEPTED;
140         return NDIS_STATUS_SUCCESS;
141 }
142
143 uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv)
144 {
145         struct _adapter *padapter = (struct _adapter *)
146                                     (poid_par_priv->adapter_context);
147
148         if (poid_par_priv->type_of_oid != QUERY_OID)
149                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH ;
156         return NDIS_STATUS_SUCCESS;
157 }
158
159 uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv
160                                                 *poid_par_priv)
161 {
162         if (poid_par_priv->type_of_oid != SET_OID)
163                 return NDIS_STATUS_NOT_ACCEPTED;
164         return NDIS_STATUS_SUCCESS;
165 }
166
167 uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv)
168 {
169         struct _adapter *padapter = (struct _adapter *)
170                                     (poid_par_priv->adapter_context);
171         u32 preamblemode = 0 ;
172
173         if (poid_par_priv->type_of_oid != QUERY_OID)
174                 return NDIS_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 NDIS_STATUS_INVALID_LENGTH;
186         return NDIS_STATUS_SUCCESS;
187 }
188
189 uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv)
190 {
191         if (poid_par_priv->type_of_oid != QUERY_OID)
192                 return NDIS_STATUS_NOT_ACCEPTED;
193         return NDIS_STATUS_SUCCESS;
194 }
195
196 uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv)
197 {
198         struct _adapter *padapter = (struct _adapter *)
199                                     (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 NDIS_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 NDIS_STATUS_SUCCESS;
207 }
208
209 uint oid_rt_set_channelplan_hdl(struct oid_par_priv
210                                        *poid_par_priv)
211 {
212         struct _adapter *padapter = (struct _adapter *)
213                                     (poid_par_priv->adapter_context);
214         struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
215
216         if (poid_par_priv->type_of_oid != SET_OID)
217                 return NDIS_STATUS_NOT_ACCEPTED;
218         peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf;
219         return NDIS_STATUS_SUCCESS;
220 }
221
222 uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv
223                                          *poid_par_priv)
224 {
225         struct _adapter *padapter = (struct _adapter *)
226                                     (poid_par_priv->adapter_context);
227         u32 preamblemode = 0;
228
229         if (poid_par_priv->type_of_oid != SET_OID)
230                 return NDIS_STATUS_NOT_ACCEPTED;
231         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
232                 preamblemode = *(u32 *)poid_par_priv->information_buf;
233                 if (preamblemode == 0)
234                         padapter->registrypriv.preamble = PREAMBLE_LONG;
235                 else if (preamblemode == 1)
236                         padapter->registrypriv.preamble = PREAMBLE_AUTO;
237                 else if (preamblemode == 2)
238                         padapter->registrypriv.preamble = PREAMBLE_SHORT;
239                 *(u32 *)poid_par_priv->information_buf = preamblemode;
240                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
241         } else
242                 return NDIS_STATUS_INVALID_LENGTH;
243         return NDIS_STATUS_SUCCESS;
244 }
245
246 uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv)
247 {
248         if (poid_par_priv->type_of_oid != SET_OID)
249                 return NDIS_STATUS_NOT_ACCEPTED;
250         return NDIS_STATUS_SUCCESS;
251 }
252
253 uint oid_rt_dedicate_probe_hdl(struct oid_par_priv
254                                       *poid_par_priv)
255 {
256         return NDIS_STATUS_SUCCESS;
257 }
258
259 uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv
260                                           *poid_par_priv)
261 {
262         struct _adapter *padapter = (struct _adapter *)
263                                     (poid_par_priv->adapter_context);
264
265         if (poid_par_priv->type_of_oid != QUERY_OID)
266                 return NDIS_STATUS_NOT_ACCEPTED;
267         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
268                 *(u32 *)poid_par_priv->information_buf =
269                                                  padapter->xmitpriv.tx_bytes;
270                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
271         } else
272                 return NDIS_STATUS_INVALID_LENGTH;
273         return NDIS_STATUS_SUCCESS;
274 }
275
276 uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv
277                                           *poid_par_priv)
278 {
279         struct _adapter *padapter = (struct _adapter *)
280                                     (poid_par_priv->adapter_context);
281
282         if (poid_par_priv->type_of_oid != QUERY_OID)
283                 return NDIS_STATUS_NOT_ACCEPTED;
284         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
285                 *(u32 *)poid_par_priv->information_buf =
286                                            padapter->recvpriv.rx_bytes;
287                 *poid_par_priv->bytes_rw = poid_par_priv->
288                                            information_buf_len;
289         } else
290                 return NDIS_STATUS_INVALID_LENGTH;
291         return NDIS_STATUS_SUCCESS;
292 }
293
294 uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv
295                                               *poid_par_priv)
296 {
297         return NDIS_STATUS_SUCCESS;
298 }
299
300 uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv
301                                                   *poid_par_priv)
302 {
303         if (poid_par_priv->type_of_oid != QUERY_OID)
304                 return NDIS_STATUS_NOT_ACCEPTED;
305         return NDIS_STATUS_SUCCESS;
306 }
307
308 uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv
309                                                *poid_par_priv)
310 {
311         if (poid_par_priv->type_of_oid != QUERY_OID)
312                 return NDIS_STATUS_NOT_ACCEPTED;
313         return NDIS_STATUS_SUCCESS;
314 }
315
316 uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv)
317 {
318         struct _adapter *padapter = (struct _adapter *)
319                                     (poid_par_priv->adapter_context);
320         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
321         struct NDIS_802_11_CONFIGURATION *pnic_Config;
322         u32   channelnum;
323
324         if (poid_par_priv->type_of_oid != QUERY_OID)
325                 return NDIS_STATUS_NOT_ACCEPTED;
326         if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||
327             (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true))
328                 pnic_Config = &pmlmepriv->cur_network.network.Configuration;
329         else
330                 pnic_Config = &padapter->registrypriv.dev_network.
331                               Configuration;
332         channelnum = pnic_Config->DSConfig;
333         *(u32 *)poid_par_priv->information_buf = channelnum;
334         *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
335         return NDIS_STATUS_SUCCESS;
336 }
337
338 uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv
339                          *poid_par_priv)
340 {
341         if (poid_par_priv->type_of_oid != QUERY_OID)
342                 return NDIS_STATUS_NOT_ACCEPTED;
343         return NDIS_STATUS_SUCCESS;
344 }
345
346 uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv)
347 {
348         if (poid_par_priv->type_of_oid != QUERY_OID)
349                 return NDIS_STATUS_NOT_ACCEPTED;
350         return NDIS_STATUS_SUCCESS;
351 }
352
353 uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv
354                                                *poid_par_priv)
355 {
356         u32 ulInfo = 0;
357
358         if (poid_par_priv->type_of_oid != QUERY_OID)
359                 return NDIS_STATUS_NOT_ACCEPTED;
360         if (poid_par_priv->information_buf_len >= sizeof(u32)) {
361                 ulInfo |= 0x0100; /* WIRELESS_MODE_B */
362                 ulInfo |= 0x0200; /* WIRELESS_MODE_G */
363                 ulInfo |= 0x0400; /* WIRELESS_MODE_A */
364                 *(u32 *) poid_par_priv->information_buf = ulInfo;
365                 *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
366         } else
367                 return NDIS_STATUS_INVALID_LENGTH;
368         return NDIS_STATUS_SUCCESS;
369 }
370
371 uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv)
372 {
373         if (poid_par_priv->type_of_oid != QUERY_OID)
374                 return NDIS_STATUS_NOT_ACCEPTED;
375         return NDIS_STATUS_SUCCESS;
376 }
377
378 uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv)
379 {
380         if (poid_par_priv->type_of_oid != QUERY_OID)
381                 return NDIS_STATUS_NOT_ACCEPTED;
382         return NDIS_STATUS_SUCCESS;
383 }
384
385
386 uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv)
387 {
388         return NDIS_STATUS_SUCCESS;
389 }
390
391 uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv
392                                                    *poid_par_priv)
393 {
394         return NDIS_STATUS_SUCCESS;
395 }
396
397 uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv
398                                              *poid_par_priv)
399 {
400         if (poid_par_priv->type_of_oid != QUERY_OID)
401                 return NDIS_STATUS_NOT_ACCEPTED;
402         return NDIS_STATUS_SUCCESS;
403 }
404
405 uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv
406                                               *poid_par_priv)
407 {
408         return NDIS_STATUS_SUCCESS;
409 }
410
411 uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv
412                                                       *poid_par_priv)
413 {
414         if (poid_par_priv->type_of_oid != QUERY_OID)
415                 return NDIS_STATUS_NOT_ACCEPTED;
416         return NDIS_STATUS_SUCCESS;
417 }
418
419 uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv*
420                                               poid_par_priv)
421 {
422         return NDIS_STATUS_SUCCESS;
423 }
424
425 uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv)
426 {
427         return NDIS_STATUS_SUCCESS;
428 }
429
430 uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv)
431 {
432         if (poid_par_priv->type_of_oid != SET_OID)
433                 return NDIS_STATUS_NOT_ACCEPTED;
434         return NDIS_STATUS_SUCCESS;
435 }
436
437 uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv*
438                                              poid_par_priv)
439 {
440         uint status = NDIS_STATUS_SUCCESS;
441         struct _adapter *Adapter = (struct _adapter *)
442                         (poid_par_priv->adapter_context);
443
444         if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
445                 return NDIS_STATUS_NOT_ACCEPTED;
446         if (poid_par_priv->information_buf_len ==
447            (sizeof(unsigned long) * 3)) {
448                 if (!r8712_setrfreg_cmd(Adapter,
449                         *(unsigned char *)poid_par_priv->information_buf,
450                         (unsigned long)(*((unsigned long *)
451                                         poid_par_priv->information_buf + 2))))
452                         status = NDIS_STATUS_NOT_ACCEPTED;
453         } else
454                 status = NDIS_STATUS_INVALID_LENGTH;
455         return status;
456 }
457
458 uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv)
459 {
460         uint status = NDIS_STATUS_SUCCESS;
461         struct _adapter *Adapter = (struct _adapter *)
462                         (poid_par_priv->adapter_context);
463
464         if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */
465                 return NDIS_STATUS_NOT_ACCEPTED;
466         if (poid_par_priv->information_buf_len == (sizeof(unsigned long)*3)) {
467                 if (Adapter->mppriv.act_in_progress == true)
468                         status = NDIS_STATUS_NOT_ACCEPTED;
469                 else {
470                         /* init workparam */
471                         Adapter->mppriv.act_in_progress = true;
472                         Adapter->mppriv.workparam.bcompleted = false;
473                         Adapter->mppriv.workparam.act_type = MPT_READ_RF;
474                         Adapter->mppriv.workparam.io_offset = *(unsigned long *)
475                                                 poid_par_priv->information_buf;
476                         Adapter->mppriv.workparam.io_value = 0xcccccccc;
477
478                 /* RegOffsetValue       - The offset of RF register to read.
479                  * RegDataWidth - The data width of RF register to read.
480                  * RegDataValue - The value to read.
481                  * RegOffsetValue = *((unsigned long *)InformationBuffer);
482                  * RegDataWidth = *((unsigned long *)InformationBuffer+1);
483                  * RegDataValue =  *((unsigned long *)InformationBuffer+2);
484                  */
485                         if (!r8712_getrfreg_cmd(Adapter,
486                             *(unsigned char *)poid_par_priv->information_buf,
487                             (unsigned char *)&Adapter->mppriv.workparam.
488                             io_value))
489                                 status = NDIS_STATUS_NOT_ACCEPTED;
490                 }
491         } else
492                 status = NDIS_STATUS_INVALID_LENGTH;
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 = (struct _adapter *)
506                                      (poid_par_priv->adapter_context);
507         struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
508         u32 ulInfo;
509
510         if (poid_par_priv->type_of_oid != QUERY_OID)
511                 return NDIS_STATUS_NOT_ACCEPTED;
512         /* nStatus==0   CheckingStatus
513          * nStatus==1   Associated
514          * nStatus==2   AdHocMode
515          * nStatus==3   NotAssociated
516          */
517         if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
518                 ulInfo = CHECKINGSTATUS;
519         else if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
520                 ulInfo = ASSOCIATED;
521         else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)
522                 ulInfo = ADHOCMODE;
523         else
524                 ulInfo = NOTASSOCIATED ;
525         *(u32 *)poid_par_priv->information_buf = ulInfo;
526         *poid_par_priv->bytes_rw =  poid_par_priv->information_buf_len;
527         return NDIS_STATUS_SUCCESS;
528 }
529
530 uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv)
531 {
532         if (poid_par_priv->type_of_oid != SET_OID)
533                 return NDIS_STATUS_NOT_ACCEPTED;
534         return NDIS_STATUS_SUCCESS;
535 }