"Device has no release() function" - what does this mean? - linux

I am trying to write a simple linux kernel driver to turn a GPIO pin on while the module is loaded. Module loading works, but when I call rmmod to remove it I get this error:
sudo rmmod psctl
[13051.599199] ------------[ cut here ]------------
[13051.608758] WARNING: at drivers/base/core.c:196 device_release+0x78/0x84()
[13051.620581] Device 'psctl.0' does not have a release() function, it is broken and must be fixed.
[13051.637898] Modules linked in: psctl(O-) tmp102 hwmon nfsd rtc_ds1307 i2c_dev snd_bcm2835 snd_pcm snd_page_alloc snd_seq snd_seq_device snd_timer snd spidev leds_gpio led_class spi_bcm2708 i2c_bcm2708 [last unloaded: psctl]
[13051.670268] [<c0013f64>] (unwind_backtrace+0x0/0xf0) from [<c001e80c>] (warn_slowpath_common+0x4c/0x64)
[13051.688743] [<c001e80c>] (warn_slowpath_common+0x4c/0x64) from [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40)
[13051.707217] [<c001e8b8>] (warn_slowpath_fmt+0x30/0x40) from [<c0239240>] (device_release+0x78/0x84)
[13051.725132] [<c0239240>] (device_release+0x78/0x84) from [<c01f4ad8>] (kobject_release+0x50/0x84)
[13051.742880] [<c01f4ad8>] (kobject_release+0x50/0x84) from [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl])
[13051.761326] [<bf0e6064>] (gpiotest_exit+0x10/0x2c [psctl]) from [<c005e140>] (sys_delete_module+0x1b4/0x240)
[13051.780050] [<c005e140>] (sys_delete_module+0x1b4/0x240) from [<c000dae0>] (ret_fast_syscall+0x0/0x30)
[13051.798205] ---[ end trace 2eaa6df2dbf1f2e2 ]---
[13051.810083] psctl: Unloaded module
What does this mean? I have had a look at drivers/base/core.c and it seems that neither the kobject or the kobj_type have a release method associated with them (or there is no kobj_type set on the kobj). Am I supposed to set the release method myself, or is there something else that I haven't done that would set this for me?
The code for the module is below:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#define AUTHOR "Xian Stannard <xian#xianic.net>"
#define DESCRIPTION "Simple GPIO driver as proof of concept"
#define VERSION "0.1"
#define DRIVER_NAME "psctl"
#define OUT_GPIO 18
#define MPRINT(level, fmt, args...) printk(level DRIVER_NAME ": " fmt "\n", ## args)
struct ps_data_struct {
int out_gpio;
};
static int ps_probe(struct platform_device *pdev) {
struct ps_data_struct *data = pdev->dev.platform_data;
if(data == NULL)
MPRINT(KERN_DEBUG, "No platform data");
else {
MPRINT(KERN_DEBUG, "Has platform data: gpio %d", data->out_gpio);
}
return -ENODEV;
}
static int __exit ps_remove(struct platform_device *dev) {
MPRINT(KERN_DEBUG, "Remove");
return 0;
}
static void ps_release(struct device* dev) {
MPRINT(KERN_DEBUG, "Release");
}
static struct ps_data_struct ps_data = {
.out_gpio = OUT_GPIO
};
static struct platform_driver ps_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE
},
.probe = ps_probe,
.remove = __exit_p(ps_remove)
};
static struct platform_device ps_device = {
.name = DRIVER_NAME,
.id = 0,
.dev = {
.platform_data = &ps_data
}
};
static int __init gpiotest_init(void) {
int retval = 0;
retval = platform_driver_register(&ps_driver);
if(retval != 0) {
MPRINT(KERN_ERR, "Could not register driver");
goto drvreg;
}
retval = platform_device_register(&ps_device);
if(retval != 0) {
MPRINT(KERN_ERR, "Could not create device");
goto devreg;
}
MPRINT(KERN_INFO, "Loaded module");
return 0;
devreg:
platform_driver_unregister(&ps_driver);
drvreg:
MPRINT(KERN_ERR, "Module load failed with error code %d", retval);
return retval;
}
static void __exit gpiotest_exit(void) {
platform_device_unregister(&ps_device);
platform_driver_unregister(&ps_driver);
MPRINT(KERN_INFO, "Unloaded module");
}
module_init(gpiotest_init);
module_exit(gpiotest_exit);
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

