← Documents Documentation/input/joydev/joystick-api.rst GitHub 원문 ↗

Linux 6.18.37 · Input

Linux Joystick Programming Interface

Legacy joydev js_event 형식, read queue, ioctl과 v0.x 호환 API를 설명합니다.

Source pathDocumentation/input/joydev/joystick-api.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

joystick-api.rst:1-348

새 client에는 evdev가 권장되지만, 이 문서는 `/dev/input/jsN`의 v1.x 변화 event와 v0.x polling 호환 형식을 정확히 다룹니다. Open 직후 초기 상태, event bit와 값, queue overflow 재동기화, capability·correction ioctl을 중심으로 읽어야 합니다.

문서 개요
영역핵심 API·symbol
Open`/dev/input/js0`, `JS_EVENT_INIT`
Event`struct js_event`
Type`JS_EVENT_BUTTON`, `JS_EVENT_AXIS`
ReadBlocking, `select()`, `O_NONBLOCK`
Queue 복구Overflow 뒤 합성 INIT event
Capability`JSIOCGAXES`, `JSIOCGBUTTONS`, `JSIOCGVERSION`
Calibration`JSIOC[SG]CORR`, `struct js_corr`
Legacy`struct JS_DATA_TYPE`, `JS_RETURN`

Joydev client 구현의 핵심 단계입니다.

Joydev client 처리
Joystick node open`JS_EVENT_INIT`으로 전체 상태 초기화Blocking·select·nonblocking 방식 선택Queue가 빌 때까지 event 읽기INIT flag를 제거하고 value 기반 절대 상태 적용Overflow 뒤 합성 INIT event로 재동기화

