wl12xx: add driver
[linux-2.6.git] / drivers / net / wireless / wl12xx / acx.c
1 #include "acx.h"
2
3 #include <linux/module.h>
4 #include <linux/crc7.h>
5 #include <linux/spi/spi.h>
6
7 #include "wl12xx.h"
8 #include "wl12xx_80211.h"
9 #include "reg.h"
10 #include "spi.h"
11 #include "ps.h"
12
13 int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
14                            u8 mgt_rate, u8 mgt_mod)
15 {
16         int ret;
17         struct acx_fw_gen_frame_rates rates;
18
19         wl12xx_debug(DEBUG_ACX, "acx frame rates");
20
21         rates.header.id = ACX_FW_GEN_FRAME_RATES;
22         rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
23                 sizeof(struct acx_header);
24
25         rates.tx_ctrl_frame_rate = ctrl_rate;
26         rates.tx_ctrl_frame_mod = ctrl_mod;
27         rates.tx_mgt_frame_rate = mgt_rate;
28         rates.tx_mgt_frame_mod = mgt_mod;
29
30         ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
31         if (ret < 0) {
32                 wl12xx_error("Failed to set FW rates and modulation");
33                 return ret;
34         }
35
36         return 0;
37 }
38
39
40 int wl12xx_acx_station_id(struct wl12xx *wl)
41 {
42         int ret, i;
43         struct dot11_station_id mac;
44
45         wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
46
47         mac.header.id = DOT11_STATION_ID;
48         mac.header.len = sizeof(mac) - sizeof(struct acx_header);
49
50         for (i = 0; i < ETH_ALEN; i++)
51                 mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
52
53         ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
54         if (ret < 0)
55                 return ret;
56
57         return 0;
58 }
59
60 int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
61 {
62         struct acx_dot11_default_key default_key;
63         int ret;
64
65         wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
66
67         default_key.header.id = DOT11_DEFAULT_KEY;
68         default_key.header.len = sizeof(default_key) -
69                 sizeof(struct acx_header);
70
71         default_key.id = key_id;
72
73         ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
74         if (ret < 0) {
75                 wl12xx_error("Couldnt set default key");
76                 return ret;
77         }
78
79         wl->default_key = key_id;
80
81         return 0;
82 }
83
84 int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
85 {
86         struct acx_wake_up_condition wake_up;
87
88         wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
89
90         wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
91         wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
92
93         wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
94         wake_up.listen_interval = listen_interval;
95
96         return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
97 }
98
99 int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
100 {
101         int ret;
102         struct acx_sleep_auth auth;
103
104         wl12xx_debug(DEBUG_ACX, "acx sleep auth");
105
106         auth.header.id = ACX_SLEEP_AUTH;
107         auth.header.len = sizeof(auth) - sizeof(struct acx_header);
108
109         auth.sleep_auth = sleep_auth;
110
111         ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
112         if (ret < 0)
113                 return ret;
114
115         return 0;
116 }
117
118 int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
119 {
120         struct wl12xx_command cmd;
121         struct acx_revision *rev;
122         int ret;
123
124         wl12xx_debug(DEBUG_ACX, "acx fw rev");
125
126         memset(&cmd, 0, sizeof(cmd));
127
128         ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
129         if (ret < 0) {
130                 wl12xx_warning("ACX_FW_REV interrogate failed");
131                 return ret;
132         }
133
134         rev = (struct acx_revision *) &cmd.parameters;
135
136         /* be careful with the buffer sizes */
137         strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
138
139         /*
140          * if the firmware version string is exactly
141          * sizeof(rev->fw_version) long or fw_len is less than
142          * sizeof(rev->fw_version) it won't be null terminated
143          */
144         buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
145
146         return 0;
147 }
148
149 int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
150 {
151         struct acx_current_tx_power ie;
152         int ret;
153
154         wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
155
156         if (power < 0 || power > 25)
157                 return -EINVAL;
158
159         memset(&ie, 0, sizeof(ie));
160
161         ie.header.id = DOT11_CUR_TX_PWR;
162         ie.header.len = sizeof(ie) - sizeof(struct acx_header);
163         ie.current_tx_power = power * 10;
164
165         ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
166         if (ret < 0) {
167                 wl12xx_warning("configure of tx power failed: %d", ret);
168                 return ret;
169         }
170
171         return 0;
172 }
173
174 int wl12xx_acx_feature_cfg(struct wl12xx *wl)
175 {
176         struct acx_feature_config feature;
177         int ret;
178
179         wl12xx_debug(DEBUG_ACX, "acx feature cfg");
180
181         memset(&feature, 0, sizeof(feature));
182
183         feature.header.id = ACX_FEATURE_CFG;
184         feature.header.len = sizeof(feature) - sizeof(struct acx_header);
185
186         /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
187         feature.data_flow_options = 0;
188         feature.options = 0;
189
190         ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
191         if (ret < 0)
192                 wl12xx_error("Couldnt set HW encryption");
193
194         return ret;
195 }
196
197 int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
198 {
199         struct wl12xx_command cmd;
200         int ret;
201
202         wl12xx_debug(DEBUG_ACX, "acx mem map");
203
204         ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
205         if (ret < 0)
206                 return ret;
207         else if (cmd.status != CMD_STATUS_SUCCESS)
208                 return -EIO;
209
210         memcpy(mem_map, &cmd.parameters, len);
211
212         return 0;
213 }
214
215 int wl12xx_acx_data_path_params(struct wl12xx *wl,
216                                 struct acx_data_path_params_resp *data_path)
217 {
218         struct acx_data_path_params params;
219         struct wl12xx_command cmd;
220         int ret;
221
222         wl12xx_debug(DEBUG_ACX, "acx data path params");
223
224         params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
225         params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
226
227         params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
228         params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
229
230         params.tx_complete_threshold = 1;
231
232         params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
233
234         params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
235
236         params.header.id = ACX_DATA_PATH_PARAMS;
237         params.header.len = sizeof(params) - sizeof(struct acx_header);
238
239         ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
240         if (ret < 0)
241                 return ret;
242
243
244         ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
245                                      sizeof(struct acx_data_path_params_resp),
246                                      &cmd);
247
248         if (ret < 0) {
249                 wl12xx_warning("failed to read data path parameters: %d", ret);
250                 return ret;
251         } else if (cmd.status != CMD_STATUS_SUCCESS) {
252                 wl12xx_warning("data path parameter acx status failed");
253                 return -EIO;
254         }
255
256         memcpy(data_path, &cmd.parameters, sizeof(*data_path));
257
258         return 0;
259 }
260
261 int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
262 {
263         struct rx_msdu_lifetime msdu_lifetime;
264         int ret;
265
266         wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
267
268         msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
269         msdu_lifetime.header.len = sizeof(msdu_lifetime) -
270                 sizeof(struct acx_header);
271         msdu_lifetime.lifetime = life_time;
272
273         ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
274         if (ret < 0) {
275                 wl12xx_warning("failed to set rx msdu life time: %d", ret);
276                 return ret;
277         }
278
279         return 0;
280 }
281
282 int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
283 {
284         struct acx_rx_config rx_config;
285         int ret;
286
287         wl12xx_debug(DEBUG_ACX, "acx rx config");
288
289         rx_config.header.id = ACX_RX_CFG;
290         rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
291         rx_config.config_options = config;
292         rx_config.filter_options = filter;
293
294         ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
295         if (ret < 0) {
296                 wl12xx_warning("failed to set rx config: %d", ret);
297                 return ret;
298         }
299
300         return 0;
301 }
302
303 int wl12xx_acx_pd_threshold(struct wl12xx *wl)
304 {
305         struct acx_packet_detection packet_detection;
306         int ret;
307
308         wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
309
310         /* FIXME: threshold value not set */
311         packet_detection.header.id = ACX_PD_THRESHOLD;
312         packet_detection.header.len = sizeof(packet_detection) -
313                 sizeof(struct acx_header);
314
315         ret = wl12xx_cmd_configure(wl, &packet_detection,
316                                    sizeof(packet_detection));
317         if (ret < 0) {
318                 wl12xx_warning("failed to set pd threshold: %d", ret);
319                 return ret;
320         }
321
322         return 0;
323 }
324
325 int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
326 {
327         struct acx_slot slot;
328         int ret;
329
330         wl12xx_debug(DEBUG_ACX, "acx slot");
331
332         slot.header.id = ACX_SLOT;
333         slot.header.len = sizeof(slot) - sizeof(struct acx_header);
334
335         slot.wone_index = STATION_WONE_INDEX;
336         slot.slot_time = slot_time;
337
338         ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
339         if (ret < 0) {
340                 wl12xx_warning("failed to set slot time: %d", ret);
341                 return ret;
342         }
343
344         return 0;
345 }
346
347 int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
348 {
349         struct multicast_grp_addr_start multicast;
350         int ret;
351
352         wl12xx_debug(DEBUG_ACX, "acx group address tbl");
353
354         /* MAC filtering */
355         multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
356         multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
357
358         multicast.enabled = 0;
359         multicast.num_groups = 0;
360         memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
361
362         ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
363         if (ret < 0) {
364                 wl12xx_warning("failed to set group addr table: %d", ret);
365                 return ret;
366         }
367
368         return 0;
369 }
370
371 int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
372 {
373         struct acx_rx_timeout rx_timeout;
374         int ret;
375
376         wl12xx_debug(DEBUG_ACX, "acx service period timeout");
377
378         /* RX timeout */
379         rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
380         rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
381
382         rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
383         rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
384
385         ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
386         if (ret < 0) {
387                 wl12xx_warning("failed to set service period timeout: %d",
388                                ret);
389                 return ret;
390         }
391
392         return 0;
393 }
394
395 int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
396 {
397         struct acx_rts_threshold rts;
398         int ret;
399
400         wl12xx_debug(DEBUG_ACX, "acx rts threshold");
401
402         rts.header.id = DOT11_RTS_THRESHOLD;
403         rts.header.len = sizeof(rts) - sizeof(struct acx_header);
404
405         rts.threshold = rts_threshold;
406
407         ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
408         if (ret < 0) {
409                 wl12xx_warning("failed to set rts threshold: %d", ret);
410                 return ret;
411         }
412
413         return 0;
414 }
415
416 int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
417 {
418         struct acx_beacon_filter_option beacon_filter;
419         int ret;
420
421         wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
422
423         beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
424         beacon_filter.header.len = sizeof(beacon_filter) -
425                 sizeof(struct acx_header);
426
427         beacon_filter.enable = 0;
428         beacon_filter.max_num_beacons = 0;
429
430         ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
431         if (ret < 0) {
432                 wl12xx_warning("failed to set beacon filter opt: %d", ret);
433                 return ret;
434         }
435
436         return 0;
437 }
438
439 int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
440 {
441         struct acx_beacon_filter_ie_table ie_table;
442         int ret;
443
444         wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
445
446         ie_table.header.id = ACX_BEACON_FILTER_TABLE;
447         ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
448
449         ie_table.num_ie = 0;
450         memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
451
452         ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
453         if (ret < 0) {
454                 wl12xx_warning("failed to set beacon filter table: %d", ret);
455                 return ret;
456         }
457
458         return 0;
459 }
460
461 int wl12xx_acx_sg_enable(struct wl12xx *wl)
462 {
463         struct acx_bt_wlan_coex pta;
464         int ret;
465
466         wl12xx_debug(DEBUG_ACX, "acx sg enable");
467
468         pta.header.id = ACX_SG_ENABLE;
469         pta.header.len = sizeof(pta) - sizeof(struct acx_header);
470
471         pta.enable = SG_ENABLE;
472
473         ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
474         if (ret < 0) {
475                 wl12xx_warning("failed to set softgemini enable: %d", ret);
476                 return ret;
477         }
478
479         return 0;
480 }
481
482 int wl12xx_acx_sg_cfg(struct wl12xx *wl)
483 {
484         struct acx_bt_wlan_coex_param param;
485         int ret;
486
487         wl12xx_debug(DEBUG_ACX, "acx sg cfg");
488
489         /* BT-WLAN coext parameters */
490         param.header.id = ACX_SG_CFG;
491         param.header.len = sizeof(param) - sizeof(struct acx_header);
492
493         param.min_rate = RATE_INDEX_24MBPS;
494         param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
495         param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
496         param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
497         param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
498         param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
499         param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
500         param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
501         param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
502         param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
503         param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
504         param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
505         param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
506         param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
507         param.antenna_type = PTA_ANTENNA_TYPE_DEF;
508         param.signal_type = PTA_SIGNALING_TYPE_DEF;
509         param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
510         param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
511         param.max_cts = PTA_MAX_NUM_CTS_DEF;
512         param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
513         param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
514         param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
515         param.wlan_elp_hp = PTA_ELP_HP_DEF;
516         param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
517         param.ack_mode_dual_ant = PTA_ACK_MODE_DEF;
518         param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
519         param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
520         param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
521
522         ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
523         if (ret < 0) {
524                 wl12xx_warning("failed to set sg config: %d", ret);
525                 return ret;
526         }
527
528         return 0;
529 }
530
531 int wl12xx_acx_cca_threshold(struct wl12xx *wl)
532 {
533         struct acx_energy_detection detection;
534         int ret;
535
536         wl12xx_debug(DEBUG_ACX, "acx cca threshold");
537
538         detection.header.id = ACX_CCA_THRESHOLD;
539         detection.header.len = sizeof(detection) - sizeof(struct acx_header);
540
541         detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
542         detection.tx_energy_detection = 0;
543
544         ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
545         if (ret < 0) {
546                 wl12xx_warning("failed to set cca threshold: %d", ret);
547                 return ret;
548         }
549
550         return 0;
551 }
552
553 int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
554 {
555         struct acx_beacon_broadcast bb;
556         int ret;
557
558         wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
559
560         bb.header.id = ACX_BCN_DTIM_OPTIONS;
561         bb.header.len = sizeof(bb) - sizeof(struct acx_header);
562
563         bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
564         bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
565         bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
566         bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
567
568         ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
569         if (ret < 0) {
570                 wl12xx_warning("failed to set rx config: %d", ret);
571                 return ret;
572         }
573
574         return 0;
575 }
576
577 int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
578 {
579         struct acx_aid acx_aid;
580         int ret;
581
582         wl12xx_debug(DEBUG_ACX, "acx aid");
583
584         acx_aid.header.id = ACX_AID;
585         acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
586
587         acx_aid.aid = aid;
588
589         ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
590         if (ret < 0) {
591                 wl12xx_warning("failed to set aid: %d", ret);
592                 return ret;
593         }
594
595         return 0;
596 }
597
598 int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
599 {
600         struct acx_event_mask mask;
601         int ret;
602
603         wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
604
605         mask.header.id = ACX_EVENT_MBOX_MASK;
606         mask.header.len = sizeof(mask) - sizeof(struct acx_header);
607
608         /* high event mask is unused */
609         mask.high_event_mask = 0xffffffff;
610
611         mask.event_mask = event_mask;
612
613         ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
614         if (ret < 0) {
615                 wl12xx_warning("failed to set aid: %d", ret);
616                 return ret;
617         }
618
619         return 0;
620 }
621
622 int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
623 {
624         struct acx_preamble ie;
625         int ret;
626
627         wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
628
629         memset(&ie, 0, sizeof(ie));
630
631         ie.header.id = ACX_PREAMBLE_TYPE;
632         ie.header.len = sizeof(ie) - sizeof(struct acx_header);
633         ie.preamble = preamble;
634         ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
635         if (ret < 0) {
636                 wl12xx_warning("Setting of preamble failed: %d", ret);
637                 return ret;
638         }
639         return 0;
640 }
641
642 int wl12xx_acx_cts_protect(struct wl12xx *wl,
643                            enum acx_ctsprotect_type ctsprotect)
644 {
645         struct acx_ctsprotect ie;
646         int ret;
647
648         wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
649
650         memset(&ie, 0, sizeof(ie));
651
652         ie.header.id = ACX_CTS_PROTECTION;
653         ie.header.len = sizeof(ie) - sizeof(struct acx_header);
654         ie.ctsprotect = ctsprotect;
655         ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
656         if (ret < 0) {
657                 wl12xx_warning("Setting of ctsprotect failed: %d", ret);
658                 return ret;
659         }
660         return 0;
661 }
662
663 int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
664 {
665         struct wl12xx_command *answer;
666         int ret;
667
668         wl12xx_debug(DEBUG_ACX, "acx statistics");
669
670         answer = kmalloc(sizeof(*answer), GFP_KERNEL);
671         if (!answer) {
672                 wl12xx_warning("could not allocate memory for acx statistics");
673                 ret = -ENOMEM;
674                 goto out;
675         }
676
677         ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
678                                      answer);
679         if (ret < 0) {
680                 wl12xx_warning("acx statistics failed: %d", ret);
681                 goto out;
682         }
683
684         memcpy(stats, answer->parameters, sizeof(*stats));
685
686 out:
687         kfree(answer);
688         return ret;
689 }