I2C read write functions in linux - linux-kernel

How is the read and write functions in I2C drivers for linux are communicated to linux? In all the drivers for devices on I2C in the linux source, the file_operations structure is not used to tell the kernel about the functions. How is the various functionalities communicated to kernel, so they can be called from user space without using file_operations?

I2C driver in linux support the file operation as well. Because when you start open i2c from your application;
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
It will call to the i2c-dev.c file in linux kernel
static int i2cdev_open(struct inode *inode, struct file *file);
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
But if you want to read and write from the user space without file_operatoin then you can use the kobject in your driver for read and write through sysfs.
For reading from the user space:
static ssize_t module_show_status(struct kobject *kobj,struct kobj_attribute *attr,char *buf);
For writing from the user space
static ssize_t module_store__status(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t count);
But before using these APIs you need to create the kboject in your driver.

Related

How kernel knows the presence of netlink in userspace?

I am working on netlink sockets, written code for application and kernel module. Kernel module will send notifications regularly to user space application. If application gets killed, kernel module doesn't stop sending notification. How the kernel will know when application gets killed? Can we user bind and unbind in netlink_kernel_cfg for this purpose? I have searched a lot but didn't find any information on this.
When any application is killed in Linux, all file descriptors (including socket descriptors) are closed. In order to have your kernel module notified when the application closes the netlink socket you need to implement the optional .unbind op in struct netlink_kernel_cfg.
include/linux/netlink.h
/* optional Netlink kernel configuration parameters */
struct netlink_kernel_cfg {
unsigned int groups;
unsigned int flags;
void (*input)(struct sk_buff *skb);
struct mutex *cb_mutex;
int (*bind)(struct net *net, int group);
void (*unbind)(struct net *net, int group);
bool (*compare)(struct net *net, struct sock *sk);
};
Set the configuration parameters in your module:
struct netlink_kernel_cfg cfg = {
.unbind = my_unbind,
};
netlink = netlink_kernel_create(&my_netlink, ... , &cfg);
To understand how this is used, note the following fragment from the netlink protocol family proto_ops definition:
static const struct proto_ops netlink_ops = {
.family = PF_NETLINK,
.owner = THIS_MODULE,
.release = netlink_release,
.release is called upon close of the socket (in your case, due to the application being killed).
As a part of its cleanup process, netlink_release() has the following implementation:
net/netlink/af_netlink.c
if (nlk->netlink_unbind) {
int i;
for (i = 0; i < nlk->ngroups; i++)
if (test_bit(i, nlk->groups))
nlk->netlink_unbind(sock_net(sk), i + 1);
Here you can see that if the optional netlink_unbind has been provided, then it will be executed, providing you a callback when your application has closed the socket (either gracefully or as a result of being killed).

Registering Platform Device with info from Device Tree

I am using Petalinux for a Xilinx Zynq application, and I am new to kernel driver development.
I created a kernel module for a platform driver for an AXI FIFO interface. The devices seems to be recognised from the device tree using the .of_match_table, since I can see the correct memory space reserved with cat /proc/iomem .
If I search for the driver name xxx I get
./lib/modules/4.4.0-xilinx/extra/xxx.ko
./sys/bus/platform/drivers/xxx
./sys/module/xxx
./sys/module/xxx/drivers/platform:xxx
I found the device under /sys/bus/platform/devices/43c00000.axi_xxxx but still can't access it or see it under /dev/.
How do I register device so that I can open it from my user space app?.
Do I need to allocate memory for it and then register a new device using platform_device_register(pdev)?
Thanks
You need to register your device in a framework to get a device file created.
I would suggest registering a miscdevice in your case. It simply registers a character device.
static struct miscdevice miscdev;
static ssize_t myaxi_read(struct file *file, char __user *buf,
size_t sz, loff_t *ppos)
{
// Do something
}
static ssize_t myaxi_write(struct file *file, const char __user *buf,
size_t sz, loff_t *ppos)
{
// Do something
}
static const struct file_operations myaxi_fops = {
.owner = THIS_MODULE,
.write = myaxi_write,
.read = myaxi_read,
};
In your probe:
miscdev.minor = MISC_DYNAMIC_MINOR;
miscdev.name = "myaxi";
miscdev.fops = &myaxi_fops;
misc_register(&miscdev);
You can read more about linux kernel driver development and the device model at http://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf

Linux Char Driver

Can anyone tell me how a Char Driver is bind to the corresponding physical device?
Also, I would like to know where inside a char driver we are specifying the physical device related information, which can be used by kernel to do the binding.
Thanks !!
A global array — bdev_map for block and cdev_map for character devices — is used to implement a hash table, which employs the device major number as hash key.
while registering for char driver following calls get in invoked to get major and minor numbers.
int register_chrdev_region(dev_t from, unsigned count, const char *name)
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name);
After a device number range has been obtained, the device needs to be activated by adding it to the character device database.
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
Here on cdev structure initialize with file operation and respected character device.
Whenever a device file is opened, the various filesystem implementations invoke the init_special_inode function to create the inode for a block or character device file.
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
}
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
mode);
}
now the default_chr_fpos chrdev_open() method will get invoked. which will look up for the inode->rdev device in cdev_map array and will get a instance of cdev structure. with the reference to cdev it will bind the file->f_op to cdev file operation and invoke the open method for character driver.
In a character driver like I2C client driver, We specify the slave address in the client structure's "addr" field and then call i2c_master_send() or i2c_master_receive() on this client . This calls will ultimately go to the main adapter controlling that line and the adapter then communicates with the device specified by the slave address.
And the binding of drivers operations is done mainly with cdev_init() and cdev_add() functions.
Also driver may choose to provide probe() function and let kernel find and bind all the devices which this driver is capable of supporting.