Open부터 초기화, queue drain과 event 적용까지의 안전한 경로입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. _joystick-api:
2
3 =====================
4 Programming Interface
5 =====================
6
7 :Author: Ragnar Hojland Espinosa <[email protected]> - 7 Aug 1998
8
9 Introduction
10 ============
11
12 .. important::
13 This document describes legacy ``js`` interface. Newer clients are
14 encouraged to switch to the generic event (``evdev``) interface.
15
16 The 1.0 driver uses a new, event based approach to the joystick driver.
17 Instead of the user program polling for the joystick values, the joystick
18 driver now reports only any changes of its state. See joystick-api.txt,
19 joystick.h and jstest.c included in the joystick package for more
20 information. The joystick device can be used in either blocking or
21 nonblocking mode, and supports select() calls.
22
23 For backward compatibility the old (v0.x) interface is still included.
24 Any call to the joystick driver using the old interface will return values
25 that are compatible to the old interface. This interface is still limited
26 to 2 axes, and applications using it usually decode only 2 buttons, although
27 the driver provides up to 32.
28
29 Initialization
30 ==============
31
32 Open the joystick device following the usual semantics (that is, with open).
33 Since the driver now reports events instead of polling for changes,
34 immediately after the open it will issue a series of synthetic events
35 (JS_EVENT_INIT) that you can read to obtain the initial state of the
36 joystick.
37
38 By default, the device is opened in blocking mode::
39
40 int fd = open ("/dev/input/js0", O_RDONLY);
41
42
43 Event Reading
44 =============
45
46 ::
47
48 struct js_event e;
49 read (fd, &e, sizeof(e));
50
51 where js_event is defined as::
52
53 struct js_event {
54 __u32 time; /* event timestamp in milliseconds */
55 __s16 value; /* value */
56 __u8 type; /* event type */
57 __u8 number; /* axis/button number */
58 };
59
60 If the read is successful, it will return sizeof(e), unless you wanted to read
61 more than one event per read as described in section 3.1.
62
63
64 js_event.type
65 -------------
66
67 The possible values of ``type`` are::
68
69 #define JS_EVENT_BUTTON 0x01 /* button pressed/released */
70 #define JS_EVENT_AXIS 0x02 /* joystick moved */
71 #define JS_EVENT_INIT 0x80 /* initial state of device */
72
73 As mentioned above, the driver will issue synthetic JS_EVENT_INIT ORed
74 events on open. That is, if it's issuing an INIT BUTTON event, the
75 current type value will be::
76
77 int type = JS_EVENT_BUTTON | JS_EVENT_INIT; /* 0x81 */
78
79 If you choose not to differentiate between synthetic or real events
80 you can turn off the JS_EVENT_INIT bits::
81
82 type &= ~JS_EVENT_INIT; /* 0x01 */
83
84
85 js_event.number
86 ---------------
87
88 The values of ``number`` correspond to the axis or button that
89 generated the event. Note that they carry separate numeration (that
90 is, you have both an axis 0 and a button 0). Generally,
91
92 =============== =======
93 Axis number
94 =============== =======
95 1st Axis X 0
96 1st Axis Y 1
97 2nd Axis X 2
98 2nd Axis Y 3
99 ...and so on
100 =============== =======
101
102 Hats vary from one joystick type to another. Some can be moved in 8
103 directions, some only in 4. The driver, however, always reports a hat as two
104 independent axes, even if the hardware doesn't allow independent movement.
105
106
107 js_event.value
108 --------------
109
110 For an axis, ``value`` is a signed integer between -32767 and +32767
111 representing the position of the joystick along that axis. If you
112 don't read a 0 when the joystick is ``dead``, or if it doesn't span the
113 full range, you should recalibrate it (with, for example, jscal).
114
115 For a button, ``value`` for a press button event is 1 and for a release
116 button event is 0.
117
118 Though this::
119
120 if (js_event.type == JS_EVENT_BUTTON) {
121 buttons_state ^= (1 << js_event.number);
122 }
123
124 may work well if you handle JS_EVENT_INIT events separately,
125
126 ::
127
128 if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
129 if (js_event.value)
130 buttons_state |= (1 << js_event.number);
131 else
132 buttons_state &= ~(1 << js_event.number);
133 }
134
135 is much safer since it can't lose sync with the driver. As you would
136 have to write a separate handler for JS_EVENT_INIT events in the first
137 snippet, this ends up being shorter.
138
139
140 js_event.time
141 -------------
142
143 The time an event was generated is stored in ``js_event.time``. It's a time
144 in milliseconds since ... well, since sometime in the past. This eases the
145 task of detecting double clicks, figuring out if movement of axis and button
146 presses happened at the same time, and similar.
147
148
149 Reading
150 =======
151
152 If you open the device in blocking mode, a read will block (that is,
153 wait) forever until an event is generated and effectively read. There
154 are two alternatives if you can't afford to wait forever (which is,
155 admittedly, a long time;)
156
157 a) use select to wait until there's data to be read on fd, or
158 until it timeouts. There's a good example on the select(2)
159 man page.
160
161 b) open the device in non-blocking mode (O_NONBLOCK)
162
163
164 O_NONBLOCK
165 ----------
166
167 If read returns -1 when reading in O_NONBLOCK mode, this isn't
168 necessarily a "real" error (check errno(3)); it can just mean there
169 are no events pending to be read on the driver queue. You should read
170 all events on the queue (that is, until you get a -1).
171
172 For example,
173
174 ::
175
176 while (1) {
177 while (read (fd, &e, sizeof(e)) > 0) {
178 process_event (e);
179 }
180 /* EAGAIN is returned when the queue is empty */
181 if (errno != EAGAIN) {
182 /* error */
183 }
184 /* do something interesting with processed events */
185 }
186
187 One reason for emptying the queue is that if it gets full you'll start
188 missing events since the queue is finite, and older events will get
189 overwritten.
190
191 The other reason is that you want to know all that happened, and not
192 delay the processing till later.
193
194 Why can the queue get full? Because you don't empty the queue as
195 mentioned, or because too much time elapses from one read to another
196 and too many events to store in the queue get generated. Note that
197 high system load may contribute to space those reads even more.
198
199 If time between reads is enough to fill the queue and lose an event,
200 the driver will switch to startup mode and next time you read it,
201 synthetic events (JS_EVENT_INIT) will be generated to inform you of
202 the actual state of the joystick.
203
204
205 .. note::
206
207 As of version 1.2.8, the queue is circular and able to hold 64
208 events. You can increment this size bumping up JS_BUFF_SIZE in
209 joystick.h and recompiling the driver.
210
211
212 In the above code, you might as well want to read more than one event
213 at a time using the typical read(2) functionality. For that, you would
214 replace the read above with something like::
215
216 struct js_event mybuffer[0xff];
217 int i = read (fd, mybuffer, sizeof(mybuffer));
218
219 In this case, read would return -1 if the queue was empty, or some
220 other value in which the number of events read would be i /
221 sizeof(js_event) Again, if the buffer was full, it's a good idea to
222 process the events and keep reading it until you empty the driver queue.
223
224
225 IOCTLs
226 ======
227
228 The joystick driver defines the following ioctl(2) operations::
229
230 /* function 3rd arg */
231 #define JSIOCGAXES /* get number of axes char */
232 #define JSIOCGBUTTONS /* get number of buttons char */
233 #define JSIOCGVERSION /* get driver version int */
234 #define JSIOCGNAME(len) /* get identifier string char */
235 #define JSIOCSCORR /* set correction values &js_corr */
236 #define JSIOCGCORR /* get correction values &js_corr */
237
238 For example, to read the number of axes::
239
240 char number_of_axes;
241 ioctl (fd, JSIOCGAXES, &number_of_axes);
242
243
244 JSIOGCVERSION
245 -------------
246
247 JSIOGCVERSION is a good way to check in run-time whether the running
248 driver is 1.0+ and supports the event interface. If it is not, the
249 IOCTL will fail. For a compile-time decision, you can test the
250 JS_VERSION symbol::
251
252 #ifdef JS_VERSION
253 #if JS_VERSION > 0xsomething
254
255
256 JSIOCGNAME
257 ----------
258
259 JSIOCGNAME(len) allows you to get the name string of the joystick - the same
260 as is being printed at boot time. The 'len' argument is the length of the
261 buffer provided by the application asking for the name. It is used to avoid
262 possible overrun should the name be too long::
263
264 char name[128];
265 if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
266 strscpy(name, "Unknown", sizeof(name));
267 printf("Name: %s\n", name);
268
269
270 JSIOC[SG]CORR
271 -------------
272
273 For usage on JSIOC[SG]CORR I suggest you to look into jscal.c They are
274 not needed in a normal program, only in joystick calibration software
275 such as jscal or kcmjoy. These IOCTLs and data types aren't considered
276 to be in the stable part of the API, and therefore may change without
277 warning in following releases of the driver.
278
279 Both JSIOCSCORR and JSIOCGCORR expect &js_corr to be able to hold
280 information for all axes. That is, struct js_corr corr[MAX_AXIS];
281
282 struct js_corr is defined as::
283
284 struct js_corr {
285 __s32 coef[8];
286 __u16 prec;
287 __u16 type;
288 };
289
290 and ``type``::
291
292 #define JS_CORR_NONE 0x00 /* returns raw values */
293 #define JS_CORR_BROKEN 0x01 /* broken line */
294
295
296 Backward compatibility
297 ======================
298
299 The 0.x joystick driver API is quite limited and its usage is deprecated.
300 The driver offers backward compatibility, though. Here's a quick summary::
301
302 struct JS_DATA_TYPE js;
303 while (1) {
304 if (read (fd, &js, JS_RETURN) != JS_RETURN) {
305 /* error */
306 }
307 usleep (1000);
308 }
309
310 As you can figure out from the example, the read returns immediately,
311 with the actual state of the joystick::
312
313 struct JS_DATA_TYPE {
314 int buttons; /* immediate button state */
315 int x; /* immediate x axis value */
316 int y; /* immediate y axis value */
317 };
318
319 and JS_RETURN is defined as::
320
321 #define JS_RETURN sizeof(struct JS_DATA_TYPE)
322
323 To test the state of the buttons,
324
325 ::
326
327 first_button_state = js.buttons & 1;
328 second_button_state = js.buttons & 2;
329
330 The axis values do not have a defined range in the original 0.x driver,
331 except that the values are non-negative. The 1.2.8+ drivers use a
332 fixed range for reporting the values, 1 being the minimum, 128 the
333 center, and 255 maximum value.
334
335 The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
336 called Multisystem joysticks in this driver), under /dev/djsX. This driver
337 doesn't try to be compatible with that interface.
338
339
340 Final Notes
341 ===========
342
343 ::
344
345 ____/| Comments, additions, and specially corrections are welcome.
346 \ o.O| Documentation valid for at least version 1.2.8 of the joystick
347 =(_)= driver and as usual, the ultimate source for documentation is
348 U to "Use The Source Luke" or, at your convenience, Vojtech ;)
349

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Legacy js interface와 초기화

