USB Gadget
+ -

usb端点ep_enable与ep_disable

2025-09-26 本文链接为:http://www.usbzh.com/article/detail-1590.html ,欢迎转载,转载请附上本文链接。

启用设备之后,会调用SET_INTERFACE,会在SET_INTERFACE对应的回调function.set_alt,这时会调用usb_ep_enable启用端点。

usb_ep_enable的的结构体信息struct usb_ep来原于usb_ep_autoconfig,该函数的功能是通过输入的端点信息在UDC控制器的端点链表中查找一个空闲的端点,用来分配出来。所以struct usb_ep是一个由UDC控制器提供的信息元。

usb_ep_enable用于启用端点,它其实调用的就是其对应的OP函数,通过源代码也可知。

static inline int usb_ep_enable(struct usb_ep *ep)
{
    return ep->ops->enable(ep, ep->desc);
}
static inline int usb_ep_disable(struct usb_ep *ep)
{
    return ep->ops->disable(ep);
}
static inline int usb_ep_queue(struct usb_ep *ep,struct usb_request *req, gfp_t gfp_flags)
{
    return ep->ops->queue(ep, req, gfp_flags);
}
static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
    return ep->ops->dequeue(ep, req);
}

在IMX6ULL中,其UDC的驱动位于\drivers\usb\chipidea目录下。在其udc.c文件中,提供了回调函数实现。

static const struct usb_ep_ops usb_ep_ops = {
    .enable           = ep_enable,
    .disable       = ep_disable,
    .alloc_request = ep_alloc_request,
    .free_request  = ep_free_request,
    .queue           = ep_queue,//usb_ep_queue
    .dequeue       = ep_dequeue,//usb_ep_dequeue
    .set_halt      = ep_set_halt,
    .set_wedge     = ep_set_wedge,
    .fifo_flush    = ep_fifo_flush,
};

通过端点的初始化函数init_eps,可以看到具体的初始化过程

static int init_eps(struct ci_hdrc *ci)
{
    int retval = 0, i, j;

    for (i = 0; i < ci->hw_ep_max/2; i++)
        for (j = RX; j <= TX; j++) {
            int k = i + j * ci->hw_ep_max/2;
            struct ci_hw_ep *hwep = &ci->ci_hw_ep[k];
            hwep->ci          = ci;
            hwep->lock         = &ci->lock;
            hwep->td_pool      = ci->td_pool;

            hwep->ep.name      = hwep->name;
            hwep->ep.ops       = &usb_ep_ops;
            ...
            list_add_tail(&hwep->ep.ep_list, &ci->gadget.ep_list);
        }

    return retval;
}

这里可以看到,所有端点都位于ci->gadget.ep_list队列中。

ep_enable

static int ep_enable(struct usb_ep *ep,
             const struct usb_endpoint_descriptor *desc)
{
    struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
    int retval = 0;
    unsigned long flags;
    u32 cap = 0;

    if (ep == NULL || desc == NULL)
        return -EINVAL;

    spin_lock_irqsave(hwep->lock, flags);

    /* only internal SW should enable ctrl endpts */

    if (!list_empty(&hwep->qh.queue)) {
        dev_warn(hwep->ci->dev, "enabling a non-empty endpoint!\n");
        spin_unlock_irqrestore(hwep->lock, flags);
        return -EBUSY;
    }

    hwep->ep.desc = desc;

    hwep->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
    hwep->num  = usb_endpoint_num(desc);
    hwep->type = usb_endpoint_type(desc);

    hwep->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff;
    hwep->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc));

    if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
        cap |= QH_IOS;

    cap |= QH_ZLT;
    cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
    /*
     * For ISO-TX, we set mult at QH as the largest value, and use
     * MultO at TD as real mult value.
     */
    if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX)
        cap |= 3 << __ffs(QH_MULT);

    hwep->qh.ptr->cap = cpu_to_le32(cap);

    hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE);   /* needed? */

    if (hwep->num != 0 && hwep->type == USB_ENDPOINT_XFER_CONTROL) {
        dev_err(hwep->ci->dev, "Set control xfer at non-ep0\n");
        retval = -EINVAL;
    }

    /*
     * Enable endpoints in the HW other than ep0 as ep0
     * is always enabled
     */
    if (hwep->num)
        retval |= hw_ep_enable(hwep->ci, hwep->num, hwep->dir,hwep->type);

    spin_unlock_irqrestore(hwep->lock, flags);
    return retval;
}

这里看到,要使用端点的时候,有判断端点中的请求队列是否为空,如果为非空,则退出。

ep_disable

static int ep_disable(struct usb_ep *ep)
{
    struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
    int direction, retval = 0;
    unsigned long flags;

    if (ep == NULL)
        return -EINVAL;
    else if (hwep->ep.desc == NULL)
        return -EBUSY;

    spin_lock_irqsave(hwep->lock, flags);
    if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
        spin_unlock_irqrestore(hwep->lock, flags);
        return 0;
    }

    /* only internal SW should disable ctrl endpts */

    direction = hwep->dir;
    do {
        retval |= _ep_nuke(hwep);
        retval |= hw_ep_disable(hwep->ci, hwep->num, hwep->dir);

        if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
            hwep->dir = (hwep->dir == TX) ? RX : TX;

    } while (hwep->dir != direction);

    hwep->ep.desc = NULL;

    spin_unlock_irqrestore(hwep->lock, flags);
    return retval;
}

_ep_nuke函数会清除该端点的所有请求队列。

/**
 * _ep_nuke: dequeues all endpoint requests
 * @hwep: endpoint
 *
 * This function returns an error code
 * Caller must hold lock
 */

