IIO Linux: notify another driver when samples are ready - c

I have a driver for the LSM6DSOX provided by ST which can be configured to use hardware interrupts and read data. I see that IIO interface is exposed to the user space but I need this data in the another driver.
I think that implementation of the hwmon may be quite good and shows what I wanted to achieve, the example code I found is here https://github.com/torvalds/linux/blob/master/drivers/hwmon/iio_hwmon.c so I can find a GYRO channels and read samples but in this case hwmon needs to call "iio_read_channel_processed" to get sample.
My problem is that I don't know when I should call "iio_read_channel_processed" because I wanted to be notified by the IIO that the sample is ready to read. I expected that I could pass some callback function that will be called each time IIO buffer will receive new sample from another driver. Is that possible?

Related

Call traffic control (tc) from within Linux kernel

There is a userspace util called tc(8) for traffic shaping, i.e.
tc qdisc add dev eth0 root tbf rate 10mbit latency 100ms burst 5000.
The internal implementation of the tc command uses netlink to send specific messages to the kernel which in turn will change things accordingly.
However, there is no public interface for the kernel code for this specific procedure - as in, there is no public API like tc_qdisc_add(x,y,z) - as everything is depending on the data from the netlink message itself.
So, is there a trick to simplify the process and simulate a message from the kernel? Is there a way to bypass the userspace call to tc and get the same outcome just from a kernel context?
is there a trick to simplify the process and simulate a message from the kernel?
I don't see any way to make it simple.
If we do not go into the details of the implementation of specific tc-commands, just to contemplate an existing API inside kernel, we can see that all the related to netlink talking and qdiscs adding code is located in /net/sched subdirectory. The main function for registering qdisc is located in /net/sched/sch_api.c and called register_qdisc(). Also we can see registering basic qdiscs and netlink ops in pktsched_init().
Qdisc operations are described via struct Qdisc_ops and comprise such like init, enqueue, change, etc.
Knowing this we can take a look at how is this implemented in tbf module (net/sched/sch_tbf.c). It has several operations described with tbf_qdisc_ops. Here there is operation to change called which normally is invoked like tc_modify_qdisc() -> qdisc_change() -> tbf_change().
So depending on what exactly you want to tune, you can somehow obtain the particular qdisc, build an appropriate netlink message (struct nlmsghdr, as it is done in usermode) and invoke e.g. ->change(...) method of qdisc.
The answer does not claim to be correct. I just tried to clarify the situation a little bit.

Windows API - IOCTL_CHANGER_GET_PRODUCT_DATA always returning ERROR_INVALID_PARAMETER

I am the author of a communication library which needs to be able to communicate with serial devices and USB devices, through libusb and the native driver which corresponds to our case (CESG502, made by CASIO). Serial and libusb communication are both managed, I now want to integrate the use of CESG502 (the driver made for what we want).
The main problem comes from this driver : instead of managing the buffering the same way serial drivers do (if more data is received, it is stored until the user asks it), it expects the developer to provide a bigger buffer than data is received. This leads to two incompatible uses of ReadFile, where I have to only put the number of bytes I want to actually receive (serial, otherwise it just waits for the rest which will never come) or the size of the buffer (CESG502; if I don't do this, the driver returns a ERROR_GEN_FAILURE).
The driver is proprietary, so I cannot correct it. Because of the design of my library, I need to identify if the driver is CESG502 or not in order to work in most cases the library is made to work in. I have looked and found IOCTL_CHANGER_GET_PRODUCT_DATA, which looks like could bring the information I'm looking for. So I tried to use it here:
/* get product data */
CHANGER_PRODUCT_DATA ProductData; DWORD ReturnedBytes = 0;
DWORD wsuccess = DeviceIoControl(fhandle, IOCTL_CHANGER_GET_PRODUCT_DATA,
NULL, 0, &ProductData, sizeof(CHANGER_PRODUCT_DATA),
&ReturnedBytes, 0);
if (wsuccess) logr_info("SUCCESS!");
else logr_info("Error #0x%08lx occurred", GetLastError());
Unfortunately, I continuously receive the 0x57 (ERROR_INVALID_PARAMETER) error, which also occurs with serial devices. I am following what the page said, I have tried plenty of things (setting ReturnedBytes to sizeof(CHANGER_PRODUCT_DATA), initializing ProductData, reading the data anyway, ...) and I have found out where this error comes from...
Thanks in advance if you know how to solve this :)

