コグノスケ


2017年6月2日

USB 3.0とワイヤレスキーボード

サーバのワイヤレスキーボードが妙に調子悪くて不思議だったのですが、どうもレシーバーがUSB 3.0デバイスの近くに刺さっていると調子が悪くなります。

ワイヤレスキーボードの故障かと思ったのですが、USB 3.0デバイスを取り去ったり、レシーバーを別のポートに移動させると一気に調子が良くなるので、故障でもなさそうです。

USB 3.0の信号ってWi-Fi、ワイヤレスマウス、ワイヤレスキーボードなどで良く使われる2.4GHz帯にノイズをまき散らすんでしたっけ?まさかこんな形で体験するとは……。

もう少し検証

筐体の前面にUSB 2.0のポート、筐体の背面にUSB 3.0/USB 2.0のポートがあるマシンを使ってこんな実験をしました。

条件 レシーバーUSBメモリ結果
3.0同士 背面3.0背面3.0不調、10文字に1文字くらいしか入力できない
3.0/2.0隣接背面3.0背面2.0不調、10文字に1文字くらいしか入力できない
3.0/2.0離す背面3.0前面2.0好調
2.0同士 前面2.0前面2.0好調

ちなみにUSBメモリの電磁波対策がショボいのか?と疑って、USB 3.0ケーブル+SSDでも試してみましたが、結果は同じでした。実はUSB 3.0ケーブルもショボいか、マザーボードのコネクタ側からノイズが回り込んでいるのか、可能性を挙げるときりが無いですけど、もはや私には確かめようが無いです。

編集者:すずき(2017/06/04 01:15)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月3日

サーバのストレージをSSDに

先日の続き(2017年5月5日の日記参照)です。SanDisk SDCZ88-128G-J57というUSBメモリをサーバの起動ディスクにしていましたが、メチャメチャ熱くなります。季節的にもこれから暑くなりますし、いきなり壊れても困るのでSSDに買い換えました。

購入したのはTranscend TS128GESD400K(Amazonで9,500円くらい)です。SSDは百花繚乱でどれが良いのかわかりません。とりあえず低発熱を謳っていたので選んでみました。容量は64GBもあれば十分なので、一番安い128GBモデルです。さっき見たら1TBモデルは5万円以上するようで……。

64bitの世界へ

SSDに置き換えるついでにDebianを32bit版から64bit版に入れ替えました。せっかく16GBもメモリ積んだわけだし、64bitの広々アドレス空間で頑張って頂こうと思います。

クリーンインストールしたので、今まで使っていた設定が全部吹き飛んでいます。

とりあえず普段使っていた機能は、以前と同様レベルまで復活させましたが、DLNAサーバーだけは復活できていません。ずっとMediaTombを使っていたのですが、今はあまり使わないらしくて、ReadyMedia(MiniDLNA)に置き換えようと思っています。

他にも色々欠けた機能がありそうですけど、気づいたら復活させるってことで…。

編集者:すずき(2017/06/04 02:34)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月4日

タイヤ

気づけば6年(2011年5月1日の日記参照)経過しており、ヒビ割れていたタイヤを交換しました。以前とほぼ同じヨコハマのDNA ECOS ES31 215/45R17に換えました。イエローハット長尾店(枚方市)にて74,000円でした。

タイヤの交換工賃1本1,000円くらい、古タイヤ処分が1本500円くらいでしょうから、実質は1本17,000円くらいってことですかね。特に値引き交渉はしてないです。

ついでに、窒素充填、劣化で白くなってたバルブの交換、ホイールの土台部分?のサビ落としもやってくれましたから、もう少しお得かも。そういえばホイールの土台どころかボルトの根元まで錆びてました。放っておいたらホイールナット外れなくなりそう。

窒素ガスはやたら圧を高めに入れてました(標準は2.2〜2.3kPaですが2.5kPa入れてた)。何でだろ?理由を聞くのを忘れました。あと何回でも入れますから、来てくださいね〜的なことを言ってました。

感想

若干、静かになったような気が……しないな……。交換前とほぼ同じタイヤだし、正直言って、何が変わったのか全くわかりません。

編集者:すずき(2017/06/06 00:14)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月5日

USB 3.0と2.5GHzの関係

以前(2017年6月2日の日記参照)の続き。

CQ出版「USB 3.0設計のすべて」を良くわからんながらもパラパラ眺めているのですが、USB 3.0はPCI ExpressのPHYを使い回せるという記述がやたら出てきます。言われてみれば、なるほどで、高速SerDes設計は難しいのでUSB 3.0用に新たに起こすより、PCI ExpressのPHYを使い回せる方が半導体ベンダも楽だし、結果的に安くなるしハッピーですよね。

