iMac Debian で EarPods が鳴らない原因

問題は iMac Retina 5K (2015) を Debian 13 に移行した環境で発生した[1]。EarPods をヘッドフォン端子に接続しても音声が出ない。内蔵スピーカーは正常に鳴り、GNOME の設定画面では出力先としてアナログヘッドフォンが選択されていた。ジャックの挿入も検出され、音量もミュート状態も異常には見えなかった。画面上では、ヘッドフォンが認識され、出力先として選ばれ、音量も確保されている。それでも実際の EarPods には音が届かない。この症状は、音声再生全体の故障ではなく、認識されたデバイスを実際に駆動する経路のどこかで制御が欠けていることを示している。

この障害には、二つの段階がある。第一に、GNOME や PipeWire、ALSA のミキサーは、利用者が確認しやすい出力先、音量、ミュート、ジャック検出を表示するが、HDA コーデック内部のピン制御までは直接示さない。第二に、HDA コーデックのピン制御は、単に端子が見えているだけでは成立せず、カーネルドライバーがその機種に必要な初期化処理を選べているかに依存する。今回の環境では、EarPods が見えているにもかかわらず鳴らなかった原因は、末端の音量設定ではなく、Cirrus Logic CS4206 を iMac17,1 の実機構成として初期化する処理が選ばれていなかった点にあった。

この構造を押さえないと、調査は音量、ミュート、出力先の再選択、設定画面の開閉といった操作を繰り返すだけになる。今回必要だったのは、画面に表示される正常さを一つずつ確認したうえで、それが保証していない層へ降りることである。音声サーバーがアナログ出力を認識していること、ALSA のミキサーがヘッドフォンジャックを検出していること、コーデック内部でヘッドフォン出力ピンがどう制御されていること、さらにその制御を選ぶカーネルドライバーの機種別処理が適用されていることは、それぞれ別の確認対象である。本稿の要点は、認識されているのに鳴らないという症状を、この階層のずれとして切り分けるところにある。


1. EarPods だけが鳴らないという症状を切り分ける

最初に確認できた事実は、症状が音声出力全体には広がっていないということである。内蔵スピーカーは通常どおり鳴っていた。これは、音声ファイル、再生アプリケーション、デスクトップ環境、内部オーディオデバイス全体が壊れているという説明を弱める。一方で、EarPods をヘッドフォン端子に挿すと無音になる。つまり、同じ内部オーディオに属する出力先のうち、内蔵スピーカーの経路は成立し、ヘッドフォン端子の経路だけが成立していない。

次に見るべきなのは、ヘッドフォン端子がまったく認識されていないのか、それとも認識されたうえで音が出ていないのかである。GNOME のサウンド設定では、出力先としてアナログヘッドフォンが表示され、選択されていた。ALSA 側でも、ヘッドフォンジャックの挿入状態は検出されていた。この事実により、端子の存在が見えていないという仮説は後退する。残るのは、端子が見え、出力先として選ばれているにもかかわらず、実際の物理出力を有効にする制御が通っていないという可能性である。

ここで調査対象は、Linux の音声機能一般ではなく、iMac17,1 に搭載された Cirrus Logic CS4206 のヘッドフォン出力経路へ絞られる。内蔵スピーカーとヘッドフォン端子は、利用者からは同じ「内部オーディオ」の出力先に見える。しかし HDA コーデック内部では、スピーカーとヘッドフォンは別の出力ピン、別のアンプ制御、別の初期化条件を持つ。内蔵スピーカーが鳴ることは、ヘッドフォン出力ピンが正しく駆動されていることの証明にはならない。むしろ、同じデバイス内で一方だけが鳴るという差分が、調査対象をヘッドフォン側のピン制御へ狭める根拠になる。

観点 確認できたこと この確認で狭まる範囲
内蔵スピーカー 通常どおり音が出ていた。 音声再生全体、再生アプリケーション、内部オーディオデバイス全体の故障という説明は弱くなる。
GNOME の表示 出力先としてアナログヘッドフォンが選ばれていた。 単純な出力先未選択や、デスクトップ環境で別の出力へ流れているという説明は成立しにくい。
ジャック検出 ヘッドフォン端子への挿入は検出されていた。 端子の存在そのものが見えていないという説明は後退する。
症状の局所性 内蔵スピーカーは鳴り、EarPods だけが無音だった。 調査対象は、同じ内部オーディオの中でもヘッドフォン出力ピンとその初期化処理へ狭まる。

この段階で得られる判断は、まだ原因の確定ではない。確定できるのは、調査の順序である。画面上の出力先、ジャック検出、音量設定を確認しただけでは、物理ピンが駆動されているかは分からない。次に確認すべきなのは、PipeWire がどの出力をシンクとして扱っているか、ALSA のミキサーがヘッドフォンをどの状態として公開しているか、さらに HDA コーデック内部でヘッドフォン出力ピンがどの制御値になっているかである。認識されているのに鳴らないという症状は、この順序で層を降りなければ説明できない。


2. GNOME の正常表示は下層の出力制御を保証しない

GNOME のサウンド設定は、利用者にとって最も近い確認場所である。出力先がアナログヘッドフォンとして表示され、音量スライダーが上がり、ミュートされていなければ、画面上は正常に見える。しかし、この画面が示しているのは、音声出力経路の一部であって、物理端子まで音が届くことの証明ではない。Linux のデスクトップ音声では、PipeWire が音声ストリームを扱い、WirePlumber が PipeWire 上の機器やノードの管理を担う構成が使われる[2][3]。wpctl はその状態を確認・制御するためのコマンドであり[4]、WirePlumber は ALSA のカードから PipeWire 側のデバイスやノードを作る[5]。Debian でも PipeWire 環境の確認手段として、wpctl status や wpctl inspect が案内されている[6]

この構造では、GNOME にアナログヘッドフォンと表示されることは、PipeWire と WirePlumber が ALSA 側の内部オーディオを出力先として扱えていることを意味する。第一段階として、音声サーバーの管理対象に内部オーディオが現れ、利用者向けの出力先として選択できる状態にはなっている。第二段階として、その出力先が HDA コーデック内部のどのピンへ接続され、そのピンの出力許可やヘッドフォンアンプ起動がどう設定されているかは、GNOME の表示だけでは分からない。画面上の認識は、信号経路の上位層が存在することを示すにとどまり、末端のピン制御が完了していることまでは保証しない。

今回の症状では、この差が決定的だった。GNOME はアナログヘッドフォンを出力先として表示していたが、実際には Cirrus Logic CS4206 のヘッドフォン出力ピンで必要な制御が欠けていた。GUI の表示、PipeWire のシンク、ALSA のミキサー、HDA コーデックのピン制御は、同じ音声出力を別々の層から見ている。上位層で出力先が選べることと、下位層でヘッドフォンアンプが駆動されていることは同じではない。認識されているのに鳴らないという症状は、この二つを分けて確認しなければ説明できない。

確認できること 確認できないこと
GNOME 利用者向けの出力先としてアナログヘッドフォンが表示され、選択されていることを確認できる。 HDA コーデック内部のピン制御やヘッドフォンアンプの起動状態までは確認できない。
PipeWire / WirePlumber 内部オーディオが音声サーバー上の出力先として管理されていることを確認できる。 Apple 機種向けのコーデック初期化が適用されているかどうかは確認できない。
ALSA ミキサー ヘッドフォンジャック検出、再生スイッチ、音量など、公開されたミキサー項目を確認できる。 ミキサー値が HDA コーデック内部の必要な制御ビットとして反映されているかは確認できない。
HDA コーデック ヘッドフォン出力に対応するピンの制御値、電源状態、接続先を確認できる。 その状態がなぜ選ばれたのか、機種別初期化が適用されたのかは、さらにカーネルドライバー側を確認する必要がある。

この章で確定するのは、GNOME の表示が誤っていたということではない。GNOME は、上位層から見える範囲では正しい状態を示していた。だが、その正しさは、物理端子まで音が届くために必要な条件の一部でしかない。次に確認すべきなのは、PipeWire がどの出力を持ち、ALSA のミキサーがヘッドフォンをどの状態として公開しているかである。そこで異常が見つからなければ、調査は HDA コーデック内部のピン制御へ進むことになる。


3. PipeWire と ALSA ミキサーで通常の設定不備を除外する

3.1 PipeWire 側のシンクを確認する

最初に確認したのは、PipeWire 側で内部オーディオがどのように扱われているかである。当初は PulseAudio 互換の pactl を使おうとしたが、コマンド自体が存在しなかった。この環境では PipeWire / WirePlumber を前提に状態を確認する必要があったため、wpctl を使った。ここで見たいのは、ヘッドフォン専用の出力が存在するかどうかではなく、内部オーディオのアナログ出力が音声サーバー上で失われていないかである。

