Documentation/driver-api/uio-howto.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

The Userspace I/O HOWTO

UIO의 device file·sysfs·memory mapping·interrupt model과 kernel/userspace driver 작성법, generic PCI·Hyper-V driver를 다루는 한국어 전문 번역입니다.

Source pathDocumentation/driver-api/uio-howto.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약·해설

uio-howto.rst:1-730

UIO는 작은 kernel module로 interrupt와 memory mapping만 제공하고 장치 제어의 대부분을 userspace로 옮깁니다. 이 HOWTO는 UIO framework의 ABI에서 custom module, platform driver, PCI·Hyper-V generic driver와 userspace event loop까지 이어지는 전체 구현 절차를 설명합니다.

문서 구성
원문 줄핵심 내용
1-58문서 소개와 적용 범위
59-208UIO 동작과 sysfs ABI
209-323kernel module data structures
324-458interrupt와 platform driver
459-528userspace mapping과 event 처리
529-663generic PCI driver와 예제
664-730Hyper-V driver와 참고 자료

2. 영어 원문 전체

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

원문 전체 펼치기
1 =======================
2 The Userspace I/O HOWTO
3 =======================
4
5 :Author: Hans-Jürgen Koch Linux developer, Linutronix
6 :Date: 2006-12-11
7
8 About this document
9 ===================
10
11 Translations
12 ------------
13
14 If you know of any translations for this document, or you are interested
15 in translating it, please email me [email protected].
16
17 Preface
18 -------
19
20 For many types of devices, creating a Linux kernel driver is overkill.
21 All that is really needed is some way to handle an interrupt and provide
22 access to the memory space of the device. The logic of controlling the
23 device does not necessarily have to be within the kernel, as the device
24 does not need to take advantage of any of other resources that the
25 kernel provides. One such common class of devices that are like this are
26 for industrial I/O cards.
27
28 To address this situation, the userspace I/O system (UIO) was designed.
29 For typical industrial I/O cards, only a very small kernel module is
30 needed. The main part of the driver will run in user space. This
31 simplifies development and reduces the risk of serious bugs within a
32 kernel module.
33
34 Please note that UIO is not an universal driver interface. Devices that
35 are already handled well by other kernel subsystems (like networking or
36 serial or USB) are no candidates for an UIO driver. Hardware that is
37 ideally suited for an UIO driver fulfills all of the following:
38
39 - The device has memory that can be mapped. The device can be
40 controlled completely by writing to this memory.
41
42 - The device usually generates interrupts.
43
44 - The device does not fit into one of the standard kernel subsystems.
45
46 Acknowledgments
47 ---------------
48
49 I'd like to thank Thomas Gleixner and Benedikt Spranger of Linutronix,
50 who have not only written most of the UIO code, but also helped greatly
51 writing this HOWTO by giving me all kinds of background information.
52
53 Feedback
54 --------
55
56 Find something wrong with this document? (Or perhaps something right?) I
57 would love to hear from you. Please email me at [email protected].
58
59 About UIO
60 =========
61
62 If you use UIO for your card's driver, here's what you get:
63
64 - only one small kernel module to write and maintain.
65
66 - develop the main part of your driver in user space, with all the
67 tools and libraries you're used to.
68
69 - bugs in your driver won't crash the kernel.
70
71 - updates of your driver can take place without recompiling the kernel.
72
73 How UIO works
74 -------------
75
76 Each UIO device is accessed through a device file and several sysfs
77 attribute files. The device file will be called ``/dev/uio0`` for the
78 first device, and ``/dev/uio1``, ``/dev/uio2`` and so on for subsequent
79 devices.
80
81 ``/dev/uioX`` is used to access the address space of the card. Just use
82 :c:func:`mmap()` to access registers or RAM locations of your card.
83
84 Interrupts are handled by reading from ``/dev/uioX``. A blocking
85 :c:func:`read()` from ``/dev/uioX`` will return as soon as an
86 interrupt occurs. You can also use :c:func:`select()` on
87 ``/dev/uioX`` to wait for an interrupt. The integer value read from
88 ``/dev/uioX`` represents the total interrupt count. You can use this
89 number to figure out if you missed some interrupts.
90
91 For some hardware that has more than one interrupt source internally,
92 but not separate IRQ mask and status registers, there might be
93 situations where userspace cannot determine what the interrupt source
94 was if the kernel handler disables them by writing to the chip's IRQ
95 register. In such a case, the kernel has to disable the IRQ completely
96 to leave the chip's register untouched. Now the userspace part can
97 determine the cause of the interrupt, but it cannot re-enable
98 interrupts. Another cornercase is chips where re-enabling interrupts is
99 a read-modify-write operation to a combined IRQ status/acknowledge
100 register. This would be racy if a new interrupt occurred simultaneously.
101
102 To address these problems, UIO also implements a write() function. It is
103 normally not used and can be ignored for hardware that has only a single
104 interrupt source or has separate IRQ mask and status registers. If you
105 need it, however, a write to ``/dev/uioX`` will call the
106 :c:func:`irqcontrol()` function implemented by the driver. You have
107 to write a 32-bit value that is usually either 0 or 1 to disable or
108 enable interrupts. If a driver does not implement
109 :c:func:`irqcontrol()`, :c:func:`write()` will return with
110 ``-ENOSYS``.
111
112 To handle interrupts properly, your custom kernel module can provide its
113 own interrupt handler. It will automatically be called by the built-in
114 handler.
115
116 For cards that don't generate interrupts but need to be polled, there is
117 the possibility to set up a timer that triggers the interrupt handler at
118 configurable time intervals. This interrupt simulation is done by
119 calling :c:func:`uio_event_notify()` from the timer's event
120 handler.
121
122 Each driver provides attributes that are used to read or write
123 variables. These attributes are accessible through sysfs files. A custom
124 kernel driver module can add its own attributes to the device owned by
125 the uio driver, but not added to the UIO device itself at this time.
126 This might change in the future if it would be found to be useful.
127
128 The following standard attributes are provided by the UIO framework:
129
130 - ``name``: The name of your device. It is recommended to use the name
131 of your kernel module for this.
132
133 - ``version``: A version string defined by your driver. This allows the
134 user space part of your driver to deal with different versions of the
135 kernel module.
136
137 - ``event``: The total number of interrupts handled by the driver since
138 the last time the device node was read.
139
140 These attributes appear under the ``/sys/class/uio/uioX`` directory.
141 Please note that this directory might be a symlink, and not a real
142 directory. Any userspace code that accesses it must be able to handle
143 this.
144
145 Each UIO device can make one or more memory regions available for memory
146 mapping. This is necessary because some industrial I/O cards require
147 access to more than one PCI memory region in a driver.
148
149 Each mapping has its own directory in sysfs, the first mapping appears
150 as ``/sys/class/uio/uioX/maps/map0/``. Subsequent mappings create
151 directories ``map1/``, ``map2/``, and so on. These directories will only
152 appear if the size of the mapping is not 0.
153
154 Each ``mapX/`` directory contains four read-only files that show
155 attributes of the memory:
156
157 - ``name``: A string identifier for this mapping. This is optional, the
158 string can be empty. Drivers can set this to make it easier for
159 userspace to find the correct mapping.
160
161 - ``addr``: The address of memory that can be mapped.
162
163 - ``size``: The size, in bytes, of the memory pointed to by addr.
164
165 - ``offset``: The offset, in bytes, that has to be added to the pointer
166 returned by :c:func:`mmap()` to get to the actual device memory.
167 This is important if the device's memory is not page aligned.
168 Remember that pointers returned by :c:func:`mmap()` are always
169 page aligned, so it is good style to always add this offset.
170
171 From userspace, the different mappings are distinguished by adjusting
172 the ``offset`` parameter of the :c:func:`mmap()` call. To map the
173 memory of mapping N, you have to use N times the page size as your
174 offset::
175
176 offset = N * getpagesize();
177
178 Sometimes there is hardware with memory-like regions that can not be
179 mapped with the technique described here, but there are still ways to
180 access them from userspace. The most common example are x86 ioports. On
181 x86 systems, userspace can access these ioports using
182 :c:func:`ioperm()`, :c:func:`iopl()`, :c:func:`inb()`,
183 :c:func:`outb()`, and similar functions.
184
185 Since these ioport regions can not be mapped, they will not appear under
186 ``/sys/class/uio/uioX/maps/`` like the normal memory described above.
187 Without information about the port regions a hardware has to offer, it
188 becomes difficult for the userspace part of the driver to find out which
189 ports belong to which UIO device.
190
191 To address this situation, the new directory
192 ``/sys/class/uio/uioX/portio/`` was added. It only exists if the driver
193 wants to pass information about one or more port regions to userspace.
194 If that is the case, subdirectories named ``port0``, ``port1``, and so
195 on, will appear underneath ``/sys/class/uio/uioX/portio/``.
196
197 Each ``portX/`` directory contains four read-only files that show name,
198 start, size, and type of the port region:
199
200 - ``name``: A string identifier for this port region. The string is
201 optional and can be empty. Drivers can set it to make it easier for
202 userspace to find a certain port region.
203
204 - ``start``: The first port of this region.
205
206 - ``size``: The number of ports in this region.
207
208 - ``porttype``: A string describing the type of port.
209
210 Writing your own kernel module
211 ==============================
212
213 Please have a look at ``uio_cif.c`` as an example. The following
214 paragraphs explain the different sections of this file.
215
216 struct uio_info
217 ---------------
218
219 This structure tells the framework the details of your driver, Some of
220 the members are required, others are optional.
221
222 - ``const char *name``: Required. The name of your driver as it will
223 appear in sysfs. I recommend using the name of your module for this.
224
225 - ``const char *version``: Required. This string appears in
226 ``/sys/class/uio/uioX/version``.
227
228 - ``struct uio_mem mem[ MAX_UIO_MAPS ]``: Required if you have memory
229 that can be mapped with :c:func:`mmap()`. For each mapping you
230 need to fill one of the ``uio_mem`` structures. See the description
231 below for details.
232
233 - ``struct uio_port port[ MAX_UIO_PORTS_REGIONS ]``: Required if you
234 want to pass information about ioports to userspace. For each port
235 region you need to fill one of the ``uio_port`` structures. See the
236 description below for details.
237
238 - ``long irq``: Required. If your hardware generates an interrupt, it's
239 your modules task to determine the irq number during initialization.
240 If you don't have a hardware generated interrupt but want to trigger
241 the interrupt handler in some other way, set ``irq`` to
242 ``UIO_IRQ_CUSTOM``. If you had no interrupt at all, you could set
243 ``irq`` to ``UIO_IRQ_NONE``, though this rarely makes sense.
244
245 - ``unsigned long irq_flags``: Required if you've set ``irq`` to a
246 hardware interrupt number. The flags given here will be used in the
247 call to :c:func:`request_irq()`.
248
249 - ``int (*mmap)(struct uio_info *info, struct vm_area_struct *vma)``:
250 Optional. If you need a special :c:func:`mmap()`
251 function, you can set it here. If this pointer is not NULL, your
252 :c:func:`mmap()` will be called instead of the built-in one.
253
254 - ``int (*open)(struct uio_info *info, struct inode *inode)``:
255 Optional. You might want to have your own :c:func:`open()`,
256 e.g. to enable interrupts only when your device is actually used.
257
258 - ``int (*release)(struct uio_info *info, struct inode *inode)``:
259 Optional. If you define your own :c:func:`open()`, you will
260 probably also want a custom :c:func:`release()` function.
261
262 - ``int (*irqcontrol)(struct uio_info *info, s32 irq_on)``:
263 Optional. If you need to be able to enable or disable interrupts
264 from userspace by writing to ``/dev/uioX``, you can implement this
265 function. The parameter ``irq_on`` will be 0 to disable interrupts
266 and 1 to enable them.
267
268 Usually, your device will have one or more memory regions that can be
269 mapped to user space. For each region, you have to set up a
270 ``struct uio_mem`` in the ``mem[]`` array. Here's a description of the
271 fields of ``struct uio_mem``:
272
273 - ``const char *name``: Optional. Set this to help identify the memory
274 region, it will show up in the corresponding sysfs node.
275
276 - ``int memtype``: Required if the mapping is used. Set this to
277 ``UIO_MEM_PHYS`` if you have physical memory on your card to be
278 mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated
279 with :c:func:`__get_free_pages()` but not kmalloc()). There's also
280 ``UIO_MEM_VIRTUAL`` for virtual memory.
281
282 - ``phys_addr_t addr``: Required if the mapping is used. Fill in the
283 address of your memory block. This address is the one that appears in
284 sysfs.
285
286 - ``resource_size_t size``: Fill in the size of the memory block that
287 ``addr`` points to. If ``size`` is zero, the mapping is considered
288 unused. Note that you *must* initialize ``size`` with zero for all
289 unused mappings.
290
291 - ``void *internal_addr``: If you have to access this memory region
292 from within your kernel module, you will want to map it internally by
293 using something like :c:func:`ioremap()`. Addresses returned by
294 this function cannot be mapped to user space, so you must not store
295 it in ``addr``. Use ``internal_addr`` instead to remember such an
296 address.
297
298 Please do not touch the ``map`` element of ``struct uio_mem``! It is
299 used by the UIO framework to set up sysfs files for this mapping. Simply
300 leave it alone.
301
302 Sometimes, your device can have one or more port regions which can not
303 be mapped to userspace. But if there are other possibilities for
304 userspace to access these ports, it makes sense to make information
305 about the ports available in sysfs. For each region, you have to set up
306 a ``struct uio_port`` in the ``port[]`` array. Here's a description of
307 the fields of ``struct uio_port``:
308
309 - ``char *porttype``: Required. Set this to one of the predefined
310 constants. Use ``UIO_PORT_X86`` for the ioports found in x86
311 architectures.
312
313 - ``unsigned long start``: Required if the port region is used. Fill in
314 the number of the first port of this region.
315
316 - ``unsigned long size``: Fill in the number of ports in this region.
317 If ``size`` is zero, the region is considered unused. Note that you
318 *must* initialize ``size`` with zero for all unused regions.
319
320 Please do not touch the ``portio`` element of ``struct uio_port``! It is
321 used internally by the UIO framework to set up sysfs files for this
322 region. Simply leave it alone.
323
324 Adding an interrupt handler
325 ---------------------------
326
327 What you need to do in your interrupt handler depends on your hardware
328 and on how you want to handle it. You should try to keep the amount of
329 code in your kernel interrupt handler low. If your hardware requires no
330 action that you *have* to perform after each interrupt, then your
331 handler can be empty.
332
333 If, on the other hand, your hardware *needs* some action to be performed
334 after each interrupt, then you *must* do it in your kernel module. Note
335 that you cannot rely on the userspace part of your driver. Your
336 userspace program can terminate at any time, possibly leaving your
337 hardware in a state where proper interrupt handling is still required.
338
339 There might also be applications where you want to read data from your
340 hardware at each interrupt and buffer it in a piece of kernel memory
341 you've allocated for that purpose. With this technique you could avoid
342 loss of data if your userspace program misses an interrupt.
343
344 A note on shared interrupts: Your driver should support interrupt
345 sharing whenever this is possible. It is possible if and only if your
346 driver can detect whether your hardware has triggered the interrupt or
347 not. This is usually done by looking at an interrupt status register. If
348 your driver sees that the IRQ bit is actually set, it will perform its
349 actions, and the handler returns IRQ_HANDLED. If the driver detects
350 that it was not your hardware that caused the interrupt, it will do
351 nothing and return IRQ_NONE, allowing the kernel to call the next
352 possible interrupt handler.
353
354 If you decide not to support shared interrupts, your card won't work in
355 computers with no free interrupts. As this frequently happens on the PC
356 platform, you can save yourself a lot of trouble by supporting interrupt
357 sharing.
358
359 Using uio_pdrv for platform devices
360 -----------------------------------
361
362 In many cases, UIO drivers for platform devices can be handled in a
363 generic way. In the same place where you define your
364 ``struct platform_device``, you simply also implement your interrupt
365 handler and fill your ``struct uio_info``. A pointer to this
366 ``struct uio_info`` is then used as ``platform_data`` for your platform
367 device.
368
369 You also need to set up an array of ``struct resource`` containing
370 addresses and sizes of your memory mappings. This information is passed
371 to the driver using the ``.resource`` and ``.num_resources`` elements of
372 ``struct platform_device``.
373
374 You now have to set the ``.name`` element of ``struct platform_device``
375 to ``"uio_pdrv"`` to use the generic UIO platform device driver. This
376 driver will fill the ``mem[]`` array according to the resources given,
377 and register the device.
378
379 The advantage of this approach is that you only have to edit a file you
380 need to edit anyway. You do not have to create an extra driver.
381
382 Using uio_pdrv_genirq for platform devices
383 ------------------------------------------
384
385 Especially in embedded devices, you frequently find chips where the irq
386 pin is tied to its own dedicated interrupt line. In such cases, where
387 you can be really sure the interrupt is not shared, we can take the
388 concept of ``uio_pdrv`` one step further and use a generic interrupt
389 handler. That's what ``uio_pdrv_genirq`` does.
390
391 The setup for this driver is the same as described above for
392 ``uio_pdrv``, except that you do not implement an interrupt handler. The
393 ``.handler`` element of ``struct uio_info`` must remain ``NULL``. The
394 ``.irq_flags`` element must not contain ``IRQF_SHARED``.
395
396 You will set the ``.name`` element of ``struct platform_device`` to
397 ``"uio_pdrv_genirq"`` to use this driver.
398
399 The generic interrupt handler of ``uio_pdrv_genirq`` will simply disable
400 the interrupt line using :c:func:`disable_irq_nosync()`. After
401 doing its work, userspace can reenable the interrupt by writing
402 0x00000001 to the UIO device file. The driver already implements an
403 :c:func:`irq_control()` to make this possible, you must not
404 implement your own.
405
406 Using ``uio_pdrv_genirq`` not only saves a few lines of interrupt
407 handler code. You also do not need to know anything about the chip's
408 internal registers to create the kernel part of the driver. All you need
409 to know is the irq number of the pin the chip is connected to.
410
411 When used in a device-tree enabled system, the driver needs to be
412 probed with the ``"of_id"`` module parameter set to the ``"compatible"``
413 string of the node the driver is supposed to handle. By default, the
414 node's name (without the unit address) is exposed as name for the
415 UIO device in userspace. To set a custom name, a property named
416 ``"linux,uio-name"`` may be specified in the DT node.
417
418 Using uio_dmem_genirq for platform devices
419 ------------------------------------------
420
421 In addition to statically allocated memory ranges, they may also be a
422 desire to use dynamically allocated regions in a user space driver. In
423 particular, being able to access memory made available through the
424 dma-mapping API, may be particularly useful. The ``uio_dmem_genirq``
425 driver provides a way to accomplish this.
426
427 This driver is used in a similar manner to the ``"uio_pdrv_genirq"``
428 driver with respect to interrupt configuration and handling.
429
430 Set the ``.name`` element of ``struct platform_device`` to
431 ``"uio_dmem_genirq"`` to use this driver.
432
433 When using this driver, fill in the ``.platform_data`` element of
434 ``struct platform_device``, which is of type
435 ``struct uio_dmem_genirq_pdata`` and which contains the following
436 elements:
437
438 - ``struct uio_info uioinfo``: The same structure used as the
439 ``uio_pdrv_genirq`` platform data
440
441 - ``unsigned int *dynamic_region_sizes``: Pointer to list of sizes of
442 dynamic memory regions to be mapped into user space.
443
444 - ``unsigned int num_dynamic_regions``: Number of elements in
445 ``dynamic_region_sizes`` array.
446
447 The dynamic regions defined in the platform data will be appended to the
448 `` mem[] `` array after the platform device resources, which implies
449 that the total number of static and dynamic memory regions cannot exceed
450 ``MAX_UIO_MAPS``.
451
452 The dynamic memory regions will be allocated when the UIO device file,
453 ``/dev/uioX`` is opened. Similar to static memory resources, the memory
454 region information for dynamic regions is then visible via sysfs at
455 ``/sys/class/uio/uioX/maps/mapY/*``. The dynamic memory regions will be
456 freed when the UIO device file is closed. When no processes are holding
457 the device file open, the address returned to userspace is ~0.
458
459 Writing a driver in userspace
460 =============================
461
462 Once you have a working kernel module for your hardware, you can write
463 the userspace part of your driver. You don't need any special libraries,
464 your driver can be written in any reasonable language, you can use
465 floating point numbers and so on. In short, you can use all the tools
466 and libraries you'd normally use for writing a userspace application.
467
468 Getting information about your UIO device
469 -----------------------------------------
470
471 Information about all UIO devices is available in sysfs. The first thing
472 you should do in your driver is check ``name`` and ``version`` to make
473 sure you're talking to the right device and that its kernel driver has
474 the version you expect.
475
476 You should also make sure that the memory mapping you need exists and
477 has the size you expect.
478
479 There is a tool called ``lsuio`` that lists UIO devices and their
480 attributes. It is available here:
481
482 http://www.osadl.org/projects/downloads/UIO/user/
483
484 With ``lsuio`` you can quickly check if your kernel module is loaded and
485 which attributes it exports. Have a look at the manpage for details.
486
487 The source code of ``lsuio`` can serve as an example for getting
488 information about an UIO device. The file ``uio_helper.c`` contains a
489 lot of functions you could use in your userspace driver code.
490
491 mmap() device memory
492 --------------------
493
494 After you made sure you've got the right device with the memory mappings
495 you need, all you have to do is to call :c:func:`mmap()` to map the
496 device's memory to userspace.
497
498 The parameter ``offset`` of the :c:func:`mmap()` call has a special
499 meaning for UIO devices: It is used to select which mapping of your
500 device you want to map. To map the memory of mapping N, you have to use
501 N times the page size as your offset::
502
503 offset = N * getpagesize();
504
505 N starts from zero, so if you've got only one memory range to map, set
506 ``offset = 0``. A drawback of this technique is that memory is always
507 mapped beginning with its start address.
508
509 Waiting for interrupts
510 ----------------------
511
512 After you successfully mapped your devices memory, you can access it
513 like an ordinary array. Usually, you will perform some initialization.
514 After that, your hardware starts working and will generate an interrupt
515 as soon as it's finished, has some data available, or needs your
516 attention because an error occurred.
517
518 ``/dev/uioX`` is a read-only file. A :c:func:`read()` will always
519 block until an interrupt occurs. There is only one legal value for the
520 ``count`` parameter of :c:func:`read()`, and that is the size of a
521 signed 32 bit integer (4). Any other value for ``count`` causes
522 :c:func:`read()` to fail. The signed 32 bit integer read is the
523 interrupt count of your device. If the value is one more than the value
524 you read the last time, everything is OK. If the difference is greater
525 than one, you missed interrupts.
526
527 You can also use :c:func:`select()` on ``/dev/uioX``.
528
529 Generic PCI UIO driver
530 ======================
531
532 The generic driver is a kernel module named uio_pci_generic. It can
533 work with any device compliant to PCI 2.3 (circa 2002) and any compliant
534 PCI Express device. Using this, you only need to write the userspace
535 driver, removing the need to write a hardware-specific kernel module.
536
537 Making the driver recognize the device
538 --------------------------------------
539
540 Since the driver does not declare any device ids, it will not get loaded
541 automatically and will not automatically bind to any devices, you must
542 load it and allocate id to the driver yourself. For example::
543
544 modprobe uio_pci_generic
545 echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id
546
547 If there already is a hardware specific kernel driver for your device,
548 the generic driver still won't bind to it, in this case if you want to
549 use the generic driver (why would you?) you'll have to manually unbind
550 the hardware specific driver and bind the generic driver, like this::
551
552 echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
553 echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind
554
555 You can verify that the device has been bound to the driver by looking
556 for it in sysfs, for example like the following::
557
558 ls -l /sys/bus/pci/devices/0000:00:19.0/driver
559
560 Which if successful should print::
561
562 .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic
563
564 Note that the generic driver will not bind to old PCI 2.2 devices. If
565 binding the device failed, run the following command::
566
567 dmesg
568
569 and look in the output for failure reasons.
570
571 Things to know about uio_pci_generic
572 ------------------------------------
573
574 Interrupts are handled using the Interrupt Disable bit in the PCI
575 command register and Interrupt Status bit in the PCI status register.
576 All devices compliant to PCI 2.3 (circa 2002) and all compliant PCI
577 Express devices should support these bits. uio_pci_generic detects
578 this support, and won't bind to devices which do not support the
579 Interrupt Disable Bit in the command register.
580
581 On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
582 This prevents the device from generating further interrupts until the
583 bit is cleared. The userspace driver should clear this bit before
584 blocking and waiting for more interrupts.
585
586 Writing userspace driver using uio_pci_generic
587 ------------------------------------------------
588
589 Userspace driver can use pci sysfs interface, or the libpci library that
590 wraps it, to talk to the device and to re-enable interrupts by writing
591 to the command register.
592
593 Example code using uio_pci_generic
594 ----------------------------------
595
596 Here is some sample userspace driver code using uio_pci_generic::
597
598 #include <stdlib.h>
599 #include <stdio.h>
600 #include <unistd.h>
601 #include <sys/types.h>
602 #include <sys/stat.h>
603 #include <fcntl.h>
604 #include <errno.h>
605
606 int main()
607 {
608 int uiofd;
609 int configfd;
610 int err;
611 int i;
612 unsigned icount;
613 unsigned char command_high;
614
615 uiofd = open("/dev/uio0", O_RDONLY);
616 if (uiofd < 0) {
617 perror("uio open:");
618 return errno;
619 }
620 configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);
621 if (configfd < 0) {
622 perror("config open:");
623 return errno;
624 }
625
626 /* Read and cache command value */
627 err = pread(configfd, &command_high, 1, 5);
628 if (err != 1) {
629 perror("command config read:");
630 return errno;
631 }
632 command_high &= ~0x4;
633
634 for(i = 0;; ++i) {
635 /* Print out a message, for debugging. */
636 if (i == 0)
637 fprintf(stderr, "Started uio test driver.\n");
638 else
639 fprintf(stderr, "Interrupts: %d\n", icount);
640
641 /****************************************/
642 /* Here we got an interrupt from the
643 device. Do something to it. */
644 /****************************************/
645
646 /* Re-enable interrupts. */
647 err = pwrite(configfd, &command_high, 1, 5);
648 if (err != 1) {
649 perror("config write:");
650 break;
651 }
652
653 /* Wait for next interrupt. */
654 err = read(uiofd, &icount, 4);
655 if (err != 4) {
656 perror("uio read:");
657 break;
658 }
659
660 }
661 return errno;
662 }
663
664 Generic Hyper-V UIO driver
665 ==========================
666
667 The generic driver is a kernel module named uio_hv_generic. It
668 supports devices on the Hyper-V VMBus similar to uio_pci_generic on
669 PCI bus.
670
671 Making the driver recognize the device
672 --------------------------------------
673
674 Since the driver does not declare any device GUID's, it will not get
675 loaded automatically and will not automatically bind to any devices, you
676 must load it and allocate id to the driver yourself. For example, to use
677 the network device class GUID::
678
679 modprobe uio_hv_generic
680 echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" > /sys/bus/vmbus/drivers/uio_hv_generic/new_id
681
682 If there already is a hardware specific kernel driver for the device,
683 the generic driver still won't bind to it, in this case if you want to
684 use the generic driver for a userspace library you'll have to manually unbind
685 the hardware specific driver and bind the generic driver, using the device specific GUID
686 like this::
687
688 echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/hv_netvsc/unbind
689 echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/uio_hv_generic/bind
690
691 You can verify that the device has been bound to the driver by looking
692 for it in sysfs, for example like the following::
693
694 ls -l /sys/bus/vmbus/devices/ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver
695
696 Which if successful should print::
697
698 .../ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -> ../../../bus/vmbus/drivers/uio_hv_generic
699
700 Things to know about uio_hv_generic
701 -----------------------------------
702
703 On each interrupt, uio_hv_generic sets the Interrupt Disable bit. This
704 prevents the device from generating further interrupts until the bit is
705 cleared. The userspace driver should clear this bit before blocking and
706 waiting for more interrupts.
707
708 When host rescinds a device, the interrupt file descriptor is marked down
709 and any reads of the interrupt file descriptor will return -EIO. Similar
710 to a closed socket or disconnected serial device.
711
712 The vmbus device regions are mapped into uio device resources:
713 0) Channel ring buffers: guest to host and host to guest
714 1) Guest to host interrupt signalling pages
715 2) Guest to host monitor page
716 3) Network receive buffer region
717 4) Network send buffer region
718
719 If a subchannel is created by a request to host, then the uio_hv_generic
720 device driver will create a sysfs binary file for the per-channel ring buffer.
721 For example::
722
723 /sys/bus/vmbus/devices/3811fe4d-0fa0-4b62-981a-74fc1084c757/channels/21/ring
724
725 Further information
726 ===================
727
728 - `OSADL homepage. <http://www.osadl.org>`_
729
730 - `Linutronix homepage. <http://www.linutronix.de>`_
731