1-42

이 문서는 legacy `js` interface를 설명합니다. 새 client는 generic event interface인 `evdev`로 전환하도록 권장됩니다.

Joystick driver 1.0은 사용자 프로그램이 값을 polling하는 대신 상태가 바뀔 때만 event를 보고합니다. 추가 정보는 joystick package의 `joystick-api.txt`, `joystick.h`, `jstest.c`에 있으며 device는 blocking·nonblocking mode와 `select()`를 지원합니다.

하위 호환성을 위해 v0.x interface도 포함합니다. 옛 interface 호출에는 호환 값이 반환되지만 axis는 2개로 제한되고 application은 보통 button 2개만 decode합니다. Driver 자체는 최대 32개 button을 제공합니다.

일반적인 `open()` 의미로 `/dev/input/js0`을 엽니다. Driver는 polling 대신 event를 보고하므로 open 직후 joystick의 초기 상태를 얻을 수 있도록 합성 `JS_EVENT_INIT` event 연속열을 보냅니다. 기본 open은 `open("/dev/input/js0", O_RDONLY)`와 같은 blocking mode입니다.

Joystick interface 세대
Interface동작상태
`evdev`Generic input event새 client에 권장
`js` v1.x상태 변화 기반 `js_event`Blocking·nonblocking·select 지원
`js` v0.x현재 상태를 즉시 반환Deprecated, 2 axis 중심

권장 interface와 legacy 호환 범위를 구분합니다.

Joystick open 초기화
`/dev/input/js0` openDriver가 startup mode 진입각 axis의 `JS_EVENT_AXIS | JS_EVENT_INIT` 생성각 button의 `JS_EVENT_BUTTON | JS_EVENT_INIT` 생성Client가 합성 event를 읽어 초기 상태 구성이후 실제 변화 event 처리

