/* * Reads an ndlc frame from the chip. * * On ST21NFCB, IRQ goes in idle state when read starts. */ static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id) { struct st_nci_spi_phy *phy = phy_id; struct spi_device *dev; struct sk_buff *skb = NULL; int r; if (!phy || !phy->ndlc || irq != phy->spi_dev->irq) { WARN_ON_ONCE(1); return IRQ_NONE; } dev = phy->spi_dev; dev_dbg(&dev->dev, "IRQ\n"); if (phy->ndlc->hard_fault) return IRQ_HANDLED; if (!phy->ndlc->powered) { st_nci_spi_disable(phy); return IRQ_HANDLED; } r = st_nci_spi_read(phy, &skb); if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG) return IRQ_HANDLED; ndlc_recv(phy->ndlc, skb); return IRQ_HANDLED; }
/* * Reads an ndlc frame from the chip. * * On ST21NFCB, IRQ goes in idle state when read starts. */ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id) { struct st21nfcb_i2c_phy *phy = phy_id; struct i2c_client *client; struct sk_buff *skb = NULL; int r; if (!phy || irq != phy->i2c_dev->irq) { WARN_ON_ONCE(1); return IRQ_NONE; } client = phy->i2c_dev; dev_dbg(&client->dev, "IRQ\n"); if (phy->hard_fault) return IRQ_HANDLED; if (!phy->powered) { st21nfcb_nci_i2c_disable(phy); return IRQ_HANDLED; } r = st21nfcb_nci_i2c_read(phy, &skb); if (r == -EREMOTEIO) { phy->hard_fault = r; ndlc_recv(phy->ndlc, NULL); return IRQ_HANDLED; } else if (r == -ENOMEM || r == -EBADMSG) { return IRQ_HANDLED; } ndlc_recv(phy->ndlc, skb); return IRQ_HANDLED; }
/* * Writing a frame must not return the number of written bytes. * It must return either zero for success, or <0 for error. * In addition, it must not alter the skb */ static int st_nci_spi_write(void *phy_id, struct sk_buff *skb) { int r; struct st_nci_spi_phy *phy = phy_id; struct spi_device *dev = phy->spi_dev; struct sk_buff *skb_rx; u8 buf[ST_NCI_SPI_MAX_SIZE + NCI_DATA_HDR_SIZE + ST_NCI_FRAME_HEADROOM + ST_NCI_FRAME_TAILROOM]; struct spi_transfer spi_xfer = { .tx_buf = skb->data, .rx_buf = buf, .len = skb->len, }; if (phy->ndlc->hard_fault != 0) return phy->ndlc->hard_fault; r = spi_sync_transfer(dev, &spi_xfer, 1); /* * We may have received some valuable data on miso line. * Send them back in the ndlc state machine. */ if (!r) { skb_rx = alloc_skb(skb->len, GFP_KERNEL); if (!skb_rx) { r = -ENOMEM; goto exit; } skb_put(skb_rx, skb->len); memcpy(skb_rx->data, buf, skb->len); ndlc_recv(phy->ndlc, skb_rx); } exit: return r; } /* * Reads an ndlc frame and returns it in a newly allocated sk_buff. * returns: * 0 : if received frame is complete * -EREMOTEIO : i2c read error (fatal) * -EBADMSG : frame was incorrect and discarded * -ENOMEM : cannot allocate skb, frame dropped */ static int st_nci_spi_read(struct st_nci_spi_phy *phy, struct sk_buff **skb) { int r; u8 len; u8 buf[ST_NCI_SPI_MAX_SIZE]; struct spi_device *dev = phy->spi_dev; struct spi_transfer spi_xfer = { .rx_buf = buf, .len = ST_NCI_SPI_MIN_SIZE, }; r = spi_sync_transfer(dev, &spi_xfer, 1); if (r < 0) return -EREMOTEIO; len = be16_to_cpu(*(__be16 *) (buf + 2)); if (len > ST_NCI_SPI_MAX_SIZE) { nfc_err(&dev->dev, "invalid frame len\n"); phy->ndlc->hard_fault = 1; return -EBADMSG; } *skb = alloc_skb(ST_NCI_SPI_MIN_SIZE + len, GFP_KERNEL); if (*skb == NULL) return -ENOMEM; skb_reserve(*skb, ST_NCI_SPI_MIN_SIZE); skb_put(*skb, ST_NCI_SPI_MIN_SIZE); memcpy((*skb)->data, buf, ST_NCI_SPI_MIN_SIZE); if (!len) return 0; spi_xfer.len = len; r = spi_sync_transfer(dev, &spi_xfer, 1); if (r < 0) { kfree_skb(*skb); return -EREMOTEIO; } skb_put(*skb, len); memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len); return 0; }