How Callback is maintained from Userspace to Kernel Space

I am learning about the driver and looking into the watchdog driver code where some value is being written to /sys/devices/virtual/wdc_per now I guess this is the logic how driver gets its value from userspace and exposed file in user space is
"sys/devices/virtual/wdc_per"
But now how actually this value from wdc_per is reached to driver, there must some callback maintained
In My case its GPIO based Watchdog driver and gpio_wdt.c may be having this callback.
But I really could not figure out how it actually happens
Anybody can help me find out this userspace to kernel space link.
First of all, this driver, gpio_wdt.c, doesn't seem to exist in the mainline kernel as of this date, so it's hard to comment it.
Sysfs (usually mounted at /sys) is actually very easy to use. This is a great example of how to create Sysfs attributes. Basically, you create attributes (will become the Sysfs file names) and register them with two defined operations (callbacks): store and show, which are the equivalent of resp. write and read. The show callback is called everytime the Sysfs file (attribute) is read and store when it's written.
When writing a device driver that belongs to an existing class (most likely your situation), you will rarely need to do that yourself. This is because the standard Linux device classes already have a working set of Sysfs attributes that your driver will use more or less indirectly.
For example, the leds class (LED devices), of which you will find the devices in /sys/class/leds, has a bunch of Sysfs attributes per LED so that a user may read/modify them from userspace (brightness, maximum brightness, trigger, etc.). Now, if you look at LED specific drivers in /drivers/leds, you won't find manual Sysfs attributes creations. You will find, however, a call to led_classdev_register when the driver is probed, which takes a struct led_classdev* as a parameter. This structure has a brightness_set callback member the specific driver needs to provide. When a user writes to /sys/class/leds/whatever-led/brightness, the leds class' store Sysfs callback gets called which in turn calls the specific driver's brightness_set callback.
My point is: make sure you really know your device class before manually adding Sysfs attributes. Anyway, when submitting your driver to the LKML, you will know fast enough if it was a good decision.

C Linux Device Programming - Reading Straight from /Dev

I have been playing with creating sounds using mathematical wave functions in C. The next step in my project is getting user input from a MIDI keyboard controller in order to modulate the waves to different pitches.
My first notion was that this would be relatively simple and that Linux, being Linux, would allow me to read the raw data stream from my device like I would any other file.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
Despite these warnings, I did an experiment. I plugged in the MIDI controller and cat'ed the "/dev/midi1" device file. A steady stream of null characters appeared, and when I pressed a key on the MIDI controller several bytes appeared corresponding to the expected Message Chunks that a MIDI device should output. MIDI Protocol Info
So my questions are:
Why does the cat'ed stream behave this way?
Does this mean that there is a plug and play device driver already installed on my system?
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
Thank you in advanced for sharing your wisdom in these areas.
Why does the cat'ed stream behave this way?
Because that is presumably the raw MIDI data that is being received by the controller. The null bytes are probably some sort of sync tick.
Does this mean that there is a plug and play device driver already installed on my system?
Yes.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
<...>
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
I'm not sure what you're reading or how you're coming to this conclusion, but it's wrong. :) You've already got a perfectly good driver installed for your MIDI controller -- go ahead and use it!
Are you sure you are reading NUL bytes? And not 0xf8 bytes? Because 0xf8 is the MIDI time tick status and is usually sent periodically to keep the instruments in sync. Try reading the device using od:
od -vtx1 /dev/midi1
If you're seeing a bunch of 0xf8, it's okay. If you don't need the tempo information sent by your MIDI controller, either disable it on your controller or ignore those 0xf8 status bytes.
Also, for MIDI, keep in mind that the current MIDI status is usually sent once (to save on bytes) and then the payload bytes follow for as long as needed. For example, the pitch bend status is byte 0xeK (where K is the channel number, i.e. 0 to 15) and its payload is 7 bits of the least significant byte followed by 7 bits of the most significant bytes. Thus, maybe you got a weird controller and you're seeing only repeated payloads of some status, but any controller that's not stupid won't repeat what it doesn't need to.
Now for the driver: have a look at dmesg when you plug in your MIDI controller. Now if your OSS /dev/midi1 appears when you plug in your device (udev is doing this job), and dmesg doesn't shoot any error, you don't need anything else. The MIDI protocol is yet-another-serial-protocol that has a fixed baudrate and transmits/receives bytes. There's nothing complicated about that... just read from or write to the device and you're done.
The only issue is that queuing at some place could result in bad audio latency (if you're using the MIDI commands to control live audio, which I believe is what you're doing). It seems like those devices are mostly made for system exclusive messages, that is, for example, downloading some patch/preset for a synthesizer online and uploading it to the device using MIDI. Latency doesn't really matter in this situation.
Also have a look at the ALSA way of playing with MIDI on Linux.
If you are not developing a new MIDI controller hardware, you shouldn't worry about writing a driver for it. It's the user's concern installing their hardware, and the vendor's obligation to supply the drivers.
Under Linux, you just read the file. Now to interpret and make useful things with the data.

