Linux PCIe Driver: What to use for private data structure? - linux

I'm creating my first PCIe driver for Linux and have a question regarding which structure to use for the pci_set_drvdata() function.
The PCIe hardware is built in house and we will be using DMA to send data to and from the device. It is not a sound card or any other subsystem which needs to be plugged into the kernel.
When I look at examples there seems to be a specific struct to fill in and then send to pci_set_drvdata().
What do I fill in for this case? Do I simply ignore this and send in a blank structure? The line I am referring to in any PCIe driver is:
struct structure_in_question *my_struct;
my_struct = kzalloc( sizeof(*my_struct), GFP_KERNEL) );
This is usually found in the probe() function.

That function is used for associating with the device private data that cannot be supplied any other way. If there is no such data then the function should simply not be used.

It is a convenient way for example to save a pointer to a local dynamically allocated device context in the device probe callback and then retrieve it back with pci_get_drvdata in the device remove callback and do a proper cleanup of the context.

Related

Where the probe() function's argument comes from?

I'm studying linux device driver. currently, I understand flows of device driver approximatively, but I dont know how probe() function gets its arguments.
For example, here is my code and this is based on kernel 3.10.
static int gpio_led_probe(struct platform_device *pdev) {
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
....
priv = gpio_leds_create_of(pdev);
....
}
As like this, the argument 'pdev' is using for various point of source. I'm understading when probe() called and it's role, but I cannot find where the data 'pdev' comes from.
thanks for read my thread, and sorry that my english is not good.
platform device specific data while probing comes from the platform setup code or from device tree.
you can find the related code in arch/arm/borad/device files
struct platform_device embedded with platform_data structure where you will pass the platform related data to the drivers.
in modern kernels platform data is passed to device drivers through device tree. device tree can be found in /arch/arm/boot/dts/your_device
You can provide the platform device information by filling the platform_device structure or you have to provide your device information in device tree, during system bootup, platform_device structure gets populated based on the device tree information.In latest kernel usually we use device tree to get the device information.

Linux DMA API: specifying address increment behavior?

I am writing a driver for Altera Soc Developement Kit and need to support two modes of data transfer to/from a FPGA:
FIFO transfers: When writing to (or reading from) an FPGA FIFO, the destination (or source) address must not be incremented by the DMA controller.
non-FIFO transfers: These are normal (RAM-like) transfers where both the source and destination addresses require an increment for each word transferred.
The particular DMA controller I am using is the CoreLink DMA-330 DMA Controller and its Linux driver is pl330.c (drivers/dma/pl330.c). This DMA controller does provide a mechanism to switch between "Fixed-address burst" and "Incrementing-address burst" (these are synonymous with my "FIFO transfers" and "non-FIFO transfers"). The pl330 driver specifies which behavior it wants by setting the appropriate bits in the CCRn register
#define CC_SRCINC (1 << 0)
#define CC_DSTINC (1 << 14)
My question: it is not at all clear to me how clients of the pl330 (my driver, for example) should specify the address-incrementing behavior.
The DMA engine client API says nothing about how to specify this while the DMA engine provider API simply states:
Addresses pointing to RAM are typically incremented (or decremented)
after each transfer. In case of a ring buffer, they may loop
(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO)
are typically fixed.
without giving any detail as to how the address types are communicated to providers (in my case the pl300 driver).
The in the pl330_prep_slave_sg method it does:
if (direction == DMA_MEM_TO_DEV) {
desc->rqcfg.src_inc = 1;
desc->rqcfg.dst_inc = 0;
desc->req.rqtype = MEMTODEV;
fill_px(&desc->px,
addr, sg_dma_address(sg), sg_dma_len(sg));
} else {
desc->rqcfg.src_inc = 0;
desc->rqcfg.dst_inc = 1;
desc->req.rqtype = DEVTOMEM;
fill_px(&desc->px,
sg_dma_address(sg), addr, sg_dma_len(sg));
}
where later, the desc->rqcfg.src_inc, and desc->rqcfg.dst_inc are used by the driver to specify the address-increment behavior.
This implies the following:
Specifying a direction = DMA_MEM_TO_DEV means the client wishes to pull data from a FIFO into RAM. And presumably DMA_DEV_TO_MEM means the client wishes to push data from RAM into a FIFO.
Scatter-gather DMA operations (for the pl300 at least) is restricted to cases where either the source or destination end point is a FIFO. What if I wanted to do a scatter-gather operation from system RAM into FPGA (non-FIFO) memory?
Am I misunderstanding and/or overlooking something? Does the DMA engine already provide a (undocumented) mechanism to specify address-increment behavior?
Look at this
pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
pd->device_prep_slave_sg = pl330_prep_slave_sg;
It means you have different approaches like you have read in documentation. RAM-like transfers could be done, I suspect, via device_prep_dma_memcpy().
It appears to me (after looking to various drivers in a kernel) the only DMA transfer styles which allows you (indirectly) control auto-increment behavior is the ones which have enum dma_transfer_direction in its corresponding device_prep_... function.
And this parameter declared only for device_prep_slave_sg and device_prep_dma_cyclic, according to include/linux/dmaengine.h
Another option should be to use and struct dma_interleaved_template which allows you to specify increment behaviour directly. But support for this method is limited (only i.MX DMA driver does support it in 3.8 kernel, for example. And even this support seems to be limited)
So I think, we are stuck with device_prep_slave_sg case with all sg-related complexities for a some while.
That is that I am doing at the moment (although it is for accessing of some EBI-connected device on Atmel SAM9 SOC)
Another thing to consider is a device's bus width. memcopy-variant can perform different bus-width transfers, depending on a source and target addresses and sizes. And this may not match size of FIFO element.