I think using platform_device_register() to register a device, the pdev->dev->release is not initialized, so when you try to remove this device, the OOPS message print out.
There are two solutions to solve this problem:
Using platform_device_alloc() and platform_device_add() to register your device;
You init the ps_device.dev.release yourself, if you insist on using platform_device_register().

When you call platform_device_alloc() to get an instance of device, the release method initialization is done to the default function, as can be see here.
struct platform_device *platform_device_alloc(const char *name, int id)
{
...
...
pa->pdev.dev.release = platform_device_release;
...
...
}
This is the default implementation of platform_device_release .
However, when you avoid platform_device_alloc, you obviously miss this initialization and hence need to provide your own implementation of release method for device.

Related

Linux serdev mfd driver is not probed

I'm trying to write a MFD driver with accompanying GPIO driver using the new Serial Device Bus in Linux (using kernel 4.11rc6).
I am running under qemu for arm devices and I have modified arch/arm/boot/dts/versatile-ab.dts so that uart2 reads:
uart2: uart#101f3000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x101f3000 0x1000>;
interrupts = <14>;
clocks = <&xtal24mhz>, <&pclk>;
clock-names = "uartclk", "apb_pclk";
fcd16999 {
compatible = "ev,fcd16999";
fcd16999gpio: fcd16999-gpio {
compatible = "ev,fcd16999-gpio";
};
};
};
/proc/device-tree/amba/uart#101f3000/fcd16999/compatible reads ev,fcd16999 and the child node fcd16999-gpio/compatible is ev,fcd16999-gpio.
Still the init function of both devices gets called but not their probe functions. Am I missing something obvious here? The compatible flags matches and the device tree is loaded so it should just work, right?
Files below.
drivers/mfd/fcd16999.c
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/serdev.h>
#include <linux/slab.h>
/*#include <linux/mfd/tps6507x.h>*/
static const struct mfd_cell fcd16999_devs[] = {
{
.name = "fcd16999-gpio",
.of_compatible = "ev,fcd16999-gpio",
},
/*
{
.name = "fcd16999-adc",
},
{
.name = "fcd16999-thermometer",
},
*/
};
static int fcd16999_serdev_probe(struct serdev_device *serdev)
{
dev_warn(&serdev->dev, "fcd16999_serdev_probe\n");
return devm_mfd_add_devices(&serdev->dev, 1, fcd16999_devs,
ARRAY_SIZE(fcd16999_devs), NULL, 0, NULL);
}
void fcd16999_serdev_remove(struct serdev_device *serdev)
{
dev_warn(&serdev->dev, "fcd16999_serdev_remove\n");
}
static const struct of_device_id fcd16999_of_match[] = {
{.compatible = "ev,fcd16999", },
{},
};
MODULE_DEVICE_TABLE(of, fcd16999_of_match);
static struct serdev_device_driver fcd16999_driver = {
.driver = {
.name = "fcd16999",
.of_match_table = of_match_ptr(fcd16999_of_match),
},
.probe = fcd16999_serdev_probe,
.remove = fcd16999_serdev_remove,
};
static int __init fcd16999_serdev_init(void)
{
int ret = 101;
printk("Hello from fcd16999!\n");
ret = serdev_device_driver_register(&fcd16999_driver);
printk("serdev_device_driver_register returned %d\n", ret);
return ret;
}
/* init early so consumer devices can complete system boot */
subsys_initcall(fcd16999_serdev_init);
static void __exit fcd16999_serdev_exit(void)
{
printk("Goodbye from fcd16999!\n");
serdev_device_driver_unregister(&fcd16999_driver);
}
module_exit(fcd16999_serdev_exit);
drivers/gpio/gpio-fcd16999.c
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
/* #include <linux/mfd/stmpe.h> */
static int fcd16999_gpio_probe(struct platform_device *pdev)
{
printk("Hellow, fcd16999\n");
dev_warn(&pdev->dev, "fcd16999_gpio probing...\n");
return 0;
}
static struct platform_driver fcd16999_gpio_driver = {
.driver = {
.suppress_bind_attrs = true,
.name = "fcd16999-gpio",
},
.probe = fcd16999_gpio_probe,
};
static int __init fcd16999_gpio_init(void)
{
printk("Init Hellow, gpio-fcd16999\n");
return platform_driver_register(&fcd16999_gpio_driver);
}
subsys_initcall(fcd16999_gpio_init);
static void __exit fcd16999_gpio_exit(void)
{
printk("Goodbye from gpio-fcd16999!\n");
platform_driver_unregister(&fcd16999_gpio_driver);
}
module_exit(fcd16999_gpio_exit);
It turns out that I needed to enable the SERIAL_DEV_CTRL_TTYPORT option in the kernel to get it to probe.

