how to use i2c driver in kernel space - linux

I have wrote a character driver to control my embedded hardware with my application, In my driver there is a feature to send a command to an I2C device which is connected to my embedded device.
in command line I am able to send the following code to my device:
i2cset -y 0 0x2c 0x00 0x05
I want to do same thing in kernel space within my driver, but I did not find a sample, all I got was in userspace, how can I do that in kernel space?
edit:
I know that with "i2c_master_send" or "i2c_smbus_read_byte" function I can send data to i2c devices, bu this function gets a structure called "i2c_client", I don't know how should I suppose to fill this structure to send data. It might be really silly but I could not figure it out how can I fill this structure.

I have reached my goal with following code in my driver:
****Please read my edit before using this code*****
#define VOL1_CHIP_ADDRESS 0x2c
#define VOL1_DATA_ADDRESS 0
struct i2c_client *clientstr;
struct file * fp;
...
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open("/dev/i2c-0",O_RDWR,0);
clientstr = (struct i2c_client *)fp->private_data;
clientstr->addr=VOL1_CHIP_ADDRESS;
i2c_smbus_write_byte_data(clientstr,VOL1_DATA_ADDRESS,0x05);
filp_close(fp,NULL);
set_fs(oldfs);
EDIT:
So I did what I wanted in kernel, opening a file in kernel space regardless of any suggestions not to do so.
But I needed to open a file in kernel module...
So why every body said don't open user space files in kernel?
In these two articles there are some reasons to not using files in kernel , this link and this link.
there are some reasons like:
1- kernel module may lose CPU at any time and the file which is opened by kernel may close.
2- I am not sure really about this, But they said files needs to have a process to stay opened but kernel module itself is not a process(maybe I am wrong!).
3- If any error happens while working with files(open/close/read/write), kernel module can not handle it and causes kernel panic...
I have experienced a lot of kernel panics only while opening and closing the file I wanted to work with. These are some of reasons why you should not use files in kernel modules, So as every body said before "If you need to use files in kernel module you probably did something wrong in your code!"

Related

How can I make IOCTL calls from a driver to another driver Linux [duplicate]

Roughly speaking, I am trying to issue an IOCTL call from kernel space without going to user space. (All the answers I found in SO propose going through user space).
Specifically, I try to fill the entropy pool (/dev/random) from kernel space (using a kernel module) [I know the dangers of doing this ;)]. Filling up the entropy pool from user space is done using IOCTL, e.g., rngaddentropy. Is there a way to do the same thing from kernel space?
You can use ioctl from the kernel space too.
Because ioctl command RNDADDENTROPY is file-specific, its processing should be implemented in the .unlocked_ioctl operation for /dev/random file (and it is actually implemented this way, see function random_ioctl).
For file-specific ioctl commands you may call .unlocked_ioctl file's operation directly:
// Open file
struct file* f = filp_open("/dev/random", O_WRONLY, 0);
// Replace user space with kernel space
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
f->f_op->unlocked_ioctl(f, RNDADDENTROPY, entropy);
// Restore space
set_fs(old_fs);
// Close file
filp_close(f, 0);

Linux: writing to the i2c/SMBus

I have a problem with the i2c/SMBus on a Linux System with an Intel Apollo Lake processor. I am trying to read/write from/to an EEPROM but I face some issues. My EEPROM is located at the address 0x56, and I am able to watch the Bus with my Logic Analyzer.
When I try to read from the device via i2ctools (i2cget) the System behaves as expected. My issue occurs when I try to perform a write command via i2cset for example. i2cset ends with an error (Write failed). Because I am able to watch the Bus electrically I can also say that all lines stay HIGH and the Bus is not touched. I was able to activate the dev_dbg() functions in the i2c driver i2c_i801 and when I perform i2cset I am able to find (dmesg) the debug message:
[ 765.095591] [2753] i2c_i801:i801_check_post:433: i801_smbus 0000:00:1f.1: No response
When running my minimal I²C Python code using the smbus2 lib, I get the following error message and the above mentioned debug message:
from smbus2 import SMBus
bus = SMBus(0)
b = bus.read_byte_data(86,10) #<- This is performed
b = bus.write_byte_data(86,10,12) #<- This is not performed
bus.close()
Error:
File "usr/local/lib/python3.8/dist-packagers/smbus2-0.4.0-py3.8.egg/smbus/smbus2.py", line 455, in write_byte_data
ioctl(self.fd, I2C_SMBUS, msg)
OSERROR: [Errno 6] No such device or adress
A big hint for me is that I am not able to perform a write command in the address space form 0x50 to 0x57. My guess is that some driver locks the address space to prevent write command to that "dangerous" area.
My question is: "Does anyone know this kind of behavior and is there a solution so that I can write to my EEPROM at address 0x56? OR Is there a lock surrounding the i2c adress space from 0x50 to 0x57 and who is my opponent?"
I am kind of a newbie to the whole driver and kernel world so please be kind and it is quite possible that I made a beginner mistake.
I would appreciate hints and tips I can look after surrounding my problem.
It seems that I found the cause of my problem. In this Forum post is described that Intel changed a configuration Bit at the SMBus controller.
OK, I know what's going on.
Starting with the 8-Series/C220 chipsets, Intel introduced a new
configuration bit for the SMBus controller in register HOSTC (PCI
D31:F3 Address Offset 40h):
Bit 4 SPD Write Disable - R/WO.
0 = SPD write enabled.
1 = SPD write disabled. Writes to SMBus addresses 50h - 57h are
disabled.
This badly documented change in the configuration explains the issues.
One Challenge is, that to apply and enable changes to the SPD-write Bit the System needs to be rebooted. Unfortunately while rebooting the BIOS will change the Bit back to the default. The only solution seems to be an adaption in the BIOS.
For me, this issue is resolved. I just wanted to share this information in case someone faces the same issues.