Designing a Linux char device driver so multiple processes can read

I notice that for serial devices, e.g. /dev/ttyUSB0, multiple processes can open the device but only one process gets the bytes (whichever reads them first).
However, for the Linux input API, e.g. /dev/input/event0, multiple processes can open the device, and all of the processes are able to read the input events.
My current goal:
I'd like to write a driver for several multi-position switches (e.g. like a slider switch with 3 or 4 possible positions), where apps can get a notification of any switch position changes. Ideally I'd like to use the Linux input API, however it seems that the Linux input API has no support for the concept of multi-position switches. So I'm looking at making a custom driver with similar capabilities to the Linux input API.
Two questions:
From a driver design point-of-view, why is there that difference in behaviour between Linux input API and Linux serial devices? I reckon it could be useful for multiple processes to all be able to open one serial port and all listen to incoming bytes.
What is a good way to write a Linux character device driver so that it's like the Linux input API, so multiple processes can open the device and read all the data?
The distinction is partly historical and partly due to the different expectation models.
The event subsystem is designed for unidirectional notification of simple events from multiple writers into the system with very little (or no) configuration options.
The tty subsystem is intended for bidirectional end-to-end communication of potentially large amounts of data and provides a reasonably flexible (albeit fairly baroque) configuration mechanism.
Historically, the tty subsystem was the main mechanism of communicating with the system: you plug your "teletype" into a serial port and bits went in and out. Different teletypes from different vendors used different protocols and thus the termios interface was born. To make the system perform well in a multi-user context, buffering was added in the kernel (and made configurable). The expectation model of the tty subsystem is that of a point-to-point link between moderately intelligent endpoints who will agree on what the data passing between them will look like.
While there are circumstances where "single writer, multiple readers" would make sense in the tty subsystem (GPS receiver connected to a serial port, continually reporting its position, for instance), that's not the main purpose of the system. But you can easily accomplish this "multiple readers" in userspace.
The event system on the other hand, is basically an interrupt mechanism intended for things like mice and keyboards. Unlike teletypes, input devices are unidirectional and provide little or no control over the data they produce. There is also little point in buffering the data. Nobody is going to be interested in where the mouse moved ten minutes ago.
I hope that answers your first question.
For your second question: "it depends". What do you want to accomplish? And what is the "longevity" of the data? You also have to ask yourself whether it makes sense to put the complexity in the kernel or if it wouldn't be better to put it in userspace.
Getting data out to multiple readers isn't particularly difficult. You could create a receive buffer per reader and fill each of them as the data comes in. Things get a little more interesting if the data comes in faster than the readers can consume it, but even that is mostly a solved problem. Look at the network stack for inspiration!
If your device is simple and just produces events, maybe you just want to be an input driver?
Your second question is a lot more difficult to answer without knowing more about what you want to accomplish.
Update after you added your specific goal:
When I do position switches, I usually just create a character device and implement poll and read. If you want to be fancy and have a lot of switches, you could do mmap but I wouldn't bother.
Userspace just opens your /dev/foo and reads the current state and starts polling. When your switches change state, you just wake up the readers and they they'll read again. All your readers will wake up, they'll all read the new state and everyone will be happy.
Be careful to only wake up readers when your switches are 'settled'. Many position switches are very noisy and they'll bounce around a fair bit.
In other words: I would ignore the input system altogether for this. As you surmise, position switches are not really "inputs".
How a character device handles these kinds of semantics is completely up to the driver to define and implement.
It would certainly be possible, for example, to implement a driver for a serial device that will deliver all read data to every process that has the character driver open. And it would also be possible to implement an input device driver that delivers events to only one process, whichever one is queued up to receive the latest event. It's all a matter of coding the appropriate implementation.
The difference is that it all comes down to a simple question: "what makes sense". For a serial device, it's been decided that it makes more sense to handle any read data by a single process. For an input device, it's been decided that it makes more sense to deliver all input events to every process that has the input device open. It would be reasonable to expect that, for example, one process might only care about a particular input event, say pointer button #3 pressed, while another process wants to process all pointer motion events. So, in this situation, it might make more sense to distribute all input events to all concerned parties.
I am ignoring some side issues, for simplicity, like in the situation of serial data being delivered to all reading processes what should happen when one of them stops reading from the device. That's also something that would be factored in, when deciding how to implement the semantics of a particular device.
What is a good way to write a Linux character device driver so that it's like the Linux input API, so multiple processes can open the device and read all the data?
See the .open member of struct file_operations for the char device. Whenever userspace opens the device, then the .open function is called. It can add the open file to a list of open files for the device (and then .release removes it).
The char device data struct should most likely use a kernel struct list_head to keep a list of open files:
struct my_dev_data {
...
struct cdev cdev;
struct list_head file_open_list;
...
}
Data for each file:
struct file_data {
struct my_dev_data *dev_data;
struct list_head file_open_list;
...
}
In the .open function, add the open file to dev_data->file_open_list (use a mutex to protect these operations as needed):
static int my_dev_input_open(struct inode * inode, struct file * filp)
{
struct my_dev_data *dev_data;
dev_data = container_of(inode->i_cdev, struct my_dev_data, cdev);
...
/* Allocate memory for file data and channel data */
file_data = devm_kzalloc(&dev_data->pdev->dev,
sizeof(struct file_data), GFP_KERNEL);
...
/* Add open file data to list */
INIT_LIST_HEAD(&file_data->file_open_list);
list_add(&file_data->file_open_list, &dev_data->file_open_list);
...
file_data->dev_data = dev_data;
filp->private_data = file_data;
}
The .release function should remove the open file from dev_data->file_open_list, and release the memory of file_data.
Now that the .open and .release functions maintain the list of open files, it is possible for all open files to read data. Two possible strategies:
A separate read buffer for each open file. When data is received, it is copied into the buffers of all open files.
A single read buffer for the device, but a separate read pointer for each open file. Data can be freed from the buffer once it has been read through all open files.
Serial to input/event
You could try to look into serial mouse driver source code.
This seem to be what you're searching for: from a TTYSx build a input/event device.
Simplier: creating a server, instead of a driver.
Historically, the 1st character device I remember is /dev/lp0.
To be able to write on it from many source, without overlap or other conflict,
a LPR server was wrotten.
To share a device, you have to
open this device in exclusive (rw) mode.
Create a socket (un*x or TCP) to listen on
redirect request from socket's clients to the device and maybe
store device status (from reading device's answers)
send device status to socket's clients when required.

Linux input event interface numbering

In Linux, how do you create an input event interface with a user specified event number and map that to a specific device event?
I'm using the gpio-keys driver to translate key presses from a keypad. I define the keys to be used in my board configuration source file as shown below
static struct gpio_keys_button ev_keys[] = {
[0] = {
.type = EV_KEY,
.active_low = 1,
.wakeup = 0,
.debounce_interval = KEYS_DEBOUNCE_MS,
.code = KEY_MUTE,
.desc = "mute",
.gpio = PUSHBUTTON_MUTE,
}
};
and register this with the kernel.
And I enable the event interface and GPIO buttons when building the kernel.
Device Drivers ---> Input device support --> Event interface
Device Drivers ---> Input device support --> Keyboards --> GPIO buttons
This creates a node to the event at /dev/input/event0 to which the GPIO button events are mapped. In a system that uses only one event interface I can call poll() on the fd to /dev/input/event0 and everything works as expected.
Now, I have second peripheral on my system that uses /dev/input/event0 by default and I need to map the events from the gpio-keys driver to another event. Any suggestions on how I go about creating an event with a number/id I can specify and then map this to the gpio-keys events?
Thanks.
If you mean by "mapping" specifying the name of the /dev/input/eventX 'file', you should use Udev. The kernel assigns the number of the event device, it is a bad idea and probably impossible to try and force this number since you never know which other device may have gotten this number first.
My recommendation would be to let Udev create a symlink that points to your device; you can choose your own name and use that in your program (i.e. /dev/my_first_keypad). For example, my Wacom tablet is assigned /dev/wacom with the following udev rule:
KERNEL=="event*", SUBSYSTEM=="input", SUBSYSTEMS=="input", ATTRS{name}=="Wacom Volito", SYMLINK+="wacom"
The trick is to find the proper set of variables to exactly specify your keypad. If it is USB based, the vender/product ID are a good start. Otherwise, use udevadm info --export-db to get a full dump of the Udev database. Udev rules go in files in /etc/udev/rules.d/ or /lib/udev.d, depending on the Linux distribution you are using.
You can check System.map file for functions that register event interface. The one that comes first, usually gets lowest eventX number and later functions gets eventX number increased by one. IMO, its ok to rely on static device node file for embedded device where device configuration is static and is not going to change during operation, but generally you should use udev for you purposes.

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.

Resources