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

GPIOデバイスドライバ

GPIOポートに接続されたLEDを点灯するため、「Raspberry PIのGPIOのデバイスドライバ – Open 」で作成したデバイスドライのファイル操作構造体「file_operations」に、GPIOの書き込みデバイスドライバ関数「raspi_gpio_write」のアドレスと、GPIOの書き込みデバイスドライバ関数「raspi_gpio_write」を追加します。
デバイスのマイナー番号をGPIOポート番号とする設計ですが、今回は強制的にLEDを点灯させるため、GPIOポート「25」とし、 raspi_gpio_write関数の17行目に「gpio = 25;」を挿入しました。
raspi_gpio_write関数で使用しているgpio_direction_output関数とgpio_set_value関数について次に示します。

gpio_direction_output
入出力制御を出力側にする
gpio_set_value
パラメータで指定されたGPIO番号に対して指定された値を出力する
/* File operation structure */
static struct file_operations raspi_gpio_fops = {
	.owner = THIS_MODULE,
	.open = raspi_gpio_open,
	.write = raspi_gpio_write,
};
static ssize_t raspi_gpio_write ( struct file *filp,
	const char *buf,
	size_t count,
	loff_t *f_pos)
{
	unsigned int gpio, len = 0, value = 0;
	char kbuf[BUF_SIZE];
	struct raspi_gpio_dev *raspi_gpio_devp = filp->private_data;
	unsigned long flags;
//	gpio = iminor(filp->f_path.dentry->d_inode);
	gpio = 25;
	len = count < BUF_SIZE ? count-1 : BUF_SIZE-1;
	if(copy_from_user(kbuf, buf, len) != 0)
	return -EFAULT;
	kbuf[len] = '\0';
	printk(KERN_INFO "Request from user: %s\n", kbuf);
	// Check the content of kbuf and set GPIO pin accordingly
	if (strcmp(kbuf, "out") == 0) {
		printk(KERN_ALERT "gpio[%d] direction set to ouput\n", gpio); 
		if (raspi_gpio_devp->dir != out) {
			spin_lock_irqsave(&raspi_gpio_devp->lock, flags);
			gpio_direction_output(gpio, low);
			raspi_gpio_devp->dir = out;
			raspi_gpio_devp->state = low;
			spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags);
		}
	} else if ((strcmp(kbuf, "1") == 0) || (strcmp(kbuf, "0") == 0)) {
		sscanf(kbuf, "%d", &value);
		if (raspi_gpio_devp->dir == in) {
			printk("Cannot set GPIO %d, direction: input\n", gpio);
			return -EPERM;
		}
		if (raspi_gpio_devp->dir == out) {
			if (value > 0) {
				spin_lock_irqsave(&raspi_gpio_devp->lock, flags);
				gpio_set_value(gpio, high);
				raspi_gpio_devp->state = high;
				spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags);
			} else {
				spin_lock_irqsave(&raspi_gpio_devp->lock, flags);
				gpio_set_value(gpio, low);
				raspi_gpio_devp->state = low;
				spin_unlock_irqrestore(&raspi_gpio_devp->lock, flags);
			}
		}
	} else {
		printk(KERN_ERR "Invalid value\n");
		return -EINVAL;
	}
	*f_pos += count;
	return count;
}

ユーザープログラム

ユーザプログラムではWrite関数は2回呼び出します。最初にGPIOに出力してLEDを制御するため、Write関数で”out”を書き込みます。次に、LEDの点灯/消灯を指示します。点灯するか消灯するかは、ユーザープログラムの実行時のパラメータに従います。「1」の場合LEDの点灯、「0」の時LEDの消灯とし、Write関数で文字列のパラメータで与えます。

/*
* Name : output_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 4
#define PATH_SIZE 20
int main(int argc, char **argv)
{
	int i = 0, index = 0, value;
	int fd;
	char path[PATH_SIZE];
	char buf[BUF_SIZE];
	
	if (argc != 2) {
		printf("Option low/high must be used\n");
		exit(EXIT_FAILURE);
	}
	// Open all GPIO pins
	snprintf(path, sizeof(path), "/dev/raspiGpio0");
	fd = open(path, O_WRONLY);
	if (fd < 0) {
		perror("Error opening GPIO");
		exit(EXIT_FAILURE);
	}
	// Set direction of GPIO pins to output
	printf("Set GPIO pins to output, logic level :%s\n", argv[1]);
	strncpy(buf, "out", 3);
	buf[3] = '\0';
	if (write(fd, buf, sizeof(buf)) < 0) {
		perror("write, set pin output");
		exit(EXIT_FAILURE);
	}
	// Set logic state of GPIO pins low/high
	value = atoi(argv[1]);
	if (value == 1) {
		strncpy(buf, "1", 1);
		buf[1] = '\0';
	} else if (value == 0) {
		strncpy(buf, "0", 1);
		buf[1] = '\0';
	} else {
		printf("Invalid logic value\n");
		exit(EXIT_FAILURE);
	}
	if (write(fd, buf, sizeof(buf)) < 0) {
		perror("write, set GPIO state of GPIO pins");
		exit(EXIT_FAILURE);
	}
	return EXIT_SUCCESS;
}

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

# dmesg
     ・
     ・
     ・
[ 1204.497443] start gpio_init
[ 1204.502487] RaspberryPi GPIO driver initialized
[ 1625.097917] GPIOstart open
[ 1625.097958] GPIO[0] opened
[ 1625.099254] Request from user: out
[ 1625.099559] gpio[25] direction set to ouput
[ 1625.112248] Request from user: 1

デバイスドライバのraspi_gpio_write関数により、”[ 1625.099559] gpio[25] direction set to ouput”がログされており、GPIOポート25に出力されていいることが確認できます。

実行時のパラメータを次のように与えるとLEDが点灯します。

# ./output_test 1

実行時のパラメータを次のように与えるとLEDが消灯します。
# ./output_test 0