]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/staging/ks7010/ks7010_sdio.c
staging: ks7010: clean up SDIO source comments
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / ks7010 / ks7010_sdio.c
CommitLineData
13a9930d
WS
1/*
2 * Driver for KeyStream, KS7010 based SDIO cards.
3 *
13a9930d
WS
4 * Copyright (C) 2006-2008 KeyStream Corp.
5 * Copyright (C) 2009 Renesas Technology Corp.
c5d9a030 6 * Copyright (C) 2016 Sang Engineering, Wolfram Sang
13a9930d
WS
7 *
8 * This program is free software; you can redistribute it and/or modify
c5d9a030
WS
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13a9930d
WS
11 */
12
1c013a5c 13#include <linux/firmware.h>
13a9930d
WS
14#include <linux/mmc/card.h>
15#include <linux/mmc/sdio_func.h>
1c013a5c 16#include <linux/workqueue.h>
041c4d75 17#include <linux/atomic.h>
13a9930d
WS
18
19#include "ks_wlan.h"
20#include "ks_wlan_ioctl.h"
13a9930d 21#include "ks_hostif.h"
13a9930d
WS
22#include "ks7010_sdio.h"
23
24#define KS7010_FUNC_NUM 1
25#define KS7010_IO_BLOCK_SIZE 512
26#define KS7010_MAX_CLOCK 25000000
27
f9b5bd05 28static const struct sdio_device_id ks7010_sdio_ids[] = {
cdf6ecc5
WS
29 {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010)},
30 {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010)},
13a9930d
WS
31 { /* all zero */ }
32};
f9b5bd05 33MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids);
13a9930d 34
13a9930d 35#define inc_txqhead(priv) \
4fdaa0d7 36 (priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE)
13a9930d 37#define inc_txqtail(priv) \
4fdaa0d7 38 (priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE)
13a9930d 39#define cnt_txqbody(priv) \
4fdaa0d7 40 (((priv->tx_dev.qtail + TX_DEVICE_BUFF_SIZE) - (priv->tx_dev.qhead)) % TX_DEVICE_BUFF_SIZE)
13a9930d
WS
41
42#define inc_rxqhead(priv) \
4fdaa0d7 43 (priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE)
13a9930d 44#define inc_rxqtail(priv) \
4fdaa0d7 45 (priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE)
13a9930d 46#define cnt_rxqbody(priv) \
4fdaa0d7 47 (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE)
13a9930d 48
4c0d46d2
WS
49static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address,
50 unsigned char *buffer, int length)
51{
52 struct ks_sdio_card *card;
1770ae9d 53 int ret;
4c0d46d2 54
18bd6dd1 55 card = priv->ks_sdio_card;
4c0d46d2
WS
56
57 if (length == 1) /* CMD52 */
1770ae9d 58 *buffer = sdio_readb(card->func, address, &ret);
4c0d46d2 59 else /* CMD53 multi-block transfer */
1770ae9d 60 ret = sdio_memcpy_fromio(card->func, buffer, address, length);
4c0d46d2 61
1770ae9d
TH
62 if (ret) {
63 DPRINTK(1, "sdio error=%d size=%d\n", ret, length);
64 return ret;
65 }
4c0d46d2 66
1770ae9d 67 return 0;
4c0d46d2
WS
68}
69
70static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address,
71 unsigned char *buffer, int length)
72{
73 struct ks_sdio_card *card;
1770ae9d 74 int ret;
4c0d46d2 75
18bd6dd1 76 card = priv->ks_sdio_card;
4c0d46d2
WS
77
78 if (length == 1) /* CMD52 */
1770ae9d 79 sdio_writeb(card->func, *buffer, address, &ret);
4c0d46d2 80 else /* CMD53 */
1770ae9d 81 ret = sdio_memcpy_toio(card->func, address, buffer, length);
4c0d46d2 82
1770ae9d
TH
83 if (ret) {
84 DPRINTK(1, "sdio error=%d size=%d\n", ret, length);
85 return ret;
86 }
4c0d46d2 87
1770ae9d 88 return 0;
4c0d46d2
WS
89}
90
4433459a 91static void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv)
13a9930d
WS
92{
93 unsigned char rw_data;
1770ae9d 94 int ret;
13a9930d
WS
95
96 DPRINTK(4, "\n");
97
98 /* clear request */
cdf6ecc5 99 atomic_set(&priv->sleepstatus.doze_request, 0);
13a9930d 100
cdf6ecc5 101 if (atomic_read(&priv->sleepstatus.status) == 0) {
13a9930d 102 rw_data = GCR_B_DOZE;
1770ae9d
TH
103 ret = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data));
104 if (ret) {
13a9930d 105 DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
f283dd69 106 goto set_sleep_mode;
13a9930d
WS
107 }
108 DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data);
cdf6ecc5 109 DPRINTK(3, "sleep_mode=SLP_SLEEP\n");
13a9930d 110 atomic_set(&priv->sleepstatus.status, 1);
cdf6ecc5
WS
111 priv->last_doze = jiffies;
112 } else {
113 DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
13a9930d
WS
114 }
115
f283dd69 116set_sleep_mode:
13a9930d 117 priv->sleep_mode = atomic_read(&priv->sleepstatus.status);
13a9930d
WS
118}
119
4433459a 120static void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv)
13a9930d
WS
121{
122 unsigned char rw_data;
1770ae9d 123 int ret;
13a9930d
WS
124
125 DPRINTK(4, "\n");
126
127 /* clear request */
cdf6ecc5 128 atomic_set(&priv->sleepstatus.wakeup_request, 0);
13a9930d 129
cdf6ecc5 130 if (atomic_read(&priv->sleepstatus.status) == 1) {
13a9930d 131 rw_data = WAKEUP_REQ;
1770ae9d
TH
132 ret = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data));
133 if (ret) {
13a9930d 134 DPRINTK(1, " error : WAKEUP=%02X\n", rw_data);
f283dd69 135 goto set_sleep_mode;
13a9930d
WS
136 }
137 DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data);
138 atomic_set(&priv->sleepstatus.status, 0);
cdf6ecc5 139 priv->last_wakeup = jiffies;
13a9930d 140 ++priv->wakeup_count;
cdf6ecc5
WS
141 } else {
142 DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
13a9930d
WS
143 }
144
f283dd69 145set_sleep_mode:
13a9930d 146 priv->sleep_mode = atomic_read(&priv->sleepstatus.status);
13a9930d
WS
147}
148
feedcf1a 149void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv)
13a9930d
WS
150{
151 unsigned char rw_data;
1770ae9d 152 int ret;
13a9930d
WS
153
154 DPRINTK(4, "\n");
cdf6ecc5 155 if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
13a9930d 156 rw_data = WAKEUP_REQ;
1770ae9d
TH
157 ret = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data));
158 if (ret)
13a9930d 159 DPRINTK(1, " error : WAKEUP=%02X\n", rw_data);
53638cef 160
13a9930d 161 DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data);
cdf6ecc5 162 priv->last_wakeup = jiffies;
13a9930d 163 ++priv->wakeup_count;
cdf6ecc5
WS
164 } else {
165 DPRINTK(1, "psstatus=%d\n",
166 atomic_read(&priv->psstatus.status));
13a9930d
WS
167 }
168}
169
fa740a9e 170static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv)
13a9930d 171{
13a9930d 172 unsigned char rw_data;
f7172487 173 int ret;
13a9930d 174
cdf6ecc5 175 if (priv->reg.powermgt == POWMGT_ACTIVE_MODE)
fa740a9e 176 return;
13a9930d 177
482c03c7
TH
178 if (priv->reg.operation_mode != MODE_INFRASTRUCTURE)
179 return;
180
181 if ((priv->connect_status & CONNECT_STATUS_MASK) != CONNECT_STATUS)
fa740a9e 182 return;
d5f1db31
TH
183
184 if (priv->dev_state != DEVICE_STATE_SLEEP)
fa740a9e 185 return;
d5f1db31 186
3188bc09 187 if (atomic_read(&priv->psstatus.status) == PS_SNOOZE)
fa740a9e 188 return;
3188bc09
TH
189
190 DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n",
191 atomic_read(&priv->psstatus.status),
192 atomic_read(&priv->psstatus.confirm_wait),
193 atomic_read(&priv->psstatus.snooze_guard),
194 cnt_txqbody(priv));
195
fa740a9e
TH
196 if (atomic_read(&priv->psstatus.confirm_wait) ||
197 atomic_read(&priv->psstatus.snooze_guard) ||
198 cnt_txqbody(priv)) {
18bd6dd1 199 queue_delayed_work(priv->wq, &priv->rw_dwork, 0);
fa740a9e
TH
200 return;
201 }
202
203 ret = ks7010_sdio_read(priv, INT_PENDING, &rw_data, sizeof(rw_data));
204 if (ret) {
205 DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data);
f8641485 206 goto queue_delayed_work;
fa740a9e 207 }
f8641485
TH
208 if (rw_data)
209 goto queue_delayed_work;
fa740a9e 210
f8641485
TH
211 rw_data = GCR_B_DOZE;
212 ret = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data));
213 if (ret) {
214 DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
215 goto queue_delayed_work;
13a9930d 216 }
f8641485
TH
217 DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data);
218 atomic_set(&priv->psstatus.status, PS_SNOOZE);
219 DPRINTK(3, "psstatus.status=PS_SNOOZE\n");
13a9930d 220
fa740a9e 221 return;
f8641485
TH
222
223queue_delayed_work:
18bd6dd1 224 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
13a9930d
WS
225}
226
feedcf1a 227int ks_wlan_hw_power_save(struct ks_wlan_private *priv)
13a9930d 228{
18bd6dd1 229 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
13a9930d
WS
230 return 0;
231}
232
cdf6ecc5
WS
233static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p,
234 unsigned long size,
055da4f9
TH
235 void (*complete_handler)(struct ks_wlan_private *priv,
236 struct sk_buff *skb),
237 struct sk_buff *skb)
13a9930d
WS
238{
239 struct tx_device_buffer *sp;
1770ae9d 240 int ret;
13a9930d
WS
241
242 if (priv->dev_state < DEVICE_STATE_BOOT) {
1770ae9d 243 ret = -EPERM;
aa6ca807 244 goto err_complete;
13a9930d
WS
245 }
246
cdf6ecc5 247 if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) {
cdf6ecc5 248 DPRINTK(1, "tx buffer overflow\n");
1770ae9d 249 ret = -EOVERFLOW;
aa6ca807 250 goto err_complete;
13a9930d
WS
251 }
252
253 sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail];
254 sp->sendp = p;
255 sp->size = size;
256 sp->complete_handler = complete_handler;
055da4f9 257 sp->skb = skb;
13a9930d
WS
258 inc_txqtail(priv);
259
260 return 0;
aa6ca807
TH
261
262err_complete:
263 kfree(p);
264 if (complete_handler)
055da4f9 265 (*complete_handler)(priv, skb);
aa6ca807 266
1770ae9d 267 return ret;
13a9930d
WS
268}
269
270/* write data */
cdf6ecc5
WS
271static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer,
272 unsigned long size)
13a9930d 273{
13a9930d
WS
274 unsigned char rw_data;
275 struct hostif_hdr *hdr;
1770ae9d 276 int ret;
697f9f7f 277
13a9930d 278 hdr = (struct hostif_hdr *)buffer;
13a9930d 279
cdf6ecc5
WS
280 DPRINTK(4, "size=%d\n", hdr->size);
281 if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) {
282 DPRINTK(1, "unknown event=%04X\n", hdr->event);
13a9930d
WS
283 return 0;
284 }
285
1770ae9d
TH
286 ret = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size);
287 if (ret) {
288 DPRINTK(1, " write error : retval=%d\n", ret);
289 return ret;
13a9930d
WS
290 }
291
bfee6a23 292 rw_data = REG_STATUS_BUSY;
1770ae9d
TH
293 ret = ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data));
294 if (ret) {
13a9930d 295 DPRINTK(1, " error : WRITE_STATUS=%02X\n", rw_data);
1770ae9d 296 return ret;
13a9930d
WS
297 }
298
299 return 0;
300}
301
5141e9c6 302static void tx_device_task(struct ks_wlan_private *priv)
13a9930d 303{
cdf6ecc5 304 struct tx_device_buffer *sp;
03b02449 305 int ret;
13a9930d
WS
306
307 DPRINTK(4, "\n");
638a75b6
TH
308 if (cnt_txqbody(priv) <= 0 ||
309 atomic_read(&priv->psstatus.status) == PS_SNOOZE)
310 return;
13a9930d 311
638a75b6
TH
312 sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead];
313 if (priv->dev_state >= DEVICE_STATE_BOOT) {
314 ret = write_to_device(priv, sp->sendp, sp->size);
315 if (ret) {
316 DPRINTK(1, "write_to_device error !!(%d)\n", ret);
18bd6dd1 317 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
638a75b6 318 return;
13a9930d
WS
319 }
320 }
638a75b6
TH
321 kfree(sp->sendp);
322 if (sp->complete_handler) /* TX Complete */
055da4f9 323 (*sp->complete_handler)(priv, sp->skb);
638a75b6
TH
324 inc_txqhead(priv);
325
18bd6dd1
TH
326 if (cnt_txqbody(priv) > 0)
327 queue_delayed_work(priv->wq, &priv->rw_dwork, 0);
13a9930d
WS
328}
329
cdf6ecc5 330int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
055da4f9
TH
331 void (*complete_handler)(struct ks_wlan_private *priv,
332 struct sk_buff *skb),
333 struct sk_buff *skb)
13a9930d 334{
cdf6ecc5 335 int result = 0;
13a9930d 336 struct hostif_hdr *hdr;
697f9f7f 337
13a9930d
WS
338 hdr = (struct hostif_hdr *)p;
339
cdf6ecc5
WS
340 if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) {
341 DPRINTK(1, "unknown event=%04X\n", hdr->event);
13a9930d
WS
342 return 0;
343 }
344
345 /* add event to hostt buffer */
346 priv->hostt.buff[priv->hostt.qtail] = hdr->event;
cdf6ecc5 347 priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE;
13a9930d 348
cdf6ecc5 349 DPRINTK(4, "event=%04X\n", hdr->event);
13a9930d 350 spin_lock(&priv->tx_dev.tx_dev_lock);
055da4f9 351 result = enqueue_txdev(priv, p, size, complete_handler, skb);
13a9930d
WS
352 spin_unlock(&priv->tx_dev.tx_dev_lock);
353
18bd6dd1
TH
354 if (cnt_txqbody(priv) > 0)
355 queue_delayed_work(priv->wq, &priv->rw_dwork, 0);
356
13a9930d
WS
357 return result;
358}
359
360static void rx_event_task(unsigned long dev)
361{
cdf6ecc5
WS
362 struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
363 struct rx_device_buffer *rp;
13a9930d 364
cdf6ecc5 365 DPRINTK(4, "\n");
13a9930d 366
cdf6ecc5 367 if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) {
13a9930d
WS
368 rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead];
369 hostif_receive(priv, rp->data, rp->size);
370 inc_rxqhead(priv);
371
53638cef 372 if (cnt_rxqbody(priv) > 0)
321dabdc 373 tasklet_schedule(&priv->rx_bh_task);
13a9930d 374 }
13a9930d
WS
375}
376
5141e9c6 377static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size)
13a9930d 378{
f7172487 379 int ret;
13a9930d
WS
380 struct rx_device_buffer *rx_buffer;
381 struct hostif_hdr *hdr;
cdf6ecc5
WS
382 unsigned char read_status;
383 unsigned short event = 0;
13a9930d 384
cdf6ecc5 385 DPRINTK(4, "\n");
13a9930d
WS
386
387 /* receive data */
cdf6ecc5 388 if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) {
71a476e4 389 DPRINTK(1, "rx buffer overflow\n");
13b05e46 390 return;
13a9930d
WS
391 }
392 rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail];
393
f7172487
TH
394 ret = ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0],
395 hif_align_size(size));
396 if (ret)
13b05e46 397 return;
13a9930d
WS
398
399 /* length check */
cdf6ecc5 400 if (size > 2046 || size == 0) {
3215bb1a
WS
401#ifdef KS_WLAN_DEBUG
402 if (KS_WLAN_DEBUG > 5)
cdf6ecc5
WS
403 print_hex_dump_bytes("INVALID DATA dump: ",
404 DUMP_PREFIX_OFFSET,
3215bb1a
WS
405 rx_buffer->data, 32);
406#endif
13a9930d 407 /* rx_status update */
bfee6a23 408 read_status = REG_STATUS_IDLE;
f7172487
TH
409 ret = ks7010_sdio_write(priv, READ_STATUS, &read_status,
410 sizeof(read_status));
411 if (ret)
13a9930d 412 DPRINTK(1, " error : READ_STATUS=%02X\n", read_status);
53638cef 413
13b05e46
TH
414 /* length check fail */
415 return;
13a9930d
WS
416 }
417
418 hdr = (struct hostif_hdr *)&rx_buffer->data[0];
419 rx_buffer->size = le16_to_cpu(hdr->size) + sizeof(hdr->size);
420 event = hdr->event;
421 inc_rxqtail(priv);
422
423 /* read status update */
bfee6a23 424 read_status = REG_STATUS_IDLE;
f7172487
TH
425 ret = ks7010_sdio_write(priv, READ_STATUS, &read_status,
426 sizeof(read_status));
427 if (ret)
13a9930d 428 DPRINTK(1, " error : READ_STATUS=%02X\n", read_status);
53638cef 429
13a9930d
WS
430 DPRINTK(4, "READ_STATUS=%02X\n", read_status);
431
cdf6ecc5
WS
432 if (atomic_read(&priv->psstatus.confirm_wait)) {
433 if (IS_HIF_CONF(event)) {
13a9930d
WS
434 DPRINTK(4, "IS_HIF_CONF true !!\n");
435 atomic_dec(&priv->psstatus.confirm_wait);
436 }
437 }
438
321dabdc 439 tasklet_schedule(&priv->rx_bh_task);
13a9930d
WS
440}
441
442static void ks7010_rw_function(struct work_struct *work)
443{
13a9930d
WS
444 struct ks_wlan_private *priv;
445 unsigned char rw_data;
1770ae9d 446 int ret;
13a9930d 447
18bd6dd1 448 priv = container_of(work, struct ks_wlan_private, rw_dwork.work);
13a9930d 449
cdf6ecc5 450 DPRINTK(4, "\n");
13a9930d 451
e61e73d7 452 /* wait after DOZE */
cdf6ecc5 453 if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) {
c8abeaf8 454 DPRINTK(4, "wait after DOZE\n");
18bd6dd1 455 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
13a9930d
WS
456 return;
457 }
458
e61e73d7 459 /* wait after WAKEUP */
cdf6ecc5 460 while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) {
c8abeaf8 461 DPRINTK(4, "wait after WAKEUP\n");
18bd6dd1 462 dev_info(&priv->ks_sdio_card->func->dev,
9887b5e5
SG
463 "wake: %lu %lu\n",
464 priv->last_wakeup + (30 * HZ) / 1000,
465 jiffies);
13a9930d
WS
466 msleep(30);
467 }
468
18bd6dd1 469 sdio_claim_host(priv->ks_sdio_card->func);
13a9930d
WS
470
471 /* power save wakeup */
cdf6ecc5
WS
472 if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
473 if (cnt_txqbody(priv) > 0) {
13a9930d 474 ks_wlan_hw_wakeup_request(priv);
18bd6dd1 475 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
13a9930d 476 }
f283dd69 477 goto err_release_host;
13a9930d
WS
478 }
479
480 /* sleep mode doze */
cdf6ecc5 481 if (atomic_read(&priv->sleepstatus.doze_request) == 1) {
13a9930d 482 ks_wlan_hw_sleep_doze_request(priv);
f283dd69 483 goto err_release_host;
13a9930d
WS
484 }
485 /* sleep mode wakeup */
cdf6ecc5 486 if (atomic_read(&priv->sleepstatus.wakeup_request) == 1) {
13a9930d 487 ks_wlan_hw_sleep_wakeup_request(priv);
f283dd69 488 goto err_release_host;
13a9930d
WS
489 }
490
491 /* read (WriteStatus/ReadDataSize FN1:00_0014) */
1770ae9d
TH
492 ret = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data));
493 if (ret) {
cdf6ecc5
WS
494 DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data,
495 atomic_read(&priv->psstatus.status));
f283dd69 496 goto err_release_host;
13a9930d
WS
497 }
498 DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data);
499
cdf6ecc5 500 if (rw_data & RSIZE_MASK) { /* Read schedule */
5141e9c6 501 ks_wlan_hw_rx(priv, (uint16_t)((rw_data & RSIZE_MASK) << 4));
13a9930d 502 }
53638cef 503 if ((rw_data & WSTATUS_MASK))
5141e9c6 504 tx_device_task(priv);
53638cef 505
13a9930d
WS
506 _ks_wlan_hw_power_save(priv);
507
f283dd69 508err_release_host:
18bd6dd1 509 sdio_release_host(priv->ks_sdio_card->func);
13a9930d
WS
510}
511
13a9930d
WS
512static void ks_sdio_interrupt(struct sdio_func *func)
513{
f7172487 514 int ret;
13a9930d 515 struct ks_sdio_card *card;
feedcf1a 516 struct ks_wlan_private *priv;
13a9930d
WS
517 unsigned char status, rsize, rw_data;
518
519 card = sdio_get_drvdata(func);
520 priv = card->priv;
521 DPRINTK(4, "\n");
522
638a75b6
TH
523 if (priv->dev_state < DEVICE_STATE_BOOT)
524 goto queue_delayed_work;
525
526 ret = ks7010_sdio_read(priv, INT_PENDING, &status, sizeof(status));
527 if (ret) {
528 DPRINTK(1, "read INT_PENDING Failed!!(%d)\n", ret);
529 goto queue_delayed_work;
530 }
531 DPRINTK(4, "INT_PENDING=%02X\n", rw_data);
532
533 /* schedule task for interrupt status */
534 /* bit7 -> Write General Communication B register */
535 /* read (General Communication B register) */
536 /* bit5 -> Write Status Idle */
537 /* bit2 -> Read Status Busy */
538 if (status & INT_GCR_B ||
539 atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
540 ret = ks7010_sdio_read(priv, GCR_B, &rw_data,
541 sizeof(rw_data));
f7172487 542 if (ret) {
638a75b6 543 DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
f283dd69 544 goto queue_delayed_work;
13a9930d 545 }
638a75b6
TH
546 if (rw_data == GCR_B_ACTIVE) {
547 if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
548 atomic_set(&priv->psstatus.status, PS_WAKEUP);
549 priv->wakeup_count = 0;
13a9930d 550 }
638a75b6 551 complete(&priv->psstatus.wakeup_wait);
13a9930d 552 }
638a75b6 553 }
13a9930d 554
638a75b6
TH
555 do {
556 /* read (WriteStatus/ReadDataSize FN1:00_0014) */
557 ret = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data,
558 sizeof(rw_data));
559 if (ret) {
560 DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n", rw_data);
561 goto queue_delayed_work;
562 }
563 DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data);
564 rsize = rw_data & RSIZE_MASK;
565 if (rsize != 0) /* Read schedule */
566 ks_wlan_hw_rx(priv, (uint16_t)(rsize << 4));
567
568 if (rw_data & WSTATUS_MASK) {
569 if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
570 if (cnt_txqbody(priv)) {
571 ks_wlan_hw_wakeup_request(priv);
18bd6dd1 572 queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
638a75b6 573 return;
cdf6ecc5 574 }
638a75b6
TH
575 } else {
576 tx_device_task(priv);
13a9930d 577 }
638a75b6
TH
578 }
579 } while (rsize);
13a9930d 580
f283dd69 581queue_delayed_work:
18bd6dd1 582 queue_delayed_work(priv->wq, &priv->rw_dwork, 0);
13a9930d
WS
583}
584
cdf6ecc5 585static int trx_device_init(struct ks_wlan_private *priv)
13a9930d 586{
20358d13
NR
587 priv->tx_dev.qhead = 0;
588 priv->tx_dev.qtail = 0;
13a9930d 589
20358d13
NR
590 priv->rx_dev.qhead = 0;
591 priv->rx_dev.qtail = 0;
13a9930d 592
13a9930d
WS
593 spin_lock_init(&priv->tx_dev.tx_dev_lock);
594 spin_lock_init(&priv->rx_dev.rx_dev_lock);
595
321dabdc 596 tasklet_init(&priv->rx_bh_task, rx_event_task, (unsigned long)priv);
13a9930d
WS
597
598 return 0;
599}
600
cdf6ecc5 601static void trx_device_exit(struct ks_wlan_private *priv)
13a9930d 602{
cdf6ecc5 603 struct tx_device_buffer *sp;
13a9930d
WS
604
605 /* tx buffer clear */
cdf6ecc5 606 while (cnt_txqbody(priv) > 0) {
13a9930d 607 sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead];
e61e73d7 608 kfree(sp->sendp);
c7e65f4d 609 if (sp->complete_handler) /* TX Complete */
055da4f9 610 (*sp->complete_handler)(priv, sp->skb);
13a9930d
WS
611 inc_txqhead(priv);
612 }
613
321dabdc 614 tasklet_kill(&priv->rx_bh_task);
13a9930d 615}
cdf6ecc5 616
feedcf1a 617static int ks7010_sdio_update_index(struct ks_wlan_private *priv, u32 index)
13a9930d 618{
1770ae9d 619 int ret;
13a9930d 620 unsigned char *data_buf;
13a9930d
WS
621
622 data_buf = kmalloc(sizeof(u32), GFP_KERNEL);
aa6ca807
TH
623 if (!data_buf)
624 return -ENOMEM;
13a9930d
WS
625
626 memcpy(data_buf, &index, sizeof(index));
1770ae9d
TH
627 ret = ks7010_sdio_write(priv, WRITE_INDEX, data_buf, sizeof(index));
628 if (ret)
f283dd69 629 goto err_free_data_buf;
13a9930d 630
1770ae9d
TH
631 ret = ks7010_sdio_write(priv, READ_INDEX, data_buf, sizeof(index));
632 if (ret)
f283dd69 633 goto err_free_data_buf;
aa6ca807
TH
634
635 return 0;
636
f283dd69 637err_free_data_buf:
58043f25 638 kfree(data_buf);
aa6ca807 639
1770ae9d 640 return ret;
13a9930d
WS
641}
642
0966c755 643#define ROM_BUFF_SIZE (64 * 1024)
feedcf1a 644static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address,
13a9930d
WS
645 unsigned char *data, unsigned int size)
646{
1770ae9d 647 int ret;
13a9930d 648 unsigned char *read_buf;
eeed92c0 649
13a9930d 650 read_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL);
aa6ca807
TH
651 if (!read_buf)
652 return -ENOMEM;
653
1770ae9d
TH
654 ret = ks7010_sdio_read(priv, address, read_buf, size);
655 if (ret)
f283dd69 656 goto err_free_read_buf;
13a9930d 657
58af272b
TH
658 if (memcmp(data, read_buf, size) != 0) {
659 ret = -EIO;
1770ae9d 660 DPRINTK(0, "data compare error (%d)\n", ret);
f283dd69 661 goto err_free_read_buf;
13a9930d 662 }
aa6ca807
TH
663
664 return 0;
665
f283dd69 666err_free_read_buf:
58043f25 667 kfree(read_buf);
aa6ca807 668
1770ae9d 669 return ret;
13a9930d 670}
cdf6ecc5 671
ed246b9e 672static int ks7010_upload_firmware(struct ks_sdio_card *card)
13a9930d 673{
ed246b9e 674 struct ks_wlan_private *priv = card->priv;
cdf6ecc5
WS
675 unsigned int size, offset, n = 0;
676 unsigned char *rom_buf;
677 unsigned char rw_data = 0;
1770ae9d 678 int ret;
881f76b9 679 unsigned int length;
13a9930d 680 const struct firmware *fw_entry = NULL;
13a9930d 681
13a9930d 682 rom_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL);
369e1b69 683 if (!rom_buf)
aa6ca807 684 return -ENOMEM;
13a9930d
WS
685
686 sdio_claim_host(card->func);
687
688 /* Firmware running ? */
1770ae9d 689 ret = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data));
cdf6ecc5
WS
690 if (rw_data == GCR_A_RUN) {
691 DPRINTK(0, "MAC firmware running ...\n");
aa6ca807 692 goto release_host_and_free;
13a9930d
WS
693 }
694
1770ae9d 695 ret = request_firmware(&fw_entry, ROM_FILE,
18bd6dd1 696 &priv->ks_sdio_card->func->dev);
1770ae9d 697 if (ret)
aa6ca807 698 goto release_host_and_free;
6ee9169b 699
13a9930d 700 length = fw_entry->size;
13a9930d 701
13a9930d 702 n = 0;
cdf6ecc5
WS
703 do {
704 if (length >= ROM_BUFF_SIZE) {
13a9930d
WS
705 size = ROM_BUFF_SIZE;
706 length = length - ROM_BUFF_SIZE;
cdf6ecc5
WS
707 } else {
708 size = length;
709 length = 0;
13a9930d 710 }
cdf6ecc5
WS
711 DPRINTK(4, "size = %d\n", size);
712 if (size == 0)
713 break;
714 memcpy(rom_buf, fw_entry->data + n, size);
e61e73d7 715
13a9930d 716 offset = n;
1770ae9d
TH
717 ret = ks7010_sdio_update_index(priv, KS7010_IRAM_ADDRESS + offset);
718 if (ret)
aa6ca807 719 goto release_firmware;
13a9930d 720
1770ae9d
TH
721 ret = ks7010_sdio_write(priv, DATA_WINDOW, rom_buf, size);
722 if (ret)
aa6ca807 723 goto release_firmware;
13a9930d 724
1770ae9d
TH
725 ret = ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size);
726 if (ret)
aa6ca807
TH
727 goto release_firmware;
728
13a9930d
WS
729 n += size;
730
cdf6ecc5 731 } while (size);
13a9930d 732
13a9930d 733 rw_data = GCR_A_REMAP;
1770ae9d
TH
734 ret = ks7010_sdio_write(priv, GCR_A, &rw_data, sizeof(rw_data));
735 if (ret)
aa6ca807
TH
736 goto release_firmware;
737
cdf6ecc5 738 DPRINTK(4, " REMAP Request : GCR_A=%02X\n", rw_data);
13a9930d
WS
739
740 /* Firmware running check */
741 for (n = 0; n < 50; ++n) {
cdf6ecc5 742 mdelay(10); /* wait_ms(10); */
1770ae9d
TH
743 ret = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data));
744 if (ret)
aa6ca807
TH
745 goto release_firmware;
746
cdf6ecc5
WS
747 if (rw_data == GCR_A_RUN)
748 break;
13a9930d 749 }
cdf6ecc5 750 DPRINTK(4, "firmware wakeup (%d)!!!!\n", n);
13a9930d
WS
751 if ((50) <= n) {
752 DPRINTK(1, "firmware can't start\n");
1770ae9d 753 ret = -EIO;
aa6ca807 754 goto release_firmware;
13a9930d
WS
755 }
756
1770ae9d 757 ret = 0;
13a9930d 758
aa6ca807 759 release_firmware:
13a9930d 760 release_firmware(fw_entry);
aa6ca807 761 release_host_and_free:
13a9930d 762 sdio_release_host(card->func);
58043f25 763 kfree(rom_buf);
aa6ca807 764
1770ae9d 765 return ret;
13a9930d
WS
766}
767
e8593a8a 768static void ks7010_card_init(struct ks_wlan_private *priv)
13a9930d 769{
cdf6ecc5 770 DPRINTK(5, "\ncard_init_task()\n");
13a9930d 771
13a9930d
WS
772 init_completion(&priv->confirm_wait);
773
cdf6ecc5 774 DPRINTK(5, "init_completion()\n");
13a9930d
WS
775
776 /* get mac address & firmware version */
777 hostif_sme_enqueue(priv, SME_START);
778
cdf6ecc5 779 DPRINTK(5, "hostif_sme_enqueu()\n");
13a9930d 780
cdf6ecc5
WS
781 if (!wait_for_completion_interruptible_timeout
782 (&priv->confirm_wait, 5 * HZ)) {
783 DPRINTK(1, "wait time out!! SME_START\n");
13a9930d
WS
784 }
785
310e916f 786 if (priv->mac_address_valid && priv->version_size != 0)
13a9930d 787 priv->dev_state = DEVICE_STATE_PREINIT;
53638cef 788
13a9930d
WS
789 hostif_sme_enqueue(priv, SME_GET_EEPROM_CKSUM);
790
791 /* load initial wireless parameter */
792 hostif_sme_enqueue(priv, SME_STOP_REQUEST);
793
794 hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST);
795 hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST);
796
797 hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST);
798 hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST);
799 hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST);
800 hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST);
801 hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST);
802
803 hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST);
804 hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST);
805 hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST);
806 hostif_sme_enqueue(priv, SME_START_REQUEST);
807
cdf6ecc5
WS
808 if (!wait_for_completion_interruptible_timeout
809 (&priv->confirm_wait, 5 * HZ)) {
810 DPRINTK(1, "wait time out!! wireless parameter set\n");
13a9930d
WS
811 }
812
cdf6ecc5 813 if (priv->dev_state >= DEVICE_STATE_PREINIT) {
13a9930d
WS
814 DPRINTK(1, "DEVICE READY!!\n");
815 priv->dev_state = DEVICE_STATE_READY;
cdf6ecc5
WS
816 } else {
817 DPRINTK(1, "dev_state=%d\n", priv->dev_state);
13a9930d
WS
818 }
819}
820
6ee9169b
WS
821static void ks7010_init_defaults(struct ks_wlan_private *priv)
822{
823 priv->reg.tx_rate = TX_RATE_AUTO;
824 priv->reg.preamble = LONG_PREAMBLE;
825 priv->reg.powermgt = POWMGT_ACTIVE_MODE;
826 priv->reg.scan_type = ACTIVE_SCAN;
827 priv->reg.beacon_lost_count = 20;
828 priv->reg.rts = 2347UL;
829 priv->reg.fragment = 2346UL;
830 priv->reg.phy_type = D_11BG_COMPATIBLE_MODE;
831 priv->reg.cts_mode = CTS_MODE_FALSE;
832 priv->reg.rate_set.body[11] = TX_RATE_54M;
833 priv->reg.rate_set.body[10] = TX_RATE_48M;
834 priv->reg.rate_set.body[9] = TX_RATE_36M;
835 priv->reg.rate_set.body[8] = TX_RATE_18M;
836 priv->reg.rate_set.body[7] = TX_RATE_9M;
837 priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE;
838 priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE;
839 priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE;
840 priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE;
841 priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE;
842 priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE;
843 priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE;
844 priv->reg.tx_rate = TX_RATE_FULL_AUTO;
845 priv->reg.rate_set.size = 12;
846}
847
c4730a92 848static int ks7010_sdio_probe(struct sdio_func *func,
cdf6ecc5 849 const struct sdio_device_id *device)
13a9930d 850{
feedcf1a 851 struct ks_wlan_private *priv;
13a9930d
WS
852 struct ks_sdio_card *card;
853 struct net_device *netdev;
854 unsigned char rw_data;
2801d7a2 855 int ret;
13a9930d 856
c4730a92 857 DPRINTK(5, "ks7010_sdio_probe()\n");
13a9930d
WS
858
859 priv = NULL;
cdf6ecc5 860 netdev = NULL;
13a9930d 861
2d738bd2 862 card = kzalloc(sizeof(*card), GFP_KERNEL);
13a9930d
WS
863 if (!card)
864 return -ENOMEM;
865
cdf6ecc5 866 card->func = func;
13a9930d 867
13a9930d
WS
868 sdio_claim_host(func);
869
13a9930d 870 ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE);
cdf6ecc5
WS
871 DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n",
872 func->card->cccr.multi_block, func->cur_blksize, ret);
13a9930d 873
13a9930d
WS
874 ret = sdio_enable_func(func);
875 DPRINTK(5, "sdio_enable_func() %d\n", ret);
876 if (ret)
f283dd69 877 goto err_free_card;
13a9930d
WS
878
879 /* interrupt disable */
cdf6ecc5 880 sdio_writeb(func, 0, INT_ENABLE, &ret);
13a9930d 881 if (ret)
f283dd69 882 goto err_free_card;
cdf6ecc5 883 sdio_writeb(func, 0xff, INT_PENDING, &ret);
13a9930d 884 if (ret)
f283dd69 885 goto err_disable_func;
13a9930d
WS
886
887 /* setup interrupt handler */
888 ret = sdio_claim_irq(func, ks_sdio_interrupt);
889 if (ret)
f283dd69 890 goto err_disable_func;
13a9930d
WS
891
892 sdio_release_host(func);
893
894 sdio_set_drvdata(func, card);
895
896 DPRINTK(5, "class = 0x%X, vendor = 0x%X, "
cdf6ecc5 897 "device = 0x%X\n", func->class, func->vendor, func->device);
13a9930d
WS
898
899 /* private memory allocate */
900 netdev = alloc_etherdev(sizeof(*priv));
c7e65f4d 901 if (!netdev) {
9887b5e5 902 dev_err(&card->func->dev, "ks7010 : Unable to alloc new net device\n");
f283dd69 903 goto err_release_irq;
13a9930d 904 }
6634cff1 905 if (dev_alloc_name(netdev, "wlan%d") < 0) {
9887b5e5
SG
906 dev_err(&card->func->dev,
907 "ks7010 : Couldn't get name!\n");
f283dd69 908 goto err_free_netdev;
13a9930d
WS
909 }
910
911 priv = netdev_priv(netdev);
912
913 card->priv = priv;
914 SET_NETDEV_DEV(netdev, &card->func->dev); /* for create sysfs symlinks */
915
916 /* private memory initialize */
18bd6dd1 917 priv->ks_sdio_card = card;
53638cef 918
13a9930d
WS
919 priv->dev_state = DEVICE_STATE_PREBOOT;
920 priv->net_dev = netdev;
921 priv->firmware_version[0] = '\0';
922 priv->version_size = 0;
e61e73d7 923 priv->last_doze = jiffies;
13a9930d
WS
924 priv->last_wakeup = jiffies;
925 memset(&priv->nstats, 0, sizeof(priv->nstats));
926 memset(&priv->wstats, 0, sizeof(priv->wstats));
927
928 /* sleep mode */
cdf6ecc5
WS
929 atomic_set(&priv->sleepstatus.doze_request, 0);
930 atomic_set(&priv->sleepstatus.wakeup_request, 0);
931 atomic_set(&priv->sleepstatus.wakeup_request, 0);
13a9930d
WS
932
933 trx_device_init(priv);
934 hostif_init(priv);
cdf6ecc5 935 ks_wlan_net_start(netdev);
13a9930d 936
6ee9169b 937 ks7010_init_defaults(priv);
13a9930d 938
ed246b9e 939 ret = ks7010_upload_firmware(card);
cdf6ecc5 940 if (ret) {
9887b5e5
SG
941 dev_err(&card->func->dev,
942 "ks7010: firmware load failed !! return code = %d\n",
943 ret);
cf10e78e 944 goto err_free_netdev;
13a9930d
WS
945 }
946
947 /* interrupt setting */
948 /* clear Interrupt status write (ARMtoSD_InterruptPending FN1:00_0024) */
949 rw_data = 0xff;
950 sdio_claim_host(func);
951 ret = ks7010_sdio_write(priv, INT_PENDING, &rw_data, sizeof(rw_data));
952 sdio_release_host(func);
53638cef 953 if (ret)
13a9930d 954 DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data);
53638cef 955
13a9930d
WS
956 DPRINTK(4, " clear Interrupt : INT_PENDING=%02X\n", rw_data);
957
13a9930d 958 /* enable ks7010sdio interrupt (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS) */
cdf6ecc5 959 rw_data = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS);
13a9930d
WS
960 sdio_claim_host(func);
961 ret = ks7010_sdio_write(priv, INT_ENABLE, &rw_data, sizeof(rw_data));
962 sdio_release_host(func);
53638cef 963 if (ret)
f283dd69 964 DPRINTK(1, " err : INT_ENABLE=%02X\n", rw_data);
53638cef 965
13a9930d
WS
966 DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", rw_data);
967 priv->dev_state = DEVICE_STATE_BOOT;
968
18bd6dd1
TH
969 priv->wq = create_workqueue("wq");
970 if (!priv->wq) {
13a9930d 971 DPRINTK(1, "create_workqueue failed !!\n");
cf10e78e 972 goto err_free_netdev;
13a9930d
WS
973 }
974
18bd6dd1 975 INIT_DELAYED_WORK(&priv->rw_dwork, ks7010_rw_function);
e8593a8a 976 ks7010_card_init(priv);
13a9930d 977
3fb54d75
WS
978 ret = register_netdev(priv->net_dev);
979 if (ret)
cf10e78e 980 goto err_free_netdev;
3fb54d75 981
13a9930d
WS
982 return 0;
983
f283dd69 984 err_free_netdev:
13a9930d
WS
985 free_netdev(priv->net_dev);
986 card->priv = NULL;
f283dd69 987 err_release_irq:
13a9930d
WS
988 sdio_claim_host(func);
989 sdio_release_irq(func);
f283dd69 990 err_disable_func:
13a9930d 991 sdio_disable_func(func);
f283dd69 992 err_free_card:
13a9930d
WS
993 sdio_release_host(func);
994 sdio_set_drvdata(func, NULL);
995 kfree(card);
2801d7a2 996
13a9930d
WS
997 return -ENODEV;
998}
999
2ab6fd59
TH
1000/* send stop request to MAC */
1001static int send_stop_request(struct sdio_func *func)
1002{
1003 struct hostif_stop_request_t *pp;
1004 struct ks_sdio_card *card;
1005 size_t size;
1006
1007 card = sdio_get_drvdata(func);
1008
1009 pp = kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL);
1010 if (!pp) {
1011 DPRINTK(3, "allocate memory failed..\n");
1012 return -ENOMEM;
1013 }
1014
1015 size = sizeof(*pp) - sizeof(pp->header.size);
1016 pp->header.size = cpu_to_le16((uint16_t)size);
1017 pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ);
1018
1019 sdio_claim_host(func);
1020 write_to_device(card->priv, (unsigned char *)pp,
1021 hif_align_size(sizeof(*pp)));
1022 sdio_release_host(func);
1023
1024 kfree(pp);
1025 return 0;
1026}
1027
1028
c4730a92 1029static void ks7010_sdio_remove(struct sdio_func *func)
13a9930d
WS
1030{
1031 int ret;
1032 struct ks_sdio_card *card;
1033 struct ks_wlan_private *priv;
697f9f7f 1034
c4730a92 1035 DPRINTK(1, "ks7010_sdio_remove()\n");
13a9930d
WS
1036
1037 card = sdio_get_drvdata(func);
1038
c7e65f4d 1039 if (!card)
13a9930d
WS
1040 return;
1041
1042 DPRINTK(1, "priv = card->priv\n");
1043 priv = card->priv;
cdf6ecc5 1044 if (priv) {
803394d0
CIK
1045 struct net_device *netdev = priv->net_dev;
1046
13a9930d
WS
1047 ks_wlan_net_stop(netdev);
1048 DPRINTK(1, "ks_wlan_net_stop\n");
1049
1050 /* interrupt disable */
1051 sdio_claim_host(func);
cdf6ecc5
WS
1052 sdio_writeb(func, 0, INT_ENABLE, &ret);
1053 sdio_writeb(func, 0xff, INT_PENDING, &ret);
13a9930d
WS
1054 sdio_release_host(func);
1055 DPRINTK(1, "interrupt disable\n");
1056
2ab6fd59
TH
1057 ret = send_stop_request(func);
1058 if (ret) /* memory allocation failure */
1059 return;
697f9f7f 1060
13a9930d
WS
1061 DPRINTK(1, "STOP Req\n");
1062
18bd6dd1
TH
1063 if (priv->wq) {
1064 flush_workqueue(priv->wq);
1065 destroy_workqueue(priv->wq);
13a9930d 1066 }
18bd6dd1 1067 DPRINTK(1, "destroy_workqueue(priv->wq);\n");
13a9930d 1068
13a9930d
WS
1069 hostif_exit(priv);
1070 DPRINTK(1, "hostif_exit\n");
1071
3fb54d75 1072 unregister_netdev(netdev);
13a9930d
WS
1073
1074 trx_device_exit(priv);
13a9930d
WS
1075 free_netdev(priv->net_dev);
1076 card->priv = NULL;
1077 }
1078
1079 sdio_claim_host(func);
1080 sdio_release_irq(func);
1081 DPRINTK(1, "sdio_release_irq()\n");
1082 sdio_disable_func(func);
1083 DPRINTK(1, "sdio_disable_func()\n");
1084 sdio_release_host(func);
1085
1086 sdio_set_drvdata(func, NULL);
1087
1088 kfree(card);
1089 DPRINTK(1, "kfree()\n");
1090
cdf6ecc5 1091 DPRINTK(5, " Bye !!\n");
13a9930d
WS
1092}
1093
4c0d46d2
WS
1094static struct sdio_driver ks7010_sdio_driver = {
1095 .name = "ks7010_sdio",
1096 .id_table = ks7010_sdio_ids,
1097 .probe = ks7010_sdio_probe,
1098 .remove = ks7010_sdio_remove,
1099};
1100
6b0cb0b0 1101module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver);
e1240140
WS
1102MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream");
1103MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards");
1104MODULE_LICENSE("GPL v2");
1105MODULE_FIRMWARE(ROM_FILE);