Open 직후 합성 event로 전체 초기 상태를 복원합니다.

.. _joystick-api:

=====================
Programming Interface
=====================

:Author: Ragnar Hojland Espinosa <[email protected]> - 7 Aug 1998

Introduction
============

.. important::
   This document describes legacy ``js`` interface. Newer clients are
   encouraged to switch to the generic event (``evdev``) interface.

The 1.0 driver uses a new, event based approach to the joystick driver.
Instead of the user program polling for the joystick values, the joystick
driver now reports only any changes of its state. See joystick-api.txt,
joystick.h and jstest.c included in the joystick package for more
information. The joystick device can be used in either blocking or
nonblocking mode, and supports select() calls.

For backward compatibility the old (v0.x) interface is still included.
Any call to the joystick driver using the old interface will return values
that are compatible to the old interface. This interface is still limited
to 2 axes, and applications using it usually decode only 2 buttons, although
the driver provides up to 32.

Initialization
==============

Open the joystick device following the usual semantics (that is, with open).
Since the driver now reports events instead of polling for changes,
immediately after the open it will issue a series of synthetic events
(JS_EVENT_INIT) that you can read to obtain the initial state of the
joystick.

By default, the device is opened in blocking mode::

        int fd = open ("/dev/input/js0", O_RDONLY);

`js_event` 구조와 type·number

43-106

Event 하나는 `struct js_event e`를 준비하고 `read(fd, &e, sizeof(e))`로 읽습니다. 단일 event read가 성공하면 여러 event를 요청한 경우가 아닌 한 `sizeof(e)`를 반환합니다.

`struct js_event`
필드형식의미
`time``__u32`Millisecond event timestamp
`value``__s16`Axis 위치 또는 button 상태
`type``__u8`Button·axis·initial flag
`number``__u8`Axis 또는 button 번호

Legacy joydev가 전달하는 고정 크기 event record입니다.

`type`은 button press·release인 `JS_EVENT_BUTTON`(0x01), joystick 이동인 `JS_EVENT_AXIS`(0x02), 초기 상태 표시인 `JS_EVENT_INIT`(0x80)을 사용합니다.

Open 때 합성 초기 event는 기본 type과 `JS_EVENT_INIT`을 OR합니다. 예를 들어 초기 button event는 `JS_EVENT_BUTTON | JS_EVENT_INIT`, 즉 0x81입니다. 합성과 실제 event를 구분하지 않으려면 `type &= ~JS_EVENT_INIT`으로 초기 flag를 지웁니다.

`js_event.type` bit
SymbolValue의미
`JS_EVENT_BUTTON`0x01Button pressed 또는 released
`JS_EVENT_AXIS`0x02Joystick axis moved
`JS_EVENT_INIT`0x80합성 초기 상태
Initial button0x81`BUTTON | INIT`
Initial axis0x82`AXIS | INIT`

Base event와 초기 상태 flag는 bitwise OR로 결합됩니다.

`number`는 event를 만든 axis 또는 button 번호입니다. Axis와 button은 별도로 번호를 매기므로 axis 0과 button 0이 동시에 존재합니다. 일반적으로 첫 X·Y axis는 0·1, 두 번째 X·Y axis는 2·3입니다.

Hat의 물리 방향 수는 4방향 또는 8방향처럼 장치마다 다르지만 driver는 hardware가 독립 이동을 지원하지 않아도 항상 서로 독립적인 axis 두 개로 보고합니다.

일반 axis numbering
Axis`number`
1st Axis X0
1st Axis Y1
2nd Axis X2
2nd Axis Y3
Additional axes4 이상

Axis와 button 번호 공간은 서로 독립적입니다.

Event type 정규화
`e.type` 읽기`e.type & JS_EVENT_INIT`로 합성 여부 확인`e.type & ~JS_EVENT_INIT`으로 base type 추출`JS_EVENT_BUTTON` 또는 `JS_EVENT_AXIS` 처리`e.number`를 해당 button·axis 공간의 index로 사용

합성 여부와 base event 종류를 각각 해석합니다.

Event Reading
=============

::

        struct js_event e;
        read (fd, &e, sizeof(e));

where js_event is defined as::

        struct js_event {
                __u32 time;     /* event timestamp in milliseconds */
                __s16 value;    /* value */
                __u8 type;      /* event type */
                __u8 number;    /* axis/button number */
        };

If the read is successful, it will return sizeof(e), unless you wanted to read
more than one event per read as described in section 3.1.


js_event.type
-------------

The possible values of ``type`` are::

        #define JS_EVENT_BUTTON         0x01    /* button pressed/released */
        #define JS_EVENT_AXIS           0x02    /* joystick moved */
        #define JS_EVENT_INIT           0x80    /* initial state of device */

