Merge branch 'next/drivers' into HEAD
[deliverable/linux.git] / drivers / staging / csr / ul_int.c
1 /*
2 * ***************************************************************************
3 * FILE: ul_int.c
4 *
5 * PURPOSE:
6 * Manage list of client applications using UniFi.
7 *
8 * Copyright (C) 2006-2009 by Cambridge Silicon Radio Ltd.
9 *
10 * Refer to LICENSE.txt included with this source code for details on
11 * the license terms.
12 *
13 * ***************************************************************************
14 */
15 #include <linux/version.h>
16 #include "csr_wifi_hip_unifi.h"
17 #include "csr_wifi_hip_conversions.h"
18 #include "unifi_priv.h"
19 #include "unifiio.h"
20 #include "unifi_os.h"
21
22 static void free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata);
23 static void reset_driver_status(unifi_priv_t *priv);
24
25 /*
26 * ---------------------------------------------------------------------------
27 * ul_init_clients
28 *
29 * Initialise the clients array to empty.
30 *
31 * Arguments:
32 * priv Pointer to device private context struct
33 *
34 * Returns:
35 * None.
36 *
37 * Notes:
38 * This function needs to be called before priv is stored in
39 * Unifi_instances[].
40 * ---------------------------------------------------------------------------
41 */
42 void
43 ul_init_clients(unifi_priv_t *priv)
44 {
45 int id;
46 ul_client_t *ul_clients;
47
48 sema_init(&priv->udi_logging_mutex, 1);
49 priv->logging_client = NULL;
50
51 ul_clients = priv->ul_clients;
52
53 for (id = 0; id < MAX_UDI_CLIENTS; id++) {
54 memset(&ul_clients[id], 0, sizeof(ul_client_t));
55
56 ul_clients[id].client_id = id;
57 ul_clients[id].sender_id = UDI_SENDER_ID_BASE + (id << UDI_SENDER_ID_SHIFT);
58 ul_clients[id].instance = -1;
59 ul_clients[id].event_hook = NULL;
60
61 INIT_LIST_HEAD(&ul_clients[id].udi_log);
62 init_waitqueue_head(&ul_clients[id].udi_wq);
63 sema_init(&ul_clients[id].udi_sem, 1);
64
65 ul_clients[id].wake_up_wq_id = 0;
66 ul_clients[id].seq_no = 0;
67 ul_clients[id].wake_seq_no = 0;
68 ul_clients[id].snap_filter.count = 0;
69 }
70 } /* ul_init_clients() */
71
72
73 /*
74 * ---------------------------------------------------------------------------
75 * ul_register_client
76 *
77 * This function registers a new ul client.
78 *
79 * Arguments:
80 * priv Pointer to device private context struct
81 * configuration Special configuration for the client.
82 * udi_event_clbk Callback for receiving event from unifi.
83 *
84 * Returns:
85 * 0 if a new clients is registered, -1 otherwise.
86 * ---------------------------------------------------------------------------
87 */
88 ul_client_t *
89 ul_register_client(unifi_priv_t *priv, unsigned int configuration,
90 udi_event_t udi_event_clbk)
91 {
92 unsigned char id, ref;
93 ul_client_t *ul_clients;
94
95 ul_clients = priv->ul_clients;
96
97 /* check for an unused entry */
98 for (id = 0; id < MAX_UDI_CLIENTS; id++) {
99 if (ul_clients[id].udi_enabled == 0) {
100 ul_clients[id].instance = priv->instance;
101 ul_clients[id].udi_enabled = 1;
102 ul_clients[id].configuration = configuration;
103
104 /* Allocate memory for the reply signal.. */
105 ul_clients[id].reply_signal = kmalloc(sizeof(CSR_SIGNAL), GFP_KERNEL);
106 if (ul_clients[id].reply_signal == NULL) {
107 unifi_error(priv, "Failed to allocate reply signal for client.\n");
108 return NULL;
109 }
110 /* .. and the bulk data of the reply signal. */
111 for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
112 ul_clients[id].reply_bulkdata[ref] = kmalloc(sizeof(bulk_data_t), GFP_KERNEL);
113 /* If allocation fails, free allocated memory. */
114 if (ul_clients[id].reply_bulkdata[ref] == NULL) {
115 for (; ref > 0; ref --) {
116 kfree(ul_clients[id].reply_bulkdata[ref - 1]);
117 }
118 kfree(ul_clients[id].reply_signal);
119 unifi_error(priv, "Failed to allocate bulk data buffers for client.\n");
120 return NULL;
121 }
122 }
123
124 /* Set the event callback. */
125 ul_clients[id].event_hook = udi_event_clbk;
126
127 unifi_trace(priv, UDBG2, "UDI %d (0x%x) registered. configuration = 0x%x\n",
128 id, &ul_clients[id], configuration);
129 return &ul_clients[id];
130 }
131 }
132 return NULL;
133 } /* ul_register_client() */
134
135
136 /*
137 * ---------------------------------------------------------------------------
138 * ul_deregister_client
139 *
140 * This function deregisters a blocking UDI client.
141 *
142 * Arguments:
143 * client Pointer to the client we deregister.
144 *
145 * Returns:
146 * 0 if a new clients is deregistered.
147 * ---------------------------------------------------------------------------
148 */
149 int
150 ul_deregister_client(ul_client_t *ul_client)
151 {
152 struct list_head *pos, *n;
153 udi_log_t *logptr;
154 unifi_priv_t *priv = uf_find_instance(ul_client->instance);
155 int ref;
156
157 ul_client->instance = -1;
158 ul_client->event_hook = NULL;
159 ul_client->udi_enabled = 0;
160 unifi_trace(priv, UDBG5, "UDI (0x%x) deregistered.\n", ul_client);
161
162 /* Free memory allocated for the reply signal and its bulk data. */
163 kfree(ul_client->reply_signal);
164 for (ref = 0; ref < UNIFI_MAX_DATA_REFERENCES; ref ++) {
165 kfree(ul_client->reply_bulkdata[ref]);
166 }
167
168 if (ul_client->snap_filter.count) {
169 ul_client->snap_filter.count = 0;
170 kfree(ul_client->snap_filter.protocols);
171 }
172
173 /* Free anything pending on the udi_log list */
174 down(&ul_client->udi_sem);
175 list_for_each_safe(pos, n, &ul_client->udi_log)
176 {
177 logptr = list_entry(pos, udi_log_t, q);
178 list_del(pos);
179 kfree(logptr);
180 }
181 up(&ul_client->udi_sem);
182
183 return 0;
184 } /* ul_deregister_client() */
185
186
187
188 /*
189 * ---------------------------------------------------------------------------
190 * logging_handler
191 *
192 * This function is registered with the driver core.
193 * It is called every time a UniFi HIP Signal is sent. It iterates over
194 * the list of processes interested in receiving log events and
195 * delivers the events to them.
196 *
197 * Arguments:
198 * ospriv Pointer to driver's private data.
199 * sigdata Pointer to the packed signal buffer.
200 * signal_len Length of the packed signal.
201 * bulkdata Pointer to the signal's bulk data.
202 * dir Direction of the signal
203 * 0 = from-host
204 * 1 = to-host
205 *
206 * Returns:
207 * None.
208 * ---------------------------------------------------------------------------
209 */
210 void
211 logging_handler(void *ospriv,
212 u8 *sigdata, u32 signal_len,
213 const bulk_data_param_t *bulkdata,
214 enum udi_log_direction direction)
215 {
216 unifi_priv_t *priv = (unifi_priv_t*)ospriv;
217 ul_client_t *client;
218 int dir;
219
220 dir = (direction == UDI_LOG_FROM_HOST) ? UDI_FROM_HOST : UDI_TO_HOST;
221
222 down(&priv->udi_logging_mutex);
223 client = priv->logging_client;
224 if (client != NULL) {
225 client->event_hook(client, sigdata, signal_len,
226 bulkdata, dir);
227 }
228 up(&priv->udi_logging_mutex);
229
230 } /* logging_handler() */
231
232
233
234 /*
235 * ---------------------------------------------------------------------------
236 * ul_log_config_ind
237 *
238 * This function uses the client's register callback
239 * to indicate configuration information e.g core errors.
240 *
241 * Arguments:
242 * priv Pointer to driver's private data.
243 * conf_param Pointer to the configuration data.
244 * len Length of the configuration data.
245 *
246 * Returns:
247 * None.
248 * ---------------------------------------------------------------------------
249 */
250 void
251 ul_log_config_ind(unifi_priv_t *priv, u8 *conf_param, int len)
252 {
253 #ifdef CSR_SUPPORT_SME
254 if (priv->smepriv == NULL)
255 {
256 return;
257 }
258 if ((CONFIG_IND_ERROR == (*conf_param)) && (priv->wifi_on_state == wifi_on_in_progress)) {
259 unifi_notice(priv, "ul_log_config_ind: wifi on in progress, suppress error\n");
260 } else {
261 /* wifi_off_ind (error or exit) */
262 CsrWifiRouterCtrlWifiOffIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, (CsrWifiRouterCtrlControlIndication)(*conf_param));
263 }
264 #ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
265 unifi_debug_buf_dump();
266 #endif
267 #else
268 bulk_data_param_t bulkdata;
269
270 /*
271 * If someone killed unifi_managed before the driver was unloaded
272 * the g_drvpriv pointer is going to be NULL. In this case it is
273 * safe to assume that there is no client to get the indication.
274 */
275 if (!priv) {
276 unifi_notice(NULL, "uf_sme_event_ind: NULL priv\n");
277 return;
278 }
279
280 /* Create a null bulkdata structure. */
281 bulkdata.d[0].data_length = 0;
282 bulkdata.d[1].data_length = 0;
283
284 sme_native_log_event(priv->sme_cli, conf_param, sizeof(u8),
285 &bulkdata, UDI_CONFIG_IND);
286
287 #endif /* CSR_SUPPORT_SME */
288
289 } /* ul_log_config_ind */
290
291
292 /*
293 * ---------------------------------------------------------------------------
294 * free_bulkdata_buffers
295 *
296 * Free the bulkdata buffers e.g. after a failed unifi_send_signal().
297 *
298 * Arguments:
299 * priv Pointer to device private struct
300 * bulkdata Pointer to bulkdata parameter table
301 *
302 * Returns:
303 * None.
304 * ---------------------------------------------------------------------------
305 */
306 static void
307 free_bulkdata_buffers(unifi_priv_t *priv, bulk_data_param_t *bulkdata)
308 {
309 int i;
310
311 if (bulkdata) {
312 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; ++i) {
313 if (bulkdata->d[i].data_length != 0) {
314 unifi_net_data_free(priv, (bulk_data_desc_t *)(&bulkdata->d[i]));
315 /* data_length is now 0 */
316 }
317 }
318 }
319
320 } /* free_bulkdata_buffers */
321
322 static int
323 _align_bulk_data_buffers(unifi_priv_t *priv, u8 *signal,
324 bulk_data_param_t *bulkdata)
325 {
326 unsigned int i;
327
328 if ((bulkdata == NULL) || (CSR_WIFI_ALIGN_BYTES == 0)) {
329 return 0;
330 }
331
332 for (i = 0; i < UNIFI_MAX_DATA_REFERENCES; i++)
333 {
334 struct sk_buff *skb;
335 /*
336 * The following complex casting is in place in order to eliminate 64-bit compilation warning
337 * "cast to/from pointer from/to integer of different size"
338 */
339 u32 align_offset = (u32)(long)(bulkdata->d[i].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1);
340 if (align_offset)
341 {
342 skb = (struct sk_buff*)bulkdata->d[i].os_net_buf_ptr;
343 if (skb == NULL) {
344 unifi_warning(priv,
345 "_align_bulk_data_buffers: Align offset found (%d) but skb is NULL!\n",
346 align_offset);
347 return -EINVAL;
348 }
349 if (bulkdata->d[i].data_length == 0) {
350 unifi_warning(priv,
351 "_align_bulk_data_buffers: Align offset found (%d) but length is zero\n",
352 align_offset);
353 return CSR_RESULT_SUCCESS;
354 }
355 unifi_trace(priv, UDBG5,
356 "Align f-h buffer (0x%p) by %d bytes (skb->data: 0x%p)\n",
357 bulkdata->d[i].os_data_ptr, align_offset, skb->data);
358
359
360 /* Check if there is enough headroom... */
361 if (unlikely(skb_headroom(skb) < align_offset))
362 {
363 struct sk_buff *tmp = skb;
364
365 unifi_trace(priv, UDBG5, "Headroom not enough - realloc it\n");
366 skb = skb_realloc_headroom(skb, align_offset);
367 if (skb == NULL) {
368 unifi_error(priv,
369 "_align_bulk_data_buffers: skb_realloc_headroom failed - signal is dropped\n");
370 return -EFAULT;
371 }
372 /* Free the old bulk data only if allocation succeeds */
373 kfree_skb(tmp);
374 /* Bulkdata needs to point to the new skb */
375 bulkdata->d[i].os_net_buf_ptr = (const unsigned char*)skb;
376 bulkdata->d[i].os_data_ptr = (const void*)skb->data;
377 }
378 /* ... before pushing the data to the right alignment offset */
379 skb_push(skb, align_offset);
380
381 }
382 /* The direction bit is zero for the from-host */
383 signal[SIZEOF_SIGNAL_HEADER + (i * SIZEOF_DATAREF) + 1] = align_offset;
384
385 }
386 return 0;
387 } /* _align_bulk_data_buffers() */
388
389
390 /*
391 * ---------------------------------------------------------------------------
392 * ul_send_signal_unpacked
393 *
394 * This function sends a host formatted signal to unifi.
395 *
396 * Arguments:
397 * priv Pointer to driver's private data.
398 * sigptr Pointer to the signal.
399 * bulkdata Pointer to the signal's bulk data.
400 *
401 * Returns:
402 * O on success, error code otherwise.
403 *
404 * Notes:
405 * The signals have to be sent in the format described in the host interface
406 * specification, i.e wire formatted. Certain clients use the host formatted
407 * structures. The write_pack() transforms the host formatted signal
408 * into the wired formatted signal. The code is in the core, since the signals
409 * are defined therefore binded to the host interface specification.
410 * ---------------------------------------------------------------------------
411 */
412 int
413 ul_send_signal_unpacked(unifi_priv_t *priv, CSR_SIGNAL *sigptr,
414 bulk_data_param_t *bulkdata)
415 {
416 u8 sigbuf[UNIFI_PACKED_SIGBUF_SIZE];
417 u16 packed_siglen;
418 CsrResult csrResult;
419 unsigned long lock_flags;
420 int r;
421
422
423 csrResult = write_pack(sigptr, sigbuf, &packed_siglen);
424 if (csrResult != CSR_RESULT_SUCCESS) {
425 unifi_error(priv, "Malformed HIP signal in ul_send_signal_unpacked()\n");
426 return CsrHipResultToStatus(csrResult);
427 }
428 r = _align_bulk_data_buffers(priv, sigbuf, (bulk_data_param_t*)bulkdata);
429 if (r) {
430 return r;
431 }
432
433 spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
434 csrResult = unifi_send_signal(priv->card, sigbuf, packed_siglen, bulkdata);
435 if (csrResult != CSR_RESULT_SUCCESS) {
436 /* free_bulkdata_buffers(priv, (bulk_data_param_t *)bulkdata); */
437 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
438 return CsrHipResultToStatus(csrResult);
439 }
440 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
441
442 return 0;
443 } /* ul_send_signal_unpacked() */
444
445
446 /*
447 * ---------------------------------------------------------------------------
448 * reset_driver_status
449 *
450 * This function is called from ul_send_signal_raw() when it detects
451 * that the SME has sent a MLME-RESET request.
452 *
453 * Arguments:
454 * priv Pointer to device private struct
455 *
456 * Returns:
457 * None.
458 * ---------------------------------------------------------------------------
459 */
460 static void
461 reset_driver_status(unifi_priv_t *priv)
462 {
463 priv->sta_wmm_capabilities = 0;
464 #ifdef CSR_NATIVE_LINUX
465 #ifdef CSR_SUPPORT_WEXT
466 priv->wext_conf.flag_associated = 0;
467 priv->wext_conf.block_controlled_port = CSR_WIFI_ROUTER_PORT_ACTION_8021X_PORT_OPEN;
468 priv->wext_conf.bss_wmm_capabilities = 0;
469 priv->wext_conf.disable_join_on_ssid_set = 0;
470 #endif
471 #endif
472 } /* reset_driver_status() */
473
474
475 /*
476 * ---------------------------------------------------------------------------
477 * ul_send_signal_raw
478 *
479 * This function sends a wire formatted data signal to unifi.
480 *
481 * Arguments:
482 * priv Pointer to driver's private data.
483 * sigptr Pointer to the signal.
484 * siglen Length of the signal.
485 * bulkdata Pointer to the signal's bulk data.
486 *
487 * Returns:
488 * O on success, error code otherwise.
489 * ---------------------------------------------------------------------------
490 */
491 int
492 ul_send_signal_raw(unifi_priv_t *priv, unsigned char *sigptr, int siglen,
493 bulk_data_param_t *bulkdata)
494 {
495 CsrResult csrResult;
496 unsigned long lock_flags;
497 int r;
498
499 /*
500 * Make sure that the signal is updated with the bulk data
501 * alignment for DMA.
502 */
503 r = _align_bulk_data_buffers(priv, (u8*)sigptr, bulkdata);
504 if (r) {
505 return r;
506 }
507
508 spin_lock_irqsave(&priv->send_signal_lock, lock_flags);
509 csrResult = unifi_send_signal(priv->card, sigptr, siglen, bulkdata);
510 if (csrResult != CSR_RESULT_SUCCESS) {
511 free_bulkdata_buffers(priv, bulkdata);
512 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
513 return CsrHipResultToStatus(csrResult);
514 }
515 spin_unlock_irqrestore(&priv->send_signal_lock, lock_flags);
516
517 /*
518 * Since this is use by unicli, if we get an MLME reset request
519 * we need to initialize a few status parameters
520 * that the driver uses to make decisions.
521 */
522 if (GET_SIGNAL_ID(sigptr) == CSR_MLME_RESET_REQUEST_ID) {
523 reset_driver_status(priv);
524 }
525
526 return 0;
527 } /* ul_send_signal_raw() */
528
529
This page took 0.042118 seconds and 5 git commands to generate.