指摘したとおりこの問題ioctl
、Linuxカーネルモジュールの関数プロトタイプは次のとおりです。
(バージョン1)
int ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg);
または
(バージョン2)
long ioctl(struct file *f, unsigned int cmd, unsigned long arg);
文字デバイスドライバを実装するカーネルモジュールで使用したいと思います。
- 上記の両方のタイプがこの状況に適していますか?では、なぜそうなのでしょうか?そうでなければ正しいものを選ぶ方法は?
- これらのプロトタイプを含むヘッダー/ソースファイルは何ですか?つまり、これらのプロトタイプの公式参照文書は何ですか?
私はUbuntu 20.04を実行していますx86_64
が、次は私が使用できるヘッダーファイルです。
/usr/include/asm-generic/ioctl.h
/usr/include/linux/ioctl.h
/usr/include/linux/mmc/ioctl.h
/usr/include/linux/hdlc/ioctl.h
/usr/include/x86_64-linux-gnu/sys/ioctl.h
/usr/include/x86_64-linux-gnu/asm/ioctl.h
唯一重要な行は次のとおりです/usr/include/x86_64-linux-gnu/sys/ioctl.h
。
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
しかし、ここでは、上記の2つの代替プロトタイプのどの手がかりも見つかりません。
ベストアンサー1
さまざまなコンテキストで定義された関数を見ています。 3番目:
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
はシステムコール (つまり、ユーザー空間からカーネル空間への呼び出し)
他のものはカーネルで定義されている関数のように見えます(struct file
どちらstruct inode
もカーネルデータ構造です)。
一部のユーザー空間プログラムでシステムコールを呼び出すと
+-------------------+
| userspace program |
+-------------------+
|
ioctl(fd, requestType, arg);
|
| userspace
-------------------------------------------------------------------
| kernelspace
v
SYSCALL_DEFINE3(ioctl...) /* ${kernel_root}/fs/ioctl.c */
|
v
do_vfs_ioctl(...)
|
/*
look at fd, map it to the device driver. Call the ioctl
registered for that device type.
for example: drivers/char/random.c:
const struct file_operations random_fops = {
...
.unlocked_ioctl = random_ioctl,
...
};
|
V
static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
なぜいくつかstruct file
とは違うのですstruct inode
か?わかりませんが、指定されたファイル記述子(システムコールの引数)に関連fd
するデバイスの種類によって異なります。 VFS層は、さまざまな種類の登録済みドライバに渡すことができます。たとえば、デバイスドライバは.を使用し、struct file
ファイルシステムドライバはstruct inode
.
編集する
あなたの質問どのように書くのですか?特徴システムコールをサポートするデバイスドライバioctl
?、以下は簡単な例です。
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
static int example_device_major_number;
static const char example_device_name[] = "example-driver";
#define LOG(fmt, ...) printk(KERN_NOTICE "%s[%s:%d]: " fmt "\n", example_device_name, __FUNCTION__, __LINE__, ##__VA_ARGS__)
static long example_module_ioctl(struct file *, unsigned int cmd, unsigned long arg)
{
LOG("cmd: %d, arg: %lu", cmd, arg);
return 0;
}
static struct file_operations example_module_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = example_module_ioctl,
};
static int example_module_init(void)
{
int result = 0;
result = register_chrdev(0, example_device_name, &example_module_fops);
if (result < 0)
{
LOG("Can't register character device with error code = %d", result);
return result;
}
example_device_major_number = result;
LOG("Registered character device with major number = %d", example_device_major_number);
return 0;
}
static void example_module_exit(void)
{
if (example_device_major_number != 0)
{
unregister_chrdev(example_device_major_number, example_device_name);
}
LOG("Module removed");
}
module_init(example_module_init);
module_exit(example_module_exit);
MODULE_LICENSE("GPL");
モジュールをコンパイルしてロードすると、出力に次のものが表示されますdmesg
。
[1325403.600381] example-driver[example_module_init:35]: Registered character device with major number = 238
ここでは、カーネルが新しく追加された文字デバイスドライバに238という主要なデバイス番号を割り当てたことがわかります。
これで、対応するメジャー番号を使用して文字デバイスファイルを作成できます。
$ sudo mknod mydevice c 238 0
$ ls -l mydevice
crw-r--r-- 1 root root 238, 0 Nov 26 17:03 mydevice
次に、(1)装置ファイルを開き、(2)ioctl()
結果ファイル記述子を呼び出すユーザ空間プログラムを作成することができる。
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main(void)
{
int fd = open("mydevice", O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
int rc = ioctl(fd, 1, 2);
if (rc < 0) {
perror("ioctl");
}
(void) close(fd);
return 0;
}
以前にロードされたモジュールを使用してユーザー空間アプリケーションをコンパイルして実行すると、出力に次のものが表示されます。dmesg
[1325593.158303] example-driver[example_module_ioctl:12]: cmd: 1, arg: 2