Attaching device with device driver

I am trying to learn about Linux platform drivers. I have taken a driver from the following tutorial:
http://linuxseekernel.blogspot.com/2014/05/platform-device-driver-practical.html
It is a basic platform driver. I have compiled it and loaded the module. It loads fine, however, its probe function is never executed. There is a lot of documentation that has said as long as the devices id and drivers id match, then the probe function is called. Well I have the following driver:
#include <linux/module.h>
#include <linux/kernel.h>
//for platform drivers....
#include <linux/platform_device.h>
#define DRIVER_NAME "twl12xx"
MODULE_LICENSE("GPL");
/**************/
static int sample_drv_probe(struct platform_device *pdev){
printk(KERN_ALERT "twl12xx: Probed\n");
return 0;
}
static int sample_drv_remove(struct platform_device *pdev){
printk(KERN_ALERT "twl12xx: Removing twl12xx\n");
return 0;
}
static const struct platform_device_id twl12xx_id_table[] = {
{ "twl12xx", 0},
{}
};
MODULE_DEVICE_TABLE(platform, twl12xx_id_table);
static struct platform_driver sample_pldriver = {
.probe = sample_drv_probe,
.remove = sample_drv_remove,
.driver = {
.name = DRIVER_NAME,
},
};
/**************/
int ourinitmodule(void)
{
printk(KERN_ALERT "\n Welcome to twl12xx driver.... \n");
/* Registering with Kernel */
platform_driver_register(&sample_pldriver);
return 0;
}
void ourcleanupmodule(void)
{
printk(KERN_ALERT "\n Thanks....Exiting twl12xx driver... \n");
/* Unregistering from Kernel */
platform_driver_unregister(&sample_pldriver);
return;
}
module_init(ourinitmodule);
module_exit(ourcleanupmodule);
I also have the following entry in my device tree:
twl12xx: twl12xx#2 {
compatible = "twl12xx";
};
I feel like I am must be missing something or incorrectly defining my device tree.
Whatever you have read is correct; driver and device ID both should match.
You have just create the skeleton of driver and you are using the device tree. So it looks fine. But you are missing the of_match_table entry in your code; which is very important for device ID match (same string as you have pass from the device tree) and driver probe calling.
So add the below changes your code:
#ifdef CONFIG_OF
static const struct of_device_id twl12xx_dt_ids[] = {
.compatible = "ti,twl12xx",
{}
};
MODULE_DEVICE_TABLE(of, twl12xx_dt_ids);
#endif
static struct platform_driver sample_pldriver = {
.probe = sample_drv_probe,
.remove = sample_drv_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(twl12xx_dt_ids),
},
.id_table = twl12xx_id_table,
};
I had similar problem. Probe function also wasn't able to print anything. The reason in my case was: In my linux I had ready driver that was binded to the device . When I unbinded this driver, Probe function worked successfully.
(Note, to unbind:
cd /sys/bus/platform/drivers/<driver_name>
echo "device_name" > unbind
)

