Monthly Archives: June 2014

Module Interactions

This seventeenth article, which is part of the series on Linux device drivers, demonstrates various interactions with a Linux module.

<< Sixteenth Article

As Shweta and Pugs are gearing up for their final semester project in Linux drivers, they are closing on some final tidbits of technical romancing. This mainly includes the various communications with a Linux module (dynamically loadable and unload-able driver), namely accessing its variables, calling its functions, and passing parameters to it.

Global variables and functions

One might think as what a big deal in accessing the variables and functions of a module, outside it. Just make them global, declare them extern in a header, include the header, and access. In the general application development paradigm, it is this simple – but in kernel development environment, it is not so. Though, recommendations to make everything static by default, has always been there, there were and are cases where non-static globals may be needed. A simple example could be a driver spanning over multiple files and function(s) from one file needed to be called in the other. Now to avoid any kernel collision even with such cases, every module is embodied in its own name space. And we know that two modules with the same name cannot be loaded at the same time. Thus by default zero collision is achieved. However, this also implies that by default nothing from a module can be made really global throughout the kernel, even if we want to. And exactly for such scenarios, the <linux/module.h> header defines the following macros:

EXPORT_SYMBOL(sym)
EXPORT_SYMBOL_GPL(sym)
EXPORT_SYMBOL_GPL_FUTURE(sym)

Each of these exports the symbol passed as their parameter, with additionally putting them in the default, _gpl and _gpl_future sections, respectively. And hence only one of them has to be used for a particular symbol – though the symbol could be either a variable name or a function name. Here’s the complete code (our_glob_syms.c) to demonstrate the same:

#include <linux/module.h>
#include <linux/device.h>

static struct class *cool_cl;
static struct class *get_cool_cl(void)
{
	return cool_cl;
}
EXPORT_SYMBOL(cool_cl);
EXPORT_SYMBOL_GPL(get_cool_cl);

static int __init glob_sym_init(void)
{
	if (IS_ERR(cool_cl = class_create(THIS_MODULE, "cool")))
	/* Creates /sys/class/cool/ */
	{
		return PTR_ERR(cool_cl);
	}
	return 0;
}

static void __exit glob_sym_exit(void)
{
	/* Removes /sys/class/cool/ */
	class_destroy(cool_cl);
}

