How to use linux device model and /sys filesystem? - linux

I'm new in developing Linux driver.
Traditionally, If i want to create char device, I just need to implement read write and ioctl functions, and register it by register_chrdev_region with corresponding Major device ID. And then use mknod to create a device file of that Major device ID. Then call read write open in user space will then call the corresponding functions by kernel.
But now i'm studying Linux device model and sys filesystem, which is added in kernel 2.6. I'm told if possible, Don't use /dev filesystem, as linux now has a good device model to handle device and driver.This confused me, so I'll summarize my confusion into some questions:
How do I create a char device in /sys? To be more specific, how do I create a null device just like /dev/null?
How do I call my char device driver function from userspace?
I heard that udev is based on sys filesystem to create device file in /dev. Why? Since I'm told "If possible, Don't use /dev filesystem", why does udev use /sys to create file in /dev?
Does a file in sys have any conceptions like char device file or block device?
In /dev, open write from user space will finally map to functions in file operation structure defined by me, then what functions will be called when I open or write to files in /ssy?

Without context your statement about /dev is not clear. Anyway:
You cannot create char devices on sysfs. The main purpose of sysfs is to export information and allow the user to adjust single values (just navigate under /sys/ for some examples). Char devices usually does much complicated things.
If you mean how you call your driver's open,read,write,ioctl, ... well, by doing open(2), read(2), write(2), ioctl(2) (look at man pages of these commands)
when a device appear, the kernel create a directory under /sys. For example take a look at ls /sys/bus/usb/devices/. All that directories are created when an USB device appear. You can try by plug/unplug USB devices. udev put an eye on sysfs to detect new devices and according to the information from sysfs it create the device under /dev. This happens when the driver, somehow, calls device_add(). Often this functions is invoked by other register functions like: device_create, device_register, or other from other sub-systems.
the idea of sysfs is to provide information about the devices and drivers loaded. So you can change device, bus and driver options. Or manually attach a device to a module
Actually, behind the sysfs attributes there is a set of file_operation, where open, read and write are managed by the kernel and not by your driver. In order to create a sysfs attribute you have to provide the pair of function show and store to read/write something from/to the driver. Then the kernel will route the requests to your correct attribute

Related

lm75 kernel module available in userspace

I'm using the lm75 kernel module to interact with a sensor on a custom board. Every things works fine, I have my device mounted in /sys/bus/i2c/devices/5-0048. But I would like to let the user set the max temp hysteresis so in other words let the user write into the temp_max_hyst file. The permission for this file is read only except for root
My question is, is there any way to mount my device in /dev?
Mounting isn't the right term here so you won't find anything searching for that. Block devices with file systems are mounted on directories, which then become mount points.
Here the device 5-0048 is bound to the driver lm75. You'd find the device is there, assuming it appears in the device tree or board info, whether or not the lm75 driver exists. If and when the lm75 driver binds to the device, it creates a new device of class hwmon. It is that device which has attributes, like temp_max_hyst, that you are interested in.
What you see in /dev are known as device nodes. While many devices, once bound to a driver, will have a device node created to interact with the device, this doesn't have to happen. There are probably a bunch of devices that appear in /sys/class/regulator or /sys/class/net that have no nodes in /dev associated with them.
Drivers of type hwmon, like lm75, don't normally create any device nodes to provide a char device or block device userspace interface to the hardware. So there is nothing to appear in dev for this device. The attributes of the hwmon device are all you get.
But your problem has a simple solution. As root, just chmod a+w temp_max_hyst or chown user_account temp_max_hyst or (this is probably best) chmod g+w temp_max_hyst ; chgrp hw_access_group temp_max_hyst and add the user to a group hw_access_group. You could use an existing group, there might be one named wheel or adm that would be used for something like this, or make a new one just for hwmon access.
Of course this won't persist across a reboot, as sysfs is not a real file system on disk. To make the change persistent, the best way is to create a udev rule that automatically effects the chmod/chown when it detects the hwmon device. It's the hwmon device you care about here, not the i2c device. Try running udevadm info -a /sys/class/hwmon/hwmon0.

Best Way to copy data from Kernel Driver to user space driver

