aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas_tf
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas_tf')
-rw-r--r--drivers/net/wireless/libertas_tf/Makefile6
-rw-r--r--drivers/net/wireless/libertas_tf/cmd.c669
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c766
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.h98
-rw-r--r--drivers/net/wireless/libertas_tf/libertas_tf.h514
-rw-r--r--drivers/net/wireless/libertas_tf/main.c662
6 files changed, 2715 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas_tf/Makefile b/drivers/net/wireless/libertas_tf/Makefile
new file mode 100644
index 000000000000..ff5544d6ac9d
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/Makefile
@@ -0,0 +1,6 @@
1libertas_tf-objs := main.o cmd.o
2
3libertas_tf_usb-objs += if_usb.o
4
5obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf.o
6obj-$(CONFIG_LIBERTAS_THINFIRM_USB) += libertas_tf_usb.o
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
new file mode 100644
index 000000000000..fdbcf8ba3e8a
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -0,0 +1,669 @@
1/*
2 * Copyright (C) 2008, cozybit Inc.
3 * Copyright (C) 2003-2006, Marvell International Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 */
10#include "libertas_tf.h"
11
12static const struct channel_range channel_ranges[] = {
13 { LBTF_REGDOMAIN_US, 1, 12 },
14 { LBTF_REGDOMAIN_CA, 1, 12 },
15 { LBTF_REGDOMAIN_EU, 1, 14 },
16 { LBTF_REGDOMAIN_JP, 1, 14 },
17 { LBTF_REGDOMAIN_SP, 1, 14 },
18 { LBTF_REGDOMAIN_FR, 1, 14 },
19};
20
21static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
22{
23 LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU,
24 LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP,
25};
26
27static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv);
28
29
30/**
31 * lbtf_cmd_copyback - Simple callback that copies response back into command
32 *
33 * @priv A pointer to struct lbtf_private structure
34 * @extra A pointer to the original command structure for which
35 * 'resp' is a response
36 * @resp A pointer to the command response
37 *
38 * Returns: 0 on success, error on failure
39 */
40int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
41 struct cmd_header *resp)
42{
43 struct cmd_header *buf = (void *)extra;
44 uint16_t copy_len;
45
46 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
47 memcpy(buf, resp, copy_len);
48 return 0;
49}
50EXPORT_SYMBOL_GPL(lbtf_cmd_copyback);
51
52#define CHAN_TO_IDX(chan) ((chan) - 1)
53
54static void lbtf_geo_init(struct lbtf_private *priv)
55{
56 const struct channel_range *range = channel_ranges;
57 u8 ch;
58 int i;
59
60 for (i = 0; i < ARRAY_SIZE(channel_ranges); i++)
61 if (channel_ranges[i].regdomain == priv->regioncode) {
62 range = &channel_ranges[i];
63 break;
64 }
65
66 for (ch = priv->range.start; ch < priv->range.end; ch++)
67 priv->channels[CHAN_TO_IDX(ch)].flags = 0;
68}
69
70/**
71 * lbtf_update_hw_spec: Updates the hardware details.
72 *
73 * @priv A pointer to struct lbtf_private structure
74 *
75 * Returns: 0 on success, error on failure
76 */
77int lbtf_update_hw_spec(struct lbtf_private *priv)
78{
79 struct cmd_ds_get_hw_spec cmd;
80 int ret = -1;
81 u32 i;
82 DECLARE_MAC_BUF(mac);
83
84 memset(&cmd, 0, sizeof(cmd));
85 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
86 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
87 ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
88 if (ret)
89 goto out;
90
91 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
92
93 /* The firmware release is in an interesting format: the patch
94 * level is in the most significant nibble ... so fix that: */
95 priv->fwrelease = le32_to_cpu(cmd.fwrelease);
96 priv->fwrelease = (priv->fwrelease << 8) |
97 (priv->fwrelease >> 24 & 0xff);
98
99 printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n",
100 print_mac(mac, cmd.permanentaddr),
101 priv->fwrelease >> 24 & 0xff,
102 priv->fwrelease >> 16 & 0xff,
103 priv->fwrelease >> 8 & 0xff,
104 priv->fwrelease & 0xff,
105 priv->fwcapinfo);
106
107 /* Clamp region code to 8-bit since FW spec indicates that it should
108 * only ever be 8-bit, even though the field size is 16-bit. Some
109 * firmware returns non-zero high 8 bits here.
110 */
111 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
112
113 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
114 /* use the region code to search for the index */
115 if (priv->regioncode == lbtf_region_code_to_index[i])
116 break;
117 }
118
119 /* if it's unidentified region code, use the default (USA) */
120 if (i >= MRVDRV_MAX_REGION_CODE)
121 priv->regioncode = 0x10;
122
123 if (priv->current_addr[0] == 0xff)
124 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
125
126 SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr);
127
128 lbtf_geo_init(priv);
129out:
130 return ret;
131}
132
133/**
134 * lbtf_set_channel: Set the radio channel
135 *
136 * @priv A pointer to struct lbtf_private structure
137 * @channel The desired channel, or 0 to clear a locked channel
138 *
139 * Returns: 0 on success, error on failure
140 */
141int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
142{
143 struct cmd_ds_802_11_rf_channel cmd;
144
145 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
146 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
147 cmd.channel = cpu_to_le16(channel);
148
149 return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
150}
151
152int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
153{
154 struct cmd_ds_802_11_beacon_set cmd;
155 int size;
156
157 if (beacon->len > MRVL_MAX_BCN_SIZE)
158 return -1;
159 size = sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
160 cmd.hdr.size = cpu_to_le16(size);
161 cmd.len = cpu_to_le16(beacon->len);
162 memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
163
164 lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
165 return 0;
166}
167
168int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
169 int beacon_int) {
170 struct cmd_ds_802_11_beacon_control cmd;
171
172 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
173 cmd.action = cpu_to_le16(CMD_ACT_SET);
174 cmd.beacon_enable = cpu_to_le16(beacon_enable);
175 cmd.beacon_period = cpu_to_le16(beacon_int);
176
177 lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
178 return 0;
179}
180
181static void lbtf_queue_cmd(struct lbtf_private *priv,
182 struct cmd_ctrl_node *cmdnode)
183{
184 unsigned long flags;
185
186 if (!cmdnode)
187 return;
188
189 if (!cmdnode->cmdbuf->size)
190 return;
191
192 cmdnode->result = 0;
193 spin_lock_irqsave(&priv->driver_lock, flags);
194 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
195 spin_unlock_irqrestore(&priv->driver_lock, flags);
196}
197
198static void lbtf_submit_command(struct lbtf_private *priv,
199 struct cmd_ctrl_node *cmdnode)
200{
201 unsigned long flags;
202 struct cmd_header *cmd;
203 uint16_t cmdsize;
204 uint16_t command;
205 int timeo = 5 * HZ;
206 int ret;
207
208 cmd = cmdnode->cmdbuf;
209
210 spin_lock_irqsave(&priv->driver_lock, flags);
211 priv->cur_cmd = cmdnode;
212 cmdsize = le16_to_cpu(cmd->size);
213 command = le16_to_cpu(cmd->command);
214 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
215 spin_unlock_irqrestore(&priv->driver_lock, flags);
216
217 if (ret)
218 /* Let the timer kick in and retry, and potentially reset
219 the whole thing if the condition persists */
220 timeo = HZ;
221
222 /* Setup the timer after transmit command */
223 mod_timer(&priv->command_timer, jiffies + timeo);
224}
225
226/**
227 * This function inserts command node to cmdfreeq
228 * after cleans it. Requires priv->driver_lock held.
229 */
230static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
231 struct cmd_ctrl_node *cmdnode)
232{
233 if (!cmdnode)
234 return;
235
236 cmdnode->callback = NULL;
237 cmdnode->callback_arg = 0;
238
239 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
240
241 list_add_tail(&cmdnode->list, &priv->cmdfreeq);
242}
243
244static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
245 struct cmd_ctrl_node *ptempcmd)
246{
247 unsigned long flags;
248
249 spin_lock_irqsave(&priv->driver_lock, flags);
250 __lbtf_cleanup_and_insert_cmd(priv, ptempcmd);
251 spin_unlock_irqrestore(&priv->driver_lock, flags);
252}
253
254void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
255 int result)
256{
257 cmd->result = result;
258 cmd->cmdwaitqwoken = 1;
259 wake_up_interruptible(&cmd->cmdwait_q);
260
261 if (!cmd->callback)
262 __lbtf_cleanup_and_insert_cmd(priv, cmd);
263 priv->cur_cmd = NULL;
264}
265
266int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
267{
268 struct cmd_ds_mac_multicast_addr cmd;
269
270 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
271 cmd.action = cpu_to_le16(CMD_ACT_SET);
272
273 cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
274 memcpy(cmd.maclist, priv->multicastlist,
275 priv->nr_of_multicastmacaddr * ETH_ALEN);
276
277 lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
278 return 0;
279}
280
281void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
282{
283 struct cmd_ds_set_mode cmd;
284
285 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
286 cmd.mode = cpu_to_le16(mode);
287 lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
288}
289
290void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid)
291{
292 struct cmd_ds_set_bssid cmd;
293
294 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
295 cmd.activate = activate ? 1 : 0;
296 if (activate)
297 memcpy(cmd.bssid, bssid, ETH_ALEN);
298
299 lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
300}
301
302int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
303{
304 struct cmd_ds_802_11_mac_address cmd;
305
306 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
307 cmd.action = cpu_to_le16(CMD_ACT_SET);
308
309 memcpy(cmd.macadd, mac_addr, ETH_ALEN);
310
311 lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
312 return 0;
313}
314
315int lbtf_set_radio_control(struct lbtf_private *priv)
316{
317 int ret = 0;
318 struct cmd_ds_802_11_radio_control cmd;
319
320 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
321 cmd.action = cpu_to_le16(CMD_ACT_SET);
322
323 switch (priv->preamble) {
324 case CMD_TYPE_SHORT_PREAMBLE:
325 cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
326 break;
327
328 case CMD_TYPE_LONG_PREAMBLE:
329 cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
330 break;
331
332 case CMD_TYPE_AUTO_PREAMBLE:
333 default:
334 cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
335 break;
336 }
337
338 if (priv->radioon)
339 cmd.control |= cpu_to_le16(TURN_ON_RF);
340 else
341 cmd.control &= cpu_to_le16(~TURN_ON_RF);
342
343 ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
344 return ret;
345}
346
347void lbtf_set_mac_control(struct lbtf_private *priv)
348{
349 struct cmd_ds_mac_control cmd;
350 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
351 cmd.action = cpu_to_le16(priv->mac_control);
352 cmd.reserved = 0;
353
354 lbtf_cmd_async(priv, CMD_MAC_CONTROL,
355 &cmd.hdr, sizeof(cmd));
356}
357
358/**
359 * lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue
360 *
361 * @priv A pointer to struct lbtf_private structure
362 *
363 * Returns: 0 on success.
364 */
365int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
366{
367 u32 bufsize;
368 u32 i;
369 struct cmd_ctrl_node *cmdarray;
370
371 /* Allocate and initialize the command array */
372 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
373 cmdarray = kzalloc(bufsize, GFP_KERNEL);
374 if (!cmdarray)
375 return -1;
376 priv->cmd_array = cmdarray;
377
378 /* Allocate and initialize each command buffer in the command array */
379 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
380 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
381 if (!cmdarray[i].cmdbuf)
382 return -1;
383 }
384
385 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
386 init_waitqueue_head(&cmdarray[i].cmdwait_q);
387 lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
388 }
389 return 0;
390}
391
392/**
393 * lbtf_free_cmd_buffer - Frees the cmd buffer.
394 *
395 * @priv A pointer to struct lbtf_private structure
396 *
397 * Returns: 0
398 */
399int lbtf_free_cmd_buffer(struct lbtf_private *priv)
400{
401 struct cmd_ctrl_node *cmdarray;
402 unsigned int i;
403
404 /* need to check if cmd array is allocated or not */
405 if (priv->cmd_array == NULL)
406 return 0;
407
408 cmdarray = priv->cmd_array;
409
410 /* Release shared memory buffers */
411 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
412 kfree(cmdarray[i].cmdbuf);
413 cmdarray[i].cmdbuf = NULL;
414 }
415
416 /* Release cmd_ctrl_node */
417 kfree(priv->cmd_array);
418 priv->cmd_array = NULL;
419
420 return 0;
421}
422
423/**
424 * lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue.
425 *
426 * @priv A pointer to struct lbtf_private structure
427 *
428 * Returns: pointer to a struct cmd_ctrl_node or NULL if none available.
429 */
430static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
431{
432 struct cmd_ctrl_node *tempnode;
433 unsigned long flags;
434
435 if (!priv)
436 return NULL;
437
438 spin_lock_irqsave(&priv->driver_lock, flags);
439
440 if (!list_empty(&priv->cmdfreeq)) {
441 tempnode = list_first_entry(&priv->cmdfreeq,
442 struct cmd_ctrl_node, list);
443 list_del(&tempnode->list);
444 } else
445 tempnode = NULL;
446
447 spin_unlock_irqrestore(&priv->driver_lock, flags);
448
449 return tempnode;
450}
451
452/**
453 * lbtf_execute_next_command: execute next command in cmd pending queue.
454 *
455 * @priv A pointer to struct lbtf_private structure
456 *
457 * Returns: 0 on success.
458 */
459int lbtf_execute_next_command(struct lbtf_private *priv)
460{
461 struct cmd_ctrl_node *cmdnode = NULL;
462 struct cmd_header *cmd;
463 unsigned long flags;
464
465 /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
466 * only caller to us is lbtf_thread() and we get even when a
467 * data packet is received */
468
469 spin_lock_irqsave(&priv->driver_lock, flags);
470
471 if (priv->cur_cmd) {
472 spin_unlock_irqrestore(&priv->driver_lock, flags);
473 return -1;
474 }
475
476 if (!list_empty(&priv->cmdpendingq)) {
477 cmdnode = list_first_entry(&priv->cmdpendingq,
478 struct cmd_ctrl_node, list);
479 }
480
481 if (cmdnode) {
482 cmd = cmdnode->cmdbuf;
483
484 list_del(&cmdnode->list);
485 spin_unlock_irqrestore(&priv->driver_lock, flags);
486 lbtf_submit_command(priv, cmdnode);
487 } else
488 spin_unlock_irqrestore(&priv->driver_lock, flags);
489 return 0;
490}
491
492static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
493 uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
494 int (*callback)(struct lbtf_private *, unsigned long,
495 struct cmd_header *),
496 unsigned long callback_arg)
497{
498 struct cmd_ctrl_node *cmdnode;
499
500 if (priv->surpriseremoved)
501 return ERR_PTR(-ENOENT);
502
503 cmdnode = lbtf_get_cmd_ctrl_node(priv);
504 if (cmdnode == NULL) {
505 /* Wake up main thread to execute next command */
506 queue_work(lbtf_wq, &priv->cmd_work);
507 return ERR_PTR(-ENOBUFS);
508 }
509
510 cmdnode->callback = callback;
511 cmdnode->callback_arg = callback_arg;
512
513 /* Copy the incoming command to the buffer */
514 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
515
516 /* Set sequence number, clean result, move to buffer */
517 priv->seqnum++;
518 cmdnode->cmdbuf->command = cpu_to_le16(command);
519 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
520 cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
521 cmdnode->cmdbuf->result = 0;
522 cmdnode->cmdwaitqwoken = 0;
523 lbtf_queue_cmd(priv, cmdnode);
524 queue_work(lbtf_wq, &priv->cmd_work);
525
526 return cmdnode;
527}
528
529void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
530 struct cmd_header *in_cmd, int in_cmd_size)
531{
532 __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
533}
534
535int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
536 struct cmd_header *in_cmd, int in_cmd_size,
537 int (*callback)(struct lbtf_private *,
538 unsigned long, struct cmd_header *),
539 unsigned long callback_arg)
540{
541 struct cmd_ctrl_node *cmdnode;
542 unsigned long flags;
543 int ret = 0;
544
545 cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
546 callback, callback_arg);
547 if (IS_ERR(cmdnode))
548 return PTR_ERR(cmdnode);
549
550 might_sleep();
551 ret = wait_event_interruptible(cmdnode->cmdwait_q,
552 cmdnode->cmdwaitqwoken);
553 if (ret) {
554 printk(KERN_DEBUG
555 "libertastf: command 0x%04x interrupted by signal",
556 command);
557 return ret;
558 }
559
560 spin_lock_irqsave(&priv->driver_lock, flags);
561 ret = cmdnode->result;
562 if (ret)
563 printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n",
564 command, ret);
565
566 __lbtf_cleanup_and_insert_cmd(priv, cmdnode);
567 spin_unlock_irqrestore(&priv->driver_lock, flags);
568
569 return ret;
570}
571EXPORT_SYMBOL_GPL(__lbtf_cmd);
572
573/* Call holding driver_lock */
574void lbtf_cmd_response_rx(struct lbtf_private *priv)
575{
576 priv->cmd_response_rxed = 1;
577 queue_work(lbtf_wq, &priv->cmd_work);
578}
579EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx);
580
581int lbtf_process_rx_command(struct lbtf_private *priv)
582{
583 uint16_t respcmd, curcmd;
584 struct cmd_header *resp;
585 int ret = 0;
586 unsigned long flags;
587 uint16_t result;
588
589 mutex_lock(&priv->lock);
590 spin_lock_irqsave(&priv->driver_lock, flags);
591
592 if (!priv->cur_cmd) {
593 ret = -1;
594 spin_unlock_irqrestore(&priv->driver_lock, flags);
595 goto done;
596 }
597
598 resp = (void *)priv->cmd_resp_buff;
599 curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
600 respcmd = le16_to_cpu(resp->command);
601 result = le16_to_cpu(resp->result);
602
603 if (net_ratelimit())
604 printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n",
605 respcmd, le16_to_cpu(resp->seqnum),
606 le16_to_cpu(resp->size));
607
608 if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
609 spin_unlock_irqrestore(&priv->driver_lock, flags);
610 ret = -1;
611 goto done;
612 }
613 if (respcmd != CMD_RET(curcmd)) {
614 spin_unlock_irqrestore(&priv->driver_lock, flags);
615 ret = -1;
616 goto done;
617 }
618
619 if (resp->result == cpu_to_le16(0x0004)) {
620 /* 0x0004 means -EAGAIN. Drop the response, let it time out
621 and be resubmitted */
622 spin_unlock_irqrestore(&priv->driver_lock, flags);
623 ret = -1;
624 goto done;
625 }
626
627 /* Now we got response from FW, cancel the command timer */
628 del_timer(&priv->command_timer);
629 priv->cmd_timed_out = 0;
630 if (priv->nr_retries)
631 priv->nr_retries = 0;
632
633 /* If the command is not successful, cleanup and return failure */
634 if ((result != 0 || !(respcmd & 0x8000))) {
635 /*
636 * Handling errors here
637 */
638 switch (respcmd) {
639 case CMD_RET(CMD_GET_HW_SPEC):
640 case CMD_RET(CMD_802_11_RESET):
641 printk(KERN_DEBUG "libertastf: reset failed\n");
642 break;
643
644 }
645 lbtf_complete_command(priv, priv->cur_cmd, result);
646 spin_unlock_irqrestore(&priv->driver_lock, flags);
647
648 ret = -1;
649 goto done;
650 }
651
652 spin_unlock_irqrestore(&priv->driver_lock, flags);
653
654 if (priv->cur_cmd && priv->cur_cmd->callback) {
655 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
656 resp);
657 }
658 spin_lock_irqsave(&priv->driver_lock, flags);
659
660 if (priv->cur_cmd) {
661 /* Clean up and Put current command back to cmdfreeq */
662 lbtf_complete_command(priv, priv->cur_cmd, result);
663 }
664 spin_unlock_irqrestore(&priv->driver_lock, flags);
665
666done:
667 mutex_unlock(&priv->lock);
668 return ret;
669}
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
new file mode 100644
index 000000000000..1cc03a8dd67a
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -0,0 +1,766 @@
1/*
2 * Copyright (C) 2008, cozybit Inc.
3 * Copyright (C) 2003-2006, Marvell International Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 */
10#include <linux/delay.h>
11#include <linux/moduleparam.h>
12#include <linux/firmware.h>
13#include <linux/netdevice.h>
14#include <linux/usb.h>
15
16#define DRV_NAME "lbtf_usb"
17
18#include "libertas_tf.h"
19#include "if_usb.h"
20
21#define MESSAGE_HEADER_LEN 4
22
23static char *lbtf_fw_name = "lbtf_usb.bin";
24module_param_named(fw_name, lbtf_fw_name, charp, 0644);
25
26static struct usb_device_id if_usb_table[] = {
27 /* Enter the device signature inside */
28 { USB_DEVICE(0x1286, 0x2001) },
29 { USB_DEVICE(0x05a3, 0x8388) },
30 {} /* Terminating entry */
31};
32
33MODULE_DEVICE_TABLE(usb, if_usb_table);
34
35static void if_usb_receive(struct urb *urb);
36static void if_usb_receive_fwload(struct urb *urb);
37static int if_usb_prog_firmware(struct if_usb_card *cardp);
38static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
39 uint8_t *payload, uint16_t nb);
40static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
41 uint16_t nb, u8 data);
42static void if_usb_free(struct if_usb_card *cardp);
43static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
44static int if_usb_reset_device(struct if_usb_card *cardp);
45
46/**
47 * if_usb_wrike_bulk_callback - call back to handle URB status
48 *
49 * @param urb pointer to urb structure
50 */
51static void if_usb_write_bulk_callback(struct urb *urb)
52{
53 if (urb->status != 0)
54 printk(KERN_INFO "libertastf: URB in failure status: %d\n",
55 urb->status);
56}
57
58/**
59 * if_usb_free - free tx/rx urb, skb and rx buffer
60 *
61 * @param cardp pointer if_usb_card
62 */
63static void if_usb_free(struct if_usb_card *cardp)
64{
65 /* Unlink tx & rx urb */
66 usb_kill_urb(cardp->tx_urb);
67 usb_kill_urb(cardp->rx_urb);
68 usb_kill_urb(cardp->cmd_urb);
69
70 usb_free_urb(cardp->tx_urb);
71 cardp->tx_urb = NULL;
72
73 usb_free_urb(cardp->rx_urb);
74 cardp->rx_urb = NULL;
75
76 usb_free_urb(cardp->cmd_urb);
77 cardp->cmd_urb = NULL;
78
79 kfree(cardp->ep_out_buf);
80 cardp->ep_out_buf = NULL;
81}
82
83static void if_usb_setup_firmware(struct lbtf_private *priv)
84{
85 struct if_usb_card *cardp = priv->card;
86 struct cmd_ds_set_boot2_ver b2_cmd;
87
88 if_usb_submit_rx_urb(cardp);
89 b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
90 b2_cmd.action = 0;
91 b2_cmd.version = cardp->boot2_version;
92
93 if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
94 printk(KERN_INFO "libertastf: setting boot2 version failed\n");
95}
96
97static void if_usb_fw_timeo(unsigned long priv)
98{
99 struct if_usb_card *cardp = (void *)priv;
100
101 if (!cardp->fwdnldover)
102 /* Download timed out */
103 cardp->priv->surpriseremoved = 1;
104 wake_up(&cardp->fw_wq);
105}
106
107/**
108 * if_usb_probe - sets the configuration values
109 *
110 * @ifnum interface number
111 * @id pointer to usb_device_id
112 *
113 * Returns: 0 on success, error code on failure
114 */
115static int if_usb_probe(struct usb_interface *intf,
116 const struct usb_device_id *id)
117{
118 struct usb_device *udev;
119 struct usb_host_interface *iface_desc;
120 struct usb_endpoint_descriptor *endpoint;
121 struct lbtf_private *priv;
122 struct if_usb_card *cardp;
123 int i;
124
125 udev = interface_to_usbdev(intf);
126
127 cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
128 if (!cardp)
129 goto error;
130
131 setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
132 init_waitqueue_head(&cardp->fw_wq);
133
134 cardp->udev = udev;
135 iface_desc = intf->cur_altsetting;
136
137 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
138 endpoint = &iface_desc->endpoint[i].desc;
139 if (usb_endpoint_is_bulk_in(endpoint)) {
140 cardp->ep_in_size =
141 le16_to_cpu(endpoint->wMaxPacketSize);
142 cardp->ep_in = usb_endpoint_num(endpoint);
143 } else if (usb_endpoint_is_bulk_out(endpoint)) {
144 cardp->ep_out_size =
145 le16_to_cpu(endpoint->wMaxPacketSize);
146 cardp->ep_out = usb_endpoint_num(endpoint);
147 }
148 }
149 if (!cardp->ep_out_size || !cardp->ep_in_size)
150 /* Endpoints not found */
151 goto dealloc;
152
153 cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
154 if (!cardp->rx_urb)
155 goto dealloc;
156
157 cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
158 if (!cardp->tx_urb)
159 goto dealloc;
160
161 cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
162 if (!cardp->cmd_urb)
163 goto dealloc;
164
165 cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
166 GFP_KERNEL);
167 if (!cardp->ep_out_buf)
168 goto dealloc;
169
170 priv = lbtf_add_card(cardp, &udev->dev);
171 if (!priv)
172 goto dealloc;
173
174 cardp->priv = priv;
175
176 priv->hw_host_to_card = if_usb_host_to_card;
177 priv->hw_prog_firmware = if_usb_prog_firmware;
178 priv->hw_reset_device = if_usb_reset_device;
179 cardp->boot2_version = udev->descriptor.bcdDevice;
180
181 usb_get_dev(udev);
182 usb_set_intfdata(intf, cardp);
183
184 return 0;
185
186dealloc:
187 if_usb_free(cardp);
188error:
189 return -ENOMEM;
190}
191
192/**
193 * if_usb_disconnect - free resource and cleanup
194 *
195 * @intf USB interface structure
196 */
197static void if_usb_disconnect(struct usb_interface *intf)
198{
199 struct if_usb_card *cardp = usb_get_intfdata(intf);
200 struct lbtf_private *priv = (struct lbtf_private *) cardp->priv;
201
202 if_usb_reset_device(cardp);
203
204 if (priv)
205 lbtf_remove_card(priv);
206
207 /* Unlink and free urb */
208 if_usb_free(cardp);
209
210 usb_set_intfdata(intf, NULL);
211 usb_put_dev(interface_to_usbdev(intf));
212}
213
214/**
215 * if_usb_send_fw_pkt - This function downloads the FW
216 *
217 * @priv pointer to struct lbtf_private
218 *
219 * Returns: 0
220 */
221static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
222{
223 struct fwdata *fwdata = cardp->ep_out_buf;
224 u8 *firmware = (u8 *) cardp->fw->data;
225
226 /* If we got a CRC failure on the last block, back
227 up and retry it */
228 if (!cardp->CRC_OK) {
229 cardp->totalbytes = cardp->fwlastblksent;
230 cardp->fwseqnum--;
231 }
232
233 /* struct fwdata (which we sent to the card) has an
234 extra __le32 field in between the header and the data,
235 which is not in the struct fwheader in the actual
236 firmware binary. Insert the seqnum in the middle... */
237 memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
238 sizeof(struct fwheader));
239
240 cardp->fwlastblksent = cardp->totalbytes;
241 cardp->totalbytes += sizeof(struct fwheader);
242
243 memcpy(fwdata->data, &firmware[cardp->totalbytes],
244 le32_to_cpu(fwdata->hdr.datalength));
245
246 fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
247 cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
248
249 usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
250 le32_to_cpu(fwdata->hdr.datalength), 0);
251
252 if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK))
253 /* Host has finished FW downloading
254 * Donwloading FW JUMP BLOCK
255 */
256 cardp->fwfinalblk = 1;
257
258 return 0;
259}
260
261static int if_usb_reset_device(struct if_usb_card *cardp)
262{
263 struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4;
264 int ret;
265
266 *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
267
268 cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET);
269 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset));
270 cmd->hdr.result = cpu_to_le16(0);
271 cmd->hdr.seqnum = cpu_to_le16(0x5a5a);
272 cmd->action = cpu_to_le16(CMD_ACT_HALT);
273 usb_tx_block(cardp, cardp->ep_out_buf,
274 4 + sizeof(struct cmd_ds_802_11_reset), 0);
275
276 msleep(100);
277 ret = usb_reset_device(cardp->udev);
278 msleep(100);
279
280 return ret;
281}
282EXPORT_SYMBOL_GPL(if_usb_reset_device);
283
284/**
285 * usb_tx_block - transfer data to the device
286 *
287 * @priv pointer to struct lbtf_private
288 * @payload pointer to payload data
289 * @nb data length
290 * @data non-zero for data, zero for commands
291 *
292 * Returns: 0 on success, nonzero otherwise.
293 */
294static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
295 uint16_t nb, u8 data)
296{
297 struct urb *urb;
298
299 /* check if device is removed */
300 if (cardp->priv->surpriseremoved)
301 return -1;
302
303 if (data)
304 urb = cardp->tx_urb;
305 else
306 urb = cardp->cmd_urb;
307
308 usb_fill_bulk_urb(urb, cardp->udev,
309 usb_sndbulkpipe(cardp->udev,
310 cardp->ep_out),
311 payload, nb, if_usb_write_bulk_callback, cardp);
312
313 urb->transfer_flags |= URB_ZERO_PACKET;
314
315 if (usb_submit_urb(urb, GFP_ATOMIC))
316 return -1;
317 return 0;
318}
319
320static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
321 void (*callbackfn)(struct urb *urb))
322{
323 struct sk_buff *skb;
324
325 skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
326 if (!skb)
327 return -1;
328
329 cardp->rx_skb = skb;
330
331 /* Fill the receive configuration URB and initialise the Rx call back */
332 usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
333 usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
334 (void *) (skb->tail),
335 MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp);
336
337 cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
338
339 if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) {
340 kfree_skb(skb);
341 cardp->rx_skb = NULL;
342 return -1;
343 } else
344 return 0;
345}
346
347static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
348{
349 return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
350}
351
352static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
353{
354 return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
355}
356
357static void if_usb_receive_fwload(struct urb *urb)
358{
359 struct if_usb_card *cardp = urb->context;
360 struct sk_buff *skb = cardp->rx_skb;
361 struct fwsyncheader *syncfwheader;
362 struct bootcmdresp bcmdresp;
363
364 if (urb->status) {
365 kfree_skb(skb);
366 return;
367 }
368
369 if (cardp->fwdnldover) {
370 __le32 *tmp = (__le32 *)(skb->data);
371
372 if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
373 tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY))
374 /* Firmware ready event received */
375 wake_up(&cardp->fw_wq);
376 else
377 if_usb_submit_rx_urb_fwload(cardp);
378 kfree_skb(skb);
379 return;
380 }
381 if (cardp->bootcmdresp <= 0) {
382 memcpy(&bcmdresp, skb->data, sizeof(bcmdresp));
383
384 if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
385 kfree_skb(skb);
386 if_usb_submit_rx_urb_fwload(cardp);
387 cardp->bootcmdresp = 1;
388 /* Received valid boot command response */
389 return;
390 }
391 if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
392 if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
393 bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
394 bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION))
395 cardp->bootcmdresp = -1;
396 } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB &&
397 bcmdresp.result == BOOT_CMD_RESP_OK)
398 cardp->bootcmdresp = 1;
399
400 kfree_skb(skb);
401 if_usb_submit_rx_urb_fwload(cardp);
402 return;
403 }
404
405 syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
406 if (!syncfwheader) {
407 kfree_skb(skb);
408 return;
409 }
410
411 memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
412
413 if (!syncfwheader->cmd)
414 cardp->CRC_OK = 1;
415 else
416 cardp->CRC_OK = 0;
417 kfree_skb(skb);
418
419 /* reschedule timer for 200ms hence */
420 mod_timer(&cardp->fw_timeout, jiffies + (HZ/5));
421
422 if (cardp->fwfinalblk) {
423 cardp->fwdnldover = 1;
424 goto exit;
425 }
426
427 if_usb_send_fw_pkt(cardp);
428
429 exit:
430 if_usb_submit_rx_urb_fwload(cardp);
431
432 kfree(syncfwheader);
433
434 return;
435}
436
437#define MRVDRV_MIN_PKT_LEN 30
438
439static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
440 struct if_usb_card *cardp,
441 struct lbtf_private *priv)
442{
443 if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
444 || recvlength < MRVDRV_MIN_PKT_LEN) {
445 kfree_skb(skb);
446 return;
447 }
448
449 skb_put(skb, recvlength);
450 skb_pull(skb, MESSAGE_HEADER_LEN);
451 lbtf_rx(priv, skb);
452}
453
454static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
455 struct sk_buff *skb,
456 struct if_usb_card *cardp,
457 struct lbtf_private *priv)
458{
459 if (recvlength > LBS_CMD_BUFFER_SIZE) {
460 kfree_skb(skb);
461 return;
462 }
463
464 if (!in_interrupt())
465 BUG();
466
467 spin_lock(&priv->driver_lock);
468 memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN,
469 recvlength - MESSAGE_HEADER_LEN);
470 kfree_skb(skb);
471 lbtf_cmd_response_rx(priv);
472 spin_unlock(&priv->driver_lock);
473}
474
475/**
476 * if_usb_receive - read data received from the device.
477 *
478 * @urb pointer to struct urb
479 */
480static void if_usb_receive(struct urb *urb)
481{
482 struct if_usb_card *cardp = urb->context;
483 struct sk_buff *skb = cardp->rx_skb;
484 struct lbtf_private *priv = cardp->priv;
485 int recvlength = urb->actual_length;
486 uint8_t *recvbuff = NULL;
487 uint32_t recvtype = 0;
488 __le32 *pkt = (__le32 *) skb->data;
489
490 if (recvlength) {
491 if (urb->status) {
492 kfree_skb(skb);
493 goto setup_for_next;
494 }
495
496 recvbuff = skb->data;
497 recvtype = le32_to_cpu(pkt[0]);
498 } else if (urb->status) {
499 kfree_skb(skb);
500 return;
501 }
502
503 switch (recvtype) {
504 case CMD_TYPE_DATA:
505 process_cmdtypedata(recvlength, skb, cardp, priv);
506 break;
507
508 case CMD_TYPE_REQUEST:
509 process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
510 break;
511
512 case CMD_TYPE_INDICATION:
513 {
514 /* Event cause handling */
515 u32 event_cause = le32_to_cpu(pkt[1]);
516
517 /* Icky undocumented magic special case */
518 if (event_cause & 0xffff0000) {
519 u16 tmp;
520 u8 retrycnt;
521 u8 failure;
522
523 tmp = event_cause >> 16;
524 retrycnt = tmp & 0x00ff;
525 failure = (tmp & 0xff00) >> 8;
526 lbtf_send_tx_feedback(priv, retrycnt, failure);
527 } else if (event_cause == LBTF_EVENT_BCN_SENT)
528 lbtf_bcn_sent(priv);
529 else
530 printk(KERN_DEBUG
531 "Unsupported notification %d received\n",
532 event_cause);
533 kfree_skb(skb);
534 break;
535 }
536 default:
537 printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n",
538 recvtype);
539 kfree_skb(skb);
540 break;
541 }
542
543setup_for_next:
544 if_usb_submit_rx_urb(cardp);
545}
546
547/**
548 * if_usb_host_to_card - Download data to the device
549 *
550 * @priv pointer to struct lbtf_private structure
551 * @type type of data
552 * @buf pointer to data buffer
553 * @len number of bytes
554 *
555 * Returns: 0 on success, nonzero otherwise
556 */
557static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
558 uint8_t *payload, uint16_t nb)
559{
560 struct if_usb_card *cardp = priv->card;
561 u8 data = 0;
562
563 if (type == MVMS_CMD) {
564 *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
565 } else {
566 *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
567 data = 1;
568 }
569
570 memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
571
572 return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN,
573 data);
574}
575
576/**
577 * if_usb_issue_boot_command - Issue boot command to Boot2.
578 *
579 * @ivalue 1 boots from FW by USB-Download, 2 boots from FW in EEPROM.
580 *
581 * Returns: 0
582 */
583static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
584{
585 struct bootcmd *bootcmd = cardp->ep_out_buf;
586
587 /* Prepare command */
588 bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
589 bootcmd->cmd = ivalue;
590 memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
591
592 /* Issue command */
593 usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd), 0);
594
595 return 0;
596}
597
598
599/**
600 * check_fwfile_format - Check the validity of Boot2/FW image.
601 *
602 * @data pointer to image
603 * @totlen image length
604 *
605 * Returns: 0 if the image is valid, nonzero otherwise.
606 */
607static int check_fwfile_format(const u8 *data, u32 totlen)
608{
609 u32 bincmd, exit;
610 u32 blksize, offset, len;
611 int ret;
612
613 ret = 1;
614 exit = len = 0;
615
616 do {
617 struct fwheader *fwh = (void *) data;
618
619 bincmd = le32_to_cpu(fwh->dnldcmd);
620 blksize = le32_to_cpu(fwh->datalength);
621 switch (bincmd) {
622 case FW_HAS_DATA_TO_RECV:
623 offset = sizeof(struct fwheader) + blksize;
624 data += offset;
625 len += offset;
626 if (len >= totlen)
627 exit = 1;
628 break;
629 case FW_HAS_LAST_BLOCK:
630 exit = 1;
631 ret = 0;
632 break;
633 default:
634 exit = 1;
635 break;
636 }
637 } while (!exit);
638
639 if (ret)
640 printk(KERN_INFO
641 "libertastf: firmware file format check failed\n");
642 return ret;
643}
644
645
646static int if_usb_prog_firmware(struct if_usb_card *cardp)
647{
648 int i = 0;
649 static int reset_count = 10;
650 int ret = 0;
651
652 ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
653 if (ret < 0) {
654 printk(KERN_INFO "libertastf: firmware %s not found\n",
655 lbtf_fw_name);
656 goto done;
657 }
658
659 if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
660 goto release_fw;
661
662restart:
663 if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
664 ret = -1;
665 goto release_fw;
666 }
667
668 cardp->bootcmdresp = 0;
669 do {
670 int j = 0;
671 i++;
672 /* Issue Boot command = 1, Boot from Download-FW */
673 if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
674 /* wait for command response */
675 do {
676 j++;
677 msleep_interruptible(100);
678 } while (cardp->bootcmdresp == 0 && j < 10);
679 } while (cardp->bootcmdresp == 0 && i < 5);
680
681 if (cardp->bootcmdresp <= 0) {
682 if (--reset_count >= 0) {
683 if_usb_reset_device(cardp);
684 goto restart;
685 }
686 return -1;
687 }
688
689 i = 0;
690
691 cardp->totalbytes = 0;
692 cardp->fwlastblksent = 0;
693 cardp->CRC_OK = 1;
694 cardp->fwdnldover = 0;
695 cardp->fwseqnum = -1;
696 cardp->totalbytes = 0;
697 cardp->fwfinalblk = 0;
698
699 /* Send the first firmware packet... */
700 if_usb_send_fw_pkt(cardp);
701
702 /* ... and wait for the process to complete */
703 wait_event_interruptible(cardp->fw_wq, cardp->priv->surpriseremoved ||
704 cardp->fwdnldover);
705
706 del_timer_sync(&cardp->fw_timeout);
707 usb_kill_urb(cardp->rx_urb);
708
709 if (!cardp->fwdnldover) {
710 printk(KERN_INFO "libertastf: failed to load fw,"
711 " resetting device!\n");
712 if (--reset_count >= 0) {
713 if_usb_reset_device(cardp);
714 goto restart;
715 }
716
717 printk(KERN_INFO "libertastf: fw download failure\n");
718 ret = -1;
719 goto release_fw;
720 }
721
722 cardp->priv->fw_ready = 1;
723
724 release_fw:
725 release_firmware(cardp->fw);
726 cardp->fw = NULL;
727
728 if_usb_setup_firmware(cardp->priv);
729
730 done:
731 return ret;
732}
733EXPORT_SYMBOL_GPL(if_usb_prog_firmware);
734
735
736#define if_usb_suspend NULL
737#define if_usb_resume NULL
738
739static struct usb_driver if_usb_driver = {
740 .name = DRV_NAME,
741 .probe = if_usb_probe,
742 .disconnect = if_usb_disconnect,
743 .id_table = if_usb_table,
744 .suspend = if_usb_suspend,
745 .resume = if_usb_resume,
746};
747
748static int __init if_usb_init_module(void)
749{
750 int ret = 0;
751
752 ret = usb_register(&if_usb_driver);
753 return ret;
754}
755
756static void __exit if_usb_exit_module(void)
757{
758 usb_deregister(&if_usb_driver);
759}
760
761module_init(if_usb_init_module);
762module_exit(if_usb_exit_module);
763
764MODULE_DESCRIPTION("8388 USB WLAN Thinfirm Driver");
765MODULE_AUTHOR("Cozybit Inc.");
766MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas_tf/if_usb.h b/drivers/net/wireless/libertas_tf/if_usb.h
new file mode 100644
index 000000000000..6fa5b3f59efe
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_usb.h
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2008, cozybit Inc.
3 * Copyright (C) 2003-2006, Marvell International Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 */
10#include <linux/wait.h>
11#include <linux/timer.h>
12
13struct lbtf_private;
14
15/**
16 * This file contains definition for USB interface.
17 */
18#define CMD_TYPE_REQUEST 0xF00DFACE
19#define CMD_TYPE_DATA 0xBEADC0DE
20#define CMD_TYPE_INDICATION 0xBEEFFACE
21
22#define BOOT_CMD_FW_BY_USB 0x01
23#define BOOT_CMD_FW_IN_EEPROM 0x02
24#define BOOT_CMD_UPDATE_BOOT2 0x03
25#define BOOT_CMD_UPDATE_FW 0x04
26#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */
27
28struct bootcmd {
29 __le32 magic;
30 uint8_t cmd;
31 uint8_t pad[11];
32};
33
34#define BOOT_CMD_RESP_OK 0x0001
35#define BOOT_CMD_RESP_FAIL 0x0000
36
37struct bootcmdresp {
38 __le32 magic;
39 uint8_t cmd;
40 uint8_t result;
41 uint8_t pad[2];
42};
43
44/** USB card description structure*/
45struct if_usb_card {
46 struct usb_device *udev;
47 struct urb *rx_urb, *tx_urb, *cmd_urb;
48 struct lbtf_private *priv;
49
50 struct sk_buff *rx_skb;
51
52 uint8_t ep_in;
53 uint8_t ep_out;
54
55 int8_t bootcmdresp;
56
57 int ep_in_size;
58
59 void *ep_out_buf;
60 int ep_out_size;
61
62 const struct firmware *fw;
63 struct timer_list fw_timeout;
64 wait_queue_head_t fw_wq;
65 uint32_t fwseqnum;
66 uint32_t totalbytes;
67 uint32_t fwlastblksent;
68 uint8_t CRC_OK;
69 uint8_t fwdnldover;
70 uint8_t fwfinalblk;
71
72 __le16 boot2_version;
73};
74
75/** fwheader */
76struct fwheader {
77 __le32 dnldcmd;
78 __le32 baseaddr;
79 __le32 datalength;
80 __le32 CRC;
81};
82
83#define FW_MAX_DATA_BLK_SIZE 600
84/** FWData */
85struct fwdata {
86 struct fwheader hdr;
87 __le32 seqnum;
88 uint8_t data[0];
89};
90
91/** fwsyncheader */
92struct fwsyncheader {
93 __le32 cmd;
94 __le32 seqnum;
95};
96
97#define FW_HAS_DATA_TO_RECV 0x00000001
98#define FW_HAS_LAST_BLOCK 0x00000004
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
new file mode 100644
index 000000000000..8995cd7c29bf
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -0,0 +1,514 @@
1/*
2 * Copyright (C) 2008, cozybit Inc.
3 * Copyright (C) 2007, Red Hat, Inc.
4 * Copyright (C) 2003-2006, Marvell International Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 */
11#include <linux/spinlock.h>
12#include <linux/device.h>
13#include <linux/kthread.h>
14#include <net/mac80211.h>
15
16#ifndef DRV_NAME
17#define DRV_NAME "libertas_tf"
18#endif
19
20#define MRVL_DEFAULT_RETRIES 9
21#define MRVL_PER_PACKET_RATE 0x10
22#define MRVL_MAX_BCN_SIZE 440
23#define CMD_OPTION_WAITFORRSP 0x0002
24
25/* Return command are almost always the same as the host command, but with
26 * bit 15 set high. There are a few exceptions, though...
27 */
28#define CMD_RET(cmd) (0x8000 | cmd)
29
30/* Command codes */
31#define CMD_GET_HW_SPEC 0x0003
32#define CMD_802_11_RESET 0x0005
33#define CMD_MAC_MULTICAST_ADR 0x0010
34#define CMD_802_11_RADIO_CONTROL 0x001c
35#define CMD_802_11_RF_CHANNEL 0x001d
36#define CMD_802_11_RF_TX_POWER 0x001e
37#define CMD_MAC_CONTROL 0x0028
38#define CMD_802_11_MAC_ADDRESS 0x004d
39#define CMD_SET_BOOT2_VER 0x00a5
40#define CMD_802_11_BEACON_CTRL 0x00b0
41#define CMD_802_11_BEACON_SET 0x00cb
42#define CMD_802_11_SET_MODE 0x00cc
43#define CMD_802_11_SET_BSSID 0x00cd
44
45#define CMD_ACT_GET 0x0000
46#define CMD_ACT_SET 0x0001
47
48/* Define action or option for CMD_802_11_RESET */
49#define CMD_ACT_HALT 0x0003
50
51/* Define action or option for CMD_MAC_CONTROL */
52#define CMD_ACT_MAC_RX_ON 0x0001
53#define CMD_ACT_MAC_TX_ON 0x0002
54#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
55#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
56#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
57#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
58
59/* Define action or option for CMD_802_11_RADIO_CONTROL */
60#define CMD_TYPE_AUTO_PREAMBLE 0x0001
61#define CMD_TYPE_SHORT_PREAMBLE 0x0002
62#define CMD_TYPE_LONG_PREAMBLE 0x0003
63
64#define TURN_ON_RF 0x01
65#define RADIO_ON 0x01
66#define RADIO_OFF 0x00
67
68#define SET_AUTO_PREAMBLE 0x05
69#define SET_SHORT_PREAMBLE 0x03
70#define SET_LONG_PREAMBLE 0x01
71
72/* Define action or option for CMD_802_11_RF_CHANNEL */
73#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
74#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
75
76/* Codes for CMD_802_11_SET_MODE */
77enum lbtf_mode {
78 LBTF_PASSIVE_MODE,
79 LBTF_STA_MODE,
80 LBTF_AP_MODE,
81};
82
83/** Card Event definition */
84#define MACREG_INT_CODE_FIRMWARE_READY 48
85/** Buffer Constants */
86
87/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
88* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
89* driver has more local TxPDs. Each TxPD on the host memory is associated
90* with a Tx control node. The driver maintains 8 RxPD descriptors for
91* station firmware to store Rx packet information.
92*
93* Current version of MAC has a 32x6 multicast address buffer.
94*
95* 802.11b can have up to 14 channels, the driver keeps the
96* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
97*/
98
99#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
100#define LBS_NUM_CMD_BUFFERS 10
101#define LBS_CMD_BUFFER_SIZE (2 * 1024)
102#define MRVDRV_MAX_CHANNEL_SIZE 14
103#define MRVDRV_SNAP_HEADER_LEN 8
104
105#define LBS_UPLD_SIZE 2312
106#define DEV_NAME_LEN 32
107
108/** Misc constants */
109/* This section defines 802.11 specific contants */
110
111#define MRVDRV_MAX_REGION_CODE 6
112/**
113 * the table to keep region code
114 */
115#define LBTF_REGDOMAIN_US 0x10
116#define LBTF_REGDOMAIN_CA 0x20
117#define LBTF_REGDOMAIN_EU 0x30
118#define LBTF_REGDOMAIN_SP 0x31
119#define LBTF_REGDOMAIN_FR 0x32
120#define LBTF_REGDOMAIN_JP 0x40
121
122#define SBI_EVENT_CAUSE_SHIFT 3
123
124/** RxPD status */
125
126#define MRVDRV_RXPD_STATUS_OK 0x0001
127
128
129/* This is for firmware specific length */
130#define EXTRA_LEN 36
131
132#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
133 (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
134
135#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
136 (ETH_FRAME_LEN + sizeof(struct rxpd) \
137 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
138
139#define CMD_F_HOSTCMD (1 << 0)
140#define FW_CAPINFO_WPA (1 << 0)
141
142#define RF_ANTENNA_1 0x1
143#define RF_ANTENNA_2 0x2
144#define RF_ANTENNA_AUTO 0xFFFF
145
146#define LBTF_EVENT_BCN_SENT 55
147
148/** Global Variable Declaration */
149/** mv_ms_type */
150enum mv_ms_type {
151 MVMS_DAT = 0,
152 MVMS_CMD = 1,
153 MVMS_TXDONE = 2,
154 MVMS_EVENT
155};
156
157extern struct workqueue_struct *lbtf_wq;
158
159struct lbtf_private;
160
161struct lbtf_offset_value {
162 u32 offset;
163 u32 value;
164};
165
166struct channel_range {
167 u8 regdomain;
168 u8 start;
169 u8 end; /* exclusive (channel must be less than end) */
170};
171
172struct if_usb_card;
173
174/** Private structure for the MV device */
175struct lbtf_private {
176 void *card;
177 struct ieee80211_hw *hw;
178
179 /* Command response buffer */
180 u8 cmd_resp_buff[LBS_UPLD_SIZE];
181 /* Download sent:
182 bit0 1/0=data_sent/data_tx_done,
183 bit1 1/0=cmd_sent/cmd_tx_done,
184 all other bits reserved 0 */
185 struct ieee80211_vif *vif;
186
187 struct work_struct cmd_work;
188 struct work_struct tx_work;
189 /** Hardware access */
190 int (*hw_host_to_card) (struct lbtf_private *priv, u8 type, u8 *payload, u16 nb);
191 int (*hw_prog_firmware) (struct if_usb_card *cardp);
192 int (*hw_reset_device) (struct if_usb_card *cardp);
193
194
195 /** Wlan adapter data structure*/
196 /** STATUS variables */
197 u32 fwrelease;
198 u32 fwcapinfo;
199 /* protected with big lock */
200
201 struct mutex lock;
202
203 /** command-related variables */
204 u16 seqnum;
205 /* protected by big lock */
206
207 struct cmd_ctrl_node *cmd_array;
208 /** Current command */
209 struct cmd_ctrl_node *cur_cmd;
210 /** command Queues */
211 /** Free command buffers */
212 struct list_head cmdfreeq;
213 /** Pending command buffers */
214 struct list_head cmdpendingq;
215
216 /** spin locks */
217 spinlock_t driver_lock;
218
219 /** Timers */
220 struct timer_list command_timer;
221 int nr_retries;
222 int cmd_timed_out;
223
224 u8 cmd_response_rxed;
225
226 /** capability Info used in Association, start, join */
227 u16 capability;
228
229 /** MAC address information */
230 u8 current_addr[ETH_ALEN];
231 u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
232 u32 nr_of_multicastmacaddr;
233 int cur_freq;
234
235 struct sk_buff *skb_to_tx;
236 struct sk_buff *tx_skb;
237
238 /** NIC Operation characteristics */
239 u16 mac_control;
240 u16 regioncode;
241 struct channel_range range;
242
243 u8 radioon;
244 u32 preamble;
245
246 struct ieee80211_channel channels[14];
247 struct ieee80211_rate rates[12];
248 struct ieee80211_supported_band band;
249 struct lbtf_offset_value offsetvalue;
250
251 u8 fw_ready;
252 u8 surpriseremoved;
253 struct sk_buff_head bc_ps_buf;
254};
255
256/* 802.11-related definitions */
257
258/* TxPD descriptor */
259struct txpd {
260 /* Current Tx packet status */
261 __le32 tx_status;
262 /* Tx control */
263 __le32 tx_control;
264 __le32 tx_packet_location;
265 /* Tx packet length */
266 __le16 tx_packet_length;
267 /* First 2 byte of destination MAC address */
268 u8 tx_dest_addr_high[2];
269 /* Last 4 byte of destination MAC address */
270 u8 tx_dest_addr_low[4];
271 /* Pkt Priority */
272 u8 priority;
273 /* Pkt Trasnit Power control */
274 u8 powermgmt;
275 /* Time the packet has been queued in the driver (units = 2ms) */
276 u8 pktdelay_2ms;
277 /* reserved */
278 u8 reserved1;
279};
280
281/* RxPD Descriptor */
282struct rxpd {
283 /* Current Rx packet status */
284 __le16 status;
285
286 /* SNR */
287 u8 snr;
288
289 /* Tx control */
290 u8 rx_control;
291
292 /* Pkt length */
293 __le16 pkt_len;
294
295 /* Noise Floor */
296 u8 nf;
297
298 /* Rx Packet Rate */
299 u8 rx_rate;
300
301 /* Pkt addr */
302 __le32 pkt_ptr;
303
304 /* Next Rx RxPD addr */
305 __le32 next_rxpd_ptr;
306
307 /* Pkt Priority */
308 u8 priority;
309 u8 reserved[3];
310};
311
312struct cmd_header {
313 __le16 command;
314 __le16 size;
315 __le16 seqnum;
316 __le16 result;
317} __attribute__ ((packed));
318
319struct cmd_ctrl_node {
320 struct list_head list;
321 int result;
322 /* command response */
323 int (*callback)(struct lbtf_private *,
324 unsigned long, struct cmd_header *);
325 unsigned long callback_arg;
326 /* command data */
327 struct cmd_header *cmdbuf;
328 /* wait queue */
329 u16 cmdwaitqwoken;
330 wait_queue_head_t cmdwait_q;
331};
332
333/*
334 * Define data structure for CMD_GET_HW_SPEC
335 * This structure defines the response for the GET_HW_SPEC command
336 */
337struct cmd_ds_get_hw_spec {
338 struct cmd_header hdr;
339
340 /* HW Interface version number */
341 __le16 hwifversion;
342 /* HW version number */
343 __le16 version;
344 /* Max number of TxPD FW can handle */
345 __le16 nr_txpd;
346 /* Max no of Multicast address */
347 __le16 nr_mcast_adr;
348 /* MAC address */
349 u8 permanentaddr[6];
350
351 /* region Code */
352 __le16 regioncode;
353
354 /* Number of antenna used */
355 __le16 nr_antenna;
356
357 /* FW release number, example 0x01030304 = 2.3.4p1 */
358 __le32 fwrelease;
359
360 /* Base Address of TxPD queue */
361 __le32 wcb_base;
362 /* Read Pointer of RxPd queue */
363 __le32 rxpd_rdptr;
364
365 /* Write Pointer of RxPd queue */
366 __le32 rxpd_wrptr;
367
368 /*FW/HW capability */
369 __le32 fwcapinfo;
370} __attribute__ ((packed));
371
372struct cmd_ds_mac_control {
373 struct cmd_header hdr;
374 __le16 action;
375 u16 reserved;
376};
377
378struct cmd_ds_802_11_mac_address {
379 struct cmd_header hdr;
380
381 __le16 action;
382 uint8_t macadd[ETH_ALEN];
383};
384
385struct cmd_ds_mac_multicast_addr {
386 struct cmd_header hdr;
387
388 __le16 action;
389 __le16 nr_of_adrs;
390 u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
391};
392
393struct cmd_ds_set_mode {
394 struct cmd_header hdr;
395
396 __le16 mode;
397};
398
399struct cmd_ds_set_bssid {
400 struct cmd_header hdr;
401
402 u8 bssid[6];
403 u8 activate;
404};
405
406struct cmd_ds_802_11_radio_control {
407 struct cmd_header hdr;
408
409 __le16 action;
410 __le16 control;
411};
412
413
414struct cmd_ds_802_11_rf_channel {
415 struct cmd_header hdr;
416
417 __le16 action;
418 __le16 channel;
419 __le16 rftype; /* unused */
420 __le16 reserved; /* unused */
421 u8 channellist[32]; /* unused */
422};
423
424struct cmd_ds_set_boot2_ver {
425 struct cmd_header hdr;
426
427 __le16 action;
428 __le16 version;
429};
430
431struct cmd_ds_802_11_reset {
432 struct cmd_header hdr;
433
434 __le16 action;
435};
436
437struct cmd_ds_802_11_beacon_control {
438 struct cmd_header hdr;
439
440 __le16 action;
441 __le16 beacon_enable;
442 __le16 beacon_period;
443};
444
445struct cmd_ds_802_11_beacon_set {
446 struct cmd_header hdr;
447
448 __le16 len;
449 u8 beacon[MRVL_MAX_BCN_SIZE];
450};
451
452struct lbtf_private;
453struct cmd_ctrl_node;
454
455/** Function Prototype Declaration */
456void lbtf_set_mac_control(struct lbtf_private *priv);
457
458int lbtf_free_cmd_buffer(struct lbtf_private *priv);
459
460int lbtf_allocate_cmd_buffer(struct lbtf_private *priv);
461int lbtf_execute_next_command(struct lbtf_private *priv);
462int lbtf_set_radio_control(struct lbtf_private *priv);
463int lbtf_update_hw_spec(struct lbtf_private *priv);
464int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv);
465void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode);
466void lbtf_set_bssid(struct lbtf_private *priv, bool activate, u8 *bssid);
467int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr);
468
469int lbtf_set_channel(struct lbtf_private *priv, u8 channel);
470
471int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon);
472int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
473 int beacon_int);
474
475
476int lbtf_process_rx_command(struct lbtf_private *priv);
477void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
478 int result);
479void lbtf_cmd_response_rx(struct lbtf_private *priv);
480
481/* main.c */
482struct chan_freq_power *lbtf_get_region_cfp_table(u8 region,
483 int *cfp_no);
484struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev);
485int lbtf_remove_card(struct lbtf_private *priv);
486int lbtf_start_card(struct lbtf_private *priv);
487int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb);
488void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail);
489void lbtf_bcn_sent(struct lbtf_private *priv);
490
491/* support functions for cmd.c */
492/* lbtf_cmd() infers the size of the buffer to copy data back into, from
493 the size of the target of the pointer. Since the command to be sent
494 may often be smaller, that size is set in cmd->size by the caller.*/
495#define lbtf_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \
496 uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \
497 (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \
498 __lbtf_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \
499})
500
501#define lbtf_cmd_with_response(priv, cmdnr, cmd) \
502 lbtf_cmd(priv, cmdnr, cmd, lbtf_cmd_copyback, (unsigned long) (cmd))
503
504void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
505 struct cmd_header *in_cmd, int in_cmd_size);
506
507int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
508 struct cmd_header *in_cmd, int in_cmd_size,
509 int (*callback)(struct lbtf_private *, unsigned long,
510 struct cmd_header *),
511 unsigned long callback_arg);
512
513int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
514 struct cmd_header *resp);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
new file mode 100644
index 000000000000..feff945ad856
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -0,0 +1,662 @@
1/*
2 * Copyright (C) 2008, cozybit Inc.
3 * Copyright (C) 2003-2006, Marvell International Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 */
10#include "libertas_tf.h"
11#include "linux/etherdevice.h"
12
13#define DRIVER_RELEASE_VERSION "004.p0"
14/* thinfirm version: 5.132.X.pX */
15#define LBTF_FW_VER_MIN 0x05840300
16#define LBTF_FW_VER_MAX 0x0584ffff
17#define QOS_CONTROL_LEN 2
18
19static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION;
20struct workqueue_struct *lbtf_wq;
21
22static const struct ieee80211_channel lbtf_channels[] = {
23 { .center_freq = 2412, .hw_value = 1 },
24 { .center_freq = 2417, .hw_value = 2 },
25 { .center_freq = 2422, .hw_value = 3 },
26 { .center_freq = 2427, .hw_value = 4 },
27 { .center_freq = 2432, .hw_value = 5 },
28 { .center_freq = 2437, .hw_value = 6 },
29 { .center_freq = 2442, .hw_value = 7 },
30 { .center_freq = 2447, .hw_value = 8 },
31 { .center_freq = 2452, .hw_value = 9 },
32 { .center_freq = 2457, .hw_value = 10 },
33 { .center_freq = 2462, .hw_value = 11 },
34 { .center_freq = 2467, .hw_value = 12 },
35 { .center_freq = 2472, .hw_value = 13 },
36 { .center_freq = 2484, .hw_value = 14 },
37};
38
39/* This table contains the hardware specific values for the modulation rates. */
40static const struct ieee80211_rate lbtf_rates[] = {
41 { .bitrate = 10,
42 .hw_value = 0, },
43 { .bitrate = 20,
44 .hw_value = 1,
45 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
46 { .bitrate = 55,
47 .hw_value = 2,
48 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
49 { .bitrate = 110,
50 .hw_value = 3,
51 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
52 { .bitrate = 60,
53 .hw_value = 5,
54 .flags = 0 },
55 { .bitrate = 90,
56 .hw_value = 6,
57 .flags = 0 },
58 { .bitrate = 120,
59 .hw_value = 7,
60 .flags = 0 },
61 { .bitrate = 180,
62 .hw_value = 8,
63 .flags = 0 },
64 { .bitrate = 240,
65 .hw_value = 9,
66 .flags = 0 },
67 { .bitrate = 360,
68 .hw_value = 10,
69 .flags = 0 },
70 { .bitrate = 480,
71 .hw_value = 11,
72 .flags = 0 },
73 { .bitrate = 540,
74 .hw_value = 12,
75 .flags = 0 },
76};
77
78static void lbtf_cmd_work(struct work_struct *work)
79{
80 struct lbtf_private *priv = container_of(work, struct lbtf_private,
81 cmd_work);
82 spin_lock_irq(&priv->driver_lock);
83 /* command response? */
84 if (priv->cmd_response_rxed) {
85 priv->cmd_response_rxed = 0;
86 spin_unlock_irq(&priv->driver_lock);
87 lbtf_process_rx_command(priv);
88 spin_lock_irq(&priv->driver_lock);
89 }
90
91 if (priv->cmd_timed_out && priv->cur_cmd) {
92 struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
93
94 if (++priv->nr_retries > 10) {
95 lbtf_complete_command(priv, cmdnode,
96 -ETIMEDOUT);
97 priv->nr_retries = 0;
98 } else {
99 priv->cur_cmd = NULL;
100
101 /* Stick it back at the _top_ of the pending
102 * queue for immediate resubmission */
103 list_add(&cmdnode->list, &priv->cmdpendingq);
104 }
105 }
106 priv->cmd_timed_out = 0;
107 spin_unlock_irq(&priv->driver_lock);
108
109 if (!priv->fw_ready)
110 return;
111 /* Execute the next command */
112 if (!priv->cur_cmd)
113 lbtf_execute_next_command(priv);
114}
115
116/**
117 * lbtf_setup_firmware: initialize firmware.
118 *
119 * @priv A pointer to struct lbtf_private structure
120 *
121 * Returns: 0 on success.
122 */
123static int lbtf_setup_firmware(struct lbtf_private *priv)
124{
125 int ret = -1;
126
127 /*
128 * Read priv address from HW
129 */
130 memset(priv->current_addr, 0xff, ETH_ALEN);
131 ret = lbtf_update_hw_spec(priv);
132 if (ret) {
133 ret = -1;
134 goto done;
135 }
136
137 lbtf_set_mac_control(priv);
138 lbtf_set_radio_control(priv);
139
140 ret = 0;
141done:
142 return ret;
143}
144
145/**
146 * This function handles the timeout of command sending.
147 * It will re-send the same command again.
148 */
149static void command_timer_fn(unsigned long data)
150{
151 struct lbtf_private *priv = (struct lbtf_private *)data;
152 unsigned long flags;
153
154 spin_lock_irqsave(&priv->driver_lock, flags);
155
156 if (!priv->cur_cmd) {
157 printk(KERN_DEBUG "libertastf: command timer expired; "
158 "no pending command\n");
159 goto out;
160 }
161
162 printk(KERN_DEBUG "libertas: command %x timed out\n",
163 le16_to_cpu(priv->cur_cmd->cmdbuf->command));
164
165 priv->cmd_timed_out = 1;
166 queue_work(lbtf_wq, &priv->cmd_work);
167out:
168 spin_unlock_irqrestore(&priv->driver_lock, flags);
169}
170
171static int lbtf_init_adapter(struct lbtf_private *priv)
172{
173 memset(priv->current_addr, 0xff, ETH_ALEN);
174 mutex_init(&priv->lock);
175
176 priv->vif = NULL;
177 setup_timer(&priv->command_timer, command_timer_fn,
178 (unsigned long)priv);
179
180 INIT_LIST_HEAD(&priv->cmdfreeq);
181 INIT_LIST_HEAD(&priv->cmdpendingq);
182
183 spin_lock_init(&priv->driver_lock);
184
185 /* Allocate the command buffers */
186 if (lbtf_allocate_cmd_buffer(priv))
187 return -1;
188
189 return 0;
190}
191
192static void lbtf_free_adapter(struct lbtf_private *priv)
193{
194 lbtf_free_cmd_buffer(priv);
195 del_timer(&priv->command_timer);
196}
197
198static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
199{
200 struct lbtf_private *priv = hw->priv;
201
202 priv->skb_to_tx = skb;
203 queue_work(lbtf_wq, &priv->tx_work);
204 /*
205 * queue will be restarted when we receive transmission feedback if
206 * there are no buffered multicast frames to send
207 */
208 ieee80211_stop_queues(priv->hw);
209 return 0;
210}
211
212static void lbtf_tx_work(struct work_struct *work)
213{
214 struct lbtf_private *priv = container_of(work, struct lbtf_private,
215 tx_work);
216 unsigned int len;
217 struct ieee80211_tx_info *info;
218 struct txpd *txpd;
219 struct sk_buff *skb = NULL;
220 int err;
221
222 if ((priv->vif->type == NL80211_IFTYPE_AP) &&
223 (!skb_queue_empty(&priv->bc_ps_buf)))
224 skb = skb_dequeue(&priv->bc_ps_buf);
225 else if (priv->skb_to_tx) {
226 skb = priv->skb_to_tx;
227 priv->skb_to_tx = NULL;
228 } else
229 return;
230
231 len = skb->len;
232 info = IEEE80211_SKB_CB(skb);
233 txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd));
234
235 if (priv->surpriseremoved) {
236 dev_kfree_skb_any(skb);
237 return;
238 }
239
240 memset(txpd, 0, sizeof(struct txpd));
241 /* Activate per-packet rate selection */
242 txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE |
243 ieee80211_get_tx_rate(priv->hw, info)->hw_value);
244
245 /* copy destination address from 802.11 header */
246 memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4,
247 ETH_ALEN);
248 txpd->tx_packet_length = cpu_to_le16(len);
249 txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
250 BUG_ON(priv->tx_skb);
251 spin_lock_irq(&priv->driver_lock);
252 priv->tx_skb = skb;
253 err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len);
254 spin_unlock_irq(&priv->driver_lock);
255 if (err) {
256 dev_kfree_skb_any(skb);
257 priv->tx_skb = NULL;
258 }
259}
260
261static int lbtf_op_start(struct ieee80211_hw *hw)
262{
263 struct lbtf_private *priv = hw->priv;
264 void *card = priv->card;
265 int ret = -1;
266
267 if (!priv->fw_ready)
268 /* Upload firmware */
269 if (priv->hw_prog_firmware(card))
270 goto err_prog_firmware;
271
272 /* poke the firmware */
273 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
274 priv->radioon = RADIO_ON;
275 priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
276 ret = lbtf_setup_firmware(priv);
277 if (ret)
278 goto err_prog_firmware;
279
280 if ((priv->fwrelease < LBTF_FW_VER_MIN) ||
281 (priv->fwrelease > LBTF_FW_VER_MAX)) {
282 ret = -1;
283 goto err_prog_firmware;
284 }
285
286 printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n");
287 return 0;
288
289err_prog_firmware:
290 priv->hw_reset_device(card);
291 return ret;
292}
293
294static void lbtf_op_stop(struct ieee80211_hw *hw)
295{
296 struct lbtf_private *priv = hw->priv;
297 unsigned long flags;
298 struct sk_buff *skb;
299
300 struct cmd_ctrl_node *cmdnode;
301 /* Flush pending command nodes */
302 spin_lock_irqsave(&priv->driver_lock, flags);
303 list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
304 cmdnode->result = -ENOENT;
305 cmdnode->cmdwaitqwoken = 1;
306 wake_up_interruptible(&cmdnode->cmdwait_q);
307 }
308
309 spin_unlock_irqrestore(&priv->driver_lock, flags);
310 cancel_work_sync(&priv->cmd_work);
311 cancel_work_sync(&priv->tx_work);
312 while ((skb = skb_dequeue(&priv->bc_ps_buf)))
313 dev_kfree_skb_any(skb);
314 priv->radioon = RADIO_OFF;
315 lbtf_set_radio_control(priv);
316
317 return;
318}
319
320static int lbtf_op_add_interface(struct ieee80211_hw *hw,
321 struct ieee80211_if_init_conf *conf)
322{
323 struct lbtf_private *priv = hw->priv;
324 if (priv->vif != NULL)
325 return -EOPNOTSUPP;
326
327 priv->vif = conf->vif;
328 switch (conf->type) {
329 case NL80211_IFTYPE_MESH_POINT:
330 case NL80211_IFTYPE_AP:
331 lbtf_set_mode(priv, LBTF_AP_MODE);
332 break;
333 case NL80211_IFTYPE_STATION:
334 lbtf_set_mode(priv, LBTF_STA_MODE);
335 break;
336 default:
337 priv->vif = NULL;
338 return -EOPNOTSUPP;
339 }
340 lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
341 return 0;
342}
343
344static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
345 struct ieee80211_if_init_conf *conf)
346{
347 struct lbtf_private *priv = hw->priv;
348
349 if (priv->vif->type == NL80211_IFTYPE_AP ||
350 priv->vif->type == NL80211_IFTYPE_MESH_POINT)
351 lbtf_beacon_ctrl(priv, 0, 0);
352 lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
353 lbtf_set_bssid(priv, 0, NULL);
354 priv->vif = NULL;
355}
356
357static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
358{
359 struct lbtf_private *priv = hw->priv;
360 if (conf->channel->center_freq != priv->cur_freq) {
361 priv->cur_freq = conf->channel->center_freq;
362 lbtf_set_channel(priv, conf->channel->hw_value);
363 }
364 return 0;
365}
366
367static int lbtf_op_config_interface(struct ieee80211_hw *hw,
368 struct ieee80211_vif *vif,
369 struct ieee80211_if_conf *conf)
370{
371 struct lbtf_private *priv = hw->priv;
372 struct sk_buff *beacon;
373
374 switch (priv->vif->type) {
375 case NL80211_IFTYPE_AP:
376 case NL80211_IFTYPE_MESH_POINT:
377 beacon = ieee80211_beacon_get(hw, vif);
378 if (beacon) {
379 lbtf_beacon_set(priv, beacon);
380 kfree_skb(beacon);
381 lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int);
382 }
383 break;
384 default:
385 break;
386 }
387
388 if (conf->bssid) {
389 u8 null_bssid[ETH_ALEN] = {0};
390 bool activate = compare_ether_addr(conf->bssid, null_bssid);
391 lbtf_set_bssid(priv, activate, conf->bssid);
392 }
393
394 return 0;
395}
396
397#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
398static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
399 unsigned int changed_flags,
400 unsigned int *new_flags,
401 int mc_count, struct dev_mc_list *mclist)
402{
403 struct lbtf_private *priv = hw->priv;
404 int old_mac_control = priv->mac_control;
405 int i;
406 changed_flags &= SUPPORTED_FIF_FLAGS;
407 *new_flags &= SUPPORTED_FIF_FLAGS;
408
409 if (!changed_flags)
410 return;
411
412 if (*new_flags & (FIF_PROMISC_IN_BSS))
413 priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
414 else
415 priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
416 if (*new_flags & (FIF_ALLMULTI) ||
417 mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
418 priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
419 priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
420 } else if (mc_count) {
421 priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
422 priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
423 priv->nr_of_multicastmacaddr = mc_count;
424 for (i = 0; i < mc_count; i++) {
425 if (!mclist)
426 break;
427 memcpy(&priv->multicastlist[i], mclist->da_addr,
428 ETH_ALEN);
429 mclist = mclist->next;
430 }
431 lbtf_cmd_set_mac_multicast_addr(priv);
432 } else {
433 priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
434 CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
435 if (priv->nr_of_multicastmacaddr) {
436 priv->nr_of_multicastmacaddr = 0;
437 lbtf_cmd_set_mac_multicast_addr(priv);
438 }
439 }
440
441
442 if (priv->mac_control != old_mac_control)
443 lbtf_set_mac_control(priv);
444}
445
446static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
447 struct ieee80211_vif *vif,
448 struct ieee80211_bss_conf *bss_conf,
449 u32 changes)
450{
451 struct lbtf_private *priv = hw->priv;
452
453 if (changes & BSS_CHANGED_ERP_PREAMBLE) {
454 if (bss_conf->use_short_preamble)
455 priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
456 else
457 priv->preamble = CMD_TYPE_LONG_PREAMBLE;
458 lbtf_set_radio_control(priv);
459 }
460
461 return;
462}
463
464static const struct ieee80211_ops lbtf_ops = {
465 .tx = lbtf_op_tx,
466 .start = lbtf_op_start,
467 .stop = lbtf_op_stop,
468 .add_interface = lbtf_op_add_interface,
469 .remove_interface = lbtf_op_remove_interface,
470 .config = lbtf_op_config,
471 .config_interface = lbtf_op_config_interface,
472 .configure_filter = lbtf_op_configure_filter,
473 .bss_info_changed = lbtf_op_bss_info_changed,
474};
475
476int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
477{
478 struct ieee80211_rx_status stats;
479 struct rxpd *prxpd;
480 int need_padding;
481 unsigned int flags;
482 struct ieee80211_hdr *hdr;
483
484 prxpd = (struct rxpd *) skb->data;
485
486 stats.flag = 0;
487 if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
488 stats.flag |= RX_FLAG_FAILED_FCS_CRC;
489 stats.freq = priv->cur_freq;
490 stats.band = IEEE80211_BAND_2GHZ;
491 stats.signal = prxpd->snr;
492 stats.noise = prxpd->nf;
493 stats.qual = prxpd->snr - prxpd->nf;
494 /* Marvell rate index has a hole at value 4 */
495 if (prxpd->rx_rate > 4)
496 --prxpd->rx_rate;
497 stats.rate_idx = prxpd->rx_rate;
498 skb_pull(skb, sizeof(struct rxpd));
499
500 hdr = (struct ieee80211_hdr *)skb->data;
501 flags = le32_to_cpu(*(__le32 *)(skb->data + 4));
502
503 need_padding = ieee80211_is_data_qos(hdr->frame_control);
504 need_padding ^= ieee80211_has_a4(hdr->frame_control);
505 need_padding ^= ieee80211_is_data_qos(hdr->frame_control) &&
506 (*ieee80211_get_qos_ctl(hdr) &
507 IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
508
509 if (need_padding) {
510 memmove(skb->data + 2, skb->data, skb->len);
511 skb_reserve(skb, 2);
512 }
513
514 ieee80211_rx_irqsafe(priv->hw, skb, &stats);
515 return 0;
516}
517EXPORT_SYMBOL_GPL(lbtf_rx);
518
519/**
520 * lbtf_add_card: Add and initialize the card, no fw upload yet.
521 *
522 * @card A pointer to card
523 *
524 * Returns: pointer to struct lbtf_priv.
525 */
526struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
527{
528 struct ieee80211_hw *hw;
529 struct lbtf_private *priv = NULL;
530
531 hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops);
532 if (!hw)
533 goto done;
534
535 priv = hw->priv;
536 if (lbtf_init_adapter(priv))
537 goto err_init_adapter;
538
539 priv->hw = hw;
540 priv->card = card;
541 priv->tx_skb = NULL;
542
543 hw->queues = 1;
544 hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
545 hw->extra_tx_headroom = sizeof(struct txpd);
546 memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels));
547 memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates));
548 priv->band.n_bitrates = ARRAY_SIZE(lbtf_rates);
549 priv->band.bitrates = priv->rates;
550 priv->band.n_channels = ARRAY_SIZE(lbtf_channels);
551 priv->band.channels = priv->channels;
552 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
553 skb_queue_head_init(&priv->bc_ps_buf);
554
555 SET_IEEE80211_DEV(hw, dmdev);
556
557 INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
558 INIT_WORK(&priv->tx_work, lbtf_tx_work);
559 if (ieee80211_register_hw(hw))
560 goto err_init_adapter;
561
562 goto done;
563
564err_init_adapter:
565 lbtf_free_adapter(priv);
566 ieee80211_free_hw(hw);
567 priv = NULL;
568
569done:
570 return priv;
571}
572EXPORT_SYMBOL_GPL(lbtf_add_card);
573
574
575int lbtf_remove_card(struct lbtf_private *priv)
576{
577 struct ieee80211_hw *hw = priv->hw;
578
579 priv->surpriseremoved = 1;
580 del_timer(&priv->command_timer);
581 lbtf_free_adapter(priv);
582 priv->hw = NULL;
583 ieee80211_unregister_hw(hw);
584 ieee80211_free_hw(hw);
585
586 return 0;
587}
588EXPORT_SYMBOL_GPL(lbtf_remove_card);
589
590void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
591{
592 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
593 memset(&info->status, 0, sizeof(info->status));
594 /*
595 * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
596 * default pid rc algorithm.
597 *
598 * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
599 */
600 info->status.excessive_retries = fail ? 1 : 0;
601 if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
602 info->flags |= IEEE80211_TX_STAT_ACK;
603 skb_pull(priv->tx_skb, sizeof(struct txpd));
604 ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
605 priv->tx_skb = NULL;
606 if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
607 ieee80211_wake_queues(priv->hw);
608 else
609 queue_work(lbtf_wq, &priv->tx_work);
610}
611EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback);
612
613void lbtf_bcn_sent(struct lbtf_private *priv)
614{
615 struct sk_buff *skb = NULL;
616
617 if (priv->vif->type != NL80211_IFTYPE_AP)
618 return;
619
620 if (skb_queue_empty(&priv->bc_ps_buf)) {
621 bool tx_buff_bc = 0;
622
623 while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) {
624 skb_queue_tail(&priv->bc_ps_buf, skb);
625 tx_buff_bc = 1;
626 }
627 if (tx_buff_bc) {
628 ieee80211_stop_queues(priv->hw);
629 queue_work(lbtf_wq, &priv->tx_work);
630 }
631 }
632
633 skb = ieee80211_beacon_get(priv->hw, priv->vif);
634
635 if (skb) {
636 lbtf_beacon_set(priv, skb);
637 kfree_skb(skb);
638 }
639}
640EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
641
642static int __init lbtf_init_module(void)
643{
644 lbtf_wq = create_workqueue("libertastf");
645 if (lbtf_wq == NULL) {
646 printk(KERN_ERR "libertastf: couldn't create workqueue\n");
647 return -ENOMEM;
648 }
649 return 0;
650}
651
652static void __exit lbtf_exit_module(void)
653{
654 destroy_workqueue(lbtf_wq);
655}
656
657module_init(lbtf_init_module);
658module_exit(lbtf_exit_module);
659
660MODULE_DESCRIPTION("Libertas WLAN Thinfirm Driver Library");
661MODULE_AUTHOR("Cozybit Inc.");
662MODULE_LICENSE("GPL");