1
2
3
4
5
6
7
8
9
10
11
12
13
wpctl status
Audio
 Devices:
        48. Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM] [alsa]
        49. 内部オーディオ               [alsa]
 Sinks:
        58. Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM] デジタルステレオ (HDMI) [vol: 0.00 MUTED]
     *  109. 内部オーディオ アナログステレオ [vol: 0.15]
 Sources:
     *  106. 内部オーディオ アナログステレオ [vol: 1.00]
Settings
 Default Configured Devices:
         0. Audio/Sink    alsa_output.pci-0000_00_1f.3.analog-stereo

この出力では、HDMI 音声とは別に、内部オーディオのアナログステレオがシンクとして存在している。既定の出力先も alsa_output.pci-0000_00_1f.3.analog-stereo になっており、音声が HDMI 側だけに向いている状態ではなかった。さらに wpctl inspect 109 で確認すると、ミキサー名は Cirrus Logic CS4206、ノード名は alsa_output.pci-0000_00_1f.3.analog-stereo だった。PipeWire 側から見る限り、内部オーディオのアナログ出力は認識され、既定の出力経路として扱われていた。

この確認で分かる範囲は限定されている。第一に、PipeWire / WirePlumber は内部オーディオを音声サーバー上の出力先として持っている。第二に、その出力先が ALSA のアナログステレオノードに対応している。だが、この二つは、ヘッドフォン端子の物理ピンが実際に駆動されていることまでは示さない。PipeWire はストリームとノードを扱う層であり、HDA コーデック内部の Pin Widget Control や、Apple 機種向けの初期化処理そのものを表示する層ではない。ここで除外できるのは、内部アナログ出力が音声サーバー上から消えているという可能性である。

3.2 ALSA ミキサーの値を確認する

次に ALSA のミキサー値を確認した。amixer は、ALSA のミキサー項目をコマンドラインから確認・変更するためのツールである[7]。この amixer が扱う ALSA は、Linux が音声機器をサウンドデバイスとして扱うための基盤であり[8]、利用者が直接触れる画面ではなく、カーネルドライバーと音声機器の間にある低い層の仕組みである。サウンドカードごとの音量、ミュート、ジャック検出などを公開する。ミキサーという語は、ここでは複数の音を混ぜる装置というより、音声機器が持つ音量やオンオフの制御項目の集まりを指している。amixer などのユーティリティは alsa-utils として提供されている[9]

PipeWire が上位の音声経路を持っていても、ALSA 側でヘッドフォンがミュートされていたり、ジャック検出が失敗していたりすれば、EarPods が無音になる説明は成り立つ。そのため、次の確認対象は ALSA が公開しているヘッドフォン関連のミキサー項目になる。ここで見る値は、音が最終的に出るかどうかの完全な証明ではないが、音量、ミュート、挿入検出という典型的な原因を除外するためには必要である。

1
2
3
4
5
amixer -c0 controls | grep -iE 'headphone|auto|mute'
numid=17,iface=CARD,name='Headphone Jack'
numid=2,iface=MIXER,name='Headphone Playback Switch'
numid=1,iface=MIXER,name='Headphone Playback Volume'
numid=5,iface=MIXER,name='Auto-Mute Mode'
1
2
3
4
5
6
7
8
9
10
11
amixer -c0 contents | grep -A5 -i headphone
numid=17,iface=CARD,name='Headphone Jack'
  ; type=BOOLEAN,access=r-------,values=1
  : values=on
numid=2,iface=MIXER,name='Headphone Playback Switch'
  ; type=BOOLEAN,access=rw------,values=2
  : values=on,on
numid=1,iface=MIXER,name='Headphone Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=127,step=0
  : values=115,115
  | dBscale-min=-57.50dB,step=0.50dB,mute=0

Headphone Jack は on であり、ヘッドフォン端子への挿入は検出されていた。Headphone Playback Switch は左右とも on で、ヘッドフォン出力はミュートされていなかった。Headphone Playback Volume も 115,115 で、音量不足と見る値ではない。つまり、ALSA が公開している範囲では、ジャック検出、再生スイッチ、音量のいずれも正常な値を示していた。

確認対象 実際の値 除外できる説明
Headphone Jack values=on であり、ヘッドフォン端子への挿入は検出されていた。 ジャックが認識されていないため音が出ない、という説明は成立しにくい。
Headphone Playback Switch values=on,on であり、左右チャンネルとも再生スイッチは有効だった。 ALSA ミキサー上でヘッドフォン出力がミュートされている、という説明は弱くなる。
Headphone Playback Volume values=115,115 であり、ヘッドフォン音量は十分に上がっていた。 音量が小さすぎるため無音に見える、という説明は取りにくい。
内部アナログ出力 PipeWire 上では内部オーディオ アナログステレオが既定シンクとして存在していた。 音声サーバー上で内部アナログ出力が失われている、という説明は後退する。

この結果により、原因は一段下へ移る。第一に、PipeWire は内部アナログ出力を持っており、音声サーバー上で出力先が消えているわけではなかった。第二に、ALSA ミキサーでは、ヘッドフォンジャック検出、再生スイッチ、音量がいずれも正常だった。にもかかわらず EarPods が無音である以上、ミキサー値そのものではなく、その値が HDA コーデック内部の物理出力制御へどう反映されているかを見なければならない。次に確認すべき対象は、Cirrus Logic CS4206 のヘッドフォン出力ピンである。


4. HDA コーデックの Node 0x0a で制御ビットの欠落を確認する

4.1 ヘッドフォン出力ピンを proc ファイルシステムから確認する

PipeWire と ALSA ミキサーの値に異常が見つからない場合、次に見るべき対象は HDA コーデック内部の状態である。HDA は High Definition Audio の略で、PC の内蔵音声機器を扱うための規格である。コーデックは、その規格の中で音声信号をアナログのスピーカー出力やヘッドフォン端子へつなぐチップを指す。ここでいうピンは、実際の端子や内部スピーカーにつながる出力口に近い制御単位である。画面上でアナログヘッドフォンが選ばれていても、このピンが正しい状態になっていなければ、EarPods には音が届かない。

ALSA の HDA ドライバーは、コーデックの状態を proc ファイルシステム経由で公開している。proc ファイルシステムは、通常の文書ファイルではなく、カーネルが現在見ている状態をテキストとして読めるようにした入口である。Linux カーネルの HDA 文書では、HD-audio は制御側のコントローラと、そのバス上に接続されるコーデックから成ると説明されている。snd-hda-intel はコントローラ側のドライバーであり、コーデックごとの処理には、汎用解析とコーデック固有の解析がある[10]。ここで確認するのは、音声サーバーやミキサーが出力先をどう見ているかではなく、Cirrus Logic CS4206 の内部でヘッドフォン出力ピンがどの制御値になっているかである。

この環境では、card0 が PCH、つまり内蔵オーディオであり、card1 が Radeon 側の HDMI 音声に対応していた。ヘッドフォン端子は内蔵オーディオ側にあるため、確認対象は card0 の codec#0 になる。zsh では codec#0 の # がグロブの特殊文字として扱われるため、対象パスは引用符で囲む必要があった。この時点の確認は、単なるファイル参照ではなく、GUI やミキサーからは見えないコーデック内部のピン状態を読む作業である。

1
2
3
4
5
ls /proc/asound/
HDMI  PCH  card0  card1  cards  devices  hwdep  modules  oss  pcm  seq  timers  version
ls /proc/asound/card0/
codec#0  id  pcm0c  pcm0p  pcm1p
cat "/proc/asound/card0/codec#0" | sed -n '/Node 0x0a/,/Node 0x0b/p'

ヘッドフォン出力に対応する Node 0x0a は、次の状態だった。

1
2
3
4
5
6
7
8
9
10
11
12
Node 0x0a [Pin Complex] wcaps 0x410581: Stereo
  Pincap 0x00000054: OUT Detect Balanced
  Pin Default 0x002b4020: [Jack] HP Out at Ext N/A
    Conn = Comb, Color = Green
    DefAssociation = 0x2, Sequence = 0x0
  Pin-ctls: 0x40: OUT
  Unsolicited: tag=01, enabled=1
  Power states:  D0 D3 EPSS
  Power: setting=D3, actual=D3
  Delay: 1 samples
  Connection: 1
     0x03

4.2 Pin-ctls の 0x40 はヘッドフォン出力としては不足している