Linux device model: Same device but different drivers

I'm customising Linux for an ARM9 Atmel AT91SAM960 board.
In the device file Atmel named all the USART the same atmel_usart. Of course with id enumeration:
static struct platform_device at91sam9260_uart0_device = {
.name = "atmel_usart",
.id = 1,
.dev = { ...}
}
According to the Linux Device model, all these devices (5 UARTS on a SAM9260) would be bind to the driver named atmel_usart.
I don't want to set a TTYS driver on all UARTS which will be registerd. I have several own drivers which serve for different specialised purposes (LON, RS-485 etc.) I want the control which driver does serve a certain USART. So what could I do:
The Atmel device files are unsatisfiable and I can do it better. So I rename (patch) the devices in the device file. However, in case I want a TTYS driver on UART4 I would be in trouble.
I manipulate (patch) the device file,
so that I'm able the access the
structures platform_device. I could
change their names before I would
register them. But as far as I
understood the idea of the Linux Driver Model,
devices should be
registered early during boot-up but the binding to a driver follows .... later.
I could write a driver, which has an
alias name and which would be binded
to a specific bus_Id ->
atmel_usart.4. Can I really?
What solutions else exist. I want to touch a minimal set of Kernel files but I want all the freedom possible?
Addendum what freedom means to me: I can specify at runtime how the UARTS can be used
with the Atmel-Serial driver (ttyS)
with my own drivers
It means also, that changes to the kernel source are minimal.
I built my own line discipline drivers. You can build them as kernel modules and attach them to the UARTs at runtime. No changes to the Linux source are necessary.
Any funny timing or control stuff can be done through ioctl(). Specifically, I implemented a timing-sensitive RS-485 protocol in this way.
When I did this (Linux 2.6.17) there was no dynamic registration mechanism, so I overwrote the existing line disciplines. The Linux code is (was) pretty straightforward, and I was satisfied that this would be a safe thing to do.
Your problem is quite easily solved. The 5 UART devices are presently registered at kernel startup and their function is locked. This is now how it normally works for PCI or USB devices, right? So what you need to do is pull the device registration out of the startup code and register it dynamically. You can even register/unregister as needed.
at91_register_uart() is being called from your board file for every UART that needs registered. at91_add_device_serial() will then platform_device_register all those you what setup. One solution is to let at91_register_uart() be called for all 5 UARTS, but then remove the call to at91_add_device_serial() from your board. You can then make it an exported function that can be called by your loadable drivers. You can even add an argument to it (int) so that instead of looping on all UARTS, you can select which ones to register individually. You can also mirror this function by making one that unregisters the devices.
NOTE: I think you'll need to always leave one UART dedicated as your console, if you are using one that way. You could probably hide that in the exported function by only allowing index 0->3 as in input and then mapping 0->3 to 0-4, skipping the UART that you want to use for console.

Resources