3. 한국어 전문 번역

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

문서 소개와 UIO의 적용 범위

1-58

이 문서는 Hans-Jürgen Koch가 작성한 Userspace I/O HOWTO입니다. 알려진 번역본이 있거나 번역에 참여하려면 `[email protected]`로 연락하도록 안내합니다.

많은 장치에서는 완전한 Linux kernel driver를 만드는 일이 과도할 수 있습니다. Interrupt를 처리하고 장치 memory space에 접근하는 방법만 있으면 충분하며, 장치 제어 logic이 kernel의 다른 자원을 이용할 필요가 없다면 반드시 kernel 안에 있을 이유가 없습니다. 산업용 I/O card가 대표적인 예입니다.

이 상황을 위해 userspace I/O system, 즉 UIO가 설계되었습니다. 일반적인 산업용 I/O card는 매우 작은 kernel module만 필요하고 driver의 주요 부분은 user space에서 실행됩니다. 이 구조는 개발을 단순화하고 kernel module의 심각한 bug 위험을 줄입니다.

UIO는 범용 driver interface가 아닙니다. Networking, serial, USB처럼 기존 kernel subsystem이 잘 처리하는 장치는 UIO 대상이 아닙니다. UIO에 적합한 hardware는 mapping 가능한 memory를 갖고, 그 memory write만으로 완전히 제어할 수 있으며, 보통 interrupt를 생성하고, 표준 kernel subsystem에 속하지 않아야 합니다.