Node 0x0a の出力で注目すべき値は Pin-ctls である。Node は、HDA コーデック内部の部品番号のようなものである。0x0a は、この環境ではヘッドフォン出力に対応する部品を指していた。Pin-ctls は Pin controls の略で、その出力ピンをどの状態で動かすかを表す値である。ここで出てくる 0x40、0x80、0xc0 は 16 進数であり、単なる通し番号ではない。複数のスイッチのオンオフを 1 つの値にまとめたものとして読む必要がある。

HDA のピン制御では、出力を有効にするビットと、ヘッドフォン出力を有効にするビットが分かれている。Linux カーネルの hda_verbs.h では、Pin Widget Control に対応する定数として、出力有効化を示す AC_PINCTL_OUT_EN と、ヘッドフォン出力を示す AC_PINCTL_HP_EN が定義されている[11]。この環境で見えていた Pin-ctls は 0x40 であり、これは出力有効化だけが立った状態である。ヘッドフォン出力として期待される制御には、さらに 0x80 が加わり、0xc0 になる必要がある。0x40 に 0x80 が加わると 0xc0 になるため、この差はヘッドフォン出力としての追加スイッチが入っているかどうかを示している。つまり、端子そのものは出力先として見えていても、ヘッドフォンとして鳴らすための追加スイッチが入っていなかった。

この差は、見かけ上の設定では見つからない。ALSA ミキサーでは Headphone Jack が on であり、Headphone Playback Switch も左右とも on だった。それでも Pin-ctls が 0x40 のままであれば、コーデック内部ではヘッドフォン用の出力制御が完了していない。第一段階として、ジャック検出とミキサー値は利用者空間に公開される状態として正常だった。第二段階として、その状態が HDA コーデック内部のヘッドフォン出力制御まで反映されていなかった。この二つを分けることで、無音の直接原因は音量やミュートではなく、Node 0x0a のピン制御にあると分かる。

確認対象 観測された値 意味
Node 0x0a Pin Default では HP Out として表示されており、ヘッドフォン出力に対応するピンであることが確認できた。 調査対象は、内蔵オーディオ全体ではなくヘッドフォン出力ピンへ絞られる。
Pin-ctls 0x40: OUT であり、出力有効化だけが立っていた。 ヘッドフォン出力に必要な 0x80 が加わっておらず、期待される 0xc0 になっていなかった。
Power 初回確認時は setting=D3, actual=D3 だった。 省電力状態の影響を疑う余地があるため、再生中の状態を確認する必要がある。
Connection Node 0x03 に接続されていた。 後続の確認では、ヘッドフォン出力ピンだけでなく、その上流にある DAC 側の状態も確認対象になる。

4.3 再生中でも Pin-ctls は 0x40 のままだった

初回確認時に Power が D3 だったため、省電力状態によって無音になっている可能性を確認した。HDA コーデックでは、未使用時に D3 へ下がり、再生時に D0 へ移ることがある。そのため、停止中の値だけを見て原因を確定すると、電源管理とピン制御を取り違える危険がある。そこで、別の端末で実際に音声を再生しながら Node 0x0a を再確認した。

1
2
3
4
pw-play /usr/share/sounds/alsa/Front_Center.wav
cat "/proc/asound/card0/codec#0" | sed -n '/Node 0x0a/,/Node 0x0b/p'
Power: setting=D0, actual=D0
Pin-ctls: 0x40: OUT

再生中には Power が D0 へ移行しており、コーデックが省電力状態のまま固定されているわけではなかった。一方で、Pin-ctls は 0x40 のまま変化しなかった。この結果により、原因は二段階で絞られる。まず、再生中に D0 へ移るため、単純な電源復帰失敗ではない。次に、D0 へ移ってもヘッドフォン出力に必要な 0x80 が立たないため、問題は電源状態ではなく、ヘッドフォン出力ピンの制御値が期待どおりに設定されない点に残る。

4.4 内蔵スピーカー側との比較で、問題は Node 0x0a に局所化される

正常に鳴っている内蔵スピーカー側の Node 0x0b も確認した。内蔵スピーカーが鳴っている以上、比較対象として有効である。同じコーデック内で、鳴る出力と鳴らない出力の差を見れば、音声経路全体の故障ではなく、どのピンの制御に差があるのかを確認できる。

1
2
3
4
5
6
7
8
9
10
Node 0x0b [Pin Complex] wcaps 0x410101: Stereo
  Pincap 0x00000050: OUT Balanced
  Pin Default 0x90100112: [Fixed] Speaker at Int N/A
    Conn = Unknown, Color = Unknown
    DefAssociation = 0x1, Sequence = 0x2
    Misc = NO_PRESENCE
  Pin-ctls: 0x40: OUT
  Delay: 1 samples
  Connection: 1
     0x04

Node 0x0b は内蔵スピーカーに対応し、Pin Default でも Speaker として示されている。ここでは Pin-ctls が 0x40 であっても、内蔵スピーカーとしては音が出ていた。これに対し、Node 0x0a は HP Out として定義されているにもかかわらず、ヘッドフォン出力に必要な制御が 0xc0 になっていない。両者の差は、同じ 0x40 という値そのものではなく、そのピンがスピーカー用なのか、ヘッドフォン用なのかという役割にある。ヘッドフォン用の Node 0x0a では、出力有効化だけでは足りず、ヘッドフォン出力としての制御が必要になる。

この章で確認できた直接原因は、EarPods が認識されていないことではなく、ヘッドフォン出力に対応する Node 0x0a の Pin-ctls が再生中も 0x40 に留まり、期待される 0xc0 になっていないことである。ただし、これだけでは根本原因までは分からない。制御ビットが欠けている事実と、そのビットを誰が設定すべきかは別の問題である。次に必要なのは、欠けた 0x80 を手動で設定できるのか、設定しても維持されるのかを確認することである。そこで初めて、単なるビット設定の不足なのか、ドライバーが機種別の初期化処理を選べていないのかを分けられる。


5. 手動操作で解決しないことが機種認識の問題を示した

5.1 欠けた制御ビットを hda-verb で直接書き込む

Node 0x0a の Pin-ctls が 0x40 に留まり、ヘッドフォン出力に必要な 0x80 が加わっていないことは確認できた。次に分けるべきなのは、この欠落が単なる一時的な設定不足なのか、それともドライバーが正しい初期化経路を選べていないために生じているのかである。前者であれば、HDA コーデックへ直接 0xc0 を書き込めば症状が変わる可能性がある。後者であれば、単発の書き込みはドライバー側の処理によって元の値へ戻される。

この確認に使ったのが hda-verb である。hda-verb は Intel HDA デバイスへ HD-audio コマンドを送るための小さなツールであり、Debian では alsa-tools パッケージに含まれる[12][13]。この調査で新規にインストールしたパッケージは alsa-tools である。wpctl、amixer、dmesg、modinfo は調査に使ったが、少なくともこの手順で追加導入したものとして記録すべきなのは alsa-tools である。

1
2
3
4
5
6
7
sudo apt install alsa-tools
sudo hda-verb /dev/snd/hwC0D0 0x0a SET_PIN_WIDGET_CONTROL 0xc0
nid = 0xa, verb = 0x707, param = 0xc0
value = 0x0
sudo hda-verb /dev/snd/hwC0D0 0x0a GET_PIN_WIDGET_CONTROL 0
nid = 0xa, verb = 0xf07, param = 0x0
value = 0x40

SET_PIN_WIDGET_CONTROL で 0xc0 を指定した直後に GET_PIN_WIDGET_CONTROL で読み出すと、値は 0x40 に戻っていた。SET 系のコマンドで表示される value = 0x0 は、期待した制御状態になったことを意味しない。実際に反映された値は、GET 系のコマンドで読み直して確認する必要がある。この確認では、書き込み要求そのものは送られているが、Node 0x0a の最終状態として 0xc0 は維持されなかった。

この結果は、原因を一段深く絞る。第一に、0xc0 という値を知らなかったわけではなく、ヘッドフォン出力ピンに対して実際に書き込みを試している。第二に、その値が保持されず 0x40 へ戻るため、単発の手動操作では制御状態を固定できない。値を戻している主体は、利用者のシェル操作ではなく、HDA ドライバー側の初期化または状態管理である可能性が高い。ここで調査対象は、Node 0x0a へ何を書くかではなく、なぜドライバーがこの機種で 0xc0 を選ばないのかへ移る。

5.2 DAC、アンプ、Auto-Mute、GPIO を個別に確認する

