はじめに
前章の内容でデバイスドライバを通してハードウェアを制御する為のインターフェースが、準備できました。本章では、ドライバのインターフェースを通した上位層からの制御について説明します。基本的には7章で説明したsysfs、devtmpfsのファイルに対してシステムコールを呼び出すことで、準備したインターフェースを呼び出します。
システムコールについて
システムコールとは、Linuxカーネルが提供するプログラムインターフェースで、アプリケーション等のユーザーランド層から、カーネル層の機能にアクセスする為の仕組みです。今までは、Linuxカーネルから呼び出す関数を説明してきましたが、本章はアプリケーションから呼び出す関数の説明になります。ここでの、アプリケーションはprintfを用いて「Hello, world!
」を出力するようなプログラムを示しています。
主要なシステムコールには、以下のようなものがあります。
#include <fcntl.h>
int open(const char *pathname, int flags);
ファイルを開くシステムコールです。第1引数のpathnameのファイルを開き、ファイルディスクリプタを返します。第2引数のflagsには、アクセスモード O_RDONLY, O_WRONLY, O_RDWR等を指定します。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ファイルの読み書きをするシステムコールです。第1引数のfdはopenの戻り値であるファイルディスクリプタを、第2引数のbufは読み書きをするバッファーを、第3引数のcountには読み書きをする最大バイト数を指定します。
7.1 sysfs で説明しましたが、近接照度センサドライバは、ltr578_attr_listに登録されている
static DRIVER_ATTR(alstest, S_IWUSR | S_IRUGO, ltr578_show_als, NULL);
を元にdriver_create_fileを呼び出すことで、
/sys/bus/platform/drivers/als_ps/alstest
を作成していました。
このファイルに対して、openとreadのシステムコールを呼び出すことによって、ファイルが読み込みされた時に呼ばれるコールバック関数として登録していた、ltr578_show_alsが呼び出されます。更に、ltr578_show_alsからltr578_als_readが呼び出され、ltr578_master_recv(client, LTR578_ALS_DATA_0, buf, 0x03)が呼び出され、最終的にはltr578_i2c_read_block(client, addr, buf, count)が呼ばれて、実際のデバイスに存在するALS_DATAレジスタにアクセスできます。
その他主要なシステムコールに
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
があります。こちらは、基本的にdevtmpfs上のファイルに対して呼び出すシステムコールであり、単純なread/writeでは実現できない制御を実装できます。miscデバイス登録する関数であるmisc_registerを呼び出す引数として、コールバック関数を登録するfile_operations構造体に以下を入れてました。
static const struct file_operations ltr578_fops = {
.owner = THIS_MODULE,
.open = ltr578_open,
.release = ltr578_release,
.unlocked_ioctl = ltr578_unlocked_ioctl,
};
この、unlocked_ioctlに指定しているltr578_unlocked_ioctrlに繋がるのが、ioctlシステムコールです。ltr578_unlocked_ioctrlは、以下のように定義されてます。
kernel/mediatek/4.4/drivers/misc/mediatek/sensors-1.0/alsps/ltr578/ltr578.c
static long ltr578_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ioctrlシステムコールは例えば以下のように、この内容と合わせて呼び出す必要があります。
ioctl(fd, ALSPS_SET_PS_MODE, arg)
ALSPS_SET_PS_MODEは、カーネルの中では、 kernel/mediatek/4.4/drivers/misc/mediatek/sensors-1.0/hwmon/include/sensors_io.h
で定義されていますが、アプリケーションからは参照できないので、同じ値を別ファイルに定義することが基本的に必要になります。
ioctrlシステムコールを呼び出すことで、コールバック関数として登録していた、ltr578_unlocked_ioctlが呼び出され、ALSPS_SET_PS_MODEの値に基づき処理をすることができます。
最後に
ioctlとdevtmpfsの時に、記載したfile_operations構造体には、これ以外にreadやwriteも指定でき、read/writeシステムコールが呼ばれた際の制御も記載可能です。また、openに登録しているコールバック関数はopenシステムコールが呼ばれた際に呼び出されます。read/writeについては、Linuxのコマンドによるcatやechoによって、処理を呼び出すことが可能です。
C言語標準でfopenといった、プラットフォームに依存しないファイル制御関数もあります。Linuxではこちらを呼んでも内部的にはopenシステムコールに繋がります。ただ、ioctl等は呼べませんし、sysfsやdevtmpfsにアクセスする時点で、OS依存の処理なので、sysfsやdevtmpfsを制御する際には、Linuxのシステムコールを使うことをお勧めします。
記載しているシステムコールの詳細、その他のシステムコールについては、 https://linuxjm.osdn.jp/html/LDP_man-pages/man2/syscalls.2.html を参照して下さい。
コメント