문서는 UIO code의 대부분을 작성하고 배경 정보를 제공한 Linutronix의 Thomas Gleixner와 Benedikt Spranger에게 감사를 표합니다. 문서에 관한 의견도 `[email protected]`로 보낼 수 있습니다.

UIO 적합성 판단
조건의미
mapping 가능한 memoryregister 또는 RAM을 userspace에서 접근
interrupt 발생event를 `/dev/uioX`로 전달
표준 subsystem 부재networking·serial·USB 전용 framework 대상이 아님

=======================
The Userspace I/O HOWTO
=======================

:Author: Hans-Jürgen Koch Linux developer, Linutronix
:Date:   2006-12-11

About this document
===================

Translations
------------

If you know of any translations for this document, or you are interested
in translating it, please email me [email protected].

Preface
-------

For many types of devices, creating a Linux kernel driver is overkill.
All that is really needed is some way to handle an interrupt and provide
access to the memory space of the device. The logic of controlling the
device does not necessarily have to be within the kernel, as the device
does not need to take advantage of any of other resources that the
kernel provides. One such common class of devices that are like this are
for industrial I/O cards.

To address this situation, the userspace I/O system (UIO) was designed.
For typical industrial I/O cards, only a very small kernel module is
needed. The main part of the driver will run in user space. This
simplifies development and reduces the risk of serious bugs within a
kernel module.