As mentioned above, the driver will issue synthetic JS_EVENT_INIT ORed
events on open. That is, if it's issuing an INIT BUTTON event, the
current type value will be::

        int type = JS_EVENT_BUTTON | JS_EVENT_INIT;        /* 0x81 */

If you choose not to differentiate between synthetic or real events
you can turn off the JS_EVENT_INIT bits::

        type &= ~JS_EVENT_INIT;                                /* 0x01 */


js_event.number
---------------

The values of ``number`` correspond to the axis or button that
generated the event. Note that they carry separate numeration (that
is, you have both an axis 0 and a button 0). Generally,

        =============== =======
        Axis                number
        =============== =======
        1st Axis X        0
        1st Axis Y        1
        2nd Axis X        2
        2nd Axis Y        3
        ...and so on
        =============== =======

Hats vary from one joystick type to another. Some can be moved in 8
directions, some only in 4. The driver, however, always reports a hat as two
independent axes, even if the hardware doesn't allow independent movement.

`js_event.value`와 timestamp

107-148

Axis event의 `value`는 -32767부터 +32767까지의 signed integer로 해당 axis의 joystick 위치를 나타냅니다. Joystick을 놓은 상태에서 0이 아니거나 전체 범위를 사용하지 못하면 `jscal` 같은 도구로 다시 calibration해야 합니다.

Button event의 `value`는 press 1, release 0입니다.

Button event마다 현재 bit를 XOR하는 방식은 `JS_EVENT_INIT`을 별도 처리할 때 동작할 수 있지만 driver와 상태 동기화를 잃을 수 있습니다. 더 안전한 방식은 INIT flag를 제거해 button event인지 검사하고 value가 non-zero면 bit를 OR, 0이면 bit를 clear하는 것입니다. 이 방식은 합성·실제 event 모두에서 절대 상태를 적용합니다.

`js_event.value` 의미
Base typeValue의미
`JS_EVENT_AXIS`-32767…+32767Axis 위치
`JS_EVENT_AXIS`0Calibration된 중립 위치
`JS_EVENT_BUTTON`1Pressed
`JS_EVENT_BUTTON`0Released

Event 종류별 값 범위와 해석입니다.

안전한 button 상태 갱신
`type & ~JS_EVENT_INIT`으로 button event 확인`number`에 해당하는 state bit 선택`value != 0`이면 bit set`value == 0`이면 bit clear합성 초기 event와 실제 event 모두 같은 경로 사용

Toggle 대신 event value가 말하는 절대 상태를 적용합니다.

`js_event.time`에는 event 생성 시각이 과거의 어떤 기준점부터 지난 millisecond로 저장됩니다. Double click 탐지, axis 이동과 button press가 동시에 일어났는지 판단하는 데 사용할 수 있습니다.

Timestamp 활용
용도판정
Double click두 press timestamp 간격 비교
동시 입력Axis와 button timestamp 비교
Event 순서증가하는 millisecond 값 비교

절대 wall-clock보다 event 사이의 시간 관계를 판단하는 값입니다.

js_event.value
--------------

For an axis, ``value`` is a signed integer between -32767 and +32767
representing the position of the joystick along that axis. If you
don't read a 0 when the joystick is ``dead``, or if it doesn't span the
full range, you should recalibrate it (with, for example, jscal).

For a button, ``value`` for a press button event is 1 and for a release
button event is 0.

Though this::

        if (js_event.type == JS_EVENT_BUTTON) {
                buttons_state ^= (1 << js_event.number);
        }

may work well if you handle JS_EVENT_INIT events separately,

::

        if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
                if (js_event.value)
                        buttons_state |= (1 << js_event.number);
                else
                        buttons_state &= ~(1 << js_event.number);
        }

is much safer since it can't lose sync with the driver. As you would
have to write a separate handler for JS_EVENT_INIT events in the first
snippet, this ends up being shorter.


js_event.time
-------------

The time an event was generated is stored in ``js_event.time``. It's a time
in milliseconds since ... well, since sometime in the past.  This eases the
task of detecting double clicks, figuring out if movement of axis and button
presses happened at the same time, and similar.

Blocking·nonblocking read와 queue 복구

149-224

Blocking mode에서 `read()`는 event가 생성되어 읽힐 때까지 계속 기다립니다. 무기한 기다릴 수 없다면 `select()`로 fd에 data가 생기거나 timeout될 때까지 기다리거나, device를 `O_NONBLOCK`으로 엽니다.

Nonblocking mode에서 `read()`가 -1을 반환해도 반드시 실제 오류는 아닙니다. `errno`가 `EAGAIN`이면 driver queue에 pending event가 없다는 뜻입니다. Queue가 빌 때까지 모든 event를 읽어야 합니다.

