staticvoid device_wakeup(struct wfx_dev *wdev)
{ int max_retry = 3;
if (!wdev->pdata.gpio_wakeup) return; if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0) return;
if (wfx_api_older_than(wdev, 1, 4)) {
gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); if (!completion_done(&wdev->hif.ctrl_ready))
usleep_range(2000, 2500); return;
} for (;;) {
gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); /* completion.h does not provide any function to wait completion without consume it * (a kind of wait_for_completion_done_timeout()). So we have to emulate it.
*/ if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, msecs_to_jiffies(2))) {
complete(&wdev->hif.ctrl_ready); return;
} elseif (max_retry-- > 0) { /* Older firmwares have a race in sleep/wake-up process. Redo the process * is sufficient to unfreeze the chip.
*/
dev_err(wdev->dev, "timeout while wake up chip\n");
gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
usleep_range(2000, 2500);
} else {
dev_err(wdev->dev, "max wake-up retries reached\n"); return;
}
}
}
staticvoid device_release(struct wfx_dev *wdev)
{ if (!wdev->pdata.gpio_wakeup) return;
skb_put(skb, le16_to_cpu(hif->len)); /* wfx_handle_rx takes care on SKB livetime */
wfx_handle_rx(wdev, skb); if (!wdev->hif.tx_buffers_used)
wake_up(&wdev->hif.tx_buffers_empty);
return piggyback;
err: if (skb)
dev_kfree_skb(skb); return -EIO;
}
staticint bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf)
{
size_t len; int i; int ctrl_reg, piggyback;
piggyback = 0; for (i = 0; i < max_msg; i++) { if (piggyback & CTRL_NEXT_LEN_MASK)
ctrl_reg = piggyback; elseif (try_wait_for_completion(&wdev->hif.ctrl_ready))
ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0); else
ctrl_reg = 0; if (!(ctrl_reg & CTRL_NEXT_LEN_MASK)) return i; /* ctrl_reg units are 16bits words */
len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2;
piggyback = rx_helper(wdev, len, num_cnf); if (piggyback < 0) return i; if (!(piggyback & CTRL_WLAN_READY))
dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n",
piggyback);
} if (piggyback & CTRL_NEXT_LEN_MASK) {
ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback);
complete(&wdev->hif.ctrl_ready); if (ctrl_reg)
dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n",
ctrl_reg, piggyback);
} return i;
}
staticvoid tx_helper(struct wfx_dev *wdev, struct wfx_hif_msg *hif)
{ int ret; void *data; bool is_encrypted = false;
size_t len = le16_to_cpu(hif->len);
WARN(len < sizeof(*hif), "try to send corrupted data");
data = hif;
WARN(len > le16_to_cpu(wdev->hw_caps.size_inp_ch_buf), "request exceed the chip capability: %zu > %d\n",
len, le16_to_cpu(wdev->hw_caps.size_inp_ch_buf));
len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len);
ret = wfx_data_write(wdev, data, len); if (ret) goto end;
wdev->hif.tx_buffers_used++;
_trace_hif_send(hif, wdev->hif.tx_buffers_used);
end: if (is_encrypted)
kfree(data);
}
staticint bh_work_tx(struct wfx_dev *wdev, int max_msg)
{ struct wfx_hif_msg *hif; int i;
for (i = 0; i < max_msg; i++) {
hif = NULL; if (wdev->hif.tx_buffers_used < le16_to_cpu(wdev->hw_caps.num_inp_ch_bufs)) { if (try_wait_for_completion(&wdev->hif_cmd.ready)) {
WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error");
hif = wdev->hif_cmd.buf_send;
} else {
hif = wfx_tx_queues_get(wdev);
}
} if (!hif) return i;
tx_helper(wdev, hif);
} return i;
}
/* In SDIO mode, it is necessary to make an access to a register to acknowledge last received * message. It could be possible to restrict this acknowledge to SDIO mode and only if last * operation was rx.
*/ staticvoid ack_sdio_data(struct wfx_dev *wdev)
{
u32 cfg_reg;
if (!(cur & CTRL_NEXT_LEN_MASK))
dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n",
cur); if (prev != 0)
dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n",
prev, cur);
}
/* Driver want to send data */ void wfx_bh_request_tx(struct wfx_dev *wdev)
{
queue_work(wdev->bh_wq, &wdev->hif.bh);
}
/* If IRQ is not available, this function allow to manually poll the control register and simulate * an IRQ ahen an event happened. * * Note that the device has a bug: If an IRQ raise while host read control register, the IRQ is * lost. So, use this function carefully (only duing device initialisation).
*/ void wfx_bh_poll_irq(struct wfx_dev *wdev)
{
ktime_t now, start;
u32 reg;
WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ");
flush_workqueue(wdev->bh_wq);
start = ktime_get(); for (;;) {
wfx_control_reg_read(wdev, ®);
now = ktime_get(); if (reg & 0xFFF) break; if (ktime_after(now, ktime_add_ms(start, 1000))) {
dev_err(wdev->dev, "time out while polling control register\n"); return;
}
udelay(200);
}
wfx_bh_request_rx(wdev);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.