
简介本资源为MTK 6575平台USB驱动的完整源码包面向嵌入式Linux驱动开发者、Android底层工程师及芯片级固件调试人员聚焦移动设备USB通信协议栈的实现与调优。压缩包含42个文件其中21个头文件.h定义USB主机/设备模式、OTG状态机、ACM/MS/Video等类驱动接口与数据结构20个C源文件.c覆盖枚举流程、端点管理、中断传输、电源状态切换及错误恢复等核心逻辑另含1个txt文本提供外部链接信息。整体153KB轻量但高度内聚目录按功能模块划分清晰便于定向分析与移植适配。目前已有160人学习下载开发者可直接基于该源码理解MTK USB协议栈分层设计思想复用关键状态机与回调框架快速定位枚举失败、传输卡顿或休眠唤醒异常等问题亦可作为MTK新平台驱动开发的参考基线。1. MTK6575 USB 驱动源码包到底在解决什么问题不是刷机工具而是嵌入式底层 USB Host/OTG 能力的“根目录”你手头有一份名为usb.rar_mt6575_mtk_mtk 6575 usb_mtk source_mtk usb的压缩包解压后看到一堆.c、.h、Makefile和Android.mk文件夹杂着preloader、lk、kernel等目录——它不是一个点几下就能用的 GUI 刷机工具也不是拿来直接烧进手机就能升级的固件。它是一套MTK6575 平台在 Android 4.x 时代2012–2014真实量产项目中使用的 USB 子系统源码集合覆盖从 Preloader 阶段的 USB 下载协议握手、LKLittle Kernel阶段的 USB Device 模式初始化到 Linux kernel 层的mtk-usb主机控制器驱动EHCI/OHCI、OTG 双角色切换逻辑、以及配套的 gadget如usb_serial、usb_mass_storage和 host class如usb-storage、usb-serial驱动。它的核心价值在于让你能真正看懂、改懂、甚至重写 MTK6575 上 USB Host 如何枚举 U 盘、OTG 如何在 Device/Host 间切换、USB Serial 如何被/dev/ttyUSB0正确暴露——而不是靠adb devices是否显示来玄学判断。适合正在维护老旧工控终端、POS 机、车载记录仪等基于 MTK6575 的嵌入式设备的工程师也适合想逆向理解 MTK USB 架构演进从 6575 → 6580 → 6735 → 6765的驱动开发者。如果你正被mtk无法连接设备、usb抓包看不到 handshake、otg线插上没反应这类问题卡住这份源码就是你该打开的第一扇门。2. 从源码结构到编译路径看清mtk6575_usb在整个 BSP 中的位置与依赖链MTK6575 的 USB 支持横跨 BootROM → Preloader → LK → Kernel 四层而这份usb.rar恰好是这四层中可修改、可调试、可复现的关键驱动层集合。它不包含 BootROM固化不可改但完整覆盖了后续所有软件可控环节。理解其组织方式是避免“改了 kernel 驱动却忘了 LK 初始化”的前提。2.1 源码包典型目录结构解析为什么preloader和lk目录不能删解压后你会看到类似如下结构实际命名可能略有差异但逻辑一致usb/ ├── preloader/ # Preloader 阶段 USB 下载模式DA Download Agent入口 │ ├── usb_dl.c # 实现 USB 协议栈最简版SETUP/IN/OUT token 解析、EP0 控制传输 │ └── usb_hw.h # 直接操作 USB PHY 寄存器如 USB_PHY_CON0/1 ├── lk/ # Little Kernel 阶段USB Device 模式ADB/MassStorage启动 │ ├── app/usb/ # ADB/Gadget 相关逻辑 │ │ ├── usb_device.c # device descriptor 构造、ep0 handler 注册 │ │ └── usb_serial.c # CDC ACM class 实现映射到 /dev/ttyGS0 │ └── platform/mt6575/usb.c # USB PHY 初始化、VBUS 检测、ID pin 读取决定 Device/Host ├── kernel/ # Linux Kernel 3.4.x 驱动MTK 定制版 │ ├── drivers/usb/ # 核心驱动 │ │ ├── host/ # Host 控制器驱动关键 │ │ │ ├── ehci-mtk.c # MTK 自研 EHCI Host 控制器驱动非标准 OHCI/EHCI │ │ │ └── ohci-mtk.c # 备用 OHCI 驱动部分 6575 工程用 │ │ ├── phy/ # USB PHY 抽象层 │ │ │ └── phy-mtk-usb.c # 统一管理 USB PHY 供电、时钟、reset │ │ └── gadget/ # Device 模式功能 │ │ ├── f_serial.c # CDC ACM 功能串口 │ │ └── f_mass_storage.c # U 盘功能 │ └── include/linux/usb/mtk.h # MTK 特有宏定义、struct如 mtk_usb_phy └── tools/ # 辅助脚本非必需但极有用 └── usb_download.py # Python 脚本模拟 DA 协议向 Preloader 发送下载命令用于验证 USB 下载通路提示preloader/usb_dl.c是整个 USB 下载链的起点。它不依赖任何 OS纯裸机汇编少量 C只做最基础的 USB token 响应。如果这里出错mtk preloader tool就根本连不上——此时mtk无法连接设备的根因就在这里而非电脑端驱动。2.2 编译依赖链为什么改完ehci-mtk.c还要重新编译 LKMTK6575 的 USB 初始化是严格分阶段传递状态的Preloader 阶段检测 VBUS电源和 ID pinOTG 角色设置 USB PHY 为 Device 模式默认并进入等待 DA 协议握手状态LK 阶段读取 Preloader 传来的 USB 状态如usb_mode USB_MODE_DEVICE初始化 USB Device controller启动 gadget如 ADBKernel 阶段LK 会将 USB Device controller 的寄存器地址、中断号等信息通过 ATAG 或 DTB 传递给 kernelkernel 的ehci-mtk.c则负责初始化 Host controller并复位 USB PHY——注意这个复位会清空 Preloader/LK 设置的 Device 模式所以必须由 kernel 驱动再次根据 OTG ID pin 状态重新配置 PHY 为 Host 或 Device。因此修改ehci-mtk.c后必须确保lk/platform/mt6575/usb.c中的 OTG 状态读取逻辑与 kernel 保持一致。常见翻车点LK 读 ID pin 为 Devicekernel 却因 GPIO 配置错误读成 Host结果 USB 设备插上无反应——现象是lsusb看不到设备dmesg | grep usb显示mtk-ehci 101c0000.usb: cant get phy。2.3 最小可验证编译命令用make -C kernel/快速定位驱动加载失败点你不需要编译整个 Android 系统。针对 USB 驱动验证只需编译 kernel 模块并手动 insmod# 进入 kernel 目录假设已配置好 ARCHarm CROSS_COMPILEarm-linux-androideabi- cd usb/kernel/ # 编译 USB Host 驱动为模块非内置 make -C /path/to/your/kernel/source M$(pwd)/drivers/usb/host modules # 输出ehci-mtk.ko, ohci-mtk.ko, usbcore.ko若未内置 # 检查模块依赖 modinfo ehci-mtk.ko # 输出应含depends: usbcore,phy-mtk-usb # 推送到目标板需 root adb push ehci-mtk.ko /data/local/tmp/ adb shell insmod /data/local/tmp/ehci-mtk.ko # 观察 dmesg adb shell dmesg | tail -20 # 成功应见[ 12.345678] mtk-ehci 101c0000.usb: MTK EHCI Host Controller # 失败则看[ 12.345678] ehci-mtk: probe of 101c0000.usb failed with error -22参数说明-C /path/to/your/kernel/source指向你实际的 kernel 源码树如kernel-3.4M$(pwd)/drivers/usb/host告诉 make 只编译当前目录下的模块。error -22通常意味着 platform device 注册失败DTB 中usb101c0000节点缺失或 compatible 字符串不匹配而非驱动代码本身错误。3. USB Host 驱动深度剖析ehci-mtk.c的三个核心寄存器操作与 PHY 同步机制MTK6575 的 USB Host 控制器并非标准 EHCI而是 MTK 自研的兼容 EHCI 协议的 IP Block。其驱动ehci-mtk.c的关键不在协议栈实现而在如何与 USB PHY 硬件协同工作。跳过 PHYehci-mtk.c就是废纸一张。3.1ehci_mtk_power_on()不是简单 enable clock而是三步硬件握手标准 EHCI 驱动调用clk_prepare_enable()即可但ehci-mtk.c的ehci_mtk_power_on()包含不可省略的三步// drivers/usb/host/ehci-mtk.c static int ehci_mtk_power_on(struct usb_hcd *hcd) { struct ehci_hcd *ehci hcd_to_ehci(hcd); struct mtk_usb_phy *phy dev_get_drvdata(ehci-hcd.self.controller-parent); // Step 1: Enable USB PHY power clock (via MTKs PMIC or syscon) mtk_usb_phy_power_on(phy); // 写 PMIC 寄存器如 MT6323 的 USB_VBUS_EN // Step 2: Wait for PHY stable (critical! 10ms minimum) udelay(10000); // Step 3: Reset EHCI controller AND PHY together (MTK requirement) // 注意这里 reset 信号同时作用于 EHCI IP 和 USB PHY reset_control_assert(ehci-reset); udelay(1000); reset_control_deassert(ehci-reset); udelay(10000); // PHY 需要更长恢复时间 return 0; }逻辑说明MTK6575 的 USB PHY 与 EHCI controller 共享 reset line。如果只 reset controller 不 reset PHYPHY 内部状态机如 PLL 锁定可能未同步导致ehci-mtk初始化时读取CAPLENGTH寄存器返回 0x00 —— 这就是error -22的真实原因。udelay(10000)不是玄学是 datasheet 明确要求的 PHY lock time。3.2ehci_mtk_start_port_reset()OTG 角色切换的物理层开关当插入 U 盘时ehci-mtk需触发 port reset。但 MTK6575 的 reset 逻辑特殊// drivers/usb/host/ehci-mtk.c static void ehci_mtk_start_port_reset(struct ehci_hcd *ehci, int portnum) { u32 __iomem *reg ehci-regs; u32 temp; // 标准 EHCI写 PORTSC 中 PORT_RESET bit temp readl(reg-port_status[portnum]); temp | PORT_RESET; writel(temp, reg-port_status[portnum]); // MTK 扩展必须同时控制 PHY 的 RESET_N pin // 通过 platform data 获取 PHY handle if (ehci-phy) { // 强制 PHY 进入 Host 模式 reset phy_reset(ehci-phy); // 调用 phy-mtk-usb.c 中的 reset 函数 } }参数说明phy_reset()会操作USB_PHY_CON0寄存器地址0x10000A00将 bit[1:0]PHY_MODE设为2b10Host mode并 toggle bit[8]RESET_N。若此处 PHY_MODE 未设对即使 EHCI controller 工作正常U 盘也无法被枚举——lsusb空空如也dmesg却显示new high-speed USB device这是典型的 PHY 模式错配。3.3ehci_mtk_hub_control()拦截 SET_DESCRIPTOR绕过 MTK 的 USB Descriptor Cache BugMTK6575 的 USB Host controller 存在一个硬件 bug当设备发送SET_DESCRIPTOR请求时controller 会错误地 cache descriptor 并返回旧数据。ehci-mtk.c通过在 hub control 中硬编码拦截// drivers/usb/host/ehci-mtk.c static int ehci_mtk_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct ehci_hcd *ehci hcd_to_ehci(hcd); // MTK workaround: bypass cache for SET_DESCRIPTOR if ((typeReq USB_RECIP_MASK) USB_RECIP_DEVICE (typeReq USB_TYPE_MASK) USB_TYPE_STANDARD (wValue 8) USB_DT_DEVICE) { // 强制走 PIO path不走 DMA cache return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); } return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); }逻辑说明这个 patch 直接修复了usb-storage驱动加载时因 descriptor 读取错误导致的device not accepting address错误。没有它U 盘可能被识别为Unknown devicedmesg显示usb 1-1: device descriptor read/64, error -71STALL。此 bug 在 MTK 官方mtk完整驱动.zip中已被修复但很多第三方mtk6575_usb包遗漏了此补丁。4. OTG 双角色切换实战从id-pin检测到gadget/host模式动态加载MTK6575 的 OTG 不是 Linux standard OTG如dwc2而是基于 GPIO ID pin 的简单状态机。lk/platform/mt6575/usb.c和kernel/drivers/usb/phy/phy-mtk-usb.c共同完成切换但kernel 层必须接管最终决策权。4.1 ID Pin 检测LK 读值只是参考kernel 才是裁判LK 中的检测非常朴素// lk/platform/mt6575/usb.c int mt_usb_get_id(void) { // 读 GPIO21典型 ID pin高电平Host低电平Device return gpio_get_value(GPIO21); }但问题在于GPIO21 可能受 PCB layout 影响如长走线导致浮空LK 读取一次就定论。而 kernel 驱动会持续监控// kernel/drivers/usb/phy/phy-mtk-usb.c static irqreturn_t mtk_usb_id_irq(int irq, void *data) { struct mtk_usb_phy *phy data; int id_state gpio_get_value_cansleep(phy-id_gpio); // debounce连续 3 次读取相同值才确认 if (id_state phy-last_id_state) { phy-debounce_cnt; if (phy-debounce_cnt 3) { phy-id_state id_state; schedule_work(phy-otg_work); // 触发模式切换 } } else { phy-debounce_cnt 0; phy-last_id_state id_state; } return IRQ_HANDLED; }参数说明gpio_get_value_cansleep()允许在中断上下文安全读取 GPIOdebounce_cnt防抖是硬性要求否则插拔 OTG 线时会频繁切换模式导致usb-storage驱动反复加载卸载U 盘文件系统损坏。4.2 动态加载gadget或hostmodprobe不是终点configfs才是未来MTK6575 原生支持两种模式加载Host 模式modprobe ehci-mtkmodprobe usb-storageDevice 模式modprobe g_serialCDC ACM或modprobe g_mass_storageU 盘但g_mass_storage有个致命缺陷它需要指定 backing file如/dev/mmcblk0p1且不支持动态挂载。现代做法是用configfs# 创建 configfs 实例 mkdir /config mount -t configfs none /config # 创建 USB Device 配置 mkdir /config/usb_gadget/mygadget cd /config/usb_gadget/mygadget # 设置 Vendor/Product ID echo 0x0525 idVendor # NetChip echo 0xa4a1 idProduct # Linux CDC Composite # 启用 Mass Storage 功能 mkdir functions/mass_storage.usb0 echo /dev/mmcblk0p1 functions/mass_storage.usb0/lun.0/file ln -s functions/mass_storage.usb0 configs/c.1/ # 绑定到 UDCUSB Device Controller echo mt_usb UDC逻辑说明UDC文件写入mt_usb会触发phy-mtk-usb.c中的mtk_usb_vbus_draw()从而拉高 VBUS模拟 Host 供电完成 Device 模式激活。configfs方式比g_mass_storage更灵活支持热插拔 LUN且无需重启驱动。4.3 验证 OTG 切换用getprop和cat /sys/class/udc/*/state交叉确认不要只信lsusb# 查看当前 USB 角色LK 传来的初始值 getprop sys.usb.config # 输出adb,mass_storage 或 none # 查看 kernel 实际 UDC 状态 cat /sys/class/udc/*/state # 输出configuredDevice 模式运行中或 disabled # 查看 Host controller 状态 cat /sys/bus/platform/drivers/ehci-mtk/101c0000.usb/state # 输出bound已绑定或 offline # 关键交叉验证当 OTG 线插入两者应互斥 # Device 模式 active 时/sys/class/udc/* 应为 configured而 /sys/bus/platform/drivers/ehci-mtk/* 应为 offline # Host 模式 active 时反之亦然提示如果getprop sys.usb.config显示adb,mass_storage但/sys/class/udc/*/state是disabled说明 kernel 层 OTG 状态机未触发问题在phy-mtk-usb.c的 ID pin 中断或 debounce 逻辑。5. 避坑指南MTK6575 USB 开发中 4 个血泪经验总结这些坑90% 的工程师都在mtk无法连接设备或usb抓包看不到 handshake时踩过。它们不写在 datasheet 里只藏在dmesg的第 37 行和git blame的提交注释中。5.1 现象dmesg显示mtk-ehci 101c0000.usb: cant get phylsusb为空原因ehci-mtk.c的platform_get_resource()未能获取到phyresource。根源是 DTSDevice Tree中usb101c0000节点缺少phys usbphy引用或usbphy节点本身未正确定义#phy-cells。解决检查 DTS 文件确保usbphy { #phy-cells 0; status okay; }; usb { phys usbphy; phy-names usb; status okay; };注意MTK6575 的 DTS 中usbphy节点名可能是usb_phy或mt_usb_phy需与phy-mtk-usb.c中of_match_table的compatible字符串完全一致。5.2 现象U 盘插入后dmesg显示new high-speed USB device number 2 using mtk-ehci但lsusb -v读 descriptor 失败报error -71原因USB PHY 的SQUSignal Quality寄存器未正确配置导致高速信号眼图闭合。MTK6575 的USB_PHY_CON1地址0x10000A04bit[15:12]TX_PREEMPHASIS和 bit[11:8]TX_SWING需根据 PCB 阻抗微调。解决在phy-mtk-usb.c的mtk_usb_phy_init()中添加// 默认值常导致眼图不良 writel(0x0000F000, phy-base 0x04); // TX_PREEMPHASIS0xF, TX_SWING0x0 // 实际值需用示波器测 USB DP/DM 眼图后调整血泪经验这个寄存器值没有“通用解”必须用teledyne lecroy usb protocol suite或廉价usb抓包工具如 Wireshark USBPcap观察 handshake 波形再反推寄存器值。网上流传的0x0000F000仅适用于 4-layer PCB6-layer 板需改为0x0000E000。5.3 现象OTG 线插入getprop sys.usb.config显示adb,mass_storage但 PC 端无法识别为 U 盘adb devices也无响应原因g_mass_storage模块加载时backing file如/dev/mmcblk0p1的文件系统类型不被 Windows/macOS 支持如 ext4或分区未格式化。g_serial同理/dev/ttyGS0权限不足。解决# 确保 backing file 是 FAT32 mkfs.vfat -F32 /dev/mmcblk0p1 # 设置 g_serial 权限 chmod 666 /dev/ttyGS0 # 或在 init.rc 中添加chmod 0666 /dev/ttyGS0 # 加载时指定 stall0禁用 STALL避免 Windows 拒绝枚举 modprobe g_mass_storage file/dev/mmcblk0p1 stall0注意stall0是关键。MTK6575 的g_mass_storage默认启用 STALL而 Windows 10 对 STALL 敏感会直接放弃枚举。5.4 现象mtk preloader tool连接失败dmesg无任何 USB 相关 loglsusb看不到 MTK Preloader 设备原因Preloader 的 USB PHY 初始化失败最常见是VBUS检测电路问题。MTK6575 Preloader 会先读VBUSGPIO如 GPIO20若为低电平无电源则跳过 USB 初始化直接启动 kernel。解决用万用表测量主板 USB 插座的 VBUS 引脚Pin 1对 GND 电压应为 4.75~5.25V若电压正常检查 Preloader 源码中usb_dl.c的usb_vbus_detect()函数确认 GPIO 编号与原理图一致终极验证短接 VBUS GPIO 到高电平如 3.3V强制 Preloader 进入 USB 下载模式此时mtk preloader tool应能连接。后悔药如果 Preloader 已损坏可用amlogic usb burning tool的USB Download Mode强制唤醒需硬件短接 eMMC boot pins但此法不保证成功慎用。6. 进阶技巧用usbmon抓包 mtk_usb_dump寄存器快照定位 USB 协议层死锁当你已经排除了 PHY、clock、GPIO 等硬件层问题dmesg显示mtk-ehci正常加载U 盘也能被lsusb列出但dmesg却卡在usb 1-1: new high-speed USB device后不再前进——这就是 USB 协议层死锁。此时usb抓包是唯一真相。6.1 启用usbmonLinux 内核原生 USB 协议分析器usbmon不依赖外部硬件直接从内核 USB core hook 数据包# 加载 usbmon 模块kernel 需 CONFIG_USB_MONy modprobe usbmon # 查看可用 bus通常 usbmon0 对应第一个 host controller cat /sys/class/usbmon/*/name # 输出usbmon0 101c0000.usb (MTK EHCI) # 开始抓包输出到文件避免实时打印丢包 echo 1 /sys/bus/usbmon/devices/0u/enable tcpdump -i usbmon0 -w usb_trace.pcap # 插入 U 盘等待 10 秒停止 echo 0 /sys/bus/usbmon/devices/0u/enable # 在 PC 上用 Wireshark 打开 usb_trace.pcap # 过滤usb.capdata usb.transfer_type 0x00控制传输关键过滤技巧在 Wireshark 中输入usb.bRequest 0x06 usb.wValue 0x0100即可定位GET_DESCRIPTOR(Device)请求。若此请求发出后无响应说明设备未 reply问题在设备端或 PHY 信号质量若请求未发出说明ehci-mtk的 QHQueue Head未正确 setup需查ehci-q.c。6.2mtk_usb_dump打印 USB PHY 和 EHCI 寄存器快照比dmesg更直接在ehci-mtk.c中添加调试函数编译进驱动// drivers/usb/host/ehci-mtk.c void mtk_usb_dump_regs(struct ehci_hcd *ehci) { u32 __iomem *reg ehci-regs; struct mtk_usb_phy *phy ehci-phy; pr_info( MTK USB REG DUMP \n); pr_info(EHCI CAPLENGTH: 0x%02x\n, readb(reg-caplength)); pr_info(EHCI HCIVERSION: 0x%04x\n, readw(reg-hciversion)); pr_info(EHCI USBCMD: 0x%08x\n, readl(reg-command)); pr_info(EHCI USBSTS: 0x%08x\n, readl(reg-status)); pr_info(PHY CON0: 0x%08x\n, readl(phy-base 0x00)); pr_info(PHY CON1: 0x%08x\n, readl(phy-base 0x04)); pr_info(PHY CON2: 0x%08x\n, readl(phy-base 0x08)); }在ehci_mtk_run()或ehci_mtk_start_port_reset()中调用mtk_usb_dump_regs(ehci);参数说明CAPLENGTH0x00表示 EHCI controller 未响应问题在 clock/resetUSBCMD0x00000001RUN bit 未置位表示 controller 未启动PHY CON0 bit[1:0]0x00表示 PHY 处于 reset 状态。这些值比dmesg文字描述更精确。6.3 一张表usbmon抓包中 5 类关键 packet 与对应寄存器状态抓包 Packet 类型Wireshark 过滤对应寄存器状态mtk_usb_dump诊断意义SET_ADDRESSusb.bRequest 0x05USBSTS中HCHalted0,Reclaim0Host controller 正常运行QH setup 成功GET_DESCRIPTOR(Device)usb.bRequest 0x06 usb.wValue 0x0100PHY CON1bit[15:12] 值异常PHY 信号质量差需调TX_PREEMPHASISSET_CONFIGURATIONusb.bRequest 0x09USBCMD中IntThreshold0x08中断阈值未设导致urb_complete不触发BULK IN(U 盘读)usb.transfer_type 0x02 usb.endpoint_number 0x81USBSTS中USBError1Endpoint NAK设备未就绪或 buffer overflowSTALLusb.setup.bmRequestType 0x02 usb.bRequest 0x00PHY CON0bit[8]0PHY reset 未释放需检查reset_control_deassert()我习惯在每次insmod ehci-mtk.ko后立即执行mtk_usb_dump_regs()并保存输出再对比usbmon抓包。当usbmon显示SET_ADDRESS成功但GET_DESCRIPTOR超时而mtk_usb_dump显示PHY CON10x00000000我就知道该去调TX_PREEMPHASIS了——这比翻 datasheet 快 10 倍。希望帮到你。本文还有配套的精品资源点击获取