writing data to debugfs --- from a device driver

With proc we can easily use read & write system call as shown in this example.
write on /proc entry through user space
But i am working on passing information from driver to user-space using debugfs.
I am able to find these two example code. Here application is able to read and write to debugfs file using mmap() system call.
http://people.ee.ethz.ch/~arkeller/linux/code/mmap_simple_kernel.c
http://people.ee.ethz.ch/~arkeller/linux/code/mmap_user.c
But suppose in my case requirement for communicating using Debugfs file with device driver:
user-space application <-------> debugfs file <-------> Device driver
So can i use same code mmap_simple_kernel.c inside my --->> device driver code --->> and transfer data to debugfs directly from driver ? But in this case there will be two file_operations structures inside my driver will it cause some problem ? Is it right approach ?
Or just like application is following process in -- mmap_user.c --- same process -- i follow in my device driver program. And keep mmap_simple_kernel.c as seprate module for debugfs entry ?
You can take a look at how kmemleak uses debugfs in mm/kmemleak.c:
static const struct seq_operations kmemleak_seq_ops = {
.start = kmemleak_seq_start,
.next = kmemleak_seq_next,
.stop = kmemleak_seq_stop,
.show = kmemleak_seq_show,
};
static int kmemleak_open(struct inode *inode, struct file *file)
{
return seq_open(file, &kmemleak_seq_ops);
}
static int kmemleak_release(struct inode *inode, struct file *file)
{
return seq_release(inode, file);
}
static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
size_t size, loff_t *ppos)
{...}
static const struct file_operations kmemleak_fops = {
.owner = THIS_MODULE,
.open = kmemleak_open,
.read = seq_read,
.write = kmemleak_write,
.llseek = seq_lseek,
.release = kmemleak_release,
};
dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL,
&kmemleak_fops);
This question is the top search result in Google for mmap debugfs. I am adding here an important information. According to this https://lkml.org/lkml/2016/5/21/73 post debugfs_create_file() in the kernel 4.8.0 or higher will ignore .mmap field in the struct file_operations
Use debugfs_create_file_unsafe() as a workaround

Memory limit for mmap

I am trying to mmap a char device. It works for 65536 bytes. But I get the following error if I try for more memory.
mmap: Resource temporarily unavailable
I want to mmap 1MB memory for a device. I use alloc_chrdev_region, cdev_init, cdev_add for the char device. How can I mmap memory larger than 65K? Should I use block device?
Using the MAP_LOCKED flag in the mmap call can cause this error. The used mlock can return EAGAIN if the amount of memory can not be locked.
From man mmap:
MAP_LOCKED (since Linux 2.5.37) Lock the pages of the mapped region
into memory in the manner of mlock(2). This flag is ignored in older
kernels.
From man mlock:
EAGAIN:
Some or all of the specified address range could not be
locked.
Did you implement *somedevice_mmap()* file operation?
static int somedev_mmap(struct file *filp, struct vm_area_struct *vma)
{
/* Do something. You probably need to use ioremap(). */
return 0;
}
static const struct file_operations somedev_fops = {
.owner = THIS_MODULE,
/* Initialize other file operations. */
.mmap = somedev_mmap,
};

Resources