blob: 68cc407054e3f2e4284a22c5be2257c53d6f9122 [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
Dan Williamsac1a4742010-04-15 13:32:58 -0700502 /* On some platforms (like Davinci) the chip needs more time
503 * between helper blocks.
504 */
505 mdelay(2);
506
Pierre Ossman727c26e2007-10-17 22:24:24 +0200507 chunk_size = min(size, (size_t)60);
508
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000509 *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200510 memcpy(chunk_buffer + 4, firmware, chunk_size);
511/*
512 lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
513*/
514 ret = sdio_writesb(card->func, card->ioport,
515 chunk_buffer, 64);
516 if (ret)
517 goto release;
518
519 firmware += chunk_size;
520 size -= chunk_size;
521 }
522
523 /* an empty block marks the end of the transfer */
524 memset(chunk_buffer, 0, 4);
525 ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
526 if (ret)
527 goto release;
528
529 lbs_deb_sdio("waiting for helper to boot...\n");
530
531 /* wait for the helper to boot by looking at the size register */
532 timeout = jiffies + HZ;
533 while (1) {
534 u16 req_size;
535
536 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
537 if (ret)
538 goto release;
539
540 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
541 if (ret)
542 goto release;
543
544 if (req_size != 0)
545 break;
546
547 if (time_after(jiffies, timeout)) {
548 ret = -ETIMEDOUT;
549 goto release;
550 }
551
552 msleep(10);
553 }
554
555 ret = 0;
556
557release:
Pierre Ossman727c26e2007-10-17 22:24:24 +0200558 sdio_release_host(card->func);
559 kfree(chunk_buffer);
560release_fw:
561 release_firmware(fw);
562
563out:
564 if (ret)
565 lbs_pr_err("failed to load helper firmware\n");
566
567 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
568
569 return ret;
570}
571
572static int if_sdio_prog_real(struct if_sdio_card *card)
573{
574 int ret;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200575 const struct firmware *fw;
576 unsigned long timeout;
577 u8 *chunk_buffer;
578 u32 chunk_size;
David Woodhouse6dfff892008-05-23 18:37:51 +0100579 const u8 *firmware;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200580 size_t size, req_size;
581
582 lbs_deb_enter(LBS_DEB_SDIO);
583
584 ret = request_firmware(&fw, card->firmware, &card->func->dev);
585 if (ret) {
586 lbs_pr_err("can't load firmware\n");
587 goto out;
588 }
589
590 chunk_buffer = kzalloc(512, GFP_KERNEL);
591 if (!chunk_buffer) {
592 ret = -ENOMEM;
593 goto release_fw;
594 }
595
596 sdio_claim_host(card->func);
597
598 ret = sdio_set_block_size(card->func, 32);
599 if (ret)
600 goto release;
601
602 firmware = fw->data;
603 size = fw->size;
604
605 while (size) {
Dan Williams96021f02010-04-15 13:27:44 -0700606 ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
607 if (ret)
608 goto release;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200609
610 req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
611 if (ret)
612 goto release;
613
614 req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
615 if (ret)
616 goto release;
617/*
618 lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
619*/
620 if (req_size == 0) {
621 lbs_deb_sdio("firmware helper gave up early\n");
622 ret = -EIO;
623 goto release;
624 }
625
626 if (req_size & 0x01) {
627 lbs_deb_sdio("firmware helper signalled error\n");
628 ret = -EIO;
629 goto release;
630 }
631
632 if (req_size > size)
633 req_size = size;
634
635 while (req_size) {
636 chunk_size = min(req_size, (size_t)512);
637
638 memcpy(chunk_buffer, firmware, chunk_size);
639/*
640 lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
641 chunk_size, (chunk_size + 31) / 32 * 32);
642*/
643 ret = sdio_writesb(card->func, card->ioport,
Ilpo Järvinen23827922008-12-13 21:33:13 +0200644 chunk_buffer, roundup(chunk_size, 32));
Pierre Ossman727c26e2007-10-17 22:24:24 +0200645 if (ret)
646 goto release;
647
648 firmware += chunk_size;
649 size -= chunk_size;
650 req_size -= chunk_size;
651 }
652 }
653
654 ret = 0;
655
656 lbs_deb_sdio("waiting for firmware to boot...\n");
657
658 /* wait for the firmware to boot */
659 timeout = jiffies + HZ;
660 while (1) {
661 u16 scratch;
662
663 scratch = if_sdio_read_scratch(card, &ret);
664 if (ret)
665 goto release;
666
667 if (scratch == IF_SDIO_FIRMWARE_OK)
668 break;
669
670 if (time_after(jiffies, timeout)) {
671 ret = -ETIMEDOUT;
672 goto release;
673 }
674
675 msleep(10);
676 }
677
678 ret = 0;
679
680release:
Pierre Ossman727c26e2007-10-17 22:24:24 +0200681 sdio_release_host(card->func);
682 kfree(chunk_buffer);
683release_fw:
684 release_firmware(fw);
685
686out:
687 if (ret)
688 lbs_pr_err("failed to load firmware\n");
689
690 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
691
692 return ret;
693}
694
695static int if_sdio_prog_firmware(struct if_sdio_card *card)
696{
697 int ret;
698 u16 scratch;
699
700 lbs_deb_enter(LBS_DEB_SDIO);
701
702 sdio_claim_host(card->func);
703 scratch = if_sdio_read_scratch(card, &ret);
704 sdio_release_host(card->func);
705
706 if (ret)
707 goto out;
708
Bing Zhao2c7e5792009-05-21 11:32:34 -0700709 lbs_deb_sdio("firmware status = %#x\n", scratch);
710
Pierre Ossman727c26e2007-10-17 22:24:24 +0200711 if (scratch == IF_SDIO_FIRMWARE_OK) {
712 lbs_deb_sdio("firmware already loaded\n");
713 goto success;
714 }
715
716 ret = if_sdio_prog_helper(card);
717 if (ret)
718 goto out;
719
720 ret = if_sdio_prog_real(card);
721 if (ret)
722 goto out;
723
724success:
Bing Zhaod26285f82009-05-19 19:48:20 -0700725 sdio_claim_host(card->func);
726 sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
727 sdio_release_host(card->func);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200728 ret = 0;
729
730out:
731 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
732
733 return ret;
734}
735
736/*******************************************************************/
737/* Libertas callbacks */
738/*******************************************************************/
739
Holger Schurig69f90322007-11-23 15:43:44 +0100740static int if_sdio_host_to_card(struct lbs_private *priv,
741 u8 type, u8 *buf, u16 nb)
Pierre Ossman727c26e2007-10-17 22:24:24 +0200742{
743 int ret;
744 struct if_sdio_card *card;
745 struct if_sdio_packet *packet, *cur;
746 u16 size;
747 unsigned long flags;
748
749 lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
750
751 card = priv->card;
752
753 if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
754 ret = -EINVAL;
755 goto out;
756 }
757
758 /*
759 * The transfer must be in one transaction or the firmware
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200760 * goes suicidal. There's no way to guarantee that for all
761 * controllers, but we can at least try.
Pierre Ossman727c26e2007-10-17 22:24:24 +0200762 */
Pierre Ossmanad3868b2008-06-28 12:52:45 +0200763 size = sdio_align_size(card->func, nb + 4);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200764
765 packet = kzalloc(sizeof(struct if_sdio_packet) + size,
766 GFP_ATOMIC);
767 if (!packet) {
768 ret = -ENOMEM;
769 goto out;
770 }
771
772 packet->next = NULL;
773 packet->nb = size;
774
775 /*
776 * SDIO specific header.
777 */
778 packet->buffer[0] = (nb + 4) & 0xff;
779 packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
780 packet->buffer[2] = type;
781 packet->buffer[3] = 0;
782
783 memcpy(packet->buffer + 4, buf, nb);
784
785 spin_lock_irqsave(&card->lock, flags);
786
787 if (!card->packets)
788 card->packets = packet;
789 else {
790 cur = card->packets;
791 while (cur->next)
792 cur = cur->next;
793 cur->next = packet;
794 }
795
796 switch (type) {
797 case MVMS_CMD:
798 priv->dnld_sent = DNLD_CMD_SENT;
799 break;
800 case MVMS_DAT:
801 priv->dnld_sent = DNLD_DATA_SENT;
802 break;
803 default:
804 lbs_deb_sdio("unknown packet type %d\n", (int)type);
805 }
806
807 spin_unlock_irqrestore(&card->lock, flags);
808
Dan Williams9b02f412009-02-20 12:27:38 -0500809 queue_work(card->workqueue, &card->packet_worker);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200810
811 ret = 0;
812
813out:
814 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
815
816 return ret;
817}
818
Amitkumar Karwar49125452009-09-30 20:04:38 -0700819static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
820{
821 int ret = -1;
822 struct cmd_header cmd;
823
824 memset(&cmd, 0, sizeof(cmd));
825
826 lbs_deb_sdio("send DEEP_SLEEP command\n");
827 ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
828 lbs_cmd_copyback, (unsigned long) &cmd);
829 if (ret)
830 lbs_pr_err("DEEP_SLEEP cmd failed\n");
831
832 mdelay(200);
833 return ret;
834}
835
836static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
837{
838 struct if_sdio_card *card = priv->card;
839 int ret = -1;
840
841 lbs_deb_enter(LBS_DEB_SDIO);
842 sdio_claim_host(card->func);
843
844 sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
845 if (ret)
846 lbs_pr_err("sdio_writeb failed!\n");
847
848 sdio_release_host(card->func);
849 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
850 return ret;
851}
852
853static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
854{
855 struct if_sdio_card *card = priv->card;
856 int ret = -1;
857
858 lbs_deb_enter(LBS_DEB_SDIO);
859 sdio_claim_host(card->func);
860
861 sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
862 if (ret)
863 lbs_pr_err("sdio_writeb failed!\n");
864
865 sdio_release_host(card->func);
866 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
867 return ret;
868
869}
870
Pierre Ossman727c26e2007-10-17 22:24:24 +0200871/*******************************************************************/
872/* SDIO callbacks */
873/*******************************************************************/
874
875static void if_sdio_interrupt(struct sdio_func *func)
876{
877 int ret;
878 struct if_sdio_card *card;
879 u8 cause;
880
881 lbs_deb_enter(LBS_DEB_SDIO);
882
883 card = sdio_get_drvdata(func);
884
885 cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
886 if (ret)
887 goto out;
888
889 lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
890
891 sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
892 if (ret)
893 goto out;
894
895 /*
896 * Ignore the define name, this really means the card has
897 * successfully received the command.
898 */
Amitkumar Karwar49125452009-09-30 20:04:38 -0700899 card->priv->is_activity_detected = 1;
David Woodhousee775ed72007-12-06 14:36:11 +0000900 if (cause & IF_SDIO_H_INT_DNLD)
901 lbs_host_to_card_done(card->priv);
902
Pierre Ossman727c26e2007-10-17 22:24:24 +0200903
904 if (cause & IF_SDIO_H_INT_UPLD) {
905 ret = if_sdio_card_to_host(card);
906 if (ret)
907 goto out;
908 }
909
910 ret = 0;
911
912out:
913 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
914}
915
916static int if_sdio_probe(struct sdio_func *func,
917 const struct sdio_device_id *id)
918{
919 struct if_sdio_card *card;
Holger Schurig69f90322007-11-23 15:43:44 +0100920 struct lbs_private *priv;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200921 int ret, i;
922 unsigned int model;
923 struct if_sdio_packet *packet;
Daniel Mack8a64c0f2010-04-06 10:52:44 +0200924 struct mmc_host *host = func->card->host;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200925
926 lbs_deb_enter(LBS_DEB_SDIO);
927
928 for (i = 0;i < func->card->num_info;i++) {
929 if (sscanf(func->card->info[i],
930 "802.11 SDIO ID: %x", &model) == 1)
931 break;
932 if (sscanf(func->card->info[i],
933 "ID: %x", &model) == 1)
934 break;
Bing Zhaoe70a5ac2009-05-19 19:48:18 -0700935 if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
936 model = IF_SDIO_MODEL_8385;
937 break;
938 }
Pierre Ossman727c26e2007-10-17 22:24:24 +0200939 }
940
941 if (i == func->card->num_info) {
942 lbs_pr_err("unable to identify card model\n");
943 return -ENODEV;
944 }
945
946 card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
947 if (!card)
948 return -ENOMEM;
949
950 card->func = func;
951 card->model = model;
Bing Zhao2c7e5792009-05-21 11:32:34 -0700952
953 switch (card->model) {
954 case IF_SDIO_MODEL_8385:
955 card->scratch_reg = IF_SDIO_SCRATCH_OLD;
956 break;
957 case IF_SDIO_MODEL_8686:
958 card->scratch_reg = IF_SDIO_SCRATCH;
959 break;
960 case IF_SDIO_MODEL_8688:
961 default: /* for newer chipsets */
962 card->scratch_reg = IF_SDIO_FW_STATUS;
963 break;
964 }
965
Pierre Ossman727c26e2007-10-17 22:24:24 +0200966 spin_lock_init(&card->lock);
Dan Williams9b02f412009-02-20 12:27:38 -0500967 card->workqueue = create_workqueue("libertas_sdio");
Pierre Ossman727c26e2007-10-17 22:24:24 +0200968 INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
969
970 for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
971 if (card->model == if_sdio_models[i].model)
972 break;
973 }
974
975 if (i == ARRAY_SIZE(if_sdio_models)) {
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200976 lbs_pr_err("unknown card model 0x%x\n", card->model);
Pierre Ossman727c26e2007-10-17 22:24:24 +0200977 ret = -ENODEV;
978 goto free;
979 }
980
981 card->helper = if_sdio_models[i].helper;
982 card->firmware = if_sdio_models[i].firmware;
983
Holger Schurig10078322007-11-15 18:05:47 -0500984 if (lbs_helper_name) {
Pierre Ossman727c26e2007-10-17 22:24:24 +0200985 lbs_deb_sdio("overriding helper firmware: %s\n",
Holger Schurig10078322007-11-15 18:05:47 -0500986 lbs_helper_name);
987 card->helper = lbs_helper_name;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200988 }
989
Holger Schurig10078322007-11-15 18:05:47 -0500990 if (lbs_fw_name) {
991 lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
992 card->firmware = lbs_fw_name;
Pierre Ossman727c26e2007-10-17 22:24:24 +0200993 }
994
995 sdio_claim_host(func);
996
997 ret = sdio_enable_func(func);
998 if (ret)
999 goto release;
1000
1001 ret = sdio_claim_irq(func, if_sdio_interrupt);
1002 if (ret)
1003 goto disable;
1004
Daniel Mack8a64c0f2010-04-06 10:52:44 +02001005 /* For 1-bit transfers to the 8686 model, we need to enable the
1006 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
1007 * bit to allow access to non-vendor registers. */
1008 if ((card->model == IF_SDIO_MODEL_8686) &&
1009 (host->caps & MMC_CAP_SDIO_IRQ) &&
1010 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
1011 u8 reg;
1012
1013 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1014 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
1015 if (ret)
1016 goto release_int;
1017
1018 reg |= SDIO_BUS_ECSI;
1019 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
1020 if (ret)
1021 goto release_int;
1022 }
1023
Pierre Ossman727c26e2007-10-17 22:24:24 +02001024 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
1025 if (ret)
1026 goto release_int;
1027
1028 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
1029 if (ret)
1030 goto release_int;
1031
1032 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
1033 if (ret)
1034 goto release_int;
1035
1036 sdio_release_host(func);
1037
1038 sdio_set_drvdata(func, card);
1039
1040 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
1041 "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
1042 func->class, func->vendor, func->device,
1043 model, (unsigned)card->ioport);
1044
1045 ret = if_sdio_prog_firmware(card);
1046 if (ret)
1047 goto reclaim;
1048
Holger Schurig10078322007-11-15 18:05:47 -05001049 priv = lbs_add_card(card, &func->dev);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001050 if (!priv) {
1051 ret = -ENOMEM;
1052 goto reclaim;
1053 }
1054
1055 card->priv = priv;
1056
1057 priv->card = card;
1058 priv->hw_host_to_card = if_sdio_host_to_card;
Amitkumar Karwar49125452009-09-30 20:04:38 -07001059 priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
1060 priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
1061 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001062
David Woodhouseaa21c002007-12-08 20:04:36 +00001063 priv->fw_ready = 1;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001064
Bing Zhaob136a142009-05-19 19:48:19 -07001065 sdio_claim_host(func);
1066
1067 /*
1068 * Get rx_unit if the chip is SD8688 or newer.
1069 * SD8385 & SD8686 do not have rx_unit.
1070 */
1071 if ((card->model != IF_SDIO_MODEL_8385)
1072 && (card->model != IF_SDIO_MODEL_8686))
1073 card->rx_unit = if_sdio_read_rx_unit(card);
1074 else
1075 card->rx_unit = 0;
1076
Pierre Ossman727c26e2007-10-17 22:24:24 +02001077 /*
1078 * Enable interrupts now that everything is set up
1079 */
Pierre Ossman727c26e2007-10-17 22:24:24 +02001080 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
1081 sdio_release_host(func);
1082 if (ret)
1083 goto reclaim;
1084
Bing Zhaod26285f82009-05-19 19:48:20 -07001085 /*
1086 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
1087 */
Bing Zhao6bc61f42009-06-01 18:04:36 -07001088 if (card->model == IF_SDIO_MODEL_8688) {
1089 struct cmd_header cmd;
1090
1091 memset(&cmd, 0, sizeof(cmd));
1092
1093 lbs_deb_sdio("send function INIT command\n");
1094 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1095 lbs_cmd_copyback, (unsigned long) &cmd))
1096 lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
1097 }
Bing Zhaod26285f82009-05-19 19:48:20 -07001098
Holger Schurig10078322007-11-15 18:05:47 -05001099 ret = lbs_start_card(priv);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001100 if (ret)
1101 goto err_activate_card;
1102
1103out:
1104 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1105
1106 return ret;
1107
1108err_activate_card:
Dan Williams9b02f412009-02-20 12:27:38 -05001109 flush_workqueue(card->workqueue);
1110 lbs_remove_card(priv);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001111reclaim:
1112 sdio_claim_host(func);
1113release_int:
1114 sdio_release_irq(func);
1115disable:
1116 sdio_disable_func(func);
1117release:
1118 sdio_release_host(func);
1119free:
Dan Williams9b02f412009-02-20 12:27:38 -05001120 destroy_workqueue(card->workqueue);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001121 while (card->packets) {
1122 packet = card->packets;
1123 card->packets = card->packets->next;
1124 kfree(packet);
1125 }
1126
1127 kfree(card);
1128
1129 goto out;
1130}
1131
1132static void if_sdio_remove(struct sdio_func *func)
1133{
1134 struct if_sdio_card *card;
1135 struct if_sdio_packet *packet;
1136
1137 lbs_deb_enter(LBS_DEB_SDIO);
1138
1139 card = sdio_get_drvdata(func);
1140
Bing Zhao6bc61f42009-06-01 18:04:36 -07001141 if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
1142 /*
1143 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
1144 * multiple functions
1145 */
1146 struct cmd_header cmd;
1147
1148 memset(&cmd, 0, sizeof(cmd));
1149
1150 lbs_deb_sdio("send function SHUTDOWN command\n");
1151 if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
1152 &cmd, sizeof(cmd), lbs_cmd_copyback,
1153 (unsigned long) &cmd))
1154 lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
1155 }
Bing Zhaod26285f82009-05-19 19:48:20 -07001156
Pierre Ossman727c26e2007-10-17 22:24:24 +02001157
1158 lbs_deb_sdio("call remove card\n");
Bing Zhao6bc61f42009-06-01 18:04:36 -07001159 lbs_stop_card(card->priv);
Holger Schurig10078322007-11-15 18:05:47 -05001160 lbs_remove_card(card->priv);
Andrey Yurovsky23b149c2009-06-17 19:15:19 -07001161 card->priv->surpriseremoved = 1;
Pierre Ossman727c26e2007-10-17 22:24:24 +02001162
Dan Williams9b02f412009-02-20 12:27:38 -05001163 flush_workqueue(card->workqueue);
1164 destroy_workqueue(card->workqueue);
Pierre Ossman727c26e2007-10-17 22:24:24 +02001165
1166 sdio_claim_host(func);
1167 sdio_release_irq(func);
1168 sdio_disable_func(func);
1169 sdio_release_host(func);
1170
1171 while (card->packets) {
1172 packet = card->packets;
1173 card->packets = card->packets->next;
1174 kfree(packet);
1175 }
1176
1177 kfree(card);
1178
1179 lbs_deb_leave(LBS_DEB_SDIO);
1180}
1181
1182static struct sdio_driver if_sdio_driver = {
1183 .name = "libertas_sdio",
1184 .id_table = if_sdio_ids,
1185 .probe = if_sdio_probe,
1186 .remove = if_sdio_remove,
1187};
1188
1189/*******************************************************************/
1190/* Module functions */
1191/*******************************************************************/
1192
Andres Salomon4fb910f2007-11-20 17:43:45 -05001193static int __init if_sdio_init_module(void)
Pierre Ossman727c26e2007-10-17 22:24:24 +02001194{
1195 int ret = 0;
1196
1197 lbs_deb_enter(LBS_DEB_SDIO);
1198
1199 printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
1200 printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
1201
1202 ret = sdio_register_driver(&if_sdio_driver);
1203
Bing Zhao6bc61f42009-06-01 18:04:36 -07001204 /* Clear the flag in case user removes the card. */
1205 user_rmmod = 0;
1206
Pierre Ossman727c26e2007-10-17 22:24:24 +02001207 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1208
1209 return ret;
1210}
1211
Andres Salomon4fb910f2007-11-20 17:43:45 -05001212static void __exit if_sdio_exit_module(void)
Pierre Ossman727c26e2007-10-17 22:24:24 +02001213{
1214 lbs_deb_enter(LBS_DEB_SDIO);
1215
Bing Zhao6bc61f42009-06-01 18:04:36 -07001216 /* Set the flag as user is removing this module. */
1217 user_rmmod = 1;
Bing Zhaod26285f82009-05-19 19:48:20 -07001218
Pierre Ossman727c26e2007-10-17 22:24:24 +02001219 sdio_unregister_driver(&if_sdio_driver);
1220
1221 lbs_deb_leave(LBS_DEB_SDIO);
1222}
1223
1224module_init(if_sdio_init_module);
1225module_exit(if_sdio_exit_module);
1226
1227MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
1228MODULE_AUTHOR("Pierre Ossman");
1229MODULE_LICENSE("GPL");