usb设备控制器之uvc数据传输底层实现

只需要知道一点 usb设备控制器处理的是一个trb结构体指针,控制器自己分析里面数据启动传输
在这里插入图片描述

在ioctl qbuf的时候调用到__dwc3_gadget_ep_queue—>usb_gadget_map_request

int usb_gadget_map_request_by_dev(struct device *dev,
		struct usb_request *req, int is_in)
{
	if (req->length == 0)
		return 0;

	if (req->num_sgs) {
		int     mapped;

		mapped = dma_map_sg(dev, req->sg, req->num_sgs,
				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
		if (mapped == 0) {
			dev_err(dev, "failed to map SGs\n");
			return -EFAULT;
		}

		req->num_mapped_sgs = mapped;
	} else {
		req->dma = dma_map_single(dev, req->buf, req->length,
				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);在这映射到dma内存种

		if (dma_mapping_error(dev, req->dma)) {
			dev_err(dev, "failed to map buffer\n");
			return -EFAULT;
		}
	}

	return 0;
}

传输函数 准备工作__dwc3_gadget_ep_queue—>__dwc3_gadget_kick_transfer—>dwc3_prepare_trbs—>dwc3_prepare_one_trb_linear—>dwc3_prepare_one_trb

static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
		struct dwc3_request *req, dma_addr_t dma,
		unsigned length, unsigned chain, unsigned node)
{
	struct dwc3_trb		*trb;
	struct dwc3		*dwc = dep->dwc;
	struct usb_gadget	*gadget = &dwc->gadget;
	enum usb_device_speed	speed = gadget->speed;
	trb = &dep->trb_pool[dep->trb_enqueue];

	if (!req->trb) {
		dwc3_gadget_move_started_request(req);
		req->trb = trb;                                //trb虚拟地址
		req->trb_dma = dwc3_trb_dma_offset(dep, trb);  //dma地址实际指向上面trb结构体
		req->first_trb_index = dep->trb_enqueue;
		dep->queued_requests++;
	}

	dwc3_ep_inc_enq(dep);

	trb->size = DWC3_TRB_SIZE_LENGTH(length);
	trb->bpl = lower_32_bits(dma);          //将前面需要传输数据的dma映射地址赋值给trb低32位
	trb->bph = upper_32_bits(dma);

	switch (usb_endpoint_type(dep->endpoint.desc)) {
	case USB_ENDPOINT_XFER_CONTROL:
		trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
		break;
		省略代码。。。。
}

启动传输

static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
{
	struct dwc3_gadget_ep_cmd_params params;
	struct dwc3_request		*req;
	struct dwc3			*dwc = dep->dwc;
	int				starting;
	int				ret;
	u32				cmd;

	starting = !(dep->flags & DWC3_EP_BUSY);

	dwc3_prepare_trbs(dep);//dma相关准备工作  将数据dma地址赋值给dma指向的传输的trb结构体中的地址变量
	req = next_request(&dep->started_list);
	if (!req) {
		dep->flags |= DWC3_EP_PENDING_REQUEST;
		return 0;
	}

	memset(&params, 0, sizeof(params));

	if (starting && !(dep->flags&DWC3_EP_UPDATE)) {
	//这里将指向trb结构体的dma地址赋值给参数,后面分别写进两个寄存器中。然后控制器通过该地址拿到直接存储数据的dma地址以及数据长度,一包数据调用一次,后面都是走else的update
		params.param0 = upper_32_bits(req->trb_dma);
		params.param1 = lower_32_bits(req->trb_dma);
		cmd = DWC3_DEPCMD_STARTTRANSFER |
			DWC3_DEPCMD_PARAM(cmd_param);
		if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
			dep->flags |= DWC3_EP_UPDATE;
	} else {
		cmd = DWC3_DEPCMD_UPDATETRANSFER |
			DWC3_DEPCMD_PARAM(dep->resource_index);
	}
	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
	省略代码。。。
	}

使能发送数据
	int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
		struct dwc3_gadget_ep_cmd_params *params)
{
	struct dwc3		*dwc = dep->dwc;
	u32			timeout = 5000;
	u32			reg;

	int			cmd_status = 0;
	int			susphy = false;
	int			ret = -EINVAL;

	/*
	 * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
	 * we're issuing an endpoint command, we must check if
	 * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
	 *
	 * We will also set SUSPHY bit to what it was before returning as stated
	 * by the same section on Synopsys databook.
	 */
	if (dwc->gadget.speed <= USB_SPEED_HIGH) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
		if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
			susphy = true;
			reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
			dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
		}
	}

	if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
		int		needs_wakeup;

		needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
				dwc->link_state == DWC3_LINK_STATE_U2 ||
				dwc->link_state == DWC3_LINK_STATE_U3);

		if (unlikely(needs_wakeup)) {
			ret = __dwc3_gadget_wakeup(dwc);
			dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
					ret);
		}
	}

	dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);将dma地址写入寄存器
	dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
	dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);

	dwc3_writel(dep->regs, DWC3_DEPCMD, cmd | DWC3_DEPCMD_CMDACT);使能usb传输
	省略代码。。。
	}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值