Merge branch 'next/fixes-non-critical' into HEAD
[cascardo/linux.git] / drivers / staging / csr / sme_native.c
1 /*
2  * ***************************************************************************
3  *
4  *  FILE:     sme_native.c
5  *
6  * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
7  *
8  * Refer to LICENSE.txt included with this source code for details on
9  * the license terms.
10  *
11  * ***************************************************************************
12  */
13
14 #include <linux/netdevice.h>
15 #include <linux/version.h>
16 #include "unifi_priv.h"
17 #include "csr_wifi_hip_unifi.h"
18 #include "csr_wifi_hip_conversions.h"
19
20 static const unsigned char wildcard_address[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
21
22 int
23 uf_sme_init(unifi_priv_t *priv)
24 {
25     func_enter();
26
27     sema_init(&priv->mlme_blocking_mutex, 1);
28
29 #ifdef CSR_SUPPORT_WEXT
30     {
31         int r = uf_init_wext_interface(priv);
32         if (r != 0) {
33             func_exit();
34             return r;
35         }
36     }
37 #endif
38
39
40
41     func_exit();
42     return 0;
43 } /* uf_sme_init() */
44
45
46 void
47 uf_sme_deinit(unifi_priv_t *priv)
48 {
49
50     func_enter();
51
52     /* Free memory allocated for the scan table */
53 /*    unifi_clear_scan_table(priv); */
54
55     /* Cancel any pending workqueue tasks */
56     flush_workqueue(priv->unifi_workqueue);
57
58 #ifdef CSR_SUPPORT_WEXT
59     uf_deinit_wext_interface(priv);
60 #endif
61
62
63     func_exit();
64 } /* uf_sme_deinit() */
65
66
67 int sme_mgt_wifi_on(unifi_priv_t *priv)
68 {
69     int r,i;
70     s32 csrResult;
71
72     if (priv == NULL) {
73         return -EINVAL;
74     }
75     /* Initialize the interface mode to None */
76     for (i=0; i<CSR_WIFI_NUM_INTERFACES; i++) {
77         priv->interfacePriv[i]->interfaceMode = 0;
78     }
79
80     /* Set up interface mode so that get_packet_priority() can
81      * select the right QOS priority when WMM is enabled.
82      */
83     priv->interfacePriv[0]->interfaceMode = CSR_WIFI_ROUTER_CTRL_MODE_STA;
84
85     r = uf_request_firmware_files(priv, UNIFI_FW_STA);
86     if (r) {
87         unifi_error(priv, "sme_mgt_wifi_on: Failed to get f/w\n");
88         return r;
89     }
90
91     /*
92      * The request to initialise UniFi might come while UniFi is running.
93      * We need to block all I/O activity until the reset completes, otherwise
94      * an SDIO error might occur resulting an indication to the SME which
95      * makes it think that the initialisation has failed.
96      */
97     priv->bh_thread.block_thread = 1;
98
99     /* Power on UniFi */
100     CsrSdioClaim(priv->sdio);
101     csrResult = CsrSdioPowerOn(priv->sdio);
102     CsrSdioRelease(priv->sdio);
103     if(csrResult != CSR_RESULT_SUCCESS && csrResult != CSR_SDIO_RESULT_NOT_RESET) {
104         return -EIO;
105     }
106
107     if (csrResult == CSR_RESULT_SUCCESS) {
108         /* Initialise UniFi hardware */
109         r = uf_init_hw(priv);
110         if (r) {
111             return r;
112         }
113     }
114
115     /* Re-enable the I/O thread */
116     priv->bh_thread.block_thread = 0;
117
118     /* Disable deep sleep signalling during the firmware initialisation, to
119      * prevent the wakeup mechanism raising the SDIO clock beyond INIT before
120      * the first MLME-RESET.ind. It gets re-enabled at the CONNECTED.ind,
121      * immediately after the MLME-RESET.ind
122      */
123     csrResult = unifi_configure_low_power_mode(priv->card,
124                                            UNIFI_LOW_POWER_DISABLED,
125                                            UNIFI_PERIODIC_WAKE_HOST_DISABLED);
126     if (csrResult != CSR_RESULT_SUCCESS) {
127         unifi_warning(priv,
128                       "sme_mgt_wifi_on: unifi_configure_low_power_mode() returned an error\n");
129     }
130
131
132     /* Start the I/O thread */
133     CsrSdioClaim(priv->sdio);
134     r = uf_init_bh(priv);
135     if (r) {
136         CsrSdioPowerOff(priv->sdio);
137         CsrSdioRelease(priv->sdio);
138         return r;
139     }
140     CsrSdioRelease(priv->sdio);
141
142     priv->init_progress = UNIFI_INIT_FW_DOWNLOADED;
143
144     return 0;
145 }
146
147 int
148 sme_sys_suspend(unifi_priv_t *priv)
149 {
150     const int interfaceNum = 0;     /* FIXME */
151     CsrResult csrResult;
152
153     /* Abort any pending requests. */
154     uf_abort_mlme(priv);
155
156     /* Allow our mlme request to go through. */
157     priv->io_aborted = 0;
158
159     /* Send MLME-RESET.req to UniFi. */
160     unifi_reset_state(priv, priv->netdev[interfaceNum]->dev_addr, 0);
161
162     /* Stop the network traffic */
163     netif_carrier_off(priv->netdev[interfaceNum]);
164
165     /* Put UniFi to deep sleep */
166     CsrSdioClaim(priv->sdio);
167     csrResult = unifi_force_low_power_mode(priv->card);
168     CsrSdioRelease(priv->sdio);
169
170     return 0;
171 } /* sme_sys_suspend() */
172
173
174 int
175 sme_sys_resume(unifi_priv_t *priv)
176 {
177 #ifdef CSR_SUPPORT_WEXT
178     /* Send disconnect event so clients will re-initialise connection. */
179     memset(priv->wext_conf.current_ssid, 0, UNIFI_MAX_SSID_LEN);
180     memset((void*)priv->wext_conf.current_bssid, 0, ETH_ALEN);
181     priv->wext_conf.capability = 0;
182     wext_send_disassoc_event(priv);
183 #endif
184     return 0;
185 } /* sme_sys_resume() */
186
187
188 /*
189  * ---------------------------------------------------------------------------
190  *  sme_native_log_event
191  *
192  *      Callback function to be registered as the SME event callback.
193  *      Copies the signal content into a new udi_log_t struct and adds
194  *      it to the read queue for the SME client.
195  *
196  *  Arguments:
197  *      arg             This is the value given to unifi_add_udi_hook, in
198  *                      this case a pointer to the client instance.
199  *      signal          Pointer to the received signal.
200  *      signal_len      Size of the signal structure in bytes.
201  *      bulkdata        Pointers to any associated bulk data.
202  *      dir             Direction of the signal. Zero means from host,
203  *                      non-zero means to host.
204  *
205  *  Returns:
206  *      None.
207  * ---------------------------------------------------------------------------
208  */
209 void
210 sme_native_log_event(ul_client_t *pcli,
211                      const u8 *sig_packed, int sig_len,
212                      const bulk_data_param_t *bulkdata,
213                      int dir)
214 {
215     unifi_priv_t *priv;
216     udi_log_t *logptr;
217     u8 *p;
218     int i, r;
219     int signal_len;
220     int total_len;
221     udi_msg_t *msgptr;
222     CSR_SIGNAL signal;
223     ul_client_t *client = pcli;
224
225     func_enter();
226
227     if (client == NULL) {
228         unifi_error(NULL, "sme_native_log_event: client has exited\n");
229         return;
230     }
231
232     priv = uf_find_instance(client->instance);
233     if (!priv) {
234         unifi_error(priv, "invalid priv\n");
235         return;
236     }
237
238     /* Just a sanity check */
239     if ((sig_packed == NULL) || (sig_len <= 0)) {
240         return;
241     }
242
243     /* Get the unpacked signal */
244     r = read_unpack_signal(sig_packed, &signal);
245     if (r == 0) {
246         signal_len = SigGetSize(&signal);
247     } else {
248         u16 receiver_id = CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sig_packed) + sizeof(u16)) & 0xFF00;
249
250         /* The control indications are 1 byte, pass them to client. */
251         if (sig_len == 1) {
252             unifi_trace(priv, UDBG5,
253                         "Control indication (0x%x) for native SME.\n",
254                         *sig_packed);
255
256             *(u8*)&signal = *sig_packed;
257             signal_len = sig_len;
258         } else if (receiver_id == 0) {
259             /*
260              * Also "unknown" signals with a ReceiverId of 0 are passed to the client
261              * without unpacking. (This is a code size optimisation to allow signals
262              * that the driver not interested in to be dropped from the unpack code).
263              */
264             unifi_trace(priv, UDBG5,
265                         "Signal 0x%.4X with ReceiverId 0 for native SME.\n",
266                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
267
268             *(u8*)&signal = *sig_packed;
269             signal_len = sig_len;
270         } else {
271             unifi_error(priv,
272                         "sme_native_log_event - Received unknown signal 0x%.4X.\n",
273                         CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
274             return;
275         }
276     }
277
278     unifi_trace(priv, UDBG3, "sme_native_log_event: signal 0x%.4X for %d\n",
279                 signal.SignalPrimitiveHeader.SignalId,
280                 client->client_id);
281
282     total_len = signal_len;
283     /* Calculate the buffer we need to store signal plus bulk data */
284     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
285         total_len += bulkdata->d[i].data_length;
286     }
287
288     /* Allocate log structure plus actual signal. */
289     logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
290
291     if (logptr == NULL) {
292         unifi_error(priv,
293                     "Failed to allocate %d bytes for a UDI log record\n",
294                     sizeof(udi_log_t) + total_len);
295         return;
296     }
297
298     /* Fill in udi_log struct */
299     INIT_LIST_HEAD(&logptr->q);
300     msgptr = &logptr->msg;
301     msgptr->length = sizeof(udi_msg_t) + total_len;
302     msgptr->timestamp = jiffies_to_msecs(jiffies);
303     msgptr->direction = dir;
304     msgptr->signal_length = signal_len;
305
306     /* Copy signal and bulk data to the log */
307     p = (u8 *)(msgptr + 1);
308     memcpy(p, &signal, signal_len);
309     p += signal_len;
310
311     /* Append any bulk data */
312     for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++) {
313         int len = bulkdata->d[i].data_length;
314
315         /*
316          * Len here might not be the same as the length in the bulk data slot.
317          * The slot length will always be even, but len could be odd.
318          */
319         if (len > 0) {
320             if (bulkdata->d[i].os_data_ptr) {
321                 memcpy(p, bulkdata->d[i].os_data_ptr, len);
322             } else {
323                 memset(p, 0, len);
324             }
325             p += len;
326         }
327     }
328
329     /* Add to tail of log queue */
330     down(&client->udi_sem);
331     list_add_tail(&logptr->q, &client->udi_log);
332     up(&client->udi_sem);
333
334     /* Wake any waiting user process */
335     wake_up_interruptible(&client->udi_wq);
336
337     func_exit();
338
339 } /* sme_native_log_event() */
340
341
342 /*
343  * ---------------------------------------------------------------------------
344  *  unifi_ta_indicate_protocol
345  *
346  *      Report that a packet of a particular type has been seen
347  *
348  *  Arguments:
349  *      drv_priv        The device context pointer passed to ta_init.
350  *      protocol        The protocol type enum value.
351  *      direction       Whether the packet was a tx or rx.
352  *      src_addr        The source MAC address from the data packet.
353  *
354  *  Returns:
355  *      None.
356  *
357  *  Notes:
358  *      We defer the actual sending to a background workqueue,
359  *      see uf_ta_ind_wq().
360  * ---------------------------------------------------------------------------
361  */
362 void
363 unifi_ta_indicate_protocol(void *ospriv,
364                            CsrWifiRouterCtrlTrafficPacketType packet_type,
365                            CsrWifiRouterCtrlProtocolDirection direction,
366                            const CsrWifiMacAddress *src_addr)
367 {
368
369 } /* unifi_ta_indicate_protocol */
370
371 /*
372  * ---------------------------------------------------------------------------
373  * unifi_ta_indicate_sampling
374  *
375  *      Send the TA sampling information to the SME.
376  *
377  *  Arguments:
378  *      drv_priv        The device context pointer passed to ta_init.
379  *      stats           The TA sampling data to send.
380  *
381  *  Returns:
382  *      None.
383  * ---------------------------------------------------------------------------
384  */
385 void
386 unifi_ta_indicate_sampling(void *ospriv, CsrWifiRouterCtrlTrafficStats *stats)
387 {
388
389 } /* unifi_ta_indicate_sampling() */
390
391
392 void
393 unifi_ta_indicate_l4stats(void *ospriv,
394                             u32 rxTcpThroughput,
395                             u32 txTcpThroughput,
396                             u32 rxUdpThroughput,
397                             u32 txUdpThroughput)
398 {
399
400 } /* unifi_ta_indicate_l4stats() */
401
402 /*
403  * ---------------------------------------------------------------------------
404  * uf_native_process_udi_signal
405  *
406  *      Process interesting signals from the UDI interface.
407  *
408  *  Arguments:
409  *      pcli            A pointer to the client instance.
410  *      signal          Pointer to the received signal.
411  *      signal_len      Size of the signal structure in bytes.
412  *      bulkdata        Pointers to any associated bulk data.
413  *      dir             Direction of the signal. Zero means from host,
414  *                      non-zero means to host.
415  *
416  *
417  *  Returns:
418  *      None.
419  * ---------------------------------------------------------------------------
420  */
421 void
422 uf_native_process_udi_signal(ul_client_t *pcli,
423                              const u8 *packed_signal, int packed_signal_len,
424                              const bulk_data_param_t *bulkdata, int dir)
425 {
426
427 } /* uf_native_process_udi_signal() */
428
429
430 /*
431  * ---------------------------------------------------------------------------
432  *  sme_native_mlme_event_handler
433  *
434  *      Callback function to be used as the udi_event_callback when registering
435  *      as a client.
436  *      This function implements a blocking request-reply interface for WEXT.
437  *      To use it, a client specifies this function as the udi_event_callback
438  *      to ul_register_client(). The signal dispatcher in
439  *      unifi_receive_event() will call this function to deliver a signal.
440  *
441  *  Arguments:
442  *      pcli            Pointer to the client instance.
443  *      signal          Pointer to the received signal.
444  *      signal_len      Size of the signal structure in bytes.
445  *      bulkdata        Pointer to structure containing any associated bulk data.
446  *      dir             Direction of the signal. Zero means from host,
447  *                      non-zero means to host.
448  *
449  *  Returns:
450  *      None.
451  * ---------------------------------------------------------------------------
452  */
453 void
454 sme_native_mlme_event_handler(ul_client_t *pcli,
455                               const u8 *sig_packed, int sig_len,
456                               const bulk_data_param_t *bulkdata,
457                               int dir)
458 {
459     CSR_SIGNAL signal;
460     int signal_len;
461     unifi_priv_t *priv = uf_find_instance(pcli->instance);
462     int id, r;
463
464     func_enter();
465
466     /* Just a sanity check */
467     if ((sig_packed == NULL) || (sig_len <= 0)) {
468         return;
469     }
470
471     /* Get the unpacked signal */
472     r = read_unpack_signal(sig_packed, &signal);
473     if (r == 0) {
474         signal_len = SigGetSize(&signal);
475     } else {
476         unifi_error(priv,
477                     "sme_native_mlme_event_handler - Received unknown signal 0x%.4X.\n",
478                     CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed));
479         return;
480     }
481
482     id = signal.SignalPrimitiveHeader.SignalId;
483     unifi_trace(priv, UDBG4, "wext - Process signal 0x%.4X\n", id);
484
485     /*
486      * Take the appropriate action for the signal.
487      */
488     switch (id) {
489         /*
490          * Confirm replies from UniFi.
491          * These all have zero or one CSR_DATAREF member. (FIXME: check this is still true for softmac)
492          */
493         case CSR_MA_PACKET_CONFIRM_ID:
494         case CSR_MLME_RESET_CONFIRM_ID:
495         case CSR_MLME_GET_CONFIRM_ID:
496         case CSR_MLME_SET_CONFIRM_ID:
497         case CSR_MLME_GET_NEXT_CONFIRM_ID:
498         case CSR_MLME_POWERMGT_CONFIRM_ID:
499         case CSR_MLME_SCAN_CONFIRM_ID:
500         case CSR_MLME_HL_SYNC_CONFIRM_ID:
501         case CSR_MLME_MEASURE_CONFIRM_ID:
502         case CSR_MLME_SETKEYS_CONFIRM_ID:
503         case CSR_MLME_DELETEKEYS_CONFIRM_ID:
504         case CSR_MLME_HL_SYNC_CANCEL_CONFIRM_ID:
505         case CSR_MLME_ADD_PERIODIC_CONFIRM_ID:
506         case CSR_MLME_DEL_PERIODIC_CONFIRM_ID:
507         case CSR_MLME_ADD_AUTONOMOUS_SCAN_CONFIRM_ID:
508         case CSR_MLME_DEL_AUTONOMOUS_SCAN_CONFIRM_ID:
509         case CSR_MLME_SET_PACKET_FILTER_CONFIRM_ID:
510         case CSR_MLME_STOP_MEASURE_CONFIRM_ID:
511         case CSR_MLME_PAUSE_AUTONOMOUS_SCAN_CONFIRM_ID:
512         case CSR_MLME_ADD_TRIGGERED_GET_CONFIRM_ID:
513         case CSR_MLME_DEL_TRIGGERED_GET_CONFIRM_ID:
514         case CSR_MLME_ADD_BLACKOUT_CONFIRM_ID:
515         case CSR_MLME_DEL_BLACKOUT_CONFIRM_ID:
516         case CSR_MLME_ADD_RX_TRIGGER_CONFIRM_ID:
517         case CSR_MLME_DEL_RX_TRIGGER_CONFIRM_ID:
518         case CSR_MLME_CONNECT_STATUS_CONFIRM_ID:
519         case CSR_MLME_MODIFY_BSS_PARAMETER_CONFIRM_ID:
520         case CSR_MLME_ADD_TEMPLATE_CONFIRM_ID:
521         case CSR_MLME_CONFIG_QUEUE_CONFIRM_ID:
522         case CSR_MLME_ADD_TSPEC_CONFIRM_ID:
523         case CSR_MLME_DEL_TSPEC_CONFIRM_ID:
524         case CSR_MLME_START_AGGREGATION_CONFIRM_ID:
525         case CSR_MLME_STOP_AGGREGATION_CONFIRM_ID:
526         case CSR_MLME_SM_START_CONFIRM_ID:
527         case CSR_MLME_LEAVE_CONFIRM_ID:
528         case CSR_MLME_SET_TIM_CONFIRM_ID:
529         case CSR_MLME_GET_KEY_SEQUENCE_CONFIRM_ID:
530         case CSR_MLME_SET_CHANNEL_CONFIRM_ID:
531         case CSR_MLME_ADD_MULTICAST_ADDRESS_CONFIRM_ID:
532         case CSR_DEBUG_GENERIC_CONFIRM_ID:
533             unifi_mlme_copy_reply_and_wakeup_client(pcli, &signal, signal_len, bulkdata);
534             break;
535
536         case CSR_MLME_CONNECTED_INDICATION_ID:
537             /* We currently ignore the connected-ind for softmac f/w development */
538             unifi_info(priv, "CSR_MLME_CONNECTED_INDICATION_ID ignored\n");
539             break;
540
541         default:
542             break;
543     }
544
545     func_exit();
546 } /* sme_native_mlme_event_handler() */
547
548
549
550 /*
551  * -------------------------------------------------------------------------
552  *  unifi_reset_state
553  *
554  *      Ensure that a MAC address has been set.
555  *      Send the MLME-RESET signal.
556  *      This must be called at least once before starting to do any
557  *      network activities (e.g. scan, join etc).
558  *
559  * Arguments:
560  *      priv            Pointer to device private context struct
561  *      macaddr         Pointer to chip MAC address.
562  *                      If this is FF:FF:FF:FF:FF:FF it will be replaced
563  *                      with the MAC address from the chip.
564  *      set_default_mib 1 if the f/w must reset the MIB to the default values
565  *                      0 otherwise
566  *
567  * Returns:
568  *      0 on success, an error code otherwise.
569  * -------------------------------------------------------------------------
570  */
571 int
572 unifi_reset_state(unifi_priv_t *priv, unsigned char *macaddr,
573                   unsigned char set_default_mib)
574 {
575     int r = 0;
576
577     func_enter();
578
579 #ifdef CSR_SUPPORT_WEXT
580     /* The reset clears any 802.11 association. */
581     priv->wext_conf.flag_associated = 0;
582 #endif
583
584     func_exit();
585     return r;
586 } /* unifi_reset_state() */
587