5Gbpsというバカっ速な信号の取り回しは大変ですが、物理層、コネクタ、ボード設計にPCI Expressのノウハウが使い回せることも恩恵だそうです。これも結果的に値段に反映されてハッピーですね。

だからUSB 3.0の物理層とPCI Expressの物理層の間で、2ペア作動信号による全二重通信、8b/10bエンコード、信号速度5Gbps(2.5GHz付近のノイズが出る)など共通点が多いのは、偶然では無いのです。さらに本によれば、コネクタやレセプタクルに厳しく品質を求めており、スペクトル拡散クロックが必須でEMI対策を頑張っているようにも見えます。

それでも2.4GHz帯の無線とのトラブルが多いところを見ると、2.4GHz帯への干渉は抑えきれなかった?考えから抜けていたのか?もしくは使ってるデバイスや配線がショボい?単に無線がノイズに弱いだけ?

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2017/06/06 00:20)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月6日

DTIの実力

目次: プロバイダ

先日(2017年5月29日の日記参照)の続きです。

DTIからPPP接続のIDやパスワードが送られてきましたので、早速、接続先を切り替えて通信速度を測ってみました。

比較しやすいように、先週に計測したWAKWAKの通信速度と重ねてグラフを作成しました。計測した日が異なるので厳密な比較ではありません。あと横軸の時間は大体同じに揃えましたが、計測の都合上10分くらいズレてます。


日曜の速度推移、WAKWAK v.s. DTI

DTIは速いです。けっこう速度が揺れていて、今後、人が増えたらWAKWAKと同じ結末になるのでは……という不穏な気配もありますが、今のところ、日中〜夕方の速度は圧倒的です。10倍以上速いです。

これならAmazonの漫画も数分でダウンロードできます。DTIにして良かったです。

編集者:すずき(2023/09/24 13:53)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月7日

USB 3.0

先日(2017年6月2日の日記参照)の続きです。USB 3.0機器のそばにワイヤレスマウスやワイヤレスキーボードのレシーバーを設置すると、動かなくなってしまう現象についてです。

まず、本当にUSB 3.0のせいなのか気になります。

CQ出版「USB 3.0設計のすべて」を良くわからんながらもパラパラ眺めているのですが、USB 3.0はPCI ExpressのPHYを使い回せるという記述がやたら出てきます。

なるほど、高速SerDes設計は難しいのでUSB 3.0用に新たに起こすより、PCI ExpressのPHYを使い回せる方が半導体ベンダも楽だし、結果的に安くなるしハッピーですよね。

5Gbpsというバカっ速な信号の取り回しは大変ですが、物理層、コネクタ、ボード設計にPCI Expressのノウハウが使い回せることも恩恵だそうです。これも結果的に値段に反映されてハッピーですね。

だからUSB 3.0の物理層とPCI Expressの物理層の間で、2ペア作動信号による全二重通信、8b/10bエンコード、そして信号速度5Gbpsなど共通点が多いのは、偶然では無いのです。

5Gbpsの信号速度と2.4GHz無線の関係

USB 3.0の信号速度は5Gbpsです。ということはクロックは5GHzのはずで、一番強烈なノイズは5GHz付近じゃないかと思ったのですが、何故2.5GHzなのでしょうか?

まず確実に言えるのは、USB 3.0にクロック信号だけを伝える配線は存在しないことです。PCI ExpressやUSB 3.0の8b/10bエンコードは信号とクロックを一緒に送る、埋め込みクロックと呼ばれる信号の送り方をするため、5GHzで単純に振動する信号はありません。

USB 3.0は5Gbpsと名乗るからには、送信側、受信側ともに信号を5G回/sで見ている、つまり1bitの間隔が0.2nsになっているはずです。もし0.2ns間隔で1, 0を交互に繰り返すような信号なら2.5GHzの正弦波に近い信号になるため、2.5GHz付近にノイズが発生するはずです。

しかし8b/10bの信号表を見ていると1, 0が交互に出るパターンも存在しますが、1, 1, 0, 0のように同じ値が2回以上続いてから反転するパターンの方が多いように見えます。

少ないとは言え8b/10bエンコーディングで1, 0のパターンが生成される以上、USB 3.0が2.5GHz帯にノイズを出すことは間違いないと考えられますが、この考え方であってるんでしょうか?何だかスッキリしません……。

規格でのノイズ対策は?

本に依れば、コネクタやレセプタクルに厳しく品質を求めており、スペクトル拡散クロック(SSC)が必須でEMI対策を頑張っているようにも見えます。

SSCで特定の周波数にピークが来るようなノイズは防げるけど、如何なSSCと言えども満遍なくノイズが発生するのは避けられません。また、ワイヤレスマウスやキーボードの出力がそれほど強いとは考えにくいので、無線がノイズに負けやすいのかもしれません。

編集者:すずき(2017/06/08 22:06)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月8日

