Implementation of linux char driver with multiple parameters to access - c

I am writing a simple char driver which accesses a PCI card. It is registered to sysfs with the help of a new class and accessible under /dev/foodev. Using standard file operations I can perform simple read and write operations to the device.
My problem: I have multiple parameters stored at different addresses on the card (version, status, control, ...) which I would like access independently. Currently having only one read and one write function I therefore have to change the address every time again in the driver code.
Obviously there is a more convenient way to implement this. I stumbled about the two following approaches and was wondering which is the better one in terms of sustainability and user accessibility:
Using ioctl commands setting the address/parameter before an
access.
Having the device already nicely set up in udev using multiple attributes
(device_create_file()) of which the user than just can write/read from
different "files":
/dev/foodev
../version
../status
../control

I think you should take a look at the PCI framework to implement your driver.

Don't (mis)use ioctls; you'll have race conditions. Use the attributes as files. That scheme is already used in sysfs. E.G. look at GPIO LEDs and keys. – sawdust

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.

Embedded Firmware Architecture

I’ve been writing increasingly complex firmware and am starting to notice that my knowledge of design patterns and architecture is a bit lacking. I’m trying to work on developing these skills and am hoping for some input. Note: this is for embedded c for microcontrollers.
I’m working with a concept for a new project as an exercise right now that goes something like this:
We have a battery management module with user I/O
The main controller is responsible for I/O (button, LCD, UART debug), detecting things like the charger being plugged in/unplugged, and managing high level operations.
The sub controller is a battery management controller (pretty much a custom PMIC) capable of monitoring battery levels, running charging/discharging firmware etc.
The PMIC interfaces with a fuel gauge IC that it uses to read battery information from
The interface between the two controllers, fuel gauge and the LCD are all I2C
Here is a rough system diagram:
Now what I’m trying to do is to come up with a good firmware architecture that will allow for expandability (adding multiple batteries, adding more sensors, changing the LCD (or other) interface from I2C to SPI, etc), and for testing (simulate button presses via UART, replace battery readings with simulated values to test PMIC charge firmware, etc).
What I would normally do is write a custom driver for each peripheral, and a firmware module for each block. I would implement a flagging module as well with a globally available get/set that would be used throughout the system. For example my timers would set 100Hz, 5Hz, 1Hz, flags, which the main loop would handle and call the individual modules at their desired rate. Then the modules themselves could set flags for the main loop to handle for events like I2C transaction complete, transaction timed out, temperature exceeded, etc.
What I am hoping to get from this is a few suggestions on a better way to architect the system to achieve my goals of scalability, encapsulation and abstraction. It seems like what I’m doing is sort of a pseudo event-driven system but one that’s been hacked together.
In any case here’s my attempt at an architecture diagram:
The concept of an "event bus" is over-complicated. In many cases, the simplest approach is to minimize the number of things that need to happen asynchronously, but instead have a "main poll" routine which runs on an "as often as convenient" basis and calls polling routines for each subsystem. It may be helpful to have such routine in a compilation by itself, so that the essence of that file would simply be a list of all polling functions used by other subsystems, rather than anything with semantics of its own. If one has a "get button push" routine, one can have a loop within that routine which calls the main poll routine until a button is pushed, there's a keyboard timeout, or something else happens that the caller needs to deal with. That would then allow the main UI to be implemented using code like:
void maybe_do_something_fun(void)
{
while(1)
{
show_message("Do something fun?");
wait_for_button();
if (button_hit(YES_BUTTON))
{
... do something fun
return;
}
else if (button_hit(NO_BUTTON))
{
... do something boring
return;
}
} while(1);
}
This is often much more convenient than trying to have a giant state machine and say that if the code is the STATE_MAYBE_DO_SOMETHING_FUN state and the yes or no button is pushed, it will need to advance to the STATE_START_DOING_SOMETHING_FUN or STATE_START_DOING_SOMETHING_BORING state.
Note that if one uses this approach, one will need to ensure that the worst-case time between calls to main_poll will always satisfy the timeliness requirements of the polling operations handled through main_poll, but in cases where that requirement can be met, this approach can be far more convenient and efficient than doing everything necessary to preemptively-scheduled multi-threaded code along with the locks and other guards needed to make it work reliably.

Get node name given to a USB by ACM Driver

I have two usb devices that are recognized by the ACM driver and I’m developing a program in C to communicate with them. As the command for each one are different, I need to know the name given for each one (usb/acm/X).
How can I get this name given the vendorId and productId? I have tried parsing dmesg text but in some cases I may have the two lines “ttyACMX: USB ACM device” one after the other.
I could parse the order each device shows its name in dmesg and take the same number in the “ttyACMX” but this force me to parse also the disconnections messages and all becomes a bit dirty.
I’ve seen that the information I need is in the structure tty_driver created for each device and I’m sure I can have this information easier than parsing dmesg.
Can someone point me out int the right direction?
libudev (C) might be a solution, also have a look at the source of ModemManager daemon (C, glib based)
Use libudev or some higher-level library like gudev (GLib-based libudev). Don't use ModemManager unless your devices are really mobile broadband (2G/3G/4G) modems.
I found this thread to be helpful: http://forum.pololu.com/viewtopic.php?f=16&t=6741
You can make a udev rule file in /etc/udev/rules.d that has a rule like this:
KERNEL=="ttyACM0", SUBSYSTEM=="tty", SUBSYSTEMS=="usb",
ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="008c",
ATTRS{serial}=="00053419", MODE="0666", SYMLINK+="TTYS_002"
I think this will make a device named /dev/TTYS_002 when you plug in a CDC ACM device that has the specified vendor ID, product ID, and serial number.

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.

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