static int _ep_nuke(struct ci_hw_ep *hwep)
__releases(hwep->lock)
__acquires(hwep->lock)
{
    struct td_node *node, *tmpnode;
    if (hwep == NULL)
        return -EINVAL;

    hw_ep_flush(hwep->ci, hwep->num, hwep->dir);

    //从该端点队列中取出所有的请求
    while (!list_empty(&hwep->qh.queue)) {

        /* pop oldest request */
        struct ci_hw_req *hwreq = list_entry(hwep->qh.queue.next,struct ci_hw_req, queue);
        list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
            dma_pool_free(hwep->td_pool, node->ptr, node->dma);
            list_del_init(&node->td);
            node->ptr = NULL;
            kfree(node);
        }

        list_del_init(&hwreq->queue);    //从队列中移除请求
        hwreq->req.status = -ESHUTDOWN; //设置状态

        //调用完成例程
        if (hwreq->req.complete != NULL) {
            spin_unlock(hwep->lock);
            usb_gadget_giveback_request(&hwep->ep, &hwreq->req);
            spin_lock(hwep->lock);
        }
    }

    if (hwep->pending_td)
        free_pending_td(hwep);

    return 0;
}
本文链接为:http://www.usbzh.com/article/detail-1590.html ,欢迎转载,转载请附上本文链接。

0 篇笔记 写笔记

USB Gadget CDC-ECM网卡实例
ECM和NCM网卡类似,也需要安装ECM驱动设备兼容ID为:USBClass_02&SubClass_06&Prot_00USBClass_02&SubClass_06USBClass_02创建脚本:#!/bin/bashmodprobe libcompos......
Linux Gadget驱动结构关系图
Linux Gadget驱动层级如下:Gadget Function驱动/gadget legacy驱动Gadget Compoiste驱动USB UDC驱动(USB Device Control)Gadget Function驱动/gadget legacy驱动function, 更加现......
fusb300_udc
usbgadgetudcfusb300_udc是平台设备驱动程序static struct platform_driver fusb300_driver = { .remove = fusb300_remove, .driver = { ......
gadget probe过程-以g_audio为例
g_audio中通过如下代码调用usb_composite_probe,其中入参为audio_driverstatic struct usb_composite_driver audio_driver = { .name = "g_audio", ......
configfs文件系统
Linux内核使用CONFIGFS配置项支持可以通过用户创建USB Compoiste Gadget。CONFIG_CONFIGFS_FS项用于支持配置文件系统。Menconfig -> FileSystems -> Psuedo File System -> {M}User......
Gadget legacy和Gadget Function的区别
在 Linux 的 USB Gadget 子系统中,Legacy GadgetGadget Function(FunctionFS 或 configfs) 是两种不同的实现方式,用于将 Linux 设备配置为 USB 外设(如 U 盘、网卡、串口等)。它们的区别主要体现在架构、使用方式和灵活性......
usb_gadget复合HID键盘和U盘实例
#!/bin/bash# 加载模块modprobe libcompositemodprobe usb_f_hidmodprobe usb_f_mass_storage.komount -t configfs none /sys/kernel/config# 创建 Gadgetcd......
usb gadget创建uvc相机脚本实例
#!/bin/bashmodprobe libcompositemodprobe usb_f_uvcmount -t configfs none /sys/kernel/configmkdir -p /sys/kernel/config/usb_gadget/g1cd /sys/kern......
USB Gadget CDC-ACM串口实例
符合USB ACM规范的设备由Windows提供其驱动程序usbser.sysuserser.infLinux Gadget对应的ACM驱动依赖为root@ATK-IMX6U:/sys/kernel/config/usb_gadget/g1# lsmodModule ......
USB Gadget CDC-NCM网卡实例
USG Gadget也提供了CDC-NCM网卡驱动程序,使用USB Gadget CDC-NCM驱动,这样在Windows主机端和Linux设备端都会创建一个USB网卡设备。root@ATK-IMX6U:/lib/modules/4.1.15# ifconfig -ausb0 Lin......
USB Gadget 打印机实例
打印机这一块应该要与实例相连,具体这一块没有研究过。生成的设备如下:设备模块如下:root@ATK-IMX6U:/lib/modules/4.1.15# lsmodModule Size Used byusb_f_printer 1137......
USB Gadget CDC-EEM网卡实例
从理论上来讲,EEM网卡Windows是应该支持的,实际上也确实不用像NCM、ECM需要手动安装驱动,系统会自动匹配兼容ID来进行安装驱动,但是驱动启动失败,这个Linux系统下就没有问题。#!/bin/bashmodprobe libcompositemodprobe usb_f_eemm......
USB Gadget LoopBack实例
Loopback Function 提供的功能简单,它分配了两个 bulk endpoint,所做的就是把 out_ep 接收到的数据转发到 in_ep。#!/bin/bashmodprobe libcompositemodprobe usb_f_ss_lbmount -t configfs......
USB Gadget RNDIS网络适配器实列
和NCM一样,由于兼容ID的问题,RNDIS网络适配器也需要手动安装驱动。其对应的驱动为:netrndis.infrndismp6.sys其创建脚本如下:#!/bin/bashmodprobe libcompositemodprobe usb_f_rndismount -t conf......
USB Gadget实例分析usb_function_instance和usb_function
linux usb gadtet的设备类驱动有两个很重要的概念:usb_function_instance和usb_function从名来上看,usb_function_instance像是usb_function的实例化,但实际是恰恰相反。这里以f_loopback为示例解释:USB设备信息执......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • CDC
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!