요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
============================================
Implementing I2C device drivers in userspace
============================================
Usually, I2C devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.
Each registered I2C adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formatted list of all
I2C adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.
I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
i2c-10, ...). All 256 minor device numbers are reserved for I2C.
C example
=========
So let's say you want to access an I2C adapter from a C program.
First, you need to include these two headers::
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.
Next thing, open the device file, as follows::
int file;
int adapter_nr = 2; /* probably dynamically determined */
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
When you have opened the device, you must specify with what device
address you want to communicate::
int addr = 0x40; /* The I2C address */
if (ioctl(file, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below::
__u8 reg = 0x10; /* Device register to access */
__s32 res;
char buf[10];
/* Using SMBus commands */
res = i2c_smbus_read_word_data(file, reg);
if (res < 0) {
/* ERROR HANDLING: I2C transaction failed */
} else {
/* res contains the read word */
}
/*
* Using I2C Write, equivalent of
* i2c_smbus_write_word_data(file, reg, 0x6543)
*/
buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
if (write(file, buf, 3) != 3) {
/* ERROR HANDLING: I2C transaction failed */
}
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
if (read(file, buf, 1) != 1) {
/* ERROR HANDLING: I2C transaction failed */
} else {
/* buf[0] contains the read byte */
}
Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.
IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!
Full interface description
==========================
The following IOCTLs are defined:
``ioctl(file, I2C_SLAVE, long addr)``
Change slave address. The address is passed in the 7 lower bits of the
argument (except for 10 bit addresses, passed in the 10 lower bits in this
case).
``ioctl(file, I2C_TENBIT, long select)``
Selects ten bit addresses if select not equals 0, selects normal 7 bit
addresses if select equals 0. Default 0. This request is only valid
if the adapter has I2C_FUNC_10BIT_ADDR.
``ioctl(file, I2C_PEC, long select)``
Selects SMBus PEC (packet error checking) generation and verification
if select not equals 0, disables if select equals 0. Default 0.
Used only for SMBus transactions. This request only has an effect if the
the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
doesn't have any effect.
``ioctl(file, I2C_FUNCS, unsigned long *funcs)``
Gets the adapter functionality and puts it in ``*funcs``.
``ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)``
Do combined read/write transaction without stop in between.
Only valid if the adapter has I2C_FUNC_I2C. The argument is
a pointer to a::
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
}
The msgs[] themselves contain further pointers into data buffers.
The function will write or read data to or from that buffers depending
on whether the I2C_M_RD flag is set in a particular message or not.
The slave address and whether to use ten bit address mode has to be
set in each message, overriding the values set with the above ioctl's.
``ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)``
If possible, use the provided ``i2c_smbus_*`` methods described below instead
of issuing direct ioctls.
You can do plain I2C transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.
You can do SMBus level transactions (see documentation file smbus-protocol.rst
for details) through the following functions::
__s32 i2c_smbus_write_quick(int file, __u8 value);
__s32 i2c_smbus_read_byte(int file);
__s32 i2c_smbus_write_byte(int file, __u8 value);
__s32 i2c_smbus_read_byte_data(int file, __u8 command);
__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
__s32 i2c_smbus_read_word_data(int file, __u8 command);
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
__u8 *values);
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
__u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.
The above functions are made available by linking against the libi2c library,
which is provided by the i2c-tools project. See:
https://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git/.
Implementation details
======================
For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:
1) Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.
2) These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.
3) Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)
4) Other ioctl() calls are converted to in-kernel function calls by
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
performs an SMBus transaction using i2c-core-smbus.c:i2c_smbus_xfer().
The i2c-dev driver is responsible for checking all the parameters that
come from user-space for validity. After this point, there is no
difference between these calls that came from user-space through i2c-dev
and calls that would have been performed by kernel I2C chip drivers
directly. This means that I2C bus drivers don't need to implement
anything special to support access from user-space.
5) These i2c.h functions are wrappers to the actual implementation of
your I2C bus driver. Each adapter must declare callback functions
implementing these standard calls. i2c.h:i2c_get_functionality() calls
i2c_adapter.algo->functionality(), while
i2c-core-smbus.c:i2c_smbus_xfer() calls either
adapter.algo->smbus_xfer() if it is implemented, or if not,
i2c-core-smbus.c:i2c_smbus_xfer_emulated() which in turn calls
i2c_adapter.algo->master_xfer().
After your I2C bus driver has processed these requests, execution runs
up the call chain, with almost no processing done, except by i2c-dev to
package the returned data, if any, in suitable format for the ioctl.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
사용자 공간 /dev 인터페이스
1-20일반적으로 I2C 장치는 커널 드라이버가 제어하지만, `i2c-dev` 모듈을 로드하면 `/dev` 인터페이스를 통해 사용자 공간에서도 어댑터의 모든 장치에 접근할 수 있습니다.
등록된 I2C 어댑터에는 0부터 번호가 붙습니다. `/sys/class/i2c-dev/`에서 번호와 어댑터의 대응을 확인하거나 i2c-tools 패키지의 `i2cdetect -l`로 현재 시스템의 모든 어댑터 목록을 형식화해 볼 수 있습니다.
I2C 장치 파일은 주 장치 번호 89를 사용하는 문자 장치이며 부 장치 번호는 어댑터 번호와 같습니다. 이름은 `i2c-%d`, 즉 `i2c-0`, `i2c-1`, `i2c-10` 형식이어야 합니다. 256개 부 장치 번호 전체가 I2C용으로 예약되어 있습니다.
어댑터 번호와 장치 파일 규칙을 정리합니다.
커널 어댑터가 i2c-dev 문자 장치로 노출되는 경로입니다.
============================================
Implementing I2C device drivers in userspace
============================================
Usually, I2C devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.
Each registered I2C adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formatted list of all
I2C adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.
I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
i2c-10, ...). All 256 minor device numbers are reserved for I2C.
C 프로그램의 어댑터 열기와 주소 설정
21-57C 프로그램에서 I2C 어댑터에 접근하려면 `<linux/i2c-dev.h>`와 `<i2c/smbus.h>` 헤더를 포함합니다.
사용할 어댑터는 `/sys/class/i2c-dev/` 또는 `i2cdetect -l`로 결정해야 합니다. 번호는 동적으로 할당되며 부팅할 때마다 바뀔 수도 있으므로 고정값이라고 가정해서는 안 됩니다.
예제는 `adapter_nr = 2`를 사용해 `snprintf(filename, 19, "/dev/i2c-%d", adapter_nr)`로 파일명을 만들고 `open(filename, O_RDWR)`로 엽니다. 실패하면 `errno`를 확인해 원인을 처리하고 종료합니다.
장치 파일을 연 다음 통신할 I2C 주소를 지정해야 합니다. 예제 주소는 `0x40`이며 `ioctl(file, I2C_SLAVE, addr)`로 설정합니다. 이 호출이 실패해도 `errno`를 확인해 처리합니다.
예제의 헤더, 파일, 주소 설정을 구조화했습니다.
동적 어댑터 번호를 찾은 뒤 파일과 슬레이브 주소를 차례로 설정합니다.
C example
=========
So let's say you want to access an I2C adapter from a C program.
First, you need to include these two headers::
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.
Next thing, open the device file, as follows::
int file;
int adapter_nr = 2; /* probably dynamically determined */
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
When you have opened the device, you must specify with what device
address you want to communicate::
int addr = 0x40; /* The I2C address */
if (ioctl(file, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
SMBus와 일반 I2C 전송 예제
58-101설정을 마치면 SMBus 명령 또는 일반 I2C로 장치와 통신할 수 있습니다. 장치가 SMBus를 지원한다면 SMBus 명령을 우선 사용하는 것이 좋습니다.
예제는 레지스터 `0x10`을 `i2c_smbus_read_word_data(file, reg)`로 읽습니다. 음수면 트랜잭션 실패이고, 성공하면 반환값 `res`에 읽은 워드가 들어 있습니다.
일반 I2C 쓰기 예제는 `i2c_smbus_write_word_data(file, reg, 0x6543)`와 같은 효과를 내기 위해 버퍼에 `reg`, `0x43`, `0x65`를 순서대로 넣고 `write(file, buf, 3)`가 3을 반환하는지 확인합니다.
일반 I2C 읽기 예제는 `i2c_smbus_read_byte(file)`와 같은 효과를 위해 `read(file, buf, 1)`을 호출하며, 성공하면 `buf[0]`에 읽은 바이트가 있습니다.
`read()`와 `write()`로 구현할 수 있는 I2C·SMBus 프로토콜은 일부뿐입니다. 특히 한 트랜잭션에서 읽기와 쓰기 메시지를 섞는 combined transaction을 지원하지 않으므로 사용자 공간 프로그램은 이 인터페이스를 거의 사용하지 않습니다.
SMBus 함수가 inline 함수이므로 프로그램을 컴파일할 때 반드시 `-O` 또는 다른 최적화 옵션을 사용해야 합니다.
SMBus helper와 일반 read/write의 대응 관계입니다.
장치 기능에 맞춰 SMBus helper 또는 I2C_RDWR를 선택합니다.
Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below::
__u8 reg = 0x10; /* Device register to access */
__s32 res;
char buf[10];
/* Using SMBus commands */
res = i2c_smbus_read_word_data(file, reg);
if (res < 0) {
/* ERROR HANDLING: I2C transaction failed */
} else {
/* res contains the read word */
}
/*
* Using I2C Write, equivalent of
* i2c_smbus_write_word_data(file, reg, 0x6543)
*/
buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
if (write(file, buf, 3) != 3) {
/* ERROR HANDLING: I2C transaction failed */
}
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
if (read(file, buf, 1) != 1) {
/* ERROR HANDLING: I2C transaction failed */
} else {
/* buf[0] contains the read byte */
}
Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.
IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!
전체 ioctl 인터페이스
102-146`ioctl(file, I2C_SLAVE, long addr)`는 슬레이브 주소를 바꿉니다. 일반 주소는 인자의 하위 7비트, 10비트 주소는 하위 10비트로 전달합니다.
`ioctl(file, I2C_TENBIT, long select)`는 `select != 0`이면 10비트, 0이면 일반 7비트 주소를 선택합니다. 기본값은 0이며 어댑터가 `I2C_FUNC_10BIT_ADDR`를 제공할 때만 유효합니다.
`ioctl(file, I2C_PEC, long select)`는 `select != 0`이면 SMBus PEC 생성·검증을 켜고 0이면 끕니다. 기본값은 0이고 SMBus 트랜잭션에만 사용합니다. `I2C_FUNC_SMBUS_PEC`가 있을 때만 효과가 있지만, 없어도 호출은 안전하며 아무 효과가 없습니다.
`ioctl(file, I2C_FUNCS, unsigned long *funcs)`는 어댑터 기능을 얻어 `*funcs`에 저장합니다.
`ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)`는 중간 STOP 없이 combined read/write 트랜잭션을 수행하며 `I2C_FUNC_I2C`가 있어야 합니다. 인자는 `struct i2c_msg *msgs`와 메시지 수 `int nmsgs`를 가진 구조체를 가리킵니다.
각 `msgs[]`는 데이터 버퍼를 가리키는 추가 포인터를 포함합니다. 메시지의 `I2C_M_RD` 플래그 유무에 따라 버퍼를 읽거나 씁니다. 슬레이브 주소와 10비트 주소 사용 여부는 메시지마다 설정해야 하며 앞선 ioctl 값보다 우선합니다.
`ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)`를 직접 호출하기보다 가능하면 아래의 `i2c_smbus_*` 메서드를 사용하십시오.
주소 모드, 기능 조회, 복합 전송과 SMBus 요청을 정리합니다.
메시지마다 주소·방향·버퍼를 독립적으로 지정합니다.
Full interface description
==========================
The following IOCTLs are defined:
``ioctl(file, I2C_SLAVE, long addr)``
Change slave address. The address is passed in the 7 lower bits of the
argument (except for 10 bit addresses, passed in the 10 lower bits in this
case).
``ioctl(file, I2C_TENBIT, long select)``
Selects ten bit addresses if select not equals 0, selects normal 7 bit
addresses if select equals 0. Default 0. This request is only valid
if the adapter has I2C_FUNC_10BIT_ADDR.
``ioctl(file, I2C_PEC, long select)``
Selects SMBus PEC (packet error checking) generation and verification
if select not equals 0, disables if select equals 0. Default 0.
Used only for SMBus transactions. This request only has an effect if the
the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
doesn't have any effect.
``ioctl(file, I2C_FUNCS, unsigned long *funcs)``
Gets the adapter functionality and puts it in ``*funcs``.
``ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)``
Do combined read/write transaction without stop in between.
Only valid if the adapter has I2C_FUNC_I2C. The argument is
a pointer to a::
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
}
The msgs[] themselves contain further pointers into data buffers.
The function will write or read data to or from that buffers depending
on whether the I2C_M_RD flag is set in a particular message or not.
The slave address and whether to use ten bit address mode has to be
set in each message, overriding the values set with the above ioctl's.
``ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)``
If possible, use the provided ``i2c_smbus_*`` methods described below instead
of issuing direct ioctls.
일반 I2C와 libi2c SMBus 함수
147-178일반 I2C 트랜잭션은 `read(2)`와 `write(2)`로 수행할 수 있습니다. 주소 바이트를 데이터에 넣지 말고 장치 접근 전에 `I2C_SLAVE` ioctl로 주소를 설정합니다.
SMBus 수준 트랜잭션의 자세한 프로토콜은 `smbus-protocol.rst`를 참조하십시오. 사용자 공간에서는 Quick, Byte, Byte Data, Word Data, Process Call, Block Process Call, Block Data 읽기·쓰기 함수를 사용할 수 있습니다.
모든 함수는 실패 시 -1을 반환하며 `errno`로 원인을 확인합니다. 쓰기 함수는 성공 시 0, 읽기 함수는 읽은 값을 반환합니다. 단 `read_block`은 읽은 값의 개수를 반환합니다. 블록 버퍼는 32바이트보다 길 필요가 없습니다.
이 함수들은 i2c-tools 프로젝트가 제공하는 `libi2c` 라이브러리에 링크하면 사용할 수 있습니다. 저장소는 `https://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git/`입니다.
원문에 선언된 사용자 공간 함수 11개를 모두 보존합니다.
전송 유형별 반환값을 해석합니다.
You can do plain I2C transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.
You can do SMBus level transactions (see documentation file smbus-protocol.rst
for details) through the following functions::
__s32 i2c_smbus_write_quick(int file, __u8 value);
__s32 i2c_smbus_read_byte(int file);
__s32 i2c_smbus_write_byte(int file, __u8 value);
__s32 i2c_smbus_read_byte_data(int file, __u8 command);
__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
__s32 i2c_smbus_read_word_data(int file, __u8 command);
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
__u8 *values);
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
__u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.
The above functions are made available by linking against the libi2c library,
which is provided by the i2c-tools project. See:
https://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git/.
커널 내부 호출 흐름
179-221사용자 프로그램은 `/dev/i2c-N`을 열고 앞의 C 예제처럼 `ioctl()`을 호출합니다.
`open()`과 `ioctl()`은 각각 `i2c-dev.c:i2cdev_open()`과 `i2c-dev.c:i2cdev_ioctl()`이 처리합니다. `i2c-dev`는 사용자 공간에서 프로그래밍할 수 있는 범용 I2C 칩 드라이버로 생각할 수 있습니다.
일부 ioctl은 관리 작업이므로 i2c-dev가 직접 처리합니다. 예를 들어 `I2C_SLAVE`는 접근할 장치 주소를 설정하고 `I2C_PEC`는 이후 SMBus 트랜잭션의 오류 검사를 켜거나 끕니다.
다른 ioctl은 i2c-dev가 커널 내부 함수 호출로 변환합니다. `I2C_FUNCS`는 `i2c.h:i2c_get_functionality()`로 어댑터 기능을 조회하고, `I2C_SMBUS`는 `i2c-core-smbus.c:i2c_smbus_xfer()`로 SMBus 트랜잭션을 수행합니다.
i2c-dev는 사용자 공간에서 온 모든 매개변수의 유효성을 검사합니다. 그 뒤에는 i2c-dev를 거친 호출과 커널 I2C 칩 드라이버가 직접 수행한 호출 사이에 차이가 없습니다. 따라서 I2C 버스 드라이버는 사용자 공간 접근을 위해 별도 기능을 구현할 필요가 없습니다.
이 `i2c.h` 함수들은 실제 버스 드라이버 구현의 wrapper입니다. 각 어댑터는 표준 호출의 callback을 선언해야 합니다. `i2c_get_functionality()`는 `i2c_adapter.algo->functionality()`를 호출합니다.
`i2c_smbus_xfer()`는 구현되어 있으면 `adapter.algo->smbus_xfer()`를 호출합니다. 없으면 `i2c_smbus_xfer_emulated()`가 `i2c_adapter.algo->master_xfer()`를 호출해 에뮬레이션합니다.
버스 드라이버가 요청을 처리한 뒤 실행은 호출 사슬을 거슬러 올라갑니다. 반환 데이터가 있으면 i2c-dev가 ioctl에 맞는 형식으로 포장하는 것 외에는 거의 처리하지 않습니다.
사용자 호출과 커널 callback의 대응을 정리합니다.
i2c-dev가 매개변수를 검증한 뒤 표준 커널 호출로 변환합니다.
Implementation details
======================
For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:
1) Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.
2) These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.
3) Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)
4) Other ioctl() calls are converted to in-kernel function calls by
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
performs an SMBus transaction using i2c-core-smbus.c:i2c_smbus_xfer().
The i2c-dev driver is responsible for checking all the parameters that
come from user-space for validity. After this point, there is no
difference between these calls that came from user-space through i2c-dev
and calls that would have been performed by kernel I2C chip drivers
directly. This means that I2C bus drivers don't need to implement
anything special to support access from user-space.
5) These i2c.h functions are wrappers to the actual implementation of
your I2C bus driver. Each adapter must declare callback functions
implementing these standard calls. i2c.h:i2c_get_functionality() calls
i2c_adapter.algo->functionality(), while
i2c-core-smbus.c:i2c_smbus_xfer() calls either
adapter.algo->smbus_xfer() if it is implemented, or if not,
i2c-core-smbus.c:i2c_smbus_xfer_emulated() which in turn calls
i2c_adapter.algo->master_xfer().
After your I2C bus driver has processed these requests, execution runs
up the call chain, with almost no processing done, except by i2c-dev to
package the returned data, if any, in suitable format for the ioctl.
요약·해설
dev-interface.rst:1-221사용자 프로그램은 동적으로 어댑터 번호를 찾고 `/dev/i2c-N`을 연 뒤 주소와 기능을 ioctl로 설정하며, i2c-dev는 요청을 검증해 표준 버스 callback으로 전달합니다.
원문 분량과 핵심 기능을 요약합니다.
호출 또는 판단의 핵심 순서입니다.