Please note that UIO is not an universal driver interface. Devices that
are already handled well by other kernel subsystems (like networking or
serial or USB) are no candidates for an UIO driver. Hardware that is
ideally suited for an UIO driver fulfills all of the following:

-  The device has memory that can be mapped. The device can be
   controlled completely by writing to this memory.

-  The device usually generates interrupts.

-  The device does not fit into one of the standard kernel subsystems.

Acknowledgments
---------------

I'd like to thank Thomas Gleixner and Benedikt Spranger of Linutronix,
who have not only written most of the UIO code, but also helped greatly
writing this HOWTO by giving me all kinds of background information.

Feedback
--------

Find something wrong with this document? (Or perhaps something right?) I
would love to hear from you. Please email me at [email protected].

UIO의 기본 동작

59-127

UIO를 사용하면 유지할 kernel module은 작아지고, driver의 주요 부분은 익숙한 tool과 library를 사용할 수 있는 user space에서 개발할 수 있습니다. Userspace driver의 bug가 kernel을 중단시키지 않으며 kernel을 다시 compile하지 않고도 driver를 갱신할 수 있습니다.

각 UIO device에는 `/dev/uio0`, `/dev/uio1` 같은 device file과 여러 sysfs attribute file이 제공됩니다. `/dev/uioX`의 address space는 `mmap()`으로 mapping해 card register나 RAM 위치에 접근합니다.

Interrupt는 `/dev/uioX`를 읽어 처리합니다. Blocking `read()`는 interrupt가 발생하면 반환하며 `select()`로 기다릴 수도 있습니다. 읽은 integer는 누적 interrupt count이므로 이전 값과 비교해 놓친 interrupt가 있는지 판단할 수 있습니다.

내부 interrupt source가 여러 개지만 IRQ mask와 status register가 분리되지 않은 hardware에서는 kernel handler가 chip register를 변경하면 userspace가 원인을 판별하기 어려울 수 있습니다. Kernel이 IRQ line 자체를 disable하면 chip register를 보존할 수 있지만 userspace는 interrupt를 다시 enable할 방법이 필요합니다. Combined status/acknowledge register의 read-modify-write도 동시에 새 interrupt가 오면 race가 생길 수 있습니다.

이를 위해 UIO는 `write()`도 제공합니다. `/dev/uioX`에 보통 0 또는 1인 32-bit 값을 쓰면 driver의 `irqcontrol()`을 호출해 interrupt를 disable 또는 enable합니다. Driver가 `irqcontrol()`을 구현하지 않으면 `write()`는 `-ENOSYS`를 반환합니다. 단일 source이거나 mask와 status register가 분리된 hardware는 이 기능을 무시할 수 있습니다.

Custom kernel module은 자체 interrupt handler를 제공할 수 있고 built-in handler가 이를 자동으로 호출합니다. Interrupt가 없는 polling 장치는 timer event handler에서 `uio_event_notify()`를 호출해 설정 가능한 주기로 interrupt를 모의할 수 있습니다.

Driver variable을 읽고 쓰는 attribute는 sysfs file로 노출됩니다. Custom kernel module은 UIO driver가 소유한 device에 자체 attribute를 추가할 수 있지만 현재 UIO device 자체에는 추가할 수 없습니다.

UIO event 처리
`mmap(/dev/uioX)`device register·RAM 접근
interrupt 발생blocking `read()` 또는 `select()` 반환
누적 interrupt count누락 여부 확인
`write(/dev/uioX)``irqcontrol()`로 enable·disable

Memory access와 interrupt 전달, userspace 제어의 기본 경로입니다.

About UIO
=========

If you use UIO for your card's driver, here's what you get:

-  only one small kernel module to write and maintain.

-  develop the main part of your driver in user space, with all the
   tools and libraries you're used to.

-  bugs in your driver won't crash the kernel.

-  updates of your driver can take place without recompiling the kernel.

How UIO works
-------------

Each UIO device is accessed through a device file and several sysfs
attribute files. The device file will be called ``/dev/uio0`` for the
first device, and ``/dev/uio1``, ``/dev/uio2`` and so on for subsequent
devices.

``/dev/uioX`` is used to access the address space of the card. Just use
:c:func:`mmap()` to access registers or RAM locations of your card.

Interrupts are handled by reading from ``/dev/uioX``. A blocking
:c:func:`read()` from ``/dev/uioX`` will return as soon as an
interrupt occurs. You can also use :c:func:`select()` on
``/dev/uioX`` to wait for an interrupt. The integer value read from
``/dev/uioX`` represents the total interrupt count. You can use this
number to figure out if you missed some interrupts.

For some hardware that has more than one interrupt source internally,
but not separate IRQ mask and status registers, there might be
situations where userspace cannot determine what the interrupt source
was if the kernel handler disables them by writing to the chip's IRQ
register. In such a case, the kernel has to disable the IRQ completely
to leave the chip's register untouched. Now the userspace part can
determine the cause of the interrupt, but it cannot re-enable
interrupts. Another cornercase is chips where re-enabling interrupts is
a read-modify-write operation to a combined IRQ status/acknowledge
register. This would be racy if a new interrupt occurred simultaneously.

To address these problems, UIO also implements a write() function. It is
normally not used and can be ignored for hardware that has only a single
interrupt source or has separate IRQ mask and status registers. If you
need it, however, a write to ``/dev/uioX`` will call the
:c:func:`irqcontrol()` function implemented by the driver. You have
to write a 32-bit value that is usually either 0 or 1 to disable or
enable interrupts. If a driver does not implement
:c:func:`irqcontrol()`, :c:func:`write()` will return with
``-ENOSYS``.

To handle interrupts properly, your custom kernel module can provide its
own interrupt handler. It will automatically be called by the built-in
handler.

For cards that don't generate interrupts but need to be polled, there is
the possibility to set up a timer that triggers the interrupt handler at
configurable time intervals. This interrupt simulation is done by
calling :c:func:`uio_event_notify()` from the timer's event
handler.

Each driver provides attributes that are used to read or write
variables. These attributes are accessible through sysfs files. A custom
kernel driver module can add its own attributes to the device owned by
the uio driver, but not added to the UIO device itself at this time.
This might change in the future if it would be found to be useful.

표준 attribute, memory map과 port region

128-208

UIO framework는 `name`, `version`, `event` 표준 attribute를 제공합니다. `name`은 device 이름이며 kernel module 이름을 사용하는 것이 권장됩니다. `version`은 userspace가 kernel module version 차이를 처리할 수 있게 하는 문자열이고, `event`는 마지막 device node read 이후 driver가 처리한 총 interrupt 수입니다.

이 attribute들은 `/sys/class/uio/uioX` 아래에 나타납니다. 이 경로는 실제 directory가 아니라 symlink일 수 있으므로 userspace code는 두 경우를 모두 처리해야 합니다.

하나의 UIO device는 하나 이상의 memory region을 mapping 대상으로 제공할 수 있습니다. 첫 mapping은 `/sys/class/uio/uioX/maps/map0/`, 이후 mapping은 `map1/`, `map2/`에 나타나며 size가 0인 mapping의 directory는 생성되지 않습니다.

