Linux Char Driver - linux-kernel

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.

Related

What is the purpose of the function "blk_rq_map_user" in the NVME disk driver?

I am trying to understand the nvme linux drivers. I am now tackling the function nvme_user_submit_cmd, which I report partially here:
static int nvme_submit_user_cmd(struct request_queue *q,
struct nvme_command *cmd, void __user *ubuffer,
unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
u32 meta_seed, u32 *result, unsigned timeout)
{
bool write = nvme_is_write(cmd);
struct nvme_ns *ns = q->queuedata;
struct gendisk *disk = ns ? ns->disk : NULL;
struct request *req;
struct bio *bio = NULL;
void *meta = NULL;
int ret;
req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
[...]
if (ubuffer && bufflen) {
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
GFP_KERNEL);
[...]
The ubufferis a pointer to some data in the virtual address space (since this comes from an ioctl command from a user application).
Following blk_rq_map_user I was expecting some sort of mmap mechanism to translate the userspace address into a physical address, but I can't wrap my head around what the function is doing. For reference here's the call chain:
blk_rq_map_user -> import_single_range -> blk_rq_map_user_iov
Following those function just created some more confusion for me and I'd like some help.
The reason I think that this function is doing a sort of mmap is (apart from the name) that this address will be part of the struct request in the struct request queue, which will eventually be processed by the NVME disk driver (https://lwn.net/Articles/738449/) and my guess is that the disk wants the physical address when fulfilling the requests.
However I don't understand how is this mapping done.
ubuffer is a user virtual address, which means it can only be used in the context of a user process, which it is when submit is called. To use that buffer after this call ends, it has to be mapped to one or more physical addresses for the bios/bvecs. The unmap call frees the mapping after the I/O completes. If the device can't directly address the user buffer due to hardware constraints then a bounce buffer will be mapped and a copy of the data will be made.
Edit: note that unless a copy is needed, there is no kernel virtual address mapped to the buffer because the kernel never needs to touch the data.

Create array of struct scatterlist from buffer

I am trying to build an array of type "struct scatterlist", from a buffer pointed by a virtual kernel address (I know the byte size of the buffer, but it may be large). Ideally I would like to have function like init_sg_array_from_buf:
void my_function(void *buffer, int buffer_length)
{
struct scatterlist *sg;
int sg_count;
sg_count = init_sg_array_from_buf(buffer, buffer_length, sg);
}
Which function in the scatterlist api, does something similar? Currently the only possibility I see, is to manually determine the amount of pages, spanned by the buffer. Windows has a kernel macro called "ADDRESS_AND_SIZE_TO_SPAN_PAGES", but I didn't even manage to find something like this in the linux kernel.

how to define a struct msghdr to send UDP packet in linux kernel without copying data from user space

I'm trying to send a Hello message from linux kernel after a UDP connect (which calls the function ip4_datagram_connect). Since the protocol number in this message needs to be different than UDP (This is a custom protocol which I'm building with UDP as the base code), I can't use the netpoll API.
So I'm trying to use the functions (picked up from udp_sendmsg())-
ip_make_skb(struct sock *sk,
struct flowi4 *fl4,
int getfrag(void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen,
struct ipcm_cookie *ipc, struct rtable **rtp,
unsigned int flags)
to generate the sk_buff and
int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
to send out the generated sk_buff.
My problem is, the function ip_make_skb requires the pointers *from and length which in the udp_sendmsg function are the pointer to and the length of the data in the user space(+ length of udphdr) and then ip_make_skb() copies the data from the userspace. Since I'm just sending a Hello message from the kernel, this is a wasteful step for me (I don't need any data from the user space).
So can I just set the *from pointer to some dummy location and length to zero(+sizeof(struct udphdr))? If yes, what kind of value for *from will be appropriate?
Or is this completely wrong and I should do something else?
Edit 1: For now, I'm doing this
void *from = "Hello";
This will give me a valid pointer in the memory, but I feel it's a dirty way to do this. Tt works though.

sysfs: free to use struct device platform_data field?

Summary: is the platform_data field of struct device free to use in a device driver module?
I am creating a very simple sysfs entry for my character device driver module to allow me to control an internal variable (because I know using ioctl() and the proc filesystem are deprecated.) I call class_create() to make a class in /sys/class/ and then device_create() to make a new device entry. Then I call device_create_file() to set up my load and store routines for the driver. I want to lock my driver in these routines. I have a mutex in my driver's main structure. Can I use the platform_data field to store a pointer to this structure like I would the private_data field of struct file in the module's open() routine or is this reserved? It's set to NULL after device_create so it would appear OK but I don't know for sure.
What I'd like to do is:
struct mymodule mymod; // main module structure, has a mutex called lockmx
static ssize_t mydev_store_val(struct device *dev,
struct device_attribute *attr,
const char *buf,size_t count)
{
struct mymodule *mymodp=(struct mymodule*)dev->platform_data;
if(mutex_lock_interruptible(&mymodp->lockmx))
return 0;
// get data from buf
mutex_unlock(&mymodp->lockmx);
return count;
}
DEVICE_ATTR(mydeva,S_IWUSR|S_IRUGO,NULL,mydev_store_val);
static int __init modinit(void)
{
...
dev_t dev; // alloc'ed already
myclass=class_create(THIS_MODULE,"myclass");
mydev=device_create(myclass,NULL,dev,NULL,"mydev");
mydev->platform_data=&mymod;
device_create_file(mydev,&dev_attr_mydeva);
...
}
So this will create the entry /sys/class/myclass/mydev/mydeva which can be written to. If the platform_data field is available then I can avoid using globals. But if it moves under me my kernel is going to oops at best and probably panic.
Such a pointer can be stored in the drvdata field (which has been cleverly hidden so that you will not see it if you look at the definition of struct device).
Initialize it through the fourth parameter of device_create, and read it with dev_get_drvdata:
mydev = device_create(myclass, NULL, dev, &mymod, "mydev");
...
struct mymodule *mymodp = dev_get_drvdata(dev);

Where to find the general definition of i2c "master_xfer" function?

struct i2c_algorithm has function pointer template for master_xfer for i2c bus implementation. Where can I find the default function routine of master_xfer in linux kernel source.?
Please someone guide me..
What master_xfer is set to depends on your platform and bus. Look under drivers/i2c/busses/ to find where this function pointer is set. Note that it could be set to NULL.
An example of where it is set is in drivers/i2c/busses/i2c-pxa.c:
static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
Also look at include/linux/i2c.h:
struct i2c_algorithm {
/* If an adapter algorithm can't do I2C-level access, set master_xfer
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
};
:
* An i2c_msg is the low level representation of one segment of an I2C
* transaction. It is visible to drivers in the #i2c_transfer() procedure,
* to userspace from i2c-dev, and to I2C adapter drivers through the
* #i2c_adapter.#master_xfer() method.
*
There is i2c-gpio.c file in /driver/i2c/busses/. In that we are filling master_xfer function with bit_xfer. It does bit banging implementation.

Resources