0
0
Fork 0
hgicf/hgic_fmac/core.c

1152 lines
34 KiB
C
Raw Normal View History

2023-05-16 09:13:19 +00:00
#ifdef __RTOS__
#include <linux/types.h>
#include <linux/unaligned.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/completion.h>
#include <linux/rcu.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#else
#include <linux/version.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/workqueue.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <linux/version.h>
#include <linux/rtnetlink.h>
#endif
#include "hgicf.h"
#include "ctrl.h"
#include "event.h"
static int txq_size = 1024;
2023-10-12 23:37:43 +00:00
static int if_test = 0;
2023-05-16 09:13:19 +00:00
static int no_bootdl = 0;
static int qc_mode = 0;
static char *ifname = "hg%d";
2023-10-12 23:37:43 +00:00
static int if_agg = 0;
static char *conf_file = "/etc/hgicf.conf";
static int proc_dev = 0;
static char *fw_file = "hgicf.bin";
2023-05-16 09:13:19 +00:00
#ifdef __RTOS__
2023-10-12 23:37:43 +00:00
static hgic_init_cb init_cb = NULL;
2023-05-16 09:13:19 +00:00
static hgic_event_cb event_cb = NULL;
#endif
2023-10-12 23:37:43 +00:00
static const u16 hgic_fmac_devid[] = {
HGIC_WLAN_4002,
HGIC_WLAN_8400,
};
#define TXWND_INIT_VAL (3)
2023-05-16 09:13:19 +00:00
#ifdef __RTOS__
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
2023-10-12 23:37:43 +00:00
static u8 hgicf_match_devid(u16 dev_id)
{
int i = 0;
for (i = 0; i < ARRAYSIZE(hgic_fmac_devid); i++) {
if (dev_id == hgic_fmac_devid[i]) {
return 1;
}
}
return 0;
}
static u16 hgicf_data_cookie(struct hgicf_wdev *hg)
2023-05-16 09:13:19 +00:00
{
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;
}
2023-10-12 23:37:43 +00:00
static void hgicf_load_config(struct hgicf_wdev *hg)
2023-05-16 09:13:19 +00:00
{
#ifndef __RTOS__
struct file *fp = NULL;
struct iwreq wrqin;
2023-10-12 23:37:43 +00:00
struct net_device *ndev = hg->vif->ndev;
2023-05-16 09:13:19 +00:00
ssize_t ret = 0;
char *conf = kzalloc(2048, GFP_KERNEL);
char *ptr, *str;
2023-10-12 23:37:43 +00:00
char path[64];
2023-05-16 09:13:19 +00:00
2023-10-12 23:37:43 +00:00
if (strstr(conf_file, ".conf")) {
strcpy(path, conf_file);
} else {
sprintf(path, "%s/%s.conf", conf_file, ndev->name);
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
fp = filp_open(path, O_RDONLY, 0);
2023-05-16 09:13:19 +00:00
if (!IS_ERR(fp) && conf) {
2023-10-12 23:37:43 +00:00
hgic_err("load conf file: %s\r\n", path);
ret = _KERNEL_READ(fp, conf, 2048);
2023-05-16 09:13:19 +00:00
str = conf;
while (str) {
2023-10-12 23:37:43 +00:00
ptr = strchr(str, '\n');
2023-05-16 09:13:19 +00:00
if (ptr) {
2023-10-12 23:37:43 +00:00
if (*(ptr - 1) == '\r') {
*(ptr - 1) = 0;
}
*ptr++ = 0;
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
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;
}
2023-10-12 23:37:43 +00:00
} else {
hgic_err("can not open %s\r\n", path);
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
if (!IS_ERR(fp)) {
filp_close(fp, NULL);
}
if (conf) {
kfree(conf);
}
2023-05-16 09:13:19 +00:00
#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;
}
2023-10-12 23:37:43 +00:00
vif->opened = 1;
return hgic_fwctrl_open_dev(&(vif->hg->ctrl), vif->fwifidx);
2023-05-16 09:13:19 +00:00
}
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;
}
2023-10-12 23:37:43 +00:00
vif->opened = 0;
return hgic_fwctrl_close_dev(&(vif->hg->ctrl), vif->fwifidx);
2023-05-16 09:13:19 +00:00
}
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;
2023-10-12 23:37:43 +00:00
u8 pad = ((ulong)skb->data & 0x3); //push offset | <--|data .....|
2023-05-16 09:13:19 +00:00
2023-10-12 23:37:43 +00:00
if (!test_bit(HGICF_DEV_FLAGS_RUNNING, &vif->hg->flags) || (vif->hg->tx_dataq.qlen > txq_size) ||
2023-05-16 09:13:19 +00:00
test_bit(HGIC_BUS_FLAGS_SLEEP, &vif->hg->bus->flags)) {
dev_kfree_skb(skb);
2023-10-12 23:37:43 +00:00
vif->stats.tx_dropped += skb->len;
2023-05-16 09:13:19 +00:00
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;
2023-10-12 23:37:43 +00:00
pad = ((ulong)skb->data & 0x3);
2023-05-16 09:13:19 +00:00
}
#endif
hdr = (struct hgic_frm_hdr2 *)skb_push(skb, sizeof(struct hgic_frm_hdr2) + pad);
hdr->hdr.ifidx = vif->fwifidx;
2023-10-12 23:37:43 +00:00
hdr->hdr.length = cpu_to_le16(skb->len);
hdr->hdr.magic = cpu_to_le16(HGIC_HDR_TX_MAGIC);
2023-05-16 09:13:19 +00:00
hdr->hdr.type = HGIC_HDR_TYPE_FRM2;
hdr->hdr.flags = pad;
skb_queue_tail(&vif->hg->tx_dataq, skb);
queue_work(vif->hg->tx_wq, &vif->hg->tx_work);
2023-10-12 23:37:43 +00:00
vif->stats.tx_bytes += skb->len;
2023-05-16 09:13:19 +00:00
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;
}
2023-10-12 23:37:43 +00:00
ret = hgic_fwctrl_set_mac(&(vif->hg->ctrl), vif->fwifidx, sa->sa_data);
2023-05-16 09:13:19 +00:00
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
2023-10-12 23:37:43 +00:00
static struct net_device_stats *hgicf_netdev_get_stats(struct net_device *ndev)
{
struct hgicf_vif *vif = (struct hgicf_vif *)netdev_priv(ndev);
return &vif->stats;
}
2023-05-16 09:13:19 +00:00
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,
2023-10-12 23:37:43 +00:00
.ndo_get_stats = hgicf_netdev_get_stats,
2023-05-16 09:13:19 +00:00
};
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);
2023-10-12 23:37:43 +00:00
if (skb == NULL) {
return -ENOMEM;
}
2023-05-16 09:13:19 +00:00
hdr = (struct hgic_hdr *)skb->data;
2023-10-12 23:37:43 +00:00
hdr->magic = cpu_to_le16(HGIC_HDR_TX_MAGIC);
hdr->length = cpu_to_le16(sizeof(struct hgic_hdr) + 2);
hdr->cookie = 0;
2023-05-16 09:13:19 +00:00
hdr->type = HGIC_HDR_TYPE_SOFTFC;
2023-10-12 23:37:43 +00:00
hdr->ifidx = 1;
2023-05-16 09:13:19 +00:00
hdr->flags = 0;
skb_put(skb, sizeof(struct hgic_hdr) + 2);
return bus->tx_packet(bus, skb);
}
2023-10-12 23:37:43 +00:00
static int hgicf_check_txwnd(struct hgicf_wdev *hg, u8 min_wnd)
2023-05-16 09:13:19 +00:00
{
if (!hg->soft_fc || test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
return 0;
}
2023-10-12 23:37:43 +00:00
if(test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) ||
test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags) ||
!test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)){
return -1;
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
if(atomic_read(&hg->txwnd) < min_wnd){
hgicf_request_txwnd(hg->bus);
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
if (atomic_read(&hg->txwnd) < min_wnd) {
2023-05-16 09:13:19 +00:00
return -1;
} else {
atomic_dec(&hg->txwnd);
}
return 0;
}
2023-10-12 23:37:43 +00:00
static void hgicf_tx_complete(void *hgobj, struct sk_buff *skb, int success)
{
struct hgic_ctrl_hdr *hdr = (struct hgic_ctrl_hdr *)skb->data;
struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj;
if (hg->if_test) {
hg->test_tx_len += skb->len;
}
if (success) {
clear_bit(HGIC_BUS_FLAGS_ERROR, &hg->bus->flags);
} else {
hgic_err("tx failed\r\n");
if (hdr->hdr.magic == cpu_to_le16(HGIC_HDR_TX_MAGIC)) {
if ((hdr->hdr.type == HGIC_HDR_TYPE_CMD || hdr->hdr.type == HGIC_HDR_TYPE_CMD2) && HDR_CMDID(hdr) == HGIC_CMD_ENTER_SLEEP) {
clear_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags);
}
}
hg->status.tx_fail++;
set_bit(HGIC_BUS_FLAGS_ERROR, &hg->bus->flags);
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
schedule_work(&hg->detect_work);
}
}
dev_kfree_skb_any(skb);
}
2023-05-16 09:13:19 +00:00
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;
2023-10-12 23:37:43 +00:00
frmhdr->hdr.magic = cpu_to_le16(HGIC_HDR_TX_MAGIC);
frmhdr->hdr.length = cpu_to_le16(1500);
frmhdr->hdr.cookie = cpu_to_le16(hgicf_data_cookie(hg));
2023-05-16 09:13:19 +00:00
frmhdr->hdr.type = (hg->if_test == 1 ? HGIC_HDR_TYPE_TEST : HGIC_HDR_TYPE_TEST2);
frmhdr->hdr.ifidx = 0;
2023-10-12 23:37:43 +00:00
if (hg->if_test == 3) {
memset(skb->data + 8, 0xAA, 1500 - 8);
}
2023-05-16 09:13:19 +00:00
skb_put(skb, 1500);
2023-10-12 23:37:43 +00:00
while (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) && hgicf_check_txwnd(hg, TXWND_INIT_VAL)) {
2023-05-16 09:13:19 +00:00
msleep(10);
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
ret = hg->bus->tx_packet(hg->bus, skb);
if (ret) {
msleep(10);
}
} else {
msleep(10);
}
}
2023-10-12 23:37:43 +00:00
hgic_dbg("if test stop!\r\n");
}
static void hgicf_tx_single_frm(struct hgicf_wdev *hg, struct sk_buff *skb)
{
struct hgic_frm_hdr2 *hdr = NULL;
hg->status.tx_data++;
hdr = (struct hgic_frm_hdr2 *)skb->data;
hdr->hdr.cookie = cpu_to_le16(hgicf_data_cookie(hg));
hg->bus->tx_packet(hg->bus, skb);
}
static void hgicf_tx_agg_frm(struct hgicf_wdev *hg, struct sk_buff *skb)
{
struct sk_buff *agg_skb;
struct hgic_frm_hdr2 *hdr = NULL;
struct hgic_hdr *agghdr = NULL;
int cpylen = 0;
agg_skb = dev_alloc_skb(hg->bus->drv_tx_headroom + if_agg);
if (agg_skb) {
agghdr = (struct hgic_hdr *)agg_skb->data;
memset(agghdr, 0, sizeof(struct hgic_hdr));
agghdr->magic = cpu_to_le16(HGIC_HDR_TX_MAGIC);
agghdr->type = HGIC_HDR_TYPE_AGGFRM;
agghdr->length = sizeof(struct hgic_hdr);
agghdr->cookie = cpu_to_le16(hgicf_data_cookie(hg));
do {
hdr = (struct hgic_frm_hdr2 *)skb->data;
cpylen = hdr->hdr.length;
if (agghdr->length + ALIGN(cpylen, 4) > if_agg) {
skb_queue_head(&hg->tx_dataq, skb);
break;
}
hdr->hdr.length = ALIGN(cpylen, 4);
hdr->hdr.cookie = cpu_to_le16(hgicf_data_cookie(hg));
memcpy(agg_skb->data + agghdr->length, skb->data, cpylen);
agghdr->length += hdr->hdr.length;
hgicf_tx_complete(hg, skb, 1);
skb = skb_dequeue(&hg->tx_dataq);
} while (skb);
if (agghdr->length > sizeof(struct hgic_hdr)) {
hg->status.tx_data++;
skb_put(agg_skb, agghdr->length);
hg->bus->tx_packet(hg->bus, agg_skb);
} else {
hgic_err("invalid agg frm, cookie:%d\r\n", agghdr->cookie);
dev_kfree_skb(agg_skb);
}
} else {
hgicf_tx_single_frm(hg, skb);
}
}
static void hgicf_tx_ctrl_frm(struct hgicf_wdev *hg)
{
int err = 0;
struct hgic_ctrl_hdr *hdr = NULL;
struct sk_buff *skb = skb_dequeue(&hg->ctrl.txq);
if (skb) {
hdr = (struct hgic_ctrl_hdr *)skb->data;
switch (hdr->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->status.tx_ctrl++;
err = hg->bus->tx_packet(hg->bus, skb);
if (!err && (hdr->hdr.type == HGIC_HDR_TYPE_CMD || hdr->hdr.type == HGIC_HDR_TYPE_CMD2)) {
if (HDR_CMDID(hdr) == HGIC_CMD_ENTER_SLEEP) {
set_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags);
}
}
}
2023-05-16 09:13:19 +00:00
}
static void hgicf_tx_work(struct work_struct *work)
{
2023-10-12 23:37:43 +00:00
struct sk_buff *skb;
2023-05-16 09:13:19 +00:00
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, tx_work);
//hgic_dbg("Enter\n");
_CTRLQ_TX:
while (!skb_queue_empty(&hg->ctrl.txq)) {
if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) ||
2023-10-12 23:37:43 +00:00
!test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
2023-05-16 09:13:19 +00:00
hgic_clear_queue(&hg->ctrl.txq);
goto _CTRLQ_TX;
}
2023-10-12 23:37:43 +00:00
#if 0
if (hgicf_check_txwnd(hg, 1)) {
2023-05-16 09:13:19 +00:00
msleep(10);
continue;
}
2023-10-12 23:37:43 +00:00
#endif
hgicf_tx_ctrl_frm(hg);
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
while (!skb_queue_empty(&hg->tx_dataq) && hg->fw_state == STATE_FW &&
test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags) &&
2023-05-16 09:13:19 +00:00
!test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags)) {
2023-10-12 23:37:43 +00:00
if (test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) ||
2023-05-16 09:13:19 +00:00
test_bit(HGIC_BUS_FLAGS_INBOOT, &hg->bus->flags)) {
hgic_clear_queue(&hg->tx_dataq);
goto _CTRLQ_TX;
}
2023-10-12 23:37:43 +00:00
if (hgicf_check_txwnd(hg, TXWND_INIT_VAL)) {
2023-05-16 09:13:19 +00:00
msleep(10);
goto _CTRLQ_TX;
}
skb = skb_dequeue(&hg->tx_dataq);
2023-10-12 23:37:43 +00:00
if (skb) {
if (!skb_queue_empty(&hg->tx_dataq) && if_agg) {
hgicf_tx_agg_frm(hg, skb);
} else {
hgicf_tx_single_frm(hg, skb);
}
}
2023-05-16 09:13:19 +00:00
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;
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
vif = (struct hgicf_vif *)netdev_priv(ndev);
vif->ndev = ndev;
vif->hg = hg;
2023-10-12 23:37:43 +00:00
vif->opened = 0;
ndev->needed_headroom += (hg->bus->drv_tx_headroom + sizeof(struct hgic_frm_hdr2) + 4);
2023-10-12 23:44:32 +00:00
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
2023-05-16 09:13:19 +00:00
memcpy(ndev->dev_addr, hg->fwinfo.mac, ETH_ALEN);
2023-10-12 23:44:32 +00:00
#else
eth_hw_addr_set(ndev, hg->fwinfo.mac);
#endif
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
ret = register_netdev(ndev);
if (ret) {
free_netdev(ndev);
return NULL;
}
return vif;
}
2023-10-12 23:37:43 +00:00
static void hgicf_rx_single_frm(struct hgicf_wdev *hg, u8 *data, int len)
{
struct sk_buff *skb;
struct hgic_hdr *hdr = (struct hgic_hdr *)data;
if (hg->vif && len > sizeof(struct hgic_frm_hdr2)) {
hg->rx_cookie = hdr->cookie;
hg->vif->stats.rx_bytes += len;
data += sizeof(struct hgic_frm_hdr2);
len -= (sizeof(struct hgic_frm_hdr2) + hdr->flags);
skb = dev_alloc_skb(len + hg->vif->ndev->needed_headroom + hg->vif->ndev->needed_tailroom);
if (skb) {
skb_reserve(skb, hg->vif->ndev->needed_headroom);
memcpy(skb->data, data, len);
skb_put(skb, len);
skb->dev = hg->vif->ndev;
skb->protocol = eth_type_trans(skb, skb->dev);
2023-10-12 23:44:32 +00:00
netif_rx(skb);
2023-10-12 23:37:43 +00:00
} else {
hg->vif->stats.rx_dropped += len;
hgic_err("alloc skb fail, len=%d\r\n", len);
}
}
}
static void hgicf_rx_agg_frm(struct hgicf_wdev *hg, u8 *data, int len)
{
struct hgic_hdr *hdr = (struct hgic_hdr *)data;
if ((u16)(hg->rx_cookie + 1) != hdr->cookie) {
hgic_err("cookie:%d-%d\r\n", hg->rx_cookie, hdr->cookie);
}
hg->rx_cookie = hdr->cookie;
data += sizeof(struct hgic_hdr);
len -= sizeof(struct hgic_hdr);
while (len > sizeof(struct hgic_frm_hdr2)) {
hdr = (struct hgic_hdr *)data;
hdr->magic = le16_to_cpu(hdr->magic);
hdr->length = le16_to_cpu(hdr->length);
hdr->cookie = le16_to_cpu(hdr->cookie);
if (hdr->magic == HGIC_HDR_RX_MAGIC && hdr->type == HGIC_HDR_TYPE_FRM2 && len >= hdr->length) {
hgicf_rx_single_frm(hg, data, hdr->length);
data += hdr->length;
len -= hdr->length;
} else {
break;
}
}
}
static int hgicf_rx_data(void *hgobj, u8 *data, int len)
2023-05-16 09:13:19 +00:00
{
int i = 0;
struct hgic_frm_hdr2 *hdr = NULL;
struct hgicf_wdev *hg = hgobj;
2023-10-12 23:37:43 +00:00
i = hgic_skip_padding(data);
data += i; len -= i;
hdr = (struct hgic_frm_hdr2 *)data;
hdr->hdr.magic = le16_to_cpu(hdr->hdr.magic);
hdr->hdr.length = le16_to_cpu(hdr->hdr.length);
hdr->hdr.cookie = le16_to_cpu(hdr->hdr.cookie);
2023-05-16 09:13:19 +00:00
if (hdr->hdr.magic != HGIC_HDR_RX_MAGIC) {
hgic_err("invalid magic unmber:%x\r\n", hdr->hdr.magic);
2023-10-12 23:37:43 +00:00
hgic_print_hex(data, 16);
2023-05-16 09:13:19 +00:00
return -1;
}
2023-10-12 23:37:43 +00:00
if (len < hdr->hdr.length && hdr->hdr.type != HGIC_HDR_TYPE_BOOTDL) {
hgic_err("invalid data length: %x/%x,cookie:%d\r\n", len, hdr->hdr.length, hdr->hdr.cookie);
return -1;
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
len = (len < hdr->hdr.length ? len : hdr->hdr.length);
2023-05-16 09:13:19 +00:00
switch (hdr->hdr.type) {
case HGIC_HDR_TYPE_FRM2:
2023-10-12 23:37:43 +00:00
case HGIC_HDR_TYPE_AGGFRM:
2023-05-16 09:13:19 +00:00
hg->last_rx = jiffies;
2023-10-12 23:37:43 +00:00
if (hg->vif == NULL || hg->if_test) {
2023-05-16 09:13:19 +00:00
break;
}
2023-10-12 23:37:43 +00:00
if (hdr->hdr.type == HGIC_HDR_TYPE_AGGFRM) {
hgicf_rx_agg_frm(hg, data, len);
} else {
hgicf_rx_single_frm(hg, data, len);
}
2023-05-16 09:13:19 +00:00
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) {
break;
}
2023-10-12 23:37:43 +00:00
hgic_fwctrl_rx(&hg->ctrl, data, len);
2023-05-16 09:13:19 +00:00
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++) {
2023-10-12 23:37:43 +00:00
if (data[i] != 0xAA) {
hgic_err("data verify fail\r\n");
2023-05-16 09:13:19 +00:00
break;
}
}
}
break;
case HGIC_HDR_TYPE_SOFTFC:
hg->last_rx = jiffies;
atomic_set(&hg->txwnd, hdr->hdr.cookie);
complete(&hg->txwnd_cp);
break;
default:
hgic_err("invalid data:%d\r\n", hdr->hdr.type);
break;
}
return 0;
}
static int hgicf_download_fw(struct hgicf_wdev *hg)
{
int err = -1;
int retry = 10;
int status = -1;
hgic_dbg("Enter\n");
2023-10-12 23:37:43 +00:00
if (no_bootdl || qc_mode) {
status = STATE_FW;
}
2023-05-16 09:13:19 +00:00
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);
}
2023-10-12 23:37:43 +00:00
if (status < 0 || err) {
msleep(10);
}
2023-05-16 09:13:19 +00:00
}
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);
}
}
}
}
2023-10-12 23:37:43 +00:00
if (!no_bootdl && hg->bus->reinit && test_bit(HGIC_BUS_FLAGS_NOPOLL, &hg->bus->flags)) {
mod_timer(&hg->detect_tmr, jiffies + msecs_to_jiffies(HGIC_DETECT_TIMER * 4));
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
hg->fw_state = status;
2023-05-16 09:13:19 +00:00
return (status == STATE_FW);
}
static void hgicf_delay_init(struct work_struct *work)
{
int ret = 0;
2023-10-12 23:37:43 +00:00
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, delay_init);
2023-05-16 09:13:19 +00:00
2023-10-12 23:37:43 +00:00
ret = hgicf_download_fw(hg);
clear_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags);
2023-05-16 09:13:19 +00:00
if (ret) {
hg->last_rx = jiffies;
2023-10-12 23:37:43 +00:00
hgic_fwctrl_get_fwinfo(&hg->ctrl, HGIC_WDEV_ID_STA, &hg->fwinfo);
printk("hgic fw info:%d.%d.%d.%d, svn version:%d, %pM, smt_dat:%u\r\n",
2023-05-16 09:13:19 +00:00
(hg->fwinfo.version >> 24) & 0xff, (hg->fwinfo.version >> 16) & 0xff,
(hg->fwinfo.version >> 8) & 0xff, (hg->fwinfo.version & 0xff),
2023-10-12 23:37:43 +00:00
hg->fwinfo.svn_version, hg->fwinfo.mac, hg->fwinfo.smt_dat);
hg->soft_fc = (hg->fwinfo.version < 0x2000000);
hg->ctrl.fwinfo = &hg->fwinfo;
if (hg->soft_fc) {
set_bit(HGIC_BUS_FLAGS_SOFTFC, &hg->bus->flags);
} else {
clear_bit(HGIC_BUS_FLAGS_SOFTFC, &hg->bus->flags);
}
2023-05-16 09:13:19 +00:00
if (!test_bit(HGICF_DEV_FLAGS_INITED, &hg->flags)) {
2023-10-12 23:37:43 +00:00
hg->vif = hgicf_create_iface(hg);
if (!hg->vif) {
2023-05-16 09:13:19 +00:00
hgic_err("create iface fail, ret:%d\r\n", ret);
return;
}
2023-10-12 23:37:43 +00:00
hg->vif->fwifidx = HGIC_WDEV_ID_STA;
2023-05-16 09:13:19 +00:00
hgicf_create_procfs(hg);
2023-10-12 23:37:43 +00:00
#ifdef __RTOS__
2023-05-16 09:13:19 +00:00
if (init_cb) { init_cb(0); }
2023-10-12 23:37:43 +00:00
#endif
2023-05-16 09:13:19 +00:00
if (if_test) {
hg->if_test = if_test;
queue_work(hg->tx_wq, &hg->test_work);
}
set_bit(HGICF_DEV_FLAGS_INITED, &hg->flags);
}
2023-10-12 23:37:43 +00:00
if (!qc_mode) {
2023-05-16 09:13:19 +00:00
hgicf_load_config(hg);
}
}
2023-10-12 23:37:43 +00:00
hgic_dbg("Leave, ret=%d, soft_fc=%d\n", ret, hg->soft_fc);
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
static void hgicf_detect_work(struct work_struct *work)
2023-05-16 09:13:19 +00:00
{
int retry = 4;
int status = -1;
2023-10-12 23:37:43 +00:00
struct hgicf_wdev *hg = container_of(work, struct hgicf_wdev, detect_work);
hg->status.detect_tmr++;
if (!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags) && test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
if (test_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags) ||
test_bit(HGIC_BUS_FLAGS_ERROR, &hg->bus->flags) ||
time_after(jiffies, hg->last_rx + msecs_to_jiffies(HGIC_DETECT_TIMER))) {
while (retry-- > 0 && status != STATE_FW) {
2023-05-16 09:13:19 +00:00
status = hgic_bootdl_cmd_enter(&hg->bootdl);
}
2023-10-12 23:37:43 +00:00
if (status != STATE_FW || hg->fw_state != STATE_FW) {
2023-05-16 09:13:19 +00:00
hgic_dbg("need reload firmware ...\r\n");
hgic_clear_queue(&hg->ctrl.txq);
hgic_clear_queue(&hg->tx_dataq);
2023-10-12 23:37:43 +00:00
if (hg->bus->reinit) {
hg->bus->reinit(hg->bus);
}
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
hg->soft_fc = 0;
hg->fw_state = -1;
set_bit(HGICF_DEV_FLAGS_SUSPEND, &hg->flags);
schedule_work(&hg->delay_init);
}
2023-05-16 09:13:19 +00:00
}
}
}
2023-10-12 23:37:43 +00:00
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
mod_timer(&hg->detect_tmr, jiffies + msecs_to_jiffies(HGIC_DETECT_TIMER));
}
2023-05-16 09:13:19 +00:00
}
2023-11-05 21:03:29 +00:00
#if !defined(__RTOS__) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
2023-10-12 23:37:43 +00:00
static void hgicf_detect_timer(struct timer_list *t)
2023-05-16 09:13:19 +00:00
{
2023-10-12 23:37:43 +00:00
struct hgicf_wdev *hg = from_timer(hg, t, detect_tmr);
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
schedule_work(&hg->detect_work);
}
2023-05-16 09:13:19 +00:00
}
#else
2023-10-12 23:37:43 +00:00
static void hgicf_detect_timer(unsigned long arg)
2023-05-16 09:13:19 +00:00
{
struct hgicf_wdev *hg = (struct hgicf_wdev *) arg;
2023-10-12 23:37:43 +00:00
if (test_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags)) {
schedule_work(&hg->detect_work);
}
2023-05-16 09:13:19 +00:00
}
#endif
2023-10-12 23:37:43 +00:00
static void hgicf_schedule(struct hgic_fwctrl *ctrl)
2023-05-16 09:13:19 +00:00
{
struct hgicf_wdev *hg = container_of(ctrl, struct hgicf_wdev, ctrl);
queue_work(hg->tx_wq, &hg->tx_work);
}
2023-10-12 23:37:43 +00:00
static void hgicf_probe_post(void *priv)
2023-05-16 09:13:19 +00:00
{
2023-10-12 23:37:43 +00:00
struct hgicf_wdev *hg = (struct hgicf_wdev *)priv;
schedule_work(&hg->delay_init);
}
#ifdef CONFIG_PM
static int hgicf_core_suspend(void *hgobj)
{
int err = 0;
struct hgicf_wdev *hg = (struct hgicf_wdev *)hgobj;
if (!test_bit(HGIC_BUS_FLAGS_SLEEP, &hg->bus->flags)) {
err = hgic_fwctrl_enter_sleep(&hg->ctrl, HGIC_WDEV_ID_STA, 1, 0xffffffff);
}
return err;
}
static int hgicf_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, HGIC_WDEV_ID_STA, 0, 0);
if (err) {
hgic_err("exit sleep fail, ret=%d\r\n", err);
}
return err;
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
#endif
2023-05-16 09:13:19 +00:00
2023-10-12 23:37:43 +00:00
static void hgicf_core_remove(void *hgobj)
2023-05-16 09:13:19 +00:00
{
struct hgicf_wdev *hg = hgobj;
if (hg) {
hgic_dbg("Enter\n");
clear_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags);
hgic_dbg(" trace ...\r\n");
2023-10-12 23:37:43 +00:00
cancel_work_sync(&hg->detect_work);
2023-05-16 09:13:19 +00:00
hgic_dbg(" trace ...\r\n");
2023-10-12 23:37:43 +00:00
del_timer_sync(&hg->detect_tmr);
2023-05-16 09:13:19 +00:00
hgic_dbg(" trace ...\r\n");
2023-10-12 23:37:43 +00:00
cancel_work_sync(&hg->detect_work);
hgic_dbg(" trace ...\r\n");
cancel_work_sync(&hg->delay_init);
if (hg->vif) {
netif_stop_queue(hg->vif->ndev);
}
2023-05-16 09:13:19 +00:00
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 ...\r\n");
2023-10-12 23:37:43 +00:00
hgicf_delete_procfs(hg);
2023-05-16 09:13:19 +00:00
hgic_dbg(" trace ...\r\n");
2023-10-12 23:37:43 +00:00
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);
2023-05-16 09:13:19 +00:00
hgic_dbg(" trace ...\r\n");
if (hg->tx_wq) {
flush_workqueue(hg->tx_wq);
destroy_workqueue(hg->tx_wq);
}
2023-10-12 23:37:43 +00:00
hgic_dbg(" trace ... %p\r\n", hg->vif);
if (hg->vif) {
unregister_netdev(hg->vif->ndev);
}
hgic_dbg(" trace ...\r\n");
hgic_clear_queue(&hg->tx_dataq);
2023-05-16 09:13:19 +00:00
hgic_dbg(" trace ...\r\n");
#ifdef __RTOS__
2023-10-12 23:37:43 +00:00
skb_queue_head_deinit(&hg->tx_dataq);
2023-05-16 09:13:19 +00:00
deinit_completion(&hg->txwnd_cp);
spin_lock_deinit(&hg->lock);
2023-10-12 23:37:43 +00:00
#else
hgic_clear_queue(&hg->evt_list);
2023-05-16 09:13:19 +00:00
#endif
kfree(hg);
hgic_dbg("Leave\n");
}
}
2023-10-12 23:37:43 +00:00
static int hgicf_core_probe(void *dev, struct hgic_bus *bus)
2023-05-16 09:13:19 +00:00
{
struct hgicf_wdev *hg = NULL;
2023-10-12 23:37:43 +00:00
if (!hgicf_match_devid(bus->dev_id)) {
hgic_err("FMAC driver not support device %x\n", bus->dev_id);
return -1;
}
hgic_dbg("qc_mode=%d, no_bootdl=%d, if_agg=%d, txq_size=%d\n", qc_mode, no_bootdl, if_agg, txq_size);
2023-05-16 09:13:19 +00:00
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;
2023-10-12 23:37:43 +00:00
hg->proc_dev = proc_dev;
hg->fw_state = -1;
hgic_fwctrl_init(&hg->ctrl, dev, bus);
hg->ctrl.schedule = hgicf_schedule;
hg->ctrl.rx_event = hgicf_rx_fw_event;
2023-05-16 09:13:19 +00:00
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);
2023-10-12 23:37:43 +00:00
INIT_WORK(&hg->detect_work, hgicf_detect_work);
2023-05-16 09:13:19 +00:00
INIT_WORK(&hg->test_work, hgicf_test_work);
2023-10-12 23:37:43 +00:00
init_timer(&hg->detect_tmr);
setup_timer(&hg->detect_tmr, hgicf_detect_timer, (unsigned long)hg);
2023-05-16 09:13:19 +00:00
skb_queue_head_init(&hg->tx_dataq);
init_completion(&hg->txwnd_cp);
hgic_bootdl_init(&hg->bootdl, hg->bus, &hg->ctrl);
#ifndef __RTOS__
2023-10-12 23:37:43 +00:00
skb_queue_head_init(&hg->evt_list);
sema_init(&hg->evt_sema, 0);
2023-05-16 09:13:19 +00:00
#endif
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
atomic_set(&hg->txwnd, TXWND_INIT_VAL);
hg->tx_wq = ALLOC_ORDERED_WORKQUEUE("hgicf_tx", 4096);
if (!hg->tx_wq) {
goto __failed;
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
set_bit(HGICF_DEV_FLAGS_RUNNING, &hg->flags);
2023-10-12 23:37:43 +00:00
bus->tx_complete = hgicf_tx_complete;
bus->rx_packet = hgicf_rx_data;
bus->probe_post = hgicf_probe_post;
bus->remove = hgicf_core_remove;
#ifdef CONFIG_PM
bus->suspend = hgicf_core_suspend;
bus->resume = hgicf_core_resume;
#endif
bus->bus_priv = hg;
2023-05-16 09:13:19 +00:00
hgic_dbg("ok\n");
return 0;
}
__failed:
2023-10-12 23:37:43 +00:00
hgicf_core_remove(hg);
2023-05-16 09:13:19 +00:00
hgic_dbg("fail\n");
return -1;
}
#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");
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
#ifdef __RTOS__
rcu_init();
tasklet_core_init();
net_device_init();
#endif
2023-10-12 23:37:43 +00:00
#ifdef CONFIG_HGIC_USB
hgic_usb_init(hgicf_core_probe, if_agg);
2023-05-16 09:13:19 +00:00
#endif
2023-10-12 23:37:43 +00:00
#ifdef CONFIG_HGIC_SDIO
hgic_sdio_init(hgicf_core_probe, if_agg);
2023-05-16 09:13:19 +00:00
#endif
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
hgic_leave();
return 0;
}
void __exit hgicf_exit(void)
{
2023-10-12 23:37:43 +00:00
#ifdef CONFIG_HGIC_USB
2023-05-16 09:13:19 +00:00
hgic_usb_exit();
#endif
2023-10-12 23:37:43 +00:00
#ifdef CONFIG_HGIC_SDIO
2023-05-16 09:13:19 +00:00
hgic_sdio_exit();
#endif
#ifdef __RTOS__
net_device_exit();
tasklet_core_exit();
#endif
}
2023-10-12 23:37:43 +00:00
#ifdef __RTOS__
2023-05-16 09:13:19 +00:00
const char *hgic_param_ifname(const char *name)
{
2023-10-12 23:37:43 +00:00
if (name) {
ifname = (char *)name;
}
2023-05-16 09:13:19 +00:00
return ifname;
}
2023-10-12 23:37:43 +00:00
2023-05-16 09:13:19 +00:00
void hgic_param_iftest(int iftest)
{
if_test = iftest;
}
char *hgic_param_fwfile(const char *fw)
{
2023-10-12 23:37:43 +00:00
if (fw) {
fw_file = fw;
}
2023-05-16 09:13:19 +00:00
return fw_file;
}
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;
}
void hgicf_event(struct hgicf_wdev *hg, char *name, int event, int param1, int param2)
{
2023-10-12 23:37:43 +00:00
if (event_cb) {
2023-05-16 09:13:19 +00:00
event_cb(name, event, param1, param2);
2023-10-12 23:37:43 +00:00
}
2023-05-16 09:13:19 +00:00
}
2023-10-12 23:37:43 +00:00
#endif
2023-05-16 09:13:19 +00:00
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(ifname, charp, 0644);
module_param(no_bootdl, int, 0);
module_param(qc_mode, int, 0);
2023-10-12 23:37:43 +00:00
module_param(if_agg, int, 0);
module_param(conf_file, charp, 0644);
module_param(proc_dev, int, 0);
2023-05-16 09:13:19 +00:00
MODULE_DESCRIPTION("HUGE-IC FullMAC Wireless Card Driver");
MODULE_AUTHOR("Dongyun");
MODULE_LICENSE("GPL");