drivers/nfc/pn533/uart.c

Source file repositories/reference/linux-study-clean/drivers/nfc/pn533/uart.c

File Facts

System
Linux kernel
Corpus path
drivers/nfc/pn533/uart.c
Extension
.c
Size
8219 bytes
Lines
340
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pn532_uart_phy {
	struct serdev_device *serdev;
	struct sk_buff *recv_skb;
	struct pn533 *priv;
	/*
	 * send_wakeup variable is used to control if we need to send a wakeup
	 * request to the pn532 chip prior to our actual command. There is a
	 * little propability of a race condition. We decided to not mutex the
	 * variable as the worst that could happen is, that we send a wakeup
	 * to the chip that is already awake. This does not hurt. It is a
	 * no-op to the chip.
	 */
	enum send_wakeup send_wakeup;
	struct timer_list cmd_timeout;
	struct sk_buff *cur_out_buf;
};

static int pn532_uart_send_frame(struct pn533 *dev,
				struct sk_buff *out)
{
	/* wakeup sequence and dummy bytes for waiting time */
	static const u8 wakeup[] = {
		0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	struct pn532_uart_phy *pn532 = dev->phy;
	int err;

	print_hex_dump_debug("PN532_uart TX: ", DUMP_PREFIX_NONE, 16, 1,
			     out->data, out->len, false);

	pn532->cur_out_buf = out;
	if (pn532->send_wakeup) {
		err = serdev_device_write(pn532->serdev,
				wakeup, sizeof(wakeup),
				MAX_SCHEDULE_TIMEOUT);
		if (err < 0)
			return err;
	}

	if (pn532->send_wakeup == PN532_SEND_LAST_WAKEUP)
		pn532->send_wakeup = PN532_SEND_NO_WAKEUP;

	err = serdev_device_write(pn532->serdev, out->data, out->len,
			MAX_SCHEDULE_TIMEOUT);
	if (err < 0)
		return err;

	mod_timer(&pn532->cmd_timeout, HZ / 40 + jiffies);
	return 0;
}

static int pn532_uart_send_ack(struct pn533 *dev, gfp_t flags)
{
	/* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
	static const u8 ack[PN533_STD_FRAME_ACK_SIZE] = {
			0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
	struct pn532_uart_phy *pn532 = dev->phy;
	int err;

	err = serdev_device_write(pn532->serdev, ack, sizeof(ack),
			MAX_SCHEDULE_TIMEOUT);
	if (err < 0)
		return err;

	return 0;
}

static void pn532_uart_abort_cmd(struct pn533 *dev, gfp_t flags)
{
	/* An ack will cancel the last issued command */
	pn532_uart_send_ack(dev, flags);
	/* schedule cmd_complete_work to finish current command execution */
	pn533_recv_frame(dev, NULL, -ENOENT);
}

static int pn532_dev_up(struct pn533 *dev)
{
	struct pn532_uart_phy *pn532 = dev->phy;
	int ret = 0;

	ret = serdev_device_open(pn532->serdev);
	if (ret)
		return ret;

	pn532->send_wakeup = PN532_SEND_LAST_WAKEUP;
	return ret;
}

static int pn532_dev_down(struct pn533 *dev)
{

Annotation

Implementation Notes