Download presentation
Presentation is loading. Please wait.
1
Linuxのデバイスファイルを意識して使ったこと が無い方へ入口の紹介。
/dev/* とミキサーデバイスの実装 〜デバイスドライバの入口〜 LILO Monthly Seminor and LUCK 勉強会(?) / 丸市展之 Linuxのデバイスファイルを意識して使ったこと が無い方へ入口の紹介。 /dev/* はワイルドカードでデバイスファイルを示しています。 サブタイトルとして「デバイスドライバの入口」と言うのをつけさせてもらいました。 …と言うことで初歩的なことにしか触れません。 デバイスドライバの話の前にユーザ・プログラムからドライバ使うところにも触れます。 最初に使った、Linux は、0.97 広島でソフトウェアの開発やサーバーネットワークの管理を行っています。 別にLinux以外のUNIXでも通用する 部分がほとんどだと思います。 1
2
この文書について この文書は、Linux/TOWNSのカーネル添付文書用に書いた 「FM TOWNS のミキサーデバイスについて」(towns_mixer.txt) に 他デバイスについての使い方やデバイスドライバの構成などつい ての説明を加えた形でほぼ書き直し再構成した文書です。 元がカーネル添付の文書なので、GPL として公開します。 ただし、他の文書からの引用になっている部分やコードを引用し た部分もありますので、それらは元のコードのライセンスに従い ます。 (カーネル添付のものは、同じライセンスのはずです。) 2
3
説明の流れ ※ なおこのドライバは10年前の物です。 デバイス→デバイスファイル マウスの場合 Linux/TOWNSのミキサーの例
デバイスの説明(サウンドドライバ全般/ミキサー関連) ミキサーデバイスの使い方 アプリケーションからデバイスドライバまでの流れ ハードウェア関連 デバイスファイルを説明。 デバイスファイルを知っているか? 特定のデバイスを使うプログラムを作ったことがある? デバイスドライバを作ったことがある? ※ なおこのドライバは10年前の物です。
4
注意書き 今回はデバイスドライバのことについて話します が、この話は極めて初歩的な話であり、本来説明 すべき事がまったく足りていません。
∴ 以下の点に注意して下さい。 実際の読み書きを行う部分がありません。 モジュールについて触れません。 各所の内容が古いです。 開発をされたい方は、別途書籍を購入することを お薦めします。 4
5
まず、Linuxを使っていてデバイス を使っていない人は…?。
Linuxを始めUNIX系のオペレーティングシステ ムでは、あらゆるデバイスをファイルとして抽 象化して使用するようになっています。 Linuxをインストールした方や使っている方は 、CD-ROMやハードディスクのデバイスファイ ルを使っています。 /dev/hda?, /dev/sd?, /dev/cdrom などを使ったはず。 /dev/console, /dev/mouse → ∴ いない。 5
6
デバイスファイルの紹介 デバイスを抽象化したものは、デバイスファイルもしくはスペ シャルファイルと呼ばれます。
$ ls -l /usr/share/man/ja_JP.eucJP/man4/ /usr/share/man/man4/ /usr/share/man/ja_JP.eucJP/man4/: 合計 164 -rw-r--r root root 月 11日 2004年 atalk.4.gz -rw-r--r root root 月 11日 2004年 console.4.gz -rw-r--r root root 月 11日 2004年 console_codes.4.gz -rw-r--r root root 月 11日 2004年 console_ioctl.4.gz -rw-r--r root root 月 11日 2004年 dsp56k.4.gz -rw-r--r root root 月 11日 2004年 fd.4.gz -rw-r--r root root 月 11日 2004年 fifo.4.gz -rw-r--r root root 月 11日 2004年 full.4.gz -rw-r--r root root 月 11日 2004年 futex.4.gz -rw-r--r root root 月 11日 2004年 hd.4.gz -rw-r--r root root 月 11日 2004年 i gz -rw-r--r root root 月 11日 2004年 initrd.4.gz -rw-r--r root root 月 11日 2004年 intro.4.gz -rw-r--r root root 月 11日 2004年 kmem.4.gz -rw-r--r root root 月 11日 2004年 lp.4.gz -rw-r--r root root 月 11日 2004年 magic.4.gz -rw-r--r root root 月 11日 2004年 mem.4.gz -rw-r--r digit users 月 26日 2005年 mouse.4.gz まず、マニュアルを見ましょう。 $ man 4 intro じゃあ、そのファイルを見ましょう。 $ ls /dev $ ls /dev ptyb3 ptyp6 ptyt9 ptyxc tty15 ttya6 ttye9 ttysc ttywf adsp ptyb4 ptyp7 ptyta ptyxd tty16 ttya7 ttyea ttysd ttyx0 agpgart ptyb5 ptyp8 ptytb ptyxe tty17 ttya8 ttyeb ttyse ttyx1 audio ptyb6 ptyp9 ptytc ptyxf tty18 ttya9 ttyec ttysf ttyx2 bus/ ptyb7 ptypa ptytd ptyy tty19 ttyaa ttyed ttyt0 ttyx3 ptyb8 ptypb ptyte ptyy tty2 ttyab ttyee ttyt1 ttyx4 ptyb9 ptypc ptytf ptyy tty20 ttyac ttyef ttyt2 ttyx5 console ptyba ptypd ptyu0 ptyy tty21 ttyad ttyp0 ttyt3 ttyx6 dsp ptybb ptype ptyu1 ptyy tty22 ttyae ttyp1 ttyt4 ttyx7 ptybc ptypf ptyu2 ptyy tty23 ttyaf ttyp2 ttyt5 ttyx8 ptybd ptyq0 ptyu3 ptyy tty24 ttyb0 ttyp3 ttyt6 ttyx9 ドライバに関するマニュアルどんなマニュアルがあるか確認。 6
7
UNIX以外では、…。 MS-DOSも昔の売り文句には、「UNIXライクな*1みた いな…」ことが書いてありました。
じゃあ、MS-DOS(と言うか今のWindowsでは?) dir … C:\>dir NUL CON COM1 \\. のディレクトリ ファイルが見つかりません $ uname -a CYGWIN_NT-5.1 today (0.156/4/2) :52 i686 Cygwin $ ls -l NUL CON COM1 COM2 COM3 LPT1 LPT2 LPT3 hogehoge ls: CON: No such file or directory ls: COM1: No such file or directory ls: COM2: No such file or directory ls: LPT1: No such file or directory ls: LPT2: No such file or directory ls: LPT3: No such file or directory ls: cannot access hogehoge: No such file or directory ???????? ???????? 0 Jan COM1 ???????? ???????? 0 Jan COM2 -rwxrwxrwx 0 Administrators SYSTEM 0 Jan COM3 ???????? ???????? 0 Jan CON ???????? ???????? 0 Jan LPT1 ???????? ???????? 0 Jan LPT2 ???????? ???????? 0 Jan LPT3 -rwxrwxrwx 0 Administrators SYSTEM 0 Jan NUL Windows のデバイスドライバのことは良く知らないのでMS-DOSについてですが、 と行ったところですが、 *** STOP 0x0000XXXX まぁ、これ以上追っかけてもしょうがないので… ? *1 当時の基準ですけど。 ( 確かメーカのカタログに書かれていたものです。) 7
8
Linuxのデバイスファイルを さらに追っかける。
参考としてマウスを見ます。 $ ls -l /dev/mouse lrwxrwxrwx 1 root root 月 14日 2005年 /dev/mouse -> psaux リンクなので追っかけます。 $ ls -l /dev/psaux crw-rw-rw root sys , 月 7日 13:39 /dev/psaux デバイスファイルの作成方法を見ると…。 man mknod マウスのデバイスファイルを ls -l で詳細を見ると左端の'c'となっていて、通常はファイルサイズが出ているところに2つの数字が書いてあります。 8
10
で、/dev/mouse を使うには? Mouseのマニュアルを見ましょう。 $ man 4 mouse
11
マニュアルを読むとデバイスからデータが読めるみたいだけど…。
まぁ、実際にデータを見てみましょう。 od -t x1 /dev/mouse $ od -t x1 /dev/mouse ff ff ff 38 fe fe 38 fd fe 38 fd fd 38 fc fd 38 fc fd 38 fc fd 38 fc fd 38 fc fd 38 fc fd 38 fc fd 38 fc fc 38 fc fd 38 fb fc 38 fc fd fe fd 38 fd fd 38 fd fd 38 fd fd 38 fb fc 38 fe fe 38 fd fe 38 fd fd 38 fd fe 38 fe fe 38 fe fe 38 fe fe 38 fe fe 38 fe fe 38 fd fe 38 fd fd fd fd 38 f9 fa 38 fc fc 38 fc fc 38 fc fd 38 fd fd 38 fd fd 38 fc fe 38 fc fd 38 fc fd 38 fb fd 38 fc fc 38 fd fe 38 fc fd 38 fd fd 38 fc fd ... byte d7 d6 d5 d4 d3 d2 d1 d0 dy8 dx rb lb 2 dx7 dx6 dx5 dx4 dx3 dx2 dx1 dx0 3 dy7 dy6 dy5 dy4 dy3 dy2 dy1 dy0 y X L R BEGIN 実際にこのマシンでやってみます。(gpm を切る) -- マウスが、動かないでデータが来ないようです届くデータは、X軸方向を左右、Y軸を上下に動かしたとき、マウスのボタンを操作したときで異なります。 なお、od は、8進数ダンプを見るコマンドですが、私は16進数の方が分かりやすいので、16進数形式をしていてダンプをとっています。 詳細を知りたい方は、od(1) を御覧下さい。 実際のデータの16進数値を見ていくと (1) 下の位(4bit)の値が、8になっているものが定期的に3バイト毎にくり返していることが分かります。 (2) パッドの操作とデータの推移を確認すると規則性があることが分かります。 とりあえず読み込めたし、分析したフォーマット でプログラムできそうかな…。 11
12
テストプログラム リスト 先程調べた規則性から、X座標とY座標およびボタンの変化を取り出すプログラムを作ってみました。
int main(int argc, char **argv) { int rCounter = 0; int rByte = 0; int x = 0, y = 0; int dx, dy; FILE *fp; MouseData mouseData; fp = fopen("/dev/mouse", "r"); while(fp != NULL && rByte != EOF) { rByte = fgetc(fp); mouseData.byteData[rCounter%3] = rByte; if((rCounter%3) == 2) { dx = ((mouseData.vaioMouse.dx8)?(-256):(0)) | mouseData.vaioMouse.dx7_0; dy = ((mouseData.vaioMouse.dy8)?(-256):(0)) | mouseData.vaioMouse.dy7_0; x += dx; y += dy; printf("Button (L:%d / R:%d) - " "x = %4d(%3d) , y = %4d(%3d)\n", mouseData.vaioMouse.lButtun, mouseData.vaioMouse.rButtun, x, dx, y, dy); } ++rCounter; fclose(fp); リスト #include <stdio.h> #include <stdlib.h> typedef union { unsigned char byteData[4]; struct { unsigned int lButtun:1; unsigned int rButtun:1; unsigned int reserved0_1:1; unsigned int startflag0:1; unsigned int dx8:1; unsigned int dy8:1; unsigned int reserved0:2; unsigned int dx7_0:8; unsigned int dy7_0:8; unsigned int reserved3:8; } vaioMouse; } MouseData; /dev/mouseをオープン データを読み込む 先程調べた規則性から、X座標とY座標およびボタンの変化を取り出すプログラムを作ってみました。 まず、データのフォーマットを共用体/構造体で示します。 次に読み取りプログラムを示します。 /dev/mouseをクローズ
13
実行結果 試してみました。 実演予定。 $ ./mouse-test
Button (L:0 / R:0) - x = 1( 1) , y = 0( 0) Button (L:0 / R:0) - x = 2( 1) , y = 0( 0) Button (L:0 / R:0) - x = 3( 1) , y = 0( 0) Button (L:0 / R:0) - x = 4( 1) , y = 0( 0) Button (L:0 / R:0) - x = 4( 0) , y = -1( -1) Button (L:1 / R:0) - x = 4( 0) , y = -1( 0) Button (L:0 / R:0) - x = 4( 0) , y = -1( 0) Button (L:0 / R:1) - x = 4( 0) , y = -1( 0) Button (L:0 / R:0) - x = 3( -1) , y = -1( 0) 実演予定。 13
14
ミキサーデバイスの概要と実装 以降はFM TOWNSの Linux(Linux/TOWNS) 用に 実装したミキサーデバイスについてデバイスの 概要と実装について説明します。 TOWNS, Linux/TOWNS の概要 ミキサーデバイスへ 10年前に ベースのカーネルで追加したデバイスドライバなので、 内容に古いところがあります。 14
15
FM TOWNS は、1989年に富士通が発表したマ ルチメディアパソコンです。
80386ベースに設計されたため元もと32bitで動 作させることを前提になっています。 全てのマシンにCD-ROMドライブが搭載されて います。 標準搭載のCD-ROMドライブを活用したフリー ソフトウェアをメーカがとりまとめて流通に載 せていた。 TOWNS には、80386 機以外にも486/Pentium機などもあったことを説明。 PC/AT互換機ベースにTOWNSのハードの主要な機能をPCIのボードとして組み込んだ、V-TOWNS もあります。 FMV-TOWNS FUJITSU ∞ 15
16
gccが移植されていた。(Linux以前に)
FM TOWNS とLinux gccが移植されていた。(Linux以前に) 8bitのFMシリーズではOS-9/6809と言うOSがあ ったのでマルチタスク/マルチユーザーOSを望 むユーザが多かった。 FM TOWNS向けLinuxが、1992年7月21日にリリ ースされた。おそらくPC/AT互換機以外のアー キテクチャーへの移植は世界初。 パソコン通信 niftyのFM関係のフォーラムで(AT 互換機も含めた)Linux FAQが作られた。 →後のJFにつながる流れです。 16
17
TOWNSにミキサーデバイス… (1) TOWNSで標準搭載のCD-ROMを活用したフリ ーウェアの優れたCD-Playerが作られていた。
Linux/TOWNS ユーザを増やすためには、 X Window System 上で動くCD-Playerが必要と思 い、開発を始めた。 Linux/TOWNS用のCD-Playerを作った関係でボ リューム制御を行う必要が出てきた。 17
18
TOWNSにミキサーデバイス… (2) 当初は、Linux/TOWNSのサウンドドライバの作 者の方が直接I/O制御を行うプログラムを実装 されていたので、それを流用させてもらった。 元もとCD-ROMのデバイスドライバの仕様は TOWNS独自の実装だったが、Linux標準のドラ イバが開発されてPC/ATとの互換性が確保され た。ミキサーを使用可能にすれば、PC/AT互換 機で動かすことが可能となる。 18
19
TOWNSにミキサーデバイス… (3) TOWNSの電子ボリュームのハードウェアの仕 様上、現在のボリューム値を取得する際に情報 が失われる可能性があった。 一般的なLinuxのアプリケーションでTOWNSの ボリューム制御が可能になる。 19
20
TOWNSの /dev/mixer 実装前は?
int set_volume(int indx, int volume_level) { int fd; char vol; char chan; if (volume_level >= 0) { chan = chan_data[indx].chan | 0x04; vol = volume_level; } else if (volume_level == -1) { chan = chan_data[indx].chan & ~0x04; vol = 0; } if ((fd=open("/dev/port",O_RDWR))<0) { return(EOF); lseek(fd,chan_data[indx].creg,0); write(fd,&chan,1); lseek(fd,chan_data[indx].dreg,0); write(fd,&vol,1); volume_buffering(indx, chan, vol); close(fd); return(0); 以前は、/dev/port を使って直接ポートを制御 if ((fd=open("/dev/port",O_RDWR))<0) { return(EOF); } lseek(fd,chan_data[indx].creg,0); write(fd,&chan,1); lseek(fd,chan_data[indx].dreg,0); write(fd,&vol,1); volume_buffering(indx, chan, vol); close(fd); $ man 4 port 20
21
TOWNSのミキサーデバイスの例 システム構成とデバイスドライバの基礎 Linux 標準のサウンドドライバの実装の調査
Linux/TOWNSのミキサーの例 TOWNSのサウンド関連のハード構成 Linux 標準のサウンドドライバの実装の調査 21
22
デバイスドライバの位置付け ユーザー空間 カーネル空間 カーネル空間とユーザー空間
ユーザプロセス システムコール デバイスドライバ カーネル空間 この図は、Plamo のメーリングリストで出てきた図です。 OSの中心部分のカーネルやデバイスドライバと、一般のプログラムは、CPUから見て違う権限で動作しています。 一般的なプログラムは、ユーザー空間と言う他のプログラムやOS側を誤動作などで破壊することが無いように保護された状態で動かすことができるようになっています。 内部構成については、Plamo のメーリングリストを参照。 22
23
ユーザ操作から実際のI/O制御まで を順を追って見て行きます。 ユーザ プロセス ファイルシステム ファイルシステム ファイルシステム
/* * NOTE: * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl * can be called without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); }; /* * NOTE: * read, write, poll, fsync, readv, writev can be called * without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; ユーザ プロセス ファイルシステム ファイルシステム ファイルシステム ファイルシステム ファイルシステム ハードウェア デバイス ドライバ デバイス ドライバ HDD デバイス ドライバ デバイス ドライバ SCSI サウンド を順を追って見て行きます。 その他… ネットワーク
24
ミキサーデバイスを作るには? デバイスドライバの事を調べる。 サウンド関連のハードウェアを調べる。 どれが、ボリューム制御可能か? など
サウンド関連のハードウェアを調べる。 どれが、ボリューム制御可能か? など サウンド関連のデバイスドライバを調べる。 ミキサーは他のサウンドドライバに影響する。 Linux標準とするため(主にAT互換機の環境で) どのように実装されているかを調べる。 24
25
ミキサーデバイス…って。 サウンドデバイスの中でソフトウェアで制御す るボリュームのことです。 つまりサウンドデバイスの一部です。
サウンド関連のデバイスには、CD, PCM音源な どから構成されています。 どの部分のボリュームを制御できるかなどは、 ハード的なサウンド関係の構成に大きく依存し ます。 25
26
FM TOWNSのサウンド機能 TOWNS独自のものもあるかもしれませんが、 特殊なものではありません。 個々のものをあげて行きます。
CD-ROMドライブ (CD Digital Audio出力) MIC ヘッドフォン端子 LINE IN スピーカ LINE OUT FM音源 個々のものをあげて行きます。 (1) TOWNS の特徴である CD-ROM ドライブ。 (2) マイク(内蔵/MIC端子)とライン入力(HR背面) PCM音源 その他デバイス(オプション) 内蔵モデム, AD-PCM 26
27
Linuxのサウンドドライバ 現在のカーネル2.6系になってからは、ALSAが 標準のドライバに置き換わり*1ましたが、私が TOWNSでドライバを作った段階では、OSSが 標準でした。TOWNSで実装されているもの は、OSSの実装に近いもので互換性がありま す。 27
28
OSS/Freeのデバイスファイル /usr/src/linux/Documentation/devices.txt
14 char Open Sound System (OSS) 0 = /dev/mixer Mixer control 1 = /dev/sequencer Audio sequencer 2 = /dev/midi First MIDI port 3 = /dev/dsp Digital audio 4 = /dev/audio Sun-compatible digital audio 6 = /dev/sndstat Sound card status information {2.6} 7 = /dev/audioctl SPARC audio control device 8 = /dev/sequencer2 Sequencer -- alternate device 16 = /dev/mixer Second soundcard mixer control 17 = /dev/patmgr Sequencer patch manager 18 = /dev/midi Second MIDI port 19 = /dev/dsp Second soundcard digital audio 20 = /dev/audio Second soundcard Sun digital audio 33 = /dev/patmgr Sequencer patch manager 34 = /dev/midi Third MIDI port 50 = /dev/midi Fourth MIDI port カーネル添付文書より引用。 28
29
TOWNSのサウンドデバイス デバイスファイル一覧
TOWNSのサウンドデバイスは、OSS/Freeの仕様にあわせて実装にされています。しかし、FM TOWNS向けのデバイスが追加されていることや、実装の過程から独自部分が多くなっています。 29 29
30
OSS/Freeのミキサーデバイス ミキサーデバイスで実装すべき機能を調べる。 ミキサーを使うプログラムの処理を調べる。
ミキサーデバイスで実装すべき機能を調べる。 ミキサーを使うプログラムの処理を調べる。 #include <stdio.h> #include <stdlib.h> /*********************************************** * I/O 制御のためのインクルード・ファイル ***********************************************/ #include <fcntl.h> #include <sys/types.h> * Linux のサウンド関係インクルード・ファイル #include <linux/soundcard.h> void deviceList(int mixer) { int devices; int streoDevices; int counter, bitCounter; static const char *stereoOrMono[] = {"mono", "stero"}; const char *soundDeviceNames[] = SOUND_DEVICE_NAMES; const char *soundDeviceLabels[] = SOUND_DEVICE_LABELS; if(ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devices) >= 0 && ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &streoDevices) >= 0) { for(counter = 0, bitCounter = 0x001; counter < SOUND_MIXER_NRDEVICES;++counter, bitCounter <<= 1) { printf("%s %s\n", soundDeviceNames[counter], stereoOrMono[(streoDevices & bitCounter) != 0]); } int main(int argc, char **argv) { int mixer; mixer = open("/dev/mixer", O_RDWR); ・ ・(この部分にミキサーを操作するコードを記述する) close(mixer); return(0); }
31
「今の」ってどんなのI/O操作? Ioctl() とは? では、ioctl(2) を見ましょう。 $ man 2 ioctl ユーザ
/* * NOTE: * read, write, poll, fsync, readv, writev can be called * without the big kernel lock held in all filesystems. */ struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; ユーザ プロセス static struct file_operations fmmidi_fops = { read: fmmidi_read, write: fmmidi_write, poll: fmmidi_select, ioctl: fmmidi_ioctl, mmap: fmmidi_mmap, open: fmmidi_open, release: fmmidi_release, }; ・ static int __init init_tsound(void) { if(devfs_register_chrdev(SOUND_MAJOR, DRIVER_NAME, &fmmidi_fops)==-1) printk(KERN_ERR DRIVER_NAME ": sound device already in use.\n"); return -EBUSY; } devfs_handle = devfs_mk_dir (NULL, DRIVER_NAME, NULL); pcm16_inst=pcm16_init(); static int fmmidi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { int dev; dev = inode->i_rdev; dev = MINOR(dev); if( cmd == FMMINIT ){ if( MID_sysInit() ){ printk( DEVICE_NAME ":MIDI initializing fail.\n" ); return -EIO; } return 0; switch( dev & FMIDI_MINOR_MASK ){ case FMIDI_SEQCTL: return seq_ioctl( inode, file, cmd, arg ); case FMIDI_PCM: return pcm_ioctl(inode, file, cmd, arg); case FMIDI_MIXER: return towns_mixer_ioctl(inode, file, cmd , arg); break; case FMIDI_PCM16: return pcm16_ioctl( inode, file, cmd , arg); case FMIDI_FM: return fmpcm_ioctl( inode, file, cmd, arg ); return -EPERM; ファイルシステム ファイルシステム ファイルシステム ファイルシステム ファイルシステム ハードウェア デバイス ドライバ デバイス ドライバ HDD デバイス ドライバ デバイス ドライバ SCSI サウンド その他… ネットワーク
32
TOWNSのサウンドドライバ サウンドドライバのシステムコール各機能
33
ミキサーの機能 (ioctl()) SOUND_MIXER_READ_DEVMASK ボリューム制御可能な対象を取得。
SOUND_MIXER_READ_STREODEV LR 独立のステレオボリュームな対象を取得。 SOUND_MIXER_READ_RECMASK 録音可能な音源として選択可能な対象を取得。 SOUND_MIXER_READ_RECSRC 録音用の対象となっている対象を取得。 SOUND_MIXER_WRITE_RECSRC 録音用の対象となる対象を設定します。 SOUND_MIXER_READ_xxx / MIXER_READ(SOUND_MIXER_xxx) ボリューム・レベルの取得 SOUND_MIXER_WRITE_xxx / MIXER_WRITE(SOUND_MIXER_xxx) ボリューム・レベルの設定 33 33
34
SOUND_MIXER_READ_DEVMASK
ボリューム制御可能なチャンネルを取得します。 制御可能なチャンネルは、SOUND_MIXER_xxxと一対一で対応する SOUND_MASK_xxx と言う名前のマスクビットの論理和で表される。 (下の表を参照) TOWNS では、 全ミュート/ FM 音源 / 8bit PCM 音源/ 16bit PCM 音源(*10) / CD オーディオ / ライン入力 / マイク入力 / モデムカードとなります。 ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devices);
35
/usr/include/linux/soundcard.h
/* * Mixer devices * * There can be up to 20 different analog mixer channels. The * SOUND_MIXER_NRDEVICES gives the currently supported maximum. * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells * the devices supported by the particular mixer. */ #define SOUND_MIXER_NRDEVICES 25 #define SOUND_MIXER_VOLUME #define SOUND_MIXER_BASS #define SOUND_MIXER_TREBLE #define SOUND_MIXER_SYNTH #define SOUND_MIXER_PCM 《中略》 /* Device mask bits */ #define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) #define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) #define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) #define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) #define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
36
ボリューム設定可能な対象 OSS/Freeのボリューム設定対象 36
37
SOUND_MIXER_READ_STREODEV
LR 独立のステレオボリュームが扱えるチャンネルを取得します。 LR 独立での制御可能なチャンネルは、SOUND_MIXER_xxx と一対一で対応するSOUND_MASK_xxx と言う名前のマスクビットの論理和で表される。 TOWNS では、 CD オーディオ/ ライン入力/ 16bit PCM 音源10となります。 ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &streoDevices); チャンネルの取得形式は、 SOUND_MIXER_READ_DEVMASK と同じ形式です。
38
SOUND_MIXER_READ_RECMASK
録音可能な音源として選択可能なチャンネルを取得します。 制御可能なチャンネルは、SOUND_MIXER_xxxと一対一で対応するSOUND_MASK_xxx と言う名前のマスクビットの論理和で表される。 TOWNS では、得に録音のみのON/OFF が可能なチャンネルが無く、常にライン出力される音と同じものが録音の対象になります。 このため便宜上、 TOWNS では、 0 を返すことにしています。 チャンネルの取得形式は、 SOUND_MIXER_READ_DEVMASK と同じ形式です。
39
SOUND_MIXER_READ_RECSRC
録音用の対象となっているチャンネルを取得します。 制御可能なチャンネルは、SOUND_MIXER_xxxと一対一で対応するSOUND_MASK_xxx と言う名前のマスクビットの論理和で表される。 これは、 SOUND_MIXER_READ_DEVMASK と同じ形式です。 TOWNS では、 CD オーディオ/ ライン入力/ マイク入力としています。 チャンネルの取得形式は、 SOUND_MIXER_READ_DEVMASK と同じ形式です。
40
SOUND_MIXER_WRITE_RECSRC
録音用の対象となっているチャンネルを設定します。 TOWNS では、CD オーディオ/ ライン入力/ マイク入力としていて固定です。 また、TOWNS では機器の選択が不可能なため変更できません。 チャンネルの取得形式は、 SOUND_MIXER_READ_DEVMASK と同じ形式です。
41
SOUND_MIXER_READ_xxx or MIXER_READ(SOUND_MIXER_xxx)
ボリューム・レベルの取得 xxx の部分は、 取得したいチャンネルになります。 これらのラベルは、 以下のような関係になっています。 #define SOUND_MIXER_READ_xxx \ MIXER_READ(SOUND_MIXER_xxx) つまり、 channel_no = SOUND_MIXER_CD; ioctl(fd, SOUND_MIXER_READ_CD, &volume); ioctl(fd, MIXER_READ(channel_no), &volume);
42
SOUND_MIXER_WRITE_xxx or MIXER_WRITE(SOUND_MIXER_xxx)
ボリューム・レベルの設定 xxx の部分は、 設定したいチャンネルになります。 これらのラベルは、 以下のような関係になっています。 #define SOUND_MIXER_WRITE_xxx \ MIXER_WRITE(SOUND_MIXER_xxx) つまり、 channel_no = SOUND_MIXER_CD; ioctl(fd, SOUND_MIXER_WRITE_CD, &volume); ioctl(fd, MIXER_WRITE(channel_no), &volume);
43
ミキサーの機能 (ioctl()) SOUND_MIXER_READ_DEVMASK ボリューム制御可能な対象を取得。
int volume = (left & 0xff) | ((right & 0xff) << 8); ioctl(fd, MIXER_WRITE(channel_no), &volume); SOUND_MIXER_READ_DEVMASK ボリューム制御可能な対象を取得。 int devices; ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devices); SOUND_MIXER_READ_STREODEV LR 独立のステレオボリュームな対象を取得。 SOUND_MIXER_READ_xxx / MIXER_READ(SOUND_MIXER_xxx) ボリューム・レベルの取得 int streoDevices; ioctl(mixer, SOUND_MIXER_READ_STEREODEVS, &streoDevices); SOUND_MIXER_WRITE_xxx / MIXER_WRITE(SOUND_MIXER_xxx) ボリューム・レベルの設定 int left, right, volume; ioctl(fd, MIXER_READ(channel_no), &volume); left = volume & 0x000000ff; right = (volume & 0x0000ff00) >> 8; 43 43
44
サウンドデバイス→ミキサー サウンドデバイスからミキサーデバイスへ ファイルシステム ユーザ プロセス HDD デバイス ドライバ SCSI
/* Device Driver routines. */ static int fmmidi_open( struct inode *inode, struct file *file) { int dev,ret; dev = inode->i_rdev; dev = MINOR(dev); switch( dev & FMIDI_MINOR_MASK ){ 《中略》 case FMIDI_PCM: ret=pcm_open( inode, file ); break; case FMIDI_MIXER: ret=towns_mixer_open( inode, file ); case FMIDI_PCM16: ret=pcm16_open( inode, file ); default: ret=-ENODEV; } if (!ret) { MOD_INC_USE_COUNT; return ret; static int fmmidi_release( struct inode *inode, struct file *file) { int dev; dev = inode->i_rdev; dev = MINOR(dev); switch( dev & FMIDI_MINOR_MASK ){ case FMIDI_MIDI: midi_release( inode, file ); break; 《中略》 case FMIDI_PCM: pcm_release( inode, file ); case FMIDI_MIXER: towns_mixer_release( inode, file ); case FMIDI_PCM16: pcm16_release(inode,file ); case FMIDI_FM: fmpcm_release( inode, file ); } MOD_DEC_USE_COUNT; return 0; static int fmmidi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) { int dev; dev = inode->i_rdev; dev = MINOR(dev); if( cmd == FMMINIT ){ if( MID_sysInit() ){ printk( DEVICE_NAME ":MIDI initializing fail.\n" ); return -EIO; } return 0; switch( dev & FMIDI_MINOR_MASK ){ case FMIDI_SEQCTL: return seq_ioctl( inode, file, cmd, arg ); case FMIDI_PCM: return pcm_ioctl(inode, file, cmd, arg); case FMIDI_MIXER: return towns_mixer_ioctl(inode, file, cmd , arg); break; case FMIDI_PCM16: return pcm16_ioctl( inode, file, cmd , arg); case FMIDI_FM: return fmpcm_ioctl( inode, file, cmd, arg ); return -EPERM; ユーザ プロセス デバイス ドライバ ファイルシステム ネットワーク ハードウェア HDD SCSI サウンド その他…
45
TOWNSミキサーのioctl()処理 ソースコード switch(dev) { case SOUND_MIXER_RECSRC:
int towns_mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { int vol; int dev = cmd & 0xff; TownsMixerDevices *mixer = NULL; if(dev >= 0 && dev < SOUND_MIXER_NRDEVICES) mixer = &townsMixers[dev]; if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "TOWNS", sizeof(info.id)); strncpy(info.name, "FM-TOWNS", sizeof(info.name)); info.modify_counter = modify_counter; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; strncpy(info.name, "TOWNS", sizeof(info.name)); if (((cmd >> 8) & 0xff) == 'M') { modify_counter++; if (_IOC_DIR(cmd) & _IOC_WRITE) { if(mixer != NULL && mixer->setVolumeLevel != NULL) { int tmp; get_user(tmp, (int *) arg); vol = mixer->setVolumeLevel(mixer, tmp); return(ioctl_return((int*)arg, ((vol >= 0)?(vol):(0)))); } else switch(dev) { case SOUND_MIXER_RECSRC: return(ioctl_return((int*)arg, townsSystemMixer.recordableMask)); break; case SOUND_MIXER_DEVMASK: return(ioctl_return((int*)arg, townsSystemMixer.enableDevMask)); case SOUND_MIXER_STEREODEVS: return(ioctl_return((int*)arg, townsSystemMixer.stereoDevices)); case SOUND_MIXER_RECMASK: return(ioctl_return((int*)arg, 0)); /*return(ioctl_return((int*)arg, townsSystemMixer.recordableMask));*/ case SOUND_MIXER_CAPS: return(ioctl_return((int*)arg, SOUND_CAP_EXCL_INPUT)); default: if(mixer != NULL && mixer->getVolumeLevel != NULL) { vol = mixer->getVolumeLevel(mixer); return(ioctl_return((int*)arg, ((vol >= 0)?(vol):(0)))); } } else { return(-(EINVAL));
46
ミキサーの初期化処理 デバイスの初期化 void towns_mixer_init(void) {
townsSystemMixer.busy = 0; townsSystemMixer.enableDevMask = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_LINE1; townsSystemMixer.recordableMask = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; townsSystemMixer.stereoDevices = SOUND_MASK_LINE | SOUND_MASK_CD; if(townsSystemMixer.pcm16enable) { mb87078volumes[0].chan = 0x01; mb87078volumes[0].chan = 0x03; townsSystemMixer.enableDevMask |= SOUND_MASK_ALTPCM; townsSystemMixer.stereoDevices |= SOUND_MASK_ALTPCM; townsMixers[SOUND_MIXER_ALTPCM] = Pcm16mixer; } /********************** * sound.treble = 0; * sound.bass = 0; **********************/ setTownsVolume(LINE_L, MAXIMUM_LEVEL); /* line input-L: enable(0dB) */ setTownsVolume(LINE_R, MAXIMUM_LEVEL); /* line input-R: enable(0dB) */ setTownsVolume(ADDA_L, MAXIMUM_LEVEL); /* 16bit PCM-L:enable(0dB) */ setTownsVolume(ADDA_R, MAXIMUM_LEVEL); /* 16bit PCM-R:enable(0dB) */ } else { mb87078volumes[0].creg_mask &= ~2; townsVolChanel[LINE_L].creg_mask &= ~2; townsVolChanel[LINE_R].creg_mask &= ~2; setTownsVolume(CDDA_L, MAXIMUM_LEVEL); /* CDDA output-L:enable(0dB) */ setTownsVolume(CDDA_R, MAXIMUM_LEVEL); /* CDDA output-R:enable(0dB) */ setTownsVolume(MIC_IN, MINIMUM_LEVEL_MUTE); /* MIC input: enable(mute) */ setTownsVolume(MODEMI, MAXIMUM_LEVEL); /* Modem monitor:enable(0dB) */
47
参考文献 LINUX マルチメディアガイド 著者:Jeff Tranter 訳者:山形浩生 ISBN4-900900-31-1
改訂3 版FM TOWNS テクニカルデータブック 著者:千葉憲昭 ISBN 改訂版UNIX デバイスドライバ 著者:Janet I. Egan / Thomas J. Teixeira 監訳:三田典玄 翻訳:野中浩一/ 大西照代 Linux デバイスドライバ 第3版 著者:Janathan Corbet / Alessandro Rubini / Greg Kroah-Hartman 訳者:山崎 康宏 / 山崎 邦子 / 長原 宏治 / 長原 陽子
48
参考資料 JF 文書(http://www.linux.or.jp/JF/)
The Linux Sound HOWTO 著者:Jeff Tranter 訳者:小島 三弘/ 水原文 The Linux Sound Playing HOWTO 著者:Yoo C. Chung 訳者:藤原輝嘉
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.