LinuxでI/Oポート操作(Beep音を鳴らす) =============================== LinuxでシステムビープのI/Oポートを操作して、ビープ音を鳴らす方法について備忘録を残す。 システム・タイマのハード仕様 --------------------- IBM PC互換機のシステム・タイマは i8254 相当品(PIT)が使用されており、3個のプログラマブル・カウンタを内蔵。クロックは 1.19318MHz でドライブされて、以下の用途に使われている。 - チャネル0: IRQ0のハード割り込みを周期的に発生。 - チャネル1: メモリ・リフレッシュ要求信号として利用。 - チャネル2: 内蔵スピーカ音源(BEEP)の周波数を決定。 {{:programing:linux-programing:ibm-pc-system-timer-01.jpg?600|}} ### I/Oポート・アドレス 関連するI/Oレジスタのアドレス。 #### システム・タイマ(i8254) ^ アドレス ^ R/W ^ 機能 ^ 備考 ^ | 0x40 | R/W | カウンタ#0(インターバル・タイマ) | モード3 | | 0x41 | ::: | カウンタ#1(DRAMリフレッシュ) | モード2 | | 0x42 | ::: | カウンタ#2(BEEPスピーカー) | モード3 | | 0x43 | W | モード・レジスタ | | #### システム・ポート ^ アドレス ^ R/W ^ 機能 ^ 備考 ^ | 0x61 | R | システム・ステータス | | | ::: | W | システム・コマンド | | ### レジスタ詳細 #### 1) モード・レジスタ(ライト) [カウンタ選択] ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x43 | D7 | CHNO | 00: カウンタ#0選択,01: カウンタ#1選択,\\ 10: カウンタ#2選択,02: リードバック・コマンド | | ::: | D6 | ::: | ::: | | ::: | D5 | RWMD | 00: カウンタ・ラッチ動作(読み出し時),01: 下位バイトの読み書き,\\ 10: 上位バイトの読み書き,02: 下位・上位の順に読み書き(デフォルト) | | ::: | D4 | ::: | ::: | | ::: | D3 | MODE | モード番号\\ 000: カウント終了時の割り込み,\\ 010: レート・ジェネレータ,\\ 011: 方形波レート・ジェネレータ | | ::: | D2 | ::: | ::: | | ::: | D1 | ::: | ::: | | ::: | D0 | BCD | 0: バイナリ・カウント,1: BCDカウント | [リードバック・コマンド] ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x43 | D7 | 1 | | | ::: | D6 | 1 | | | ::: | D5 | CR | =0: カウンタ・ラッチ | | ::: | D4 | SR | =0: ステータス・ラッチ | | ::: | D3 | CH2 | =1 でカウンタ#2選択 | | ::: | D2 | CH1 | =1 でカウンタ#1選択 | | ::: | D1 | CH0 | =1 でカウンタ#0選択 | | ::: | D0 | 0 | | #### 2) ステータス(リード) ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x40\\ 0x41\\ 0x42 | D7 | OUT | 0: OUT端子レベル・ロー,1: OUT端子レベル・ハイ | | ::: | D6 | NULL | 0: カウンタ有効,1: カウンタ無効 | | ::: | D5 | RWMD | 00: カウンタ・ラッチ動作(読み出し時),01: 下位バイトの読み書き,\\ 10: 上位バイトの読み書き,02: 下位・上位の順に読み書き(デフォルト) | | ::: | D4 | ::: | ::: | | ::: | D3 | MODE | モード番号\\ 000: カウント終了時の割り込み,\\ 010: レート・ジェネレータ,\\ 011: 方形波レート・ジェネレータ | | ::: | D2 | ::: | ::: | | ::: | D1 | ::: | ::: | | ::: | D0 | BCD | 0: バイナリ・カウント,1: BCDカウント | #### 3) カウンタの読み書き(リード/ライト) ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x40\\ 0x41\\ 0x42 | D7 | COUNTER | モード・レジスタの設定直後に有効 | | ::: | D6 | ::: | ::: | | ::: | D5 | ::: | ::: | | ::: | D4 | ::: | ::: | | ::: | D3 | ::: | ::: | | ::: | D2 | ::: | ::: | | ::: | D1 | ::: | ::: | | ::: | D0 | ::: | ::: | #### 4) システム・コマンド(ライト) ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x61 | D7 | 0 | | | ::: | D6 | 0 | | | ::: | D5 | 0 | | | ::: | D4 | 0 | | | ::: | D3 | EIOC | I/Oチャネル・エラー状態(0:禁止, 1:許可) | | ::: | D2 | EMPE | メモリ・パリティ・チェック状態(0:禁止, 1:許可) | | ::: | D1 | SPKG | PITチャネル2のスピーカへの出力状態(0:禁止, 1:許可) | | ::: | D0 | T2G | PITチャネル2の出力状態(0:禁止, 1:許可) | #### 5) システム・ステータス(リード) ^ アドレス ^ Bit ^ 項目 ^ 説明 ^ | 0x61 | D7 | MPE | メモリ・パリティ・エラー | | ::: | D6 | IOCE | I/Oチャネル・エラー | | ::: | D5 | TC2O | チャネル2の出力信号がアクティブ | | ::: | D4 | REF | メモリ・リフレッシュのチェック | | ::: | D3 | EIOC | I/Oチャネル・エラー状態 | | ::: | D2 | EMPE | メモリ・パリティ・チェック状態 | | ::: | D1 | SPKG | PITチャネル2のスピーカへの出力状態 | | ::: | D0 | T2G | PITチャネル2出力状態 | テストプログラム ------------ I/Oポートを操作するサンプルプログラム。 #include #include #include #include /* for usleep */ #include /* for inb,outb */ static void beep_on(void) { outb(inb(0x61)|3, 0x61); /* beep on */ } static void beep_off(void) { outb(inb(0x61)&0xfc, 0x61); /* beep off */ } int main(int argc, char *argv[]) { uint32_t count; if ((ioperm(0x0040, 4, 1)) || (ioperm(0x0061, 1, 1))) { perror("ioperm"); return 1; } count = 1193180/1000; /* 1000 Hz */ outb(0xb6, 0x43); /* set freq */ outb(count & 0xff, 0x42); outb((count>>8) & 0xff, 0x42); beep_on(); usleep(1000000); /* 1sec wait */ beep_off(); return 0; } * [[https://linuxjm.osdn.jp/html/LDP_man-pages/man2/ioperm.2.html|ioperm]]関数で、ポートの入出力許可を設定する。 ### コンパイル方法 上記ソースを、`beep_test.c` ファイルに作成。下記コマンドでコンパイル。 $ gcc -o beep_test beep_test.c ### 実行方法 root権限で実行する。 $ sudo ./beep_test 実行すると、1秒間ビープ音がなる。 関連記事 ------- * [[myblog>2020/03/01/inux-beep-io-access/|LinuxでI/Oポート操作してBeep音を鳴らす]] 参考 ---- 1. {{http://www.mech.tohoku-gakuin.ac.jp/rde/contents/linux/material/linuxjapan/200107-robot.pdf|「Linuxによるハードウェア制御の基礎」 Linux Japan July 2001}} 2. 「DOS/Vテクニカル・リファレンス・マニュアル(増補版)」 ソフトバンク(株)出版 1994年7月25日初版発行 3. 「別冊トランジスタ技術 '97 IBM PC活用ハンドブック」 CQ出版社 1997年4月1日発行