Raspberry PIのGPIOのデバイスドライバを作成します。「bcm2835 ライブラリによるスイッチ入力とLEDの点滅 」で使用したタクトスイッチから入力させます。

GPIOデバイスドライバ

GPIOポートに接続されたタクトスイッチから接点信号を入力するため、「Raspberry PIのGPIOのデバイスドライバ – Open 」で作成したデバイスドライバーのファイル操作構造体「file_operations」に、GPIOの読み込みデバイスドライバ関数「raspi_gpio_read」のアドレスと、GPIOの読み込みデバイスドライバ関数「raspi_gpio_read」を追加します。
デバイスのマイナー番号をGPIOポート番号とする設計ですが、今回は強制的にタクトスイッチから接点信号を入力するため、GPIOポート「24」とし、raspi_gpio_read関数の7行目に「gpio = 24;」を挿入しました。
raspi_gpio_read関数で使用しているgpio_direction_input関数とgpio_get_value関数について次に示します。

gpio_direction_input
入出力制御を入力側にする。
gpio_get_value
パラメータで指定されたGPIO番号から信号レベルを入力して戻り値で呼び出し元に通知する。

また、システム・コールの引数を、ユーザー空間に対して出し入れするために使用できる複数の関数が、用意されています。オプションには、基本型に対応した単純な関数 (get_user や put_user など) や、構造体や配列などのデータ・ブロックを移動させるための関数 (copy_from_user と copy_to_user) が含まれます。
今回使用するput_user 関数は、 呼び出し方法が「put_user(x,ptr);」となり、カーネル変数 (x) が指定する値を、指定されたユーザー空間アドレス (ptr) に移動させます。

ファイル操作構造体file_operations

1
2
3
4
5
6
7
/* File operation structure */
static struct file_operations raspi_gpio_fops = {
    .owner = THIS_MODULE,
    .open = raspi_gpio_open,
    .read = raspi_gpio_read,
    .write = raspi_gpio_write,
};

GPIOの読み込みデバイスドライバ関数raspi_gpio_read

1
2
3
4
5
6
7
8
9
10
11
static ssize_t
raspi_gpio_read ( struct file *filp,char *buf,size_t count,loff_t *f_pos){
    unsigned int gpio;
    char byte;
     
//  gpio = iminor(filp->f_path.dentry->d_inode);
    gpio = 24;
    byte = '0' + gpio_get_value(gpio);
    put_user(byte, buf);
    return 1;
}

GPIOの書き込みデバイスドライバ関数raspi_gpio_write

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static ssize_t raspi_gpio_write ( struct file *filp,
    const char *buf,
    size_t count,
    loff_t *f_pos)
{
 
    if (strcmp(kbuf, "in") == 0) {
        if (raspi_gpio_devp->dir != in) {
            printk(KERN_INFO "Set gpio[%d] direction: input\n", gpio);
            spin_lock_irqsave(&raspi_gpio_devp->lock, flags);
            gpio_direction_input(gpio);
            raspi_gpio_devp->dir = in;
            spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags);
        }
    } else {
               ・
               ・
               ・

ユーザープログラム

ユーザプログラムではWrite関数とread関数をそれぞれ1回づつ呼び出します。最初にGPIOからタクトスイッチのデータの入力するため、Write関数で”in”を書き込みます。次に、タクトスイッチから、read関数を用いてスイッチ情報を入力します。タクトスイッチを押してユーザープログラムを実行すると、レベル情報が「Logic level: 1」と表示されます。押さないでユーザープログラムを実行すると、レベル情報が「Logic level: 0」と表示されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
* Name : input_test.c
*/
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#define NUM_GPIO_PINS 21
#define MAX_GPIO_NUMBER 32
#define BUF_SIZE 3
#define PATH_SIZE 20
int main(int argc, char **argv)
{
    int i = 0, index = 0;
    int fd;
    char path[PATH_SIZE];
    char buf[BUF_SIZE];
    char readBuf[2];
     
    printf("gpio open\n");
    // Open all GPIO pins
    snprintf(path, sizeof(path), "/dev/raspiGpio0");
    fd = open(path, O_RDWR);
    if (fd < 0) {
        perror("Error opening GPIO pin");
        exit(EXIT_FAILURE);
    }
     
    // Set direction of GPIO pins to input
    printf("Set pins to input\n");
    strncpy(buf, "in", 2);
    buf[2] = '\0';
    if (write(fd, buf, sizeof(buf)) < 0) {
        perror("write, set pin input");
        exit(EXIT_FAILURE);
    }
     
    // Read logic level of GPIO pins and display them to the terminal
    printf("gpio read\n");
    if (read(fd, readBuf, 1) < 1) {
        perror("read");
        exit(EXIT_FAILURE);
    }
    readBuf[1] = '\0';
    printf("GPIO pin: 24 Logic level: %s\n", readBuf);
 
    return EXIT_SUCCESS;
}

実行したデバイスドライバのログを次に示します。

# dmesg
     ・
     ・
[ 2500.431564] GPIOstart open
[ 2500.431602] GPIO[0] opened
[ 2500.433749] Request from user: in
[ 2500.433788] Set gpio[24] direction: input

デバイスドライバのraspi_gpio_write関数により、”[ 2500.433788] Set gpio[24] direction: input”がログされており、GPIOポート24がin制御されていることが確認できます。

タクトスイッチを押さないでユーザープログラムを実行すると、次のように「Logic level: 0」が表示されます。

# ./input_test
gpio open
Set pins to input
gpio read
GPIO pin: 24 Logic level: 0

タクトスイッチを押してユーザープログラムを実行すると、次のように「Logic level: 1」が表示されます。

# ./input_test
gpio open
Set pins to input
gpio read
GPIO pin: 24 Logic level: 1