I am having a kernel driver which is currently reading data from a sensor.
Now I have to write a user space application which will call kernel's sensor_read() API and send data to cloud.
How can I expose kernel's sensor_read() call to user space and read this data from user space? Data is about 10 bytes.
How can I expose kernel's sensor_read() call to user space and read this data from user space?
Most likely you should use IIO kernel framework, as it's specifically designed for writing sensor drivers. IIO exposes necessary files for your driver (in /sys/bus/iio/ and /dev/iio*). You can read() those files, or poll() them (to handle interrupts).
Official documentation is available here. You can also use some existing drivers as a reference, look here: drivers/iio/ .
Before IIO framework was introduced, it was common to provide sysfs files for drivers manually. So if you use old enough kernel, that should be the way to write the driver: handle your bus (like I2C) and sysfs files manually. But still, the best way is to use new kernel and IIO.
I am working on a Gyro + accel sensor. Linux driver will be sending events of type EV_MSC for both of them
It's not unusual for chip to have more than one sensor on it. In that case you should create two different drivers: one for accelerometer, and one for gyro. This way you will have two different files, one file per sensor.
For example, look how it's done for LSM330DLC chip (accelerometer + gyro):
accel driver: drivers/iio/accel/st_accel_core.c
gyro driver: drivers/iio/gyro/st_gyro_core.c
Both drivers are calling iio_device_register() function from driver's probe function, which creates corresponding files (which you can read/poll). Refer to documentation for further details.
As per my understanding I will open both the input devices from user space and add then to list of FD's which we want to poll. So when there is a new event how I can determine whether this event is from Gyro or aceel?
If you are curious about how to handle two /dev/input/event* files in user space, you basically have two choices:
using blocking I/O: you can read/poll them in different threads
using non-blocking I/O: you can open those files as O_NONBLOCK and just read() them in the same one thread; if new data is not available yet -- it will return -1 and errno will be set to EAGAIN; you can do those reads in infinite loop, for instance
This answer contains example of how to handle input file in C. And here you can read about blocking/non-blocking I/O.
There are many ways to access sensors data from kernel space to userspace
Check for relevant driver of the sensor you used. Check whether it supports/provides sysfs support.
you can read the data from /sys/class/ interfaces. You need to ensure that the relevant parameters exported to sysfs.
For eg: Temperature sensors should have exported temperature values(equivalent factors) in sysfs entry.
Examples(Below examples are fictions only)
cat /sys/class/hwmon/tempsensor/value
cat /sys/class/hwmon/tempsensor/min_value
cat /sys/class/hwmon/tempsensor/max_value
In some drivers, you can read them through ioctl / read / write api's to read/write sensor data.
You can use IOCTL (ioctl/read) calls to access the kernel functions from User space.
Refer below link for sample:
http://www.tldp.org/LDP/lkmpg/2.4/html/x856.html

sysfs_create_group(): Where to call?

currently i write an driver module which offers some entries in the sysfs. I read a lot through the driver source tree and the internet. I found two approches where the sysfs_create_group() is called:
a) most commonly: In the probe() function of the Driver. Like adviced here
How to attach file operations to sysfs attribute in platform driver?
Random Thing i looked at:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/rtc/rtc-ds1307.c#n1580
b) In the driver struct.
http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/
I know, Greg KH is a very well known developer. So i tried to follow his advice. In the bla_show()/bla_store() functions i tried to get my Driver private data, but my printk()'s showed much different addresses than i printed in the probe() function. My private data is (null). Which is ofc wrong.
When i use approch a) it works as expected, but as Greg KH suggests it is wrong too. I see it a lot in the stable tree in different drivers. Greg writes, the userspace already got the notification that there is a new device, but the LDD3 book states, that the probe function is there to determine if the device is present.
To sum my question up:
Why get the userspace notified about it, even when the kernel doesnt know if it can handle it?
Where is the right place to call sysfs_create_group()? Is it a) or b) ?
LDD3: https://static.lwn.net/images/pdf/LDD3/ch14.pdf
PDF page 24
probe is a function called to query the existence of a specific device
(and whether this driver can work with it), remove is called when the
device is removed from the system,and shutdown is called at shutdown
time to quiesce the device.
I am more confused than before .....
Best Regards
Georg
A device driver is a program that controls a particular type of device that is attached to your computer.
Platform devices are inherently not discoverable, i.e. the hardware cannot say "Hey! I'm present!" to the software. So for these kind of device we need a driver which call as Platform drivers. Drivers provide probe() and remove() methods.
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
.
.
struct device_driver driver;// this file has 2 parameter name or owner.
};
probe() should in general verify that the specified device hardware
actually exists. First we register our driver. Once it found device then it'll call driver probe. It is using name for searching a device.
Ans : your device is available then you need sysfs entry for communication (To the user space). so conceptually you need to define you sysfs entry in probe.
sys_notify function on your attribute and it will cause your userspace code to wake up. It will trigger when sysfs is available for userspace. It just avoiding a blocking call. When kernel does not have sysfs then it'll not notify userspace.
sysfs is a virtual file system provided by the Linux kernel that exports information about various kernel subsystems, hardware devices, and associated device drivers from the kernel's device model to user space through virtual files. When your device is available then you need this entry to export your information.

