Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sme_native.c
Go to the documentation of this file.
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"
19 
20 static const unsigned char wildcard_address[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
21 
22 int
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
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 */
57 
58 #ifdef CSR_SUPPORT_WEXT
60 #endif
61 
62 
63  func_exit();
64 } /* uf_sme_deinit() */
65 
66 
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 
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,
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 
143 
144  return 0;
145 }
146 
147 int
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
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;
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
211  const u8 *sig_packed, int sig_len,
212  const bulk_data_param_t *bulkdata,
213  int dir)
214 {
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",
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",
274  return;
275  }
276  }
277 
278  unifi_trace(priv, UDBG3, "sme_native_log_event: signal 0x%.4X for %d\n",
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;
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
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
387 {
388 
389 } /* unifi_ta_indicate_sampling() */
390 
391 
392 void
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
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
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;
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",
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  */
533  unifi_mlme_copy_reply_and_wakeup_client(pcli, &signal, signal_len, bulkdata);
534  break;
535 
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
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