Reverse Engineering the iPod Classic's Undocumented Mikey Chip
Reverse Engineering the iPod Classic’s Undocumented Mikey Chip
逆向工程 iPod Classic 未记录的 Mikey 芯片
My iPod Classic (7th gen) runs Rockbox, and I love almost everything about that arrangement. But the inline remote on Apple’s wired earbuds (the center play/pause button and the volume clicker) did nothing. Never has, for anyone running Rockbox on this family of iPods. 我的 iPod Classic(第七代)运行着 Rockbox 系统,我非常喜欢这种组合。但苹果有线耳机上的线控(中间的播放/暂停按钮和音量调节键)却毫无反应。对于所有在这个系列 iPod 上运行 Rockbox 的用户来说,它从来都没起过作用。
The reason is sitting right there in the Rockbox source: /* TODO: * - detect jack accessory * - support for remote buttons */ And honestly, fair enough. Rockbox on this iPod exists because volunteers reverse engineered Apple hardware with zero documentation, for free, since January 2011. Music, clickwheel, recording, all of it figured out the hard way. The earbud remote just never made it to the top of anyone’s list: the 2014 commit that added the button-interrupt plumbing called remote events “work in progress”, and the TODO landed in the audio driver in 2017. Nobody picked it up since. So I did.
原因就写在 Rockbox 的源代码里:/* TODO: * - detect jack accessory * - support for remote buttons */(待办事项:检测耳机配件、支持线控按钮)。说实话,这很合理。这款 iPod 上的 Rockbox 之所以存在,是因为自 2011 年 1 月以来,志愿者们在没有任何文档的情况下,免费对苹果硬件进行了逆向工程。音乐、点击轮、录音,所有功能都是通过艰苦的摸索实现的。耳机线控从未进入过任何人的优先级列表:2014 年添加按钮中断机制的提交将远程事件称为“进行中”,而这个 TODO 在 2017 年被放入了音频驱动程序中。从那以后,就再没人管过它。所以我接手了。
TL;DR The chip that decodes the iPod’s earphone remote (“Mikey”, I2C address 0x72) has no public documentation. At all. Anywhere. The only prior art was a 16-year-old reverse engineering writeup on a blog that no longer exists. A wiki mirror saved the day, straight out of xkcd 979. I swept the chip’s mode register through all 256 values on the device itself, found the one that enables button reporting (0x2f), and decoded the events. The hardware lies: the chip’s event engine falls asleep after ~5 seconds and reports button releases 1.8 seconds late. The result is a driver, under review upstream as Gerrit change 7677. All three buttons work. 简而言之:负责解码 iPod 耳机线控的芯片(代号“Mikey”,I2C 地址 0x72)没有任何公开文档。完全没有,任何地方都没有。唯一的参考资料是一篇 16 年前的逆向工程文章,发布在一个早已不存在的博客上。一个维基镜像网站拯救了一切,简直就像 xkcd 979 漫画里的情节。我在设备上遍历了该芯片模式寄存器的所有 256 个值,找到了启用按钮报告的那个值(0x2f),并解码了事件。硬件在撒谎:芯片的事件引擎会在约 5 秒后进入休眠,并且会延迟 1.8 秒才报告按钮释放。最终成果是一个驱动程序,目前正作为 Gerrit 变更 7677 在上游审核中。现在三个按钮都能正常工作了。
What do I do to fix it? If you’re not here for the reverse engineering story and just want working earbud buttons: I’ve published a prebuilt Rockbox image with the remote driver as ipod6g-mikey-v1. It works on the iPod Classic 6G and 7th gen, and assumes your iPod already runs Rockbox (bootloader installed via the official Rockbox Utility). 我该如何修复它?如果你不是为了看逆向工程故事,只是想让耳机按钮能用:我已经发布了一个预构建的 Rockbox 镜像,其中包含了这个线控驱动程序,版本号为 ipod6g-mikey-v1。它适用于 iPod Classic 6G 和 7 代,前提是你的 iPod 已经运行了 Rockbox(通过官方 Rockbox Utility 安装了引导加载程序)。
- Download rockbox.zip from the release
- Connect the iPod in disk mode and unzip it onto the drive root (it replaces the .rockbox firmware files; your settings, themes, database, and music are untouched)
- Eject and reboot Play/pause then works on every screen, volume works everywhere including menus (hold to ramp), and the remote keeps working with the hold switch on. This doesn’t touch the bootloader, so worst case you delete .rockbox from disk mode and unzip an official build back. Once the change merges upstream, switch back to the official daily builds.
- 从发布页面下载 rockbox.zip。
- 将 iPod 以磁盘模式连接,并将其解压到驱动器根目录(它会替换 .rockbox 固件文件;你的设置、主题、数据库和音乐不会受到影响)。
- 弹出并重启。 之后,播放/暂停功能在任何界面都有效,音量调节在任何地方(包括菜单,长按可连续调节)都有效,并且在开启锁定开关(Hold)时线控依然可用。这不会触及引导加载程序,所以最坏的情况就是你在磁盘模式下删除 .rockbox 并解压回官方版本。一旦该变更合并到上游,你就可以切回官方每日构建版了。
Bonus: custom boot screen. While I was in there, I also built a Rockbox Boot Logo Patcher that swaps the Rockbox startup logo for any image you like, right in your browser. Works on every iPod Rockbox supports. 额外福利:自定义启动画面。在处理这些工作时,我还制作了一个 Rockbox 启动 Logo 修补工具,可以直接在浏览器中将 Rockbox 的启动 Logo 替换为你喜欢的任何图片。适用于所有 Rockbox 支持的 iPod。
A chip named Mikey, documented nowhere. Quick cast of characters. The iPod Classic (mine is the 7th gen; Rockbox names the whole family “ipod6g” after the 2007 original) has a dedicated little controller for the headphone jack that Apple’s firmware calls “Mikey”. It sits on I2C bus 0 at address 0x72, has 8 registers, and handles two jobs: powering the headset microphone and decoding the inline remote buttons. Rockbox has always known it exists, but only ever used it for one thing: raising the mic bias voltage so jack recording works. 一个名为 Mikey 的芯片,没有任何文档。简单介绍一下角色:iPod Classic(我的是第七代;Rockbox 将整个系列统称为“ipod6g”,源自 2007 年的首款机型)有一个专门用于耳机插孔的小控制器,苹果固件将其称为“Mikey”。它位于 I2C 总线 0 上,地址为 0x72,拥有 8 个寄存器,负责两项工作:为耳机麦克风供电和解码线控按钮。Rockbox 一直知道它的存在,但只用它做过一件事:提高麦克风偏置电压,以便插孔录音功能正常工作。
Before touching a wire, I went looking for anyone who had done this before. The search was thorough and completely empty: freemyipod, the community that reverse engineered this iPod enough to run custom code on it in the first place, has no Mikey driver and no register docs. Rockbox’s Gerrit: I couldn’t find any abandoned attempts. GitHub code search for “mikey” returns the Atari Lynx sound chip and a Blue microphone accessory. openiBoot, the old iPhone Linux project, never did headset accessories. macOS ships an AppleMikeyDriver.kext, which proves the name is real, but nobody ever documented its internals, and on Macs the equivalent logic lives inside the audio codec anyway. An undocumented chip, an unfinished driver, and 15 years of nobody picking it up. 在动手之前,我先寻找是否有前人做过这件事。搜索非常彻底,但一无所获:freemyipod(最初对这款 iPod 进行逆向工程以运行自定义代码的社区)没有 Mikey 驱动程序,也没有寄存器文档。Rockbox 的 Gerrit:我找不到任何被放弃的尝试。在 GitHub 上搜索“mikey”返回的是 Atari Lynx 的声音芯片和 Blue 麦克风配件。古老的 iPhone Linux 项目 openiBoot 从未涉及耳机配件。macOS 中包含一个 AppleMikeyDriver.kext,证明了这个名字是真实的,但从未有人记录过其内部结构,而且在 Mac 上,类似的逻辑其实存在于音频编解码器内部。一个未记录的芯片,一个未完成的驱动程序,以及 15 年来无人问津的空白。
From an earlier session I already had half a win: raise the mic bias (write 7 to register 0, the same value the recording path uses) and the center button shows up as a nonzero value in register 4. Play/pause worked. Volume was a wall. My working theory was that volume rode some undocumented serial protocol, with an interrupt on GPIO E6 announcing new data. That theory was wrong in every detail, and the E6 interrupt never fired once during the entire project. Not once. 在之前的尝试中,我已经取得了一半的胜利:提高麦克风偏置(向寄存器 0 写入 7,与录音路径使用的值相同),中间按钮就会在寄存器 4 中显示为一个非零值。播放/暂停功能成功了。但音量调节却像是一堵墙。我当时的工作假设是音量通过某种未记录的串行协议传输,并由 GPIO E6 上的中断来通知新数据。这个理论在每一个细节上都是错误的,而且在整个项目期间,E6 中断一次都没有触发过。一次都没有。
The DenverCoder9 moment. If you’ve spent any time debugging obscure problems, you know xkcd 979. Ten years of searching, one forum thread with your exact problem, and the only reply is the author saying “never mind, fixed it.” Searching for the remote’s wire protocol surfaced exactly one thread to pull: a Hackaday post from February 2010 and a matching 16-year-old Reddit thread about David Carne reverse engineering the iPod shuffle 3G’s headphone remote. The same remote hardware my earbuds use. His site? Dead. david.carne.ca/shuffle_hax doesn’t even load anymore. Of course it’s dead, it’s been 16 years. Unlike DenverCoder9, though, the wisdom of the ancients turned out to be recoverable. A tinymicros.com wiki mirror preserved the full writeup, and a GitHub repo (reverse-shuffle) still carries an Arduino re-implementation of the accessory handshake. The ancients left notes after all. “DenverCoder9”时刻。如果你曾花时间调试过晦涩难懂的问题,你一定知道 xkcd 979。搜索了十年,终于找到了一个和你遇到完全相同问题的论坛帖子,但唯一的回复却是作者说:“没关系,修好了。”搜索线控的线路协议时,我只找到了唯一一条线索:一篇 2010 年 2 月的 Hackaday 文章,以及一篇 16 年前的 Reddit 帖子,内容是 David Carne 对 iPod shuffle 3G 耳机线控的逆向工程。那和我耳机使用的线控硬件是一样的。他的网站?挂了。david.carne.ca/shuffle_hax 甚至已经无法加载。当然它会挂,毕竟已经 16 年了。不过,与 DenverCoder9 不同的是,这些“古人的智慧”最终还是可以找回的。一个 tinymicros.com 的维基镜像保存了完整的文章,一个 GitHub 仓库(reverse-shuffle)仍然保留着配件握手协议的 Arduino 实现。古人终究还是留下了笔记。
What Carne figured out back in 2010. Carne’s data detonated my serial-protocol theory on contact. The remote is much, much dumber than I assumed: Carne 在 2010 年发现的内容。Carne 的数据一出现就彻底粉碎了我的串行协议理论。这个线控比我预想的要简单得多:
| Signal | What it actually is |
|---|---|
| Center button | A dead short of the mic line. That’s it. |
| Volume up | A static resistive load that droops the mic line from ~2.08V to ~1.68V |
| Volume down | A bigger load, drooping it to ~1.52V |
| The “smart” part | A one-time ultrasonic ID chirp 8.1ms after power-up (1.5ms at 280kHz, then 4.6ms at 244kHz), answered by a 4.8ms ACK pulse from the player |
| 信号 | 实际含义 |
|---|---|
| 中间按钮 | 麦克风线路的直接短路。仅此而已。 |
| 音量加 | 一个静态电阻负载,将麦克风电压从约 2.08V 拉低至约 1.68V |
| 音量减 | 一个更大的负载,将其拉低至约 1.52V |
| “智能”部分 | 上电 8.1ms 后的一次性超声波 ID 脉冲(280kHz 下 1.5ms,随后 244kHz 下 4.6ms),由播放器发送 4.8ms 的 ACK 脉冲响应 |
The chirp is identification, not DRM. Carne proved it by replicating the volume buttons with a plain resistor circuit. 这个脉冲是用于识别的,而不是 DRM(数字版权管理)。Carne 通过用简单的电阻电路复制音量按钮功能证明了这一点。