Tuesday, July 14, 2009

Wisdoms of the day

  • Wenn du den Kaffee nicht aufschüttest, läuft er nicht durch
  • tar cf file.tar --- "cowardly refusing to create empty archive."
    Has saved a lot of archives when typing tar cf instead of tar xf ...
  • Ever found a good editor for this blog system?
  • Why am I the only person unable to create a debugging environment for the AVR32?

Monday, July 06, 2009

Using module_param_call for Linux kernel module parameters

My first foray into linux kernel programming – writing a module to drive an external buzzer, using the high resolution timer. Not my first action on the linux kernel, though: http://www.lm-sensors.org/changeset/3613/i2c/trunk

Found a nice feature that is not yet well documented.

ushort enabled =0;
module_param(enabled, ushort, 
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); MODULE_PARM_DESC(enabled, " Enabled or not");
  • Defines a module parameter that can be set on insmod
  • giving it rights (S_*** equals 0664 aka rw-rw-r-- in this case) allows to set the value via /sys/module/modulename/parameters/parameter for both reading and writing
  • Unfortunately, the module is not notified when the value is set.

http://lwn.net/Articles/85443/ only says: “It is worth noting, however, that there is no mechanism for notifying a module that one of its parameters has been changed”.

Well, there is a method. module_param_call. Or rather a macro. It’s hard to find anything about it on the web, the only(?) source currently are the linux kernel source files … especially include/linux/moduleparam.h and kernel/params.c.

static int param_set_buzzer_enabled(const char *val, 
  struct kernel_param *kp);
unsigned int buzzerenabled = 0;
module_param_call(buzzer_enabled, param_set_buzzer_enabled, param_get_int,
    &buzzer_enabled, 0664);
MODULE_PARM_DESC(buzzer_enabled, " Buzzer enabled? default: 1 (yY)");

When the value is queried, the pre-defined method param_get_int is called which directly accesses the (&)buzzer_enabled value. When the value is set, the spezial method param_set_buzzer_enabled is called. Of course, it is also possible to do it another way, e.g., to create a read-only parameter which does not have a variable backing.

The role of the param_set_buzzer_enabled method is best passed to one of the predefined methods – in this case, param_set_bool:

static int param_set_buzzer_enabled(const char *val, struct kernel_param *kp)
{
  int hr;

  // 1yY 0nN
  hr = param_set_bool(val, kp);
  if (hr!=0) {
    printk("Unable to set buzzer_enabled to value '%s'\n", val);
    return hr;
  }
  // do the job, here ;-)
  printk("New value: %d\n", buzzer_enabled);
  return 0;
}

val is char*, always – in some cases, special care needs to be taken of trailing newlines produced by "echo 0 > /sys/...". At least some implementations of the conversion routine (using simple_strtol) fail in this case – "echo –n 0" needs to be used, then.

I’d say, far easier to use than defining your own kobject instances, attributes and files, and place them in the appropriate /sys/-folders. By the way – the macro used above, module_param, does nothing else than calling the other one with the correct param_set_##type methods based on the given type (ok, I admin, module_param_named also participates).

Yours,
Sebastian