ただし、Pin-ctls が戻るだけで、直ちに機種認識の問題と確定できるわけではない。ヘッドフォン出力の上流にある DAC が動いていない場合、Node 0x0a のアンプがミュートされている場合、ヘッドフォン挿入時の自動切替が無効な場合、あるいは Apple の実装で外部アンプ制御に GPIO が関係している場合も考えられる。そこで、周辺要因を個別に確認した。

まず、Node 0x0a の接続先として示されていた Node 0x03 を確認した。Node 0x03 は、デジタル信号をアナログ信号へ変換する DAC 側の出力である。DAC は Digital to Analog Converter の略で、計算機内部のデジタル音声をスピーカーやヘッドフォンで鳴らせる電気信号へ変える部分を指す。この段でストリームが割り当てられていなければ、ヘッドフォンピン以前に信号が来ていないことになる。

1
2
3
4
5
6
7
8
9
10
cat "/proc/asound/card0/codec#0" | sed -n '/Node 0x03/,/Node 0x04/p'
Node 0x03 [Audio Output] wcaps 0xd041d: Stereo Amp-Out
  Control: name="Headphone Playback Volume", index=0, device=0
  Control: name="Headphone Playback Switch", index=0, device=0
  Amp-Out caps: ofs=0x73, nsteps=0x7f, stepsize=0x01, mute=1
  Amp-Out vals:  [0x5c 0x5c]
  Converter: stream=1, channel=0
  Power states:  D0 D3 EPSS
  Power: setting=D0, actual=D0
  Delay: 13 samples

Node 0x03 には stream=1 が割り当てられており、Amp-Out vals にもミュートを示す 0x80 は含まれていなかった。つまり、ヘッドフォン側へ向かう上流の DAC が完全に止まっているという説明は取りにくい。次に、Node 0x0a 自体のアンプミュート状態を確認した。

1
2
3
4
5
6
sudo hda-verb /dev/snd/hwC0D0 0x0a GET_AMP_GAIN_MUTE 0xb000
nid = 0xa, verb = 0xb00, param = 0xb000
value = 0x0
sudo hda-verb /dev/snd/hwC0D0 0x0a GET_AMP_GAIN_MUTE 0xb080
nid = 0xa, verb = 0xb00, param = 0xb080
value = 0x0

左右チャンネルとも値は 0x0 であり、アンプミュートが立っている状態ではなかった。続いて Auto-Mute Mode を確認した。これは、ヘッドフォン挿入時にスピーカーとヘッドフォンの切り替えを行う項目である。無効になっていたため Enabled に変更したが、EarPods の無音は変わらなかった。

1
2
3
4
5
6
7
8
9
10
11
12
amixer -c0 contents | grep -A6 -i "Auto-Mute"
numid=5,iface=MIXER,name='Auto-Mute Mode'
  ; type=ENUMERATED,access=rw------,values=1,items=2
  ; Item #0 'Disabled'
  ; Item #1 'Enabled'
  : values=0
amixer -c0 cset name='Auto-Mute Mode' 'Enabled'
numid=5,iface=MIXER,name='Auto-Mute Mode'
  ; type=ENUMERATED,access=rw------,values=1,items=2
  ; Item #0 'Disabled'
  ; Item #1 'Enabled'
  : values=1

最後に GPIO も確認した。Apple の一部機種では、標準的な HDA ピン制御だけではなく、GPIO によるアンプや経路の追加制御が関係することがある。この環境では IO[1] が有効化され、出力方向に設定されていたため、データビットの反転も試した。しかし、これでも症状は変わらなかった。

1
2
3
4
5
GPIO: io=4, o=0, i=0, unsolicited=0, wake=0
  IO[0]: enable=0, dir=0, wake=0, sticky=0, data=0, unsol=0
  IO[1]: enable=1, dir=1, wake=0, sticky=0, data=1, unsol=0
  IO[2]: enable=0, dir=0, wake=0, sticky=0, data=0, unsol=0
sudo hda-verb /dev/snd/hwC0D0 0x01 SET_GPIO_DATA 0x00

5.3 個別操作で消えた仮説を整理する

ここまでの検証は、試行錯誤の羅列ではない。各操作は、原因候補を一つずつ消すために行っている。Node 0x03 にストリームが割り当てられているなら、上流の DAC が止まっているという説明は弱くなる。Node 0x0a のアンプミュートが立っていないなら、ミュート解除だけで直る問題ではない。Auto-Mute Mode や GPIO の単純な反転で変わらないなら、利用者空間から見える切り替え項目や単純な GPIO 操作だけでは症状を説明できない。

検証対象 疑ったこと 結果 消えた仮説
Pin Widget Control Node 0x0a に 0xc0 を書けば、ヘッドフォン出力に必要な制御が成立する可能性を確認した。 書き込み直後の読み出しで 0x40 へ戻った。 単発の手動設定で解決できるという説明は弱くなった。
Node 0x03 DAC からヘッドフォン出力ピンへ信号が来ていない可能性を確認した。 stream=1 が割り当てられ、Amp-Out もミュートされていなかった。 上流の信号経路が止まっているという説明は成立しにくい。
Node 0x0a のアンプ ヘッドフォン出力ピン側のアンプ自体がミュートされている可能性を確認した。 左右チャンネルともミュートビットは立っていなかった。 アンプのミュート解除だけで直るという説明は採れない。
Auto-Mute Mode ヘッドフォン挿入時の自動切替が無効なため、出力経路が切り替わっていない可能性を確認した。 Enabled に変更しても症状に変化はなかった。 自動切替設定だけが原因という説明は弱くなった。
GPIO 外部アンプや経路制御に関係する GPIO の単純な反転で音が出る可能性を確認した。 データビットを反転しても音は出なかった。 単純な GPIO 反転だけで解決するという説明は成立しなかった。

この段階で残る原因は、個別の値ではなく、それらの値を選ぶ処理である。第一に、HDA コーデックの上流信号、ミュート、音量、切り替え項目は、いずれも無音の直接説明にはならなかった。第二に、ヘッドフォン出力に必要な 0xc0 を手動で書いても 0x40 に戻るため、ドライバー側の管理がその状態を維持していない。帰結として、調査はコーデックのビット操作から、ALSA HDA ドライバーが iMac17,1 という機種をどのモデルとして初期化しているかへ進む。ここから先の焦点は、値の不足ではなく、機種別フィックスアップの適用有無である。


6. iMac17,1 に必要な機種別フィックスアップが自動適用されていなかった

6.1 コーデック情報と機種情報を対応させる

手動で Node 0x0a に 0xc0 を書いても 0x40 に戻る以上、次に確認すべき対象は、HDA ドライバーがこの実機をどのモデルとして初期化しているかである。ドライバーは、Linux カーネルの中で実際の機器を操作するためのプログラムである。利用者が画面で音量を変える前に、ドライバーは接続された音声チップを認識し、その機種で必要な初期設定を行う。ALSA HDA の文書では、対応する既知モデルが見つかると、ドライバーはそのモデルに用意された静的な設定や補正処理を使い、見つからない場合は汎用の自動設定へ寄ると説明されている。また、必要に応じて model オプションで既知モデルを明示できる[14]。この補正処理は一般にフィックスアップと呼ばれる。ここでいうフィックスアップは、音量やミュートのように利用者が操作する設定ではなく、特定の機種で必要になるピン割り当て、アンプ制御、GPIO などをドライバー側で補うための機種別処理である。

今回の環境でコーデックの先頭情報を確認すると、Codec は Cirrus Logic CS4206、Subsystem Id は 0x106b8200 だった。Vendor Id はコーデックそのものの種類を示し、Subsystem Id はそのコーデックがどのような実装として搭載されているかを識別する手がかりになる。HDA の障害では、同じコーデック名であっても搭載機種が違えば必要な初期化が変わるため、コーデック名だけでは判断できない。

1
2
3
4
5
6
7
head -20 "/proc/asound/card0/codec#0"
Codec: Cirrus Logic CS4206
Address: 0
AFG Function Id: 0x1 (unsol 0)
Vendor Id: 0x10134206
Subsystem Id: 0x106b8200
Revision Id: 0x100302

機種情報は DMI から確認できた。product_name は iMac17,1、product_version は 1.0 である。これにより、音が出ない対象は、単なる CS4206 搭載機ではなく、iMac17,1 に搭載された CS4206 として扱うべきことが分かる。

1
2
3
4
cat /sys/class/dmi/id/product_name
iMac17,1
cat /sys/class/dmi/id/product_version
1.0

