drivers/usb/gadget/udc/aspeed-vhub/hub.c

Source file repositories/reference/linux-study-clean/drivers/usb/gadget/udc/aspeed-vhub/hub.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/gadget/udc/aspeed-vhub/hub.c
Extension
.c
Size
27884 bytes
Lines
1083
Domain
Driver Families
Bucket
drivers/usb
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

switch (wValue >> 8) {
		case USB_DT_DEVICE:
		case USB_DT_CONFIG:
		case USB_DT_DEVICE_QUALIFIER:
		case USB_DT_OTHER_SPEED_CONFIG:
			return ast_vhub_rep_desc(ep, wValue >> 8,
						 wLength);
		case USB_DT_STRING:
			return ast_vhub_rep_string(ep, wValue & 0xff,
						   wIndex, wLength);
		}
		return std_req_stall;

		/* GET/SET_INTERFACE */
	case DeviceRequest | USB_REQ_GET_INTERFACE:
		return ast_vhub_simple_reply(ep, 0);
	case DeviceOutRequest | USB_REQ_SET_INTERFACE:
		if (wValue != 0 || wIndex != 0)
			return std_req_stall;
		return std_req_complete;
	}
	return std_req_stall;
}

static void ast_vhub_update_hub_ep1(struct ast_vhub *vhub,
				    unsigned int port)
{
	/* Update HW EP1 response */
	u32 reg = readl(vhub->regs + AST_VHUB_EP1_STS_CHG);
	u32 pmask = (1 << (port + 1));
	if (vhub->ports[port].change)
		reg |= pmask;
	else
		reg &= ~pmask;
	writel(reg, vhub->regs + AST_VHUB_EP1_STS_CHG);
}

static void ast_vhub_change_port_stat(struct ast_vhub *vhub,
				      unsigned int port,
				      u16 clr_flags,
				      u16 set_flags,
				      bool set_c)
{
	struct ast_vhub_port *p = &vhub->ports[port];
	u16 prev;

	/* Update port status */
	prev = p->status;
	p->status = (prev & ~clr_flags) | set_flags;
	DDBG(&p->dev, "port %d status %04x -> %04x (C=%d)\n",
	     port + 1, prev, p->status, set_c);

	/* Update change bits if needed */
	if (set_c) {
		u16 chg = p->status ^ prev;

		/* Only these are relevant for change */
		chg &= USB_PORT_STAT_C_CONNECTION |
		       USB_PORT_STAT_C_ENABLE |
		       USB_PORT_STAT_C_SUSPEND |
		       USB_PORT_STAT_C_OVERCURRENT |
		       USB_PORT_STAT_C_RESET |
		       USB_PORT_STAT_C_L1;

		/*
		 * We only set USB_PORT_STAT_C_ENABLE if we are disabling
		 * the port as per USB spec, otherwise MacOS gets upset
		 */
		if (p->status & USB_PORT_STAT_ENABLE)
			chg &= ~USB_PORT_STAT_C_ENABLE;

		p->change = chg;
		ast_vhub_update_hub_ep1(vhub, port);
	}
}

static void ast_vhub_send_host_wakeup(struct ast_vhub *vhub)
{
	u32 reg = readl(vhub->regs + AST_VHUB_CTRL);
	UDCDBG(vhub, "Waking up host !\n");
	reg |= VHUB_CTRL_MANUAL_REMOTE_WAKEUP;
	writel(reg, vhub->regs + AST_VHUB_CTRL);
}

void ast_vhub_device_connect(struct ast_vhub *vhub,
			     unsigned int port, bool on)
{
	if (on)
		ast_vhub_change_port_stat(vhub, port, 0,
					  USB_PORT_STAT_CONNECTION, true);

Annotation

Implementation Notes