Wizardry(囚われし亡霊の街)敵が強すぎる

目次: ゲーム

昔買って放置していた「Wizardry囚われし亡霊の街」を進めているのですが、シナリオ1終盤(アウダークルク迷宮B6F)辺りで、進めなくなりました。敵が強すぎます。

自キャラHP 600に対し、同レベルの敵が2000ダメージ以上ぶち込んでくるので必ず一撃で死にます。レベル上げれば何とかなる系なのかなあ??

シナリオ3まで一気に買ってしまって後悔しています。こんなマゾいバランスだとは思いませんでした。せめてシナリオ1はクリアしようと思いますが、シナリオ2, 3は多分やらないです。

FacebookのコメントでB6F辺りから運ゲーらしいことを教えてもらいました。うーん、そういうもんなのか。

メモ: 技術系の話はFacebookから転記しておくことにした。

パーティー編成

今のパーティー編成は、侍x 2と野伏と司祭x 3という大変偏った構成にしています。

何でかというと、侍は武器が強いことと、ノーリスクで敵1グループを一度に殴れる強力な固有スキルを持っているためです。前作の「囚われし魂の迷宮」では大変強かったので、今作も強いだろうと期待して侍を入れました。

野伏は盗賊の上位互換です。盗賊の技能+僧侶系の魔法の一部を覚えます。Wizardryは扉や宝箱に鍵だの罠だのが掛かっていて、いきなり開けると罠に殺されるので、解除するために盗賊の技能が必須です。

司祭は僧侶系、魔法使い系の魔法を両方覚えます。Wizardryはダンジョンで拾ったアイテムが全て「不明な何か」になるので、鑑定スキルを使わないと何を拾ったかすらわかりません。司祭は1人は居た方が良いです。

司祭の人数がやたら多いの魔法の使用回数が簡単に尽きないように人数でカバーするためです。Wizardryは魔法が9レベルに分類されていて、各レベル最大でも9回しか魔法が使えません(使用回数は作品に依って違うことがある)。どんなにキャラクターレベルが高かろうが9回同じ魔法を使ったら同じレベルの魔法は使えません。特に魔法使い系Lv.8はワープ系の魔法がありまして、ここの使用回数が尽きてしまうと、ダンジョンから帰るのが大変面倒になります。

ダンジョンには魔力を3減らしてくるクソみたいな敵も居て、魔法を使わずとも使用回数が0になることがありますが、さすがに司祭が3人も居れば全員の魔法が尽きることはありません。その前に殴られて死ぬ方が多いです……。

強すぎる侍、弱すぎる魔法

パーティー編成の思惑は大体当たっていたのですが、手痛い計算違いは攻撃魔法が弱すぎて後衛が置物になってしまったことです。

侍は武器さえあればメチャクチャ強いです。特に中盤の岩融という槍がバカみたいに強く1撃で1,000以上のダメージを与えられます。ほとんどの敵が一撃で沈みます。

また今作は課金アイテムとして虎徹など、シナリオ後半で出てくる刀を序盤から使えます。試しに買ってみたところ、攻撃力不足で苦戦していた序盤の敵が紙切れのごとく蹴散らせました。武器の差が異常すぎます。

司祭は計算違いでした。魔法で強力な攻撃が出来ると思っていたのですが、全然ダメでした。僧侶系最強のSmiteや、魔法使い系最強のNAL Burstですら200〜300ダメージと弱く、3人がかりで連発してやっと効き目があるかどうかです。弱すぎます……。

異常な強さの敵

このゲームで一番やる気が削がれるポイントは「敵の異常な強さ」です。敵が4桁以上のダメージを与えてくるので、前衛、後衛関係無く即死します。それでも防ぐ手立てがあるならまだ良いんですけど、防具による防御力は100行けば良い方で気休めにもなりません。防御系の魔法もほとんどありません。

侍辺りが先攻で攻撃できれば倒せるんですが、敵の方が圧倒的に速くて先攻が取れません。完全に詰んでます。どうしたら良いんだ。

クソゲーにノミネート

雑魚に全く勝てないので、私は数歩歩いてセーブ、敵にぶち殺されたらリセット&ロード、を繰り返しながら進めています。はっきり言って、全く面白くないです。しかもこのゲームは動きが全体的に遅いので、さらにイライラ度が上がります。

一体、他の人はどうやってクリアしているのか調べていたら、今作がクソゲー・オブ・ザ・イヤーにノミネートされているのを見つけてしまいました。あー、他の人も同じこと思ってるのね……。

前作はモッサリしてる以外は、そこそこ面白かったんだけどなあ?今作はちょっとクリアする気が起きないです。

編集者:すずき(2023/09/24 13:52)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月13日

実はハイレゾも再生できる、我が家のアンプ