この対応関係が必要になる理由は二段階で整理できる。第一に、HDA コーデックは標準化された形で見えていても、実機上の配線やアンプ制御は機種ごとに異なる。第二に、Linux カーネルがその機種に必要な補正処理を選べなければ、ジャック検出やミキサー値が正常でも、末端のヘッドフォン出力ピンに必要な制御が入らない。今回の Node 0x0a が 0x40 に戻る挙動は、この機種別処理の不足を疑う根拠になる。

6.2 カーネルログに機種別処理の適用痕跡は見つからなかった

次に、カーネルログからフィックスアップや機種別処理の適用痕跡を確認した。dmesg はカーネルリングバッファを表示・制御するコマンドであり[15]、デバイス初期化時にドライバーが何を検出し、どの処理を選んだかを確認する手がかりになる。ここでは、fixup、quirk、sysid、apple、imac などの語で検索した。

1
2
sudo dmesg | grep -iE 'fixup|quirk|sysid|apple|imac'
(該当出力なし)

該当出力がないことだけで、ドライバー内部のすべての判断を完全に否定できるわけではない。しかし、ここまでの観測と組み合わせると意味を持つ。第一に、Node 0x0a の Pin-ctls は再生中でも 0x40 のままで、ヘッドフォン出力に必要な 0x80 が立っていなかった。第二に、手動で 0xc0 を書いても直後に 0x40 へ戻った。第三に、カーネルログには iMac 向けの補正処理が選ばれた形跡が見つからなかった。この三つを重ねると、汎用の自動設定だけで CS4206 が初期化され、iMac17,1 に必要な機種別処理が入っていない可能性が高くなる。

ここで原因の階層が変わる。値そのものを操作する段階では、Node 0x0a に 0xc0 を書くことが焦点だった。だが、値が保持されない以上、見るべきなのは、どの値を利用者が一度書くかではなく、ドライバーが起動時や挿抜時にどの初期化規則を使ってその値を選んでいるかである。ヘッドフォンが認識されているのに鳴らないという現象は、コーデックの故障ではなく、機種別初期化の選択漏れとして説明できる段階に入る。

6.3 model パラメーターを指定する相手は snd-hda-codec-cirrus ではない

この段階で一度、snd-hda-codec-cirrus 側へ model パラメーターを指定する設定を考えた。コーデック名が Cirrus Logic CS4206 であるため、直感的には Cirrus 用のモジュールへ model を渡したくなる。しかし、この判断は誤りだった。modinfo はカーネルモジュールの情報を表示するコマンドであり[16]、実際に snd_hda_codec_cirrus のパラメーターを確認すると、model パラメーターは見つからなかった。

1
2
modinfo snd_hda_codec_cirrus | grep -A30 parm
(該当出力なし)

この確認は、単なる作業上の寄り道ではない。HDA の構造では、snd-hda-intel がコントローラ側のドライバーとして動き、その上でコーデック固有の処理が呼ばれる。model オプションを受け取る入口は、コーデック名を含む snd-hda-codec-cirrus ではなく、HDA コントローラ側の snd-hda-intel である。Linux カーネルの ALSA 設定文書でも、snd-hda-intel の model オプションはモデル名を強制するための項目として説明され、機器が一覧にない場合は model=name の形で特定モデルを指定できる[17]

この失敗分岐を明示することで、恒久対応の位置づけがはっきりする。Cirrus Logic CS4206 の問題だから Cirrus 側モジュールに指定するのではなく、HDA コントローラの初期化時に、既知モデルとして iMac 向けの処理を選ばせる必要がある。つまり、対応対象はコーデック単体ではなく、コントローラドライバーがコーデックをどのモデルとして扱うかという層にある。

6.4 modprobe.d の options はモジュール読み込み時に適用される

model オプションをどこへ指定するかが分かれば、次に確認すべきなのは、それをどの仕組みで永続化するかである。/etc/modprobe.d の options 行は、対象モジュールがカーネルへ挿入されるたびにオプションを追加する仕組みである[18]。Debian でもカーネルモジュール管理は modprobe を中心に説明されており、モジュール読み込み時の設定ファイルとしてこの仕組みを使う[19]

この性質により、model 指定は hda-verb のような一時的な書き込みとは異なる。hda-verb は動作中の HDA デバイスへ個別のコマンドを送るが、その値はドライバーの状態管理によって上書きされる可能性がある。modprobe.d の options は、snd-hda-intel が読み込まれる時点で model=imac27_122 を渡すため、コーデック初期化の入口そのものに作用する。手動で 0xc0 を後から書くのではなく、起動時に正しいモデルとして初期化させることが目的になる。

ここでいう永続性は、設定ファイルとしての永続性である。/etc/modprobe.d に設定が残り、snd-hda-intel が同じ仕組みで読み込まれる限り、再起動のたびに model オプションは渡される。一方で、将来のカーネル更新、別の設定ファイルとの競合、明示指定の削除、あるいはカーネル側で iMac17,1 向けの自動処理が追加されることにより、運用上の扱いは変わり得る。恒久対応とは、あらゆる将来変更から独立した永久保証ではなく、現行環境で起動時の初期化経路を安定させる設定である。

6.5 imac27_122 はカーネル文書と既知事例の両方から選ぶ

選ぶべきモデル名は、Linux カーネルの HD-Audio Codec-Specific Models で確認できる。Cirrus Logic CS4206/4207 の項目には、imac27、imac27_122、apple などが定義されている[20]。この一覧は、imac27_122 という文字列が単なるフォーラム上の経験則ではなく、カーネルが認識する既知モデル名であることを示す。

ただし、モデル名が一覧にあるだけでは、今回の iMac17,1 に最適だとはまだ言えない。そこで、同じ機種、近い機種、同じコーデック、同じ症状の既知事例を確認する。27-inch 2015 iMac でヘッドフォンだけが鳴らない事例では、model=imac27_122 の指定と再起動で解決した報告がある[21]。Late 2015 27-inch iMac の別事例でも、同じ指定でヘッドフォンジャックから音が出るようになっている[22]。Arch Linux の iMac 27 2015 / Cirrus Logic CS4206 事例でも、model=imac27_122 を設定ファイルに置いて再起動することで解決したと記録されている[23]。Ubuntu の HDA Intel 向け手順でも、snd-hda-intel に model オプションを渡す方法は音声不具合の回避策として説明されている[24]。Fedora 系の近縁 iMac 事例でも、Cirrus Logic CS4206 を搭載した iMac の音声出力問題が報告されている[25]

比較項目 今回の環境 既知事例との対応
機種 iMac17,1、27 インチ、2015 年モデルだった。 Linux Mint の事例では iMac17,1、Arch Linux の事例では iMac 27 2015 が報告されている。
コーデック Cirrus Logic CS4206、Subsystem Id は 0x106b8200 だった。 Arch Linux の事例でも Cirrus Logic CS4206 が示されている。
症状 ジャック検出や音量設定は正常だが、EarPods から音が出なかった。 スピーカーは鳴るがヘッドフォンだけが無音、またはヘッドフォンジャックが機能しないという点が一致する。
対応 snd-hda-intel に model=imac27_122 を指定する方針へ進んだ。 複数の事例で同じ model=imac27_122 が有効だった。

この対応関係により、model=imac27_122 を選ぶ根拠は二重になる。第一に、Linux カーネル文書上、imac27_122 は CS4206/4207 系の既知モデルとして定義されている。第二に、iMac 27 インチ 2015 年モデル、CS4206、ヘッドフォン無音という条件が重なる既知事例で、同じ指定による解決が記録されている。ここまで確認すると、次の作業は個別ビットの操作ではなく、snd-hda-intel の読み込み時に model=imac27_122 を渡し、起動時の初期化経路を変更することになる。


7. snd-hda-intel の model 指定で恒久対応する

7.1 対応はビットの手動書き込みではなく起動時の model 指定で行う

根本原因が機種別フィックスアップの未適用であるなら、対応は Node 0x0a に 0xc0 を手で書き続けることではない。hda-verb による書き込みは、動作中の HDA コーデックへ個別の命令を送る操作であり、ドライバーが管理する状態を恒久的に変えるものではなかった。実際、SET_PIN_WIDGET_CONTROL で 0xc0 を指定しても、直後の読み出しでは 0x40 に戻っていた。必要なのは、出力ピンの値を後から上書きすることではなく、snd-hda-intel が Cirrus Logic CS4206 を初期化する時点で、iMac17,1 に近い Apple iMac 向けの既知モデルとして扱わせることである。

