drivers/w1/w1_netlink.c

Source file repositories/reference/linux-study-clean/drivers/w1/w1_netlink.c

File Facts

System
Linux kernel
Corpus path
drivers/w1/w1_netlink.c
Extension
.c
Size
19400 bytes
Lines
741
Domain
Driver Families
Bucket
drivers/w1
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 w1_cb_block {
	atomic_t refcnt;
	u32 portid; /* Sending process port ID */
	/* maximum value for first_cn->len */
	u16 maxlen;
	/* pointers to building up the reply message */
	struct cn_msg *first_cn; /* fixed once the structure is populated */
	struct cn_msg *cn; /* advances as cn_msg is appeneded */
	struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */
	struct w1_netlink_cmd *cmd; /* advances as cmds are appened */
	struct w1_netlink_msg *cur_msg; /* currently message being processed */
	/* copy of the original request follows */
	struct cn_msg request_cn;
	/* followed by variable length:
	 * cn_msg, data (w1_netlink_msg and w1_netlink_cmd)
	 * one or more struct w1_cb_node
	 * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd)
	 */
};
struct w1_cb_node {
	struct w1_async_cmd async;
	/* pointers within w1_cb_block and cn data */
	struct w1_cb_block *block;
	struct w1_netlink_msg *msg;
	struct w1_slave *sl;
	struct w1_master *dev;
};

/**
 * w1_reply_len() - calculate current reply length, compare to maxlen
 * @block: block to calculate
 *
 * Calculates the current message length including possible multiple
 * cn_msg and data, excludes the first sizeof(struct cn_msg).  Direclty
 * compariable to maxlen and usable to send the message.
 */
static u16 w1_reply_len(struct w1_cb_block *block)
{
	if (!block->cn)
		return 0;
	return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;
}

static void w1_unref_block(struct w1_cb_block *block)
{
	if (atomic_sub_return(1, &block->refcnt) == 0) {
		u16 len = w1_reply_len(block);
		if (len) {
			cn_netlink_send_mult(block->first_cn, len,
					     block->portid, 0,
					     GFP_KERNEL, NULL, NULL);
		}
		kfree(block);
	}
}

/**
 * w1_reply_make_space() - send message if needed to make space
 * @block: block to make space on
 * @space: how many bytes requested
 *
 * Verify there is enough room left for the caller to add "space" bytes to the
 * message, if there isn't send the message and reset.
 */
static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
{
	u16 len = w1_reply_len(block);
	if (len + space >= block->maxlen) {
		cn_netlink_send_mult(block->first_cn, len, block->portid,
				     0, GFP_KERNEL, NULL, NULL);
		block->first_cn->len = 0;
		block->cn = NULL;
		block->msg = NULL;
		block->cmd = NULL;
	}
}

/* Early send when replies aren't bundled. */
static void w1_netlink_check_send(struct w1_cb_block *block)
{
	if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn)
		w1_reply_make_space(block, block->maxlen);
}

/**
 * w1_netlink_setup_msg() - prepare to write block->msg
 * @block: block to operate on
 * @ack: determines if cn can be reused
 *
 * block->cn will be setup with the correct ack, advancing if needed

Annotation

Implementation Notes