Is it possible to send SCSI commands to a USB device from within a kernel module?

Question
How, given the information udev passes to my kernel module (the block device path maybe), can I send SCSI commands to the block device? (yet have it function normally otherwise, meaning partitions are mounted, no data loss, etc)
What I'm Trying To Do
I have a USB mass storage device that has LEDs which are controlled via SCSI commands.
I would like to write an LED driver to provide /sys/class/leds/* entries for it.
The goal here is to have the device function normally (partitions mounted and functioning, etc) but also allow /sys/class/leds/* interactions that would send SCSI commands to control the LEDs.
It's easy to to send the SCSI commands I need in user space with sg_raw. But I need a kmod to provide /sys/class/leds/...
Essentially what I need is ioctl(). However, I understand it is generally a bad idea to call open(),ioct(),etc from within a kmod.
It can be achieved by some pseudo driver that emulates between USB & SCSI. I think what ever be your problem may achieved while you are accessing the USB device through SCSI.
These low level & mid level scsi drivers are defined.

Linux: How to map a blockdevice to a USB-device?

if I plugin a USB memory stick, I see a new folder in /sys/bus/usb/devices ... thus a new USB-device.
Also I see a new folder in /sys/block ... thus a new block-device.
My question is: How can I get a waterproof mapping between those two devices? Means:
If I get a new device in /sys/bus/usb/devices, how can I programatically (f.i. by checking /sys/...) find out which block device is mapped/related to this usb-device and vice-versa?!
The information in /sys is organized in multiple ways (by driver, by bus, etc.), and there are many symbolic links to go from one hierarchy to another.
Case in point (example seen on kernel 2.6.26): starting from the block device in /sys/block/sdc, the symbolic link /sys/block/sdc/device points inside the per-device-type hierarchy. You can see that it's an USB device because the target of the link is something like
../../devices/pci0000:00/0000:00:1d.7/usb8/8-2/8-2:1.0/host9/target9:0:0/9:0:0:0
Conversely, USB devices are listed in /sys/bus/usb/devices, and we can see that 8-2:1.0 is a disk-like device because /sys/bus/usb/devices/8-2:1.0/driver links to usb-storage. To find out what the associated block device is, it seems we need to go down to the directory /sys/bus/usb/devices/8-2:1.0/host9/target9:0:0/9:0:0:0 which contains a symbolic link block:sdc whose target is /sys/block/sdc.
ADDED: Caution: the exact structure of /sys changes from kernel version to kernel version. For example, with kernel 2.6.32, /sys/block/sdc/device points directly into the /dev/bus/scsi without going through the USB hop.
A different approach is to call the udevadm info command. udevadm info -p /sys/block/sdc --query=… gives information on a device based on its /sys entry, while udevadm info -n sdc --query=… gives information on the device /dev/sdc.
The information includes bus information, for example udevadm info -p /sys/block/sdc --query=env shows
ID_BUS=usb
ID_PATH=pci-0000:00:1d.7-usb-0:2:1.0-scsi-0:0:0:0
The udev documentation may have more information of interest to you.
A final word of caution: there are all kinds of complex cases that may make whatever you do not so waterproof. How will your program deal with a single USB device that is an array of disks that are assigned multiple block devices? Conversely, how will your program deal with a RAID array assembled from multiple devices (perhaps some of them USB and some of them not)? Do you care about other removable media types such as Firewire and e-SATA? etc. You won't be able to predict all corner cases, so make sure to fail gracefully.
As far as I found out, it's possible to access udev information via "libudev" library. There's also a good sample on the net available: http://www.signal11.us/oss/udev/
I was able to modify it to read out all "/dev/sd*" devices and get their Vendor-ID, Product-ID as well as Serial number. I think this solution is kernel/linux distribution independant enough. But I still have to verify this.

Resources