예제 loop는 `read()`가 양수인 동안 `process_event(e)`를 호출하고, queue가 비어 `EAGAIN`이 나오면 처리된 event를 이용해 다른 작업을 합니다. 다른 errno는 오류로 처리합니다.

Queue는 유한하므로 비우지 않아 가득 차면 오래된 event가 덮어써져 유실됩니다. Queue를 모두 비우면 발생한 일을 즉시 파악할 수 있고 처리를 나중으로 미루지 않습니다.

Read 간격이 너무 길거나 event가 너무 많이 생성되면 queue가 찰 수 있으며 system load가 read 간격을 더 벌릴 수 있습니다. Event가 유실되면 driver는 startup mode로 전환하고 다음 read 때 현재 joystick 상태를 알리는 합성 `JS_EVENT_INIT` event를 생성합니다.

Version 1.2.8 기준 queue는 64 event를 담는 circular buffer입니다. `joystick.h`의 `JS_BUFF_SIZE`를 늘리고 driver를 다시 compile하면 크기를 키울 수 있습니다.

Read 방식
방식대기Queue가 비었을 때
BlockingEvent까지 무기한 대기Read가 계속 block
`select()`Data 또는 timeout까지 대기Timeout 처리 가능
`O_NONBLOCK`즉시 반환-1과 `errno == EAGAIN`

대기 방식과 queue-empty 결과를 정리했습니다.

Nonblocking queue drain
반복해서 `read(fd, &e, sizeof(e))` 호출양수이면 event 처리 후 계속 읽기-1이면 `errno` 확인`EAGAIN`이면 queue가 비었으므로 종료다른 errno이면 실제 오류 처리

Queue를 매번 완전히 비워 overflow와 지연을 줄입니다.

Queue overflow 복구
Read 간격 증가 또는 event burst 발생64-entry circular queue 포화오래된 event가 overwrite되어 상태 변화 유실Driver가 startup mode로 전환다음 read에 `JS_EVENT_INIT` event 생성Client가 axis·button 현재 상태 재구성

유실이 발생하면 startup mode의 합성 상태로 다시 동기화합니다.

한 번에 여러 event를 읽으려면 `struct js_event mybuffer[0xff]` 같은 배열을 전달합니다. 반환값이 -1이면 queue가 비었고, 그 외에는 `i / sizeof(js_event)`가 읽은 event 수입니다. Buffer가 가득 찼다면 처리 후 driver queue가 빌 때까지 계속 읽는 것이 좋습니다.

Batch read 계산
결과해석
`read == -1`Queue empty 또는 errno 오류
`read > 0``read / sizeof(struct js_event)`개 event
Buffer full처리 후 다시 읽어 queue drain

Byte 반환값을 event 개수로 변환합니다.

Reading
=======

If you open the device in blocking mode, a read will block (that is,
wait) forever until an event is generated and effectively read. There
are two alternatives if you can't afford to wait forever (which is,
admittedly, a long time;)

        a) use select to wait until there's data to be read on fd, or
           until it timeouts. There's a good example on the select(2)
           man page.

        b) open the device in non-blocking mode (O_NONBLOCK)


O_NONBLOCK
----------

If read returns -1 when reading in O_NONBLOCK mode, this isn't
necessarily a "real" error (check errno(3)); it can just mean there
are no events pending to be read on the driver queue. You should read
all events on the queue (that is, until you get a -1).

For example,

::

        while (1) {
                while (read (fd, &e, sizeof(e)) > 0) {
                        process_event (e);
                }
                /* EAGAIN is returned when the queue is empty */
                if (errno != EAGAIN) {
                        /* error */
                }
                /* do something interesting with processed events */
        }

One reason for emptying the queue is that if it gets full you'll start
missing events since the queue is finite, and older events will get
overwritten.

The other reason is that you want to know all that happened, and not
delay the processing till later.

Why can the queue get full? Because you don't empty the queue as
mentioned, or because too much time elapses from one read to another
and too many events to store in the queue get generated. Note that
high system load may contribute to space those reads even more.

If time between reads is enough to fill the queue and lose an event,
the driver will switch to startup mode and next time you read it,
synthetic events (JS_EVENT_INIT) will be generated to inform you of
the actual state of the joystick.


.. note::

 As of version 1.2.8, the queue is circular and able to hold 64
 events. You can increment this size bumping up JS_BUFF_SIZE in
 joystick.h and recompiling the driver.


In the above code, you might as well want to read more than one event
at a time using the typical read(2) functionality. For that, you would
replace the read above with something like::

        struct js_event mybuffer[0xff];
        int i = read (fd, mybuffer, sizeof(mybuffer));

In this case, read would return -1 if the queue was empty, or some
other value in which the number of events read would be i /
sizeof(js_event)  Again, if the buffer was full, it's a good idea to
process the events and keep reading it until you empty the driver queue.

Joystick ioctl과 correction