각 `mapX/`에는 read-only `name`, `addr`, `size`, `offset`이 있습니다. `name`은 선택적 식별자, `addr`은 mapping 가능한 memory address, `size`는 byte 단위 크기입니다. `offset`은 `mmap()` 반환 pointer에서 실제 device memory까지 더해야 할 byte offset입니다. `mmap()` pointer는 항상 page aligned이므로 장치 memory가 page aligned가 아닐 때 특히 중요하며 항상 더하는 방식이 권장됩니다.

Userspace에서는 `mmap()`의 offset parameter로 mapping을 선택합니다. Mapping N은 `N * getpagesize()`를 offset으로 사용합니다.

x86 ioport처럼 이 방식으로 mapping할 수 없는 memory-like region도 있습니다. x86 userspace는 `ioperm()`, `iopl()`, `inb()`, `outb()` 같은 함수로 접근하지만 일반 `maps/`에는 나타나지 않습니다.

Port 정보를 userspace에 전달하려는 driver가 있으면 `/sys/class/uio/uioX/portio/`가 생기고 그 아래에 `port0`, `port1` 등이 생성됩니다. 각 `portX/`의 read-only file은 선택적 식별자인 `name`, 첫 port인 `start`, port 수인 `size`, port 종류 문자열인 `porttype`입니다.

UIO sysfs 구조
경로·항목내용
`/sys/class/uio/uioX/{name,version,event}`device identity와 interrupt count
`maps/mapX/{name,addr,size,offset}`memory mapping 정보
`portio/portX/{name,start,size,porttype}`mapping 불가능한 port region 정보

The following standard attributes are provided by the UIO framework:

-  ``name``: The name of your device. It is recommended to use the name
   of your kernel module for this.

-  ``version``: A version string defined by your driver. This allows the
   user space part of your driver to deal with different versions of the
   kernel module.

-  ``event``: The total number of interrupts handled by the driver since
   the last time the device node was read.

These attributes appear under the ``/sys/class/uio/uioX`` directory.
Please note that this directory might be a symlink, and not a real
directory. Any userspace code that accesses it must be able to handle
this.

Each UIO device can make one or more memory regions available for memory
mapping. This is necessary because some industrial I/O cards require
access to more than one PCI memory region in a driver.

Each mapping has its own directory in sysfs, the first mapping appears
as ``/sys/class/uio/uioX/maps/map0/``. Subsequent mappings create
directories ``map1/``, ``map2/``, and so on. These directories will only
appear if the size of the mapping is not 0.

Each ``mapX/`` directory contains four read-only files that show
attributes of the memory:

-  ``name``: A string identifier for this mapping. This is optional, the
   string can be empty. Drivers can set this to make it easier for
   userspace to find the correct mapping.

-  ``addr``: The address of memory that can be mapped.

-  ``size``: The size, in bytes, of the memory pointed to by addr.

-  ``offset``: The offset, in bytes, that has to be added to the pointer
   returned by :c:func:`mmap()` to get to the actual device memory.
   This is important if the device's memory is not page aligned.
   Remember that pointers returned by :c:func:`mmap()` are always
   page aligned, so it is good style to always add this offset.

From userspace, the different mappings are distinguished by adjusting
the ``offset`` parameter of the :c:func:`mmap()` call. To map the
memory of mapping N, you have to use N times the page size as your
offset::

    offset = N * getpagesize();

Sometimes there is hardware with memory-like regions that can not be
mapped with the technique described here, but there are still ways to
access them from userspace. The most common example are x86 ioports. On
x86 systems, userspace can access these ioports using
:c:func:`ioperm()`, :c:func:`iopl()`, :c:func:`inb()`,
:c:func:`outb()`, and similar functions.

Since these ioport regions can not be mapped, they will not appear under
``/sys/class/uio/uioX/maps/`` like the normal memory described above.
Without information about the port regions a hardware has to offer, it
becomes difficult for the userspace part of the driver to find out which
ports belong to which UIO device.

To address this situation, the new directory
``/sys/class/uio/uioX/portio/`` was added. It only exists if the driver
wants to pass information about one or more port regions to userspace.
If that is the case, subdirectories named ``port0``, ``port1``, and so
on, will appear underneath ``/sys/class/uio/uioX/portio/``.

Each ``portX/`` directory contains four read-only files that show name,
start, size, and type of the port region:

-  ``name``: A string identifier for this port region. The string is
   optional and can be empty. Drivers can set it to make it easier for
   userspace to find a certain port region.

-  ``start``: The first port of this region.

-  ``size``: The number of ports in this region.

-  ``porttype``: A string describing the type of port.

Kernel module과 `struct uio_info`

209-267

자체 kernel module을 작성할 때는 `uio_cif.c`를 예제로 참고할 수 있습니다. `struct uio_info`는 framework에 driver의 세부 정보를 전달하며 일부 member는 필수이고 나머지는 선택 사항입니다.

필수 `name`은 sysfs에 표시할 driver 이름이고 module 이름 사용이 권장됩니다. 필수 `version`은 `/sys/class/uio/uioX/version`에 나타납니다. `mem[MAX_UIO_MAPS]`는 `mmap()` 가능한 memory가 있을 때 필요하고 각 mapping마다 `struct uio_mem` 하나를 채웁니다. `port[MAX_UIO_PORTS_REGIONS]`는 ioport 정보를 userspace에 전달할 때 필요하며 region마다 `struct uio_port`를 채웁니다.

필수 `irq`에는 초기화 중 알아낸 hardware IRQ number를 넣습니다. Hardware interrupt가 아닌 방식으로 handler를 trigger하려면 `UIO_IRQ_CUSTOM`, interrupt가 전혀 없으면 `UIO_IRQ_NONE`을 사용할 수 있습니다. Hardware IRQ number를 지정했다면 `irq_flags`가 필수이며 `request_irq()`에 전달됩니다.

선택적 `mmap` callback은 built-in mapping 대신 특별한 `mmap()`이 필요할 때 사용합니다. 선택적 `open`은 device가 실제 사용될 때만 interrupt를 enable하는 등의 동작에 쓰며, custom `open`을 정의하면 보통 `release`도 함께 정의합니다.

선택적 `irqcontrol` callback은 userspace가 `/dev/uioX`에 값을 써서 interrupt를 제어해야 할 때 구현합니다. `irq_on`은 disable할 때 0, enable할 때 1입니다.

주요 `struct uio_info` member
member필수 여부와 역할
`name`, `version`필수, sysfs identity
`mem[]`, `port[]`해당 region을 제공할 때 필수
`irq`, `irq_flags`interrupt 종류와 `request_irq()` flag
`mmap`, `open`, `release`선택적 lifecycle callback
`irqcontrol`선택적 userspace interrupt 제어


Writing your own kernel module
==============================

Please have a look at ``uio_cif.c`` as an example. The following
paragraphs explain the different sections of this file.

struct uio_info
---------------

This structure tells the framework the details of your driver, Some of
the members are required, others are optional.

-  ``const char *name``: Required. The name of your driver as it will
   appear in sysfs. I recommend using the name of your module for this.

-  ``const char *version``: Required. This string appears in
   ``/sys/class/uio/uioX/version``.

-  ``struct uio_mem mem[ MAX_UIO_MAPS ]``: Required if you have memory
   that can be mapped with :c:func:`mmap()`. For each mapping you
   need to fill one of the ``uio_mem`` structures. See the description
   below for details.

-  ``struct uio_port port[ MAX_UIO_PORTS_REGIONS ]``: Required if you
   want to pass information about ioports to userspace. For each port
   region you need to fill one of the ``uio_port`` structures. See the
   description below for details.

-  ``long irq``: Required. If your hardware generates an interrupt, it's
   your modules task to determine the irq number during initialization.
   If you don't have a hardware generated interrupt but want to trigger
   the interrupt handler in some other way, set ``irq`` to
   ``UIO_IRQ_CUSTOM``. If you had no interrupt at all, you could set
   ``irq`` to ``UIO_IRQ_NONE``, though this rarely makes sense.

-  ``unsigned long irq_flags``: Required if you've set ``irq`` to a
   hardware interrupt number. The flags given here will be used in the
   call to :c:func:`request_irq()`.

-  ``int (*mmap)(struct uio_info *info, struct vm_area_struct *vma)``:
   Optional. If you need a special :c:func:`mmap()`
   function, you can set it here. If this pointer is not NULL, your
   :c:func:`mmap()` will be called instead of the built-in one.

-  ``int (*open)(struct uio_info *info, struct inode *inode)``:
   Optional. You might want to have your own :c:func:`open()`,
   e.g. to enable interrupts only when your device is actually used.

-  ``int (*release)(struct uio_info *info, struct inode *inode)``:
   Optional. If you define your own :c:func:`open()`, you will
   probably also want a custom :c:func:`release()` function.

-  ``int (*irqcontrol)(struct uio_info *info, s32 irq_on)``:
   Optional. If you need to be able to enable or disable interrupts
   from userspace by writing to ``/dev/uioX``, you can implement this
   function. The parameter ``irq_on`` will be 0 to disable interrupts
   and 1 to enable them.

`struct uio_mem`과 `struct uio_port`

268-323

Userspace로 mapping할 각 memory region에는 `mem[]`의 `struct uio_mem`을 설정합니다. 선택적 `name`은 sysfs 식별자로 나타납니다. 사용 중인 mapping의 `memtype`은 필수이며 card의 physical memory에는 `UIO_MEM_PHYS`, `__get_free_pages()` 등으로 할당한 logical memory에는 `UIO_MEM_LOGICAL`, virtual memory에는 `UIO_MEM_VIRTUAL`을 사용합니다.

