drivers/nfc/nfcmrvl/fw_dnld.c
Source file repositories/reference/linux-study-clean/drivers/nfc/nfcmrvl/fw_dnld.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/nfc/nfcmrvl/fw_dnld.c- Extension
.c- Size
- 14202 bytes
- Lines
- 550
- Domain
- Driver Families
- Bucket
- drivers/nfc
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/module.hlinux/unaligned.hlinux/firmware.hlinux/nfc.hnet/nfc/nci.hnet/nfc/nci_core.hnfcmrvl.h
Detected Declarations
function fw_dnld_overfunction fw_dnld_timeoutfunction process_state_resetfunction process_state_initfunction create_lcfunction process_state_set_ref_clockfunction process_state_set_hi_configfunction process_state_open_lcfunction process_state_fw_dnldfunction process_state_close_lcfunction process_state_bootfunction fw_dnld_rx_workfunction nfcmrvl_fw_dnld_initfunction nfcmrvl_fw_dnld_deinitfunction nfcmrvl_fw_dnld_recv_framefunction nfcmrvl_fw_dnld_abortfunction nfcmrvl_fw_dnld_start
Annotated Snippet
if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) {
nfc_err(priv->dev, "bad command");
return -EINVAL;
}
skb_pull(skb, 1);
len = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
comp_len = get_unaligned_le16(skb->data);
memcpy(&comp_len, skb->data, 2);
skb_pull(skb, 2);
if (((~len) & 0xFFFF) != comp_len) {
nfc_err(priv->dev, "bad len complement: %x %x %x",
len, comp_len, (~len & 0xFFFF));
out_skb = alloc_lc_skb(priv, 1);
if (!out_skb)
return -ENOMEM;
skb_put_u8(out_skb, 0xBF);
nci_send_frame(priv->ndev, out_skb);
priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT;
return 0;
}
priv->fw_dnld.chunk_len = len;
out_skb = alloc_lc_skb(priv, 1);
if (!out_skb)
return -ENOMEM;
skb_put_u8(out_skb, HELPER_ACK_PACKET_FORMAT);
nci_send_frame(priv->ndev, out_skb);
priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT;
break;
case SUBSTATE_WAIT_ACK_CREDIT:
if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
skb->len)) {
nfc_err(priv->dev, "bad packet: waiting for credit");
return -EINVAL;
}
if (priv->fw_dnld.chunk_len == 0) {
/* FW Loading is done */
uint8_t conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
priv->fw_dnld.state = STATE_CLOSE_LC;
nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CLOSE_CMD,
1, &conn_id);
} else {
out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len);
if (!out_skb)
return -ENOMEM;
skb_put_data(out_skb,
((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset,
priv->fw_dnld.chunk_len);
nci_send_frame(priv->ndev, out_skb);
priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT;
}
break;
case SUBSTATE_WAIT_DATA_CREDIT:
if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
skb->len)) {
nfc_err(priv->dev, "bad packet: waiting for credit");
return -EINVAL;
}
priv->fw_dnld.offset += priv->fw_dnld.chunk_len;
priv->fw_dnld.chunk_len = 0;
priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
break;
case SUBSTATE_WAIT_NACK_CREDIT:
if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
skb->len)) {
nfc_err(priv->dev, "bad packet: waiting for credit");
return -EINVAL;
}
priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
break;
}
return 0;
}
static int process_state_close_lc(struct nfcmrvl_private *priv,
const struct sk_buff *skb)
{
if (sizeof(nci_pattern_core_conn_close_rsp) != skb->len ||
memcmp(skb->data, nci_pattern_core_conn_close_rsp, skb->len))
return -EINVAL;
priv->fw_dnld.state = STATE_BOOT;
nci_send_cmd(priv->ndev, NCI_OP_PROPRIETARY_BOOT_CMD, 0, NULL);
Annotation
- Immediate include surface: `linux/module.h`, `linux/unaligned.h`, `linux/firmware.h`, `linux/nfc.h`, `net/nfc/nci.h`, `net/nfc/nci_core.h`, `nfcmrvl.h`.
- Detected declarations: `function fw_dnld_over`, `function fw_dnld_timeout`, `function process_state_reset`, `function process_state_init`, `function create_lc`, `function process_state_set_ref_clock`, `function process_state_set_hi_config`, `function process_state_open_lc`, `function process_state_fw_dnld`, `function process_state_close_lc`.
- Atlas domain: Driver Families / drivers/nfc.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.