113a9930dSWolfram Sang /*
213a9930dSWolfram Sang  *   Driver for KeyStream, KS7010 based SDIO cards.
313a9930dSWolfram Sang  *
413a9930dSWolfram Sang  *   Copyright (C) 2006-2008 KeyStream Corp.
513a9930dSWolfram Sang  *   Copyright (C) 2009 Renesas Technology Corp.
6c5d9a030SWolfram Sang  *   Copyright (C) 2016 Sang Engineering, Wolfram Sang
713a9930dSWolfram Sang  *
813a9930dSWolfram Sang  *   This program is free software; you can redistribute it and/or modify
9c5d9a030SWolfram Sang  *   it under the terms of the GNU General Public License version 2 as
10c5d9a030SWolfram Sang  *   published by the Free Software Foundation.
1113a9930dSWolfram Sang  */
1213a9930dSWolfram Sang 
131c013a5cSWolfram Sang #include <linux/firmware.h>
1413a9930dSWolfram Sang #include <linux/mmc/card.h>
1513a9930dSWolfram Sang #include <linux/mmc/sdio_func.h>
161c013a5cSWolfram Sang #include <linux/workqueue.h>
17041c4d75Ssayli karnik #include <linux/atomic.h>
1813a9930dSWolfram Sang 
1913a9930dSWolfram Sang #include "ks_wlan.h"
2013a9930dSWolfram Sang #include "ks_wlan_ioctl.h"
2113a9930dSWolfram Sang #include "ks_hostif.h"
2213a9930dSWolfram Sang #include "ks7010_sdio.h"
2313a9930dSWolfram Sang 
2413a9930dSWolfram Sang #define KS7010_FUNC_NUM 1
2513a9930dSWolfram Sang #define KS7010_IO_BLOCK_SIZE 512
2613a9930dSWolfram Sang #define KS7010_MAX_CLOCK 25000000
2713a9930dSWolfram Sang 
28f9b5bd05SWolfram Sang static const struct sdio_device_id ks7010_sdio_ids[] = {
2913a9930dSWolfram Sang 	{SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010)},
3013a9930dSWolfram Sang 	{SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010)},
3113a9930dSWolfram Sang 	{ /* all zero */ }
3213a9930dSWolfram Sang };
33f9b5bd05SWolfram Sang MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids);
3413a9930dSWolfram Sang 
3513a9930dSWolfram Sang /* macro */
3613a9930dSWolfram Sang 
3713a9930dSWolfram Sang #define inc_txqhead(priv) \
3813a9930dSWolfram Sang         (priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE)
3913a9930dSWolfram Sang #define inc_txqtail(priv) \
4013a9930dSWolfram Sang         (priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE)
4113a9930dSWolfram Sang #define cnt_txqbody(priv) \
4213a9930dSWolfram Sang         (((priv->tx_dev.qtail + TX_DEVICE_BUFF_SIZE) - (priv->tx_dev.qhead)) % TX_DEVICE_BUFF_SIZE)
4313a9930dSWolfram Sang 
4413a9930dSWolfram Sang #define inc_rxqhead(priv) \
4513a9930dSWolfram Sang         (priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE)
4613a9930dSWolfram Sang #define inc_rxqtail(priv) \
4713a9930dSWolfram Sang         (priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE)
4813a9930dSWolfram Sang #define cnt_rxqbody(priv) \
4913a9930dSWolfram Sang         (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE)
5013a9930dSWolfram Sang 
514c0d46d2SWolfram Sang static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address,
524c0d46d2SWolfram Sang 			    unsigned char *buffer, int length)
534c0d46d2SWolfram Sang {
544c0d46d2SWolfram Sang 	struct ks_sdio_card *card;
554c0d46d2SWolfram Sang 	int rc;
564c0d46d2SWolfram Sang 
574c0d46d2SWolfram Sang 	card = priv->ks_wlan_hw.sdio_card;
584c0d46d2SWolfram Sang 
594c0d46d2SWolfram Sang 	if (length == 1)	/* CMD52 */
604c0d46d2SWolfram Sang 		*buffer = sdio_readb(card->func, address, &rc);
614c0d46d2SWolfram Sang 	else	/* CMD53 multi-block transfer */
624c0d46d2SWolfram Sang 		rc = sdio_memcpy_fromio(card->func, buffer, address, length);
634c0d46d2SWolfram Sang 
644c0d46d2SWolfram Sang 	if (rc != 0)
654c0d46d2SWolfram Sang 		DPRINTK(1, "sdio error=%d size=%d\n", rc, length);
664c0d46d2SWolfram Sang 
674c0d46d2SWolfram Sang 	return rc;
684c0d46d2SWolfram Sang }
694c0d46d2SWolfram Sang 
704c0d46d2SWolfram Sang static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address,
714c0d46d2SWolfram Sang 			     unsigned char *buffer, int length)
724c0d46d2SWolfram Sang {
734c0d46d2SWolfram Sang 	struct ks_sdio_card *card;
744c0d46d2SWolfram Sang 	int rc;
754c0d46d2SWolfram Sang 
764c0d46d2SWolfram Sang 	card = priv->ks_wlan_hw.sdio_card;
774c0d46d2SWolfram Sang 
784c0d46d2SWolfram Sang 	if (length == 1)	/* CMD52 */
794c0d46d2SWolfram Sang 		sdio_writeb(card->func, *buffer, (unsigned int)address, &rc);
804c0d46d2SWolfram Sang 	else	/* CMD53 */
814c0d46d2SWolfram Sang 		rc = sdio_memcpy_toio(card->func, (unsigned int)address, buffer,
824c0d46d2SWolfram Sang 				      length);
834c0d46d2SWolfram Sang 
844c0d46d2SWolfram Sang 	if (rc != 0)
854c0d46d2SWolfram Sang 		DPRINTK(1, "sdio error=%d size=%d\n", rc, length);
864c0d46d2SWolfram Sang 
874c0d46d2SWolfram Sang 	return rc;
884c0d46d2SWolfram Sang }
894c0d46d2SWolfram Sang 
90feedcf1aSWolfram Sang void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv)
9113a9930dSWolfram Sang {
9213a9930dSWolfram Sang 	unsigned char rw_data;
9313a9930dSWolfram Sang 	int retval;
9413a9930dSWolfram Sang 
9513a9930dSWolfram Sang 	DPRINTK(4, "\n");
9613a9930dSWolfram Sang 
9713a9930dSWolfram Sang 	/* clear request */
9813a9930dSWolfram Sang 	atomic_set(&priv->sleepstatus.doze_request, 0);
9913a9930dSWolfram Sang 
10013a9930dSWolfram Sang 	if (atomic_read(&priv->sleepstatus.status) == 0) {
10113a9930dSWolfram Sang 		rw_data = GCR_B_DOZE;
102cdf6ecc5SWolfram Sang 		retval =
103cdf6ecc5SWolfram Sang 		    ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data));
10413a9930dSWolfram Sang 		if (retval) {
10513a9930dSWolfram Sang 			DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
10613a9930dSWolfram Sang 			goto out;
10713a9930dSWolfram Sang 		}
10813a9930dSWolfram Sang 		DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data);
10913a9930dSWolfram Sang 		DPRINTK(3, "sleep_mode=SLP_SLEEP\n");
11013a9930dSWolfram Sang 		atomic_set(&priv->sleepstatus.status, 1);
11113a9930dSWolfram Sang 		priv->last_doze = jiffies;
112cdf6ecc5SWolfram Sang 	} else {
11313a9930dSWolfram Sang 		DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
11413a9930dSWolfram Sang 	}
11513a9930dSWolfram Sang 
11613a9930dSWolfram Sang  out:
11713a9930dSWolfram Sang 	priv->sleep_mode = atomic_read(&priv->sleepstatus.status);
11813a9930dSWolfram Sang }
11913a9930dSWolfram Sang 
120feedcf1aSWolfram Sang void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv)
12113a9930dSWolfram Sang {
12213a9930dSWolfram Sang 	unsigned char rw_data;
12313a9930dSWolfram Sang 	int retval;
12413a9930dSWolfram Sang 
12513a9930dSWolfram Sang 	DPRINTK(4, "\n");
12613a9930dSWolfram Sang 
12713a9930dSWolfram Sang 	/* clear request */
12813a9930dSWolfram Sang 	atomic_set(&priv->sleepstatus.wakeup_request, 0);
12913a9930dSWolfram Sang 
13013a9930dSWolfram Sang 	if (atomic_read(&priv->sleepstatus.status) == 1) {
13113a9930dSWolfram Sang 		rw_data = WAKEUP_REQ;
132cdf6ecc5SWolfram Sang 		retval =
133cdf6ecc5SWolfram Sang 		    ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data));
13413a9930dSWolfram Sang 		if (retval) {
13513a9930dSWolfram Sang 			DPRINTK(1, " error : WAKEUP=%02X\n", rw_data);
13613a9930dSWolfram Sang 			goto out;
13713a9930dSWolfram Sang 		}
13813a9930dSWolfram Sang 		DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data);
13913a9930dSWolfram Sang 		atomic_set(&priv->sleepstatus.status, 0);
14013a9930dSWolfram Sang 		priv->last_wakeup = jiffies;
14113a9930dSWolfram Sang 		++priv->wakeup_count;
142cdf6ecc5SWolfram Sang 	} else {
14313a9930dSWolfram Sang 		DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
14413a9930dSWolfram Sang 	}
14513a9930dSWolfram Sang 
14613a9930dSWolfram Sang  out:
14713a9930dSWolfram Sang 	priv->sleep_mode = atomic_read(&priv->sleepstatus.status);
14813a9930dSWolfram Sang }
14913a9930dSWolfram Sang 
150feedcf1aSWolfram Sang void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv)
15113a9930dSWolfram Sang {
15213a9930dSWolfram Sang 	unsigned char rw_data;
15313a9930dSWolfram Sang 	int retval;
15413a9930dSWolfram Sang 
15513a9930dSWolfram Sang 	DPRINTK(4, "\n");
15613a9930dSWolfram Sang 	if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
15713a9930dSWolfram Sang 		rw_data = WAKEUP_REQ;
158cdf6ecc5SWolfram Sang 		retval =
159cdf6ecc5SWolfram Sang 		    ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data));
16053638cefSsayli karnik 		if (retval)
16113a9930dSWolfram Sang 			DPRINTK(1, " error : WAKEUP=%02X\n", rw_data);
16253638cefSsayli karnik 
16313a9930dSWolfram Sang 		DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data);
16413a9930dSWolfram Sang 		priv->last_wakeup = jiffies;
16513a9930dSWolfram Sang 		++priv->wakeup_count;
166cdf6ecc5SWolfram Sang 	} else {
167cdf6ecc5SWolfram Sang 		DPRINTK(1, "psstatus=%d\n",
168cdf6ecc5SWolfram Sang 			atomic_read(&priv->psstatus.status));
16913a9930dSWolfram Sang 	}
17013a9930dSWolfram Sang }
17113a9930dSWolfram Sang 
172feedcf1aSWolfram Sang int _ks_wlan_hw_power_save(struct ks_wlan_private *priv)
17313a9930dSWolfram Sang {
17413a9930dSWolfram Sang 	int rc = 0;
17513a9930dSWolfram Sang 	unsigned char rw_data;
17613a9930dSWolfram Sang 	int retval;
17713a9930dSWolfram Sang 
17813a9930dSWolfram Sang 	if (priv->reg.powermgt == POWMGT_ACTIVE_MODE)
17913a9930dSWolfram Sang 		return rc;
18013a9930dSWolfram Sang 
18113a9930dSWolfram Sang 	if (priv->reg.operation_mode == MODE_INFRASTRUCTURE &&
18213a9930dSWolfram Sang 	    (priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) {
18313a9930dSWolfram Sang 		if (priv->dev_state == DEVICE_STATE_SLEEP) {
18413a9930dSWolfram Sang 			switch (atomic_read(&priv->psstatus.status)) {
18513a9930dSWolfram Sang 			case PS_SNOOZE:	/* 4 */
18613a9930dSWolfram Sang 				break;
18713a9930dSWolfram Sang 			default:
188cdf6ecc5SWolfram Sang 				DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n",
18913a9930dSWolfram Sang 					atomic_read(&priv->psstatus.status),
19013a9930dSWolfram Sang 					atomic_read(&priv->psstatus.confirm_wait),
19113a9930dSWolfram Sang 					atomic_read(&priv->psstatus.snooze_guard),
19213a9930dSWolfram Sang 					cnt_txqbody(priv));
19313a9930dSWolfram Sang 
194cdf6ecc5SWolfram Sang 				if (!atomic_read(&priv->psstatus.confirm_wait)
195cdf6ecc5SWolfram Sang 				    && !atomic_read(&priv->psstatus.snooze_guard)
196cdf6ecc5SWolfram Sang 				    && !cnt_txqbody(priv)) {
197cdf6ecc5SWolfram Sang 					retval =
198cdf6ecc5SWolfram Sang 					    ks7010_sdio_read(priv, INT_PENDING,
199cdf6ecc5SWolfram Sang 							     &rw_data,
200cdf6ecc5SWolfram Sang 							     sizeof(rw_data));
20113a9930dSWolfram Sang 					if (retval) {
202cdf6ecc5SWolfram Sang 						DPRINTK(1,
203cdf6ecc5SWolfram Sang 							" error : INT_PENDING=%02X\n",
204cdf6ecc5SWolfram Sang 							rw_data);
205cdf6ecc5SWolfram Sang 						queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
206cdf6ecc5SWolfram Sang 								   &priv->ks_wlan_hw.rw_wq, 1);
20713a9930dSWolfram Sang 						break;
20813a9930dSWolfram Sang 					}
20913a9930dSWolfram Sang 					if (!rw_data) {
21013a9930dSWolfram Sang 						rw_data = GCR_B_DOZE;
211cdf6ecc5SWolfram Sang 						retval =
212cdf6ecc5SWolfram Sang 						    ks7010_sdio_write(priv,
213cdf6ecc5SWolfram Sang 								      GCR_B,
214cdf6ecc5SWolfram Sang 								      &rw_data,
215cdf6ecc5SWolfram Sang 								      sizeof(rw_data));
21613a9930dSWolfram Sang 						if (retval) {
217cdf6ecc5SWolfram Sang 							DPRINTK(1,
218cdf6ecc5SWolfram Sang 								" error : GCR_B=%02X\n",
219cdf6ecc5SWolfram Sang 								rw_data);
220cdf6ecc5SWolfram Sang 							queue_delayed_work
221cdf6ecc5SWolfram Sang 							    (priv->ks_wlan_hw.ks7010sdio_wq,
222cdf6ecc5SWolfram Sang 							     &priv->ks_wlan_hw.rw_wq, 1);
22313a9930dSWolfram Sang 							break;
22413a9930dSWolfram Sang 						}
225cdf6ecc5SWolfram Sang 						DPRINTK(4,
226cdf6ecc5SWolfram Sang 							"PMG SET!! : GCR_B=%02X\n",
227cdf6ecc5SWolfram Sang 							rw_data);
228cdf6ecc5SWolfram Sang 						atomic_set(&priv->psstatus.
229cdf6ecc5SWolfram Sang 							   status, PS_SNOOZE);
230cdf6ecc5SWolfram Sang 						DPRINTK(3,
231cdf6ecc5SWolfram Sang 							"psstatus.status=PS_SNOOZE\n");
232cdf6ecc5SWolfram Sang 					} else {
233cdf6ecc5SWolfram Sang 						queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
234cdf6ecc5SWolfram Sang 								   &priv->ks_wlan_hw.rw_wq, 1);
23513a9930dSWolfram Sang 					}
236cdf6ecc5SWolfram Sang 				} else {
237cdf6ecc5SWolfram Sang 					queue_delayed_work(priv->ks_wlan_hw.
238cdf6ecc5SWolfram Sang 							   ks7010sdio_wq,
239cdf6ecc5SWolfram Sang 							   &priv->ks_wlan_hw.rw_wq,
240cdf6ecc5SWolfram Sang 							   0);
24113a9930dSWolfram Sang 				}
24213a9930dSWolfram Sang 				break;
24313a9930dSWolfram Sang 			}
24413a9930dSWolfram Sang 		}
24513a9930dSWolfram Sang 	}
24613a9930dSWolfram Sang 
24713a9930dSWolfram Sang 	return rc;
24813a9930dSWolfram Sang }
24913a9930dSWolfram Sang 
250feedcf1aSWolfram Sang int ks_wlan_hw_power_save(struct ks_wlan_private *priv)
25113a9930dSWolfram Sang {
252cdf6ecc5SWolfram Sang 	queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
253cdf6ecc5SWolfram Sang 			   &priv->ks_wlan_hw.rw_wq, 1);
25413a9930dSWolfram Sang 	return 0;
25513a9930dSWolfram Sang }
25613a9930dSWolfram Sang 
257cdf6ecc5SWolfram Sang static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p,
258cdf6ecc5SWolfram Sang 			 unsigned long size,
25913a9930dSWolfram Sang 			 void (*complete_handler) (void *arg1, void *arg2),
26013a9930dSWolfram Sang 			 void *arg1, void *arg2)
26113a9930dSWolfram Sang {
26213a9930dSWolfram Sang 	struct tx_device_buffer *sp;
26313a9930dSWolfram Sang 
26413a9930dSWolfram Sang 	if (priv->dev_state < DEVICE_STATE_BOOT) {
26513a9930dSWolfram Sang 		kfree(p);
266c7e65f4dSsayli karnik 		if (complete_handler)
26713a9930dSWolfram Sang 			(*complete_handler) (arg1, arg2);
26813a9930dSWolfram Sang 		return 1;
26913a9930dSWolfram Sang 	}
27013a9930dSWolfram Sang 
27113a9930dSWolfram Sang 	if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) {
27213a9930dSWolfram Sang 		/* in case of buffer overflow */
27313a9930dSWolfram Sang 		DPRINTK(1, "tx buffer overflow\n");
27413a9930dSWolfram Sang 		kfree(p);
275c7e65f4dSsayli karnik 		if (complete_handler)
27613a9930dSWolfram Sang 			(*complete_handler) (arg1, arg2);
27713a9930dSWolfram Sang 		return 1;
27813a9930dSWolfram Sang 	}
27913a9930dSWolfram Sang 
28013a9930dSWolfram Sang 	sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail];
28113a9930dSWolfram Sang 	sp->sendp = p;
28213a9930dSWolfram Sang 	sp->size = size;
28313a9930dSWolfram Sang 	sp->complete_handler = complete_handler;
28413a9930dSWolfram Sang 	sp->arg1 = arg1;
28513a9930dSWolfram Sang 	sp->arg2 = arg2;
28613a9930dSWolfram Sang 	inc_txqtail(priv);
28713a9930dSWolfram Sang 
28813a9930dSWolfram Sang 	return 0;
28913a9930dSWolfram Sang }
29013a9930dSWolfram Sang 
29113a9930dSWolfram Sang /* write data */
292cdf6ecc5SWolfram Sang static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer,
293cdf6ecc5SWolfram Sang 			   unsigned long size)
29413a9930dSWolfram Sang {
295695872eaSMarkus Elfring 	int retval;
29613a9930dSWolfram Sang 	unsigned char rw_data;
29713a9930dSWolfram Sang 	struct hostif_hdr *hdr;
29813a9930dSWolfram Sang 	hdr = (struct hostif_hdr *)buffer;
29913a9930dSWolfram Sang 
30013a9930dSWolfram Sang 	DPRINTK(4, "size=%d\n", hdr->size);
30113a9930dSWolfram Sang 	if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) {
30213a9930dSWolfram Sang 		DPRINTK(1, "unknown event=%04X\n", hdr->event);
30313a9930dSWolfram Sang 		return 0;
30413a9930dSWolfram Sang 	}
30513a9930dSWolfram Sang 
30613a9930dSWolfram Sang 	retval = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size);
30713a9930dSWolfram Sang 	if (retval) {
30813a9930dSWolfram Sang 		DPRINTK(1, " write error : retval=%d\n", retval);
30913a9930dSWolfram Sang 		return -4;
31013a9930dSWolfram Sang 	}
31113a9930dSWolfram Sang 
31213a9930dSWolfram Sang 	rw_data = WRITE_STATUS_BUSY;
313cdf6ecc5SWolfram Sang 	retval =
314cdf6ecc5SWolfram Sang 	    ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data));
31513a9930dSWolfram Sang 	if (retval) {
31613a9930dSWolfram Sang 		DPRINTK(1, " error : WRITE_STATUS=%02X\n", rw_data);
31713a9930dSWolfram Sang 		return -3;
31813a9930dSWolfram Sang 	}
31913a9930dSWolfram Sang 
32013a9930dSWolfram Sang 	return 0;
32113a9930dSWolfram Sang }
32213a9930dSWolfram Sang 
32313a9930dSWolfram Sang static void tx_device_task(void *dev)
32413a9930dSWolfram Sang {
325feedcf1aSWolfram Sang 	struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
32613a9930dSWolfram Sang 	struct tx_device_buffer *sp;
32713a9930dSWolfram Sang 	int rc = 0;
32813a9930dSWolfram Sang 
32913a9930dSWolfram Sang 	DPRINTK(4, "\n");
330cdf6ecc5SWolfram Sang 	if (cnt_txqbody(priv) > 0
331cdf6ecc5SWolfram Sang 	    && atomic_read(&priv->psstatus.status) != PS_SNOOZE) {
33213a9930dSWolfram Sang 		sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead];
33313a9930dSWolfram Sang 		if (priv->dev_state >= DEVICE_STATE_BOOT) {
33413a9930dSWolfram Sang 			rc = write_to_device(priv, sp->sendp, sp->size);
33513a9930dSWolfram Sang 			if (rc) {
336cdf6ecc5SWolfram Sang 				DPRINTK(1, "write_to_device error !!(%d)\n",
337cdf6ecc5SWolfram Sang 					rc);
338cdf6ecc5SWolfram Sang 				queue_delayed_work(priv->ks_wlan_hw.
339cdf6ecc5SWolfram Sang 						   ks7010sdio_wq,
340cdf6ecc5SWolfram Sang 						   &priv->ks_wlan_hw.rw_wq, 1);
34113a9930dSWolfram Sang 				return;
34213a9930dSWolfram Sang 			}
34313a9930dSWolfram Sang 		}
34413a9930dSWolfram Sang 		kfree(sp->sendp);	/* allocated memory free */
345c7e65f4dSsayli karnik 		if (sp->complete_handler)	/* TX Complete */
34613a9930dSWolfram Sang 			(*sp->complete_handler) (sp->arg1, sp->arg2);
34713a9930dSWolfram Sang 		inc_txqhead(priv);
34813a9930dSWolfram Sang 
34913a9930dSWolfram Sang 		if (cnt_txqbody(priv) > 0) {
350cdf6ecc5SWolfram Sang 			queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
351cdf6ecc5SWolfram Sang 					   &priv->ks_wlan_hw.rw_wq, 0);
35213a9930dSWolfram Sang 		}
35313a9930dSWolfram Sang 	}
35413a9930dSWolfram Sang }
35513a9930dSWolfram Sang 
356feedcf1aSWolfram Sang int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
35713a9930dSWolfram Sang 		  void (*complete_handler) (void *arg1, void *arg2),
35813a9930dSWolfram Sang 		  void *arg1, void *arg2)
35913a9930dSWolfram Sang {
36013a9930dSWolfram Sang 	int result = 0;
36113a9930dSWolfram Sang 	struct hostif_hdr *hdr;
36213a9930dSWolfram Sang 	hdr = (struct hostif_hdr *)p;
36313a9930dSWolfram Sang 
36413a9930dSWolfram Sang 	if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) {
36513a9930dSWolfram Sang 		DPRINTK(1, "unknown event=%04X\n", hdr->event);
36613a9930dSWolfram Sang 		return 0;
36713a9930dSWolfram Sang 	}
36813a9930dSWolfram Sang 
36913a9930dSWolfram Sang 	/* add event to hostt buffer */
37013a9930dSWolfram Sang 	priv->hostt.buff[priv->hostt.qtail] = hdr->event;
37113a9930dSWolfram Sang 	priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE;
37213a9930dSWolfram Sang 
37313a9930dSWolfram Sang 	DPRINTK(4, "event=%04X\n", hdr->event);
37413a9930dSWolfram Sang 	spin_lock(&priv->tx_dev.tx_dev_lock);
37513a9930dSWolfram Sang 	result = enqueue_txdev(priv, p, size, complete_handler, arg1, arg2);
37613a9930dSWolfram Sang 	spin_unlock(&priv->tx_dev.tx_dev_lock);
37713a9930dSWolfram Sang 
37813a9930dSWolfram Sang 	if (cnt_txqbody(priv) > 0) {
379cdf6ecc5SWolfram Sang 		queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
380cdf6ecc5SWolfram Sang 				   &priv->ks_wlan_hw.rw_wq, 0);
38113a9930dSWolfram Sang 	}
38213a9930dSWolfram Sang 	return result;
38313a9930dSWolfram Sang }
38413a9930dSWolfram Sang 
38513a9930dSWolfram Sang static void rx_event_task(unsigned long dev)
38613a9930dSWolfram Sang {
387feedcf1aSWolfram Sang 	struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
38813a9930dSWolfram Sang 	struct rx_device_buffer *rp;
38913a9930dSWolfram Sang 
39013a9930dSWolfram Sang 	DPRINTK(4, "\n");
39113a9930dSWolfram Sang 
39213a9930dSWolfram Sang 	if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) {
39313a9930dSWolfram Sang 		rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead];
39413a9930dSWolfram Sang 		hostif_receive(priv, rp->data, rp->size);
39513a9930dSWolfram Sang 		inc_rxqhead(priv);
39613a9930dSWolfram Sang 
39753638cefSsayli karnik 		if (cnt_rxqbody(priv) > 0)
39813a9930dSWolfram Sang 			tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task);
39913a9930dSWolfram Sang 	}
40013a9930dSWolfram Sang }
40113a9930dSWolfram Sang 
40213a9930dSWolfram Sang static void ks_wlan_hw_rx(void *dev, uint16_t size)
40313a9930dSWolfram Sang {
404feedcf1aSWolfram Sang 	struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
40513a9930dSWolfram Sang 	int retval;
40613a9930dSWolfram Sang 	struct rx_device_buffer *rx_buffer;
40713a9930dSWolfram Sang 	struct hostif_hdr *hdr;
40813a9930dSWolfram Sang 	unsigned char read_status;
40913a9930dSWolfram Sang 	unsigned short event = 0;
41013a9930dSWolfram Sang 
41113a9930dSWolfram Sang 	DPRINTK(4, "\n");
41213a9930dSWolfram Sang 
41313a9930dSWolfram Sang 	/* receive data */
41413a9930dSWolfram Sang 	if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) {
41513a9930dSWolfram Sang 		/* in case of buffer overflow */
41613a9930dSWolfram Sang 		DPRINTK(1, "rx buffer overflow \n");
41713a9930dSWolfram Sang 		goto error_out;
41813a9930dSWolfram Sang 	}
41913a9930dSWolfram Sang 	rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail];
42013a9930dSWolfram Sang 
421cdf6ecc5SWolfram Sang 	retval =
422cdf6ecc5SWolfram Sang 	    ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0],
423cdf6ecc5SWolfram Sang 			     hif_align_size(size));
42453638cefSsayli karnik 	if (retval)
42513a9930dSWolfram Sang 		goto error_out;
42613a9930dSWolfram Sang 
42713a9930dSWolfram Sang 	/* length check */
42813a9930dSWolfram Sang 	if (size > 2046 || size == 0) {
4293215bb1aSWolfram Sang #ifdef KS_WLAN_DEBUG
4303215bb1aSWolfram Sang 		if (KS_WLAN_DEBUG > 5)
431cdf6ecc5SWolfram Sang 			print_hex_dump_bytes("INVALID DATA dump: ",
432cdf6ecc5SWolfram Sang 					     DUMP_PREFIX_OFFSET,
4333215bb1aSWolfram Sang 					     rx_buffer->data, 32);
4343215bb1aSWolfram Sang #endif
43513a9930dSWolfram Sang 		/* rx_status update */
43613a9930dSWolfram Sang 		read_status = READ_STATUS_IDLE;
437cdf6ecc5SWolfram Sang 		retval =
438cdf6ecc5SWolfram Sang 		    ks7010_sdio_write(priv, READ_STATUS, &read_status,
439cdf6ecc5SWolfram Sang 				      sizeof(read_status));
44053638cefSsayli karnik 		if (retval)
44113a9930dSWolfram Sang 			DPRINTK(1, " error : READ_STATUS=%02X\n", read_status);
44253638cefSsayli karnik 
44313a9930dSWolfram Sang 		goto error_out;
44413a9930dSWolfram Sang 	}
44513a9930dSWolfram Sang 
44613a9930dSWolfram Sang 	hdr = (struct hostif_hdr *)&rx_buffer->data[0];
44713a9930dSWolfram Sang 	rx_buffer->size = le16_to_cpu(hdr->size) + sizeof(hdr->size);
44813a9930dSWolfram Sang 	event = hdr->event;
44913a9930dSWolfram Sang 	inc_rxqtail(priv);
45013a9930dSWolfram Sang 
45113a9930dSWolfram Sang 	/* read status update */
45213a9930dSWolfram Sang 	read_status = READ_STATUS_IDLE;
453cdf6ecc5SWolfram Sang 	retval =
454cdf6ecc5SWolfram Sang 	    ks7010_sdio_write(priv, READ_STATUS, &read_status,
455cdf6ecc5SWolfram Sang 			      sizeof(read_status));
45653638cefSsayli karnik 	if (retval)
45713a9930dSWolfram Sang 		DPRINTK(1, " error : READ_STATUS=%02X\n", read_status);
45853638cefSsayli karnik 
45913a9930dSWolfram Sang 	DPRINTK(4, "READ_STATUS=%02X\n", read_status);
46013a9930dSWolfram Sang 
46113a9930dSWolfram Sang 	if (atomic_read(&priv->psstatus.confirm_wait)) {
46213a9930dSWolfram Sang 		if (IS_HIF_CONF(event)) {
46313a9930dSWolfram Sang 			DPRINTK(4, "IS_HIF_CONF true !!\n");
46413a9930dSWolfram Sang 			atomic_dec(&priv->psstatus.confirm_wait);
46513a9930dSWolfram Sang 		}
46613a9930dSWolfram Sang 	}
46713a9930dSWolfram Sang 
46813a9930dSWolfram Sang 	/* rx_event_task((void *)priv); */
46913a9930dSWolfram Sang 	tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task);
47013a9930dSWolfram Sang 
47113a9930dSWolfram Sang  error_out:
47213a9930dSWolfram Sang 	return;
47313a9930dSWolfram Sang }
47413a9930dSWolfram Sang 
47513a9930dSWolfram Sang static void ks7010_rw_function(struct work_struct *work)
47613a9930dSWolfram Sang {
47713a9930dSWolfram Sang 	struct hw_info_t *hw;
47813a9930dSWolfram Sang 	struct ks_wlan_private *priv;
47913a9930dSWolfram Sang 	unsigned char rw_data;
48013a9930dSWolfram Sang 	int retval;
48113a9930dSWolfram Sang 
48213a9930dSWolfram Sang 	hw = container_of(work, struct hw_info_t, rw_wq.work);
48313a9930dSWolfram Sang 	priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw);
48413a9930dSWolfram Sang 
48513a9930dSWolfram Sang 	DPRINTK(4, "\n");
48613a9930dSWolfram Sang 
48713a9930dSWolfram Sang 	/* wiat after DOZE */
48813a9930dSWolfram Sang 	if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) {
48913a9930dSWolfram Sang 		DPRINTK(4, "wait after DOZE\n");
490cdf6ecc5SWolfram Sang 		queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
491cdf6ecc5SWolfram Sang 				   &priv->ks_wlan_hw.rw_wq, 1);
49213a9930dSWolfram Sang 		return;
49313a9930dSWolfram Sang 	}
49413a9930dSWolfram Sang 
49513a9930dSWolfram Sang 	/* wiat after WAKEUP */
49613a9930dSWolfram Sang 	while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) {
49713a9930dSWolfram Sang 		DPRINTK(4, "wait after WAKEUP\n");
49813a9930dSWolfram Sang /*		queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq,
49913a9930dSWolfram Sang 		(priv->last_wakeup + ((30*HZ)/1000) - jiffies));*/
500cdf6ecc5SWolfram Sang 		printk("wake: %lu %lu\n", priv->last_wakeup + (30 * HZ) / 1000,
501cdf6ecc5SWolfram Sang 		       jiffies);
50213a9930dSWolfram Sang 		msleep(30);
50313a9930dSWolfram Sang 	}
50413a9930dSWolfram Sang 
50513a9930dSWolfram Sang 	sdio_claim_host(priv->ks_wlan_hw.sdio_card->func);
50613a9930dSWolfram Sang 
50713a9930dSWolfram Sang 	/* power save wakeup */
50813a9930dSWolfram Sang 	if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
50913a9930dSWolfram Sang 		if (cnt_txqbody(priv) > 0) {
51013a9930dSWolfram Sang 			ks_wlan_hw_wakeup_request(priv);
511cdf6ecc5SWolfram Sang 			queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
512cdf6ecc5SWolfram Sang 					   &priv->ks_wlan_hw.rw_wq, 1);
51313a9930dSWolfram Sang 		}
51413a9930dSWolfram Sang 		goto err_out;
51513a9930dSWolfram Sang 	}
51613a9930dSWolfram Sang 
51713a9930dSWolfram Sang 	/* sleep mode doze */
51813a9930dSWolfram Sang 	if (atomic_read(&priv->sleepstatus.doze_request) == 1) {
51913a9930dSWolfram Sang 		ks_wlan_hw_sleep_doze_request(priv);
52013a9930dSWolfram Sang 		goto err_out;
52113a9930dSWolfram Sang 	}
52213a9930dSWolfram Sang 	/* sleep mode wakeup */
52313a9930dSWolfram Sang 	if (atomic_read(&priv->sleepstatus.wakeup_request) == 1) {
52413a9930dSWolfram Sang 		ks_wlan_hw_sleep_wakeup_request(priv);
52513a9930dSWolfram Sang 		goto err_out;
52613a9930dSWolfram Sang 	}
52713a9930dSWolfram Sang 
52813a9930dSWolfram Sang 	/* read (WriteStatus/ReadDataSize FN1:00_0014) */
529cdf6ecc5SWolfram Sang 	retval =
530cdf6ecc5SWolfram Sang 	    ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data));
53113a9930dSWolfram Sang 	if (retval) {
532cdf6ecc5SWolfram Sang 		DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data,
533cdf6ecc5SWolfram Sang 			atomic_read(&priv->psstatus.status));
53413a9930dSWolfram Sang 		goto err_out;
53513a9930dSWolfram Sang 	}
53613a9930dSWolfram Sang 	DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data);
53713a9930dSWolfram Sang 
53813a9930dSWolfram Sang 	if (rw_data & RSIZE_MASK) {	/* Read schedule */
539cdf6ecc5SWolfram Sang 		ks_wlan_hw_rx((void *)priv,
540149ad082Ssayli karnik 			      (uint16_t)((rw_data & RSIZE_MASK) << 4));
54113a9930dSWolfram Sang 	}
54253638cefSsayli karnik 	if ((rw_data & WSTATUS_MASK))
54313a9930dSWolfram Sang 		tx_device_task((void *)priv);
54453638cefSsayli karnik 
54513a9930dSWolfram Sang 	_ks_wlan_hw_power_save(priv);
54613a9930dSWolfram Sang 
54713a9930dSWolfram Sang  err_out:
54813a9930dSWolfram Sang 	sdio_release_host(priv->ks_wlan_hw.sdio_card->func);
54913a9930dSWolfram Sang }
55013a9930dSWolfram Sang 
55113a9930dSWolfram Sang static void ks_sdio_interrupt(struct sdio_func *func)
55213a9930dSWolfram Sang {
55313a9930dSWolfram Sang 	int retval;
55413a9930dSWolfram Sang 	struct ks_sdio_card *card;
555feedcf1aSWolfram Sang 	struct ks_wlan_private *priv;
55613a9930dSWolfram Sang 	unsigned char status, rsize, rw_data;
55713a9930dSWolfram Sang 
55813a9930dSWolfram Sang 	card = sdio_get_drvdata(func);
55913a9930dSWolfram Sang 	priv = card->priv;
56013a9930dSWolfram Sang 	DPRINTK(4, "\n");
56113a9930dSWolfram Sang 
56213a9930dSWolfram Sang 	if (priv->dev_state >= DEVICE_STATE_BOOT) {
563cdf6ecc5SWolfram Sang 		retval =
564cdf6ecc5SWolfram Sang 		    ks7010_sdio_read(priv, INT_PENDING, &status,
565cdf6ecc5SWolfram Sang 				     sizeof(status));
56613a9930dSWolfram Sang 		if (retval) {
56713a9930dSWolfram Sang 			DPRINTK(1, "read INT_PENDING Failed!!(%d)\n", retval);
56813a9930dSWolfram Sang 			goto intr_out;
56913a9930dSWolfram Sang 		}
57013a9930dSWolfram Sang 		DPRINTK(4, "INT_PENDING=%02X\n", rw_data);
57113a9930dSWolfram Sang 
57213a9930dSWolfram Sang 		/* schedule task for interrupt status */
57313a9930dSWolfram Sang 		/* bit7 -> Write General Communication B register */
57413a9930dSWolfram Sang 		/* read (General Communication B register) */
57513a9930dSWolfram Sang 		/* bit5 -> Write Status Idle */
57613a9930dSWolfram Sang 		/* bit2 -> Read Status Busy  */
577cdf6ecc5SWolfram Sang 		if (status & INT_GCR_B
578cdf6ecc5SWolfram Sang 		    || atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
579cdf6ecc5SWolfram Sang 			retval =
580cdf6ecc5SWolfram Sang 			    ks7010_sdio_read(priv, GCR_B, &rw_data,
581cdf6ecc5SWolfram Sang 					     sizeof(rw_data));
58213a9930dSWolfram Sang 			if (retval) {
58313a9930dSWolfram Sang 				DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
58413a9930dSWolfram Sang 				goto intr_out;
58513a9930dSWolfram Sang 			}
58613a9930dSWolfram Sang 			/* DPRINTK(1, "GCR_B=%02X\n", rw_data); */
58713a9930dSWolfram Sang 			if (rw_data == GCR_B_ACTIVE) {
588cdf6ecc5SWolfram Sang 				if (atomic_read(&priv->psstatus.status) ==
589cdf6ecc5SWolfram Sang 				    PS_SNOOZE) {
590cdf6ecc5SWolfram Sang 					atomic_set(&priv->psstatus.status,
591cdf6ecc5SWolfram Sang 						   PS_WAKEUP);
59213a9930dSWolfram Sang 					priv->wakeup_count = 0;
59313a9930dSWolfram Sang 				}
59413a9930dSWolfram Sang 				complete(&priv->psstatus.wakeup_wait);
59513a9930dSWolfram Sang 			}
59613a9930dSWolfram Sang 		}
59713a9930dSWolfram Sang 
59813a9930dSWolfram Sang 		do {
59913a9930dSWolfram Sang 			/* read (WriteStatus/ReadDataSize FN1:00_0014) */
600cdf6ecc5SWolfram Sang 			retval =
601cdf6ecc5SWolfram Sang 			    ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data,
602cdf6ecc5SWolfram Sang 					     sizeof(rw_data));
60313a9930dSWolfram Sang 			if (retval) {
604cdf6ecc5SWolfram Sang 				DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n",
605cdf6ecc5SWolfram Sang 					rw_data);
60613a9930dSWolfram Sang 				goto intr_out;
60713a9930dSWolfram Sang 			}
60813a9930dSWolfram Sang 			DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data);
60913a9930dSWolfram Sang 			rsize = rw_data & RSIZE_MASK;
61013a9930dSWolfram Sang 			if (rsize) {	/* Read schedule */
611cdf6ecc5SWolfram Sang 				ks_wlan_hw_rx((void *)priv,
612149ad082Ssayli karnik 					      (uint16_t)(rsize << 4));
61313a9930dSWolfram Sang 			}
61413a9930dSWolfram Sang 			if (rw_data & WSTATUS_MASK) {
61513a9930dSWolfram Sang #if 0
616cdf6ecc5SWolfram Sang 				if (status & INT_WRITE_STATUS
617cdf6ecc5SWolfram Sang 				    && !cnt_txqbody(priv)) {
61813a9930dSWolfram Sang 					/* dummy write for interrupt clear */
61913a9930dSWolfram Sang 					rw_data = 0;
620cdf6ecc5SWolfram Sang 					retval =
621cdf6ecc5SWolfram Sang 					    ks7010_sdio_write(priv, DATA_WINDOW,
622cdf6ecc5SWolfram Sang 							      &rw_data,
623cdf6ecc5SWolfram Sang 							      sizeof(rw_data));
62413a9930dSWolfram Sang 					if (retval) {
625cdf6ecc5SWolfram Sang 						DPRINTK(1,
626cdf6ecc5SWolfram Sang 							"write DATA_WINDOW Failed!!(%d)\n",
627cdf6ecc5SWolfram Sang 							retval);
62813a9930dSWolfram Sang 					}
62913a9930dSWolfram Sang 					status &= ~INT_WRITE_STATUS;
630cdf6ecc5SWolfram Sang 				} else {
63113a9930dSWolfram Sang #endif
63213a9930dSWolfram Sang 					if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
63313a9930dSWolfram Sang 						if (cnt_txqbody(priv)) {
63413a9930dSWolfram Sang 							ks_wlan_hw_wakeup_request(priv);
635cdf6ecc5SWolfram Sang 							queue_delayed_work
636cdf6ecc5SWolfram Sang 							    (priv->ks_wlan_hw.
637cdf6ecc5SWolfram Sang 							     ks7010sdio_wq,
638cdf6ecc5SWolfram Sang 							     &priv->ks_wlan_hw.
639cdf6ecc5SWolfram Sang 							     rw_wq, 1);
64013a9930dSWolfram Sang 							return;
64113a9930dSWolfram Sang 						}
642cdf6ecc5SWolfram Sang 					} else {
64313a9930dSWolfram Sang 						tx_device_task((void *)priv);
64413a9930dSWolfram Sang 					}
645cdf6ecc5SWolfram Sang #if 0
646cdf6ecc5SWolfram Sang 				}
647cdf6ecc5SWolfram Sang #endif
64813a9930dSWolfram Sang 			}
64913a9930dSWolfram Sang 		} while (rsize);
65013a9930dSWolfram Sang 	}
65113a9930dSWolfram Sang 
65213a9930dSWolfram Sang  intr_out:
653cdf6ecc5SWolfram Sang 	queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
654cdf6ecc5SWolfram Sang 			   &priv->ks_wlan_hw.rw_wq, 0);
65513a9930dSWolfram Sang }
65613a9930dSWolfram Sang 
657feedcf1aSWolfram Sang static int trx_device_init(struct ks_wlan_private *priv)
65813a9930dSWolfram Sang {
65913a9930dSWolfram Sang 	/* initialize values (tx) */
66013a9930dSWolfram Sang 	priv->tx_dev.qtail = priv->tx_dev.qhead = 0;
66113a9930dSWolfram Sang 
66213a9930dSWolfram Sang 	/* initialize values (rx) */
66313a9930dSWolfram Sang 	priv->rx_dev.qtail = priv->rx_dev.qhead = 0;
66413a9930dSWolfram Sang 
66513a9930dSWolfram Sang 	/* initialize spinLock (tx,rx) */
66613a9930dSWolfram Sang 	spin_lock_init(&priv->tx_dev.tx_dev_lock);
66713a9930dSWolfram Sang 	spin_lock_init(&priv->rx_dev.rx_dev_lock);
66813a9930dSWolfram Sang 
669cdf6ecc5SWolfram Sang 	tasklet_init(&priv->ks_wlan_hw.rx_bh_task, rx_event_task,
670cdf6ecc5SWolfram Sang 		     (unsigned long)priv);
67113a9930dSWolfram Sang 
67213a9930dSWolfram Sang 	return 0;
67313a9930dSWolfram Sang }
67413a9930dSWolfram Sang 
675feedcf1aSWolfram Sang static void trx_device_exit(struct ks_wlan_private *priv)
67613a9930dSWolfram Sang {
67713a9930dSWolfram Sang 	struct tx_device_buffer *sp;
67813a9930dSWolfram Sang 
67913a9930dSWolfram Sang 	/* tx buffer clear */
68013a9930dSWolfram Sang 	while (cnt_txqbody(priv) > 0) {
68113a9930dSWolfram Sang 		sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead];
68213a9930dSWolfram Sang 		kfree(sp->sendp);	/* allocated memory free */
683c7e65f4dSsayli karnik 		if (sp->complete_handler)	/* TX Complete */
68413a9930dSWolfram Sang 			(*sp->complete_handler) (sp->arg1, sp->arg2);
68513a9930dSWolfram Sang 		inc_txqhead(priv);
68613a9930dSWolfram Sang 	}
68713a9930dSWolfram Sang 
68813a9930dSWolfram Sang 	tasklet_kill(&priv->ks_wlan_hw.rx_bh_task);
68913a9930dSWolfram Sang }
690cdf6ecc5SWolfram Sang 
691feedcf1aSWolfram Sang static int ks7010_sdio_update_index(struct ks_wlan_private *priv, u32 index)
69213a9930dSWolfram Sang {
69313a9930dSWolfram Sang 	int rc = 0;
69413a9930dSWolfram Sang 	int retval;
69513a9930dSWolfram Sang 	unsigned char *data_buf;
69613a9930dSWolfram Sang 
69713a9930dSWolfram Sang 	data_buf = kmalloc(sizeof(u32), GFP_KERNEL);
698cdf6ecc5SWolfram Sang 	if (!data_buf) {
699cdf6ecc5SWolfram Sang 		rc = 1;
700cdf6ecc5SWolfram Sang 		goto error_out;
701cdf6ecc5SWolfram Sang 	}
70213a9930dSWolfram Sang 
70313a9930dSWolfram Sang 	memcpy(data_buf, &index, sizeof(index));
70413a9930dSWolfram Sang 	retval = ks7010_sdio_write(priv, WRITE_INDEX, data_buf, sizeof(index));
705cdf6ecc5SWolfram Sang 	if (retval) {
706cdf6ecc5SWolfram Sang 		rc = 2;
707cdf6ecc5SWolfram Sang 		goto error_out;
708cdf6ecc5SWolfram Sang 	}
70913a9930dSWolfram Sang 
71013a9930dSWolfram Sang 	retval = ks7010_sdio_write(priv, READ_INDEX, data_buf, sizeof(index));
711cdf6ecc5SWolfram Sang 	if (retval) {
712cdf6ecc5SWolfram Sang 		rc = 3;
713cdf6ecc5SWolfram Sang 		goto error_out;
714cdf6ecc5SWolfram Sang 	}
71513a9930dSWolfram Sang  error_out:
716cdf6ecc5SWolfram Sang 	kfree(data_buf);
71713a9930dSWolfram Sang 	return rc;
71813a9930dSWolfram Sang }
71913a9930dSWolfram Sang 
72013a9930dSWolfram Sang #define ROM_BUFF_SIZE (64*1024)
721feedcf1aSWolfram Sang static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address,
72213a9930dSWolfram Sang 				    unsigned char *data, unsigned int size)
72313a9930dSWolfram Sang {
72413a9930dSWolfram Sang 	int rc = 0;
72513a9930dSWolfram Sang 	int retval;
72613a9930dSWolfram Sang 	unsigned char *read_buf;
727eeed92c0SMarkus Elfring 
72813a9930dSWolfram Sang 	read_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL);
729cdf6ecc5SWolfram Sang 	if (!read_buf) {
730cdf6ecc5SWolfram Sang 		rc = 1;
731cdf6ecc5SWolfram Sang 		goto error_out;
732cdf6ecc5SWolfram Sang 	}
73313a9930dSWolfram Sang 	retval = ks7010_sdio_read(priv, address, read_buf, size);
734cdf6ecc5SWolfram Sang 	if (retval) {
735cdf6ecc5SWolfram Sang 		rc = 2;
736cdf6ecc5SWolfram Sang 		goto error_out;
737cdf6ecc5SWolfram Sang 	}
73813a9930dSWolfram Sang 	retval = memcmp(data, read_buf, size);
73913a9930dSWolfram Sang 
74013a9930dSWolfram Sang 	if (retval) {
741cdf6ecc5SWolfram Sang 		DPRINTK(0, "data compare error (%d)\n", retval);
742cdf6ecc5SWolfram Sang 		rc = 3;
743cdf6ecc5SWolfram Sang 		goto error_out;
74413a9930dSWolfram Sang 	}
74513a9930dSWolfram Sang  error_out:
746cdf6ecc5SWolfram Sang 	kfree(read_buf);
74713a9930dSWolfram Sang 	return rc;
74813a9930dSWolfram Sang }
749cdf6ecc5SWolfram Sang 
750c4730a92SWolfram Sang static int ks7010_upload_firmware(struct ks_wlan_private *priv,
751cdf6ecc5SWolfram Sang 				  struct ks_sdio_card *card)
75213a9930dSWolfram Sang {
75313a9930dSWolfram Sang 	unsigned int size, offset, n = 0;
75413a9930dSWolfram Sang 	unsigned char *rom_buf;
75513a9930dSWolfram Sang 	unsigned char rw_data = 0;
75613a9930dSWolfram Sang 	int retval, rc = 0;
75713a9930dSWolfram Sang 	int length;
75813a9930dSWolfram Sang 	const struct firmware *fw_entry = NULL;
75913a9930dSWolfram Sang 
76013a9930dSWolfram Sang 	/* buffer allocate */
76113a9930dSWolfram Sang 	rom_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL);
762369e1b69SSudip Mukherjee 	if (!rom_buf)
763369e1b69SSudip Mukherjee 		return 3;
76413a9930dSWolfram Sang 
76513a9930dSWolfram Sang 	sdio_claim_host(card->func);
76613a9930dSWolfram Sang 
76713a9930dSWolfram Sang 	/* Firmware running ? */
76813a9930dSWolfram Sang 	retval = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data));
76913a9930dSWolfram Sang 	if (rw_data == GCR_A_RUN) {
77013a9930dSWolfram Sang 		DPRINTK(0, "MAC firmware running ...\n");
77113a9930dSWolfram Sang 		rc = 0;
77213a9930dSWolfram Sang 		goto error_out0;
77313a9930dSWolfram Sang 	}
77413a9930dSWolfram Sang 
7756ee9169bSWolfram Sang 	retval = request_firmware(&fw_entry, ROM_FILE, &priv->ks_wlan_hw.sdio_card->func->dev);
7766ee9169bSWolfram Sang 	if (retval)
777b80cfea2SSudip Mukherjee 		goto error_out0;
7786ee9169bSWolfram Sang 
77913a9930dSWolfram Sang 	length = fw_entry->size;
78013a9930dSWolfram Sang 
78113a9930dSWolfram Sang 	/* Load Program */
78213a9930dSWolfram Sang 	n = 0;
78313a9930dSWolfram Sang 	do {
78413a9930dSWolfram Sang 		if (length >= ROM_BUFF_SIZE) {
78513a9930dSWolfram Sang 			size = ROM_BUFF_SIZE;
78613a9930dSWolfram Sang 			length = length - ROM_BUFF_SIZE;
787cdf6ecc5SWolfram Sang 		} else {
78813a9930dSWolfram Sang 			size = length;
78913a9930dSWolfram Sang 			length = 0;
79013a9930dSWolfram Sang 		}
79113a9930dSWolfram Sang 		DPRINTK(4, "size = %d\n", size);
792cdf6ecc5SWolfram Sang 		if (size == 0)
793cdf6ecc5SWolfram Sang 			break;
79413a9930dSWolfram Sang 		memcpy(rom_buf, fw_entry->data + n, size);
79513a9930dSWolfram Sang 		/* Update write index */
79613a9930dSWolfram Sang 		offset = n;
797cdf6ecc5SWolfram Sang 		retval =
798cdf6ecc5SWolfram Sang 		    ks7010_sdio_update_index(priv,
799cdf6ecc5SWolfram Sang 					     KS7010_IRAM_ADDRESS + offset);
800cdf6ecc5SWolfram Sang 		if (retval) {
801cdf6ecc5SWolfram Sang 			rc = 6;
802cdf6ecc5SWolfram Sang 			goto error_out1;
803cdf6ecc5SWolfram Sang 		}
80413a9930dSWolfram Sang 
80513a9930dSWolfram Sang 		/* Write data */
80613a9930dSWolfram Sang 		retval = ks7010_sdio_write(priv, DATA_WINDOW, rom_buf, size);
807cdf6ecc5SWolfram Sang 		if (retval) {
808cdf6ecc5SWolfram Sang 			rc = 8;
809cdf6ecc5SWolfram Sang 			goto error_out1;
810cdf6ecc5SWolfram Sang 		}
81113a9930dSWolfram Sang 
81213a9930dSWolfram Sang 		/* compare */
813cdf6ecc5SWolfram Sang 		retval =
814cdf6ecc5SWolfram Sang 		    ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size);
815cdf6ecc5SWolfram Sang 		if (retval) {
816cdf6ecc5SWolfram Sang 			rc = 9;
817cdf6ecc5SWolfram Sang 			goto error_out1;
818cdf6ecc5SWolfram Sang 		}
81913a9930dSWolfram Sang 		n += size;
82013a9930dSWolfram Sang 
82113a9930dSWolfram Sang 	} while (size);
82213a9930dSWolfram Sang 
82313a9930dSWolfram Sang 	/* Remap request */
82413a9930dSWolfram Sang 	rw_data = GCR_A_REMAP;
82513a9930dSWolfram Sang 	retval = ks7010_sdio_write(priv, GCR_A, &rw_data, sizeof(rw_data));
82613a9930dSWolfram Sang 	if (retval) {
82713a9930dSWolfram Sang 		rc = 11;
82813a9930dSWolfram Sang 		goto error_out1;
82913a9930dSWolfram Sang 	}
83013a9930dSWolfram Sang 	DPRINTK(4, " REMAP Request : GCR_A=%02X\n", rw_data);
83113a9930dSWolfram Sang 
83213a9930dSWolfram Sang 	/* Firmware running check */
83313a9930dSWolfram Sang 	for (n = 0; n < 50; ++n) {
83413a9930dSWolfram Sang 		mdelay(10);	/* wait_ms(10); */
835cdf6ecc5SWolfram Sang 		retval =
836cdf6ecc5SWolfram Sang 		    ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data));
837cdf6ecc5SWolfram Sang 		if (retval) {
838cdf6ecc5SWolfram Sang 			rc = 11;
839cdf6ecc5SWolfram Sang 			goto error_out1;
840cdf6ecc5SWolfram Sang 		}
841cdf6ecc5SWolfram Sang 		if (rw_data == GCR_A_RUN)
842cdf6ecc5SWolfram Sang 			break;
84313a9930dSWolfram Sang 	}
84413a9930dSWolfram Sang 	DPRINTK(4, "firmware wakeup (%d)!!!!\n", n);
84513a9930dSWolfram Sang 	if ((50) <= n) {
84613a9930dSWolfram Sang 		DPRINTK(1, "firmware can't start\n");
84713a9930dSWolfram Sang 		rc = 12;
84813a9930dSWolfram Sang 		goto error_out1;
84913a9930dSWolfram Sang 	}
85013a9930dSWolfram Sang 
85113a9930dSWolfram Sang 	rc = 0;
85213a9930dSWolfram Sang 
85313a9930dSWolfram Sang  error_out1:
85413a9930dSWolfram Sang 	release_firmware(fw_entry);
85513a9930dSWolfram Sang  error_out0:
85613a9930dSWolfram Sang 	sdio_release_host(card->func);
85713a9930dSWolfram Sang 	kfree(rom_buf);
85813a9930dSWolfram Sang 	return rc;
85913a9930dSWolfram Sang }
86013a9930dSWolfram Sang 
861e8593a8aSWolfram Sang static void ks7010_card_init(struct ks_wlan_private *priv)
86213a9930dSWolfram Sang {
86313a9930dSWolfram Sang 	DPRINTK(5, "\ncard_init_task()\n");
86413a9930dSWolfram Sang 
86513a9930dSWolfram Sang 	/* init_waitqueue_head(&priv->confirm_wait); */
86613a9930dSWolfram Sang 	init_completion(&priv->confirm_wait);
86713a9930dSWolfram Sang 
86813a9930dSWolfram Sang 	DPRINTK(5, "init_completion()\n");
86913a9930dSWolfram Sang 
87013a9930dSWolfram Sang 	/* get mac address & firmware version */
87113a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_START);
87213a9930dSWolfram Sang 
87313a9930dSWolfram Sang 	DPRINTK(5, "hostif_sme_enqueu()\n");
87413a9930dSWolfram Sang 
875cdf6ecc5SWolfram Sang 	if (!wait_for_completion_interruptible_timeout
876cdf6ecc5SWolfram Sang 	    (&priv->confirm_wait, 5 * HZ)) {
87713a9930dSWolfram Sang 		DPRINTK(1, "wait time out!! SME_START\n");
87813a9930dSWolfram Sang 	}
87913a9930dSWolfram Sang 
88053638cefSsayli karnik 	if (priv->mac_address_valid && priv->version_size)
88113a9930dSWolfram Sang 		priv->dev_state = DEVICE_STATE_PREINIT;
88253638cefSsayli karnik 
88313a9930dSWolfram Sang 
88413a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_GET_EEPROM_CKSUM);
88513a9930dSWolfram Sang 
88613a9930dSWolfram Sang 	/* load initial wireless parameter */
88713a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_STOP_REQUEST);
88813a9930dSWolfram Sang 
88913a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST);
89013a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST);
89113a9930dSWolfram Sang 
89213a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST);
89313a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST);
89413a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST);
89513a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST);
89613a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST);
89713a9930dSWolfram Sang 
89813a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST);
89913a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST);
90013a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST);
90113a9930dSWolfram Sang 	hostif_sme_enqueue(priv, SME_START_REQUEST);
90213a9930dSWolfram Sang 
903cdf6ecc5SWolfram Sang 	if (!wait_for_completion_interruptible_timeout
904cdf6ecc5SWolfram Sang 	    (&priv->confirm_wait, 5 * HZ)) {
90513a9930dSWolfram Sang 		DPRINTK(1, "wait time out!! wireless parameter set\n");
90613a9930dSWolfram Sang 	}
90713a9930dSWolfram Sang 
90813a9930dSWolfram Sang 	if (priv->dev_state >= DEVICE_STATE_PREINIT) {
90913a9930dSWolfram Sang 		DPRINTK(1, "DEVICE READY!!\n");
91013a9930dSWolfram Sang 		priv->dev_state = DEVICE_STATE_READY;
911cdf6ecc5SWolfram Sang 	} else {
91213a9930dSWolfram Sang 		DPRINTK(1, "dev_state=%d\n", priv->dev_state);
91313a9930dSWolfram Sang 	}
91413a9930dSWolfram Sang }
91513a9930dSWolfram Sang 
9166ee9169bSWolfram Sang static void ks7010_init_defaults(struct ks_wlan_private *priv)
9176ee9169bSWolfram Sang {
9186ee9169bSWolfram Sang 	priv->reg.tx_rate = TX_RATE_AUTO;
9196ee9169bSWolfram Sang 	priv->reg.preamble = LONG_PREAMBLE;
9206ee9169bSWolfram Sang 	priv->reg.powermgt = POWMGT_ACTIVE_MODE;
9216ee9169bSWolfram Sang 	priv->reg.scan_type = ACTIVE_SCAN;
9226ee9169bSWolfram Sang 	priv->reg.beacon_lost_count = 20;
9236ee9169bSWolfram Sang 	priv->reg.rts = 2347UL;
9246ee9169bSWolfram Sang 	priv->reg.fragment = 2346UL;
9256ee9169bSWolfram Sang 	priv->reg.phy_type = D_11BG_COMPATIBLE_MODE;
9266ee9169bSWolfram Sang 	priv->reg.cts_mode = CTS_MODE_FALSE;
9276ee9169bSWolfram Sang 	priv->reg.rate_set.body[11] = TX_RATE_54M;
9286ee9169bSWolfram Sang 	priv->reg.rate_set.body[10] = TX_RATE_48M;
9296ee9169bSWolfram Sang 	priv->reg.rate_set.body[9] = TX_RATE_36M;
9306ee9169bSWolfram Sang 	priv->reg.rate_set.body[8] = TX_RATE_18M;
9316ee9169bSWolfram Sang 	priv->reg.rate_set.body[7] = TX_RATE_9M;
9326ee9169bSWolfram Sang 	priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE;
9336ee9169bSWolfram Sang 	priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE;
9346ee9169bSWolfram Sang 	priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE;
9356ee9169bSWolfram Sang 	priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE;
9366ee9169bSWolfram Sang 	priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE;
9376ee9169bSWolfram Sang 	priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE;
9386ee9169bSWolfram Sang 	priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE;
9396ee9169bSWolfram Sang 	priv->reg.tx_rate = TX_RATE_FULL_AUTO;
9406ee9169bSWolfram Sang 	priv->reg.rate_set.size = 12;
9416ee9169bSWolfram Sang }
9426ee9169bSWolfram Sang 
943c4730a92SWolfram Sang static int ks7010_sdio_probe(struct sdio_func *func,
944cdf6ecc5SWolfram Sang 			     const struct sdio_device_id *device)
94513a9930dSWolfram Sang {
946feedcf1aSWolfram Sang 	struct ks_wlan_private *priv;
94713a9930dSWolfram Sang 	struct ks_sdio_card *card;
94813a9930dSWolfram Sang 	struct net_device *netdev;
94913a9930dSWolfram Sang 	unsigned char rw_data;
9502801d7a2SWolfram Sang 	int ret;
95113a9930dSWolfram Sang 
952c4730a92SWolfram Sang 	DPRINTK(5, "ks7010_sdio_probe()\n");
95313a9930dSWolfram Sang 
95413a9930dSWolfram Sang 	priv = NULL;
95513a9930dSWolfram Sang 	netdev = NULL;
95613a9930dSWolfram Sang 
95713a9930dSWolfram Sang 	/* initilize ks_sdio_card */
95813a9930dSWolfram Sang 	card = kzalloc(sizeof(struct ks_sdio_card), GFP_KERNEL);
95913a9930dSWolfram Sang 	if (!card)
96013a9930dSWolfram Sang 		return -ENOMEM;
96113a9930dSWolfram Sang 
96213a9930dSWolfram Sang 	card->func = func;
96313a9930dSWolfram Sang 	spin_lock_init(&card->lock);
96413a9930dSWolfram Sang 
96513a9930dSWolfram Sang 	/*** Initialize  SDIO ***/
96613a9930dSWolfram Sang 	sdio_claim_host(func);
96713a9930dSWolfram Sang 
96813a9930dSWolfram Sang 	/* bus setting  */
96913a9930dSWolfram Sang 	/* Issue config request to override clock rate */
97013a9930dSWolfram Sang 
97113a9930dSWolfram Sang 	/* function blocksize set */
97213a9930dSWolfram Sang 	ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE);
973cdf6ecc5SWolfram Sang 	DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n",
974cdf6ecc5SWolfram Sang 		func->card->cccr.multi_block, func->cur_blksize, ret);
97513a9930dSWolfram Sang 
97613a9930dSWolfram Sang 	/* Allocate the slot current */
97713a9930dSWolfram Sang 
97813a9930dSWolfram Sang 	/* function enable */
97913a9930dSWolfram Sang 	ret = sdio_enable_func(func);
98013a9930dSWolfram Sang 	DPRINTK(5, "sdio_enable_func() %d\n", ret);
98113a9930dSWolfram Sang 	if (ret)
98213a9930dSWolfram Sang 		goto error_free_card;
98313a9930dSWolfram Sang 
98413a9930dSWolfram Sang 	/* interrupt disable */
98513a9930dSWolfram Sang 	sdio_writeb(func, 0, INT_ENABLE, &ret);
98613a9930dSWolfram Sang 	if (ret)
98713a9930dSWolfram Sang 		goto error_free_card;
98813a9930dSWolfram Sang 	sdio_writeb(func, 0xff, INT_PENDING, &ret);
98913a9930dSWolfram Sang 	if (ret)
99013a9930dSWolfram Sang 		goto error_disable_func;
99113a9930dSWolfram Sang 
99213a9930dSWolfram Sang 	/* setup interrupt handler */
99313a9930dSWolfram Sang 	ret = sdio_claim_irq(func, ks_sdio_interrupt);
99413a9930dSWolfram Sang 	if (ret)
99513a9930dSWolfram Sang 		goto error_disable_func;
99613a9930dSWolfram Sang 
99713a9930dSWolfram Sang 	sdio_release_host(func);
99813a9930dSWolfram Sang 
99913a9930dSWolfram Sang 	sdio_set_drvdata(func, card);
100013a9930dSWolfram Sang 
100113a9930dSWolfram Sang 	DPRINTK(5, "class = 0x%X, vendor = 0x%X, "
1002cdf6ecc5SWolfram Sang 		"device = 0x%X\n", func->class, func->vendor, func->device);
100313a9930dSWolfram Sang 
100413a9930dSWolfram Sang 	/* private memory allocate */
100513a9930dSWolfram Sang 	netdev = alloc_etherdev(sizeof(*priv));
1006c7e65f4dSsayli karnik 	if (!netdev) {
1007c4730a92SWolfram Sang 		printk(KERN_ERR "ks7010 : Unable to alloc new net device\n");
100813a9930dSWolfram Sang 		goto error_release_irq;
100913a9930dSWolfram Sang 	}
10106634cff1SWolfram Sang 	if (dev_alloc_name(netdev, "wlan%d") < 0) {
1011c4730a92SWolfram Sang 		printk(KERN_ERR "ks7010 :  Couldn't get name!\n");
101213a9930dSWolfram Sang 		goto error_free_netdev;
101313a9930dSWolfram Sang 	}
101413a9930dSWolfram Sang 
101513a9930dSWolfram Sang 	priv = netdev_priv(netdev);
101613a9930dSWolfram Sang 
101713a9930dSWolfram Sang 	card->priv = priv;
101813a9930dSWolfram Sang 	SET_NETDEV_DEV(netdev, &card->func->dev);	/* for create sysfs symlinks */
101913a9930dSWolfram Sang 
102013a9930dSWolfram Sang 	/* private memory initialize */
102113a9930dSWolfram Sang 	priv->ks_wlan_hw.sdio_card = card;
102213a9930dSWolfram Sang 	init_completion(&priv->ks_wlan_hw.ks7010_sdio_wait);
102313a9930dSWolfram Sang 	priv->ks_wlan_hw.read_buf = NULL;
102413a9930dSWolfram Sang 	priv->ks_wlan_hw.read_buf = kmalloc(RX_DATA_SIZE, GFP_KERNEL);
102553638cefSsayli karnik 	if (!priv->ks_wlan_hw.read_buf)
102613a9930dSWolfram Sang 		goto error_free_netdev;
102753638cefSsayli karnik 
102813a9930dSWolfram Sang 	priv->dev_state = DEVICE_STATE_PREBOOT;
102913a9930dSWolfram Sang 	priv->net_dev = netdev;
103013a9930dSWolfram Sang 	priv->firmware_version[0] = '\0';
103113a9930dSWolfram Sang 	priv->version_size = 0;
103213a9930dSWolfram Sang 	priv->last_doze = jiffies;	/* set current jiffies */
103313a9930dSWolfram Sang 	priv->last_wakeup = jiffies;
103413a9930dSWolfram Sang 	memset(&priv->nstats, 0, sizeof(priv->nstats));
103513a9930dSWolfram Sang 	memset(&priv->wstats, 0, sizeof(priv->wstats));
103613a9930dSWolfram Sang 
103713a9930dSWolfram Sang 	/* sleep mode */
103813a9930dSWolfram Sang 	atomic_set(&priv->sleepstatus.doze_request, 0);
103913a9930dSWolfram Sang 	atomic_set(&priv->sleepstatus.wakeup_request, 0);
104013a9930dSWolfram Sang 	atomic_set(&priv->sleepstatus.wakeup_request, 0);
104113a9930dSWolfram Sang 
104213a9930dSWolfram Sang 	trx_device_init(priv);
104313a9930dSWolfram Sang 	hostif_init(priv);
104413a9930dSWolfram Sang 	ks_wlan_net_start(netdev);
104513a9930dSWolfram Sang 
10466ee9169bSWolfram Sang 	ks7010_init_defaults(priv);
104713a9930dSWolfram Sang 
104813a9930dSWolfram Sang 	/* Upload firmware */
1049c4730a92SWolfram Sang 	ret = ks7010_upload_firmware(priv, card);	/* firmware load */
105013a9930dSWolfram Sang 	if (ret) {
1051cdf6ecc5SWolfram Sang 		printk(KERN_ERR
1052c4730a92SWolfram Sang 		       "ks7010: firmware load failed !! retern code = %d\n",
1053cdf6ecc5SWolfram Sang 		       ret);
105413a9930dSWolfram Sang 		goto error_free_read_buf;
105513a9930dSWolfram Sang 	}
105613a9930dSWolfram Sang 
105713a9930dSWolfram Sang 	/* interrupt setting */
105813a9930dSWolfram Sang 	/* clear Interrupt status write (ARMtoSD_InterruptPending FN1:00_0024) */
105913a9930dSWolfram Sang 	rw_data = 0xff;
106013a9930dSWolfram Sang 	sdio_claim_host(func);
106113a9930dSWolfram Sang 	ret = ks7010_sdio_write(priv, INT_PENDING, &rw_data, sizeof(rw_data));
106213a9930dSWolfram Sang 	sdio_release_host(func);
106353638cefSsayli karnik 	if (ret)
106413a9930dSWolfram Sang 		DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data);
106553638cefSsayli karnik 
106613a9930dSWolfram Sang 	DPRINTK(4, " clear Interrupt : INT_PENDING=%02X\n", rw_data);
106713a9930dSWolfram Sang 
106813a9930dSWolfram Sang 	/* enable ks7010sdio interrupt (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS) */
106913a9930dSWolfram Sang 	rw_data = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS);
107013a9930dSWolfram Sang 	sdio_claim_host(func);
107113a9930dSWolfram Sang 	ret = ks7010_sdio_write(priv, INT_ENABLE, &rw_data, sizeof(rw_data));
107213a9930dSWolfram Sang 	sdio_release_host(func);
107353638cefSsayli karnik 	if (ret)
107413a9930dSWolfram Sang 		DPRINTK(1, " error : INT_ENABLE=%02X\n", rw_data);
107553638cefSsayli karnik 
107613a9930dSWolfram Sang 	DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", rw_data);
107713a9930dSWolfram Sang 	priv->dev_state = DEVICE_STATE_BOOT;
107813a9930dSWolfram Sang 
107913a9930dSWolfram Sang 	priv->ks_wlan_hw.ks7010sdio_wq = create_workqueue("ks7010sdio_wq");
108013a9930dSWolfram Sang 	if (!priv->ks_wlan_hw.ks7010sdio_wq) {
108113a9930dSWolfram Sang 		DPRINTK(1, "create_workqueue failed !!\n");
108213a9930dSWolfram Sang 		goto error_free_read_buf;
108313a9930dSWolfram Sang 	}
108413a9930dSWolfram Sang 
108513a9930dSWolfram Sang 	INIT_DELAYED_WORK(&priv->ks_wlan_hw.rw_wq, ks7010_rw_function);
1086e8593a8aSWolfram Sang 	ks7010_card_init(priv);
108713a9930dSWolfram Sang 
10883fb54d75SWolfram Sang 	ret = register_netdev(priv->net_dev);
10893fb54d75SWolfram Sang 	if (ret)
10903fb54d75SWolfram Sang 		goto error_free_read_buf;
10913fb54d75SWolfram Sang 
109213a9930dSWolfram Sang 	return 0;
109313a9930dSWolfram Sang 
109413a9930dSWolfram Sang  error_free_read_buf:
109513a9930dSWolfram Sang 	kfree(priv->ks_wlan_hw.read_buf);
109613a9930dSWolfram Sang 	priv->ks_wlan_hw.read_buf = NULL;
109713a9930dSWolfram Sang  error_free_netdev:
109813a9930dSWolfram Sang 	free_netdev(priv->net_dev);
109913a9930dSWolfram Sang 	card->priv = NULL;
110013a9930dSWolfram Sang  error_release_irq:
110113a9930dSWolfram Sang 	sdio_claim_host(func);
110213a9930dSWolfram Sang 	sdio_release_irq(func);
110313a9930dSWolfram Sang  error_disable_func:
110413a9930dSWolfram Sang 	sdio_disable_func(func);
110513a9930dSWolfram Sang  error_free_card:
110613a9930dSWolfram Sang 	sdio_release_host(func);
110713a9930dSWolfram Sang 	sdio_set_drvdata(func, NULL);
110813a9930dSWolfram Sang 	kfree(card);
11092801d7a2SWolfram Sang 
111013a9930dSWolfram Sang 	return -ENODEV;
111113a9930dSWolfram Sang }
111213a9930dSWolfram Sang 
1113c4730a92SWolfram Sang static void ks7010_sdio_remove(struct sdio_func *func)
111413a9930dSWolfram Sang {
111513a9930dSWolfram Sang 	int ret;
111613a9930dSWolfram Sang 	struct ks_sdio_card *card;
111713a9930dSWolfram Sang 	struct ks_wlan_private *priv;
1118c4730a92SWolfram Sang 	DPRINTK(1, "ks7010_sdio_remove()\n");
111913a9930dSWolfram Sang 
112013a9930dSWolfram Sang 	card = sdio_get_drvdata(func);
112113a9930dSWolfram Sang 
1122c7e65f4dSsayli karnik 	if (!card)
112313a9930dSWolfram Sang 		return;
112413a9930dSWolfram Sang 
112513a9930dSWolfram Sang 	DPRINTK(1, "priv = card->priv\n");
112613a9930dSWolfram Sang 	priv = card->priv;
112713a9930dSWolfram Sang 	if (priv) {
1128803394d0SColin Ian King 		struct net_device *netdev = priv->net_dev;
1129803394d0SColin Ian King 
113013a9930dSWolfram Sang 		ks_wlan_net_stop(netdev);
113113a9930dSWolfram Sang 		DPRINTK(1, "ks_wlan_net_stop\n");
113213a9930dSWolfram Sang 
113313a9930dSWolfram Sang 		/* interrupt disable */
113413a9930dSWolfram Sang 		sdio_claim_host(func);
113513a9930dSWolfram Sang 		sdio_writeb(func, 0, INT_ENABLE, &ret);
113613a9930dSWolfram Sang 		sdio_writeb(func, 0xff, INT_PENDING, &ret);
113713a9930dSWolfram Sang 		sdio_release_host(func);
113813a9930dSWolfram Sang 		DPRINTK(1, "interrupt disable\n");
113913a9930dSWolfram Sang 
114013a9930dSWolfram Sang 		/* send stop request to MAC */
114113a9930dSWolfram Sang 		{
114213a9930dSWolfram Sang 			struct hostif_stop_request_t *pp;
1143cbb351ccSSandhya Bankar 			pp = kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL);
1144c7e65f4dSsayli karnik 			if (!pp) {
114513a9930dSWolfram Sang 				DPRINTK(3, "allocate memory failed..\n");
114613a9930dSWolfram Sang 				return;	/* to do goto ni suru */
114713a9930dSWolfram Sang 			}
1148cdf6ecc5SWolfram Sang 			pp->header.size =
1149cdf6ecc5SWolfram Sang 			    cpu_to_le16((uint16_t)
1150cdf6ecc5SWolfram Sang 					(sizeof(*pp) -
1151cdf6ecc5SWolfram Sang 					 sizeof(pp->header.size)));
115213a9930dSWolfram Sang 			pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ);
115313a9930dSWolfram Sang 
115413a9930dSWolfram Sang 			sdio_claim_host(func);
1155cdf6ecc5SWolfram Sang 			write_to_device(priv, (unsigned char *)pp,
1156cdf6ecc5SWolfram Sang 					hif_align_size(sizeof(*pp)));
115713a9930dSWolfram Sang 			sdio_release_host(func);
115813a9930dSWolfram Sang 			kfree(pp);
115913a9930dSWolfram Sang 		}
116013a9930dSWolfram Sang 		DPRINTK(1, "STOP Req\n");
116113a9930dSWolfram Sang 
116213a9930dSWolfram Sang 		if (priv->ks_wlan_hw.ks7010sdio_wq) {
116313a9930dSWolfram Sang 			flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);
116413a9930dSWolfram Sang 			destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);
116513a9930dSWolfram Sang 		}
1166cdf6ecc5SWolfram Sang 		DPRINTK(1,
1167cdf6ecc5SWolfram Sang 			"destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n");
116813a9930dSWolfram Sang 
116913a9930dSWolfram Sang 		hostif_exit(priv);
117013a9930dSWolfram Sang 		DPRINTK(1, "hostif_exit\n");
117113a9930dSWolfram Sang 
117213a9930dSWolfram Sang 		unregister_netdev(netdev);
117313a9930dSWolfram Sang 
117413a9930dSWolfram Sang 		trx_device_exit(priv);
117513a9930dSWolfram Sang 		kfree(priv->ks_wlan_hw.read_buf);
117613a9930dSWolfram Sang 		free_netdev(priv->net_dev);
117713a9930dSWolfram Sang 		card->priv = NULL;
117813a9930dSWolfram Sang 	}
117913a9930dSWolfram Sang 
118013a9930dSWolfram Sang 	sdio_claim_host(func);
118113a9930dSWolfram Sang 	sdio_release_irq(func);
118213a9930dSWolfram Sang 	DPRINTK(1, "sdio_release_irq()\n");
118313a9930dSWolfram Sang 	sdio_disable_func(func);
118413a9930dSWolfram Sang 	DPRINTK(1, "sdio_disable_func()\n");
118513a9930dSWolfram Sang 	sdio_release_host(func);
118613a9930dSWolfram Sang 
118713a9930dSWolfram Sang 	sdio_set_drvdata(func, NULL);
118813a9930dSWolfram Sang 
118913a9930dSWolfram Sang 	kfree(card);
119013a9930dSWolfram Sang 	DPRINTK(1, "kfree()\n");
119113a9930dSWolfram Sang 
119213a9930dSWolfram Sang 	DPRINTK(5, " Bye !!\n");
119313a9930dSWolfram Sang }
119413a9930dSWolfram Sang 
11954c0d46d2SWolfram Sang static struct sdio_driver ks7010_sdio_driver = {
11964c0d46d2SWolfram Sang 	.name = "ks7010_sdio",
11974c0d46d2SWolfram Sang 	.id_table = ks7010_sdio_ids,
11984c0d46d2SWolfram Sang 	.probe = ks7010_sdio_probe,
11994c0d46d2SWolfram Sang 	.remove = ks7010_sdio_remove,
12004c0d46d2SWolfram Sang };
12014c0d46d2SWolfram Sang 
12026b0cb0b0SWolfram Sang module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver);
1203e1240140SWolfram Sang MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream");
1204e1240140SWolfram Sang MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards");
1205e1240140SWolfram Sang MODULE_LICENSE("GPL v2");
1206e1240140SWolfram Sang MODULE_FIRMWARE(ROM_FILE);
1207