사용 중인 mapping의 `addr`에는 sysfs에 표시할 memory block address를 넣고 `size`에는 byte 크기를 넣습니다. Size가 0이면 사용하지 않는 mapping으로 간주되므로 모든 미사용 mapping의 `size`를 반드시 0으로 초기화해야 합니다.

Kernel module 내부에서 `ioremap()` 등으로 얻은 address는 userspace에 mapping할 수 없으므로 `addr`에 저장하면 안 됩니다. 이런 address는 `internal_addr`에 보관합니다. `struct uio_mem`의 `map` element는 framework가 sysfs file을 설정하는 내부 필드이므로 수정하지 않습니다.

Mapping할 수 없는 port region 정보를 제공하려면 `port[]`의 `struct uio_port`를 설정합니다. 필수 `porttype`에는 미리 정의된 상수를 사용하며 x86 ioport는 `UIO_PORT_X86`입니다. 사용 중인 region의 `start`는 첫 port number이고 `size`는 port 수입니다. Size 0은 미사용을 뜻하므로 모든 미사용 region을 0으로 초기화합니다. `portio` element는 framework 내부용이므로 수정하지 않습니다.

UIO region 구조체
구조체application-owned fieldframework-owned field
`struct uio_mem``name`, `memtype`, `addr`, `size`, `internal_addr``map`
`struct uio_port``porttype`, `start`, `size``portio`

Usually, your device will have one or more memory regions that can be
mapped to user space. For each region, you have to set up a
``struct uio_mem`` in the ``mem[]`` array. Here's a description of the
fields of ``struct uio_mem``:

-  ``const char *name``: Optional. Set this to help identify the memory
   region, it will show up in the corresponding sysfs node.

-  ``int memtype``: Required if the mapping is used. Set this to
   ``UIO_MEM_PHYS`` if you have physical memory on your card to be
   mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated
   with :c:func:`__get_free_pages()` but not kmalloc()). There's also
   ``UIO_MEM_VIRTUAL`` for virtual memory.

-  ``phys_addr_t addr``: Required if the mapping is used. Fill in the
   address of your memory block. This address is the one that appears in
   sysfs.

-  ``resource_size_t size``: Fill in the size of the memory block that
   ``addr`` points to. If ``size`` is zero, the mapping is considered
   unused. Note that you *must* initialize ``size`` with zero for all
   unused mappings.

-  ``void *internal_addr``: If you have to access this memory region
   from within your kernel module, you will want to map it internally by
   using something like :c:func:`ioremap()`. Addresses returned by
   this function cannot be mapped to user space, so you must not store
   it in ``addr``. Use ``internal_addr`` instead to remember such an
   address.

Please do not touch the ``map`` element of ``struct uio_mem``! It is
used by the UIO framework to set up sysfs files for this mapping. Simply
leave it alone.

Sometimes, your device can have one or more port regions which can not
be mapped to userspace. But if there are other possibilities for
userspace to access these ports, it makes sense to make information
about the ports available in sysfs. For each region, you have to set up
a ``struct uio_port`` in the ``port[]`` array. Here's a description of
the fields of ``struct uio_port``:

-  ``char *porttype``: Required. Set this to one of the predefined
   constants. Use ``UIO_PORT_X86`` for the ioports found in x86
   architectures.

-  ``unsigned long start``: Required if the port region is used. Fill in
   the number of the first port of this region.

-  ``unsigned long size``: Fill in the number of ports in this region.
   If ``size`` is zero, the region is considered unused. Note that you
   *must* initialize ``size`` with zero for all unused regions.

Please do not touch the ``portio`` element of ``struct uio_port``! It is
used internally by the UIO framework to set up sysfs files for this
region. Simply leave it alone.

Interrupt handler 작성

324-358

Interrupt handler가 해야 할 일은 hardware와 처리 방식에 따라 다릅니다. Kernel interrupt handler의 code는 가능한 한 작게 유지해야 하며 interrupt 뒤 반드시 수행할 hardware action이 없다면 비어 있어도 됩니다.

반대로 interrupt마다 hardware가 반드시 요구하는 action은 kernel module에서 수행해야 합니다. Userspace program은 언제든 종료될 수 있으므로 필요한 interrupt 처리를 userspace에만 의존하면 hardware가 올바르지 않은 상태로 남을 수 있습니다.

Interrupt마다 hardware data를 읽어 kernel memory에 buffer하면 userspace program이 interrupt를 놓쳤을 때 data loss를 피할 수 있습니다.

가능하면 shared interrupt를 지원해야 합니다. Hardware가 interrupt를 발생시켰는지 status register로 판별할 수 있을 때만 공유할 수 있습니다. 자기 hardware의 IRQ bit가 설정됐으면 필요한 작업 뒤 `IRQ_HANDLED`를 반환하고, 원인이 아니면 아무 작업 없이 `IRQ_NONE`을 반환해 kernel이 다음 handler를 호출하게 합니다. Shared interrupt를 지원하지 않으면 free IRQ가 없는 PC에서 card가 동작하지 않을 수 있습니다.

Shared IRQ 판별
interrupt status 확인자기 hardware 여부 판별
자기 hardware가 원인처리 후 `IRQ_HANDLED`
다른 device가 원인`IRQ_NONE`으로 다음 handler 허용

Handler가 interrupt source를 확인한 뒤 반환값을 선택합니다.

Adding an interrupt handler
---------------------------

What you need to do in your interrupt handler depends on your hardware
and on how you want to handle it. You should try to keep the amount of
code in your kernel interrupt handler low. If your hardware requires no
action that you *have* to perform after each interrupt, then your
handler can be empty.

If, on the other hand, your hardware *needs* some action to be performed
after each interrupt, then you *must* do it in your kernel module. Note
that you cannot rely on the userspace part of your driver. Your
userspace program can terminate at any time, possibly leaving your
hardware in a state where proper interrupt handling is still required.

There might also be applications where you want to read data from your
hardware at each interrupt and buffer it in a piece of kernel memory
you've allocated for that purpose. With this technique you could avoid
loss of data if your userspace program misses an interrupt.

A note on shared interrupts: Your driver should support interrupt
sharing whenever this is possible. It is possible if and only if your
driver can detect whether your hardware has triggered the interrupt or
not. This is usually done by looking at an interrupt status register. If
your driver sees that the IRQ bit is actually set, it will perform its
actions, and the handler returns IRQ_HANDLED. If the driver detects
that it was not your hardware that caused the interrupt, it will do
nothing and return IRQ_NONE, allowing the kernel to call the next
possible interrupt handler.

If you decide not to support shared interrupts, your card won't work in
computers with no free interrupts. As this frequently happens on the PC
platform, you can save yourself a lot of trouble by supporting interrupt
sharing.

Platform device에서 `uio_pdrv` 사용

359-381

Platform device용 UIO driver는 많은 경우 generic 방식으로 처리할 수 있습니다. `struct platform_device`를 정의하는 곳에서 interrupt handler를 구현하고 `struct uio_info`를 채운 뒤 그 pointer를 platform device의 `platform_data`로 사용합니다.

Memory mapping의 address와 size를 담은 `struct resource` array도 준비하고 `struct platform_device`의 `.resource`와 `.num_resources`로 전달합니다.

Generic UIO platform driver를 사용하려면 `struct platform_device`의 `.name`을 `"uio_pdrv"`로 설정합니다. Driver는 resource에 따라 `mem[]`을 채우고 device를 등록합니다. 별도 driver를 만들지 않고 어차피 수정할 platform device 정의 file만 편집할 수 있다는 장점이 있습니다.

`uio_pdrv` 설정
항목설정
`.platform_data`채운 `struct uio_info` pointer
`.resource`, `.num_resources`memory mapping resource array
`.name``"uio_pdrv"`

Using uio_pdrv for platform devices
-----------------------------------

In many cases, UIO drivers for platform devices can be handled in a
generic way. In the same place where you define your
``struct platform_device``, you simply also implement your interrupt
handler and fill your ``struct uio_info``. A pointer to this
``struct uio_info`` is then used as ``platform_data`` for your platform
device.

You also need to set up an array of ``struct resource`` containing
addresses and sizes of your memory mappings. This information is passed
to the driver using the ``.resource`` and ``.num_resources`` elements of
``struct platform_device``.

You now have to set the ``.name`` element of ``struct platform_device``
to ``"uio_pdrv"`` to use the generic UIO platform device driver. This
driver will fill the ``mem[]`` array according to the resources given,
and register the device.

The advantage of this approach is that you only have to edit a file you
need to edit anyway. You do not have to create an extra driver.

`uio_pdrv_genirq`와 generic interrupt

382-417

Embedded device처럼 IRQ pin이 전용 interrupt line에 연결되어 공유되지 않음이 확실하면 `uio_pdrv`보다 더 일반화된 `uio_pdrv_genirq`를 사용할 수 있습니다.

설정은 `uio_pdrv`와 같지만 interrupt handler를 구현하지 않습니다. `struct uio_info`의 `.handler`는 `NULL`이어야 하고 `.irq_flags`에는 `IRQF_SHARED`를 넣으면 안 됩니다. `struct platform_device.name`은 `"uio_pdrv_genirq"`로 설정합니다.

Generic handler는 `disable_irq_nosync()`로 interrupt line을 disable합니다. Userspace는 작업을 마친 뒤 UIO device file에 `0x00000001`을 써서 다시 enable할 수 있습니다. Driver가 이를 위한 `irq_control()`을 이미 구현하므로 custom callback을 구현하면 안 됩니다.

이 방식은 handler code뿐 아니라 chip internal register 지식도 줄입니다. Kernel driver 쪽에는 chip IRQ pin이 연결된 IRQ number만 필요합니다.

Device tree system에서는 처리할 node의 `compatible` 문자열을 `of_id` module parameter로 지정해 probe합니다. 기본 UIO 이름은 unit address를 뺀 node name이며 DT node의 `linux,uio-name` property로 custom name을 지정할 수 있습니다.