この違いは、対応の安定性に直結する。第一に、手動書き込みは、すでに起動したドライバーの状態に対して一時的に介入するだけであり、再起動や再初期化で失われる。第二に、modprobe.d による model 指定は、snd-hda-intel が読み込まれる時点で model=imac27_122 を渡し、コーデック初期化の入口を変える。今回の無音は、ヘッドフォン出力ピンが存在しないためではなく、そのピンを iMac 向けに初期化する処理が選ばれていなかったために起きていた。従って、最終対応は、実行中のビット操作ではなく、起動時の機種モデル指定になる。

7.2 誤った設定ファイルを削除し、正しい設定ファイルだけを残す

最終的に残す設定は、snd-hda-intel に model=imac27_122 を渡す 1 行である。先に作成した snd-hda-codec-cirrus 向けの設定ファイルは、model パラメーターを受け取る相手が違うため削除する。Cirrus Logic CS4206 というコーデック名に引きずられると、snd-hda-codec-cirrus へ指定したくなるが、この環境で model オプションを受け取る入口は HDA コントローラ側の snd-hda-intel である。

1
2
3
4
sudo rm /etc/modprobe.d/cs4206-imac.conf
echo "options snd-hda-intel model=imac27_122" | sudo tee /etc/modprobe.d/mac-fix.conf
options snd-hda-intel model=imac27_122
sudo reboot

再起動後、EarPods からの音声出力は正常化した。ここで効いたのは、ヘッドフォン出力の値をその場で書き換える操作ではなく、ドライバーがコーデックを初期化する時点で別の機種モデルを使わせる設定である。HDA の model 指定は、ユーザー空間で音量を上げる設定ではない。カーネルドライバーがどの機種向けの初期化経路を通るかを変える指定である。


8. 作成ファイル、削除ファイル、導入パッケージ、永続性を整理する

8.1 最終的に残す設定ファイルは mac-fix.conf だけである

最終的に残す設定ファイルは /etc/modprobe.d/mac-fix.conf である。内容は 1 行だけで、snd-hda-intel に model=imac27_122 を渡す。この指定は、動作中の HDA コーデックに一度だけ値を書き込む操作ではない。snd-hda-intel が読み込まれる時点で、Cirrus Logic CS4206 を iMac 向けの既知モデルとして初期化させるための設定である。

1
2
cat /etc/modprobe.d/mac-fix.conf
options snd-hda-intel model=imac27_122

この設定が効く理由は二段階で整理できる。第一に、/etc/modprobe.d の options 行は、対象モジュールがカーネルへ挿入されるときに指定オプションを追加する。第二に、snd-hda-intel の model 指定は、コーデック初期化時にどの既知モデルを使うかを変える。hda-verb で Node 0x0a に 0xc0 を後から書く操作は、ドライバーの状態管理に上書きされる可能性があった。これに対し、mac-fix.conf は起動時の初期化経路そのものに作用する。

このため、再起動したら必ず元の無音状態に戻る、あるいは EarPods を抜き差ししたら必ず設定が失われる、という種類の対処ではない。設定ファイルが残り、snd-hda-intel が同じ仕組みで読み込まれる限り、再起動後も model=imac27_122 は渡される。今回の対処は、利用者空間の音量設定ではなく、カーネルドライバーがコーデックを初期化する入口を修正するものである。

8.2 削除するファイルは誤った指定を残さないために明示する

調査途中で作成した /etc/modprobe.d/cs4206-imac.conf は、最終構成には残さない。このファイルは、Cirrus Logic CS4206 というコーデック名に引きずられて、snd-hda-codec-cirrus 側へ model を指定しようとした誤設定である。modinfo で確認した範囲では、snd_hda_codec_cirrus に model パラメーターは見つからなかった。model を渡す相手は、コーデック名を含むモジュールではなく、HDA コントローラ側の snd-hda-intel である。

誤った設定ファイルを残すと、後から障害を再確認するときに、どの設定が実際に効いているのか分からなくなる。音が出るようになった後でも、不要な設定が残っていれば、将来のカーネル更新時や別の音声問題を調べるときの混乱要因になる。最終状態は、mac-fix.conf だけを残し、cs4206-imac.conf は削除する形にそろえる。

8.3 新規に導入したパッケージは alsa-tools である

調査の過程で新規に導入したパッケージは alsa-tools である。目的は hda-verb を使うためだった。hda-verb は、HDA デバイスへ直接コマンドを送るための調査用ツールであり、Node 0x0a に SET_PIN_WIDGET_CONTROL 0xc0 を送る検証に使った。この検証により、0xc0 を手動で書いても直後に 0x40 へ戻ることが分かった。

一方で、最終対応そのものは alsa-tools に依存しない。hda-verb は、原因を切り分けるために使った道具であり、起動時に常用する仕組みではない。実際に再起動後の挙動を変えたのは、/etc/modprobe.d/mac-fix.conf による snd-hda-intel の model 指定である。調査用に導入したパッケージと、恒久設定として残すファイルは分けて記録する必要がある。

対象 最終状態 本文上の意味
/etc/modprobe.d/mac-fix.conf 作成して残す。内容は options snd-hda-intel model=imac27_122 の 1 行である。 snd-hda-intel の読み込み時に iMac 向けモデルを明示する恒久設定である。
/etc/modprobe.d/cs4206-imac.conf 削除する。snd-hda-codec-cirrus には model パラメーターが確認できなかったため、最終構成には残さない。 誤ったモジュールに model を指定する設定であり、残すと後続調査の混乱要因になる。
alsa-tools 調査中にインストールした。 hda-verb を使い、HDA コーデックへ直接コマンドを送るために必要だった。
wpctl PipeWire / WirePlumber 側の状態確認に使った。 新規導入パッケージではなく、出力シンク確認のために使った調査コマンドである。
amixer ALSA ミキサー値の確認に使った。 ジャック検出、ミュート、音量不足を除外するための調査コマンドである。
dmesg カーネルログ上の fixup や quirk の痕跡確認に使った。 機種別処理が適用された形跡を調べるために使った。
modinfo カーネルモジュールのパラメーター確認に使った。 model を指定すべき相手が snd-hda-codec-cirrus ではなく snd-hda-intel であることを確認する材料になった。

8.4 永続性は設定ファイルとしての永続性である

この対応は、再起動で消える一時処置ではない。/etc/modprobe.d/mac-fix.conf が存在し、snd-hda-intel が通常どおり modprobe の仕組みで読み込まれる限り、model=imac27_122 はモジュール読み込み時に適用される。Node 0x0a に 0xc0 を直接書く操作とは異なり、起動時に HDA コーデックをどのモデルとして扱うかを変えるため、再起動後も同じ初期化経路を通ることが期待できる。

