drivers/net/wwan/t7xx/t7xx_port_wwan.c

Source file repositories/reference/linux-study-clean/drivers/net/wwan/t7xx/t7xx_port_wwan.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wwan/t7xx/t7xx_port_wwan.c
Extension
.c
Size
6328 bytes
Lines
250
Domain
Driver Families
Bucket
drivers/net
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

if (ret) {
			dev_kfree_skb(tx_skb);
			dev_err(port->dev, "Write error on fastboot port, %d\n", ret);
			break;
		}
		offset += len;
		actual -= len;
	}

	dev_kfree_skb(skb);
	return 0;
}

static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb)
{
	const struct t7xx_port_conf *port_conf;
	struct sk_buff *cur = skb, *cloned;
	struct t7xx_fsm_ctl *ctl;
	enum md_state md_state;
	int cnt = 0, ret;

	port_conf = port->port_conf;
	ctl = port->t7xx_dev->md->fsm_ctl;
	md_state = t7xx_fsm_get_md_state(ctl);
	if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) {
		dev_warn(port->dev, "Cannot write to %s port when md_state=%d\n",
			 port_conf->name, md_state);
		return -ENODEV;
	}

	while (cur) {
		cloned = skb_clone(cur, GFP_KERNEL);
		if (!cloned)
			return cnt ? cnt : -ENOMEM;
		cloned->len = skb_headlen(cur);
		ret = t7xx_port_send_skb(port, cloned, 0, 0);
		if (ret) {
			dev_kfree_skb(cloned);
			dev_err(port->dev, "Write error on %s port, %d\n",
				port_conf->name, ret);
			return cnt ? cnt + ret : ret;
		}
		cnt += cur->len;
		if (cur == skb)
			cur = skb_shinfo(skb)->frag_list;
		else
			cur = cur->next;
	}

	dev_kfree_skb(skb);
	return 0;
}

static int t7xx_port_wwan_tx(struct wwan_port *port, struct sk_buff *skb)
{
	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
	const struct t7xx_port_conf *port_conf = port_private->port_conf;
	int ret;

	if (!port_private->chan_enable)
		return -EINVAL;

	if (port_conf->port_type != WWAN_PORT_FASTBOOT)
		ret = t7xx_port_ctrl_tx(port_private, skb);
	else
		ret = t7xx_port_fastboot_tx(port_private, skb);

	return ret;
}

static const struct wwan_port_ops wwan_ops = {
	.start = t7xx_port_wwan_start,
	.stop = t7xx_port_wwan_stop,
	.tx = t7xx_port_wwan_tx,
};

static void t7xx_port_wwan_create(struct t7xx_port *port)
{
	const struct t7xx_port_conf *port_conf = port->port_conf;
	unsigned int header_len = sizeof(struct ccci_header), mtu;
	struct wwan_port_caps caps;

	if (!port->wwan.wwan_port) {
		mtu = t7xx_get_port_mtu(port);
		caps.frag_len = mtu - header_len;
		caps.headroom_len = header_len;
		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
							&wwan_ops, &caps, port);
		if (IS_ERR(port->wwan.wwan_port))
			dev_err(port->dev, "Unable to create WWAN port %s", port_conf->name);

Annotation

Implementation Notes