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