8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Golangでioctlのシステムコールを使う

Posted at

組み込みLinuxでGolangを使っていると、ioctlのシステムコールを使用したい場面が出てきます。ioctlは汎用的で使用する場面によって異なるストラクチャを使用します。
Golangでカーネルの定義するストラクチャに値をセットする場合、以下の2つの方法があります。

  1. cgoを使ってカーネルのヘッダをインクルードする。
  2. Golangでメモリレイアウトが等価になるようなstructを定義して使用する。

今回は2の方法を試してみました。

i2cのioctlで使用されていたstruct

/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
	struct i2c_msg __user *msgs;	/* pointers to i2c_msgs */
	__u32 nmsgs;			/* number of i2c_msgs */
};
struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
#define I2C_M_16BIT_REG		0x0002	/* indicate reg bit-width is 16bit */
#define I2C_M_16BIT_DATA	0x0008	/* indicate data bit-width is 16bit */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};

この2つのstructとメモリレイアウトが等価になるようなGoのstructを定義して使用しました。

#Golangのサンプルプログラム

const (
	_I2C_RDWR                = 0x0707
	_I2C_RDRW_IOCTL_MAX_MSGS = 42
	_I2C_M_RD                = 0x0001
)

type i2c_msg struct {
	addr      uint16
	flags     uint16
	len       uint16
	__padding uint16
	buf       uintptr
}

type i2c_rdwr_ioctl_data struct {
	msgs  uintptr
	nmsgs uint32
}

func transfer(f *os.File, msgs *i2c_msg, n int) (err error) {
	data := i2c_rdwr_ioctl_data{
		msgs:  uintptr(unsafe.Pointer(msgs)),
		nmsgs: uint32(n),
	}
	err = nil
	_, _, errno := syscall.Syscall(
		syscall.SYS_IOCTL,
		uintptr(f.Fd()),
		uintptr(_I2C_RDWR),
		uintptr(unsafe.Pointer(&data)),
	)
	if (errno != 0) {
		err = errno
	}
	return
}

これの全ソースコードはgistに貼りました。ここ

#余談
今回使用したSoCのi2cドライバが特殊なようで、一般のi2c用のダンプコマンド等が使用で来ませんでした。よって世の中にあるいくつかのgolangのi2c用ライブラリも使えませんでした。
SoCのSDKに付属するi2cツールで使っているシステムコールをstraceで観察し、それと同様の動きをするものをgolangで書きました。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?