Jump to content
Sign in to follow this  
yyrkoon

WIP: UIO

Recommended Posts

https://www.kernel.org/doc/htmldocs/uio-howto/about.html

 

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.

 

This howto seems to be very PCI card oriented. But it is *not* limited to PCI cards only. I had not realized until recently, with the help of another beagleboard.org google group user. This can in fact make writing drivers really simple, and effective. So what this person helped me with, is the basic understanding of how all this works. In fact, I had to write absolutely zero kernel module code, by using a pre-existing generic module that exposes hardware interrupts, and register addresses to userland. That is to say, for an ADC userland driver. In fact, TI wrote the pru shared memory module using UIO in a similar fashion. Except they did write their own kernel module code ( uio_pruss - Module uio_pruss.c - Module source code ).

 

So also keep in mind I'm still learning some of this, hence the work in progress part of this post. But I do have the steps written down, which I will post here for myself, and others. Hopefully, this will serve as an example to others, of how "simple" this really can be.

 

 

Here is what was shared with me via a pastebin:

# put in /etc/modprobe.d/uio.conf
#
# make driver match on  compatible = "uio";
options uio_pdrv_genirq of_id=uio
 
 
# put in /etc/udev/rules.d/uio.rules
#
# create named symlink to locate the device easily
# (assumes your kernel is new enough to have of_node symlinks in sysfs)
SUBSYSTEM=="uio", SYMLINK+="uio/%s{device/of_node/uio-alias}"
#
# give some group access rights (adjust as needed)
SUBSYSTEM=="uio", GROUP="users", MODE="0660"
 
 
# example device tree node to give userspace direct access to ADC
&tscadc {
        status = "okay";
        compatible = "uio";
        uio-alias = "adc";
};
 
 
# device will appear as /dev/uio/adc

So everything above with the exception of the device tree aspect works exactly as mentioned in the text. The "hard" part was figuring out how to make this work as a device tree overlay.

 

Doing some digging, am33xxx.dtsi has this fragment:

tscadc: tscadc@44e0d000 {
            compatible = "ti,am3359-tscadc";
            reg = <0x44e0d000 0x1000>;
            interrupt-parent = <&intc>;
            interrupts = <16>;
            ti,hwmods = "adc_tsc";
            status = "disabled";

            tsc {
                compatible = "ti,am3359-tsc";
            };
            am335x_adc: adc {
                #io-channel-cells = <1>;
                compatible = "ti,am3359-adc";
            };
        };
How I found this fragment, I started by reading through the am335x-boneblack.dtb source file am335x-boneblack.dts. Which if you google, you'll run into about 5 million ( exaggeration ) hits. Granted, there have been many changes to this file since it's initial creation. So you'll want to find one that matches your kernel. I just so happen to have the git kernel source tree on a dev system of mine. So it was not too hard to find the correct file for me. Anyway, near the top of this file there are two #includes.

 

http://lxr.free-electrons.com/source/arch/arm/boot/dts/am335x-boneblack.dts

#include "am33xx.dtsi"
#include "am335x-bone-common.dtsi"

The rest should be obvious. At this point I had to do a bit of experimentation, because I know very little about device tree files. But upon examining the files closely things begin to seems clearer. What I eventually wound up with for a device tree overlay file was this:

 

WH-ADC-00A0.dtbo

/dts-v1/;
/plugin/;

/ {
        compatible = "ti,beaglebone", "ti,beaglebone-black";

        /* identification */
        part-number = "WH-ADC";
        version = "00A0";


        fragment@0 {
                target = <&tscadc>;
                __overlay__ {
                        compatible = "uio";
                        uio-alias = "adc";
                        status = "okay";
                };
        };
};
The rest was fairly simple:
$ dtc -O dtb -o WH-ADC-00A0.dtbo -b 0 -@ WH-ADC-00A0.dts
$ sudo cp WH-ADC-00A0.dtbo /lib/firmware/
$ sudo sh -c "echo 'WH-ADC' > /sys/devices/platform/bone_capemgr/slots"

$ dmesg | grep WH-ADC
[ 1290.096328] bone_capemgr bone_capemgr: part_number 'WH-ADC', version 'N/A'
[ 1290.116039] bone_capemgr bone_capemgr: slot #5: 'Override Board Name,00A0,Override Manuf,WH-ADC'
[ 1290.137733] bone_capemgr bone_capemgr: slot #5: dtbo 'WH-ADC-00A0.dtbo' loaded; overlay id #0

$ ls /dev/uio
adc

$ ./lsuio
uio0: name=tscadc, version=devicetree, events=0
        map[0]: addr=0x44E0D000, size=4096
Do also keep in mind I'm using a 4.1.x kernel. Which is important in relation to which device tree compiler is used to compile the overlay file from source - And how the file is loaded via cape manager. In short, 3.8.x kernels use a 1.4.0 dtc, while 4.x kernels use a 1.4.1 dtc. This is important, since if the wrong device tree compiler ( dtc ) is used, the overlay will not work. As for the cape manager aspect, it is mostly ( only ? ) a difference in syntax.

 

So here is what else I've been told. Once a file descriptor is opened on this device (/dev/uio0), the ADC will automagically be enabled. What I was told is that this has to do with the ti,hwmods = "adc_tsc"; bit in the device tree fragment in the am33xxx.dtsi file. I wont pretend to understand how this works exactly. It is another aspect of all this I need to figure out. But if "we" examine the rest of the file, such as: reg = <0x44e0d000 0x1000>; This should be completely obvious what this is for, if you look at the output of the command lsuio It is the start address of the ADC module registers, followed by the mmap() length( 4096 in decimal ). Which for most Linux systems, getpagesize() will return 4096 . . .

 

Anyway, again, this is a work in progress, and I've yet to write the userland side code to use this. It should be very similar to the code I used for /dev/mem + mmap() to do the same thing, but with a few added benefits. Not leaving a huge gaping security hole in the system would be a big one . . .

Share this post


Link to post
Share on other sites

Right now, I'm considering getting a very simple USR LED example working with UIO, as a basic "hello world" type UIO app. But also in the future I want to demonstrate many different UIO "driver" possibilities. Pretty much anything, hardware module wise on the beaglebone will work with this. That it to say, Obviously the pruss do, ADC, but UIO can be used to work with SPI, I2C, on chip timers, CAN, DMA memory transfers . . . and if one felt so inclined, one could map plain ole memory . . . but I'm trying to think how that would be useful, exactly . . .heh.

 

EDIT:

 

Also for what it is worth: the reason why it is taking me so long to get something else, simple working. Is that I know very little about device tree. The USR LEDS are already claimed by the board, and I am trying to figure out the correct way of taking control of these LEDs. To be sure, I can just start twiddling register bits willy-nilly . . . but that's not the right way . . .

Share this post


Link to post
Share on other sites

Ok, so after some experimentation, I've come to the conclusion that using UIO to control the user LEDs is probably a bad idea. It is pretty bad, when the "light at the end of the tunnel" seems to point to using uio_pruss. Which is to say, it seems to make way more sense to use the existing PRU uio driver to do this.

 

As I believe it would require me to write a completely custom uio kernel "stub" which would then step all over existing gpio device tree stuff, and . . . yeah it would be a mess, and honestly now that I'm learning more. It does not make sense anyway.

 

With that said, I'm starting to get to a point where I understand the uio_pruss driver well enough to write custom code for the PRUs, that would allow a userspace program to twiddle the USR LEDs . . . I just need to understand the PRU registers / ASM a bit better.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×