module_init(glob_sym_init);
module_exit(glob_sym_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email@sarika-pugs.com>");
MODULE_DESCRIPTION("Global Symbols exporting Driver");

Each exported symbol also have a corresponding structure placed into each of the kernel symbol table (__ksymtab), kernel string table (__kstrtab), and kernel CRC table (__kcrctab) sections, marking it to be globally accessible. Figure 30 shows a filtered snippet of the /proc/kallsyms kernel window, before and after loading the module our_glob_syms.ko, which has been compiled using the driver’s usual makefile.

Figure 30: Our global symbols module

Figure 30: Our global symbols module

The following code shows the supporting header file (our_glob_syms.h), to be included by modules using the exported symbols cool_cl and get_cool_cl:

#ifndef OUR_GLOB_SYMS_H
#define OUR_GLOB_SYMS_H

#ifdef __KERNEL__
#include <linux/device.h>

extern struct class *cool_cl;
extern struct class *get_cool_cl(void);
#endif

#endif

Figure 30 also shows the file Module.symvers, generated by compilation of the module our_glob_syms. This contains the various details of all the exported symbols in its directory. Apart from including the above header file, the modules using the exported symbols, possibly should have this file Module.symvers in their build directory.

Note the <linux/device.h> header in the above examples, is being included for the various class related declarations & definitions, which has been already covered under the character drivers discussions.

Module Parameters

Being aware of passing command line arguments to an application, it is a natural quest to ask if something similar can be done with a module. And the answer is yes. Parameters can be passed to a module along with loading it, say using insmod. Interestingly enough and in contrast with the command line arguments to an application, these can be modified even later as well, through sysfs interactions.

The module parameters are setup using the following macro (defined in <linux/moduleparam.h>, included through <linux/module.h>):

module_param(name, type, perm)

where, name is the parameter name, type is the type of the parameter, and perm is the permissions of the sysfs file corresponding to this parameter. Supported type values are: byte, short, ushort, int, uint, long, ulong, charp (character pointer), bool or invbool (inverted boolean). The following module code (module_param.c) demonstrates a module parameter:

#include <linux/module.h>
#include <linux/kernel.h>

static int cfg_value = 3;
module_param(cfg_value, int, 0764);

static int __init mod_par_init(void)
{
	printk(KERN_INFO "Loaded with %d\n", cfg_value);
	return 0;
}

static void __exit mod_par_exit(void)
{
	printk(KERN_INFO "Unloaded cfg value: %d\n", cfg_value);
}

module_init(mod_par_init);
module_exit(mod_par_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email@sarika-pugs.com>");
MODULE_DESCRIPTION("Module Parameter demonstration Driver");

Note that before the parameter setup, a variable of the same name and compatible type needs to be defined.

Subsequently, the following steps and experiments are shown in Figures 31 and 32:

  • Building the driver (module_param.ko file) using the driver’s usual makefile
  • Loading the driver using insmod (with and without parameters)
  • Various experiments through the corresponding /sys entries
  • And finally, unloading the driver using rmmod
Figure 31: Experiments with module parameter

Figure 31: Experiments with module parameter

Figure 32: Experiments with module parameter (as root)

Figure 32: Experiments with module parameter (as root)

Observe the following:

  • Initial value (3) of cfg_value becomes its default value when insmod is done without any parameters
  • Permission 0764 gives rwx to the user, rw- to the group, and r– for the others on the file cfg_value under parameters of module_param under /sys/module/

Check for yourself:

  • Output of dmesg | tail on every insmod and rmmod for the output of printk‘s
  • Try writing into the /sys/module/module_param/parameters/cfg_value file as a normal user

Summing up

With this, the duo have a fairly good understanding of Linux drivers and they are all set to start working on their final semester project. Any guesses on what their topic is all about? Hint: They have picked up one of the most daunting Linux driver topic. Let us see, how they fair at it.

Eighteenth Article >>

   Send article as PDF   

High School Trigo with Maxima

This seventeenth article of the mathematical journey through open source, takes through a tour of the high school trigonometry using Maxima.

<< Sixteenth Article

Trigonometry first gets introduced to students of standard IX, through triangles. And, then it takes its own journey through the jungle of formulae and tables. And one knows, being good at instant recall of various formulae, makes her good at trigo. The idea here is not to be good at mugging up the formulae but rather applying them to get the various end results. It assumes that you possibly already know the formulae.

Fundamental trigonometric functions

Maxima provides all the familiar fundamental trigonometric functions, including the hyperbolic ones. They can be tabulated as follows:

Mathematical Names

Normal

Hyperbolic

Functions

Inv. Functions

Functions

Inv. Functions

sine (sin)

sin()

asin()

sinh()

asinh()

cosine (cos)

cos()

acos()

cosh()

acosh()

tangent (tan)

tan()

atan()

tanh()

atanh()

cosecant (cosec)

csc()

acsc()

csch()

acsch()

secant (sec)

sec()

asec()

sech()

asech()

cotangent (cot)

cot()

acot()

coth()

acoth()

Note that all of their arguments are values in radians. And here follows a demonstration of a small subset of those:

$ maxima -q
(%i1) cos(0);
(%o1)                                  1
(%i2) cos(%pi/2);
(%o2)                                  0
(%i3) cot(0);
The number 0 isn't in the domain of cot
 -- an error. To debug this try: debugmode(true);
(%i4) tan(%pi/4);
(%o4)                                  1
(%i5) string(asin(1));
(%o5)                                %pi/2
(%i6) csch(0);
The number 0 isn't in the domain of csch
 -- an error. To debug this try: debugmode(true);
(%i7) csch(1);
(%o7)                               csch(1)
(%i8) asinh(0);
(%o8)                                  0
(%i9) string(%i * sin(%pi / 3)^2 + cos(5 * %pi / 6));
(%o9)                         3*%i/4-sqrt(3)/2
(%i10) quit();

Simplifications with special angles like %pi / 10 and its multiples could be enabled by loading the ntrig package. Check out the difference below, before and after loading the package:

$ maxima -q
(%i1) string(sin(%pi/10));
(%o1)                             sin(%pi/10)
(%i2) string(cos(2*%pi/10));
(%o2)                             cos(%pi/5)
(%i3) string(tan(3*%pi/10));
(%o3)                            tan(3*%pi/10)
(%i4) load(ntrig);
(%o4)        /usr/share/maxima/5.24.0/share/trigonometry/ntrig.mac
(%i5) string(sin(%pi/10));
(%o5)                            (sqrt(5)-1)/4
(%i6) string(cos(2*%pi/10));
(%o6)                            (sqrt(5)+1)/4
(%i7) string(tan(3*%pi/10));
(%o7)          sqrt(2)*(sqrt(5)+1)/((sqrt(5)-1)*sqrt(sqrt(5)+5))
(%i8) quit();

A very common trigonometric problem is, given a tangent value find the corresponding angle. Now, a common challenge is for every value, the angle could lie in two quadrants. For a positive tangent, the angle could be in the first or the third quadrant, and for a negative value, the angle could be in the second or the fourth quadrant. So, atan() cannot always calculate the correct quadrant of the angle. Now, how do we know it exactly. Obviously, we need some extra information, say the actual values of the perpendicular (p) and the base (b) of the tangent, rather than just the tangent value. With that, the angle location could be tabulated as follows:

Perpendicular (p)

Base (b)

Tangent (p/b)

Angle Quadrant

Positive

Positive

Positive

First

Positive

Negative

Negative

Second

Negative

Negative

Positive

Third

Negative

Positive

Negative

Fourth

And this functionality is captured in the atan2() function, which takes 2 arguments, the p and the b, and thus does provide the angle in the correct quadrant, as per the table above. Along with this, the infinities of tangent are also taken care. Here’s a demo:

$ maxima -q
(%i1) atan2(0, 1); /* Zero */
(%o1)                                  0
(%i2) atan2(0, -1); /* Zero */
(%o2)                                 %pi
(%i3) string(atan2(1, -1)); /* -1 */
(%o3)                               3*%pi/4
(%i4) string(atan2(-1, -1)); /* 1 */
(%o4)                              -3*%pi/4
(%i5) string(atan2(-1, 0)); /* - Infinity */
(%o5)                               -%pi/2
(%i6) string(atan2(5, 0)); /* + Infinity */
(%o6)                                %pi/2
(%i7) quit();

Trigonometric Identities

Maxima supports many built-in trigonometric identities, and one can add his own as well. First one to look at would be the set dealing with integral multiples and factors of %pi. We’ll declare a few integers and then play around with them.

$ maxima -q
(%i1) declare(m, integer, n, integer);
(%o1)                                done
(%i2) properties(m);
(%o2)                  [database info, kind(m, integer)]
(%i3) sin(m * %pi);
(%o3)                                  0
(%i4) string(cos(n * %pi));
(%o4)                              (-1)^n
(%i5) string(cos(m * %pi / 2)); /* No simplification */
(%o5)                            cos(%pi*m/2)
(%i6) declare(m, even); /* Will lead to simplification */
(%o6)                               done
(%i7) declare(n, odd);
(%o7)                               done
(%i8) cos(m * %pi);
(%o8)                                 1
(%i9) cos(n * %pi);
(%o9)                                - 1
(%i10) string(cos(m * %pi / 2));
(%o10)                             (-1)^(m/2)
(%i11) string(cos(n * %pi / 2));
(%o11)                            cos(%pi*n/2)
(%i12) quit();

Next is the relation between the normal & the hyperbolic trigo functions.

$ maxima -q
(%i1) sin(%i * x);
(%o1)                            %i sinh(x)
(%i2) cos(%i * x);
(%o2)                              cosh(x)
(%i3) tan(%i * x);
(%o3)                            %i tanh(x)
(%i4) quit();

By enabling the option variable halfangles, many half angle identities, come into play. To be specific, sin(x/2) gets further simplified in (0, 2 * %pi) range, cos(x/2) gets further simplified in (-%pi/2, %pi/2) range. Check out the differences, before and after enabling the option variable, along with the range modifications, in the examples below:

$ maxima -q
(%i1) string(2*cos(x/2)^2 - 1); /* No effect */
(%o1)                           2*cos(x/2)^2-1
(%i2) string(cos(x/2)); /* No effect */
(%o2)                              cos(x/2)
(%i3) halfangles:true; /* Enabling half angles */
(%o3)                                true
(%i4) string(2*cos(x/2)^2 - 1); /* Simplified */
(%o4)                               cos(x)
(%i5) string(cos(x/2)); /* Complex expansion for all x */
(%o5)         (-1)^floor((x+%pi)/(2*%pi))*sqrt(cos(x)+1)/sqrt(2)
(%i6) assume(-%pi < x, x < %pi); /* Limiting x values */
(%o6)                        [x > - %pi, x < %pi]
(%i7) string(cos(x/2)); /* Further simplified */
(%o7)                       sqrt(cos(x)+1)/sqrt(2)
(%i8) quit();

Trigonometric Expansions and Simplifications

Trigonometry is full of multiples of angles, sums of angles, products & powers of trigo functions, and the long list of relations between them. Multiples and sums of angles fall into one category. Products and powers of trigo functions in an another category. And its very useful to do conversions from one of these categories to the other one, to crack a range of simple to complex problems, catering to basic hobby science to quantum mechanics. trigexpand() does the conversion from “multiples & sums of angles” to “products & powers of trigo functions”. trigreduce() does exactly the opposite. Here’s goes a small demo:

$ maxima -q
(%i1) trigexpand(sin(2*x));
(%o1)                           2 cos(x) sin(x)
(%i2) trigexpand(sin(x+y)-sin(x-y));
(%o2)                           2 cos(x) sin(y)
(%i3) trigexpand(cos(2*x+y)-cos(2*x-y));
(%o3)                         - 2 sin(2 x) sin(y)
(%i4) trigexpand(%o3);
(%o4)                      - 4 cos(x) sin(x) sin(y)
(%i5) string(trigreduce(%o4));
(%o5)                  -2*(cos(y-2*x)/2-cos(y+2*x)/2)
(%i6) string(trigsimp(%o5));
(%o6)                       cos(y+2*x)-cos(y-2*x)
(%i7) string(trigexpand(cos(2*x)));
(%o7)                         cos(x)^2-sin(x)^2
(%i8) string(trigexpand(cos(2*x) + 2*sin(x)^2));
(%o8)                         sin(x)^2+cos(x)^2
(%i9) trigsimp(trigexpand(cos(2*x) + 2*sin(x)^2));
(%o9)                                 1
(%i10) quit();

In %o5 above, you might have noted that the 2’s could have been cancelled for further simplification. But that is not the job of trigreduce(), and for that we have to apply the trigsimp() function as shown in %i6. In fact, many other trigonometric identities based simplification are achieved using trigsimp(). Check out the %i7 to %o9 sequences for another such example.

Eighteenth Article >>

   Send article as PDF