Getting ENOTTY on ioctl for a Linux Kernel Module

I have the following chardev defined:
.h
#define MAJOR_NUM 245
#define MINOR_NUM 0
#define IOCTL_MY_DEV1 _IOW(MAJOR_NUM, 0, unsigned long)
#define IOCTL_MY_DEV2 _IOW(MAJOR_NUM, 1, unsigned long)
#define IOCTL_MY_DEV3 _IOW(MAJOR_NUM, 2, unsigned long)
module .c
static long device_ioctl(
struct file* file,
unsigned int ioctl_num,
unsigned long ioctl_param)
{
...
}
static int device_open(struct inode* inode, struct file* file)
{
...
}
static int device_release(struct inode* inode, struct file* file)
{
...
}
struct file_operations Fops = {
.open=device_open,
.unlocked_ioctl= device_ioctl,
.release=device_release
};
static int __init my_dev_init(void)
{
register_chrdev(MAJOR_NUM, "MY_DEV", &Fops);
...
}
module_init(my_dev_init);
My user code
ioctl(fd, IOCTL_MY_DEV1, 1);
Always fails with same error: ENOTTY
Inappropriate ioctl for device
I've seen similar questions:
i.e
Linux kernel module - IOCTL usage returns ENOTTY
Linux Kernel Module/IOCTL: inappropriate ioctl for device
But their solutions didn't work for me
ENOTTY is issued by the kernel when your device driver has not registered a ioctl function to be called. I'm afraid your function is not well registered, probably because you have registered it in the .unlocked_ioctl field of the struct file_operations structure.
Probably you'll get a different result if you register it in the locked version of the function. The most probable cause is that the inode is locked for the ioctl call (as it should be, to avoid race conditions with simultaneous read or write operations to the same device)
Sorry, I have no access to the linux source tree for the proper name of the field to use, but for sure you'll be able to find it yourself.
NOTE
I observe that you have used macro _IOW, using the major number as the unique identifier. This is probably not what you want. First parameter for _IOW tries to ensure that ioctl calls get unique identifiers. There's no general way to acquire such identifiers, as this is an interface contract you create between application code and kernel code. So using the major number is bad practice, for two reasons:
Several devices (in linux, at least) can share the same major number (minor allocation in linux kernel allows this) making it possible for a clash between devices' ioctls.
In case you change the major number (you configure a kernel where that number is already allocated) you have to recompile all your user level software to cope with the new device ioctl ids (all of them change if you do this)
_IOW is a macro built a long time ago (long ago from the birth of linux kernel) that tried to solve this problem, by allowing you to select a different character for each driver (but not dependant of other kernel parameters, for the reasons pointed above) for a device having ioctl calls not clashing with another device driver's. The probability of such a clash is low, but when it happens you can lead to an incorrect machine state (you have issued a valid, working ioctl call to the wrong device)
Ancient unix (and early linux) kernels used different chars to build these calls, so, for example, tty driver used 'T' as parameter for the _IO* macros, scsi disks used 'S', etc.
I suggest you to select a random number (not appearing elsewhere in the linux kernel listings) and then use it in all your devices (probably there will be less drivers you write than drivers in the kernel) and select a different ioctl id for each ioctl call. Maintaining a local ioctl file with the registered ioctls this way is far better than trying to guess a value that works always.
Also, a look at the definition of the _IO* macros should be very illustrative :)

How to get a device file name using major and minor number

I am trying add some debug messages in block io to track the io operation in linux kernel.
IO could happen to multiple block device, I have dev_t value with me.
I can get major and minor number from dev_t.
I want to know is there any way to get the device file name from /dev/ dir using these major and minor number?
Of course, I need kernel APIs.
It's simple:
Use bdget function to find the block_device by dev_t.
Use bdevname to get the device name.
Use bdput to put the device reference.
Have fun.
You can also use libudev. Since you already have the dev_t id this way is aesier.
#include <libudev.h>
// Create the udev context.
struct udev *udev = udev_new();
// Create de udev_device from the dev_t.
struct udev_device *dev = udev_device_new_from_devnum(udev, 'b', sb.st_dev);
// Finally obtain the node.
const char* node = udev_device_get_devnode(dev);
udev_unref(udev);
In general, you cannot do such simple reverse mapping. This is because knowing some major and major numbers, one can always use mknod to create valid device file anywhere, not necessarily under /dev.
At the end of the day, kernel does not care much how did any particular device node with certain major/minor came about - such a node is simply entry point into the kernel device driver that can handle this hardware or software device.
Granted, in practice on most modern Linux systems most device nodes are located in /dev and maintained by udev - but it is user-space daemon, which your kernel driver cannot talk to. Also note that udev can be configured to create new device nodes with any name.

How to get Linux kernel modules list from user space C code?

I want to get the list of kernel modules by C code, and later on print their version.
From a script this is simple:
cat /proc/modules
lsmod
and later on, run for all drivers found:
modinfo driver_name
From C code, I can open /proc/modules, and analyze the data there, but is there a simpler way of reading this drivers list?
From C code, I can open /proc/modules, and analyze the data there, but is there a simpler way of reading this drivers list?
Depends on your definition of simple. The concept in Unix land of everything being a file does make everything simpler in one respect, because:
int fd = open("/proc/modules" | O_RDONLY);
while ( read(fd, &buffer, BUFFER_LIMIT) )
{
// parse buffer
}
close(fd);
involves the same set of function calls as opening and reading any file.
The alternative mechanism would be for the kernel to allocate some memory in your process' address space pointing to that information (and you could probably do this with a custom system call) but there's really no need - as you've seen, this way works very well not just with C, but with scripts also.

Resources