2 * ***************************************************************************
6 * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
8 * Refer to LICENSE.txt included with this source code for details on
11 * ***************************************************************************
14 #include <linux/netdevice.h>
15 #include "unifi_priv.h"
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
19 static const unsigned char wildcard_address
[ETH_ALEN
] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
22 uf_sme_init(unifi_priv_t
*priv
)
24 sema_init(&priv
->mlme_blocking_mutex
, 1);
26 #ifdef CSR_SUPPORT_WEXT
28 int r
= uf_init_wext_interface(priv
);
40 uf_sme_deinit(unifi_priv_t
*priv
)
43 /* Free memory allocated for the scan table */
44 /* unifi_clear_scan_table(priv); */
46 /* Cancel any pending workqueue tasks */
47 flush_workqueue(priv
->unifi_workqueue
);
49 #ifdef CSR_SUPPORT_WEXT
50 uf_deinit_wext_interface(priv
);
53 } /* uf_sme_deinit() */
56 int sme_mgt_wifi_on(unifi_priv_t
*priv
)
64 /* Initialize the interface mode to None */
65 for (i
=0; i
<CSR_WIFI_NUM_INTERFACES
; i
++) {
66 priv
->interfacePriv
[i
]->interfaceMode
= 0;
69 /* Set up interface mode so that get_packet_priority() can
70 * select the right QOS priority when WMM is enabled.
72 priv
->interfacePriv
[0]->interfaceMode
= CSR_WIFI_ROUTER_CTRL_MODE_STA
;
74 r
= uf_request_firmware_files(priv
, UNIFI_FW_STA
);
76 unifi_error(priv
, "sme_mgt_wifi_on: Failed to get f/w\n");
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.
86 priv
->bh_thread
.block_thread
= 1;
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
) {
96 if (csrResult
== CSR_RESULT_SUCCESS
) {
97 /* Initialise UniFi hardware */
104 /* Re-enable the I/O thread */
105 priv
->bh_thread
.block_thread
= 0;
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
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
) {
117 "sme_mgt_wifi_on: unifi_configure_low_power_mode() returned an error\n");
121 /* Start the I/O thread */
122 CsrSdioClaim(priv
->sdio
);
123 r
= uf_init_bh(priv
);
125 CsrSdioPowerOff(priv
->sdio
);
126 CsrSdioRelease(priv
->sdio
);
129 CsrSdioRelease(priv
->sdio
);
131 priv
->init_progress
= UNIFI_INIT_FW_DOWNLOADED
;
137 sme_sys_suspend(unifi_priv_t
*priv
)
139 const int interfaceNum
= 0; /* FIXME */
142 /* Abort any pending requests. */
145 /* Allow our mlme request to go through. */
146 priv
->io_aborted
= 0;
148 /* Send MLME-RESET.req to UniFi. */
149 unifi_reset_state(priv
, priv
->netdev
[interfaceNum
]->dev_addr
, 0);
151 /* Stop the network traffic */
152 netif_carrier_off(priv
->netdev
[interfaceNum
]);
154 /* Put UniFi to deep sleep */
155 CsrSdioClaim(priv
->sdio
);
156 csrResult
= unifi_force_low_power_mode(priv
->card
);
157 CsrSdioRelease(priv
->sdio
);
160 } /* sme_sys_suspend() */
164 sme_sys_resume(unifi_priv_t
*priv
)
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
);
174 } /* sme_sys_resume() */
178 * ---------------------------------------------------------------------------
179 * sme_native_log_event
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.
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.
196 * ---------------------------------------------------------------------------
199 sme_native_log_event(ul_client_t
*pcli
,
200 const u8
*sig_packed
, int sig_len
,
201 const bulk_data_param_t
*bulkdata
,
212 ul_client_t
*client
= pcli
;
214 if (client
== NULL
) {
215 unifi_error(NULL
, "sme_native_log_event: client has exited\n");
219 priv
= uf_find_instance(client
->instance
);
221 unifi_error(priv
, "invalid priv\n");
225 /* Just a sanity check */
226 if ((sig_packed
== NULL
) || (sig_len
<= 0)) {
230 /* Get the unpacked signal */
231 r
= read_unpack_signal(sig_packed
, &signal
);
233 signal_len
= SigGetSize(&signal
);
235 u16 receiver_id
= CSR_GET_UINT16_FROM_LITTLE_ENDIAN((sig_packed
) + sizeof(u16
)) & 0xFF00;
237 /* The control indications are 1 byte, pass them to client. */
239 unifi_trace(priv
, UDBG5
,
240 "Control indication (0x%x) for native SME.\n",
243 *(u8
*)&signal
= *sig_packed
;
244 signal_len
= sig_len
;
245 } else if (receiver_id
== 0) {
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).
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
));
255 *(u8
*)&signal
= *sig_packed
;
256 signal_len
= sig_len
;
259 "sme_native_log_event - Received unknown signal 0x%.4X.\n",
260 CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed
));
265 unifi_trace(priv
, UDBG3
, "sme_native_log_event: signal 0x%.4X for %d\n",
266 signal
.SignalPrimitiveHeader
.SignalId
,
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
;
275 /* Allocate log structure plus actual signal. */
276 logptr
= (udi_log_t
*)kmalloc(sizeof(udi_log_t
) + total_len
, GFP_KERNEL
);
278 if (logptr
== NULL
) {
280 "Failed to allocate %d bytes for a UDI log record\n",
281 sizeof(udi_log_t
) + total_len
);
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
;
293 /* Copy signal and bulk data to the log */
294 p
= (u8
*)(msgptr
+ 1);
295 memcpy(p
, &signal
, signal_len
);
298 /* Append any bulk data */
299 for (i
= 0; i
< UNIFI_MAX_DATA_REFERENCES
; i
++) {
300 int len
= bulkdata
->d
[i
].data_length
;
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.
307 if (bulkdata
->d
[i
].os_data_ptr
) {
308 memcpy(p
, bulkdata
->d
[i
].os_data_ptr
, len
);
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
);
321 /* Wake any waiting user process */
322 wake_up_interruptible(&client
->udi_wq
);
324 } /* sme_native_log_event() */
328 * ---------------------------------------------------------------------------
329 * unifi_ta_indicate_protocol
331 * Report that a packet of a particular type has been seen
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.
343 * We defer the actual sending to a background workqueue,
344 * see uf_ta_ind_wq().
345 * ---------------------------------------------------------------------------
348 unifi_ta_indicate_protocol(void *ospriv
,
349 CsrWifiRouterCtrlTrafficPacketType packet_type
,
350 CsrWifiRouterCtrlProtocolDirection direction
,
351 const CsrWifiMacAddress
*src_addr
)
354 } /* unifi_ta_indicate_protocol */
357 * ---------------------------------------------------------------------------
358 * unifi_ta_indicate_sampling
360 * Send the TA sampling information to the SME.
363 * drv_priv The device context pointer passed to ta_init.
364 * stats The TA sampling data to send.
368 * ---------------------------------------------------------------------------
371 unifi_ta_indicate_sampling(void *ospriv
, CsrWifiRouterCtrlTrafficStats
*stats
)
374 } /* unifi_ta_indicate_sampling() */
378 unifi_ta_indicate_l4stats(void *ospriv
,
385 } /* unifi_ta_indicate_l4stats() */
388 * ---------------------------------------------------------------------------
389 * uf_native_process_udi_signal
391 * Process interesting signals from the UDI interface.
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.
404 * ---------------------------------------------------------------------------
407 uf_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
)
412 } /* uf_native_process_udi_signal() */
416 * ---------------------------------------------------------------------------
417 * sme_native_mlme_event_handler
419 * Callback function to be used as the udi_event_callback when registering
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.
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.
436 * ---------------------------------------------------------------------------
439 sme_native_mlme_event_handler(ul_client_t
*pcli
,
440 const u8
*sig_packed
, int sig_len
,
441 const bulk_data_param_t
*bulkdata
,
446 unifi_priv_t
*priv
= uf_find_instance(pcli
->instance
);
449 /* Just a sanity check */
450 if ((sig_packed
== NULL
) || (sig_len
<= 0)) {
454 /* Get the unpacked signal */
455 r
= read_unpack_signal(sig_packed
, &signal
);
457 signal_len
= SigGetSize(&signal
);
460 "sme_native_mlme_event_handler - Received unknown signal 0x%.4X.\n",
461 CSR_GET_UINT16_FROM_LITTLE_ENDIAN(sig_packed
));
465 id
= signal
.SignalPrimitiveHeader
.SignalId
;
466 unifi_trace(priv
, UDBG4
, "wext - Process signal 0x%.4X\n", id
);
469 * Take the appropriate action for the signal.
473 * Confirm replies from UniFi.
474 * These all have zero or one CSR_DATAREF member. (FIXME: check this is still true for softmac)
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
);
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");
528 } /* sme_native_mlme_event_handler() */
533 * -------------------------------------------------------------------------
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).
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
550 * 0 on success, an error code otherwise.
551 * -------------------------------------------------------------------------
554 unifi_reset_state(unifi_priv_t
*priv
, unsigned char *macaddr
,
555 unsigned char set_default_mib
)
559 #ifdef CSR_SUPPORT_WEXT
560 /* The reset clears any 802.11 association. */
561 priv
->wext_conf
.flag_associated
= 0;
565 } /* unifi_reset_state() */