Creating a device file: Linux device driver - linux

How to create a device file when I do not know the minor and major number (i.e. by using dynamic registration) without using mknod or MAKEDEV.

Say you want to dynamically assign a major number to a char device on insertion, use:
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
From Linux Device Drivers 3rd Edition. Google it you can get the entire book for free along with tons of great source code for messing with drivers.

Also, the codes provided in the LDD3 are obsolete now. So, use this github repo to download example codes of LDD3: https://github.com/martinezjavier/ldd3

Related

Change the ifindex of netdev

I have the following requirement. I want with a kernel module to change the ifindex of a netdev with one of my choice. I know that it acts as a key and cannot be change during runtime. Created interfaces are based on Intel e1000 driver.
In order to achieve the change the following has been thought:
unregister_netdev(dev);
//Change the dev->ifindex
//bring back network device to operational state somehow, tried register_netdev but this results in kernel panic of course
Can you please inform me if this is somehow possible? I am very new to linux kernel drivers.
Thank you!
I think I have found a trick/way to tackle this issue:
create a dummy network namespace
use dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) to move device to this namespace
then use __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) to move dev to init_net with the
desired new_ifindex
delete dummy network namespace
In my kernel __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) does not exist but it is not though so hard to be created since it only pickups a new_ifindex in case it is not provided, or checks the provided one if it is currently used inside namespace
Not tested yet, but it will be very soon.

Register level access in linux device driver

I have only 2 weeks experience in linux driver development, but have good experience on embedded c programming. I have only tried character device driver in linux. Now i wish to try a device driver for a set of LED's connected to GPIO. I am using BeagleBone Black. I wish to access it from the register level and not by just calling any driver. (I am doing this to learn the basics)
I wish my driver GPIO access code to be somewhat like below
void SetLED(unsigned char LED,unsigned char Status){
//Read the port register
//BitWise Operation according to function parameters
//Write back to the register
}
But i need some help on how to access the registers directly in linux. I have got the actual address of the port OUT register from the datasheet as 0x4804C13C
Pardon me if i am breaking any basics in my question. I am really new to linux.
Your driver has to call
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
to register exclusive access to that region of memory.
Then it must use ioread8(),ioread16(), etc. and iowrite8(),iowrite16(), etc.

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.

linux gpio c api

I have an powerpc board with 3.2 kernel running on it. Accessing gpio with sysfs works as expected e.g.
> echo 242 > /sys/class/gpio/export
> cat /sys/class/gpio/gpio242/value
> 1
Is there no API to direct access gpio pins from user space? Must I deal with the text based sysfs interface?
I seach for something like:
gpio_set(int no, int val);
Thanks
Klaus
GPIO access through sysfs has been deprecated since Linux 4.8.
The new way for user space access is through libgpiod, which includes a library to link with (obviously), as well as some tools which can be run from the command line (for scripting convenience). Notably, GPIO lines are referenced with the line name string rather than an integer identifier, like with sysfs. E.g.
gpioset $(gpiofind "USR-LED-2")=1
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README
Edit: sysfs direct access for GPIOs is deprecated, new way is programmatic through libgpiod
sysfs is the lowest level at which you will be able to manipulate GPIO in recent kernels. It can be a bit tedious but it offers several advantages over the old style API:
No ugly ioctl
Can be scripted very easily (think startup scripts)
For inputs, the "value" file can easily be poll-ed for rising/falling/both edges and it will be very reactive to hardware interrupts
I have no example code at the moment but when accessing them through C code, I often implemented a very simple wrapper manipulating file descriptors and having variations of the following interface:
int gpio_open(int number, int out); /* returns handle (fd) */
int gpio_close(int gpio);
int gpio_set(int gpio, int up);
int gpio_get(int gpio, int *up);
int gpio_poll(int gpio, int rising_edge, int timeout);
From then, the implementation is pretty straightforward.
Once you have the devices created in the vfs tree, you can open them like typical files assuming you have a driver written and have the correct major and minor numbers assigned in the makedev file that creates the gpio pins on the vfs tree.
Every GPIO is memory mapped as a register, so you can access to it through /dev/mem. See here. If you want to access directly to a GPIO you have to work at kernel space level

What is the difference between register_chrdev_region and alloc_chrdev_region to allocate device numbers?

I want to know the difference between these two functions:
int register_chrdev_region(dev_t first, unsigned int count, char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
See here for details on these two functions.
Registration is only really useful if you know in advance which major number you want to start with. With registration, you tell the kernel what device numbers you want (the start major/minor number and count) and it either gives them to you or not (depending on availability).
With allocation, you tell the kernel how many device numbers you need (the starting minor number and count) and it will find a starting major number for you, if one is available, of course.
Partially to avoid conflict with other device drivers, it's considered preferable to use the allocation function, which will dynamically allocate the device numbers for you.
From the link given above:
Some major device numbers are statically assigned to the most common devices. A list of those devices can be found in Documentation/devices.txt within the kernel source tree. The chances of a static number having already been assigned for the use of your new driver are small, however, and new numbers are not being assigned. So, as a driver writer, you have a choice: you can simply pick a number that appears to be unused, or you can allocate major numbers in a dynamic manner.
Picking a number may work as long as the only user of your driver is you; once your driver is more widely deployed, a randomly picked major number will lead to conflicts and trouble.
Thus, for new drivers, we strongly suggest that you use dynamic allocation to obtain your major device number, rather than choosing a number randomly from the ones that are currently free. In other words, your drivers should almost certainly be using alloc_chrdev_region rather than register_chrdev_region.
The disadvantage of dynamic assignment is that you can't create the device nodes in advance, because the major number assigned to your module will vary. For normal use of the driver, this is hardly a problem, because once the number has been assigned, you can read it from /proc/devices.
There's a related, but not technically duplicate, question here.
To put in simple terms:
You use register_chrdev_region when you have the device ID for your character driver with you and you want to inform the VFS that reserve this device ID (basically the Major Number) for your driver.
dev_t mydev;
mydev = MKDEV(MAJORNO, MINORNO);//you have already decided on a static majorno and minorno
register_chrdev_region(mydev, count, CHAR_DEV_NAME)
//**here you are supplying the device ID in mydev**
You use alloc_chrdev_region when you are asking the VFS to give you a free device ID (which is basically the major number) for your character driver.
dev_t mydev;
//you are asking VFS for the device ID
alloc_chrdev_region(&mydev, start_minor_no, count, CHAR_DEV_NAME)
//**Here you get the device ID in mydev**.
As per the LDD3 Document,
When setting up a character device is to obtain one or more device numbers to work with. The necessary function for this task is,
int register_chrdev_region(dev_t first, unsigned int count, char *name);
(or)
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,
unsigned int count, char *name);
Note that, register_chrdev_region works well if you know ahead of time exactly which device numbers you want. Often, however, you will not know which major numbers your device will use; there is a constant effort within the Linux kernel development community to move over to the use of dynamicly-allocated device numbers. The kernel will happily allocate a major number for you on the fly, but you must request this allocation by using a alloc_chrdev_region. Basically its a dynamic Allocation of the Major number.
Thus, for new drivers, we strongly suggest that you use dynamic allocation to obtain your major device number, rather than choosing a number randomly from the ones that are currently free. In other words, your drivers should almost certainly be using alloc_chrdev_region rather than register_chrdev_region.

Resources