225-295

Joystick driver는 axis 수를 `char`로 얻는 `JSIOCGAXES`, button 수를 `char`로 얻는 `JSIOCGBUTTONS`, driver version을 `int`로 얻는 `JSIOCGVERSION`, 식별 문자열을 얻는 `JSIOCGNAME(len)`, correction 값을 설정·조회하는 `JSIOCSCORR`와 `JSIOCGCORR` ioctl을 정의합니다.

Joystick ioctl
Ioctl기능세 번째 인자
`JSIOCGAXES`Axis 수 조회`char *`
`JSIOCGBUTTONS`Button 수 조회`char *`
`JSIOCGVERSION`Driver version 조회`int *`
`JSIOCGNAME(len)`Joystick 이름 조회`char *`
`JSIOCSCORR`Correction 값 설정`struct js_corr *`
`JSIOCGCORR`Correction 값 조회`struct js_corr *`

Operation과 세 번째 인자 형식입니다.

실행 중 driver가 1.0 이상이고 event interface를 지원하는지는 `JSIOCGVERSION`으로 검사할 수 있으며 지원하지 않으면 ioctl이 실패합니다. Compile-time에는 `JS_VERSION` symbol을 검사합니다. 원문 절 제목은 `JSIOGCVERSION`으로 표기하지만 operation 목록의 symbol은 `JSIOCGVERSION`입니다.

`JSIOCGNAME(len)`은 boot 때 출력되는 것과 같은 joystick 이름을 가져옵니다. `len`은 application buffer 길이여서 긴 이름으로 인한 overrun을 막습니다. Ioctl이 실패하면 예제는 `strscpy()`로 `Unknown`을 기록합니다.

`JSIOC[SG]CORR` 사용법은 `jscal.c`를 참고합니다. 일반 프로그램에는 필요 없고 `jscal`, `kcmjoy` 같은 calibration software만 사용합니다. 이 ioctl과 data type은 stable API로 간주되지 않아 경고 없이 바뀔 수 있습니다.

`JSIOCSCORR`와 `JSIOCGCORR`은 모든 axis 정보를 담을 수 있는 `struct js_corr corr[MAX_AXIS]`를 기대합니다. `struct js_corr`은 coefficient 여덟 개 `coef[8]`, precision `prec`, correction type `type`을 가집니다.

`struct js_corr`
필드·symbol형식·값의미
`coef[8]``__s32[8]`Correction coefficients
`prec``__u16`Precision
`type``__u16`Correction algorithm
`JS_CORR_NONE`0x00Raw values 반환
`JS_CORR_BROKEN`0x01Broken-line correction

Axis correction parameter와 type 값입니다.

Runtime capability 조회
`JSIOCGVERSION`으로 event API 지원 확인`JSIOCGAXES`로 axis 수 조회`JSIOCGBUTTONS`로 button 수 조회`JSIOCGNAME(len)`으로 식별 이름 조회Calibration tool만 correction ioctl 사용

Open한 fd에서 장치 규모와 API 정보를 얻습니다.

IOCTLs
======

The joystick driver defines the following ioctl(2) operations::

                                /* function                        3rd arg  */
        #define JSIOCGAXES        /* get number of axes                char         */
        #define JSIOCGBUTTONS        /* get number of buttons        char         */
        #define JSIOCGVERSION        /* get driver version                int         */
        #define JSIOCGNAME(len) /* get identifier string        char         */
        #define JSIOCSCORR        /* set correction values        &js_corr */
        #define JSIOCGCORR        /* get correction values        &js_corr */

For example, to read the number of axes::

        char number_of_axes;
        ioctl (fd, JSIOCGAXES, &number_of_axes);


JSIOGCVERSION
-------------

JSIOGCVERSION is a good way to check in run-time whether the running
driver is 1.0+ and supports the event interface. If it is not, the
IOCTL will fail. For a compile-time decision, you can test the
JS_VERSION symbol::

        #ifdef JS_VERSION
        #if JS_VERSION > 0xsomething


JSIOCGNAME
----------

JSIOCGNAME(len) allows you to get the name string of the joystick - the same
as is being printed at boot time. The 'len' argument is the length of the
buffer provided by the application asking for the name. It is used to avoid
possible overrun should the name be too long::

        char name[128];
        if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
                strscpy(name, "Unknown", sizeof(name));
        printf("Name: %s\n", name);


JSIOC[SG]CORR
-------------

For usage on JSIOC[SG]CORR I suggest you to look into jscal.c  They are
not needed in a normal program, only in joystick calibration software
such as jscal or kcmjoy. These IOCTLs and data types aren't considered
to be in the stable part of the API, and therefore may change without
warning in following releases of the driver.

Both JSIOCSCORR and JSIOCGCORR expect &js_corr to be able to hold
information for all axes. That is, struct js_corr corr[MAX_AXIS];

