Commit 8d169aa0 authored by Franky Lin's avatar Franky Lin Committed by John W. Linville

brcm80211: fmac: move busstate to struct brcmf_bus

busstate keeps track of the bus (USB/SDIO) status and is used by
both generic layer and bus layer. Move it to brcmf_bus helps to clean
up the interface. This patch is part of fullmac bus interface
refactoring.
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarAlwin Beukers <alwin@broadcom.com>
Reviewed-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarFranky Lin <frankyl@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 655713be
...@@ -574,6 +574,7 @@ struct brcmf_dcmd { ...@@ -574,6 +574,7 @@ struct brcmf_dcmd {
struct brcmf_bus { struct brcmf_bus {
u8 type; /* bus type */ u8 type; /* bus type */
void *bus_priv; /* pointer to bus private structure */ void *bus_priv; /* pointer to bus private structure */
enum brcmf_bus_state state;
}; };
/* Forward decls for struct brcmf_pub (see below) */ /* Forward decls for struct brcmf_pub (see below) */
...@@ -586,6 +587,7 @@ struct brcmf_cfg80211_dev; /* cfg80211 device info */ ...@@ -586,6 +587,7 @@ struct brcmf_cfg80211_dev; /* cfg80211 device info */
struct brcmf_pub { struct brcmf_pub {
/* Linkage ponters */ /* Linkage ponters */
struct brcmf_sdio *bus; struct brcmf_sdio *bus;
struct brcmf_bus *bus_if;
struct brcmf_proto *prot; struct brcmf_proto *prot;
struct brcmf_info *info; struct brcmf_info *info;
struct brcmf_cfg80211_dev *config; struct brcmf_cfg80211_dev *config;
...@@ -593,7 +595,6 @@ struct brcmf_pub { ...@@ -593,7 +595,6 @@ struct brcmf_pub {
/* Internal brcmf items */ /* Internal brcmf items */
bool up; /* Driver up/down (to OS) */ bool up; /* Driver up/down (to OS) */
bool txoff; /* Transmit flow-controlled */ bool txoff; /* Transmit flow-controlled */
enum brcmf_bus_state busstate;
uint hdrlen; /* Total BRCMF header length (proto + bus) */ uint hdrlen; /* Total BRCMF header length (proto + bus) */
uint maxctl; /* Max size rxctl request from proto to bus */ uint maxctl; /* Max size rxctl request from proto to bus */
uint rxsz; /* Rx buffer size bus module should use */ uint rxsz; /* Rx buffer size bus module should use */
...@@ -661,7 +662,6 @@ struct brcmf_pub { ...@@ -661,7 +662,6 @@ struct brcmf_pub {
u8 country_code[BRCM_CNTRY_BUF_SZ]; u8 country_code[BRCM_CNTRY_BUF_SZ];
char eventmask[BRCMF_EVENTING_MASK_LEN]; char eventmask[BRCMF_EVENTING_MASK_LEN];
}; };
struct brcmf_if_event { struct brcmf_if_event {
...@@ -687,7 +687,7 @@ extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, ...@@ -687,7 +687,7 @@ extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
* bus_hdrlen specifies required headroom for bus module header. * bus_hdrlen specifies required headroom for bus module header.
*/ */
extern struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, extern struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus,
uint bus_hdrlen); uint bus_hdrlen, struct device *dev);
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
......
...@@ -280,7 +280,7 @@ brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, ...@@ -280,7 +280,7 @@ brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
struct brcmf_proto *prot = drvr->prot; struct brcmf_proto *prot = drvr->prot;
int ret = -1; int ret = -1;
if (drvr->busstate == BRCMF_BUS_DOWN) { if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
return ret; return ret;
} }
......
...@@ -292,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) ...@@ -292,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
struct brcmf_info *drvr_priv = drvr->info; struct brcmf_info *drvr_priv = drvr->info;
/* Reject if down */ /* Reject if down */
if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
return -ENODEV; return -ENODEV;
/* Update multicast statistic */ /* Update multicast statistic */
...@@ -322,9 +322,11 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -322,9 +322,11 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
/* Reject if down */ /* Reject if down */
if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { if (!drvr_priv->pub.up ||
brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) {
drvr_priv->pub.up, drvr_priv->pub.busstate); brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n",
drvr_priv->pub.up,
drvr_priv->pub.bus_if->state);
netif_stop_queue(ndev); netif_stop_queue(ndev);
return -ENODEV; return -ENODEV;
} }
...@@ -761,7 +763,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) ...@@ -761,7 +763,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
/* send to dongle (must be up, and wl) */ /* send to dongle (must be up, and wl) */
if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) {
brcmf_dbg(ERROR, "DONGLE_DOWN\n"); brcmf_dbg(ERROR, "DONGLE_DOWN\n");
err = -EIO; err = -EIO;
goto done; goto done;
...@@ -940,7 +942,8 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) ...@@ -940,7 +942,8 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
} }
} }
struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen) struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen,
struct device *dev)
{ {
struct brcmf_info *drvr_priv = NULL; struct brcmf_info *drvr_priv = NULL;
...@@ -959,6 +962,7 @@ struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen) ...@@ -959,6 +962,7 @@ struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen)
/* Link to bus module */ /* Link to bus module */
drvr_priv->pub.bus = bus; drvr_priv->pub.bus = bus;
drvr_priv->pub.hdrlen = bus_hdrlen; drvr_priv->pub.hdrlen = bus_hdrlen;
drvr_priv->pub.bus_if = dev_get_drvdata(dev);
/* Attach and link in the protocol */ /* Attach and link in the protocol */
if (brcmf_proto_attach(&drvr_priv->pub) != 0) { if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
...@@ -995,7 +999,7 @@ int brcmf_bus_start(struct brcmf_pub *drvr) ...@@ -995,7 +999,7 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
} }
/* If bus is not ready, can't come up */ /* If bus is not ready, can't come up */
if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) {
brcmf_dbg(ERROR, "failed bus is not ready\n"); brcmf_dbg(ERROR, "failed bus is not ready\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -1068,7 +1068,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) ...@@ -1068,7 +1068,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
/* If we can't reach the device, signal failure */ /* If we can't reach the device, signal failure */
if (err || brcmf_sdcard_regfail(bus->sdiodev)) if (err || brcmf_sdcard_regfail(bus->sdiodev))
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
/* copy a buffer into a pkt buffer chain */ /* copy a buffer into a pkt buffer chain */
...@@ -1714,7 +1714,8 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) ...@@ -1714,7 +1714,8 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
*finished = false; *finished = false;
for (rxseq = bus->rx_seq, rxleft = maxframes; for (rxseq = bus->rx_seq, rxleft = maxframes;
!bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; !bus->rxskip && rxleft &&
bus->drvr->bus_if->state != BRCMF_BUS_DOWN;
rxseq++, rxleft--) { rxseq++, rxleft--) {
/* Handle glomming separately */ /* Handle glomming separately */
...@@ -2286,7 +2287,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) ...@@ -2286,7 +2287,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
} }
/* Deflow-control stack if needed */ /* Deflow-control stack if needed */
if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && if (drvr->up && (drvr->bus_if->state == BRCMF_BUS_DATA) &&
drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
brcmf_txflowcontrol(drvr, 0, OFF); brcmf_txflowcontrol(drvr, 0, OFF);
...@@ -2321,7 +2322,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) ...@@ -2321,7 +2322,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
SBSDIO_DEVICE_CTL, &err); SBSDIO_DEVICE_CTL, &err);
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
#endif /* BCMDBG */ #endif /* BCMDBG */
...@@ -2331,7 +2332,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) ...@@ -2331,7 +2332,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading CSR: %d\n", brcmf_dbg(ERROR, "error reading CSR: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
...@@ -2344,7 +2345,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) ...@@ -2344,7 +2345,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
...@@ -2352,7 +2353,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) ...@@ -2352,7 +2353,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
if (err) { if (err) {
brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
err); err);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
} }
bus->clkstate = CLK_AVAIL; bus->clkstate = CLK_AVAIL;
} else { } else {
...@@ -2508,11 +2509,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) ...@@ -2508,11 +2509,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
else await next interrupt */ else await next interrupt */
/* On failed register access, all bets are off: /* On failed register access, all bets are off:
no resched or interrupts */ no resched or interrupts */
if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || if ((bus->drvr->bus_if->state == BRCMF_BUS_DOWN) ||
brcmf_sdcard_regfail(bus->sdiodev)) { brcmf_sdcard_regfail(bus->sdiodev)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
brcmf_sdcard_regfail(bus->sdiodev)); brcmf_sdcard_regfail(bus->sdiodev));
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
bus->intstatus = 0; bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) { } else if (bus->clkstate == CLK_PENDING) {
brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
...@@ -2549,7 +2550,7 @@ static int brcmf_sdbrcm_dpc_thread(void *data) ...@@ -2549,7 +2550,7 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
if (!wait_for_completion_interruptible(&bus->dpc_wait)) { if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
/* Call bus dpc unless it indicated down /* Call bus dpc unless it indicated down
(then clean stop) */ (then clean stop) */
if (bus->drvr->busstate != BRCMF_BUS_DOWN) { if (bus->drvr->bus_if->state != BRCMF_BUS_DOWN) {
if (brcmf_sdbrcm_dpc(bus)) if (brcmf_sdbrcm_dpc(bus))
complete(&bus->dpc_wait); complete(&bus->dpc_wait);
} else { } else {
...@@ -3111,7 +3112,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) ...@@ -3111,7 +3112,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
/* Allow HT Clock now that the ARM is running. */ /* Allow HT Clock now that the ARM is running. */
bus->alp_only = false; bus->alp_only = false;
bus->drvr->busstate = BRCMF_BUS_LOAD; bus->drvr->bus_if->state = BRCMF_BUS_LOAD;
} }
fail: fail:
return bcmerror; return bcmerror;
...@@ -3354,7 +3355,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_sdio *bus) ...@@ -3354,7 +3355,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_sdio *bus)
bus->hostintmask = 0; bus->hostintmask = 0;
/* Change our idea of bus state */ /* Change our idea of bus state */
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
/* Force clocks on backplane to be sure F2 interrupt propagates */ /* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
...@@ -3410,7 +3411,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) ...@@ -3410,7 +3411,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
/* try to download image and nvram to the dongle */ /* try to download image and nvram to the dongle */
if (drvr->busstate == BRCMF_BUS_DOWN) { if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
if (!(brcmf_sdbrcm_download_firmware(bus))) if (!(brcmf_sdbrcm_download_firmware(bus)))
return -1; return -1;
} }
...@@ -3476,7 +3477,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) ...@@ -3476,7 +3477,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
SBSDIO_WATERMARK, 8, &err); SBSDIO_WATERMARK, 8, &err);
/* Set bus state according to enable result */ /* Set bus state according to enable result */
drvr->busstate = BRCMF_BUS_DATA; drvr->bus_if->state = BRCMF_BUS_DATA;
} }
else { else {
...@@ -3491,7 +3492,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) ...@@ -3491,7 +3492,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
/* If we didn't come up, turn off backplane clock */ /* If we didn't come up, turn off backplane clock */
if (drvr->busstate != BRCMF_BUS_DATA) if (drvr->bus_if->state != BRCMF_BUS_DATA)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
exit: exit:
...@@ -3511,7 +3512,7 @@ void brcmf_sdbrcm_isr(void *arg) ...@@ -3511,7 +3512,7 @@ void brcmf_sdbrcm_isr(void *arg)
return; return;
} }
if (bus->drvr->busstate == BRCMF_BUS_DOWN) { if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN) {
brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
return; return;
} }
...@@ -3585,7 +3586,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) ...@@ -3585,7 +3586,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
} }
#ifdef BCMDBG #ifdef BCMDBG
/* Poll for console output periodically */ /* Poll for console output periodically */
if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { if (drvr->bus_if->state == BRCMF_BUS_DATA &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS; bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) { if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval; bus->console.count -= bus->console_interval;
...@@ -3764,7 +3766,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) ...@@ -3764,7 +3766,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL); SDIO_FUNC_ENABLE_1, NULL);
bus->drvr->busstate = BRCMF_BUS_DOWN; bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
bus->sleeping = false; bus->sleeping = false;
bus->rxflow = false; bus->rxflow = false;
...@@ -3924,7 +3926,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) ...@@ -3924,7 +3926,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
} }
/* Attach to the brcmf/OS/network interface */ /* Attach to the brcmf/OS/network interface */
bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); bus->drvr = brcmf_attach(bus, SDPCM_RESERVE, bus->sdiodev->dev);
if (!bus->drvr) { if (!bus->drvr) {
brcmf_dbg(ERROR, "brcmf_attach failed\n"); brcmf_dbg(ERROR, "brcmf_attach failed\n");
goto fail; goto fail;
...@@ -4003,7 +4005,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) ...@@ -4003,7 +4005,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
} }
/* don't start the wd until fw is loaded */ /* don't start the wd until fw is loaded */
if (bus->drvr->busstate == BRCMF_BUS_DOWN) if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN)
return; return;
if (wdtick) { if (wdtick) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment