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.
Related
I am writing a Linux kernel driver (kernel 4.9) for our custom setup.
We do use a ARM64 based board with a PCIe interface.
Connected to the interface we have an extension board with a FPGA on it.
At this moment I succeed at creating a device that registers my FPGA with some basic functions, like reading the version of the FPGA in a certain register in the FPGA.
In the FPGA we do have some additional "devices" like GPIO, memory regions ... that I would like to add as its own chardevice. We do have existing drivers for these.
Normally, Linux goes over the DTB and calls the correct driver for our FPGA, following the correct drivers for our child devices.
Now I would like to archieve the same with this PCIe interface. To do this, I look for a node in my DTB fpga and add its children.
for_each_available_child_of_node(np, nc) {
subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
list_add(&subdev->subdev_entry, &priv->subdev_list.subdev_entry);
...
}
list_for_each_entry(subdev, &priv->subdev_list.subdev_entry,
subdev_entry) {
ret = mfd_add_devices(priv->dev, PLATFORM_DEVID_NONE,
subdev->mfd_cell, 1, NULL, irq_base, NULL);
if (ret) {
dev_err(priv->dev, "Failed to add mfd cell\n");
goto err_mfd_add;
}
}
For some reason, the driver is not loaded for its children.
print's in the device drivers probe function shows nothing, not being called.
Added print's to the loops and it shows its children (all properties and values check out with what I set in the DTB).
Yes, the driver is compiled an available in the kernel.
I also tried building the driver as a kmod and load it that way, no change in behaviour. The output of lsmod shows the module is loaded but not used.
Somebody got an idea why my driver is not being loaded?
EDIT:
I also can see the "nodes" from my DTB that should be created as a chardevice.
They can be found in the expected location /sys/class/my_fpga/fpga/device/, in this case GPIO.
Under the GPIO folder I can see the driver_override (which is (null) ), modalias, power, sybsystem and uevent.
So my device (my_fpga) seems to be enumerated, only its children are not created.
A reboot does not solve it, nor a rescan of the PCIe-bus. The extension-board is powered via an external powersupply and is already configured before booting Linux
my problem is I want to manually handle how USB devices are handled when they are plugged in. I don't want the operating system to do anything with the plugged in USB devices other than notify me of their type and their ID when they are plugged in. From there I can then select the appropriate driver to apply to it, or manually do something with it with custom code.
I've read this about how MacOS handles USBs, and it says:
If you want your driver selected above others, all you need to do is add key value pairs for the device your driver is for which cause your driver to get a really high score. Usually it's enough to just put keys in for your vendor id/model. However, I think you can override the matching method (device drivers are written in a restricted set of C++) to give your driver a really high score.
I have also found these 3 libraries for getting notified about things in the USB drive:
https://github.com/tessel/node-usb
https://github.com/MadLittleMods/node-usb-detection
https://github.com/node-hid/node-hid
I just am not sure if these libraries will interrupt all USB device handling by the operating system before anything occurs (before any device driver is selected automatically and applied). I would like for nothing to happen except for me to get access to the device and its type in one of the above libraries, but I'm not sure if they will do that.
I don't have much code yet other than this:
var usb = require('usb')
usb.getDeviceList()
But I imagine this would resolve the plugged in devices after the OS has already selected and applied a default driver to it. I want to do something like this:
usb.blockDefaultOSDeviceHandler()
usb.on('device:plugged_in', function(data){
if (data.type == 'keyboard') {
if (data.modelNumber == '123') {
// allow
usb.applyKeyboardDriver('abc', data.modelNumber)
usb.on('keyboard:event', logKeyboardEvent)
} else {
throw new Error('Unrecognized device')
}
}
})
I would hope that the library would interrupt all default behavior by the operating system so I can handle myself what should be done when a USB device is plugged in. A reason is because maybe the USB device is a keyboard and it automatically starts typing in some keys. I would like to know that it is a keyboard, and require a password and a specific driver I have pre-approved for it. Stuff like that.
I would like to get access to any newly plugged in USB device before the operating system applies its default handling rules. And then have the ability to write the code to manually handle what to do with each plugged in device.
If it's only possible in C, then knowing how to do it there would be good instead of node.js.
https://github.com/Arti3DPlayer/USBDeviceSwift
https://github.com/USBGuard/usbguard
How to block/unlock USB port in mac os x programatically without reboot
https://apple.stackexchange.com/questions/59764/how-to-disable-individual-usb-ports-by-script
https://serverfault.com/questions/566687/blocking-usb-through-gpo-in-2008-r2-excluding-certain-users
https://github.com/google/gousb
https://github.com/IntergatedCircuits/USBDevice
The answer is in the Apple documentation on USB devices. Basically you want to override the probe function in a custom driver, have it return the highest score so as to override all other drivers, and implement the driver like normal. Here is some useful documentation on the driver selection and instantiation process.
Before a device—or any service provider—can be used, a driver for it must be found and loaded into the kernel. The I/O Kit defines a flexible, three-phase matching process that narrows a pool of candidate drivers down to one or more drivers. The final candidate (or, if multiple candidates, the m
ost eligible one) is then loaded and given the first opportunity to manage the device or service provider.
...
Each device driver, considered as a loadable kernel extension (KEXT), must define one or more personalities that specify the kinds of devices it can support.
...
Because a driver can contain multiple matching dictionaries, each one defining a different personality for the driver, the same driver code can be loaded for different devices. For purposes of competition, the I/O Kit treats each personality as if it were a driver. If, in any single personality, all of the properties required by the family match, the driver’s code is loaded and given a chance to run for that device.
...
One common property of personalities is the probe score. A probe score is an integer that reflects how well-suited a driver is to drive a particular device. A driver may have an initial probe-score value in its personality and it may implement a probe function that allows it to modify this default value, based on its suitability to drive a device. As with other matching values, probe scores are specific to each family. That’s because once matching proceeds past the class-matching stage, only personalities from the same family compete. For more information on probe scores and what a driver does in the probe function, see Device Probing.
...
At boot time and at any time devices are added or removed, the process of driver matching occurs for each detected device (or other service provider). The process dynamically locates the most suitable driver in /System/Library/Extensions for the device or service.
...
As described in Driver Matching in the chapter Architectural Overview the matching process is triggered when a bus controller driver scans its bus and detects a new device attached to it. For each detected device the controller driver creates a nub. The I/O Kit then initiates the matching process and obtains the values from the device to use in matching (for example, examining the PCI registers). Once a suitable driver is found for the nub, the driver is registered and loaded. That driver, in turn, may create its own nub (possibly through behavior inherited from its family), which initiates the matching process to find a suitable driver.
...
The matching process proceeds as follows:
In the class matching step, the I/O Kit narrows the list of potential drivers by eliminating any drivers of the wrong class for the provider service (that is, the nub). For example, all driver objects that descend from a SCSI class can be ruled out when the search is for a USB driver.
In the passive matching step, the driver’s personality (specified in a driver’s XML information property list) is examined for properties specific to the provider’s family. For example, the personality might specify a particular vendor name.
In the active matching step, the driver’s probe function is called with reference to the nub it is being matched against. This function allows the driver to communicate with the device and verify that it can in fact drive it. The driver returns a probe score that reflects its ability to drive the device. See Device Probing for more information. During active matching, the I/O Kit loads and probes all candidate drivers, then sorts them in order of highest to lowest probe score.
...
The I/O Kit then chooses the remaining driver with the highest probe score and starts it. If the driver successfully starts, it is added to the I/O Registry and any remaining driver candidates are discarded. If it does not start successfully, the driver with the next highest probe score is started, and so on. If more than one driver is in the pool of possible candidates, the more generic driver typically loses out to the more specific driver if both claim to be able to drive the device.
...
The probe score is a signed 32-bit integer initialized to a value specified in the driver’s personality (or to zero if not explicitly initialized).
...
A driver, in its probe function, returns a driver object (IOService *) if the probe was successful and returns zero otherwise. The returned object is usually the driver itself, but the driver can return another driver that is more suited to the provider. The probe score is an in-out parameter, which probe can modify based on what it discovers about the device.
...
After all drivers have probed the device, the one with the highest probe score is attached and its startfunction, which must be implemented by all drivers, is invoked. The start function initializes the device hardware and prepares it for operation. If the driver succeeds in starting, it returns true; the remaining candidate driver instances are discarded and the driver that started successfully continues operating. If the driver cannot initialize the hardware it must leave the hardware in the state it was in when start was invoked and return false. The failing driver is then detached and discarded, and the candidate driver with the next highest probe score is given a chance to start.
This can't be done with Node.js unless (potentially) a C/C++ extension in node is used.
How can I write a C program (in userspace) to call functions that are part of a kernel driver? If it's not possible to do directly, how else do I do it?
CONTEXT: I am trying to use the PWM pins of my single-board computer (Intel NUC DE3815TYBE) so that I can control fans. A linux driver called pwm_lpss allows control of these pins (driver developed by Intel, source code here). I have verified that this driver is installed by using the lsmod command. Here is the driver information after typing modinfo pwm_lpss:
filename: /lib/modules/3.19.0-25-generic/kernel/drivers/pwm/pwm-lpss.ko
license: GPL v2
author: Mika Westerberg <mika.westerberg#linux.intel.com>
description: PWM driver for Intel LPSS
srcversion: 44AA14AF3E2F96C813770A8
depends:
intree: Y
vermagic: 3.19.0-25-generic SMP mod_unload modversions
signer: Magrathea: Glacier signing key
sig_key: 6A:AA:11:D1:8C:2D:3A:40:B1:B4:DB:E5:BF:8A:D6:56:DD:F5:18:38
sig_hashalgo: sha512
So I know where the driver module is (the pwm-lpss.ko file) and I have the source code which I know has a function in it called pwm_lpss_config() that I'd like to use. How do I call the function from my userspace C program? How would I go about #including it? Or is this not possible to do from userspace?
Unfortunately Intel has provided zero documentation for how to use this driver. I thought drivers normally map their functionality to some user-accessible file. I was able to find some PWM-related files after some digging, but I haven't been able to find a file that looks like it can set PWM duty cycle/frequency.
It's a standard Linux PWM driver, so no special documentation is necessary.
Check the /sys/class/pwm/ directory. (/sys is the interface the kernel provides for access to its data structures. It just looks and acts like a filesystem.) You should have something like /sys/class/pwm/pwmchip0/. Each such directory corresponds to a PWM chip.
The directory will have the following entries. You may need superuser privileges to access these (as you wouldn't want everybody to mess with them):
npwm: Read this to find out how many PWM channels this chip has.
export: Write a channel number (0 to whatever-the-number-in-npwm-1) to make that channel available via this sysfs interface
unexport: Write a channel number to remove the channel from sysfs interface control
Each PWM channel exported to be used via the sysfs interface will show up as a subdirectory named pwmN, where N is the channel number. Here, you can read and write to entries
period: Total period (off + on) in nanoseconds.
duty_cycle: On time in nanoseconds. Must be less than period.
polarity: If the chip supports reversing the signal polarity, you can write inversed here to invert the polarity; normal is the default/normal polarity.
enable: 1 if enabled, 0 if disabled.
When reading or writing to these entries, no special locking is necessary. The kernel will receive all data in one write(), and return all data in one read() operation. When a write() succeeds, the kernel has applied the setting.
some ioctl ? The ioctl() function manipulates the underlying device parameters of special files.
Along the lines
fd = open("/dev/pwm0", O_RDONLY); // put whatever device you've got
if (ioctl(fd, STATUSGET, &status) == -1) // magic constant should be set
....
} else {
....
}
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.
I need a method to perform the following task, suppose if I have a computer with k (k is large) number of Ethernet interfaces. I want to have a method to identify which identifier (em0) is assigned to which physical interface.
The only "easy" method that I came up is to blink the LED light on the physical interface.
For example
etherblink em0
Would flash the link or the activity LED on the physical Ethernet interface that is assigned to em0.
I know on linux there is the ethertool, but that doesn't work with FreeBSD. As well as there is the LED driver on FreeBSD, but that only support limited number of Ethernet modules.
Any ideas? I thought about binding a socket to the interface and write to the socket, but that didn't work.
C or Perl
Tough I have not done this, but, according to FreeBSD handbook, it's possible to bind specific driver node to specific hardware IRQ using kernel configuration hints. See device.hints(5) and FreeBSD network setup to see how to locate each Ethernet device IRQ.
Assume the interface in question is fxp0... run this as root
use strict;
my $intf = "fxp0";
while (1) {
foreach my $state (qw/up down/) {
system("ifconfig $intf $state\n");
sleep 3;
}
}
I assume you won't care about transfering data through the interface while it's blinking...
Sadly I did not find a general solution to this problem, however, from my research (by reading the change log of FreeBSD 8.2, and from the forums) It seems that:
"some cards blink the LEDs on access, so pings could make a repeated pattern.
The LEDs might even go off if the card is downed with ifconfig(8)."
Particularly em and igb interfaces, as stated by:
"The em(4) and igb(4) drivers now support the led(4) interface via /dev/led/emN and
/dev/led/igbN for identification LED control. The following command line makes the
LED blink on em0:[r211241]" (FreeBSD 8.2 Release changelog)
However I do not have the hardware to test this. What I did end up doing was rewritten the Ethernet driver for the interface that I am using to support the LED hardware feature.