Problem with hotplugging device driver module

I'm writing a module that when you plug in a usb mouse prints "hello world". The problem comes when I plug in the mouse, dmesg prints six times the below message:
[ 7367.238560] helwor_mod: disagrees about version of symbol
module_layout
This is my code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Isaac Lleida <isakyllr#opmbx.org>");
MODULE_VERSION("0.1");
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ }
};
MODULE_DEVICE_TABLE(usb, usb_mouse_id_table);
static int mouse_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
pr_info("Hello World!");
return 0;
}
static void mouse_disconnect(struct usb_interface *iface)
{
pr_info("Bye World!");
}
static struct usb_driver mouse_driver = {
.name = "usbmouse",
.probe = mouse_probe,
.disconnect = mouse_disconnect,
.id_table = usb_mouse_id_table,
};
module_usb_driver(mouse_driver);
static int __init hello_init(void)
{
int res = 0;
res = usb_register(&mouse_driver);
if(res)
pr_err("usb_register failed with error %d", res);
return res;
}
static void __exit hello_exit(void)
{
pr_debug("USB Mouse Removed...");
usb_deregister(&mouse_driver);
}
I have been googling all the afternoon and still don't know how to solve it.
I hope someone can help me, thanks.
This is related:
module_layout version incompatibility
I'd bet that the kernel sources (headers) you're using to compile your module are from a different kernel version than then one you're running.
Problem solved. This issue is produced because the device is being controled by another driver and it's loaded in the system. Just unload it and load your driver module.
And sorry Gilles for the offtopic.

Using the Linux sysfs_notify call