ただし、永続的という語は、将来のすべての条件を固定するという意味ではない。この設定はファイルとして永続するが、カーネル更新によって imac27_122 の処理内容が変わる可能性はある。別の /etc/modprobe.d/*.conf が同じモジュールに異なる model を指定すれば、設定の競合も起こり得る。管理作業で mac-fix.conf を削除すれば、当然この指定は失われる。さらに、将来のカーネルで iMac17,1 の Subsystem Id に対する自動フィックスアップが追加されれば、明示的な model 指定そのものが不要になる可能性もある。

このため、本稿でいう恒久対応とは、現行環境で起動時の初期化経路を安定させる設定を残す、という意味である。永久に手を触れなくてよいという意味ではない。HDA の機種別処理はカーネル側の実装に依存するため、カーネル更新後には、同じ設定が引き続き有効かを確認するのが妥当である。

8.5 抜き差しで再発する可能性と確認条件を分けて扱う

EarPods の抜き差しだけで元の無音状態に戻る可能性は、今回の原因から見ると高くない。最初からヘッドフォンジャックの挿入検出は on であり、問題は挿抜を検出できないことではなかった。実際の原因は、起動時に iMac17,1 向けの機種別フィックスアップが選ばれず、ヘッドフォン出力ピンの制御が 0x40 に留まっていた点にある。model=imac27_122 が適用された状態で起動していれば、通常の抜き差しは、その初期化済みの経路の上で処理される。

一方で、抜き差し、サスペンド復帰、カーネル更新は同じ確認ではない。抜き差しはジャック検出と出力経路の再選択を確認する操作である。サスペンド復帰は、起動時とは異なる再初期化経路を通る可能性がある。カーネル更新は、ドライバーの実装や model 指定の扱いそのものが変わる可能性を持つ。再起動後に音が出たことは強い確認材料になるが、すべての電源状態と更新後の挙動まで同時に保証するわけではない。

確認条件 確認する理由 期待される状態
通常の再起動後 modprobe.d の設定が snd-hda-intel の読み込み時に適用されるかを確認する。 EarPods から音が出る。
電源断後のコールドブート 完全な電源投入からの初期化でも model 指定が効くかを確認する。 EarPods から音が出る。
EarPods の複数回抜き差し ジャック検出とヘッドフォン出力制御が挿抜後も維持されるかを確認する。 抜き差し後も音声出力が戻る。
サスペンド復帰後 起動時とは異なる復帰処理でも出力制御が崩れないかを確認する。 復帰後も EarPods から音が出る。
カーネル更新後 snd-hda-intel の model 指定や imac27_122 の処理が変わっていないかを確認する。 同じ設定で EarPods から音が出る。

この章の帰結は、作業結果を小さく、検証条件を明確に保つことである。残すファイルは /etc/modprobe.d/mac-fix.conf だけでよい。内容は options snd-hda-intel model=imac27_122 の 1 行である。調査のために導入したパッケージは alsa-tools であり、hda-verb は原因を切り分けるために使った。再起動後に EarPods が鳴ったという結果は、HDA コーデックへ後から値を書いたからではなく、snd-hda-intel の初期化時に iMac 向けの既知モデルを選ばせたことによる帰結である。


9. ユーザー空間の正常表示はカーネル初期化の完了を意味しない

9.1 正常に見えた層と、実際に欠けていた層は違っていた

この障害の要点は、GNOME、PipeWire、ALSA ミキサーの確認が無意味だったということではない。それらは、どの層まで正常に見えているかを切り分けるために必要だった。GNOME ではアナログヘッドフォンが出力先として選ばれていた。PipeWire では内部オーディオのアナログステレオが既定シンクとして存在していた。ALSA ミキサーでは Headphone Jack が on、Headphone Playback Switch が on,on、Headphone Playback Volume も十分な値だった。この段階までを確認することで、出力先未選択、音量不足、ミュート、ジャック未検出という典型的な説明は後退した。

しかし、これらの正常値は、HDA コーデック内部のヘッドフォン出力ピンが正しく駆動されていることまでは示さなかった。Node 0x0a では Pin-ctls が再生中も 0x40 に留まり、ヘッドフォン出力に必要な 0x80 が加わった 0xc0 にはならなかった。第一に、ユーザー空間ではヘッドフォンが認識され、出力先として扱われていた。第二に、カーネルドライバーが iMac17,1 に必要な機種別初期化を選べていなかったため、認識された出力先を実際に鳴らすためのピン制御が完成していなかった。今回の無音は、この二つの層がずれたことで起きていた。

正常に見えていた内容 残っていた未解決点
GNOME アナログヘッドフォンが出力先として表示され、選択されていた。 実際の HDA コーデックのピン制御までは確認できなかった。
PipeWire / WirePlumber 内部オーディオのアナログステレオが既定シンクとして存在していた。 Apple iMac 向けの初期化処理が適用されたかどうかは分からなかった。
ALSA ミキサー ジャック検出、再生スイッチ、音量は正常値だった。 ミキサー値が Node 0x0a のヘッドフォン出力制御へ反映されているかは確認できなかった。
HDA コーデック Node 0x0a が HP Out として見えていた。 Pin-ctls が 0x40 のままで、ヘッドフォン出力として期待される 0xc0 になっていなかった。
カーネルドライバー CS4206 は汎用的には認識されていた。 iMac17,1 向けの機種別フィックスアップが自動適用された形跡は確認できなかった。

9.2 Bluetooth 既稿と同じく、表示と初期化の成否は分かれる

同じ iMac Debian 環境では、Bluetooth でも似た構造の問題が発生している。GNOME のトグルや bluetooth.service が正常に見えても、カーネルドライバーが Broadcom の HCI reset を完了できなければ、Bluetooth コントローラとして成立しないという切り分けが既稿に記録されている[26]。音声と Bluetooth は別のデバイスであり、使うドライバーも確認するファイルも違う。だが、ユーザー空間では利用可能に見え、下層のカーネル初期化が完了していないため実機としては動かない、という構造は共通している。

この共通性は、古い Mac を Linux で運用する際の判断に関係する。Apple のハードウェアでは、標準的な部品名が見えていても、その機種固有の配線、GPIO、アンプ制御、リセット処理まで Linux カーネルが正しく扱えているとは限らない。今回の音声では、Cirrus Logic CS4206 が見え、ヘッドフォンジャックも検出されていた。それでも、iMac17,1 で必要なフィックスアップが選ばれなければ、ヘッドフォン出力ピンは期待される状態にならなかった。Bluetooth でも、サービスやトグルが見えていることと、Broadcom コントローラが初期化済みであることは同じではなかった。

9.3 結論は、iMac17,1 では model=imac27_122 を起動時に渡す必要があるという点にある

古い Mac を Linux で使うとき、GUI は入口であり、ミキサー値は中間層である。障害解析では、そこで異常が見つからない場合に、/proc/asound/card0/codec#0、dmesg、DMI 情報、モジュールパラメーター、カーネル側のモデル一覧まで確認対象を下げる必要がある。今回の調査では、内蔵スピーカーが鳴ること、アナログヘッドフォンが表示されること、Headphone Jack が on であることは、どれも必要な確認だった。しかし、それらだけでは EarPods が鳴らない理由を説明できなかった。

結局、EarPods が鳴らなかった原因は、EarPods、ヘッドフォン端子、音量、ミュート、PipeWire の出力先選択の失敗ではなかった。iMac17,1 に搭載された Cirrus Logic CS4206 を、Linux カーネルの HDA ドライバーがこの機種に合う形で初期化できておらず、ヘッドフォン出力に対応する Node 0x0a の Pin-ctls が 0x40 のまま残っていたことが直接の手がかりだった。GUI と ALSA ミキサーでは正常に見えていたが、HDA コーデック内部ではヘッドフォン出力として必要な制御が完成していなかった。

最終的な対応は、/etc/modprobe.d/mac-fix.conf に options snd-hda-intel model=imac27_122 を置くことである。この 1 行により、snd-hda-intel の読み込み時に iMac 向けの既知モデルを明示し、起動時の初期化経路を汎用設定から iMac 向けの処理へ寄せる。再起動後に EarPods から音が出たことは、HDA コーデックへ後から値を書き込んだからではなく、カーネルドライバーが音声チップを初期化する段階で必要な機種別フィックスアップに入れたことによる結果である。


10. 本稿で使う用語

本稿で使う用語を整理する。ここで必要なのは、音声技術の百科事典的な知識ではない。アプリケーションから出た音が、どの順序で EarPods へ届くのか、その途中のどこまで正常で、どこから先が怪しいのかを読めることである。

まず、音は再生アプリケーションから直接 EarPods へ届くわけではない。画面上の出力先、Linux の音声処理、カーネルドライバー、iMac 内部の音声チップ、ヘッドフォン端子という順に、いくつもの層を通る。本稿の調査は、この流れを上から順に確認し、最後に iMac17,1 向けの初期化処理が足りないところまで下りていく。

段階 一般的な言い方 本稿で確認したこと
再生アプリケーション 音を出す側である。 内蔵スピーカーでは音が出るため、音声ファイルや再生アプリケーション全体の故障ではないと判断した。
GNOME 音量や出力先を表示する画面である。 アナログヘッドフォンが出力先として選ばれていることを確認した。
PipeWire / WirePlumber アプリケーションの音を、どの出力先へ流すかを管理する層である。 内部オーディオのアナログ出力が、音声サーバー上の出力先として存在することを確認した。
ALSA Linux が音声機器を扱うための下地である。 ヘッドフォン端子の挿入検出、ミュート、音量が正常に見えることを確認した。
カーネルドライバー OS が実際のハードウェアを動かす部分である。 この iMac 向けの初期化処理が自動で選ばれているかを確認した。
HDA コーデック iMac 内部で音声信号を端子へつなぐ音声チップである。 ヘッドフォン端子側の制御値が、期待される状態になっているかを確認した。
EarPods 最後に音を受け取る機器である。 画面上では認識されているのに、実際には音が出なかった。

次の用語一覧は、本文を読み返すための作業用の説明である。一度にすべて覚える必要はない。読んでいる途中で ALSA、HDA、DAC、Node、Pin-ctls などが出てきたとき、どの層の何を見ているのかへ戻るための表である。

用語 本稿での意味 この障害で見る理由
GNOME Debian の画面操作で使っているデスクトップ環境である。サウンド設定画面では、出力先や音量を確認できる。 画面上ではアナログヘッドフォンが選ばれていたため、単純な出力先未選択ではないことを確認する。
PipeWire アプリケーションから出た音を、スピーカー、ヘッドフォン、HDMI などのどの出力先へ流すかを扱う音声サーバーである。 内部オーディオのアナログ出力が、デスクトップ上の出力先として存在しているかを確認するために見る。
WirePlumber PipeWire 上で、どの機器や出力先を使えるようにするかを管理する仕組みである。音声機器の管理係に近い。 PipeWire に見えている出力先が、ALSA 側の実際の音声デバイスから作られていることを確認するために関係する。
ALSA Advanced Linux Sound Architecture の略で、Linux がスピーカー、マイク、ヘッドフォン端子などの音声機器を扱うための下地である。GNOME や PipeWire より下の層にあり、音声機器に近い状態を扱う。 ヘッドフォンが挿さっているか、ミュートされていないか、音量が上がっているかを確認するために使う。ただし、ALSA で正常に見えても、音声チップ内部の最終的な制御まで正しいとは限らない。
ミキサー 音量、ミュート、入力や出力の切り替えなど、音声デバイスの調整項目をまとめて扱う部分である。物理的なミキサー卓ではなく、ソフトウェア上の調整項目である。 音が出ない原因が、単なる音量不足やミュートではないことを確認するために見る。
HDA High Definition Audio の略で、PC の内蔵音声で使われる音声機器の規格である。OS と内蔵音声チップがやり取りするための決まりごとに近い。 今回の iMac の内蔵音声はこの仕組みで扱われており、ヘッドフォン端子のさらに細かい制御を読むために必要になる。
コーデック ここでいうコーデックは、動画や音声の圧縮形式のことではない。HDA の中で、音声信号をスピーカーやヘッドフォン端子へつなぐ iMac 内部の音声チップである。本稿では Cirrus Logic CS4206 が該当する。 画面上ではヘッドフォンが見えていても、実際に端子へ音を出す制御はこのコーデック内部で行われる。
DAC Digital-to-Analog Converter の略で、計算機内部のデジタル音声を、スピーカーやヘッドフォンへ送れるアナログ信号に変える部分である。音声ファイルは数字の列だが、EarPods を鳴らすには電気信号として出す必要がある。 DAC 側が完全に止まっているという説明を弱める材料になる。
アンプ 音声信号を出力先へ送れる強さにする部分である。ここでは大きな外部アンプではなく、音声チップ内部や端子近くにある小さな増幅部分を指す。 アンプがミュートされていると、他の設定が正常でもヘッドフォンから音が出ない可能性があるため確認する。
Node HDA コーデック内部の部品を番号で表した単位である。端子、DAC、アンプなどが Node として並ぶ。本稿では Node 0x0a がヘッドフォン端子側、Node 0x03 がその手前の DAC 側、Node 0x0b が内蔵スピーカー側として出てくる。 鳴る経路と鳴らない経路を、コーデック内部の部品番号ごとに比較するために使う。
ピン 音声チップからスピーカーやヘッドフォン端子へつながる出口である。物理端子そのものではなく、チップ内部でその端子に対応する接続点として読む。 ヘッドフォン端子へ音を出すには、対応するピンが正しい状態で有効になっている必要がある。
Pin-ctls Pin controls の略で、コーデック内部の出力ピンをどう動かすかを示す制御値である。0x40 や 0xc0 は、複数のオンオフ状態を 16 進数でまとめて表した値である。 今回の直接原因は、ヘッドフォン出力に必要な 0x80 が加わらず、Pin-ctls が 0x40 のままだった点にある。
16 進数 0 から 9 と a から f を使って数を表す方法である。本稿では 0x40、0x80、0xc0 のように、0x から始まる値として出てくる。 HDA の制御値がこの形式で表示されるため、0x40 と 0xc0 が違う状態を表していることを読むために必要になる。
D0 / D3 音声チップ内部の電源状態を表す名前である。D0 は動作中、D3 は省電力状態と読めばよい。 再生中に D0 へ移っているかを確認することで、単なる省電力状態のまま音が出ないのではないと判断できる。
GPIO General Purpose Input/Output の略で、機器ごとの追加制御に使われる汎用の入出力線である。音声専用ではないが、機種によってはアンプや経路切り替えに関係する。 Apple 機種では、標準的な音声端子の制御だけでなく、アンプや経路の切り替えに GPIO が関係する可能性があるため確認した。
ドライバー Linux カーネルの中で、実際のハードウェアを初期化し、操作するためのソフトウェアである。アプリケーションと機械の間に立つ操作係である。 GUI やミキサーが正常でも、ドライバーがこの iMac に必要な初期化を選べていなければ、ヘッドフォン端子は鳴らない。
フィックスアップ 特定の機種だけに必要な補正処理である。同じ音声チップでも、iMac 内部での配線やアンプの使い方は機種によって違う。その差を Linux 側で補う処理を、本稿ではフィックスアップと呼んでいる。 今回の根本原因は、iMac17,1 に必要なフィックスアップが自動適用されていなかった点にある。
model 指定 snd-hda-intel に、どの既知モデルとして音声デバイスを初期化するかを明示する指定である。今回の場合は、Linux に対して、この音声機器を imac27_122 として扱うよう伝える設定である。 model=imac27_122 を渡すことで、起動時に iMac 向けの初期化経路へ入れる。

参考文献

  1. id774, iMac Retina 5K (2015) を Debian 13 に移行した(2026-02-09). https://blog.id774.net/entry/2026/02/09/3515/
  2. PipeWire, PipeWire. https://pipewire.org/
  3. WirePlumber, WirePlumber Documentation. https://pipewire.pages.freedesktop.org/wireplumber/
  4. Debian Manpages, wpctl(1). https://manpages.debian.org/testing/wireplumber-doc/wpctl.1.en.html
  5. WirePlumber, ALSA configuration. https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/alsa.html
  6. Debian Wiki, PipeWire. https://wiki.debian.org/PipeWire
  7. Debian Manpages, amixer(1). https://manpages.debian.org/testing/alsa-utils/amixer.1.en.html
  8. ALSA Project, Advanced Linux Sound Architecture. https://www.alsa-project.org/
  9. ALSA Project, alsa-utils. https://github.com/alsa-project/alsa-utils
  10. Linux Kernel Documentation, More Notes on HD-Audio Driver. https://docs.kernel.org/sound/hd-audio/notes.html
  11. Codebrowser, linux/include/sound/hda_verbs.h. https://codebrowser.dev/linux/linux/include/sound/hda_verbs.h.html
  12. Debian, Details of package alsa-tools in bookworm. https://packages.debian.org/bookworm/alsa-tools
  13. ALSA Project, hda-verb README. https://git.alsa-project.org/?p=alsa-tools.git%3Ba%3Dblob%3Bf%3Dhda-verb%2FREADME
  14. Linux Kernel Documentation, More Notes on HD-Audio Driver: Model Option. https://docs.kernel.org/sound/hd-audio/notes.html
  15. Debian Manpages, dmesg(1). https://manpages.debian.org/testing/util-linux/dmesg.1.en.html
  16. Debian Manpages, modinfo(8). https://manpages.debian.org/unstable/manpages-ja/modinfo.8.ja.html
  17. Linux Kernel Documentation, Advanced Linux Sound Architecture – Driver Configuration guide. https://docs.kernel.org/sound/alsa-configuration.html
  18. Debian Manpages, modprobe.d(5). https://manpages.debian.org/trixie/kmod/modprobe.d.5.en.html
  19. Debian Kernel Handbook, Chapter 6. Managing the kernel modules. https://kernel-team.pages.debian.net/kernel-handbook/ch-modules.html
  20. Linux Kernel Documentation, HD-Audio Codec-Specific Models. https://docs.kernel.org/sound/hd-audio/models.html
  21. Linux Mint Forums, [SOLVED] headphones not working: 27-inch 2015 iMac Dual Boot. https://forums.linuxmint.com/viewtopic.php?t=329356
  22. Linux Mint Forums, Heaphone Jack (on iMac Late 2015 27”) does not work. https://forums.linuxmint.com/viewtopic.php?t=333952
  23. Arch Linux Forums, [Solved] No headphone sound – Imac 27 2015 Cirrus Logic. https://bbs.archlinux.org/viewtopic.php?id=262978
  24. Ubuntu Community Help Wiki, HdaIntelSoundHowto. https://help.ubuntu.com/community/HdaIntelSoundHowto
  25. Fedora Discussion, No Sound to Audio Out Jack iMac 15,1 (Late 2014). https://discussion.fedoraproject.org/t/no-sound-to-audio-out-jack-imac-15-1-late-2014/80817
  26. id774, iMac (Debian) で Bluetooth を利用する(2026-02-12). https://blog.id774.net/entry/2026/02/12/3572/