`uio_pdrv_genirq` interrupt
IRQ 발생`disable_irq_nosync()`
userspace 처리device memory 작업
`0x00000001` writeinterrupt re-enable

Generic handler와 userspace 사이의 disable·reenable 순서입니다.

Using uio_pdrv_genirq for platform devices
------------------------------------------

Especially in embedded devices, you frequently find chips where the irq
pin is tied to its own dedicated interrupt line. In such cases, where
you can be really sure the interrupt is not shared, we can take the
concept of ``uio_pdrv`` one step further and use a generic interrupt
handler. That's what ``uio_pdrv_genirq`` does.

The setup for this driver is the same as described above for
``uio_pdrv``, except that you do not implement an interrupt handler. The
``.handler`` element of ``struct uio_info`` must remain ``NULL``. The
``.irq_flags`` element must not contain ``IRQF_SHARED``.

You will set the ``.name`` element of ``struct platform_device`` to
``"uio_pdrv_genirq"`` to use this driver.

The generic interrupt handler of ``uio_pdrv_genirq`` will simply disable
the interrupt line using :c:func:`disable_irq_nosync()`. After
doing its work, userspace can reenable the interrupt by writing
0x00000001 to the UIO device file. The driver already implements an
:c:func:`irq_control()` to make this possible, you must not
implement your own.

Using ``uio_pdrv_genirq`` not only saves a few lines of interrupt
handler code. You also do not need to know anything about the chip's
internal registers to create the kernel part of the driver. All you need
to know is the irq number of the pin the chip is connected to.

When used in a device-tree enabled system, the driver needs to be
probed with the ``"of_id"`` module parameter set to the ``"compatible"``
string of the node the driver is supposed to handle. By default, the
node's name (without the unit address) is exposed as name for the
UIO device in userspace. To set a custom name, a property named
``"linux,uio-name"`` may be specified in the DT node.

Dynamic memory용 `uio_dmem_genirq`

418-458

Static memory range뿐 아니라 dma-mapping API가 제공하는 memory처럼 동적으로 할당한 region을 userspace driver에서 접근해야 할 수 있습니다. `uio_dmem_genirq`가 이 기능을 제공하며 interrupt 설정과 처리는 `uio_pdrv_genirq`와 비슷합니다.

Driver를 사용하려면 `struct platform_device.name`을 `"uio_dmem_genirq"`로 설정하고 `.platform_data`에는 `struct uio_dmem_genirq_pdata`를 채웁니다.

`uioinfo`는 `uio_pdrv_genirq`에서 쓰는 것과 같은 `struct uio_info`입니다. `dynamic_region_sizes`는 userspace에 mapping할 dynamic memory region size 목록이고 `num_dynamic_regions`는 그 array의 element 수입니다.

Dynamic region은 platform resource 뒤에 `mem[]`으로 추가되므로 static과 dynamic region 합계가 `MAX_UIO_MAPS`를 넘으면 안 됩니다.

Dynamic memory는 `/dev/uioX`를 open할 때 할당되고 `/sys/class/uio/uioX/maps/mapY/*`에서 sysfs 정보가 보입니다. Device file을 close하면 해제되며 아무 process도 file을 open하지 않았을 때 userspace에 반환되는 address는 `~0`입니다.

`uio_dmem_genirq_pdata`
member역할
`uioinfo`공통 `struct uio_info`
`dynamic_region_sizes`dynamic region size 목록
`num_dynamic_regions`목록 element 수

Using uio_dmem_genirq for platform devices
------------------------------------------

In addition to statically allocated memory ranges, they may also be a
desire to use dynamically allocated regions in a user space driver. In
particular, being able to access memory made available through the
dma-mapping API, may be particularly useful. The ``uio_dmem_genirq``
driver provides a way to accomplish this.

This driver is used in a similar manner to the ``"uio_pdrv_genirq"``
driver with respect to interrupt configuration and handling.

Set the ``.name`` element of ``struct platform_device`` to
``"uio_dmem_genirq"`` to use this driver.

When using this driver, fill in the ``.platform_data`` element of
``struct platform_device``, which is of type
``struct uio_dmem_genirq_pdata`` and which contains the following
elements:

-  ``struct uio_info uioinfo``: The same structure used as the
   ``uio_pdrv_genirq`` platform data

-  ``unsigned int *dynamic_region_sizes``: Pointer to list of sizes of
   dynamic memory regions to be mapped into user space.

-  ``unsigned int num_dynamic_regions``: Number of elements in
   ``dynamic_region_sizes`` array.

The dynamic regions defined in the platform data will be appended to the
`` mem[] `` array after the platform device resources, which implies
that the total number of static and dynamic memory regions cannot exceed
``MAX_UIO_MAPS``.