I am trying to communicate asynchronously between a kernel driver and a user-space program (I know there are lots of questions here that ask for similar information, but I could find none that deal with sysfs_notify).
I am leaving Vilhelm's edit here, but adding the source to both a simple driver utilizing sysfs and a user-space program to poll it. The driver works fine (I got most of it from the net; it is missing the credits, but I couldn't find them when I went back to add them).
Unfortunately, the polling program does not work. It always returns success immediately. Interestingly, if I don't perform the two reads prior to the poll, the revents members are set to POLLERR | POLLIN instead of just POLLIN as seen in the program output.
Program output:
root#ubuntu:/home/wmulcahy/demo# ./readhello
triggered
Attribute file value: 74 (t) [0]
revents[0]: 00000001
revents[1]: 00000001
Here is the driver: hello.c (you can see where I started out...)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
struct my_attr {
struct attribute attr;
int value;
};
static struct my_attr notify = {
.attr.name="notify",
.attr.mode = 0644,
.value = 0,
};
static struct my_attr trigger = {
.attr.name="trigger",
.attr.mode = 0644,
.value = 0,
};
static struct attribute * myattr[] = {
&notify.attr,
&trigger.attr,
NULL
};
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
printk( "hello: show called (%s)\n", a->attr.name );
return scnprintf(buf, PAGE_SIZE, "%s: %d\n", a->attr.name, a->value);
}
static struct kobject *mykobj;
static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len)
{
struct my_attr *a = container_of(attr, struct my_attr, attr);
sscanf(buf, "%d", &a->value);
notify.value = a->value;
printk("sysfs_notify store %s = %d\n", a->attr.name, a->value);
sysfs_notify(mykobj, NULL, "notify");
return sizeof(int);
}
static struct sysfs_ops myops = {
.show = show,
.store = store,
};
static struct kobj_type mytype = {
.sysfs_ops = &myops,
.default_attrs = myattr,
};
static struct kobject *mykobj;
static int __init hello_module_init(void)
{
int err = -1;
printk("Hello: init\n");
mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
if (mykobj) {
kobject_init(mykobj, &mytype);
if (kobject_add(mykobj, NULL, "%s", "hello")) {
err = -1;
printk("Hello: kobject_add() failed\n");
kobject_put(mykobj);
mykobj = NULL;
}
err = 0;
}
return err;
}
static void __exit hello_module_exit(void)
{
if (mykobj) {
kobject_put(mykobj);
kfree(mykobj);
}
printk("Hello: exit\n");
}
module_init(hello_module_init);
module_exit(hello_module_exit);
MODULE_LICENSE("GPL");
And here is the poll program: readhello.c
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <poll.h>
#define TEST_SYSFS_TRIGGER "/sys/hello/trigger"
#define TEST_SYSFS_NOTIFY "/sys/hello/notify"
int main(int argc, char **argv)
{
int cnt, notifyFd, triggerFd, rv;
char attrData[100];
struct pollfd ufds[2];
// Open a connection to the attribute file.
if ((notifyFd = open(TEST_SYSFS_NOTIFY, O_RDWR)) < 0)
{
perror("Unable to open notify");
exit(1);
}
// Open a connection to the attribute file.
if ((triggerFd = open(TEST_SYSFS_TRIGGER, O_RDWR)) < 0)
{
perror("Unable to open trigger");
exit(1);
}
ufds[0].fd = notifyFd;
ufds[0].events = POLLIN;
ufds[1].fd = triggerFd;
ufds[1].events = POLLIN;
// Someone suggested dummy reads before the poll() call
cnt = read( notifyFd, attrData, 100 );
cnt = read( triggerFd, attrData, 100 );
ufds[0].revents = 0;
ufds[1].revents = 0;
if (( rv = poll( ufds, 2, 10000)) < 0 )
{
perror("poll error");
}
else if (rv == 0)
{
printf("Timeout occurred!\n");
}
else if (ufds[0].revents & POLLIN)
{
printf("triggered\n");
cnt = read( notifyFd, attrData, 1 );
printf( "Attribute file value: %02X (%c) [%d]\n", attrData[0], attrData[0], cnt );
}
printf( "revents[0]: %08X\n", ufds[0].revents );
printf( "revents[1]: %08X\n", ufds[1].revents );
close( triggerFd );
close( notifyFd );
}
Some upcoming sysfs enhancements.
Internally, the patch adds a wait queue head to every kobject on the
system; that queue is inserted into a poll table in response to a
poll() call. The sysfs code has no way of knowing, however, when the
value of any given sysfs attribute has changed, so the subsystem
implementing a pollable attribute must make explicit calls to:
void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
Thanks,
Lee
The blocking poll is from the user side. User code can simply tell the kernel which attributes it's interested in, then block in a poll() until one of them has changed.
The sysfs_notify() is a kernel-side call that releases the user-space poll(). After you adjust your kernel attribute value, just call sysfs_notify() to allow any user-space applications to respond to their outstanding poll().
Think of the poll() as "subscribing" to notices of a change in an attribute of interest, and sysfs_notify() as "publishing" the change to any subscribers.

why am I getting an "implicit declaration of function 'ndo_get_stats' " error?

I'm building a VERY SIMPLE kernel module for gathering some stats from the network card here's the code, I keep getting an error implicit declaration of function 'ndo_get_stats'. I'm not sure why...
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/netdevice.h> /* Needed for netdevice*/
static int __init hello_start(void)
{
struct net_device *dev;
printk(KERN_INFO "Loading Stats module...\n");
printk(KERN_ALERT "Hello world\n");
dev = first_net_device(&init_net);
while (dev)
{
printk(KERN_INFO "found [%s] and it's [%d]\n", dev->name, dev->flags & IFF_UP);
printk(KERN_INFO "End of dev struct ... now starts the get_stats struct\n");
dev->stats = ndo_get_stats(dev);
printk(KERN_INFO "recive errors: [%li]\n transmission errors: [%li]\n number of collisions: [%li]", dev->stats.rx_errors , dev->stats.tx_errors, dev->stats.collisions);
dev = next_net_device(dev);
}
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_ALERT "Goodbye.\n");
}
module_init(hello_start);
module_exit(hello_end);
Thanks
ndo_get_stats is a net_device_ops function pointer. You have to call it through the netdev_ops field of your net_device.
Something like this would work:
stats = dev->netdev_ops->ndo_get_stats(dev);

Resources