なぜハイレゾは「バカげている」のかを読んで。

記事の内容についてはさておいて、リンクされてるWAVファイル再生してみたところ、歪みなどは全く何も聞こえませんでした。ONKYO SE-U33GXV2はお値段の割にとても良いアンプだと思います。

以前22kHz Sin波を再生させて、オシロで見た(2014年11月25日の日記参照)ときも、鳴り始めが美しいSinc関数になっていて、波形の打ち切りなどもありませんでした。基本に忠実&作りが良いのでしょう。

何も考えないで適当に買ったんですけど、買って良かった一品でした。

私の耳とハイレゾ

私にはハイレゾは意味がありませんね。聞こえないし、差もわかりません。

そもそもDAT(fs = 48kHz)とCD(44.1kHz)の差だってわかりませんし、もっといえばfs = 32kHzつまり16kHz以上の音を打ち切っても差がわかりません。

まあSin波だけデカい音量で鳴らせば16.5kHzくらいまでは聞こえますが、17kHz以降はもう何しても全然聞こえません。どう考えてもCD音質より上は要らないです……。

私にはハイレゾは意味ない(=わからない)というだけであって、ハイレゾ音源なんか買うな!とか、売るな!とか、そんなことは微塵も思っていません。

趣味の世界なんですから、楽しくやるのが一番です。差がわかろうがわかるまいが、死にゃあしねえし、外野の声なんて、気にしないで楽しむのが一番です。

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2018/04/11 01:53)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月14日

最速のyes

目次: ベンチマーク

How is GNU `yes` so fast?を読んで。このサイトを Twitterで知って面白かったので、やってみました。

記事の最後にあるプログラム(iteration 4)のバッファサイズを8KBから16KBに変更するとGNU yesより速くなるようです。

家のLinuxマシンでやってみたらyesというかcoreutilsのバージョンによって全然速さが違うことがわかりました。


CPU                 : GNU yes 8.23 : GNU yes 8.26 : 自家製yes(バッファ16KB)
AMD A10 7800        : 123MiB/s     : 2.8GiB/s     : 3.2GiB/s
Intel Pentium J4205 : 40MiB/s      : 1.9GiB/s     : 2GiB/s

何も変わっていないように見えるyesも実は速度が進化したんですね…。

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2023/09/24 13:48)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月15日

ALSAのミキサーとregmapその1 - ミキサーとkcontrol

目次: ALSA

メモ代わりの超マニアックな話です。なぜALSAのドライバ、特にミキサーがregmapを使うのかを調べました。

ALSAのドライバでミュートのON/OFFとか、ボリューム上げ下げの機能を実装するときに、kcontrolというフレームワークを使います。

ボリュームはさらにもう一つ仕組みがあって面倒なので、ミュートON/OFFスイッチを例にします。下記はTexsas InstrumentsのTAS5711というDACのドライバです。

kcontrolの宣言

//from linux-4.4/sound/soc/codecs/tas571x.c

static const struct snd_kcontrol_new tas5711_controls[] = {
...
        SOC_DOUBLE("Speaker Switch",
                   TAS571X_SOFT_MUTE_REG,
                   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
                   1, 1),
};

引数の意味はスイッチの名前(Speaker Switch)、レジスタのアドレス、Lチャネルを制御するときのシフト数、Rチャネルを制御するときのシフト数、最大値、反転するかどか、みたいです。

「反転するかどうか」を何に使っているかというと、通常ON = max値, OFF = min値という意味ですが、ON = min値, OFF = max値にするようです。TI TAS5711仕様書のSOFT MUTE REGISTER (0x06) を見た感じ、Muteするときは1設定しろとありますので、多分合っていると思います。間違ってたらごめんよ。

もちろんこれだけではダメで、struct snd_soc_codec_driverのcontrolsにポインタを代入し、snd_soc_register_codec() に渡す必要があります。

どうもtas571x.cのドライバはTAS5711とTAS5717という2つのDACに対応するため、渡し方がちょっと変わってるので、TAS5086用のドライバを見ます。

kcontrolの宣言

//from linux-4.4/sound/soc/codecs/tas5086.c

static const struct snd_kcontrol_new tas5086_controls[] = {
        SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
...

static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
        .probe                  = tas5086_probe,
        .remove                 = tas5086_remove,
        .suspend                = tas5086_soc_suspend,
        .resume                 = tas5086_soc_resume,
        .controls               = tas5086_controls,    //★snd_kcontrol_new配列のポインタをここに渡している★
        .num_controls           = ARRAY_SIZE(tas5086_controls),
        .dapm_widgets           = tas5086_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(tas5086_dapm_widgets),
        .dapm_routes            = tas5086_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(tas5086_dapm_routes),
};

