blob: 60dc9b64381d8679abfa29d2174246a7dcf0bfce [file] [log] [blame]
Pierre Ossman727c26e2007-10-17 22:24:24 +02001/*
2 * linux/drivers/net/wireless/libertas/if_sdio.c
3 *
Pierre Ossmanad3868b2008-06-28 12:52:45 +02004 * Copyright 2007-2008 Pierre Ossman
Pierre Ossman727c26e2007-10-17 22:24:24 +02005 *
6 * Inspired by if_cs.c, Copyright 2007 Holger Schurig
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This hardware has more or less no CMD53 support, so all registers
14 * must be accessed using sdio_readb()/sdio_writeb().
15 *
16 * Transfers must be in one transaction or the firmware goes bonkers.
17 * This means that the transfer must either be small enough to do a
18 * byte based transfer or it must be padded to a multiple of the
19 * current block size.
20 *
21 * As SDIO is still new to the kernel, it is unfortunately common with
David Woodhouse7e226272007-12-14 22:53:41 -050022 * bugs in the host controllers related to that. One such bug is that
Pierre Ossman727c26e2007-10-17 22:24:24 +020023 * controllers cannot do transfers that aren't a multiple of 4 bytes.
24 * If you don't have time to fix the host controller driver, you can
25 * work around the problem by modifying if_sdio_host_to_card() and
26 * if_sdio_card_to_host() to pad the data.
27 */
28
Ilpo Järvinen23827922008-12-13 21:33:13 +020029#include <linux/kernel.h>
Pierre Ossman727c26e2007-10-17 22:24:24 +020030#include <linux/moduleparam.h>
31#include <linux/firmware.h>
32#include <linux/netdevice.h>
33#include <linux/delay.h>
34#include <linux/mmc/card.h>
35#include <linux/mmc/sdio_func.h>
36#include <linux/mmc/sdio_ids.h>
Daniel Mack8a64c0f2010-04-06 10:52:44 +020037#include <linux/mmc/sdio.h>
38#include <linux/mmc/host.h>
Pierre Ossman727c26e2007-10-17 22:24:24 +020039
40#include "host.h"
41#include "decl.h"
42#include "defs.h"
43#include "dev.h"
Bing Zhao6bc61f42009-06-01 18:04:36 -070044#include "cmd.h"
Pierre Ossman727c26e2007-10-17 22:24:24 +020045#include "if_sdio.h"
46
Bing Zhao6bc61f42009-06-01 18:04:36 -070047/* The if_sdio_remove() callback function is called when
48 * user removes this module from kernel space or ejects
49 * the card from the slot. The driver handles these 2 cases
50 * differently for SD8688 combo chip.
51 * If the user is removing the module, the FUNC_SHUTDOWN
52 * command for SD8688 is sent to the firmware.
53 * If the card is removed, there is no need to send this command.
54 *
55 * The variable 'user_rmmod' is used to distinguish these two
56 * scenarios. This flag is initialized as FALSE in case the card
57 * is removed, and will be set to TRUE for module removal when
58 * module_exit function is called.
59 */
60static u8 user_rmmod;
61
Holger Schurig10078322007-11-15 18:05:47 -050062static char *lbs_helper_name = NULL;
63module_param_named(helper_name, lbs_helper_name, charp, 0644);
Pierre Ossman727c26e2007-10-17 22:24:24 +020064
Holger Schurig10078322007-11-15 18:05:47 -050065static char *lbs_fw_name = NULL;
66module_param_named(fw_name, lbs_fw_name, charp, 0644);
Pierre Ossman727c26e2007-10-17 22:24:24 +020067
68static const struct sdio_device_id if_sdio_ids[] = {
Bing Zhaoe45d8e52009-04-06 15:50:56 -070069 { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
70 SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
71 { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
72 SDIO_DEVICE_ID_MARVELL_8688WLAN) },
73 { /* end: all zeroes */ },
Pierre Ossman727c26e2007-10-17 22:24:24 +020074};
75
76MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
77
78struct if_sdio_model {
79 int model;
80 const char *helper;
81 const char *firmware;
82};
83
84static struct if_sdio_model if_sdio_models[] = {
85 {
86 /* 8385 */
Bing Zhaoe70a5ac2009-05-19 19:48:18 -070087 .model = IF_SDIO_MODEL_8385,
Pierre Ossman727c26e2007-10-17 22:24:24 +020088 .helper = "sd8385_helper.bin",
89 .firmware = "sd8385.bin",
90 },
91 {
92 /* 8686 */
Bing Zhaoe70a5ac2009-05-19 19:48:18 -070093 .model = IF_SDIO_MODEL_8686,
Pierre Ossman727c26e2007-10-17 22:24:24 +020094 .helper = "sd8686_helper.bin",
95 .firmware = "sd8686.bin",
96 },
Bing Zhaoe45d8e52009-04-06 15:50:56 -070097 {
98 /* 8688 */
Bing Zhaoe70a5ac2009-05-19 19:48:18 -070099 .model = IF_SDIO_MODEL_8688,
Bing Zhaoe45d8e52009-04-06 15:50:56 -0700100 .helper = "sd8688_helper.bin",
101 .firmware = "sd8688.bin",
102 },
Pierre Ossman727c26e2007-10-17 22:24:24 +0200103};
Ben Hutchingsa974a4b2009-11-07 22:00:03 +0000104MODULE_FIRMWARE("sd8385_helper.bin");
105MODULE_FIRMWARE("sd8385.bin");
106MODULE_FIRMWARE("sd8686_helper.bin");
107MODULE_FIRMWARE("sd8686.bin");
108MODULE_FIRMWARE("sd8688_helper.bin");
109MODULE_FIRMWARE("sd8688.bin");
Pierre Ossman727c26e2007-10-17 22:24:24 +0200110
111struct if_sdio_packet {
112 struct if_sdio_packet *next;
113 u16 nb;
114 u8 buffer[0] __attribute__((aligned(4)));
115};
116
117struct if_sdio_card {
118 struct sdio_func *func;
Holger Schurig69f90322007-11-23 15:43:44 +0100119 struct lbs_private *priv;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200120
121 int model;
122 unsigned long ioport;
Bing Zhao2c7e5792009-05-21 11:32:34 -0700123 unsigned int scratch_reg;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200124
125 const char *helper;
126 const char *firmware;
127
128 u8 buffer[65536];
Pierre Ossman727c26e2007-10-17 22:24:24 +0200129
130 spinlock_t lock;
131 struct if_sdio_packet *packets;
Dan Williams9b02f412009-02-20 12:27:38 -0500132
133 struct workqueue_struct *workqueue;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200134 struct work_struct packet_worker;
Bing Zhaob136a142009-05-19 19:48:19 -0700135
136 u8 rx_unit;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200137};
138
139/********************************************************************/
140/* I/O */
141/********************************************************************/
142
Bing Zhao2c7e5792009-05-21 11:32:34 -0700143/*
144 * For SD8385/SD8686, this function reads firmware status after
145 * the image is downloaded, or reads RX packet length when
146 * interrupt (with IF_SDIO_H_INT_UPLD bit set) is received.
147 * For SD8688, this function reads firmware status only.
148 */
Pierre Ossman727c26e2007-10-17 22:24:24 +0200149static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
150{
Bing Zhao2c7e5792009-05-21 11:32:34 -0700151 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200152 u16 scratch;
153
Bing Zhao2c7e5792009-05-21 11:32:34 -0700154 scratch = sdio_readb(card->func, card->scratch_reg, &ret);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200155 if (!ret)
Bing Zhao2c7e5792009-05-21 11:32:34 -0700156 scratch |= sdio_readb(card->func, card->scratch_reg + 1,
157 &ret) << 8;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200158
159 if (err)
160 *err = ret;
161
162 if (ret)
163 return 0xffff;
164
165 return scratch;
166}
167
Bing Zhaob136a142009-05-19 19:48:19 -0700168static u8 if_sdio_read_rx_unit(struct if_sdio_card *card)
169{
170 int ret;
171 u8 rx_unit;
172
173 rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret);
174
175 if (ret)
176 rx_unit = 0;
177
178 return rx_unit;
179}
180
181static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
182{
183 int ret;
184 u16 rx_len;
185
186 switch (card->model) {
187 case IF_SDIO_MODEL_8385:
188 case IF_SDIO_MODEL_8686:
189 rx_len = if_sdio_read_scratch(card, &ret);
190 break;
191 case IF_SDIO_MODEL_8688:
192 default: /* for newer chipsets */
193 rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
194 if (!ret)
195 rx_len <<= card->rx_unit;
196 else
197 rx_len = 0xffff; /* invalid length */
198
199 break;
200 }
201
202 if (err)
203 *err = ret;
204
205 return rx_len;
206}
207
Pierre Ossman727c26e2007-10-17 22:24:24 +0200208static int if_sdio_handle_cmd(struct if_sdio_card *card,
209 u8 *buffer, unsigned size)
210{
Holger Schurig7919b892008-04-01 14:50:43 +0200211 struct lbs_private *priv = card->priv;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200212 int ret;
213 unsigned long flags;
Holger Schurig7919b892008-04-01 14:50:43 +0200214 u8 i;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200215
216 lbs_deb_enter(LBS_DEB_SDIO);
217
Dan Williamsddac4522007-12-11 13:49:39 -0500218 if (size > LBS_CMD_BUFFER_SIZE) {
Pierre Ossman727c26e2007-10-17 22:24:24 +0200219 lbs_deb_sdio("response packet too large (%d bytes)\n",
220 (int)size);
221 ret = -E2BIG;
222 goto out;
223 }
224
Holger Schurig7919b892008-04-01 14:50:43 +0200225 spin_lock_irqsave(&priv->driver_lock, flags);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200226
Holger Schurig7919b892008-04-01 14:50:43 +0200227 i = (priv->resp_idx == 0) ? 1 : 0;
228 BUG_ON(priv->resp_len[i]);
229 priv->resp_len[i] = size;
230 memcpy(priv->resp_buf[i], buffer, size);
231 lbs_notify_command_response(priv, i);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200232
Holger Schurig7919b892008-04-01 14:50:43 +0200233 spin_unlock_irqrestore(&card->priv->driver_lock, flags);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200234
235 ret = 0;
236
237out:
Pierre Ossman727c26e2007-10-17 22:24:24 +0200238 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200239 return ret;
240}
241
242static int if_sdio_handle_data(struct if_sdio_card *card,
243 u8 *buffer, unsigned size)
244{
245 int ret;
246 struct sk_buff *skb;
247 char *data;
248
249 lbs_deb_enter(LBS_DEB_SDIO);
250
251 if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
252 lbs_deb_sdio("response packet too large (%d bytes)\n",
253 (int)size);
254 ret = -E2BIG;
255 goto out;
256 }
257
Pierre Ossman51e6b712007-10-22 19:05:32 +0200258 skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200259 if (!skb) {
260 ret = -ENOMEM;
261 goto out;
262 }
263
Pierre Ossman51e6b712007-10-22 19:05:32 +0200264 skb_reserve(skb, NET_IP_ALIGN);
265
Pierre Ossman727c26e2007-10-17 22:24:24 +0200266 data = skb_put(skb, size);
267
268 memcpy(data, buffer, size);
269
Holger Schurig10078322007-11-15 18:05:47 -0500270 lbs_process_rxed_packet(card->priv, skb);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200271
272 ret = 0;
273
274out:
275 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
276
277 return ret;
278}
279
280static int if_sdio_handle_event(struct if_sdio_card *card,
281 u8 *buffer, unsigned size)
282{
283 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200284 u32 event;
285
286 lbs_deb_enter(LBS_DEB_SDIO);
287
Bing Zhaoe70a5ac2009-05-19 19:48:18 -0700288 if (card->model == IF_SDIO_MODEL_8385) {
Pierre Ossman727c26e2007-10-17 22:24:24 +0200289 event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
290 if (ret)
291 goto out;
Bing Zhaof5ac2b92009-02-04 22:22:39 -0800292
293 /* right shift 3 bits to get the event id */
294 event >>= 3;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200295 } else {
296 if (size < 4) {
297 lbs_deb_sdio("event packet too small (%d bytes)\n",
298 (int)size);
299 ret = -EINVAL;
300 goto out;
301 }
302 event = buffer[3] << 24;
303 event |= buffer[2] << 16;
304 event |= buffer[1] << 8;
305 event |= buffer[0] << 0;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200306 }
307
Holger Schurig7919b892008-04-01 14:50:43 +0200308 lbs_queue_event(card->priv, event & 0xFF);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200309 ret = 0;
310
311out:
312 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
313
314 return ret;
315}
316
Dan Williams96021f02010-04-15 13:27:44 -0700317static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
318{
319 u8 status;
320 unsigned long timeout;
321 int ret = 0;
322
323 timeout = jiffies + HZ;
324 while (1) {
325 status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
326 if (ret || (status & condition))
327 break;
328 if (time_after(jiffies, timeout))
329 return -ETIMEDOUT;
330 mdelay(1);
331 }
332 return ret;
333}
334
Pierre Ossman727c26e2007-10-17 22:24:24 +0200335static int if_sdio_card_to_host(struct if_sdio_card *card)
336{
337 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200338 u16 size, type, chunk;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200339
340 lbs_deb_enter(LBS_DEB_SDIO);
341
Bing Zhaob136a142009-05-19 19:48:19 -0700342 size = if_sdio_read_rx_len(card, &ret);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200343 if (ret)
344 goto out;
345
346 if (size < 4) {
347 lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
348 (int)size);
349 ret = -EINVAL;
350 goto out;
351 }
352
Dan Williams96021f02010-04-15 13:27:44 -0700353 ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
354 if (ret)
355 goto out;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200356
357 /*
358 * The transfer must be in one transaction or the firmware
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200359 * goes suicidal. There's no way to guarantee that for all
360 * controllers, but we can at least try.
Pierre Ossman727c26e2007-10-17 22:24:24 +0200361 */
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200362 chunk = sdio_align_size(card->func, size);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200363
364 ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
365 if (ret)
366 goto out;
367
368 chunk = card->buffer[0] | (card->buffer[1] << 8);
369 type = card->buffer[2] | (card->buffer[3] << 8);
370
371 lbs_deb_sdio("packet of type %d and size %d bytes\n",
372 (int)type, (int)chunk);
373
374 if (chunk > size) {
375 lbs_deb_sdio("packet fragment (%d > %d)\n",
376 (int)chunk, (int)size);
377 ret = -EINVAL;
378 goto out;
379 }
380
381 if (chunk < size) {
382 lbs_deb_sdio("packet fragment (%d < %d)\n",
383 (int)chunk, (int)size);
384 }
385
386 switch (type) {
387 case MVMS_CMD:
388 ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
389 if (ret)
390 goto out;
391 break;
392 case MVMS_DAT:
393 ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
394 if (ret)
395 goto out;
396 break;
397 case MVMS_EVENT:
398 ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
399 if (ret)
400 goto out;
401 break;
402 default:
403 lbs_deb_sdio("invalid type (%d) from firmware\n",
404 (int)type);
405 ret = -EINVAL;
406 goto out;
407 }
408
409out:
410 if (ret)
411 lbs_pr_err("problem fetching packet from firmware\n");
412
413 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
414
415 return ret;
416}
417
418static void if_sdio_host_to_card_worker(struct work_struct *work)
419{
420 struct if_sdio_card *card;
421 struct if_sdio_packet *packet;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200422 int ret;
423 unsigned long flags;
424
425 lbs_deb_enter(LBS_DEB_SDIO);
426
427 card = container_of(work, struct if_sdio_card, packet_worker);
428
429 while (1) {
430 spin_lock_irqsave(&card->lock, flags);
431 packet = card->packets;
432 if (packet)
433 card->packets = packet->next;
434 spin_unlock_irqrestore(&card->lock, flags);
435
436 if (!packet)
437 break;
438
439 sdio_claim_host(card->func);
440
Dan Williams96021f02010-04-15 13:27:44 -0700441 ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
442 if (ret == 0) {
443 ret = sdio_writesb(card->func, card->ioport,
444 packet->buffer, packet->nb);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200445 }
446
Pierre Ossman727c26e2007-10-17 22:24:24 +0200447 if (ret)
Dan Williams96021f02010-04-15 13:27:44 -0700448 lbs_pr_err("error %d sending packet to firmware\n", ret);
449
Pierre Ossman727c26e2007-10-17 22:24:24 +0200450 sdio_release_host(card->func);
451
452 kfree(packet);
453 }
454
455 lbs_deb_leave(LBS_DEB_SDIO);
456}
457
458/********************************************************************/
459/* Firmware */
460/********************************************************************/
461
Dan Williams96021f02010-04-15 13:27:44 -0700462#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
463
Pierre Ossman727c26e2007-10-17 22:24:24 +0200464static int if_sdio_prog_helper(struct if_sdio_card *card)
465{
466 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200467 const struct firmware *fw;
468 unsigned long timeout;
469 u8 *chunk_buffer;
470 u32 chunk_size;
David Woodhouse6dfff892008-05-23 18:37:51 +0100471 const u8 *firmware;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200472 size_t size;
473
474 lbs_deb_enter(LBS_DEB_SDIO);
475
476 ret = request_firmware(&fw, card->helper, &card->func->dev);
477 if (ret) {
478 lbs_pr_err("can't load helper firmware\n");
479 goto out;
480 }
481
482 chunk_buffer = kzalloc(64, GFP_KERNEL);
483 if (!chunk_buffer) {
484 ret = -ENOMEM;
485 goto release_fw;
486 }
487
488 sdio_claim_host(card->func);
489
490 ret = sdio_set_block_size(card->func, 32);
491 if (ret)
492 goto release;
493
494 firmware = fw->data;
495 size = fw->size;
496
497 while (size) {
Dan Williams96021f02010-04-15 13:27:44 -0700498 ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
499 if (ret)
500 goto release;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200501
502 chunk_size = min(size, (size_t)60);
503
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000504 *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200505 memcpy(chunk_buffer + 4, firmware, chunk_size);
506/*
507 lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
508*/
509 ret = sdio_writesb(card->func, card->ioport,
510 chunk_buffer, 64);
511 if (ret)
512 goto release;
513
514 firmware += chunk_size;
515 size -= chunk_size;
516 }
517
518 /* an empty block marks the end of the transfer */
519 memset(chunk_buffer, 0, 4);
520 ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
521 if (ret)
522 goto release;
523
524 lbs_deb_sdio("waiting for helper to boot...\n");
525
526 /* wait for the helper to boot by looking at the size register */
527 timeout = jiffies + HZ;
528 while (1) {
529 u16 req_size;
530
531 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
532 if (ret)
533 goto release;
534
535 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
536 if (ret)
537 goto release;
538
539 if (req_size != 0)
540 break;
541
542 if (time_after(jiffies, timeout)) {
543 ret = -ETIMEDOUT;
544 goto release;
545 }
546
547 msleep(10);
548 }
549
550 ret = 0;
551
552release:
Pierre Ossman727c26e2007-10-17 22:24:24 +0200553 sdio_release_host(card->func);
554 kfree(chunk_buffer);
555release_fw:
556 release_firmware(fw);
557
558out:
559 if (ret)
560 lbs_pr_err("failed to load helper firmware\n");
561
562 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
563
564 return ret;
565}
566
567static int if_sdio_prog_real(struct if_sdio_card *card)
568{
569 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200570 const struct firmware *fw;
571 unsigned long timeout;
572 u8 *chunk_buffer;
573 u32 chunk_size;
David Woodhouse6dfff892008-05-23 18:37:51 +0100574 const u8 *firmware;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200575 size_t size, req_size;
576
577 lbs_deb_enter(LBS_DEB_SDIO);
578
579 ret = request_firmware(&fw, card->firmware, &card->func->dev);
580 if (ret) {
581 lbs_pr_err("can't load firmware\n");
582 goto out;
583 }
584
585 chunk_buffer = kzalloc(512, GFP_KERNEL);
586 if (!chunk_buffer) {
587 ret = -ENOMEM;
588 goto release_fw;
589 }
590
591 sdio_claim_host(card->func);
592
593 ret = sdio_set_block_size(card->func, 32);
594 if (ret)
595 goto release;
596
597 firmware = fw->data;
598 size = fw->size;
599
600 while (size) {
Dan Williams96021f02010-04-15 13:27:44 -0700601 ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
602 if (ret)
603 goto release;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200604
605 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
606 if (ret)
607 goto release;
608
609 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
610 if (ret)
611 goto release;
612/*
613 lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
614*/
615 if (req_size == 0) {
616 lbs_deb_sdio("firmware helper gave up early\n");
617 ret = -EIO;
618 goto release;
619 }
620
621 if (req_size & 0x01) {
622 lbs_deb_sdio("firmware helper signalled error\n");
623 ret = -EIO;
624 goto release;
625 }
626
627 if (req_size > size)
628 req_size = size;
629
630 while (req_size) {
631 chunk_size = min(req_size, (size_t)512);
632
633 memcpy(chunk_buffer, firmware, chunk_size);
634/*
635 lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
636 chunk_size, (chunk_size + 31) / 32 * 32);
637*/
638 ret = sdio_writesb(card->func, card->ioport,
Ilpo Järvinen23827922008-12-13 21:33:13 +0200639 chunk_buffer, roundup(chunk_size, 32));
Pierre Ossman727c26e2007-10-17 22:24:24 +0200640 if (ret)
641 goto release;
642
643 firmware += chunk_size;
644 size -= chunk_size;
645 req_size -= chunk_size;
646 }
647 }
648
649 ret = 0;
650
651 lbs_deb_sdio("waiting for firmware to boot...\n");
652
653 /* wait for the firmware to boot */
654 timeout = jiffies + HZ;
655 while (1) {
656 u16 scratch;
657
658 scratch = if_sdio_read_scratch(card, &ret);
659 if (ret)
660 goto release;
661
662 if (scratch == IF_SDIO_FIRMWARE_OK)
663 break;
664
665 if (time_after(jiffies, timeout)) {
666 ret = -ETIMEDOUT;
667 goto release;
668 }
669
670 msleep(10);
671 }
672
673 ret = 0;
674
675release:
Pierre Ossman727c26e2007-10-17 22:24:24 +0200676 sdio_release_host(card->func);
677 kfree(chunk_buffer);
678release_fw:
679 release_firmware(fw);
680
681out:
682 if (ret)
683 lbs_pr_err("failed to load firmware\n");
684
685 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
686
687 return ret;
688}
689
690static int if_sdio_prog_firmware(struct if_sdio_card *card)
691{
692 int ret;
693 u16 scratch;
694
695 lbs_deb_enter(LBS_DEB_SDIO);
696
697 sdio_claim_host(card->func);
698 scratch = if_sdio_read_scratch(card, &ret);
699 sdio_release_host(card->func);
700
701 if (ret)
702 goto out;
703
Bing Zhao2c7e5792009-05-21 11:32:34 -0700704 lbs_deb_sdio("firmware status = %#x\n", scratch);
705
Pierre Ossman727c26e2007-10-17 22:24:24 +0200706 if (scratch == IF_SDIO_FIRMWARE_OK) {
707 lbs_deb_sdio("firmware already loaded\n");
708 goto success;
709 }
710
711 ret = if_sdio_prog_helper(card);
712 if (ret)
713 goto out;
714
715 ret = if_sdio_prog_real(card);
716 if (ret)
717 goto out;
718
719success:
Bing Zhaod26285f82009-05-19 19:48:20 -0700720 sdio_claim_host(card->func);
721 sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
722 sdio_release_host(card->func);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200723 ret = 0;
724
725out:
726 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
727
728 return ret;
729}
730
731/*******************************************************************/
732/* Libertas callbacks */
733/*******************************************************************/
734
Holger Schurig69f90322007-11-23 15:43:44 +0100735static int if_sdio_host_to_card(struct lbs_private *priv,
736 u8 type, u8 *buf, u16 nb)
Pierre Ossman727c26e2007-10-17 22:24:24 +0200737{
738 int ret;
739 struct if_sdio_card *card;
740 struct if_sdio_packet *packet, *cur;
741 u16 size;
742 unsigned long flags;
743
744 lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
745
746 card = priv->card;
747
748 if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
749 ret = -EINVAL;
750 goto out;
751 }
752
753 /*
754 * The transfer must be in one transaction or the firmware
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200755 * goes suicidal. There's no way to guarantee that for all
756 * controllers, but we can at least try.
Pierre Ossman727c26e2007-10-17 22:24:24 +0200757 */
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200758 size = sdio_align_size(card->func, nb + 4);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200759
760 packet = kzalloc(sizeof(struct if_sdio_packet) + size,
761 GFP_ATOMIC);
762 if (!packet) {
763 ret = -ENOMEM;
764 goto out;
765 }
766
767 packet->next = NULL;
768 packet->nb = size;
769
770 /*
771 * SDIO specific header.
772 */
773 packet->buffer[0] = (nb + 4) & 0xff;
774 packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
775 packet->buffer[2] = type;
776 packet->buffer[3] = 0;
777
778 memcpy(packet->buffer + 4, buf, nb);
779
780 spin_lock_irqsave(&card->lock, flags);
781
782 if (!card->packets)
783 card->packets = packet;
784 else {
785 cur = card->packets;
786 while (cur->next)
787 cur = cur->next;
788 cur->next = packet;
789 }
790
791 switch (type) {
792 case MVMS_CMD:
793 priv->dnld_sent = DNLD_CMD_SENT;
794 break;
795 case MVMS_DAT:
796 priv->dnld_sent = DNLD_DATA_SENT;
797 break;
798 default:
799 lbs_deb_sdio("unknown packet type %d\n", (int)type);
800 }
801
802 spin_unlock_irqrestore(&card->lock, flags);
803
Dan Williams9b02f412009-02-20 12:27:38 -0500804 queue_work(card->workqueue, &card->packet_worker);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200805
806 ret = 0;
807
808out:
809 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
810
811 return ret;
812}
813
Amitkumar Karwar49125452009-09-30 20:04:38 -0700814static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
815{
816 int ret = -1;
817 struct cmd_header cmd;
818
819 memset(&cmd, 0, sizeof(cmd));
820
821 lbs_deb_sdio("send DEEP_SLEEP command\n");
822 ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
823 lbs_cmd_copyback, (unsigned long) &cmd);
824 if (ret)
825 lbs_pr_err("DEEP_SLEEP cmd failed\n");
826
827 mdelay(200);
828 return ret;
829}
830
831static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
832{
833 struct if_sdio_card *card = priv->card;
834 int ret = -1;
835
836 lbs_deb_enter(LBS_DEB_SDIO);
837 sdio_claim_host(card->func);
838
839 sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
840 if (ret)
841 lbs_pr_err("sdio_writeb failed!\n");
842
843 sdio_release_host(card->func);
844 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
845 return ret;
846}
847
848static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
849{
850 struct if_sdio_card *card = priv->card;
851 int ret = -1;
852
853 lbs_deb_enter(LBS_DEB_SDIO);
854 sdio_claim_host(card->func);
855
856 sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
857 if (ret)
858 lbs_pr_err("sdio_writeb failed!\n");
859
860 sdio_release_host(card->func);
861 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
862 return ret;
863
864}
865
Pierre Ossman727c26e2007-10-17 22:24:24 +0200866/*******************************************************************/
867/* SDIO callbacks */
868/*******************************************************************/
869
870static void if_sdio_interrupt(struct sdio_func *func)
871{
872 int ret;
873 struct if_sdio_card *card;
874 u8 cause;
875
876 lbs_deb_enter(LBS_DEB_SDIO);
877
878 card = sdio_get_drvdata(func);
879
880 cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
881 if (ret)
882 goto out;
883
884 lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
885
886 sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
887 if (ret)
888 goto out;
889
890 /*
891 * Ignore the define name, this really means the card has
892 * successfully received the command.
893 */
Amitkumar Karwar49125452009-09-30 20:04:38 -0700894 card->priv->is_activity_detected = 1;
David Woodhousee775ed72007-12-06 14:36:11 +0000895 if (cause & IF_SDIO_H_INT_DNLD)
896 lbs_host_to_card_done(card->priv);
897
Pierre Ossman727c26e2007-10-17 22:24:24 +0200898
899 if (cause & IF_SDIO_H_INT_UPLD) {
900 ret = if_sdio_card_to_host(card);
901 if (ret)
902 goto out;
903 }
904
905 ret = 0;
906
907out:
908 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
909}
910
911static int if_sdio_probe(struct sdio_func *func,
912 const struct sdio_device_id *id)
913{
914 struct if_sdio_card *card;
Holger Schurig69f90322007-11-23 15:43:44 +0100915 struct lbs_private *priv;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200916 int ret, i;
917 unsigned int model;
918 struct if_sdio_packet *packet;
Daniel Mack8a64c0f2010-04-06 10:52:44 +0200919 struct mmc_host *host = func->card->host;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200920
921 lbs_deb_enter(LBS_DEB_SDIO);
922
923 for (i = 0;i < func->card->num_info;i++) {
924 if (sscanf(func->card->info[i],
925 "802.11 SDIO ID: %x", &model) == 1)
926 break;
927 if (sscanf(func->card->info[i],
928 "ID: %x", &model) == 1)
929 break;
Bing Zhaoe70a5ac2009-05-19 19:48:18 -0700930 if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
931 model = IF_SDIO_MODEL_8385;
932 break;
933 }
Pierre Ossman727c26e2007-10-17 22:24:24 +0200934 }
935
936 if (i == func->card->num_info) {
937 lbs_pr_err("unable to identify card model\n");
938 return -ENODEV;
939 }
940
941 card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
942 if (!card)
943 return -ENOMEM;
944
945 card->func = func;
946 card->model = model;
Bing Zhao2c7e5792009-05-21 11:32:34 -0700947
948 switch (card->model) {
949 case IF_SDIO_MODEL_8385:
950 card->scratch_reg = IF_SDIO_SCRATCH_OLD;
951 break;
952 case IF_SDIO_MODEL_8686:
953 card->scratch_reg = IF_SDIO_SCRATCH;
954 break;
955 case IF_SDIO_MODEL_8688:
956 default: /* for newer chipsets */
957 card->scratch_reg = IF_SDIO_FW_STATUS;
958 break;
959 }
960
Pierre Ossman727c26e2007-10-17 22:24:24 +0200961 spin_lock_init(&card->lock);
Dan Williams9b02f412009-02-20 12:27:38 -0500962 card->workqueue = create_workqueue("libertas_sdio");
Pierre Ossman727c26e2007-10-17 22:24:24 +0200963 INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
964
965 for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
966 if (card->model == if_sdio_models[i].model)
967 break;
968 }
969
970 if (i == ARRAY_SIZE(if_sdio_models)) {
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200971 lbs_pr_err("unknown card model 0x%x\n", card->model);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200972 ret = -ENODEV;
973 goto free;
974 }
975
976 card->helper = if_sdio_models[i].helper;
977 card->firmware = if_sdio_models[i].firmware;
978
Holger Schurig10078322007-11-15 18:05:47 -0500979 if (lbs_helper_name) {
Pierre Ossman727c26e2007-10-17 22:24:24 +0200980 lbs_deb_sdio("overriding helper firmware: %s\n",
Holger Schurig10078322007-11-15 18:05:47 -0500981 lbs_helper_name);
982 card->helper = lbs_helper_name;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200983 }
984
Holger Schurig10078322007-11-15 18:05:47 -0500985 if (lbs_fw_name) {
986 lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
987 card->firmware = lbs_fw_name;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200988 }
989
990 sdio_claim_host(func);
991
992 ret = sdio_enable_func(func);
993 if (ret)
994 goto release;
995
996 ret = sdio_claim_irq(func, if_sdio_interrupt);
997 if (ret)
998 goto disable;
999
Daniel Mack8a64c0f2010-04-06 10:52:44 +02001000 /* For 1-bit transfers to the 8686 model, we need to enable the
1001 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
1002 * bit to allow access to non-vendor registers. */
1003 if ((card->model == IF_SDIO_MODEL_8686) &&
1004 (host->caps & MMC_CAP_SDIO_IRQ) &&
1005 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
1006 u8 reg;
1007
1008 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1009 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
1010 if (ret)
1011 goto release_int;
1012
1013 reg |= SDIO_BUS_ECSI;
1014 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
1015 if (ret)
1016 goto release_int;
1017 }
1018
Pierre Ossman727c26e2007-10-17 22:24:24 +02001019 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
1020 if (ret)
1021 goto release_int;
1022
1023 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
1024 if (ret)
1025 goto release_int;
1026
1027 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
1028 if (ret)
1029 goto release_int;
1030
1031 sdio_release_host(func);
1032
1033 sdio_set_drvdata(func, card);
1034
1035 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
1036 "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
1037 func->class, func->vendor, func->device,
1038 model, (unsigned)card->ioport);
1039
1040 ret = if_sdio_prog_firmware(card);
1041 if (ret)
1042 goto reclaim;
1043
Holger Schurig10078322007-11-15 18:05:47 -05001044 priv = lbs_add_card(card, &func->dev);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001045 if (!priv) {
1046 ret = -ENOMEM;
1047 goto reclaim;
1048 }
1049
1050 card->priv = priv;
1051
1052 priv->card = card;
1053 priv->hw_host_to_card = if_sdio_host_to_card;
Amitkumar Karwar49125452009-09-30 20:04:38 -07001054 priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
1055 priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
1056 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001057
David Woodhouseaa21c002007-12-08 20:04:36 +00001058 priv->fw_ready = 1;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001059
Bing Zhaob136a142009-05-19 19:48:19 -07001060 sdio_claim_host(func);
1061
1062 /*
1063 * Get rx_unit if the chip is SD8688 or newer.
1064 * SD8385 & SD8686 do not have rx_unit.
1065 */
1066 if ((card->model != IF_SDIO_MODEL_8385)
1067 && (card->model != IF_SDIO_MODEL_8686))
1068 card->rx_unit = if_sdio_read_rx_unit(card);
1069 else
1070 card->rx_unit = 0;
1071
Pierre Ossman727c26e2007-10-17 22:24:24 +02001072 /*
1073 * Enable interrupts now that everything is set up
1074 */
Pierre Ossman727c26e2007-10-17 22:24:24 +02001075 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
1076 sdio_release_host(func);
1077 if (ret)
1078 goto reclaim;
1079
Bing Zhaod26285f82009-05-19 19:48:20 -07001080 /*
1081 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
1082 */
Bing Zhao6bc61f42009-06-01 18:04:36 -07001083 if (card->model == IF_SDIO_MODEL_8688) {
1084 struct cmd_header cmd;
1085
1086 memset(&cmd, 0, sizeof(cmd));
1087
1088 lbs_deb_sdio("send function INIT command\n");
1089 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1090 lbs_cmd_copyback, (unsigned long) &cmd))
1091 lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
1092 }
Bing Zhaod26285f82009-05-19 19:48:20 -07001093
Holger Schurig10078322007-11-15 18:05:47 -05001094 ret = lbs_start_card(priv);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001095 if (ret)
1096 goto err_activate_card;
1097
1098out:
1099 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1100
1101 return ret;
1102
1103err_activate_card:
Dan Williams9b02f412009-02-20 12:27:38 -05001104 flush_workqueue(card->workqueue);
1105 lbs_remove_card(priv);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001106reclaim:
1107 sdio_claim_host(func);
1108release_int:
1109 sdio_release_irq(func);
1110disable:
1111 sdio_disable_func(func);
1112release:
1113 sdio_release_host(func);
1114free:
Dan Williams9b02f412009-02-20 12:27:38 -05001115 destroy_workqueue(card->workqueue);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001116 while (card->packets) {
1117 packet = card->packets;
1118 card->packets = card->packets->next;
1119 kfree(packet);
1120 }
1121
1122 kfree(card);
1123
1124 goto out;
1125}
1126
1127static void if_sdio_remove(struct sdio_func *func)
1128{
1129 struct if_sdio_card *card;
1130 struct if_sdio_packet *packet;
1131
1132 lbs_deb_enter(LBS_DEB_SDIO);
1133
1134 card = sdio_get_drvdata(func);
1135
Bing Zhao6bc61f42009-06-01 18:04:36 -07001136 if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
1137 /*
1138 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
1139 * multiple functions
1140 */
1141 struct cmd_header cmd;
1142
1143 memset(&cmd, 0, sizeof(cmd));
1144
1145 lbs_deb_sdio("send function SHUTDOWN command\n");
1146 if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
1147 &cmd, sizeof(cmd), lbs_cmd_copyback,
1148 (unsigned long) &cmd))
1149 lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
1150 }
Bing Zhaod26285f82009-05-19 19:48:20 -07001151
Pierre Ossman727c26e2007-10-17 22:24:24 +02001152
1153 lbs_deb_sdio("call remove card\n");
Bing Zhao6bc61f42009-06-01 18:04:36 -07001154 lbs_stop_card(card->priv);
Holger Schurig10078322007-11-15 18:05:47 -05001155 lbs_remove_card(card->priv);
Andrey Yurovsky23b149c2009-06-17 19:15:19 -07001156 card->priv->surpriseremoved = 1;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001157
Dan Williams9b02f412009-02-20 12:27:38 -05001158 flush_workqueue(card->workqueue);
1159 destroy_workqueue(card->workqueue);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001160
1161 sdio_claim_host(func);
1162 sdio_release_irq(func);
1163 sdio_disable_func(func);
1164 sdio_release_host(func);
1165
1166 while (card->packets) {
1167 packet = card->packets;
1168 card->packets = card->packets->next;
1169 kfree(packet);
1170 }
1171
1172 kfree(card);
1173
1174 lbs_deb_leave(LBS_DEB_SDIO);
1175}
1176
1177static struct sdio_driver if_sdio_driver = {
1178 .name = "libertas_sdio",
1179 .id_table = if_sdio_ids,
1180 .probe = if_sdio_probe,
1181 .remove = if_sdio_remove,
1182};
1183
1184/*******************************************************************/
1185/* Module functions */
1186/*******************************************************************/
1187
Andres Salomon4fb910f2007-11-20 17:43:45 -05001188static int __init if_sdio_init_module(void)
Pierre Ossman727c26e2007-10-17 22:24:24 +02001189{
1190 int ret = 0;
1191
1192 lbs_deb_enter(LBS_DEB_SDIO);
1193
1194 printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
1195 printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
1196
1197 ret = sdio_register_driver(&if_sdio_driver);
1198
Bing Zhao6bc61f42009-06-01 18:04:36 -07001199 /* Clear the flag in case user removes the card. */
1200 user_rmmod = 0;
1201
Pierre Ossman727c26e2007-10-17 22:24:24 +02001202 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1203
1204 return ret;
1205}
1206
Andres Salomon4fb910f2007-11-20 17:43:45 -05001207static void __exit if_sdio_exit_module(void)
Pierre Ossman727c26e2007-10-17 22:24:24 +02001208{
1209 lbs_deb_enter(LBS_DEB_SDIO);
1210
Bing Zhao6bc61f42009-06-01 18:04:36 -07001211 /* Set the flag as user is removing this module. */
1212 user_rmmod = 1;
Bing Zhaod26285f82009-05-19 19:48:20 -07001213
Pierre Ossman727c26e2007-10-17 22:24:24 +02001214 sdio_unregister_driver(&if_sdio_driver);
1215
1216 lbs_deb_leave(LBS_DEB_SDIO);
1217}
1218
1219module_init(if_sdio_init_module);
1220module_exit(if_sdio_exit_module);
1221
1222MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
1223MODULE_AUTHOR("Pierre Ossman");
1224MODULE_LICENSE("GPL");