GordonFreeman
GordonFreeman

Reputation: 68

How to call Linux kernel driver functions from a userspace program?

How can I write a C program (in userspace) to call functions that are part of a kernel driver? If it's not possible to do directly, how else do I do it?

CONTEXT: I am trying to use the PWM pins of my single-board computer (Intel NUC DE3815TYBE) so that I can control fans. A linux driver called pwm_lpss allows control of these pins (driver developed by Intel, source code here). I have verified that this driver is installed by using the lsmod command. Here is the driver information after typing modinfo pwm_lpss:

filename:       /lib/modules/3.19.0-25-generic/kernel/drivers/pwm/pwm-lpss.ko
license:        GPL v2
author:         Mika Westerberg <[email protected]>
description:    PWM driver for Intel LPSS
srcversion:     44AA14AF3E2F96C813770A8
depends:
intree:         Y
vermagic:       3.19.0-25-generic SMP mod_unload modversions
signer:         Magrathea: Glacier signing key
sig_key:        6A:AA:11:D1:8C:2D:3A:40:B1:B4:DB:E5:BF:8A:D6:56:DD:F5:18:38
sig_hashalgo:   sha512

So I know where the driver module is (the pwm-lpss.ko file) and I have the source code which I know has a function in it called pwm_lpss_config() that I'd like to use. How do I call the function from my userspace C program? How would I go about #including it? Or is this not possible to do from userspace?

Unfortunately Intel has provided zero documentation for how to use this driver. I thought drivers normally map their functionality to some user-accessible file. I was able to find some PWM-related files after some digging, but I haven't been able to find a file that looks like it can set PWM duty cycle/frequency.

Upvotes: 2

Views: 7552

Answers (2)

Nominal Animal
Nominal Animal

Reputation: 39316

It's a standard Linux PWM driver, so no special documentation is necessary.

Check the /sys/class/pwm/ directory. (/sys is the interface the kernel provides for access to its data structures. It just looks and acts like a filesystem.) You should have something like /sys/class/pwm/pwmchip0/. Each such directory corresponds to a PWM chip.

The directory will have the following entries. You may need superuser privileges to access these (as you wouldn't want everybody to mess with them):

  • npwm: Read this to find out how many PWM channels this chip has.

  • export: Write a channel number (0 to whatever-the-number-in-npwm-1) to make that channel available via this sysfs interface

  • unexport: Write a channel number to remove the channel from sysfs interface control

Each PWM channel exported to be used via the sysfs interface will show up as a subdirectory named pwmN, where N is the channel number. Here, you can read and write to entries

  • period: Total period (off + on) in nanoseconds.

  • duty_cycle: On time in nanoseconds. Must be less than period.

  • polarity: If the chip supports reversing the signal polarity, you can write inversed here to invert the polarity; normal is the default/normal polarity.

  • enable: 1 if enabled, 0 if disabled.

When reading or writing to these entries, no special locking is necessary. The kernel will receive all data in one write(), and return all data in one read() operation. When a write() succeeds, the kernel has applied the setting.

Upvotes: 6

Severin Pappadeux
Severin Pappadeux

Reputation: 20080

some ioctl ? The ioctl() function manipulates the underlying device parameters of special files.

Along the lines

fd = open("/dev/pwm0", O_RDONLY); // put whatever device you've got
if (ioctl(fd, STATUSGET, &status) == -1) // magic constant should be set
    ....
} else {
    ....
}

Upvotes: 1

Related Questions