#ifdef __RTOS__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #endif #include "hgicf.h" #include "ctrl.h" #include "cfg.h" #include "event.h" static int txq_size = 1024; static char *conf_file = "/etc/hgicf.conf"; static char *fw_file = "hgicf.bin"; static int if_test = 0; static int soft_fc = 1; static int no_bootdl = 0; static int qc_mode = 0; static char *ifname = "hg%d"; static hgic_init_cb init_cb = NULL; #ifdef __RTOS__ static hgic_event_cb event_cb = NULL; #endif #define TXWND_INIT_VAL (2) #define MATCH_NDEV(fwidx,hg) ((fwidx) == HGIC_WDEV_ID_STA ? (hg->sta ? hg->sta->ndev : NULL) : \ (hg->ap ? hg->ap->ndev : NULL)) #ifdef __RTOS__ static int iface_cnt = 1; void dev_queue_xmit(struct sk_buff *skb) { struct net_device *ndev = skb->dev; if (ndev) { ndev->netdev_ops->ndo_start_xmit(skb, ndev); } else { kfree_skb(skb); } } #endif u16 hgicf_data_cookie(struct hgicf_wdev *hg) { unsigned long flags; uint16_t cookie = 0; spin_lock_irqsave(&hg->lock, flags); cookie = hg->data_cookie++; spin_unlock_irqrestore(&hg->lock, flags); return cookie; } void hgicf_load_config(struct hgicf_wdev *hg) { #ifndef __RTOS__ struct file *fp = NULL; struct iwreq wrqin; struct net_device *ndev = NULL; ssize_t ret = 0; unsigned long long __maybe_unused offset = 0 ; char *conf = kzalloc(2048, GFP_KERNEL); char *ptr, *str; if (hg->sta) {ndev = hg->sta->ndev; } else if (hg->ap) {ndev = hg->ap->ndev; } else { hgic_err("No netdev!! \r\n"); goto __out; } fp = filp_open(conf_file, O_RDONLY, 0); if (!IS_ERR(fp) && conf) { ret = _KERNEL_READ(fp, conf, 2048, &offset); str = conf; hgic_fwctrl_close_dev(&(hg->ctrl)); while (str) { ptr = strstr(str, "\r\n"); if (ptr) { *ptr = 0; ptr += 2; } else { ptr = strstr(str, "\n"); if (ptr) { *ptr++ = 0;} } wrqin.u.data.length = strlen(str); if (wrqin.u.data.length > 0) { hgic_dbg("param: [%s]\r\n", str); wrqin.u.data.pointer = str; ret = hgicf_ioctl_set_proc(ndev, &wrqin); if (ret < 0) { hgic_err("invalid param:[%s]\r\n", str); } } str = ptr; } hgic_fwctrl_open_dev(&(hg->ctrl)); } __out: if (!IS_ERR(fp)) { filp_close(fp, NULL); } if (conf) { kfree(conf); } #endif } static int hgicf_netif_open(struct net_device *dev) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return 0; } vif->hg->radio_off = 0; return hgic_fwctrl_open_dev(&(vif->hg->ctrl)); } static int hgicf_netif_stop(struct net_device *dev) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return 0; } vif->hg->radio_off = 1; return hgic_fwctrl_close_dev(&(vif->hg->ctrl)); } static void hgicf_netif_uninit(struct net_device *dev) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return; } } static netdev_tx_t hgicf_netif_xmit(struct sk_buff *skb, struct net_device *dev) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); struct hgic_frm_hdr2 *hdr = NULL; u8 pad = ((ulong)skb->data & 0x3) ? (4 - ((ulong)skb->data & 0x3)) : 0; if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags) || (vif->hg->tx_dataq.qlen > txq_size) || test_bit(HGIC_BUS_FLAGS_SLEEP, &vif->hg->bus->flags)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } #ifndef __RTOS__ if (skb_headroom(skb) < sizeof(struct hgic_frm_hdr2)) { struct sk_buff *nskb = skb_copy_expand(skb, skb->dev->needed_headroom, skb->dev->needed_tailroom, GFP_KERNEL); dev_kfree_skb(skb); if (nskb == NULL) { return NETDEV_TX_OK; } skb = nskb; pad = ((ulong)skb->data & 0x3) ? (4 - ((ulong)skb->data & 0x3)) : 0; } #endif hdr = (struct hgic_frm_hdr2 *)skb_push(skb, sizeof(struct hgic_frm_hdr2) + pad); hdr->hdr.ifidx = vif->fwifidx; hdr->hdr.length = skb->len; hdr->hdr.magic = HGIC_HDR_TX_MAGIC; hdr->hdr.type = HGIC_HDR_TYPE_FRM2; hdr->hdr.flags = pad; hdr->hdr.cookie = hgicf_data_cookie(vif->hg); skb_queue_tail(&vif->hg->tx_dataq, skb); queue_work(vif->hg->tx_wq, &vif->hg->tx_work); return NETDEV_TX_OK; } static int hgicf_netif_change_mac(struct net_device *dev, void *addr) { int ret = 0; #ifdef __RTOS__ ret = hgicf_ioctl(dev, HGIC_CMD_SET_MAC, addr, 0); #else struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); struct sockaddr *sa = (struct sockaddr *)addr; if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return 0; } ret = hgic_fwctrl_set_mac(&(vif->hg->ctrl), sa->sa_data); if (!ret) { ret = eth_mac_addr(dev, addr); } #endif return ret; } static void hgicf_netif_set_multicast_list(struct net_device *dev) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return; } } #ifdef __RTOS__ static int hgicf_netif_ioctl(struct net_device *dev, u32 cmd, u32 param1, u32 param2) { return hgicf_ioctl(dev, cmd, param1, param2); } int hgicf_cmd(char *ifname, unsigned int cmd, unsigned int param1, unsigned int param2) { struct net_device *ndev = net_device_get_by_name(ifname); if (ndev == NULL) { return -ENODEV; } return hgicf_netif_ioctl(ndev, cmd, param1, param2); } #else static int hgicf_netif_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(dev); if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags)) { return 0; } return hgicf_ioctl(dev, ifr, cmd); } #endif static const struct net_device_ops hgicf_netif_ops = { .ndo_open = hgicf_netif_open, .ndo_stop = hgicf_netif_stop, .ndo_uninit = hgicf_netif_uninit, .ndo_start_xmit = hgicf_netif_xmit, .ndo_set_rx_mode = hgicf_netif_set_multicast_list, .ndo_set_mac_address = hgicf_netif_change_mac, .ndo_do_ioctl = hgicf_netif_ioctl, }; static void hgicf_netif_setup(struct net_device *dev) { #ifdef __RTOS__ dev->netdev_ops = &hgicf_netif_ops; #else ether_setup(dev); dev->netdev_ops = &hgicf_netif_ops; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) dev->priv_destructor = free_netdev; #else dev->destructor = free_netdev; #endif #endif } static int hgicf_request_txwnd(struct hgic_bus *bus) { struct hgic_hdr *hdr = NULL; struct sk_buff *skb = dev_alloc_skb(sizeof(struct hgic_hdr) + 2); if (skb == NULL) { return -ENOMEM; } hdr = (struct hgic_hdr *)skb->data; hdr->magic = HGIC_HDR_TX_MAGIC; hdr->type = HGIC_HDR_TYPE_SOFTFC; hdr->length = sizeof(struct hgic_hdr) + 2; hdr->ifidx = 0; hdr->flags = 0; hdr->cookie = 0; skb_put(skb, sizeof(struct hgic_hdr) + 2); return bus->tx_packet(bus, skb); } static int hgicf_check_txwnd(struct hgicf_wdev *hg) { int err = 0; if (!hg->soft_fc || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) { return 0; } while (hg->soft_fc && atomic_read(&hg->txwnd) < TXWND_INIT_VAL && test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && !test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) && !test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags) && !test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) { err = hgicf_request_txwnd(hg->bus); if (!err) { wait_for_completion_timeout(&hg->txwnd_cp, msecs_to_jiffies(100)); } if(atomic_read(&hg->txwnd) < TXWND_INIT_VAL) msleep(10); } if (!hg->soft_fc || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) { return 0; } if (atomic_read(&hg->txwnd) < TXWND_INIT_VAL) { return -1; } else { atomic_dec(&hg->txwnd); } return 0; } static void hgicf_test_work(struct work_struct *work) { int ret = 0; u32 diff_jiff = 0; struct hgicf_wdev *hg = NULL; struct sk_buff *skb = NULL; struct hgic_frm_hdr *frmhdr = NULL; printk("start if test ...\r\n"); hg = container_of(work, struct hgicf_wdev, test_work); hg->test_jiff = jiffies; //set_bit(HGIC_BUS_FLAGS_DISABLE_REINIT, &hg->bus->flags); while (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) { if (time_after(jiffies, hg->test_jiff + msecs_to_jiffies(5000))) { diff_jiff = jiffies_to_msecs(jiffies - hg->test_jiff); diff_jiff /= 1000; if (diff_jiff == 0) { diff_jiff = 0xffff; } printk("HGIC IF TEST: tx:%d KB/s, rx:%d KB/s (%d %d %d)\r\n", (hg->test_tx_len / 1024) / diff_jiff, (hg->test_rx_len / 1024) / diff_jiff, hg->test_tx_len, hg->test_rx_len, diff_jiff); hg->test_rx_len = 0; hg->test_tx_len = 0; hg->test_jiff = jiffies; } skb = dev_alloc_skb(1500 + hg->bus->drv_tx_headroom); if (skb) { skb_reserve(skb, hg->bus->drv_tx_headroom); frmhdr = (struct hgic_frm_hdr *)skb->data; frmhdr->hdr.magic = HGIC_HDR_TX_MAGIC; frmhdr->hdr.type = (hg->if_test == 1 ? HGIC_HDR_TYPE_TEST : HGIC_HDR_TYPE_TEST2); frmhdr->hdr.length = 1500; frmhdr->hdr.ifidx = 0; frmhdr->hdr.cookie = hgicf_data_cookie(hg); if(hg->if_test == 3) memset(skb->data+8, 0xAA, 1500-8); skb_put(skb, 1500); while (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && hgicf_check_txwnd(hg)) { msleep(10); } ret = hg->bus->tx_packet(hg->bus, skb); if (ret) { msleep(10); } } else { msleep(10); } } printk("if test stop!\r\n"); } static void hgicf_tx_work(struct work_struct *work) { struct sk_buff *skb = NULL; struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, tx_work); struct hgic_hdr *hdr = NULL; //hgic_dbg("Enter\n"); _CTRLQ_TX: while (!skb_queue_empty(&hg->ctrl.txq)) { if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) || !test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) { hgic_clear_queue(&hg->ctrl.txq); goto _CTRLQ_TX; } if (hgicf_check_txwnd(hg)) { msleep(10); continue; } skb = skb_dequeue(&hg->ctrl.txq); if(skb){ hdr = (struct hgic_hdr *)skb->data; switch(hdr->type){ case HGIC_HDR_TYPE_BOOTDL: break; case HGIC_HDR_TYPE_BOOTDL_DATA: skb_pull(skb, sizeof(struct hgic_bootdl_cmd_hdr)); break; default: if(test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)){ kfree_skb(skb); skb = NULL; } break; } } if(skb){ hg->bus->tx_packet(hg->bus, skb); } } while (!skb_queue_empty(&hg->tx_dataq) && test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && !test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags)) { if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) { hgic_clear_queue(&hg->tx_dataq); goto _CTRLQ_TX; } if (hgicf_check_txwnd(hg)) { msleep(10); goto _CTRLQ_TX; } skb = skb_dequeue(&hg->tx_dataq); hg->bus->tx_packet(hg->bus, skb); if (!skb_queue_empty(&hg->ctrl.txq)) { goto _CTRLQ_TX; } } //hgic_dbg("Leave\n"); } static struct hgicf_vif *hgicf_create_iface(struct hgicf_wdev *hg) { int ret = 0; struct net_device *ndev = NULL; struct hgicf_vif *vif = NULL; hgic_dbg("Enter\n"); ndev = ALLOC_NETDEV_MQS(sizeof(struct hgicf_vif), ifname, hgicf_netif_setup, 1, 1); if (!ndev) { hgic_err("%s: alloc_netdev_mqs failed\n", __func__); return NULL; } vif = (struct hgicf_vif *)netdev_priv(ndev); vif->ndev = ndev; vif->hg = hg; vif->state = 0; ndev->needed_headroom += (hg->bus->drv_tx_headroom + sizeof(struct hgic_frm_hdr2)); memcpy(ndev->dev_addr, hg->fwinfo.mac, ETH_ALEN); ret = register_netdev(ndev); if (ret) { free_netdev(ndev); return NULL; } #ifndef __RTOS__ rtnl_lock(); DEV_OPEN(ndev); rtnl_unlock(); #endif return vif; } static int hgicf_rx_data(void *hgobj, struct sk_buff *skb, int len) { int i = 0; struct hgic_frm_hdr2 *hdr = NULL; struct hgicf_wdev *hg = hgobj; hgic_skip_padding(skb); hdr = (struct hgic_frm_hdr2 *) skb->data; skb->dev = MATCH_NDEV(hdr->hdr.ifidx, hg); if (hdr->hdr.magic != HGIC_HDR_RX_MAGIC) { hgic_err("invalid magic unmber:%x\r\n", hdr->hdr.magic); hgic_print_hex(skb->data, 16); dev_kfree_skb_any(skb); return -1; } if (hdr->hdr.type != HGIC_HDR_TYPE_BOOTDL) { if (len < hdr->hdr.length) { hgic_err("invalid data length: %x/%x,cookie:%d\r\n", len, hdr->hdr.length, hdr->hdr.cookie); dev_kfree_skb_any(skb); return -1; } } skb_put(skb, len > hdr->hdr.length ? hdr->hdr.length : len); switch (hdr->hdr.type) { case HGIC_HDR_TYPE_FRM2: hg->last_rx = jiffies; if (skb->dev == NULL || hg->if_test) { dev_kfree_skb_any(skb); break; } skb_pull(skb, sizeof(struct hgic_frm_hdr2)); skb->protocol = eth_type_trans(skb, skb->dev); if (in_interrupt()) { netif_rx(skb); } else { netif_rx_ni(skb); } break; case HGIC_HDR_TYPE_CMD: case HGIC_HDR_TYPE_CMD2: case HGIC_HDR_TYPE_EVENT: case HGIC_HDR_TYPE_EVENT2: case HGIC_HDR_TYPE_OTA: case HGIC_HDR_TYPE_BOOTDL: if (hg->if_test) { dev_kfree_skb_any(skb); break; } hgic_fwctrl_rx(&hg->ctrl, skb); break; case HGIC_HDR_TYPE_TEST2: hg->last_rx = jiffies; hg->test_rx_len += len; if (hg->if_test == 3) { for (i = 8; i < 1500; i++) { if (skb->data[i] != 0xAA) { printk("data verify fail\r\n"); break; } } } dev_kfree_skb(skb); break; case HGIC_HDR_TYPE_SOFTFC: hg->last_rx = jiffies; atomic_set(&hg->txwnd, hdr->hdr.cookie); complete(&hg->txwnd_cp); dev_kfree_skb_any(skb); break; default: hgic_err("invalid data:%d\r\n", hdr->hdr.type); dev_kfree_skb_any(skb); break; } return 0; } static void hgicf_tx_complete(void *hgobj, struct sk_buff *skb, int success) { struct hgicf_wdev *hg = hgobj; if (hg->if_test) { hg->test_tx_len += skb->len; } dev_kfree_skb_any(skb); if (!success) { hgic_err("tx failed\r\n"); } } static int hgicf_download_fw(struct hgicf_wdev *hg) { int err = -1; int retry = 10; int status = -1; hgic_dbg("Enter\n"); if (no_bootdl || qc_mode) { status = STATE_FW; } set_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags); while (status != STATE_FW && retry-- > 0 && err) { status = hgic_bootdl_cmd_enter(&hg->bootdl); if (status == STATE_BOOT) { err = hgic_bootdl_download(&hg->bootdl, fw_file); } } clear_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags); if (status == STATE_BOOT && !err) { set_bit(HGICF_DEV_FLAGS_BOOTDL, &hg->flags); if (hg->bus->reinit && test_bit(HGIC_BUS_FLAGS_NOPOLL, &hg->bus->flags)) { msleep(100); retry = 4; if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && !hg->bus->reinit(hg->bus)) { while (retry-- > 0 && (STATE_FW != status)) { status = hgic_bootdl_cmd_enter(&hg->bootdl); } } } } if(!no_bootdl && hg->bus->reinit){ mod_timer(&hg->alive_tmr, jiffies + msecs_to_jiffies(HGIC_ALIVE_TIMER*4)); } return (status == STATE_FW); } static void hgicf_delay_init(struct work_struct *work) { int ret = 0; u8 retry = 0; int conn_stat = 0; struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, delay_init); hgic_dbg("Enter\n"); while(!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) && test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)){ if((retry & 0xf) == 0){ ret = hgicf_download_fw(hg); if(ret) break; } msleep(10); retry++; } if (ret) { clear_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags); hg->last_rx = jiffies; hg->soft_fc = soft_fc; conn_stat = hgic_fwctrl_get_conn_state(&hg->ctrl); #ifndef __RTOS__ hgic_fwctrl_get_dhcpc_result(&hg->ctrl, (u8 *)&hg->dhcpc, sizeof(hg->dhcpc)); #endif hgic_fwctrl_get_fwinfo(&hg->ctrl, &hg->fwinfo); printk("hgic fw info:%d.%d.%d.%d, svn version:%d, %pM, conn_state:%d\r\n", (hg->fwinfo.version >> 24) & 0xff, (hg->fwinfo.version >> 16) & 0xff, (hg->fwinfo.version >> 8) & 0xff, (hg->fwinfo.version & 0xff), hg->fwinfo.svn_version, hg->fwinfo.mac, conn_stat); if (!test_bit(HGICF_DEV_FLAGS_INITED, &hg->flags)) { hg->sta = hgicf_create_iface(hg); if (!hg->sta) { hgic_err("create iface fail, ret:%d\r\n", ret); return; } hg->sta->fwifidx = HGIC_WDEV_ID_STA; hg->sta->hw_state = conn_stat; hgicf_create_procfs(hg); if (init_cb) { init_cb(0); } if (if_test) { hg->if_test = if_test; queue_work(hg->tx_wq, &hg->test_work); } set_bit(HGICF_DEV_FLAGS_INITED, &hg->flags); } if ((test_bit(HGICF_DEV_FLAGS_BOOTDL, &hg->flags) || conn_stat != HGICF_HW_CONNECTED) && !qc_mode) { hgicf_load_config(hg); } } hgic_dbg("Leave, ret=%d\n", ret); } static void hgicf_alive_work(struct work_struct *work) { int retry = 4; int status = -1; struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, alive_work); //hgic_dbg("SLEEP:%d\r\n", test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags)); if(!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags)){ if(time_after(jiffies, hg->last_rx + msecs_to_jiffies(HGIC_ALIVE_TIMER))){ //hgic_dbg("detect device status ...\r\n"); while(retry-- > 0 && status != STATE_FW){ status = hgic_bootdl_cmd_enter(&hg->bootdl); } if (status != STATE_FW) { hgic_dbg("need reload firmware ...\r\n"); hg->soft_fc = 0; set_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags); hgic_clear_queue(&hg->ctrl.txq); hgic_clear_queue(&hg->tx_dataq); hg->bus->reinit(hg->bus); schedule_work(&hg->delay_init); } } } //hgic_dbg("next detect after %d sec.\r\n", HGIC_ALIVE_TIMER); mod_timer(&hg->alive_tmr, jiffies + msecs_to_jiffies(HGIC_ALIVE_TIMER)); } #ifdef __RTOS__ static void hgicf_alive_timer(unsigned long arg) { struct hgicf_wdev *hg = (struct hgicf_wdev *) arg; schedule_work(&hg->alive_work); } #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) static void hgicf_alive_timer(struct timer_list *t) { struct hgicf_wdev *hg = from_timer(hg, t, alive_tmr); schedule_work(&hg->alive_work); } #else static void hgicf_alive_timer(unsigned long arg) { struct hgicf_wdev *hg = (struct hgicf_wdev *) arg; schedule_work(&hg->alive_work); } #endif #endif void hgic_schedule(struct hgic_fwctrl *ctrl) { struct hgicf_wdev *hg = container_of(ctrl, struct hgicf_wdev, ctrl); queue_work(hg->tx_wq, &hg->tx_work); } void hgic_rx_fw_event(struct hgic_fwctrl *ctrl, struct sk_buff *skb) { struct hgicf_wdev *hg = container_of(ctrl, struct hgicf_wdev, ctrl); hgicf_rx_fw_event(hg, skb); } int hgic_core_remove(void *hgobj) { struct hgicf_wdev *hg = hgobj; if (hg) { hgic_dbg("Enter\n"); clear_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags); del_timer_sync(&hg->alive_tmr); cancel_work_sync(&hg->alive_work); cancel_work_sync(&hg->delay_init); hgic_dbg(" trace ...\r\n"); if (hg->ap) { netif_stop_queue(hg->ap->ndev); } if (hg->sta) { netif_stop_queue(hg->sta->ndev); } hgicf_delete_procfs(hg); hgic_fwctrl_release(&hg->ctrl); hgic_dbg(" trace ...\r\n"); hgic_ota_release(&hg->ota); hgic_dbg(" trace ...\r\n"); hgic_bootdl_release(&hg->bootdl, 0); hgic_dbg(" trace ...\r\n"); //while (!test_bit(HGICF_DEV_FLAGS_STOP, &hg->flags)); cancel_work_sync(&hg->tx_work); hgic_dbg(" trace ...\r\n"); cancel_work_sync(&hg->test_work); hgic_dbg(" trace ... %p\r\n", hg->ap); if (hg->ap) { unregister_netdev(hg->ap->ndev); } hgic_dbg(" trace ... %p\r\n", hg->sta); if (hg->sta) { unregister_netdev(hg->sta->ndev); } hgic_dbg(" trace ...\r\n"); hgic_clear_queue(&hg->tx_dataq); hgic_dbg(" trace ...\r\n"); #ifdef __RTOS__ skb_queue_head_deinit(&hg->tx_dataq); #else hgic_clear_queue(&hg->custmgmt_q); hgic_clear_queue(&hg->dbginfo_q); hgic_clear_queue(&hg->cust_driverdata_q); #endif hgic_dbg(" trace ...\r\n"); if (hg->tx_wq) { flush_workqueue(hg->tx_wq); destroy_workqueue(hg->tx_wq); } hgic_dbg(" trace ...\r\n"); #ifdef __RTOS__ deinit_completion(&hg->txwnd_cp); spin_lock_deinit(&hg->lock); #endif if(hg->paired_stas) kfree(hg->paired_stas); kfree(hg); hgic_dbg("Leave\n"); } return 0; } EXPORT_SYMBOL(hgic_core_remove); int hgic_core_probe(void *dev, struct hgic_bus *bus) { struct hgicf_wdev *hg = NULL; hgic_dbg("Enter,qc_mode=%d, no_bootdl=%d\n", qc_mode, no_bootdl); hg = kzalloc(sizeof(struct hgicf_wdev), GFP_KERNEL); if (hg) { memset(hg, 0, sizeof(struct hgicf_wdev)); hg->ctrl.qc_mode = qc_mode; hg->bus = bus; hg->dev = dev; hg->dev_id = bus->dev_id; hgic_fwctrl_init(&hg->ctrl, dev); hgic_ota_init(&hg->ota, &hg->ctrl, &hg->fwinfo); spin_lock_init(&hg->lock); INIT_WORK(&hg->tx_work, hgicf_tx_work); INIT_WORK(&hg->delay_init, hgicf_delay_init); INIT_WORK(&hg->alive_work, hgicf_alive_work); INIT_WORK(&hg->test_work, hgicf_test_work); init_timer(&hg->alive_tmr); setup_timer(&hg->alive_tmr, hgicf_alive_timer, (unsigned long)hg); skb_queue_head_init(&hg->tx_dataq); init_completion(&hg->txwnd_cp); hgic_bootdl_init(&hg->bootdl, hg->bus, &hg->ctrl); #ifndef __RTOS__ skb_queue_head_init(&hg->custmgmt_q); skb_queue_head_init(&hg->dbginfo_q); skb_queue_head_init(&hg->cust_driverdata_q); sema_init(&hg->evtq.sema, 0); #endif atomic_set(&hg->txwnd, TXWND_INIT_VAL); bus->rx_packet = hgicf_rx_data; bus->tx_complete = hgicf_tx_complete; bus->bus_priv = hg; hg->tx_wq = ALLOC_ORDERED_WORKQUEUE("hgicf_tx", 4096); if (!hg->tx_wq) { goto __failed; } set_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags); hgic_dbg("ok\n"); return 0; } __failed: bus->rx_packet = NULL; bus->tx_complete = NULL; bus->bus_priv = NULL; hgic_core_remove(hg); hgic_dbg("fail\n"); return -1; } EXPORT_SYMBOL(hgic_core_probe); #ifdef CONFIG_PM int hgic_core_suspend(void *hgobj) { int err = 0; struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj; err = hgic_fwctrl_enter_sleep(&hg->ctrl, 1); set_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags); return err; } EXPORT_SYMBOL(hgic_core_suspend); int hgic_core_resume(void *hgobj) { int err = 0; struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj; clear_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags); if (hg->bus->reinit) { hg->bus->reinit(hg->bus); } err = hgic_fwctrl_enter_sleep(&hg->ctrl, 0); if(err) hgic_err("exit sleep fail, ret=%d\r\n", err); schedule_work(&hg->alive_work); return err; } EXPORT_SYMBOL(hgic_core_resume); #endif void hgic_core_probe_post(void *priv) { struct hgicf_wdev *hg = (struct hgicf_wdev *)priv; schedule_work(&hg->delay_init); } EXPORT_SYMBOL(hgic_core_probe_post); #ifdef __RTOS__ int hgic_ifbus_reinit(const char *ifname) { struct hgicf_vif *vif = NULL; struct net_device *ndev = net_device_get_by_name(ifname); if (ndev) { vif = (struct hgicf_vif *)netdev_priv(ndev); if (vif->hg->bus->reinit) { return vif->hg->bus->reinit(vif->hg->bus); } } return 0; } struct hgic_ota *hgic_devota(struct net_device *dev) { struct hgicf_vif *vif = NULL; if (dev == NULL) { return NULL; } vif = (struct hgicf_vif *)netdev_priv(dev); return &(vif->hg->ota); } #endif int __init hgicf_init(void) { VERSOIN_SHOW("fmac"); #ifdef __RTOS__ rcu_init(); tasklet_core_init(); net_device_init(); #else #ifdef CONFIG_HGIC_USBIN hgic_usb_init(); #endif #ifdef CONFIG_HGIC_SDIOIN hgic_sdio_init(); #endif #endif hgic_leave(); return 0; } void __exit hgicf_exit(void) { #ifndef __RTOS__ #ifdef CONFIG_HGIC_USBIN hgic_usb_exit(); #endif #ifdef CONFIG_HGIC_SDIOIN hgic_sdio_exit(); #endif #endif #ifdef __RTOS__ net_device_exit(); tasklet_core_exit(); #endif } const char *hgic_param_ifname(const char *name) { if (name) ifname = (char *)name; return ifname; } #ifdef __RTOS__ void hgic_param_iftest(int iftest) { if_test = iftest; } char *hgic_param_fwfile(const char *fw) { if (fw) fw_file = fw; return fw_file; } int hgic_param_ifcount(int count) { if (count) iface_cnt = count; return iface_cnt; } void hgic_param_initcb(hgic_init_cb cb) { init_cb = cb; } void hgic_param_eventcb(hgic_event_cb cb) { event_cb = cb; } void hgic_param_bootdl(int enable) { no_bootdl = !enable; } #endif void hgicf_event(struct hgicf_wdev *hg, char *name, int event, int param1, int param2) { #ifdef __RTOS__ if(event_cb) event_cb(name, event, param1, param2); #else FWEVTQ_SET(&hg->evtq, event); up(&hg->evtq.sema); #endif } module_init(hgicf_init); module_exit(hgicf_exit); module_param(txq_size, int, 0); module_param(fw_file, charp, 0644); module_param(if_test, int, 0); module_param(soft_fc, int, 0); module_param(ifname, charp, 0644); module_param(conf_file, charp, 0644); module_param(no_bootdl, int, 0); module_param(qc_mode, int, 0); MODULE_DESCRIPTION("HUGE-IC FullMAC Wireless Card Driver"); MODULE_AUTHOR("Dongyun"); MODULE_LICENSE("GPL");