static int tas5086_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
{
...
        if (ret == 0)
                ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,    //★snd_soc_codec_driverのポインタをここに渡している★
                                             &tas5086_dai, 1);

        return ret;
}

こんな感じです。本当に言いたかったことはregmapですけど、出てこないうちに終わってしまいました。また次回にします。

編集者:すずき(2022/05/22 15:22)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月16日

ALSAのミキサーとregmapその2 - kcontrolとregmapの関係

目次: ALSA

メモ代わりの超マニアックな話です。kcontrolについては前回を参照。

ALSAのkcontrolはレジスタのアドレスと値の範囲をALSAの共通レイヤに渡すだけで、ミキサー機能から、ハードウェアレジスタの値が書き換えられます。レジスタの値をアクセスする関数を一切書いていないにも関わらず、です。

最初、この仕組みがわからず、超不思議でした。どうなってるんでしょうか?

kcontrolとregmap

まずkcontrolが何をしているか見てみます。といってもkcontrol側は深追いせず、レジスタアクセスのみ調べます。ちなみにkcontrol_newの何がどうなってミキサーに繋がるか調べるのは、かなり大変そうです……。

kcontrolの宣言とSOC_DOUBLEの実装

//linux-4.4/sound/soc/codecs/tas571x.c

static const struct snd_kcontrol_new tas5717_controls[] = {
...
        SOC_DOUBLE("Speaker Switch",
                   TAS571X_SOFT_MUTE_REG,
                   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
                   1, 1),


//linux-4.4/include/sound/soc.h

#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \    //★たぶんこれ使って読んでるんだろう★
        .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
                                          max, invert, 0) }


//linux-4.4/sound/soc/soc-ops.c

