Pages

Creating a misc characther device and reading from it

Linux has misc devices which meant for small device drivers. According to the article written by Alessandro Rubini Miscellaneous Character Drivers :

Sometimes people need to write “small” device drivers, to support custom hacks—either hardware or software ones. To this end, as well as to host some real drivers, the Linux kernel exports an interface to allow modules to register their own small drivers. The misc driver was designed for this purpose.

miscdevice is declared as the structure in miscdevice.h



For this example we will just use the first three fields.



The name of the device can be any name that the user wants. The minor number can be statically assigned by the user , if it has to be dynamically assigned by the user , the value has to be set to `MISC_DYNAMIC_MINOR.

Thus our device structure will look as below.



To register a misc device the function used is



We can create a characther string which will hold the data for now which will be sent out everytime the device is read. Thus we create a function to fill the data for the device.



The init function for the device will have to register the device. Unlike a charachter device, we dont need to get a major number for a misc device as the default major number for misc devices is 10. To see the minor number which will be assigned dynamically we will add a print statement to get the minor number.



We will create two file operations for this, one to open the device and one to read from the device. Thus the file operations structure will be



The open function will fill data into the device,which we can read using the read function.



The read function will copy the contents of the device to the userspace.



Thus the full code misc device will be



Save the above code as misc_device_read.c

Use the following makefile to compile the code.



Compile and insert the code using



To see the minor number allocated to the device, use dmesg



We can also view the minor number and find if the device got registered succssfully by looking into the file /proc/misc



The device will automatically get listed under /dev which we can view using the ls command.



We can see that the major number is 10 and the minor number is 55.

To read the device, we can use the cat command.




Using average and averagea in libreoffice

If we want to find the average of values in a column in libreoffice, and the column has mix of numbers and characters we can use the function "AVERAGE" which takes input the range of cells ,but the drawback is that the function does not count the cells that have characters.

Let us say we have the following file and the column labelled "data" has a mix of numbers and characters.



Using the function "AVERAGE" we will get the average of 1,2,3,4 as 2.5,which is (1+2+3+4)/4. Though there were 2 cells having characters, the function did not consider them and gave an average as if it was for 4 cells.



On the other hand, if we wanted to calculate the average as if the two character cells were 0, and take the number of cells to be 6. We can use the function "AVERAGEA



This gives the output of 1.66 which is nothing but 10/6, thus considering all the 6 cells.




copy string in kernel using kstrcpy

Creating copy of existing strings would require allocation of new memory and then assign the old string to new one. The multiple steps required to create a string copy can be done with the help of a single function in the kernel.



Ref: Kernel API

In the example below, we have created a proc entry to show the usage of the function. A call to read the proc entry creates a copy of the existing string in temp allcates it to the string called copy which we send as output of the proc entry.



Save the file as proc_read_copy.c and compile it using the following makefile.



Compile and load the module into kernel using.



To see the output, read the proc entry created by the module.




Example of using getnstimeofday in linux kernel

The linux kernel provides a number of interfaces to manage time. getnstimeofday is one of them, which gives the time in seconds and nanoseconds . The function is implemented in "timekeeping32.h" and returns a structure of the type timespec which has two members.



To print the time, we only need to print the values of tv_sec and tv_nsec which gets filled by the call to the function getnstimeofday.

In the following example code, we have created a proc entry called gettime, which prints out the values of seconds and nanoseconds when read.



Save the above code as proc_read_gettimeofday.c and compile the code using the following makefile.



Compile and insert the module using



To see the output, just read the proc entry gettime, using the cat command.




Using get_options to read a range of integer arguments from a function in linux kernel.

In the post , we saw how to use read integers using the get_option, if we want to read a range of integers we can use get_options.



Ref: Kernel API

To read the numbers that are passed,as it is a range we will use an array into which the numbers can be filled. The array will have to be declared with the appropriate size.

The array will be passed to get_options which will fill the array with the elements that belong the range that was passed as shown in the function below.



We can pass a range of integers seperated by a "-" , which will be used to fill the array with the elements.

The following is the full code that passes range of numbers to the getargs function shown above,which in turn prints out all the numbers in the range.



Save the file as readOptions.c and compile it using the following makefile.



Compile and insert the code using



To view the output, run the command dmesg.


Parsing integer argument to functions in linux kernel

Kernel API provides functions to help making parsing of integer arguments being passed to functions easier. One of the functions is



Ref: Kernel API

To understand what has been passed as the argument we need to look at the return value of the function.

To understand the working a function is implemented as an example which tests for all the 4 possible return values and prints the option received.



In the function above the argument is received in *str, which is passed to the get_option function which, which in turn assigns the values to pint from the str.

To see the function in action, we can call the function in the init function with different arguments as shown in the example below.



In the code, we have called the function "getargs" with no arguments,one argument,argument and a comma and specified a range.

To compile code,save it as readOptions.c use the following makefile



To comple and insert the code.



To see the output run the command dmesg



In the above output we can see that, the first call to getargs did not have any arguments in it, hence we see the output as no arguments. The calls after that print out exactly as they are passed.


Creating a FIFO in linux kernel

FIFO is a first in first out data structure that which can be used to hold any kind of data. Linux kernel provides useful APIs to make creation and use of FIFO data structure easy.

The first step in creation of FIFO is to define the FIFO required with the type of data it will be holding using



Once the FIFO has been defined we can use a number of functions available to add,remove, check the FIFO. To put data into the FIFO



To take the date out of the FIFO



Just to see the above functions in use we will create a proc entry which will output one data from a FIFO that gets created as soon as the module is inserted into the kernel.

To create a module with 6 char entries



An array of values to be added to the FIFO



To add the entries into the FIFO when the module gets inserted into the kernel, the init function needs to call the kfifo_put function



Once the fifo has been created, we can extract one data at a time using the function kfifo_get . To ensure that only one data is read from the FIFO each time we use the cat command on the proc entry extra checks and flags are needed



The function kfifo_is_empty returns true when the fifo is empty else it returns false.

The full code for creation of the proc entry called "fifo" which will output one data value at a time is:



If the file is saved as proc_read_fifo.c, it can be compiled using



To test the code, once the compile and insert the code



Read the proc entry using the cat command

The output shows that every call to read the entry removes one item from the fifo and when all entries are removed "FIFO empty" message gets printed.

Using sched_clock to get kernel uptime

In this post we will see how we can get the information of number of nanoseconds the kernel has been working from and how to print it. We will create a proc entry which when read will print the number of nano seconds from which the kernel has been up for.

The function that is available in kernel to get information about the kernel uptime in nano seconds is sched_clock. sched_clock for x86 is defined as a function in the file "arch/x86/tsc.c", which basically overwrites a default version of the function.

According to the linux documentation : "This function shall return the number of nanoseconds since the system was started. An architecture may or may not provide an implementation of sched_clock() on its own. If a local implementation is not provided, the system jiffy counter will be used as sched_clock()."

To use the function in a module we will need the header file "linux/sched/clock.h"

The function is called with no arguments and returns a "unsigned long long".

In the code below a proc entry is created that will print out the output of sched_clock by converting it to the string.



The details of proc entry and its creation have been discussed in the posts
Creating read only proc entry in linux 5.3

Creating proc read write function in linux kernel 5.3

. The following is the full code for creating the proc entry to display the system up time in nanoseconds



Assuming the above file is saved as "proc_read_time.c". Here is the makefile that can be used to compile the code.



Once the code gets compiled successfully, insert the module using

To test the code , read the proce entry that was created using the cat command

The number shown is the number of nano seconds from which the kernel has been running.