ioctl関数
32841 ワード
私がここで言ったioctl関数はドライバの中を指しています.他のフィールドが併用されているかどうか分からないので、私たちが議論する範囲を規定しました.この文章を書いたのは、私がこの間ioctlに間違えられたので、ここ数日やっとそれを理解して、ここで頭を整理しました.
一、ioctlとは何か ioctlは、デバイスドライバでデバイスのI/Oチャネルを管理する関数です.I/Oチャネルの管理とは、シリアルポートの伝送ボーレート、モータの回転数など、デバイスのいくつかの特性を制御することである.その呼び出し個数は以下の通りである:int ioctl(int fd,ind cmd,...); ここでfdはユーザプログラムがデバイスを開くときにopen関数を使用して返されるファイルマーカーであり、cmdはユーザプログラムのデバイスに対する制御コマンドであり、後の省略記号については、いくつかの補足パラメータであり、一般的には最大1つであり、このパラメータの有無はcmdの意味と関連している. ioctl関数はファイル構造の属性成分であり、ドライバがioctlのサポートを提供している場合、ユーザーはユーザープログラムでioctl関数を使用してデバイスのI/Oチャネルを制御することができます.
二、ioctlの必要性 ioctlを使わなければ、デバイスI/Oチャネルの制御も可能ですが、それはねじれています.たとえば、ドライバでwriteを実装するときに、特別な約束のデータストリームが通過しているかどうかを確認することができます.もしあれば、後で制御コマンドに従います(一般的にsocketプログラミングではよくそうします).しかし、そうすると、コードの分業が不明になり、プログラム構造が混乱し、プログラマー自身も目がくらくらします.そこでioctlを用いて制御機能を実現します.ユーザプログラムが行ったことは、コマンドコード(cmd)を通じてドライバに何をしたいのか、これらのコマンドをどのように解釈し、どのように実現するかを伝えるだけで、ドライバがしなければならないことを覚えておいてください.
三、ioctlはどのように実現するか これは面倒な問題で、私は節約できるなら節約します.それをはっきり言うには、四五千字がないとだめなので、ここでははっきり言うことはできませんが、読者がユーザープログラムがどのようにドライバと結びついているのかに興味があれば、私がこの間書いた「writeの奥義」を見ることができます.読者はwriteをioctlに変えるだけで、ユーザープログラムのioctlがドライバのioctl実装とどのように関連しているかを知ることができます.「Linuxデバイスドライバ」という本はもうはっきり言っていると思いますが、時間をかけて見なければなりません. ドライバで実装されるioctl関数には、実際にはswitch{case}構造があり、各caseはコマンドコードに対応し、対応する操作を行う.これらの操作をどのように実現するかは、プログラマー一人一人のことです.設備はすべて特定なので、ここでも言えません.重要なのは、ioctlでコマンドコードがユーザプログラムコマンドとドライバサポートに唯一連絡する方法であるため、コマンドコードをどのように組織するかです.命令コードの組織にはいくつかのこだわりがあります.私たちは命令と設備が一つ一つ対応していることをしなければなりません.そうすれば、正しい命令を間違った設備に送ったり、間違った命令を正しい設備に送ったり、間違った命令を間違った設備に送ったりしません.これらのエラーは予想できないことを引き起こしますが、プログラマーがこれらの奇妙なことを発見したときに、プログラムをデバッグしてエラーを探すのは非常に難しいことです.Linuxコアでは、コマンドコードを定義します.デバイスタイプ|シリアル番号|方向|データサイズ||----------------------------------------------------------------------|8 bit | 8 bit | 2 bit |8~14 bit| |----------|--------|------|--------|
これにより、1つのコマンドは整数形式のコマンドコードになります.しかし、コマンドコードは非常に直感的ではないので、Linux Kernelにはいくつかのマクロが提供されています.これらのマクロは、理解しやすい文字列に基づいてコマンドコードを生成することができ、または、コマンドコードから、このコマンドに対応するデバイスタイプ、デバイスシーケンス番号、データ転送方向、およびデータ転送サイズを示すために、一部のユーザが理解できる文字列を得ることができる.
これらのマクロは私はここで説明しないで、具体的な形式は読者にLinuxコアソースコードの中のマクロを見てもらって、ファイルの中でこれらのマクロに完全な定義をしました.ここで私はただ1つの場所だけを言って、それは“幻数”です.「幻数」はアルファベットで、データの長さも8で、特定のアルファベットでデバイスのタイプを表記します.これは数字と同じですが、記憶と理解に役立ちます.このようにして、これ以上複雑なものはありません.もっと言っても始まらないので、読者はやはりソースコードを見てみましょう.「Linuxデバイスドライバ」が持っているソースコードのshortの一例を読むことをお勧めします.短いので、機能が簡単で、ioctlの機能と詳細を見ることができます.
四、cmdパラメータはどのように得られますか ここでは確かに、cmdパラメータは、ユーザプログラム側でデバイスタイプ、シーケンス番号、伝送方向、データサイズなどに応じてマクロによって生成され、この整数はシステム呼び出しによってカーネルに伝達されるドライバであり、この整数からデバイスのタイプ、シーケンス番号、伝送方向、データサイズなどの情報を復号マクロを用いてドライバによって得られ、switch{case}構造は対応する操作を行います.徹底的に理解するには、ソースコードを読むしかありません.私のこの文章は実際にはリードにすぎません.cmdパラメータの組織は複雑で、それを理解するのに時間がかかると思いますが、ドライバの中で最も難しいのは中断に対する理解です.
五、まとめ ioctlは実は何も理解する必要はありません.肝心なのはcmdコマンドコードがどのようにユーザープログラムの中で生成され、ドライバの中で解析されたのかを理解することです.プログラマーの最も主要な仕事量はswitch{case}構造の中で、デバイスに対するI/O制御はこの部分のコードによって実現されているからです.
問題について、いくつかのサンプルコードで説明します.
プログラム1:検出インタフェースのinet_addr,netmask,broad_addr
一、ioctlとは何か ioctlは、デバイスドライバでデバイスのI/Oチャネルを管理する関数です.I/Oチャネルの管理とは、シリアルポートの伝送ボーレート、モータの回転数など、デバイスのいくつかの特性を制御することである.その呼び出し個数は以下の通りである:int ioctl(int fd,ind cmd,...); ここでfdはユーザプログラムがデバイスを開くときにopen関数を使用して返されるファイルマーカーであり、cmdはユーザプログラムのデバイスに対する制御コマンドであり、後の省略記号については、いくつかの補足パラメータであり、一般的には最大1つであり、このパラメータの有無はcmdの意味と関連している. ioctl関数はファイル構造の属性成分であり、ドライバがioctlのサポートを提供している場合、ユーザーはユーザープログラムでioctl関数を使用してデバイスのI/Oチャネルを制御することができます.
二、ioctlの必要性 ioctlを使わなければ、デバイスI/Oチャネルの制御も可能ですが、それはねじれています.たとえば、ドライバでwriteを実装するときに、特別な約束のデータストリームが通過しているかどうかを確認することができます.もしあれば、後で制御コマンドに従います(一般的にsocketプログラミングではよくそうします).しかし、そうすると、コードの分業が不明になり、プログラム構造が混乱し、プログラマー自身も目がくらくらします.そこでioctlを用いて制御機能を実現します.ユーザプログラムが行ったことは、コマンドコード(cmd)を通じてドライバに何をしたいのか、これらのコマンドをどのように解釈し、どのように実現するかを伝えるだけで、ドライバがしなければならないことを覚えておいてください.
三、ioctlはどのように実現するか これは面倒な問題で、私は節約できるなら節約します.それをはっきり言うには、四五千字がないとだめなので、ここでははっきり言うことはできませんが、読者がユーザープログラムがどのようにドライバと結びついているのかに興味があれば、私がこの間書いた「writeの奥義」を見ることができます.読者はwriteをioctlに変えるだけで、ユーザープログラムのioctlがドライバのioctl実装とどのように関連しているかを知ることができます.「Linuxデバイスドライバ」という本はもうはっきり言っていると思いますが、時間をかけて見なければなりません. ドライバで実装されるioctl関数には、実際にはswitch{case}構造があり、各caseはコマンドコードに対応し、対応する操作を行う.これらの操作をどのように実現するかは、プログラマー一人一人のことです.設備はすべて特定なので、ここでも言えません.重要なのは、ioctlでコマンドコードがユーザプログラムコマンドとドライバサポートに唯一連絡する方法であるため、コマンドコードをどのように組織するかです.命令コードの組織にはいくつかのこだわりがあります.私たちは命令と設備が一つ一つ対応していることをしなければなりません.そうすれば、正しい命令を間違った設備に送ったり、間違った命令を正しい設備に送ったり、間違った命令を間違った設備に送ったりしません.これらのエラーは予想できないことを引き起こしますが、プログラマーがこれらの奇妙なことを発見したときに、プログラムをデバッグしてエラーを探すのは非常に難しいことです.Linuxコアでは、コマンドコードを定義します.デバイスタイプ|シリアル番号|方向|データサイズ||----------------------------------------------------------------------|8 bit | 8 bit | 2 bit |8~14 bit| |----------|--------|------|--------|
これにより、1つのコマンドは整数形式のコマンドコードになります.しかし、コマンドコードは非常に直感的ではないので、Linux Kernelにはいくつかのマクロが提供されています.これらのマクロは、理解しやすい文字列に基づいてコマンドコードを生成することができ、または、コマンドコードから、このコマンドに対応するデバイスタイプ、デバイスシーケンス番号、データ転送方向、およびデータ転送サイズを示すために、一部のユーザが理解できる文字列を得ることができる.
これらのマクロは私はここで説明しないで、具体的な形式は読者にLinuxコアソースコードの中のマクロを見てもらって、ファイルの中でこれらのマクロに完全な定義をしました.ここで私はただ1つの場所だけを言って、それは“幻数”です.「幻数」はアルファベットで、データの長さも8で、特定のアルファベットでデバイスのタイプを表記します.これは数字と同じですが、記憶と理解に役立ちます.このようにして、これ以上複雑なものはありません.もっと言っても始まらないので、読者はやはりソースコードを見てみましょう.「Linuxデバイスドライバ」が持っているソースコードのshortの一例を読むことをお勧めします.短いので、機能が簡単で、ioctlの機能と詳細を見ることができます.
四、cmdパラメータはどのように得られますか ここでは確かに、cmdパラメータは、ユーザプログラム側でデバイスタイプ、シーケンス番号、伝送方向、データサイズなどに応じてマクロによって生成され、この整数はシステム呼び出しによってカーネルに伝達されるドライバであり、この整数からデバイスのタイプ、シーケンス番号、伝送方向、データサイズなどの情報を復号マクロを用いてドライバによって得られ、switch{case}構造は対応する操作を行います.徹底的に理解するには、ソースコードを読むしかありません.私のこの文章は実際にはリードにすぎません.cmdパラメータの組織は複雑で、それを理解するのに時間がかかると思いますが、ドライバの中で最も難しいのは中断に対する理解です.
五、まとめ ioctlは実は何も理解する必要はありません.肝心なのはcmdコマンドコードがどのようにユーザープログラムの中で生成され、ドライバの中で解析されたのかを理解することです.プログラマーの最も主要な仕事量はswitch{case}構造の中で、デバイスに対するI/O制御はこの部分のコードによって実現されているからです.
問題について、いくつかのサンプルコードで説明します.
プログラム1:検出インタフェースのinet_addr,netmask,broad_addr
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- static void usage()
- {
- printf("usage : ipconfig interface
");
- exit(0);
- }
- int main(int argc,char **argv)
- {
- struct sockaddr_in *addr;
- struct ifreq ifr;
- char *name,*address;
- int sockfd;
-
- if(argc != 2)
- usage();
- else
- name = argv[1];
-
- sockfd = socket(AF_INET,SOCK_DGRAM,0);
- strncpy(ifr.ifr_name,name,IFNAMSIZ-1);
-
- if(ioctl(sockfd,SIOCGIFADDR,&ifr) == -1)
- perror("ioctl error");
- exit(1);
-
- addr = (struct sockaddr_in *)&(ifr.ifr_addr);
- address = inet_ntoa(addr->sin_addr);
- printf("inet addr: %s ",address);
-
- if(ioctl(sockfd,SIOCGIFBRDADDR,&ifr) == -1)
- perror("ioctl error"),exit(1);
-
- addr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
- address = inet_ntoa(addr->sin_addr);
- printf("broad addr: %s ",address);
-
- if(ioctl(sockfd,SIOCGIFNETMASK,&ifr) == -1)
- perror("ioctl error"),exit(1);
- addr = (struct sockaddr_in *)&ifr.ifr_addr;
- address = inet_ntoa(addr->sin_addr);
- printf("inet mask: %s ",address);
-
- printf("
");
- exit(0);
- }
- 2:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- typedef unsigned short u16;
- typedef unsigned int u32;
- typedef unsigned char u8;
- #include
- #include
-
- int detect_mii(int skfd, char *ifname)
- {
- struct ifreq ifr;
- u16 *data, mii_val;
- unsigned phy_id;
-
- /* Get the vitals from the interface. */
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
- if (ioctl(skfd, SIOCGMIIPHY, &ifr)
- {
- fprintf(stderr, "SIOCGMIIPHY on %s failed: %s
", ifname, strerror(errno));
- (void) close(skfd);
- return 2;
- }
-
- data = (u16 *)(&ifr.ifr_data);
- phy_id = data[0];
- data[1] = 1;
-
- if (ioctl(skfd, SIOCGMIIREG, &ifr)
- {
- fprintf(stderr, "SIOCGMIIREG on %s failed: %s
", ifr.ifr_name, strerror(errno));
- return 2;
- }
-
- mii_val = data[3];
- return(((mii_val & 0x0016) == 0x0004) ? 0 : 1);
- }
-
- int detect_ethtool(int skfd, char *ifname)
- {
- struct ifreq ifr;
- struct ethtool_value edata;
- memset(&ifr, 0, sizeof(ifr));
- edata.cmd = ETHTOOL_GLINK;
-
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
- ifr.ifr_data = (char *) &edata;
-
- if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
- {
- printf("ETHTOOL_GLINK failed: %s
", strerror(errno));
- return 2;
- }
-
- return (edata.data ? 0 : 1);
- }
-
- int main(int argc, char **argv)
- {
- int skfd = -1;
- char *ifname;
- int retval;
-
- if( argv[1] ) ifname = argv[1];
- else ifname = "eth0";
-
- /* Open a socket. */
- if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 ) )
- {
- printf("socket error
");
- exit(-1);
- }
-
- retval = detect_ethtool(skfd, ifname);
- if (retval == 2)
- retval = detect_mii(skfd, ifname);
-
- close(skfd);
-
- if (retval == 2)
- printf("Could not determine status
");
- if (retval == 1)
- printf("Link down
");
- if (retval == 0)
- printf("Link up
");
-
- return retval;
- }
- 3:
- ******************************* 3*****************************************************
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define LINKTEST_GLINK 0x0000000a
-
- struct linktest_value {
- unsigned int cmd;
- unsigned int data;
- };
-
- static void usage(const char * pname)
- {
- fprintf(stderr, "usage: %s
" , pname);
- fprintf(stderr, "returns:
");
- fprintf(stderr, "\t 0: link detected
");
- fprintf(stderr, "\t%d: %s
", ENODEV, strerror(ENODEV));
- fprintf(stderr, "\t%d: %s
", ENONET, strerror(ENONET));
- fprintf(stderr, "\t%d: %s
", EOPNOTSUPP, strerror(EOPNOTSUPP));
- exit(EXIT_FAILURE);
- }
- static int linktest(const char * devname)
- {
- struct ifreq ifr;
- struct linktest_value edata;
- int fd;
- /* setup our control structures. */
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, devname);
- /* open control socket. */
- fd=socket(AF_INET, SOCK_DGRAM, 0);
- if(fd
- return -ECOMM;
-
- errno = 0;
- edata.cmd = LINKTEST_GLINK;
- ifr.ifr_data = (caddr_t)&edata;
-
- if(!ioctl(fd, SIOCETHTOOL, &ifr))
- {
- if(edata.data)
- {
- fprintf(stdout, "link detected on %s
", devname);
- return 0;
- }
- else
- {
- errno=ENONET;
- }
- }
- perror("linktest");
- return errno;
- }
- int main(int argc, char *argv[])
- {
- if(argc != 2)
- usage(argv[0]);
- return linktest(argv[1]);
- }
4:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define BASE_VALUE 257
-
- int main(int argc,char *argv[])
- {
- int mixer_fd=0;
- char *names[SOUND_MIXER_NRDEVICES]=SOUND_DEVICE_LABELS;
- int value,i;
-
- printf("
usage:%s dev_no.[0..24] value[0..100]
",argv[0]);
- printf("eg. %s 0 100
",argv[0]);
- printf("will change the volume to MAX volume.
");
- printf("The dev_no. are as below:
");
-
- for (i=0;i
- {
- if (i%3==0) printf("
");
- printf("%s:%d\t\t",names[i],i);
- }
-
- printf("
");
-
- if (argc<3) exit(1);
-
- if ((mixer_fd = open("/dev/mixer",O_RDWR)))
- {
- printf("Mixer opened successfully,working...
");
- value=BASE_VALUE*atoi(argv[2]);
-
- if (ioctl(mixer_fd,MIXER_WRITE(atoi(argv[1])),&value)==0)
- printf("successfully.....");
- else
- printf("unsuccessfully.....");
-
- printf("done.
");
- }
- else
- printf("can't open /dev/mixer error....
");
- exit(0);
- }