int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
{
...
        ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
        if (ret)
                return ret;
...


//linux-4.4/sound/soc/soc-ops.c

static int snd_soc_read_signed(struct snd_soc_component *component,
        unsigned int reg, unsigned int mask, unsigned int shift,
        unsigned int sign_bit, int *signed_val)
{
...
        ret = snd_soc_component_read(component, reg, &val);
        if (ret < 0)
                return ret;


//linux-4.4/sound/soc/soc-io.c

int snd_soc_component_read(struct snd_soc_component *component,
        unsigned int reg, unsigned int *val)
{
        int ret;

        if (component->regmap)
                ret = regmap_read(component->regmap, reg, val);    //★regmapで読み出すか★
        else if (component->read)
                ret = component->read(component, reg, val);    //★regmapが無くて、独自のレジスタアクセス関数があればそちらを使う★
        else
                ret = -EIO;    //★どちらもなければエラー★

        return ret;
}

はい、やっと出ましたregmapです。コードを見るとcomponent->regmapとやらを参照していますが、こんなものを設定した覚えはありません。どこから来たのでしょうか?

答えは前回の最後に呼んでいたsnd_soc_register_codec() にあります。

snd_soc_register_codec

答えはsnd_soc_register_codec() にある、あるんですけど、ちょっと面倒くさいです。

snd_soc_register_codec

//linux-4.4/sound/soc/soc-core.c

int snd_soc_register_codec(struct device *dev,
                           const struct snd_soc_codec_driver *codec_drv,
                           struct snd_soc_dai_driver *dai_drv,
                           int num_dai)
{
...
        struct snd_soc_codec *codec;
...
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
        if (codec == NULL)
                return -ENOMEM;

        codec->component.codec = codec;

        ret = snd_soc_component_initialize(&codec->component,    //★注目その2★
                        &codec_drv->component_driver, dev);
        if (ret)
                goto err_free;
...
        mutex_lock(&client_mutex);
        snd_soc_component_add_unlocked(&codec->component);    //★注目その1★
        list_add(&codec->list, &codec_list);
        mutex_unlock(&client_mutex);
...

順序が逆転しますが、ゴールから逆にたどる形で説明します。まずcomponent->regmapがどこから来たのか?を追います。答えはsnd_soc_component_add_unlocked() にあります。

component->regmapが設定されるまで

//linux-4.4/sound/soc/soc-core.c

static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
{
        if (!component->write && !component->read) {
                if (!component->regmap)
                        component->regmap = dev_get_regmap(component->dev, NULL);
...


//linux-4.4/drivers/base/regmap/regmap.c

struct regmap *dev_get_regmap(struct device *dev, const char *name)
{
        struct regmap **r = devres_find(dev, dev_get_regmap_release,
                                        dev_get_regmap_match, (void *)name);
...


//linux-4.4/drivers/base/regmap/regmap.c

static int dev_get_regmap_match(struct device *dev, void *res, void *data)
{
        struct regmap **r = res;
...
        /* If the user didn't specify a name match any */
        if (data)
                return (*r)->name == data;
        else
                return 1;
...


//linux-4.4/drivers/base/devres.c

void * devres_find(struct device *dev, dr_release_t release,
                   dr_match_t match, void *match_data)
{
        struct devres *dr;
...
        dr = find_dr(dev, release, match, match_data);
...


//linux-4.4/drivers/base/devres.c

static struct devres *find_dr(struct device *dev, dr_release_t release,
                              dr_match_t match, void *match_data)
{
        struct devres_node *node;

        list_for_each_entry_reverse(node, &dev->devres_head, entry) {
                struct devres *dr = container_of(node, struct devres, node);

                if (node->release != release)
                        continue;
                //★今回はmatchにdev_get_regmap_match() を渡しています★
                //★またmatch_dataにはNULLを渡しています★
                //★dev_get_regmap_match() の第3引数がNULLの場合、最初に見つけたregmapにヒットします★
                if (match && !match(dev, dr->data, match_data))
                        continue;
                return dr;
        }

        return NULL;
}

以上のようにcomponent->regmapはdev_get_regmap(component->dev, NULL) の結果を使っています。dev_get_regmap() の第2引数NULLなので、デバイスのリソース一覧(dev->devres_head)から、とにかく何でも良いので最初に見つけたregmapを返してくれという意味になります。

最初見たとき、関数名と中身が全然違うので、分かるわけねぇだろこんなの…って思いました。

次にcomponent->devはどこから来たのか?を追います。答えはsnd_soc_component_initialize() にあります。

component->regmapが設定されるまで

//linux-4.4/sound/soc/soc-core.c

static int snd_soc_component_initialize(struct snd_soc_component *component,
        const struct snd_soc_component_driver *driver, struct device *dev)
{
...
        component->dev = dev;    //★これです★
        component->driver = driver;
        component->probe = component->driver->probe;
        component->remove = component->driver->remove;

こちらはそんなに難しくないですね。

最後の疑問

ここまで調べてきて分かったことは、下記の通りです。

  • ALSAのkcontrolはsnd_soc_component_read() という関数でハードウェアのレジスタにアクセスしているようだ
  • snd_component_read() はcomponent->regmapを使う
  • component->regmapはデバイスcomponent->devのリソースリストから探す
  • component->devはsnd_soc_register_codec() に渡したdevを使う

ここで最後の疑問です。regmapをdevresに追加する方法は?わからないですね。追加した覚えはありません。

でも絶対何かしているハズです。もう一回TAS5086のドライバに戻ってみます。

TAS5086再び

//linux-4.4/sound/soc/codecs/tas5086.c

static int tas5086_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
{
...
        priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);    //★もしかしてこれ?★
        if (IS_ERR(priv->regmap)) {
                ret = PTR_ERR(priv->regmap);
                dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
                return ret;
        }
...
        if (ret == 0)
                ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,    //★snd_soc_codec_driverのポインタをここに渡している★
                                             &tas5086_dai, 1);

        return ret;
}

ざっと見てもregmapに何かしているのはdevm_regmap_init() だけです。どうしてdevm_regmap_init() なのでしょうか?どうしてregmap_init() ではダメなのでしょうか?

デバイスのリソースリストとregmapの関係

//linux-4.4/include/linux/regmap.h

#define devm_regmap_init(dev, bus, bus_context, config)                 \
        __regmap_lockdep_wrapper(__devm_regmap_init, #config,           \
                                dev, bus, bus_context, config)
//★__regmap_lockdep_wrapper() はロックを取って __devm_regmap_init() を呼ぶマクロ★


//linux-4.4/drivers/base/regmap/regmap.c

struct regmap *__devm_regmap_init(struct device *dev,
                                  const struct regmap_bus *bus,
                                  void *bus_context,
                                  const struct regmap_config *config,
                                  struct lock_class_key *lock_key,
                                  const char *lock_name)
{
        struct regmap **ptr, *regmap;

        ptr = devres_alloc(devm_regmap_release, sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
                return ERR_PTR(-ENOMEM);

        //★regmap_init() も結局 __regmap_init() を呼ぶだけなのに何が違う?★
        regmap = __regmap_init(dev, bus, bus_context, config,
                               lock_key, lock_name);
        if (!IS_ERR(regmap)) {
                *ptr = regmap;
                devres_add(dev, ptr);    //★もしかしてこれ?★
        } else {
                devres_free(ptr);
        }

        return regmap;
}


//linux-4.4/drivers/base/devres.c

void devres_add(struct device *dev, void *res)
{
        struct devres *dr = container_of(res, struct devres, data);
        unsigned long flags;

        spin_lock_irqsave(&dev->devres_lock, flags);
        add_dr(dev, &dr->node);
        spin_unlock_irqrestore(&dev->devres_lock, flags);
}


//linux-4.4/drivers/base/devres.c

static void add_dr(struct device *dev, struct devres_node *node)
{
        devres_log(dev, node, "ADD");
        BUG_ON(!list_empty(&node->entry));
        list_add_tail(&node->entry, &dev->devres_head);    //★ここでリストに追加している!★
}

以上のように、devm_regmap_init() もregmap_init() もregmap初期化という役割から見ると同等ですが、devm_regmap_init() はデバイスのリソースリスト(dev->devres_head)にregmapを登録するという役割も果たしています。

まとめ

まとめると、

  • ALSAのkcontrolを使うときはregmap_init() ではなく、必ずdevm_regmap_init() を使い、regmapをデバイスのリソースリストに足しましょう。
  • regmapを登録したデバイスをsnd_soc_register_codec() に渡しましょう。別のデバイスを渡してはいけません。

このルールだけ見れば難しくないですが、なぜこのルールなのか調べると、結構複雑でした。面白かったです。

編集者:すずき(2022/05/22 15:19)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2017年6月17日

exim4の設定

サーバのexim4がIPv6 socket creation failedというエラーを出し続けていて、鬱陶しいです。

どうしたものかと思っていたら、同じ症状で悩んでいる人を見つけました。要は設定ファイルにdisable_ipv6 = trueを足せば良いだけみたいですが、Debianのexim4は変な設定方法になっていて苦戦していました。

まずは、現在の状態を確認してみます。

exim4の設定を更新、確認する方法
# update-exim4.conf

# exim4 -bP disable_ipv6
no_disable_ipv6

これは無効(disable)が無効(no)なので、IPv6有効状態です。なんでenable_ipv6じゃないんだろう。変な名前…。

変更方法ですが、先ほどのフォーラムによれば /etc/exim4/update-exim4.conf.confに足しても意味が無くて/etc/exim4/exim4.conf.templateに足すと良いみたいです。

exim4の設定を変更
# vim /etc/exim4/exim4.conf.template

# update-exim4.conf

# exim4 -bP disable_ipv6
disable_ipv6

とりあえず設定ファイルの先頭に足してみたら効いているみたいですが、どこでも良いのか?これ。

一応 /usr/share/doc/exim4/README.Debian.gzにマニュアルがありますが、クッソ長くて読む気が起きないです。

拾い読みした感じだと、多分2.1.1.12. Split configuration into small filesの真ん中辺りに書いてある、

If you chose unsplit configuration, update-exim4.conf builds the configuration from /etc/exim4/exim4.conf.template, which is basically the files from /etc/exim4/conf.d/ concatenated together at package build time, and thus guarantees consistency on the target system.

設定ファイルを分割していない人(私がそう)はexim4.conf.templateに全ての設定が書いてあるから、何か足したければexim4.conf.templateに足せば良さそうだな?ってのが何となくわかります。でも、仕組みは良いから使い方を書いてくれないかな…って気分になりますね。

編集者:すずき(2017/06/18 02:29)

コメント一覧

  • hdkさん(2017/06/18 06:03)
    Exim は知りませんでしたが conf.d スタイルになっているパッケージ結構ありませんか。共通ファイルをいじると、パッケージ更新の時に手動マージになることがあって手間なので conf.d に勝手に俺様ファイルを作るのがいいのかなと思います。
  • すずきさん(2017/06/18 14:22)
    >hdk さん
    Apache と cron くらいしか知りませんが、conf.d スタイルはありますね。概念を揃えていただけるのはありがたいのですが、exim4 の微妙なところは反映のさせ方が独特でわからないところです。
    なぜこうなっているのかまではわかりませんが、exim4 が設定ファイルの分割に対応していないところに、強引に設定ファイルの分割を持ち込んだのかなあ?
open/close この記事にコメントする



2017年6月30日

いまさらCocos2d-xを触ってみる

そういえばゲームをしばらく作っていなかったけれど、今時のゲームはどうやって作るんだろう?と調べていました。

今はスクラッチからガリガリ書くのではなく、ゲームエンジンとして3DならUnityで、2DならCocos2d-xを使うのが定番のようです。スマホゲームはAndroidとiOSに両対応することが普通だと思われてますよね。スクラッチから作ってAndroidとiOSに両方対応させるなんて、想像するだけで辛そうです。ゲームエンジン様々ですよ。

UnityはC# で書く必要があるみたいで、今時のゲームエンジンと3DとC# を同時に覚えようとすると間違いなく挫折するので、2DメインかつC/C++ で書けるCocos2d-xを試します。

Windows無くても何とかなる

いざ始めようとして、そういえばWindowsマシンを持ってない(潰してLinuxマシンにしてしまった)ことに気づきましたが、Linuxでのインストールガイド(公式ドキュメント)もちゃんと用意されていました。さすが。

どのバージョンを使えば良いのかわかりませんが、とりあえず現時点での最新リリース版っぽい3.15.1のタグをチェックアウトしておきます。

ソースコードダウンロード
$ mkdir -p ~/usr/src/
$ cd ~/usr/src/

$ git clone https://github.com/cocos2d/cocos2d-x.git
Cloning into 'cocos2d-x'...
remote: Counting objects: 433999, done.
remote: Total 433999 (delta 0), reused 0 (delta 0), pack-reused 433998
Receiving objects: 100% (433999/433999), 883.31 MiB | 1.47 MiB/s, done.
Resolving deltas: 100% (294953/294953), done.

$ cd cocos2d-x
$ git checkout cocos2d-x-3.15.1

ビルドします。ビルドする前にcmakeやOpenGL系ライブラリの開発パッケージを入れる必要があります。公式ドキュメントさん曰く、UbuntuやDebianをお使いなら、
cd build
./install-deps-linux.sh
とすると楽にセットアップできるとのこと。私は使ったことがないです。

ビルド失敗した
$ cd cocos2d-x
$ cd build
$ mkdir linux-build
$ cd linux-build

$ cmake ../../
...
-- SQLite3 include dirs: /usr/include
CMake Error at cmake/Modules/FindPackageHandleStandardArgs.cmake:136 (message):
  Could NOT find FMOD (missing: FMOD_LIBRARIES FMOD_INCLUDE_DIRS)
Call Stack (most recent call first):
  cmake/Modules/FindPackageHandleStandardArgs.cmake:343 (_FPHSA_FAILURE_MESSAGE)
  cmake/Modules/FindFMOD.cmake:48 (find_package_handle_standard_args)
  cmake/Modules/CocosBuildHelpers.cmake:44 (find_package)
  cmake/Modules/BuildModules.cmake:21 (cocos_find_package)
  CMakeLists.txt:98 (BuildModules)


-- Configuring incomplete, errors occurred!
See also "/home/katsuhiro/usr/src/cocos2d-x/build/linux-build/CMakeFiles/CMakeOutput.log".
See also "/home/katsuhiro/usr/src/cocos2d-x/build/linux-build/CMakeFiles/CMakeError.log".

FMODなるモジュールが無いと怒られました。調べてみるとgitからソースコードを持ってきた場合は、依存ライブラリをダウンロードする一手が必要とのことです。ダウンロードは簡単です。

依存ライブラリのダウンロード
$ cd cocos2d-x

$ ./download-deps.py
=======================================================
==> Prepare to download external libraries!
==> version file doesn't exist
==> Ready to download 'v3-deps-130.zip' from 'https://github.com/cocos2d/cocos2d-x-3rd-party-libs-bin/archive/v3-deps-130.zip'
==> WARNING: Couldn't grab the file size from remote, use 'zip_file_size' section in '/home/katsuhiro/usr/src/cocos2d-x/external/config.json'
==> Start to download, please wait ...
==> Downloading finished!
==> Extracting files, please wait ...
==> Extraction done!
==> Cleaning cocos2d-x/external folder ...
==> Copying files...
==> Cleaning...
==> Would you like to save 'v3-deps-130.zip'? So you don't have to download it later. [Yes/no]: Yes
==> Saving the dependency libraries by default

もう一度cmakeを実行します。成功しました、良かった良かった。あとはmakeするだけですが、gcc 6.3を使っているせいか、凄まじい量の警告が出ます。ドキュメントを見るとgcc 4.9でビルドするのが推奨みたい?ですが、gccのバージョンに関わらずWarning出るのはダメじゃないの……?

ビルド
$ cd cocos2d-x
$ cd build/linux-build

$ cmake ../../
It appears you are building natively for Linux with GCC
-- OpenGL include dirs: /usr/include
-- GLEW include dirs: /usr/include
-- PkgConfig found
-- GLFW3 include dirs: /usr/include/GLFW
-- SQLite3 include dirs: /usr/include
-- FMOD include dirs: /home/katsuhiro/usr/src/cocos2d-x/external/linux-specific/fmod/include
-- Fontconfig include dirs: /usr/include/freetype2
...
-- CURL add to include_dirs: /usr/include/x86_64-linux-gnu
-- CURL libs added to 'cpp-tests': curl
SPIDERMONKEY_LIBRARY: /home/katsuhiro/usr/src/cocos2d-x/external/spidermonkey/prebuilt/linux/64-bit/libjs_static.a
-- Configuring done
-- Generating done
-- Build files have been written to: /home/katsuhiro/usr/src/cocos2d-x/build/linux-build

$ make
Scanning dependencies of target bullet
[  0%] Building CXX object external/bullet/CMakeFiles/bullet.dir/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp.o

...(かなり時間かかります)...

やっと入り口に立てました。次回はゲームのプロジェクトを作ろうと思います。

編集者:すずき(2017/07/02 22:40)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報