lm75 kernel module available in userspace - linux

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.

Related

How to use linux device model and /sys filesystem?

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

udev usb everytime different path

I have following problem with my Linux board:
My USB media device every time mounted as different device in /dev/ folder:
First time I attach the USB, it appears as
/dev/sdb1
Then, I remove usb and plug it in again and it gets different name:
/dev/sdc1
And so on and so forth.
I want it to have constant name always, so I wrote following udev rule:
SUBSYSTEM=="block",ENV{ID_SERIAL}==" serial id ",NAME="myusbmedia"
This rule doesn't work. I could have symbolic name with following rule:
SUBSYSTEM=="block",ENV{ID_SERIAL}==" serial id ",SYMLINK="myusbmedia"
This rule works, but it doesn't solve the problem, because usb still gets /dev/sd[b,c,d, ...] names...
Does anyone have an idea how to make USB appear in /dev/ under the same device node with the same name?
When you connect your device, i assume you use mount in order to approach its files.
You should unmount the drive (using the umount command) before you disconnect it, and then it should stay as the same device at the /dev folder.
For example:
umount /dev/sdc1
The problem is unsolvable, at least using udev. The device node is created by the kernel, not by udev. So you need to modify the kernel.
From man page udev(7):
The following keys can get values assigned:
NAME
The name to use for a network interface. The name of a device
node cannot be changed by udev, only additional symlinks
can be created.
See also http://lists.kernelnewbies.org/pipermail/kernelnewbies/2015-April/013889.html
Something in that direction has been proposed to the kernel, but it has not been accepted into mainline Linux http://thread.gmane.org/gmane.linux.scsi/70947

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.

Open physical drive from Linux

I'd like to open SD card as physical drive on Linux.
Somethink like:
CreateFile("PHYSICALDRIVE0",...)
On MS Windows.
How can I do it?
All devices are represented as files under the /dev directory. These files can be opened exactly like regular files, e.g. open(/dev/sdb, ...).
Disk-like devices are also symlinked in the directories /dev/disk/by-id/, /dev/disk/by-path, and /dev/disk/by-uuid, which makes it much easier to find to matching device file.
Type df, to list all your filesystems mounted or unmounted. Once you know its address(everything in Linux is a file, so it will look like /dev/sda# or something like that) you can mount it with the mount command:
mount /path/to/drive /folder/to/mount/to
You open the block device special file (typically something like /dev/sdb) and then you can read/write blocks from it.
The interface is not clearly documented, it is a bug that there is no block(4) man page.
The sd(4) man page does help a bit though. The ioctls described there are probably valid for (some) other block devices as well.
Nowadays nearly all block devices appear as a "scsi drive" regardless of whether they are actually attached by scsi or not. This includes USB and (most) ATA drives.
Finding the right device to open may be a big part of the problem though, particularly if you have hotplug devices. You might be able to interrogate some things in /sys to find out what devices there are.

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