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