struct js_corr is defined as::

        struct js_corr {
                __s32 coef[8];
                __u16 prec;
                __u16 type;
        };

and ``type``::

        #define JS_CORR_NONE            0x00    /* returns raw values */
        #define JS_CORR_BROKEN          0x01    /* broken line */

v0.x backward compatibility

296-339

Joystick driver v0.x API는 매우 제한적이며 deprecated지만 driver가 하위 호환성을 제공합니다. 옛 프로그램은 `struct JS_DATA_TYPE` 크기인 `JS_RETURN`만큼 read하고 짧은 `usleep(1000)`을 두며 현재 상태를 반복 조회합니다.

이 read는 즉시 반환합니다. `struct JS_DATA_TYPE`에는 현재 button bitmask인 `buttons`, 즉시 X axis 값인 `x`, Y axis 값인 `y`가 있으며 `JS_RETURN`은 `sizeof(struct JS_DATA_TYPE)`입니다.

Legacy `JS_DATA_TYPE`
필드형식의미
`buttons``int`현재 button bitmask
`x``int`현재 X axis 값
`y``int`현재 Y axis 값
`JS_RETURN``sizeof(struct JS_DATA_TYPE)`Expected read byte count

Event가 아니라 read 시점의 즉시 상태를 반환합니다.

첫 button 상태는 `js.buttons & 1`, 두 번째는 `js.buttons & 2`로 검사합니다.

원래 v0.x driver에서 axis 값은 non-negative라는 점 외에 범위가 정의되지 않았습니다. 1.2.8 이상 driver는 최소 1, 중앙 128, 최대 255의 고정 범위를 사용합니다.

v0.8.0.2 driver는 현재 Multisystem joystick이라 부르는 digital joystick용 `/dev/djsX` interface도 제공했지만 현재 driver는 이 interface와 호환되지 않습니다.

Legacy API 제한
항목v0.xv1.x
전달 방식즉시 상태 polling상태 변화 event
Axis 수주로 2개장치 capability만큼
ButtonBitmask, application은 보통 2개번호별 최대 32개
Axis 범위원본은 미정, 1.2.8+는 1~255-32767~+32767
Digital `/dev/djsX`v0.8.0.2에 존재호환하지 않음

v0.x 상태 polling과 v1.x event interface 차이입니다.

Legacy polling loop
`JS_RETURN` byte read 요청반환 크기가 다르면 오류 처리`buttons`, `x`, `y` 즉시 상태 적용`usleep(1000)`으로 짧게 대기다음 상태 read 반복

Deprecated API는 현재 상태 구조체를 반복해서 읽습니다.

Backward compatibility
======================

The 0.x joystick driver API is quite limited and its usage is deprecated.
The driver offers backward compatibility, though. Here's a quick summary::

        struct JS_DATA_TYPE js;
        while (1) {
                if (read (fd, &js, JS_RETURN) != JS_RETURN) {
                        /* error */
                }
                usleep (1000);
        }

As you can figure out from the example, the read returns immediately,
with the actual state of the joystick::

        struct JS_DATA_TYPE {
                int buttons;    /* immediate button state */
                int x;          /* immediate x axis value */
                int y;          /* immediate y axis value */
        };

and JS_RETURN is defined as::

        #define JS_RETURN       sizeof(struct JS_DATA_TYPE)

To test the state of the buttons,

::

        first_button_state  = js.buttons & 1;
        second_button_state = js.buttons & 2;

The axis values do not have a defined range in the original 0.x driver,
except that the values are non-negative. The 1.2.8+ drivers use a
fixed range for reporting the values, 1 being the minimum, 128 the
center, and 255 maximum value.

The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
called Multisystem joysticks in this driver), under /dev/djsX. This driver
doesn't try to be compatible with that interface.

적용 버전과 문서 기여

340-348

의견, 추가 내용, 특히 수정 제안을 환영합니다. 이 문서는 joystick driver 1.2.8 이상에 유효하며 최종적인 정확성 판단에는 source code를 참고해야 합니다.

문서 적용 범위
항목내용
최소 적용 versionJoystick driver 1.2.8
기여Comments, additions, corrections welcome
최종 기준Driver source code

원문의 ASCII 서명을 내용 중심 note로 구조화했습니다.

API 확인 우선순위
현재 driver version 확인이 문서의 1.2.8 이상 규약 확인Header의 symbol·구조체 확인실제 driver source 동작 확인차이가 있으면 문서 수정 제안

문서와 실행 환경의 차이가 있을 때 확인할 순서입니다.

Final Notes
===========

::

  ____/|        Comments, additions, and specially corrections are welcome.
  \ o.O|        Documentation valid for at least version 1.2.8 of the joystick
   =(_)=        driver and as usual, the ultimate source for documentation is
     U                to "Use The Source Luke" or, at your convenience, Vojtech ;)