The dynamic memory regions will be allocated when the UIO device file,
``/dev/uioX`` is opened. Similar to static memory resources, the memory
region information for dynamic regions is then visible via sysfs at
``/sys/class/uio/uioX/maps/mapY/*``. The dynamic memory regions will be
freed when the UIO device file is closed. When no processes are holding
the device file open, the address returned to userspace is ~0.

Userspace driver, device 확인과 `mmap()`

459-508

Hardware용 kernel module이 동작하면 userspace driver를 작성할 수 있습니다. 특별한 library는 필요하지 않고 일반적인 language, floating point, 평소 userspace application에 쓰는 tool과 library를 모두 사용할 수 있습니다.

모든 UIO device 정보는 sysfs에 있습니다. Driver는 먼저 `name`과 `version`을 확인해 올바른 device와 예상한 kernel driver version인지 검증해야 합니다. 필요한 memory mapping이 존재하고 size도 예상과 일치하는지 확인합니다.

`lsuio` tool은 UIO device와 attribute를 나열합니다. `http://www.osadl.org/projects/downloads/UIO/user/`에서 구할 수 있으며 kernel module load 여부와 export된 attribute를 빠르게 점검할 수 있습니다. Source의 `uio_helper.c`는 userspace driver에서 재사용할 수 있는 UIO 정보 조회 함수 예제를 제공합니다.

Device와 mapping을 확인한 뒤 `mmap()`으로 device memory를 userspace에 mapping합니다. UIO에서 `mmap()`의 `offset`은 선택할 mapping을 뜻하며 mapping N은 `N * getpagesize()`를 사용합니다. N은 0부터 시작하므로 하나뿐인 mapping은 `offset = 0`입니다. 이 방식은 memory가 항상 해당 region의 시작 address부터 mapping된다는 제약이 있습니다.

Userspace 초기 검증
순서확인 항목
1sysfs `name`, `version`
2mapping 존재 여부와 `size`
3`offset = N * getpagesize()` 계산
4`mmap()`으로 device memory 연결

Writing a driver in userspace
=============================

Once you have a working kernel module for your hardware, you can write
the userspace part of your driver. You don't need any special libraries,
your driver can be written in any reasonable language, you can use
floating point numbers and so on. In short, you can use all the tools
and libraries you'd normally use for writing a userspace application.

Getting information about your UIO device
-----------------------------------------

Information about all UIO devices is available in sysfs. The first thing
you should do in your driver is check ``name`` and ``version`` to make
sure you're talking to the right device and that its kernel driver has
the version you expect.

You should also make sure that the memory mapping you need exists and
has the size you expect.

There is a tool called ``lsuio`` that lists UIO devices and their
attributes. It is available here:

http://www.osadl.org/projects/downloads/UIO/user/

With ``lsuio`` you can quickly check if your kernel module is loaded and
which attributes it exports. Have a look at the manpage for details.

The source code of ``lsuio`` can serve as an example for getting
information about an UIO device. The file ``uio_helper.c`` contains a
lot of functions you could use in your userspace driver code.

mmap() device memory
--------------------

After you made sure you've got the right device with the memory mappings
you need, all you have to do is to call :c:func:`mmap()` to map the
device's memory to userspace.

The parameter ``offset`` of the :c:func:`mmap()` call has a special
meaning for UIO devices: It is used to select which mapping of your
device you want to map. To map the memory of mapping N, you have to use
N times the page size as your offset::

        offset = N * getpagesize();

N starts from zero, so if you've got only one memory range to map, set
``offset = 0``. A drawback of this technique is that memory is always
mapped beginning with its start address.

Interrupt 기다리기

509-528

Device memory를 mapping하면 일반 array처럼 접근해 초기화할 수 있습니다. Hardware는 작업 완료, data 준비 또는 error 발생 시 interrupt를 생성합니다.

`/dev/uioX`를 `read()`하면 interrupt가 올 때까지 block됩니다. `count` parameter의 유일한 합법 값은 signed 32-bit integer 크기인 4이며 다른 값은 실패합니다. 읽은 32-bit integer는 device의 누적 interrupt count입니다. 이전 값보다 1 크면 정상이고 차이가 1보다 크면 interrupt를 놓친 것입니다. `/dev/uioX`에 `select()`를 사용할 수도 있습니다.

Interrupt count 확인
`read(fd, &count, 4)`interrupt까지 block
현재 count - 이전 count = 1정상
차이가 1보다 큼interrupt 누락

Blocking read 결과로 누락 여부를 판단합니다.

Waiting for interrupts
----------------------

After you successfully mapped your devices memory, you can access it
like an ordinary array. Usually, you will perform some initialization.
After that, your hardware starts working and will generate an interrupt
as soon as it's finished, has some data available, or needs your
attention because an error occurred.

``/dev/uioX`` is a read-only file. A :c:func:`read()` will always
block until an interrupt occurs. There is only one legal value for the
``count`` parameter of :c:func:`read()`, and that is the size of a
signed 32 bit integer (4). Any other value for ``count`` causes
:c:func:`read()` to fail. The signed 32 bit integer read is the
interrupt count of your device. If the value is one more than the value
you read the last time, everything is OK. If the difference is greater
than one, you missed interrupts.

You can also use :c:func:`select()` on ``/dev/uioX``.

Generic PCI UIO driver

529-592

`uio_pci_generic` kernel module은 PCI 2.3 호환 device와 호환 PCI Express device에서 동작합니다. Hardware-specific kernel module 없이 userspace driver만 작성할 수 있습니다.

Driver가 device ID를 선언하지 않으므로 자동 load·bind되지 않습니다. `modprobe uio_pci_generic` 뒤 vendor와 device ID를 `/sys/bus/pci/drivers/uio_pci_generic/new_id`에 써서 직접 할당합니다.

Hardware-specific driver가 이미 bind되어 있으면 먼저 해당 driver에서 device를 unbind한 뒤 `uio_pci_generic`에 bind해야 합니다. `/sys/bus/pci/devices/.../driver` symlink로 성공 여부를 확인할 수 있습니다. PCI 2.2 같은 오래된 device에는 bind하지 않으며 실패 이유는 `dmesg`에서 확인합니다.

Interrupt 처리는 PCI command register의 Interrupt Disable bit와 PCI status register의 Interrupt Status bit를 사용합니다. PCI 2.3 및 PCI Express 호환 device는 이를 지원해야 하며 `uio_pci_generic`은 Interrupt Disable bit 지원이 없는 device에는 bind하지 않습니다.

Interrupt마다 `uio_pci_generic`이 Interrupt Disable bit를 설정해 추가 interrupt를 막습니다. Userspace driver는 다음 interrupt를 block해 기다리기 전에 이 bit를 clear해야 합니다. PCI sysfs interface 또는 이를 감싼 `libpci`로 device와 통신하고 command register를 써서 interrupt를 다시 enable할 수 있습니다.

`uio_pci_generic` 준비
module load와 `new_id`generic driver에 ID 등록
필요 시 기존 driver unbind`uio_pci_generic` bind
interrupt 발생Interrupt Disable bit 설정
userspace command register writebit clear 후 다음 interrupt 대기

수동 ID 등록부터 interrupt re-enable까지의 핵심 순서입니다.

Generic PCI UIO driver
======================

The generic driver is a kernel module named uio_pci_generic. It can
work with any device compliant to PCI 2.3 (circa 2002) and any compliant
PCI Express device. Using this, you only need to write the userspace
driver, removing the need to write a hardware-specific kernel module.

Making the driver recognize the device
--------------------------------------

Since the driver does not declare any device ids, it will not get loaded
automatically and will not automatically bind to any devices, you must
load it and allocate id to the driver yourself. For example::

     modprobe uio_pci_generic
     echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id

If there already is a hardware specific kernel driver for your device,
the generic driver still won't bind to it, in this case if you want to
use the generic driver (why would you?) you'll have to manually unbind
the hardware specific driver and bind the generic driver, like this::

        echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
        echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind

You can verify that the device has been bound to the driver by looking
for it in sysfs, for example like the following::

        ls -l /sys/bus/pci/devices/0000:00:19.0/driver

Which if successful should print::

      .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic

Note that the generic driver will not bind to old PCI 2.2 devices. If
binding the device failed, run the following command::

      dmesg

and look in the output for failure reasons.

Things to know about uio_pci_generic
------------------------------------

Interrupts are handled using the Interrupt Disable bit in the PCI
command register and Interrupt Status bit in the PCI status register.
All devices compliant to PCI 2.3 (circa 2002) and all compliant PCI
Express devices should support these bits. uio_pci_generic detects
this support, and won't bind to devices which do not support the
Interrupt Disable Bit in the command register.

On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
This prevents the device from generating further interrupts until the
bit is cleared. The userspace driver should clear this bit before
blocking and waiting for more interrupts.

Writing userspace driver using uio_pci_generic
------------------------------------------------

Userspace driver can use pci sysfs interface, or the libpci library that
wraps it, to talk to the device and to re-enable interrupts by writing
to the command register.

`uio_pci_generic` userspace 예제

593-663

예제 C program은 `/dev/uio0`을 read-only로 열고 `/sys/class/uio/uio0/device/config`를 read-write로 엽니다. PCI command register의 high byte를 읽어 cache한 뒤 Interrupt Disable bit mask인 `0x4`를 clear한 값을 준비합니다.

Loop에서는 interrupt 처리 위치를 지나 `pwrite()`로 command byte를 써서 interrupt를 다시 enable하고, `read(uiofd, &icount, 4)`로 다음 interrupt와 누적 count를 기다립니다. 각 system call이 정확한 byte 수를 처리했는지 검사하고 실패하면 `errno`를 반환합니다.

PCI 예제 file descriptor
descriptor경로용도
`uiofd``/dev/uio0`interrupt count read
`configfd``/sys/class/uio/uio0/device/config`PCI command byte read·write

Example code using uio_pci_generic
----------------------------------

Here is some sample userspace driver code using uio_pci_generic::

    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>

    int main()
    {
        int uiofd;
        int configfd;
        int err;
        int i;
        unsigned icount;
        unsigned char command_high;

        uiofd = open("/dev/uio0", O_RDONLY);
        if (uiofd < 0) {
            perror("uio open:");
            return errno;
        }
        configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);
        if (configfd < 0) {
            perror("config open:");
            return errno;
        }

        /* Read and cache command value */
        err = pread(configfd, &command_high, 1, 5);
        if (err != 1) {
            perror("command config read:");
            return errno;
        }
        command_high &= ~0x4;

        for(i = 0;; ++i) {
            /* Print out a message, for debugging. */
            if (i == 0)
                fprintf(stderr, "Started uio test driver.\n");
            else
                fprintf(stderr, "Interrupts: %d\n", icount);

            /****************************************/
            /* Here we got an interrupt from the
               device. Do something to it. */
            /****************************************/

            /* Re-enable interrupts. */
            err = pwrite(configfd, &command_high, 1, 5);
            if (err != 1) {
                perror("config write:");
                break;
            }

            /* Wait for next interrupt. */
            err = read(uiofd, &icount, 4);
            if (err != 4) {
                perror("uio read:");
                break;
            }

        }
        return errno;
    }

Generic Hyper-V UIO driver

664-724

`uio_hv_generic` kernel module은 PCI bus의 `uio_pci_generic`과 비슷하게 Hyper-V VMBus device를 지원합니다.

Device GUID를 선언하지 않으므로 자동 load·bind되지 않습니다. Module을 load한 뒤 사용할 device class GUID를 `/sys/bus/vmbus/drivers/uio_hv_generic/new_id`에 직접 씁니다. Hardware-specific driver가 이미 bind되어 있으면 device-specific GUID를 사용해 기존 driver에서 unbind하고 `uio_hv_generic`에 bind합니다. VMBus device의 `driver` symlink로 결과를 확인합니다.

Interrupt마다 `uio_hv_generic`이 Interrupt Disable bit를 설정하므로 userspace driver는 다음 interrupt를 기다리기 전에 clear해야 합니다. Host가 device를 rescind하면 interrupt file descriptor가 down 상태가 되고 이후 read는 closed socket이나 disconnected serial device처럼 `-EIO`를 반환합니다.

VMBus region은 UIO resource로 mapping됩니다. Resource 0은 guest-to-host와 host-to-guest channel ring buffer, 1은 guest-to-host interrupt signalling page, 2는 guest-to-host monitor page, 3은 network receive buffer, 4는 network send buffer입니다.

Host 요청으로 subchannel이 만들어지면 `uio_hv_generic`은 channel별 ring buffer용 sysfs binary file을 `.../channels/<id>/ring` 경로에 생성합니다.

Hyper-V UIO resource
indexregion
0channel ring buffers
1guest-to-host interrupt signalling pages
2guest-to-host monitor page
3network receive buffer
4network send buffer

Generic Hyper-V UIO driver
==========================

The generic driver is a kernel module named uio_hv_generic. It
supports devices on the Hyper-V VMBus similar to uio_pci_generic on
PCI bus.

Making the driver recognize the device
--------------------------------------

Since the driver does not declare any device GUID's, it will not get
loaded automatically and will not automatically bind to any devices, you
must load it and allocate id to the driver yourself. For example, to use
the network device class GUID::

     modprobe uio_hv_generic
     echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" > /sys/bus/vmbus/drivers/uio_hv_generic/new_id

If there already is a hardware specific kernel driver for the device,
the generic driver still won't bind to it, in this case if you want to
use the generic driver for a userspace library you'll have to manually unbind
the hardware specific driver and bind the generic driver, using the device specific GUID
like this::

          echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/hv_netvsc/unbind
          echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/uio_hv_generic/bind

You can verify that the device has been bound to the driver by looking
for it in sysfs, for example like the following::

        ls -l /sys/bus/vmbus/devices/ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver

Which if successful should print::

      .../ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -> ../../../bus/vmbus/drivers/uio_hv_generic

Things to know about uio_hv_generic
-----------------------------------

On each interrupt, uio_hv_generic sets the Interrupt Disable bit. This
prevents the device from generating further interrupts until the bit is
cleared. The userspace driver should clear this bit before blocking and
waiting for more interrupts.

When host rescinds a device, the interrupt file descriptor is marked down
and any reads of the interrupt file descriptor will return -EIO. Similar
to a closed socket or disconnected serial device.

The vmbus device regions are mapped into uio device resources:
    0) Channel ring buffers: guest to host and host to guest
    1) Guest to host interrupt signalling pages
    2) Guest to host monitor page
    3) Network receive buffer region
    4) Network send buffer region

If a subchannel is created by a request to host, then the uio_hv_generic
device driver will create a sysfs binary file for the per-channel ring buffer.
For example::

        /sys/bus/vmbus/devices/3811fe4d-0fa0-4b62-981a-74fc1084c757/channels/21/ring