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; 551770ae9dSTobin C. Harding int ret; 564c0d46d2SWolfram Sang 574c0d46d2SWolfram Sang card = priv->ks_wlan_hw.sdio_card; 584c0d46d2SWolfram Sang 594c0d46d2SWolfram Sang if (length == 1) /* CMD52 */ 601770ae9dSTobin C. Harding *buffer = sdio_readb(card->func, address, &ret); 614c0d46d2SWolfram Sang else /* CMD53 multi-block transfer */ 621770ae9dSTobin C. Harding ret = sdio_memcpy_fromio(card->func, buffer, address, length); 634c0d46d2SWolfram Sang 641770ae9dSTobin C. Harding if (ret) { 651770ae9dSTobin C. Harding DPRINTK(1, "sdio error=%d size=%d\n", ret, length); 661770ae9dSTobin C. Harding return ret; 671770ae9dSTobin C. Harding } 684c0d46d2SWolfram Sang 691770ae9dSTobin C. Harding return 0; 704c0d46d2SWolfram Sang } 714c0d46d2SWolfram Sang 724c0d46d2SWolfram Sang static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, 734c0d46d2SWolfram Sang unsigned char *buffer, int length) 744c0d46d2SWolfram Sang { 754c0d46d2SWolfram Sang struct ks_sdio_card *card; 761770ae9dSTobin C. Harding int ret; 774c0d46d2SWolfram Sang 784c0d46d2SWolfram Sang card = priv->ks_wlan_hw.sdio_card; 794c0d46d2SWolfram Sang 804c0d46d2SWolfram Sang if (length == 1) /* CMD52 */ 811770ae9dSTobin C. Harding sdio_writeb(card->func, *buffer, address, &ret); 824c0d46d2SWolfram Sang else /* CMD53 */ 831770ae9dSTobin C. Harding ret = sdio_memcpy_toio(card->func, address, buffer, length); 844c0d46d2SWolfram Sang 851770ae9dSTobin C. Harding if (ret) { 861770ae9dSTobin C. Harding DPRINTK(1, "sdio error=%d size=%d\n", ret, length); 871770ae9dSTobin C. Harding return ret; 881770ae9dSTobin C. Harding } 894c0d46d2SWolfram Sang 901770ae9dSTobin C. Harding return 0; 914c0d46d2SWolfram Sang } 924c0d46d2SWolfram Sang 934433459aSSergio Paracuellos static void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv) 9413a9930dSWolfram Sang { 9513a9930dSWolfram Sang unsigned char rw_data; 961770ae9dSTobin C. Harding int ret; 9713a9930dSWolfram Sang 9813a9930dSWolfram Sang DPRINTK(4, "\n"); 9913a9930dSWolfram Sang 10013a9930dSWolfram Sang /* clear request */ 10113a9930dSWolfram Sang atomic_set(&priv->sleepstatus.doze_request, 0); 10213a9930dSWolfram Sang 10313a9930dSWolfram Sang if (atomic_read(&priv->sleepstatus.status) == 0) { 10413a9930dSWolfram Sang rw_data = GCR_B_DOZE; 1051770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); 1061770ae9dSTobin C. Harding if (ret) { 10713a9930dSWolfram Sang DPRINTK(1, " error : GCR_B=%02X\n", rw_data); 108f283dd69STobin C. Harding goto set_sleep_mode; 10913a9930dSWolfram Sang } 11013a9930dSWolfram Sang DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); 11113a9930dSWolfram Sang DPRINTK(3, "sleep_mode=SLP_SLEEP\n"); 11213a9930dSWolfram Sang atomic_set(&priv->sleepstatus.status, 1); 11313a9930dSWolfram Sang priv->last_doze = jiffies; 114cdf6ecc5SWolfram Sang } else { 11513a9930dSWolfram Sang DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); 11613a9930dSWolfram Sang } 11713a9930dSWolfram Sang 118f283dd69STobin C. Harding set_sleep_mode: 11913a9930dSWolfram Sang priv->sleep_mode = atomic_read(&priv->sleepstatus.status); 12013a9930dSWolfram Sang } 12113a9930dSWolfram Sang 1224433459aSSergio Paracuellos static void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv) 12313a9930dSWolfram Sang { 12413a9930dSWolfram Sang unsigned char rw_data; 1251770ae9dSTobin C. Harding int ret; 12613a9930dSWolfram Sang 12713a9930dSWolfram Sang DPRINTK(4, "\n"); 12813a9930dSWolfram Sang 12913a9930dSWolfram Sang /* clear request */ 13013a9930dSWolfram Sang atomic_set(&priv->sleepstatus.wakeup_request, 0); 13113a9930dSWolfram Sang 13213a9930dSWolfram Sang if (atomic_read(&priv->sleepstatus.status) == 1) { 13313a9930dSWolfram Sang rw_data = WAKEUP_REQ; 1341770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); 1351770ae9dSTobin C. Harding if (ret) { 13613a9930dSWolfram Sang DPRINTK(1, " error : WAKEUP=%02X\n", rw_data); 137f283dd69STobin C. Harding goto set_sleep_mode; 13813a9930dSWolfram Sang } 13913a9930dSWolfram Sang DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data); 14013a9930dSWolfram Sang atomic_set(&priv->sleepstatus.status, 0); 14113a9930dSWolfram Sang priv->last_wakeup = jiffies; 14213a9930dSWolfram Sang ++priv->wakeup_count; 143cdf6ecc5SWolfram Sang } else { 14413a9930dSWolfram Sang DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); 14513a9930dSWolfram Sang } 14613a9930dSWolfram Sang 147f283dd69STobin C. Harding set_sleep_mode: 14813a9930dSWolfram Sang priv->sleep_mode = atomic_read(&priv->sleepstatus.status); 14913a9930dSWolfram Sang } 15013a9930dSWolfram Sang 151feedcf1aSWolfram Sang void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv) 15213a9930dSWolfram Sang { 15313a9930dSWolfram Sang unsigned char rw_data; 1541770ae9dSTobin C. Harding int ret; 15513a9930dSWolfram Sang 15613a9930dSWolfram Sang DPRINTK(4, "\n"); 15713a9930dSWolfram Sang if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { 15813a9930dSWolfram Sang rw_data = WAKEUP_REQ; 1591770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); 1601770ae9dSTobin C. Harding if (ret) 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 1724433459aSSergio Paracuellos static int _ks_wlan_hw_power_save(struct ks_wlan_private *priv) 17313a9930dSWolfram Sang { 17413a9930dSWolfram Sang unsigned char rw_data; 175f7172487STobin C. Harding int ret; 17613a9930dSWolfram Sang 17713a9930dSWolfram Sang if (priv->reg.powermgt == POWMGT_ACTIVE_MODE) 1787d359a84Ssayli karnik return 0; 17913a9930dSWolfram Sang 180d5f1db31STobin C. Harding if (priv->reg.operation_mode != MODE_INFRASTRUCTURE || 181d5f1db31STobin C. Harding (priv->connect_status & CONNECT_STATUS_MASK) != CONNECT_STATUS) 182d5f1db31STobin C. Harding return 0; 183d5f1db31STobin C. Harding 184d5f1db31STobin C. Harding if (priv->dev_state != DEVICE_STATE_SLEEP) 185d5f1db31STobin C. Harding return 0; 186d5f1db31STobin C. Harding 1873188bc09STobin C. Harding if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) 1883188bc09STobin C. Harding return 0; 1893188bc09STobin C. Harding 190cdf6ecc5SWolfram Sang DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n", 19113a9930dSWolfram Sang atomic_read(&priv->psstatus.status), 19213a9930dSWolfram Sang atomic_read(&priv->psstatus.confirm_wait), 19313a9930dSWolfram Sang atomic_read(&priv->psstatus.snooze_guard), 19413a9930dSWolfram Sang cnt_txqbody(priv)); 19513a9930dSWolfram Sang 196cf57e659STobin C. Harding if (!atomic_read(&priv->psstatus.confirm_wait) && 197cf57e659STobin C. Harding !atomic_read(&priv->psstatus.snooze_guard) && 198cf57e659STobin C. Harding !cnt_txqbody(priv)) { 199f7172487STobin C. Harding ret = ks7010_sdio_read(priv, INT_PENDING, &rw_data, 200cdf6ecc5SWolfram Sang sizeof(rw_data)); 201f7172487STobin C. Harding if (ret) { 202dad5980eSTobin C. Harding DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); 203cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 204cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 2053188bc09STobin C. Harding return 0; 20613a9930dSWolfram Sang } 20713a9930dSWolfram Sang if (!rw_data) { 20813a9930dSWolfram Sang rw_data = GCR_B_DOZE; 209f7172487STobin C. Harding ret = ks7010_sdio_write(priv, GCR_B, &rw_data, 210cdf6ecc5SWolfram Sang sizeof(rw_data)); 211f7172487STobin C. Harding if (ret) { 212dad5980eSTobin C. Harding DPRINTK(1, " error : GCR_B=%02X\n", rw_data); 213dad5980eSTobin C. Harding queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 214cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 2153188bc09STobin C. Harding return 0; 21613a9930dSWolfram Sang } 217dad5980eSTobin C. Harding DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); 2189f9d7030STobin C. Harding atomic_set(&priv->psstatus.status, PS_SNOOZE); 219dad5980eSTobin C. Harding DPRINTK(3, "psstatus.status=PS_SNOOZE\n"); 220cdf6ecc5SWolfram Sang } else { 221cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 222cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 22313a9930dSWolfram Sang } 224cdf6ecc5SWolfram Sang } else { 2259f9d7030STobin C. Harding queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 226dad5980eSTobin C. Harding &priv->ks_wlan_hw.rw_wq, 0); 22713a9930dSWolfram Sang } 22813a9930dSWolfram Sang 2297d359a84Ssayli karnik return 0; 23013a9930dSWolfram Sang } 23113a9930dSWolfram Sang 232feedcf1aSWolfram Sang int ks_wlan_hw_power_save(struct ks_wlan_private *priv) 23313a9930dSWolfram Sang { 234cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 235cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 23613a9930dSWolfram Sang return 0; 23713a9930dSWolfram Sang } 23813a9930dSWolfram Sang 239cdf6ecc5SWolfram Sang static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, 240cdf6ecc5SWolfram Sang unsigned long size, 24113a9930dSWolfram Sang void (*complete_handler)(void *arg1, void *arg2), 24213a9930dSWolfram Sang void *arg1, void *arg2) 24313a9930dSWolfram Sang { 24413a9930dSWolfram Sang struct tx_device_buffer *sp; 2451770ae9dSTobin C. Harding int ret; 24613a9930dSWolfram Sang 24713a9930dSWolfram Sang if (priv->dev_state < DEVICE_STATE_BOOT) { 2481770ae9dSTobin C. Harding ret = -EPERM; 249aa6ca807STobin C. Harding goto err_complete; 25013a9930dSWolfram Sang } 25113a9930dSWolfram Sang 25213a9930dSWolfram Sang if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) { 25313a9930dSWolfram Sang /* in case of buffer overflow */ 25413a9930dSWolfram Sang DPRINTK(1, "tx buffer overflow\n"); 2551770ae9dSTobin C. Harding ret = -EOVERFLOW; 256aa6ca807STobin C. Harding goto err_complete; 25713a9930dSWolfram Sang } 25813a9930dSWolfram Sang 25913a9930dSWolfram Sang sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail]; 26013a9930dSWolfram Sang sp->sendp = p; 26113a9930dSWolfram Sang sp->size = size; 26213a9930dSWolfram Sang sp->complete_handler = complete_handler; 26313a9930dSWolfram Sang sp->arg1 = arg1; 26413a9930dSWolfram Sang sp->arg2 = arg2; 26513a9930dSWolfram Sang inc_txqtail(priv); 26613a9930dSWolfram Sang 26713a9930dSWolfram Sang return 0; 268aa6ca807STobin C. Harding 269aa6ca807STobin C. Harding err_complete: 270aa6ca807STobin C. Harding kfree(p); 271aa6ca807STobin C. Harding if (complete_handler) 272aa6ca807STobin C. Harding (*complete_handler) (arg1, arg2); 273aa6ca807STobin C. Harding 2741770ae9dSTobin C. Harding return ret; 27513a9930dSWolfram Sang } 27613a9930dSWolfram Sang 27713a9930dSWolfram Sang /* write data */ 278cdf6ecc5SWolfram Sang static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, 279cdf6ecc5SWolfram Sang unsigned long size) 28013a9930dSWolfram Sang { 28113a9930dSWolfram Sang unsigned char rw_data; 28213a9930dSWolfram Sang struct hostif_hdr *hdr; 2831770ae9dSTobin C. Harding int ret; 284697f9f7fSMuraru Mihaela 28513a9930dSWolfram Sang hdr = (struct hostif_hdr *)buffer; 28613a9930dSWolfram Sang 28713a9930dSWolfram Sang DPRINTK(4, "size=%d\n", hdr->size); 28813a9930dSWolfram Sang if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) { 28913a9930dSWolfram Sang DPRINTK(1, "unknown event=%04X\n", hdr->event); 29013a9930dSWolfram Sang return 0; 29113a9930dSWolfram Sang } 29213a9930dSWolfram Sang 2931770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size); 2941770ae9dSTobin C. Harding if (ret) { 2951770ae9dSTobin C. Harding DPRINTK(1, " write error : retval=%d\n", ret); 2961770ae9dSTobin C. Harding return ret; 29713a9930dSWolfram Sang } 29813a9930dSWolfram Sang 29913a9930dSWolfram Sang rw_data = WRITE_STATUS_BUSY; 3001770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data)); 3011770ae9dSTobin C. Harding if (ret) { 30213a9930dSWolfram Sang DPRINTK(1, " error : WRITE_STATUS=%02X\n", rw_data); 3031770ae9dSTobin C. Harding return ret; 30413a9930dSWolfram Sang } 30513a9930dSWolfram Sang 30613a9930dSWolfram Sang return 0; 30713a9930dSWolfram Sang } 30813a9930dSWolfram Sang 3095141e9c6STobin C. Harding static void tx_device_task(struct ks_wlan_private *priv) 31013a9930dSWolfram Sang { 31113a9930dSWolfram Sang struct tx_device_buffer *sp; 31203b02449STobin C. Harding int ret; 31313a9930dSWolfram Sang 31413a9930dSWolfram Sang DPRINTK(4, "\n"); 315638a75b6STobin C. Harding if (cnt_txqbody(priv) <= 0 || 316638a75b6STobin C. Harding atomic_read(&priv->psstatus.status) == PS_SNOOZE) 317638a75b6STobin C. Harding return; 318638a75b6STobin C. Harding 31913a9930dSWolfram Sang sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; 32013a9930dSWolfram Sang if (priv->dev_state >= DEVICE_STATE_BOOT) { 32103b02449STobin C. Harding ret = write_to_device(priv, sp->sendp, sp->size); 32203b02449STobin C. Harding if (ret) { 32303b02449STobin C. Harding DPRINTK(1, "write_to_device error !!(%d)\n", ret); 32403b02449STobin C. Harding queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 325cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 32613a9930dSWolfram Sang return; 32713a9930dSWolfram Sang } 32813a9930dSWolfram Sang } 329638a75b6STobin C. Harding kfree(sp->sendp); 330c7e65f4dSsayli karnik if (sp->complete_handler) /* TX Complete */ 33113a9930dSWolfram Sang (*sp->complete_handler) (sp->arg1, sp->arg2); 33213a9930dSWolfram Sang inc_txqhead(priv); 33313a9930dSWolfram Sang 33413a9930dSWolfram Sang if (cnt_txqbody(priv) > 0) { 335cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 336cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 0); 33713a9930dSWolfram Sang } 33813a9930dSWolfram Sang } 33913a9930dSWolfram Sang 340feedcf1aSWolfram Sang int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, 34113a9930dSWolfram Sang void (*complete_handler)(void *arg1, void *arg2), 34213a9930dSWolfram Sang void *arg1, void *arg2) 34313a9930dSWolfram Sang { 34413a9930dSWolfram Sang int result = 0; 34513a9930dSWolfram Sang struct hostif_hdr *hdr; 346697f9f7fSMuraru Mihaela 34713a9930dSWolfram Sang hdr = (struct hostif_hdr *)p; 34813a9930dSWolfram Sang 34913a9930dSWolfram Sang if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) { 35013a9930dSWolfram Sang DPRINTK(1, "unknown event=%04X\n", hdr->event); 35113a9930dSWolfram Sang return 0; 35213a9930dSWolfram Sang } 35313a9930dSWolfram Sang 35413a9930dSWolfram Sang /* add event to hostt buffer */ 35513a9930dSWolfram Sang priv->hostt.buff[priv->hostt.qtail] = hdr->event; 35613a9930dSWolfram Sang priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; 35713a9930dSWolfram Sang 35813a9930dSWolfram Sang DPRINTK(4, "event=%04X\n", hdr->event); 35913a9930dSWolfram Sang spin_lock(&priv->tx_dev.tx_dev_lock); 36013a9930dSWolfram Sang result = enqueue_txdev(priv, p, size, complete_handler, arg1, arg2); 36113a9930dSWolfram Sang spin_unlock(&priv->tx_dev.tx_dev_lock); 36213a9930dSWolfram Sang 36313a9930dSWolfram Sang if (cnt_txqbody(priv) > 0) { 364cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 365cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 0); 36613a9930dSWolfram Sang } 36713a9930dSWolfram Sang return result; 36813a9930dSWolfram Sang } 36913a9930dSWolfram Sang 37013a9930dSWolfram Sang static void rx_event_task(unsigned long dev) 37113a9930dSWolfram Sang { 372feedcf1aSWolfram Sang struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; 37313a9930dSWolfram Sang struct rx_device_buffer *rp; 37413a9930dSWolfram Sang 37513a9930dSWolfram Sang DPRINTK(4, "\n"); 37613a9930dSWolfram Sang 37713a9930dSWolfram Sang if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) { 37813a9930dSWolfram Sang rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead]; 37913a9930dSWolfram Sang hostif_receive(priv, rp->data, rp->size); 38013a9930dSWolfram Sang inc_rxqhead(priv); 38113a9930dSWolfram Sang 38253638cefSsayli karnik if (cnt_rxqbody(priv) > 0) 38313a9930dSWolfram Sang tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); 38413a9930dSWolfram Sang } 38513a9930dSWolfram Sang } 38613a9930dSWolfram Sang 3875141e9c6STobin C. Harding static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size) 38813a9930dSWolfram Sang { 389f7172487STobin C. Harding int ret; 39013a9930dSWolfram Sang struct rx_device_buffer *rx_buffer; 39113a9930dSWolfram Sang struct hostif_hdr *hdr; 39213a9930dSWolfram Sang unsigned char read_status; 39313a9930dSWolfram Sang unsigned short event = 0; 39413a9930dSWolfram Sang 39513a9930dSWolfram Sang DPRINTK(4, "\n"); 39613a9930dSWolfram Sang 39713a9930dSWolfram Sang /* receive data */ 39813a9930dSWolfram Sang if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) { 39913a9930dSWolfram Sang /* in case of buffer overflow */ 40013a9930dSWolfram Sang DPRINTK(1, "rx buffer overflow\n"); 40113b05e46STobin C. Harding return; 40213a9930dSWolfram Sang } 40313a9930dSWolfram Sang rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail]; 40413a9930dSWolfram Sang 405f7172487STobin C. Harding ret = ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0], 406cdf6ecc5SWolfram Sang hif_align_size(size)); 407f7172487STobin C. Harding if (ret) 40813b05e46STobin C. Harding return; 40913a9930dSWolfram Sang 41013a9930dSWolfram Sang /* length check */ 41113a9930dSWolfram Sang if (size > 2046 || size == 0) { 4123215bb1aSWolfram Sang #ifdef KS_WLAN_DEBUG 4133215bb1aSWolfram Sang if (KS_WLAN_DEBUG > 5) 414cdf6ecc5SWolfram Sang print_hex_dump_bytes("INVALID DATA dump: ", 415cdf6ecc5SWolfram Sang DUMP_PREFIX_OFFSET, 4163215bb1aSWolfram Sang rx_buffer->data, 32); 4173215bb1aSWolfram Sang #endif 41813a9930dSWolfram Sang /* rx_status update */ 41913a9930dSWolfram Sang read_status = READ_STATUS_IDLE; 420f7172487STobin C. Harding ret = ks7010_sdio_write(priv, READ_STATUS, &read_status, 421cdf6ecc5SWolfram Sang sizeof(read_status)); 422f7172487STobin C. Harding if (ret) 42313a9930dSWolfram Sang DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); 42453638cefSsayli karnik 42513b05e46STobin C. Harding /* length check fail */ 42613b05e46STobin C. Harding return; 42713a9930dSWolfram Sang } 42813a9930dSWolfram Sang 42913a9930dSWolfram Sang hdr = (struct hostif_hdr *)&rx_buffer->data[0]; 43013a9930dSWolfram Sang rx_buffer->size = le16_to_cpu(hdr->size) + sizeof(hdr->size); 43113a9930dSWolfram Sang event = hdr->event; 43213a9930dSWolfram Sang inc_rxqtail(priv); 43313a9930dSWolfram Sang 43413a9930dSWolfram Sang /* read status update */ 43513a9930dSWolfram Sang read_status = READ_STATUS_IDLE; 436f7172487STobin C. Harding ret = ks7010_sdio_write(priv, READ_STATUS, &read_status, 437cdf6ecc5SWolfram Sang sizeof(read_status)); 438f7172487STobin C. Harding if (ret) 43913a9930dSWolfram Sang DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); 44053638cefSsayli karnik 44113a9930dSWolfram Sang DPRINTK(4, "READ_STATUS=%02X\n", read_status); 44213a9930dSWolfram Sang 44313a9930dSWolfram Sang if (atomic_read(&priv->psstatus.confirm_wait)) { 44413a9930dSWolfram Sang if (IS_HIF_CONF(event)) { 44513a9930dSWolfram Sang DPRINTK(4, "IS_HIF_CONF true !!\n"); 44613a9930dSWolfram Sang atomic_dec(&priv->psstatus.confirm_wait); 44713a9930dSWolfram Sang } 44813a9930dSWolfram Sang } 44913a9930dSWolfram Sang 45013a9930dSWolfram Sang /* rx_event_task((void *)priv); */ 45113a9930dSWolfram Sang tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); 45213a9930dSWolfram Sang } 45313a9930dSWolfram Sang 45413a9930dSWolfram Sang static void ks7010_rw_function(struct work_struct *work) 45513a9930dSWolfram Sang { 45613a9930dSWolfram Sang struct hw_info_t *hw; 45713a9930dSWolfram Sang struct ks_wlan_private *priv; 45813a9930dSWolfram Sang unsigned char rw_data; 4591770ae9dSTobin C. Harding int ret; 46013a9930dSWolfram Sang 46113a9930dSWolfram Sang hw = container_of(work, struct hw_info_t, rw_wq.work); 46213a9930dSWolfram Sang priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw); 46313a9930dSWolfram Sang 46413a9930dSWolfram Sang DPRINTK(4, "\n"); 46513a9930dSWolfram Sang 46613a9930dSWolfram Sang /* wiat after DOZE */ 46713a9930dSWolfram Sang if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) { 46813a9930dSWolfram Sang DPRINTK(4, "wait after DOZE\n"); 469cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 470cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 47113a9930dSWolfram Sang return; 47213a9930dSWolfram Sang } 47313a9930dSWolfram Sang 47413a9930dSWolfram Sang /* wiat after WAKEUP */ 47513a9930dSWolfram Sang while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) { 47613a9930dSWolfram Sang DPRINTK(4, "wait after WAKEUP\n"); 4779887b5e5SSabitha George dev_info(&priv->ks_wlan_hw.sdio_card->func->dev, 4789887b5e5SSabitha George "wake: %lu %lu\n", 4799887b5e5SSabitha George priv->last_wakeup + (30 * HZ) / 1000, 480cdf6ecc5SWolfram Sang jiffies); 48113a9930dSWolfram Sang msleep(30); 48213a9930dSWolfram Sang } 48313a9930dSWolfram Sang 48413a9930dSWolfram Sang sdio_claim_host(priv->ks_wlan_hw.sdio_card->func); 48513a9930dSWolfram Sang 48613a9930dSWolfram Sang /* power save wakeup */ 48713a9930dSWolfram Sang if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { 48813a9930dSWolfram Sang if (cnt_txqbody(priv) > 0) { 48913a9930dSWolfram Sang ks_wlan_hw_wakeup_request(priv); 490cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 491cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 1); 49213a9930dSWolfram Sang } 493f283dd69STobin C. Harding goto err_release_host; 49413a9930dSWolfram Sang } 49513a9930dSWolfram Sang 49613a9930dSWolfram Sang /* sleep mode doze */ 49713a9930dSWolfram Sang if (atomic_read(&priv->sleepstatus.doze_request) == 1) { 49813a9930dSWolfram Sang ks_wlan_hw_sleep_doze_request(priv); 499f283dd69STobin C. Harding goto err_release_host; 50013a9930dSWolfram Sang } 50113a9930dSWolfram Sang /* sleep mode wakeup */ 50213a9930dSWolfram Sang if (atomic_read(&priv->sleepstatus.wakeup_request) == 1) { 50313a9930dSWolfram Sang ks_wlan_hw_sleep_wakeup_request(priv); 504f283dd69STobin C. Harding goto err_release_host; 50513a9930dSWolfram Sang } 50613a9930dSWolfram Sang 50713a9930dSWolfram Sang /* read (WriteStatus/ReadDataSize FN1:00_0014) */ 5081770ae9dSTobin C. Harding ret = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); 5091770ae9dSTobin C. Harding if (ret) { 510cdf6ecc5SWolfram Sang DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data, 511cdf6ecc5SWolfram Sang atomic_read(&priv->psstatus.status)); 512f283dd69STobin C. Harding goto err_release_host; 51313a9930dSWolfram Sang } 51413a9930dSWolfram Sang DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); 51513a9930dSWolfram Sang 51613a9930dSWolfram Sang if (rw_data & RSIZE_MASK) { /* Read schedule */ 5175141e9c6STobin C. Harding ks_wlan_hw_rx(priv, (uint16_t)((rw_data & RSIZE_MASK) << 4)); 51813a9930dSWolfram Sang } 51953638cefSsayli karnik if ((rw_data & WSTATUS_MASK)) 5205141e9c6STobin C. Harding tx_device_task(priv); 52153638cefSsayli karnik 52213a9930dSWolfram Sang _ks_wlan_hw_power_save(priv); 52313a9930dSWolfram Sang 524f283dd69STobin C. Harding err_release_host: 52513a9930dSWolfram Sang sdio_release_host(priv->ks_wlan_hw.sdio_card->func); 52613a9930dSWolfram Sang } 52713a9930dSWolfram Sang 52813a9930dSWolfram Sang static void ks_sdio_interrupt(struct sdio_func *func) 52913a9930dSWolfram Sang { 530f7172487STobin C. Harding int ret; 53113a9930dSWolfram Sang struct ks_sdio_card *card; 532feedcf1aSWolfram Sang struct ks_wlan_private *priv; 53313a9930dSWolfram Sang unsigned char status, rsize, rw_data; 53413a9930dSWolfram Sang 53513a9930dSWolfram Sang card = sdio_get_drvdata(func); 53613a9930dSWolfram Sang priv = card->priv; 53713a9930dSWolfram Sang DPRINTK(4, "\n"); 53813a9930dSWolfram Sang 539638a75b6STobin C. Harding if (priv->dev_state < DEVICE_STATE_BOOT) 540638a75b6STobin C. Harding goto queue_delayed_work; 541638a75b6STobin C. Harding 542638a75b6STobin C. Harding ret = ks7010_sdio_read(priv, INT_PENDING, &status, sizeof(status)); 543f7172487STobin C. Harding if (ret) { 544f7172487STobin C. Harding DPRINTK(1, "read INT_PENDING Failed!!(%d)\n", ret); 545f283dd69STobin C. Harding goto queue_delayed_work; 54613a9930dSWolfram Sang } 54713a9930dSWolfram Sang DPRINTK(4, "INT_PENDING=%02X\n", rw_data); 54813a9930dSWolfram Sang 54913a9930dSWolfram Sang /* schedule task for interrupt status */ 55013a9930dSWolfram Sang /* bit7 -> Write General Communication B register */ 55113a9930dSWolfram Sang /* read (General Communication B register) */ 55213a9930dSWolfram Sang /* bit5 -> Write Status Idle */ 55313a9930dSWolfram Sang /* bit2 -> Read Status Busy */ 554ddd10774SXiangyang Zhang if (status & INT_GCR_B || 555ddd10774SXiangyang Zhang atomic_read(&priv->psstatus.status) == PS_SNOOZE) { 556f7172487STobin C. Harding ret = ks7010_sdio_read(priv, GCR_B, &rw_data, 557cdf6ecc5SWolfram Sang sizeof(rw_data)); 558f7172487STobin C. Harding if (ret) { 55913a9930dSWolfram Sang DPRINTK(1, " error : GCR_B=%02X\n", rw_data); 560f283dd69STobin C. Harding goto queue_delayed_work; 56113a9930dSWolfram Sang } 56213a9930dSWolfram Sang if (rw_data == GCR_B_ACTIVE) { 563638a75b6STobin C. Harding if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { 564638a75b6STobin C. Harding atomic_set(&priv->psstatus.status, PS_WAKEUP); 56513a9930dSWolfram Sang priv->wakeup_count = 0; 56613a9930dSWolfram Sang } 56713a9930dSWolfram Sang complete(&priv->psstatus.wakeup_wait); 56813a9930dSWolfram Sang } 56913a9930dSWolfram Sang } 57013a9930dSWolfram Sang 57113a9930dSWolfram Sang do { 57213a9930dSWolfram Sang /* read (WriteStatus/ReadDataSize FN1:00_0014) */ 573f7172487STobin C. Harding ret = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, 574cdf6ecc5SWolfram Sang sizeof(rw_data)); 575f7172487STobin C. Harding if (ret) { 576638a75b6STobin C. Harding DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n", rw_data); 577f283dd69STobin C. Harding goto queue_delayed_work; 57813a9930dSWolfram Sang } 57913a9930dSWolfram Sang DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); 58013a9930dSWolfram Sang rsize = rw_data & RSIZE_MASK; 5815141e9c6STobin C. Harding if (rsize != 0) /* Read schedule */ 5825141e9c6STobin C. Harding ks_wlan_hw_rx(priv, (uint16_t)(rsize << 4)); 5835141e9c6STobin C. Harding 58413a9930dSWolfram Sang if (rw_data & WSTATUS_MASK) { 58513a9930dSWolfram Sang if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { 58613a9930dSWolfram Sang if (cnt_txqbody(priv)) { 58713a9930dSWolfram Sang ks_wlan_hw_wakeup_request(priv); 588638a75b6STobin C. Harding queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 589638a75b6STobin C. Harding &priv->ks_wlan_hw.rw_wq, 1); 59013a9930dSWolfram Sang return; 59113a9930dSWolfram Sang } 592cdf6ecc5SWolfram Sang } else { 5935141e9c6STobin C. Harding tx_device_task(priv); 59413a9930dSWolfram Sang } 59513a9930dSWolfram Sang } 59613a9930dSWolfram Sang } while (rsize); 59713a9930dSWolfram Sang 598f283dd69STobin C. Harding queue_delayed_work: 599cdf6ecc5SWolfram Sang queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, 600cdf6ecc5SWolfram Sang &priv->ks_wlan_hw.rw_wq, 0); 60113a9930dSWolfram Sang } 60213a9930dSWolfram Sang 603feedcf1aSWolfram Sang static int trx_device_init(struct ks_wlan_private *priv) 60413a9930dSWolfram Sang { 60513a9930dSWolfram Sang /* initialize values (tx) */ 60620358d13SNick Rosbrook priv->tx_dev.qhead = 0; 60720358d13SNick Rosbrook priv->tx_dev.qtail = 0; 60813a9930dSWolfram Sang 60913a9930dSWolfram Sang /* initialize values (rx) */ 61020358d13SNick Rosbrook priv->rx_dev.qhead = 0; 61120358d13SNick Rosbrook priv->rx_dev.qtail = 0; 61213a9930dSWolfram Sang 61313a9930dSWolfram Sang /* initialize spinLock (tx,rx) */ 61413a9930dSWolfram Sang spin_lock_init(&priv->tx_dev.tx_dev_lock); 61513a9930dSWolfram Sang spin_lock_init(&priv->rx_dev.rx_dev_lock); 61613a9930dSWolfram Sang 617cdf6ecc5SWolfram Sang tasklet_init(&priv->ks_wlan_hw.rx_bh_task, rx_event_task, 618cdf6ecc5SWolfram Sang (unsigned long)priv); 61913a9930dSWolfram Sang 62013a9930dSWolfram Sang return 0; 62113a9930dSWolfram Sang } 62213a9930dSWolfram Sang 623feedcf1aSWolfram Sang static void trx_device_exit(struct ks_wlan_private *priv) 62413a9930dSWolfram Sang { 62513a9930dSWolfram Sang struct tx_device_buffer *sp; 62613a9930dSWolfram Sang 62713a9930dSWolfram Sang /* tx buffer clear */ 62813a9930dSWolfram Sang while (cnt_txqbody(priv) > 0) { 62913a9930dSWolfram Sang sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; 63013a9930dSWolfram Sang kfree(sp->sendp); /* allocated memory free */ 631c7e65f4dSsayli karnik if (sp->complete_handler) /* TX Complete */ 63213a9930dSWolfram Sang (*sp->complete_handler) (sp->arg1, sp->arg2); 63313a9930dSWolfram Sang inc_txqhead(priv); 63413a9930dSWolfram Sang } 63513a9930dSWolfram Sang 63613a9930dSWolfram Sang tasklet_kill(&priv->ks_wlan_hw.rx_bh_task); 63713a9930dSWolfram Sang } 638cdf6ecc5SWolfram Sang 639feedcf1aSWolfram Sang static int ks7010_sdio_update_index(struct ks_wlan_private *priv, u32 index) 64013a9930dSWolfram Sang { 6411770ae9dSTobin C. Harding int ret; 64213a9930dSWolfram Sang unsigned char *data_buf; 64313a9930dSWolfram Sang 64413a9930dSWolfram Sang data_buf = kmalloc(sizeof(u32), GFP_KERNEL); 645aa6ca807STobin C. Harding if (!data_buf) 646aa6ca807STobin C. Harding return -ENOMEM; 64713a9930dSWolfram Sang 64813a9930dSWolfram Sang memcpy(data_buf, &index, sizeof(index)); 6491770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, WRITE_INDEX, data_buf, sizeof(index)); 6501770ae9dSTobin C. Harding if (ret) 651f283dd69STobin C. Harding goto err_free_data_buf; 65213a9930dSWolfram Sang 6531770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, READ_INDEX, data_buf, sizeof(index)); 6541770ae9dSTobin C. Harding if (ret) 655f283dd69STobin C. Harding goto err_free_data_buf; 656aa6ca807STobin C. Harding 657aa6ca807STobin C. Harding return 0; 658aa6ca807STobin C. Harding 659f283dd69STobin C. Harding err_free_data_buf: 660cdf6ecc5SWolfram Sang kfree(data_buf); 661aa6ca807STobin C. Harding 6621770ae9dSTobin C. Harding return ret; 66313a9930dSWolfram Sang } 66413a9930dSWolfram Sang 66513a9930dSWolfram Sang #define ROM_BUFF_SIZE (64 * 1024) 666feedcf1aSWolfram Sang static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, 66713a9930dSWolfram Sang unsigned char *data, unsigned int size) 66813a9930dSWolfram Sang { 6691770ae9dSTobin C. Harding int ret; 67013a9930dSWolfram Sang unsigned char *read_buf; 671eeed92c0SMarkus Elfring 67213a9930dSWolfram Sang read_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); 673aa6ca807STobin C. Harding if (!read_buf) 674aa6ca807STobin C. Harding return -ENOMEM; 67513a9930dSWolfram Sang 6761770ae9dSTobin C. Harding ret = ks7010_sdio_read(priv, address, read_buf, size); 6771770ae9dSTobin C. Harding if (ret) 678f283dd69STobin C. Harding goto err_free_read_buf; 679aa6ca807STobin C. Harding 68058af272bSTobin C. Harding if (memcmp(data, read_buf, size) != 0) { 68158af272bSTobin C. Harding ret = -EIO; 6821770ae9dSTobin C. Harding DPRINTK(0, "data compare error (%d)\n", ret); 683f283dd69STobin C. Harding goto err_free_read_buf; 68413a9930dSWolfram Sang } 685aa6ca807STobin C. Harding 686aa6ca807STobin C. Harding return 0; 687aa6ca807STobin C. Harding 688f283dd69STobin C. Harding err_free_read_buf: 689cdf6ecc5SWolfram Sang kfree(read_buf); 690aa6ca807STobin C. Harding 6911770ae9dSTobin C. Harding return ret; 69213a9930dSWolfram Sang } 693cdf6ecc5SWolfram Sang 694ed246b9eSTobin C. Harding static int ks7010_upload_firmware(struct ks_sdio_card *card) 69513a9930dSWolfram Sang { 696ed246b9eSTobin C. Harding struct ks_wlan_private *priv = card->priv; 69713a9930dSWolfram Sang unsigned int size, offset, n = 0; 69813a9930dSWolfram Sang unsigned char *rom_buf; 69913a9930dSWolfram Sang unsigned char rw_data = 0; 7001770ae9dSTobin C. Harding int ret; 701881f76b9STobin C. Harding unsigned int length; 70213a9930dSWolfram Sang const struct firmware *fw_entry = NULL; 70313a9930dSWolfram Sang 70413a9930dSWolfram Sang /* buffer allocate */ 70513a9930dSWolfram Sang rom_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); 706369e1b69SSudip Mukherjee if (!rom_buf) 707aa6ca807STobin C. Harding return -ENOMEM; 70813a9930dSWolfram Sang 70913a9930dSWolfram Sang sdio_claim_host(card->func); 71013a9930dSWolfram Sang 71113a9930dSWolfram Sang /* Firmware running ? */ 7121770ae9dSTobin C. Harding ret = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); 71313a9930dSWolfram Sang if (rw_data == GCR_A_RUN) { 71413a9930dSWolfram Sang DPRINTK(0, "MAC firmware running ...\n"); 715aa6ca807STobin C. Harding goto release_host_and_free; 71613a9930dSWolfram Sang } 71713a9930dSWolfram Sang 7181770ae9dSTobin C. Harding ret = request_firmware(&fw_entry, ROM_FILE, 7191770ae9dSTobin C. Harding &priv->ks_wlan_hw.sdio_card->func->dev); 7201770ae9dSTobin C. Harding if (ret) 721aa6ca807STobin C. Harding goto release_host_and_free; 7226ee9169bSWolfram Sang 72313a9930dSWolfram Sang length = fw_entry->size; 72413a9930dSWolfram Sang 72513a9930dSWolfram Sang /* Load Program */ 72613a9930dSWolfram Sang n = 0; 72713a9930dSWolfram Sang do { 72813a9930dSWolfram Sang if (length >= ROM_BUFF_SIZE) { 72913a9930dSWolfram Sang size = ROM_BUFF_SIZE; 73013a9930dSWolfram Sang length = length - ROM_BUFF_SIZE; 731cdf6ecc5SWolfram Sang } else { 73213a9930dSWolfram Sang size = length; 73313a9930dSWolfram Sang length = 0; 73413a9930dSWolfram Sang } 73513a9930dSWolfram Sang DPRINTK(4, "size = %d\n", size); 736cdf6ecc5SWolfram Sang if (size == 0) 737cdf6ecc5SWolfram Sang break; 73813a9930dSWolfram Sang memcpy(rom_buf, fw_entry->data + n, size); 73913a9930dSWolfram Sang /* Update write index */ 74013a9930dSWolfram Sang offset = n; 7411770ae9dSTobin C. Harding ret = ks7010_sdio_update_index(priv, KS7010_IRAM_ADDRESS + offset); 7421770ae9dSTobin C. Harding if (ret) 743aa6ca807STobin C. Harding goto release_firmware; 74413a9930dSWolfram Sang 74513a9930dSWolfram Sang /* Write data */ 7461770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, DATA_WINDOW, rom_buf, size); 7471770ae9dSTobin C. Harding if (ret) 748aa6ca807STobin C. Harding goto release_firmware; 74913a9930dSWolfram Sang 75013a9930dSWolfram Sang /* compare */ 7511770ae9dSTobin C. Harding ret = ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size); 7521770ae9dSTobin C. Harding if (ret) 753aa6ca807STobin C. Harding goto release_firmware; 754aa6ca807STobin C. Harding 75513a9930dSWolfram Sang n += size; 75613a9930dSWolfram Sang 75713a9930dSWolfram Sang } while (size); 75813a9930dSWolfram Sang 75913a9930dSWolfram Sang /* Remap request */ 76013a9930dSWolfram Sang rw_data = GCR_A_REMAP; 7611770ae9dSTobin C. Harding ret = ks7010_sdio_write(priv, GCR_A, &rw_data, sizeof(rw_data)); 7621770ae9dSTobin C. Harding if (ret) 763aa6ca807STobin C. Harding goto release_firmware; 764aa6ca807STobin C. Harding 76513a9930dSWolfram Sang DPRINTK(4, " REMAP Request : GCR_A=%02X\n", rw_data); 76613a9930dSWolfram Sang 76713a9930dSWolfram Sang /* Firmware running check */ 76813a9930dSWolfram Sang for (n = 0; n < 50; ++n) { 76913a9930dSWolfram Sang mdelay(10); /* wait_ms(10); */ 7701770ae9dSTobin C. Harding ret = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); 7711770ae9dSTobin C. Harding if (ret) 772aa6ca807STobin C. Harding goto release_firmware; 773aa6ca807STobin C. Harding 774cdf6ecc5SWolfram Sang if (rw_data == GCR_A_RUN) 775cdf6ecc5SWolfram Sang break; 77613a9930dSWolfram Sang } 77713a9930dSWolfram Sang DPRINTK(4, "firmware wakeup (%d)!!!!\n", n); 77813a9930dSWolfram Sang if ((50) <= n) { 77913a9930dSWolfram Sang DPRINTK(1, "firmware can't start\n"); 7801770ae9dSTobin C. Harding ret = -EIO; 781aa6ca807STobin C. Harding goto release_firmware; 78213a9930dSWolfram Sang } 78313a9930dSWolfram Sang 7841770ae9dSTobin C. Harding ret = 0; 78513a9930dSWolfram Sang 786aa6ca807STobin C. Harding release_firmware: 78713a9930dSWolfram Sang release_firmware(fw_entry); 788aa6ca807STobin C. Harding release_host_and_free: 78913a9930dSWolfram Sang sdio_release_host(card->func); 79013a9930dSWolfram Sang kfree(rom_buf); 791aa6ca807STobin C. Harding 7921770ae9dSTobin C. Harding return ret; 79313a9930dSWolfram Sang } 79413a9930dSWolfram Sang 795e8593a8aSWolfram Sang static void ks7010_card_init(struct ks_wlan_private *priv) 79613a9930dSWolfram Sang { 79713a9930dSWolfram Sang DPRINTK(5, "\ncard_init_task()\n"); 79813a9930dSWolfram Sang 79913a9930dSWolfram Sang /* init_waitqueue_head(&priv->confirm_wait); */ 80013a9930dSWolfram Sang init_completion(&priv->confirm_wait); 80113a9930dSWolfram Sang 80213a9930dSWolfram Sang DPRINTK(5, "init_completion()\n"); 80313a9930dSWolfram Sang 80413a9930dSWolfram Sang /* get mac address & firmware version */ 80513a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_START); 80613a9930dSWolfram Sang 80713a9930dSWolfram Sang DPRINTK(5, "hostif_sme_enqueu()\n"); 80813a9930dSWolfram Sang 809cdf6ecc5SWolfram Sang if (!wait_for_completion_interruptible_timeout 810cdf6ecc5SWolfram Sang (&priv->confirm_wait, 5 * HZ)) { 81113a9930dSWolfram Sang DPRINTK(1, "wait time out!! SME_START\n"); 81213a9930dSWolfram Sang } 81313a9930dSWolfram Sang 814310e916fSTobin C. Harding if (priv->mac_address_valid && priv->version_size != 0) 81513a9930dSWolfram Sang priv->dev_state = DEVICE_STATE_PREINIT; 81653638cefSsayli karnik 81713a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_GET_EEPROM_CKSUM); 81813a9930dSWolfram Sang 81913a9930dSWolfram Sang /* load initial wireless parameter */ 82013a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_STOP_REQUEST); 82113a9930dSWolfram Sang 82213a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST); 82313a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST); 82413a9930dSWolfram Sang 82513a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST); 82613a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST); 82713a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST); 82813a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST); 82913a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST); 83013a9930dSWolfram Sang 83113a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); 83213a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST); 83313a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST); 83413a9930dSWolfram Sang hostif_sme_enqueue(priv, SME_START_REQUEST); 83513a9930dSWolfram Sang 836cdf6ecc5SWolfram Sang if (!wait_for_completion_interruptible_timeout 837cdf6ecc5SWolfram Sang (&priv->confirm_wait, 5 * HZ)) { 83813a9930dSWolfram Sang DPRINTK(1, "wait time out!! wireless parameter set\n"); 83913a9930dSWolfram Sang } 84013a9930dSWolfram Sang 84113a9930dSWolfram Sang if (priv->dev_state >= DEVICE_STATE_PREINIT) { 84213a9930dSWolfram Sang DPRINTK(1, "DEVICE READY!!\n"); 84313a9930dSWolfram Sang priv->dev_state = DEVICE_STATE_READY; 844cdf6ecc5SWolfram Sang } else { 84513a9930dSWolfram Sang DPRINTK(1, "dev_state=%d\n", priv->dev_state); 84613a9930dSWolfram Sang } 84713a9930dSWolfram Sang } 84813a9930dSWolfram Sang 8496ee9169bSWolfram Sang static void ks7010_init_defaults(struct ks_wlan_private *priv) 8506ee9169bSWolfram Sang { 8516ee9169bSWolfram Sang priv->reg.tx_rate = TX_RATE_AUTO; 8526ee9169bSWolfram Sang priv->reg.preamble = LONG_PREAMBLE; 8536ee9169bSWolfram Sang priv->reg.powermgt = POWMGT_ACTIVE_MODE; 8546ee9169bSWolfram Sang priv->reg.scan_type = ACTIVE_SCAN; 8556ee9169bSWolfram Sang priv->reg.beacon_lost_count = 20; 8566ee9169bSWolfram Sang priv->reg.rts = 2347UL; 8576ee9169bSWolfram Sang priv->reg.fragment = 2346UL; 8586ee9169bSWolfram Sang priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; 8596ee9169bSWolfram Sang priv->reg.cts_mode = CTS_MODE_FALSE; 8606ee9169bSWolfram Sang priv->reg.rate_set.body[11] = TX_RATE_54M; 8616ee9169bSWolfram Sang priv->reg.rate_set.body[10] = TX_RATE_48M; 8626ee9169bSWolfram Sang priv->reg.rate_set.body[9] = TX_RATE_36M; 8636ee9169bSWolfram Sang priv->reg.rate_set.body[8] = TX_RATE_18M; 8646ee9169bSWolfram Sang priv->reg.rate_set.body[7] = TX_RATE_9M; 8656ee9169bSWolfram Sang priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; 8666ee9169bSWolfram Sang priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; 8676ee9169bSWolfram Sang priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; 8686ee9169bSWolfram Sang priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; 8696ee9169bSWolfram Sang priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; 8706ee9169bSWolfram Sang priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; 8716ee9169bSWolfram Sang priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; 8726ee9169bSWolfram Sang priv->reg.tx_rate = TX_RATE_FULL_AUTO; 8736ee9169bSWolfram Sang priv->reg.rate_set.size = 12; 8746ee9169bSWolfram Sang } 8756ee9169bSWolfram Sang 876c4730a92SWolfram Sang static int ks7010_sdio_probe(struct sdio_func *func, 877cdf6ecc5SWolfram Sang const struct sdio_device_id *device) 87813a9930dSWolfram Sang { 879feedcf1aSWolfram Sang struct ks_wlan_private *priv; 88013a9930dSWolfram Sang struct ks_sdio_card *card; 88113a9930dSWolfram Sang struct net_device *netdev; 88213a9930dSWolfram Sang unsigned char rw_data; 8832801d7a2SWolfram Sang int ret; 88413a9930dSWolfram Sang 885c4730a92SWolfram Sang DPRINTK(5, "ks7010_sdio_probe()\n"); 88613a9930dSWolfram Sang 88713a9930dSWolfram Sang priv = NULL; 88813a9930dSWolfram Sang netdev = NULL; 88913a9930dSWolfram Sang 890f3f2d351SNick Rosbrook /* initialize ks_sdio_card */ 8912d738bd2SSandhya Bankar card = kzalloc(sizeof(*card), GFP_KERNEL); 89213a9930dSWolfram Sang if (!card) 89313a9930dSWolfram Sang return -ENOMEM; 89413a9930dSWolfram Sang 89513a9930dSWolfram Sang card->func = func; 89613a9930dSWolfram Sang spin_lock_init(&card->lock); 89713a9930dSWolfram Sang 89813a9930dSWolfram Sang /*** Initialize SDIO ***/ 89913a9930dSWolfram Sang sdio_claim_host(func); 90013a9930dSWolfram Sang 90113a9930dSWolfram Sang /* bus setting */ 90213a9930dSWolfram Sang /* Issue config request to override clock rate */ 90313a9930dSWolfram Sang 90413a9930dSWolfram Sang /* function blocksize set */ 90513a9930dSWolfram Sang ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE); 906cdf6ecc5SWolfram Sang DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n", 907cdf6ecc5SWolfram Sang func->card->cccr.multi_block, func->cur_blksize, ret); 90813a9930dSWolfram Sang 90913a9930dSWolfram Sang /* Allocate the slot current */ 91013a9930dSWolfram Sang 91113a9930dSWolfram Sang /* function enable */ 91213a9930dSWolfram Sang ret = sdio_enable_func(func); 91313a9930dSWolfram Sang DPRINTK(5, "sdio_enable_func() %d\n", ret); 91413a9930dSWolfram Sang if (ret) 915f283dd69STobin C. Harding goto err_free_card; 91613a9930dSWolfram Sang 91713a9930dSWolfram Sang /* interrupt disable */ 91813a9930dSWolfram Sang sdio_writeb(func, 0, INT_ENABLE, &ret); 91913a9930dSWolfram Sang if (ret) 920f283dd69STobin C. Harding goto err_free_card; 92113a9930dSWolfram Sang sdio_writeb(func, 0xff, INT_PENDING, &ret); 92213a9930dSWolfram Sang if (ret) 923f283dd69STobin C. Harding goto err_disable_func; 92413a9930dSWolfram Sang 92513a9930dSWolfram Sang /* setup interrupt handler */ 92613a9930dSWolfram Sang ret = sdio_claim_irq(func, ks_sdio_interrupt); 92713a9930dSWolfram Sang if (ret) 928f283dd69STobin C. Harding goto err_disable_func; 92913a9930dSWolfram Sang 93013a9930dSWolfram Sang sdio_release_host(func); 93113a9930dSWolfram Sang 93213a9930dSWolfram Sang sdio_set_drvdata(func, card); 93313a9930dSWolfram Sang 93413a9930dSWolfram Sang DPRINTK(5, "class = 0x%X, vendor = 0x%X, " 935cdf6ecc5SWolfram Sang "device = 0x%X\n", func->class, func->vendor, func->device); 93613a9930dSWolfram Sang 93713a9930dSWolfram Sang /* private memory allocate */ 93813a9930dSWolfram Sang netdev = alloc_etherdev(sizeof(*priv)); 939c7e65f4dSsayli karnik if (!netdev) { 9409887b5e5SSabitha George dev_err(&card->func->dev, "ks7010 : Unable to alloc new net device\n"); 941f283dd69STobin C. Harding goto err_release_irq; 94213a9930dSWolfram Sang } 9436634cff1SWolfram Sang if (dev_alloc_name(netdev, "wlan%d") < 0) { 9449887b5e5SSabitha George dev_err(&card->func->dev, 9459887b5e5SSabitha George "ks7010 : Couldn't get name!\n"); 946f283dd69STobin C. Harding goto err_free_netdev; 94713a9930dSWolfram Sang } 94813a9930dSWolfram Sang 94913a9930dSWolfram Sang priv = netdev_priv(netdev); 95013a9930dSWolfram Sang 95113a9930dSWolfram Sang card->priv = priv; 95213a9930dSWolfram Sang SET_NETDEV_DEV(netdev, &card->func->dev); /* for create sysfs symlinks */ 95313a9930dSWolfram Sang 95413a9930dSWolfram Sang /* private memory initialize */ 95513a9930dSWolfram Sang priv->ks_wlan_hw.sdio_card = card; 95613a9930dSWolfram Sang init_completion(&priv->ks_wlan_hw.ks7010_sdio_wait); 95713a9930dSWolfram Sang priv->ks_wlan_hw.read_buf = NULL; 95813a9930dSWolfram Sang priv->ks_wlan_hw.read_buf = kmalloc(RX_DATA_SIZE, GFP_KERNEL); 95953638cefSsayli karnik if (!priv->ks_wlan_hw.read_buf) 960f283dd69STobin C. Harding goto err_free_netdev; 96153638cefSsayli karnik 96213a9930dSWolfram Sang priv->dev_state = DEVICE_STATE_PREBOOT; 96313a9930dSWolfram Sang priv->net_dev = netdev; 96413a9930dSWolfram Sang priv->firmware_version[0] = '\0'; 96513a9930dSWolfram Sang priv->version_size = 0; 96613a9930dSWolfram Sang priv->last_doze = jiffies; /* set current jiffies */ 96713a9930dSWolfram Sang priv->last_wakeup = jiffies; 96813a9930dSWolfram Sang memset(&priv->nstats, 0, sizeof(priv->nstats)); 96913a9930dSWolfram Sang memset(&priv->wstats, 0, sizeof(priv->wstats)); 97013a9930dSWolfram Sang 97113a9930dSWolfram Sang /* sleep mode */ 97213a9930dSWolfram Sang atomic_set(&priv->sleepstatus.doze_request, 0); 97313a9930dSWolfram Sang atomic_set(&priv->sleepstatus.wakeup_request, 0); 97413a9930dSWolfram Sang atomic_set(&priv->sleepstatus.wakeup_request, 0); 97513a9930dSWolfram Sang 97613a9930dSWolfram Sang trx_device_init(priv); 97713a9930dSWolfram Sang hostif_init(priv); 97813a9930dSWolfram Sang ks_wlan_net_start(netdev); 97913a9930dSWolfram Sang 9806ee9169bSWolfram Sang ks7010_init_defaults(priv); 98113a9930dSWolfram Sang 982ed246b9eSTobin C. Harding ret = ks7010_upload_firmware(card); 98313a9930dSWolfram Sang if (ret) { 9849887b5e5SSabitha George dev_err(&card->func->dev, 9859887b5e5SSabitha George "ks7010: firmware load failed !! return code = %d\n", 986cdf6ecc5SWolfram Sang ret); 987f283dd69STobin C. Harding goto err_free_read_buf; 98813a9930dSWolfram Sang } 98913a9930dSWolfram Sang 99013a9930dSWolfram Sang /* interrupt setting */ 99113a9930dSWolfram Sang /* clear Interrupt status write (ARMtoSD_InterruptPending FN1:00_0024) */ 99213a9930dSWolfram Sang rw_data = 0xff; 99313a9930dSWolfram Sang sdio_claim_host(func); 99413a9930dSWolfram Sang ret = ks7010_sdio_write(priv, INT_PENDING, &rw_data, sizeof(rw_data)); 99513a9930dSWolfram Sang sdio_release_host(func); 99653638cefSsayli karnik if (ret) 99713a9930dSWolfram Sang DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); 99853638cefSsayli karnik 99913a9930dSWolfram Sang DPRINTK(4, " clear Interrupt : INT_PENDING=%02X\n", rw_data); 100013a9930dSWolfram Sang 100113a9930dSWolfram Sang /* enable ks7010sdio interrupt (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS) */ 100213a9930dSWolfram Sang rw_data = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS); 100313a9930dSWolfram Sang sdio_claim_host(func); 100413a9930dSWolfram Sang ret = ks7010_sdio_write(priv, INT_ENABLE, &rw_data, sizeof(rw_data)); 100513a9930dSWolfram Sang sdio_release_host(func); 100653638cefSsayli karnik if (ret) 1007f283dd69STobin C. Harding DPRINTK(1, " err : INT_ENABLE=%02X\n", rw_data); 100853638cefSsayli karnik 100913a9930dSWolfram Sang DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", rw_data); 101013a9930dSWolfram Sang priv->dev_state = DEVICE_STATE_BOOT; 101113a9930dSWolfram Sang 101213a9930dSWolfram Sang priv->ks_wlan_hw.ks7010sdio_wq = create_workqueue("ks7010sdio_wq"); 101313a9930dSWolfram Sang if (!priv->ks_wlan_hw.ks7010sdio_wq) { 101413a9930dSWolfram Sang DPRINTK(1, "create_workqueue failed !!\n"); 1015f283dd69STobin C. Harding goto err_free_read_buf; 101613a9930dSWolfram Sang } 101713a9930dSWolfram Sang 101813a9930dSWolfram Sang INIT_DELAYED_WORK(&priv->ks_wlan_hw.rw_wq, ks7010_rw_function); 1019e8593a8aSWolfram Sang ks7010_card_init(priv); 102013a9930dSWolfram Sang 10213fb54d75SWolfram Sang ret = register_netdev(priv->net_dev); 10223fb54d75SWolfram Sang if (ret) 1023f283dd69STobin C. Harding goto err_free_read_buf; 10243fb54d75SWolfram Sang 102513a9930dSWolfram Sang return 0; 102613a9930dSWolfram Sang 1027f283dd69STobin C. Harding err_free_read_buf: 102813a9930dSWolfram Sang kfree(priv->ks_wlan_hw.read_buf); 102913a9930dSWolfram Sang priv->ks_wlan_hw.read_buf = NULL; 1030f283dd69STobin C. Harding err_free_netdev: 103113a9930dSWolfram Sang free_netdev(priv->net_dev); 103213a9930dSWolfram Sang card->priv = NULL; 1033f283dd69STobin C. Harding err_release_irq: 103413a9930dSWolfram Sang sdio_claim_host(func); 103513a9930dSWolfram Sang sdio_release_irq(func); 1036f283dd69STobin C. Harding err_disable_func: 103713a9930dSWolfram Sang sdio_disable_func(func); 1038f283dd69STobin C. Harding err_free_card: 103913a9930dSWolfram Sang sdio_release_host(func); 104013a9930dSWolfram Sang sdio_set_drvdata(func, NULL); 104113a9930dSWolfram Sang kfree(card); 10422801d7a2SWolfram Sang 104313a9930dSWolfram Sang return -ENODEV; 104413a9930dSWolfram Sang } 104513a9930dSWolfram Sang 1046c4730a92SWolfram Sang static void ks7010_sdio_remove(struct sdio_func *func) 104713a9930dSWolfram Sang { 104813a9930dSWolfram Sang int ret; 104913a9930dSWolfram Sang struct ks_sdio_card *card; 105013a9930dSWolfram Sang struct ks_wlan_private *priv; 1051697f9f7fSMuraru Mihaela 1052c4730a92SWolfram Sang DPRINTK(1, "ks7010_sdio_remove()\n"); 105313a9930dSWolfram Sang 105413a9930dSWolfram Sang card = sdio_get_drvdata(func); 105513a9930dSWolfram Sang 1056c7e65f4dSsayli karnik if (!card) 105713a9930dSWolfram Sang return; 105813a9930dSWolfram Sang 105913a9930dSWolfram Sang DPRINTK(1, "priv = card->priv\n"); 106013a9930dSWolfram Sang priv = card->priv; 106113a9930dSWolfram Sang if (priv) { 1062803394d0SColin Ian King struct net_device *netdev = priv->net_dev; 1063803394d0SColin Ian King 106413a9930dSWolfram Sang ks_wlan_net_stop(netdev); 106513a9930dSWolfram Sang DPRINTK(1, "ks_wlan_net_stop\n"); 106613a9930dSWolfram Sang 106713a9930dSWolfram Sang /* interrupt disable */ 106813a9930dSWolfram Sang sdio_claim_host(func); 106913a9930dSWolfram Sang sdio_writeb(func, 0, INT_ENABLE, &ret); 107013a9930dSWolfram Sang sdio_writeb(func, 0xff, INT_PENDING, &ret); 107113a9930dSWolfram Sang sdio_release_host(func); 107213a9930dSWolfram Sang DPRINTK(1, "interrupt disable\n"); 107313a9930dSWolfram Sang 107413a9930dSWolfram Sang /* send stop request to MAC */ 107513a9930dSWolfram Sang { 107613a9930dSWolfram Sang struct hostif_stop_request_t *pp; 1077697f9f7fSMuraru Mihaela 1078cbb351ccSSandhya Bankar pp = kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL); 1079c7e65f4dSsayli karnik if (!pp) { 108013a9930dSWolfram Sang DPRINTK(3, "allocate memory failed..\n"); 108113a9930dSWolfram Sang return; /* to do goto ni suru */ 108213a9930dSWolfram Sang } 1083cdf6ecc5SWolfram Sang pp->header.size = 1084cdf6ecc5SWolfram Sang cpu_to_le16((uint16_t) 1085cdf6ecc5SWolfram Sang (sizeof(*pp) - 1086cdf6ecc5SWolfram Sang sizeof(pp->header.size))); 108713a9930dSWolfram Sang pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ); 108813a9930dSWolfram Sang 108913a9930dSWolfram Sang sdio_claim_host(func); 1090cdf6ecc5SWolfram Sang write_to_device(priv, (unsigned char *)pp, 1091cdf6ecc5SWolfram Sang hif_align_size(sizeof(*pp))); 109213a9930dSWolfram Sang sdio_release_host(func); 109313a9930dSWolfram Sang kfree(pp); 109413a9930dSWolfram Sang } 109513a9930dSWolfram Sang DPRINTK(1, "STOP Req\n"); 109613a9930dSWolfram Sang 109713a9930dSWolfram Sang if (priv->ks_wlan_hw.ks7010sdio_wq) { 109813a9930dSWolfram Sang flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); 109913a9930dSWolfram Sang destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); 110013a9930dSWolfram Sang } 1101cdf6ecc5SWolfram Sang DPRINTK(1, 1102cdf6ecc5SWolfram Sang "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n"); 110313a9930dSWolfram Sang 110413a9930dSWolfram Sang hostif_exit(priv); 110513a9930dSWolfram Sang DPRINTK(1, "hostif_exit\n"); 110613a9930dSWolfram Sang 110713a9930dSWolfram Sang unregister_netdev(netdev); 110813a9930dSWolfram Sang 110913a9930dSWolfram Sang trx_device_exit(priv); 111013a9930dSWolfram Sang kfree(priv->ks_wlan_hw.read_buf); 111113a9930dSWolfram Sang free_netdev(priv->net_dev); 111213a9930dSWolfram Sang card->priv = NULL; 111313a9930dSWolfram Sang } 111413a9930dSWolfram Sang 111513a9930dSWolfram Sang sdio_claim_host(func); 111613a9930dSWolfram Sang sdio_release_irq(func); 111713a9930dSWolfram Sang DPRINTK(1, "sdio_release_irq()\n"); 111813a9930dSWolfram Sang sdio_disable_func(func); 111913a9930dSWolfram Sang DPRINTK(1, "sdio_disable_func()\n"); 112013a9930dSWolfram Sang sdio_release_host(func); 112113a9930dSWolfram Sang 112213a9930dSWolfram Sang sdio_set_drvdata(func, NULL); 112313a9930dSWolfram Sang 112413a9930dSWolfram Sang kfree(card); 112513a9930dSWolfram Sang DPRINTK(1, "kfree()\n"); 112613a9930dSWolfram Sang 112713a9930dSWolfram Sang DPRINTK(5, " Bye !!\n"); 112813a9930dSWolfram Sang } 112913a9930dSWolfram Sang 11304c0d46d2SWolfram Sang static struct sdio_driver ks7010_sdio_driver = { 11314c0d46d2SWolfram Sang .name = "ks7010_sdio", 11324c0d46d2SWolfram Sang .id_table = ks7010_sdio_ids, 11334c0d46d2SWolfram Sang .probe = ks7010_sdio_probe, 11344c0d46d2SWolfram Sang .remove = ks7010_sdio_remove, 11354c0d46d2SWolfram Sang }; 11364c0d46d2SWolfram Sang 11376b0cb0b0SWolfram Sang module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver); 1138e1240140SWolfram Sang MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream"); 1139e1240140SWolfram Sang MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards"); 1140e1240140SWolfram Sang MODULE_LICENSE("GPL v2"); 1141e1240140SWolfram Sang MODULE_FIRMWARE(ROM_FILE); 1142