The call to request_mem_region is failing (returns null).
I would say that the memory region I'm trying to access (GPIO starting at 0x3f20000) is being used.
I removed (rmmod) the module bcm28795_gpio but the request is still failing.
The modules I have loaded are (lsmod):
Module Size Used by
cfg80211 427817 0
rfkill 16018 1 cfg80211
snd_bcm2835 20511 0
snd_pcm 75890 1 snd_bcm2835
snd_timer 19160 1 snd_pcm
snd 51908 3 snd_bcm2835,snd_timer,snd_pcm
bcm2835_wdt 3225 0
uio_pdrv_genirq 3164 0
uio 8000 1 uio_pdrv_genirq
i2c_dev 5859 0
ipv6 347473 30`
cat /proc/iomem is returning the following:
00000000-3affffff : System RAM
00008000-007e7483 : Kernel code
00860000-0098e1ab : Kernel data
3f006000-3f006fff : dwc_otg
3f007000-3f007eff : /soc/dma#7e007000
3f00b840-3f00b84e : /soc/vchiq
3f00b880-3f00b8bf : /soc/mailbox#7e00b800
3f200000-3f2000b3 : /soc/gpio#7e200000
3f201000-3f201fff : /soc/uart#7e201000
3f201000-3f201fff : /soc/uart#7e201000
3f202000-3f2020ff : /soc/sdhost#7e202000
3f980000-3f98ffff : dwc_otg`
I think this issue is related to the Device Tree, but I'm not sure what do next.
The driver code:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/of.h>
#include <linux/of_address.h>
#define DRIVER_NAME "tsgpio"
struct tsgpio_dev {
struct resource res;
void __iomem *virtbase;
} dev;
static const struct file_operations tsgpio_fops = {
.owner = THIS_MODULE,
};
static struct miscdevice tsgpio_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = DRIVER_NAME,
.fops = &tsgpio_fops,
};
static const struct of_device_id tsgpio_of_match[] = {
{ .compatible = "brcm,bcm2835-gpiomem" },
{},
};
MODULE_DEVICE_TABLE(of, tsgpio_of_match);
int __init tsgpio_probe(struct platform_device *pdev)
{
int ret;
ret = misc_register(&tsgpio_misc_device);
if (ret)
return ENODEV;
// Find address range in device tree
ret = of_address_to_resource(pdev->dev.of_node, 0, &dev.res);
if (ret) {
ret = ENOENT;
goto out_deregister;
}
// Request access to memory
if (request_mem_region(dev.res.start, resource_size(&dev.res),
DRIVER_NAME) == NULL) {
ret = EBUSY;
goto out_deregister;
}
/* Arrange access to our registers (calls ioremap) */
dev.virtbase = of_iomap(pdev->dev.of_node, 0);
if (dev.virtbase == NULL) {
ret = ENOMEM;
goto out_release_mem_region;
}
return 0;
out_release_mem_region:
release_mem_region(dev.res.start, resource_size(&dev.res));
out_deregister:
misc_deregister(&tsgpio_misc_device);
return ret;
}
int tsgpio_remove(struct platform_device *pdev)
{
iounmap(dev.virtbase);
release_mem_region(dev.res.start, resource_size(&dev.res));
misc_deregister(&tsgpio_misc_device);
return 0;
}
static struct platform_driver tsgpio_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tsgpio_of_match),
},
.remove = __exit_p(tsgpio_remove),
};
static int __init tsgpio_init(void)
{
return platform_driver_probe(&tsgpio_driver, tsgpio_probe);
}
static void __exit tsgpio_exit(void)
{
platform_driver_unregister(&tsgpio_driver);
}
module_init(tsgpio_init);
module_exit(tsgpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Emanuel Oliveira");
Output from dmesg:
[ 1745.126636] tsgpio: init
[ 1745.130025] tsgpio: probe of 3f200000.gpiomem failed with error 16
Thank you!
Related
This is my first time writing a Linux kernel driver. After looking for examples online, I started to write my driver. The driver is getting initialized but the ->probe() function is not revoked. I have attached below my C code and the relevant device tree node code snippets.
Can you please help and let me know what changes should I make?
DTS file:
ubv#96002000 {
compatible = "ubv";
no-map;
reg = <0 0x96002000 0 0x0002000>;
};
Driver C code:
static int ubv_probe(struct platform_device *pdev)
{
printk (KERN_ALERT "%s\n", __FUNCTION__);
pr_info("---------------%s\n", __func__);
return 0;
}
static int ubv_remove(struct platform_device *pdev)
{
pr_info("------------------- %s\n", __func__);
return 0;
}
static struct of_device_id ubv_match_table[] = {
{ .compatible = "ubv" },
{}
};
static struct platform_device_id ubv_plat_device_ids[] = {
{ .name = "ubv" },
{}
};
static struct platform_driver ubv_platform_driver = {
.probe = ubv_probe,
.remove = ubv_remove,
.id_table = ubv_plat_device_ids,
.driver = {
.name = "ubv",
.owner = THIS_MODULE,
.of_match_table = ubv_match_table,
},
};
static int __init ubv_init(void)
{
int ret;
printk (KERN_ALERT "%s\n", __FUNCTION__);
ret = platform_driver_probe(&ubv_platform_driver, ubv_probe);
printk (KERN_ALERT "ret = %d\n", ret);
pr_info("ret = %d\n", ret);
return ret;
}
static void __exit ubv_exit(void)
{
platform_driver_unregister(&ubv_platform_driver);
}
module_init(ubv_init);
module_exit(ubv_exit);
I would like to use register_wide_hw_breakpoint in my kernel module to observe changes to the page structs of the memory pages I am working with (for debugging purposes).
However, it seems like I can only register breakpoints in the module init function. The function returns -1 (EPERM?) if I use it from the ioctl-handler. This blogpost had me assume it should be possible.
I am running a 5.1.0 kernel on a Intel(R) Xeon(R) Silver 4215.
Example code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/kallsyms.h>
static uint32_t val = 0;
void inc_val(void)
{
val++;
}
struct perf_event * __percpu *sample_hbp;
static void sample_hbp_handler(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs)
{
pr_info("My module: val changed!");
}
int test_hw_breakpoint(void)
{
struct perf_event_attr attr;
hw_breakpoint_init(&attr);
attr.bp_addr = (unsigned long)&val;
attr.bp_len = HW_BREAKPOINT_LEN_4;
attr.bp_type = HW_BREAKPOINT_W;
pr_info("My module: HW breakpoint at 0x%llx\n", attr.bp_addr);
sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL);
if (IS_ERR((void __force *)sample_hbp))
{
int ret = PTR_ERR((void __force *)sample_hbp);
pr_info("My module: Breakpoint registration failed: %d\n", ret);
return ret;
}
inc_val();
pr_info("My module: val: %d", val);
inc_val();
pr_info("My module: val: %d", val);
unregister_wide_hw_breakpoint(sample_hbp);
return 0;
}
static int mod_open(struct inode *inode, struct file *file)
{
(void)inode;
(void)file;
pr_info("My module: Opening...\n");
return 0;
}
static int mod_release(struct inode *inode, struct file *file)
{
(void)inode;
(void)file;
pr_info("My module: Releasing...\n");
return 0;
}
static long mod_ioctl(struct file *file, unsigned num, uintptr_t param)
{
(void)file;
(void)num;
(void)param;
pr_info("My module: Ioctl...\n");
test_hw_breakpoint();
return 0;
}
static struct file_operations fops = {
.open = mod_open,
.release = mod_release,
.unlocked_ioctl = mod_ioctl,
};
static struct miscdevice mod_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mymod!io",
.fops = &fops,
.mode = 0666,
};
int mod_init(void)
{
int ret;
ret = misc_register(&mod_dev);
if (ret != 0)
return ret;
test_hw_breakpoint();
return 0;
}
void mod_exit(void)
{
misc_deregister(&mod_dev);
}
static int __init od_init(void)
{
int ret;
pr_info("My module: Initializing...\n");
ret = mod_init();
if (ret != 0)
return -1;
return 0;
}
static void __exit od_exit(void)
{
pr_info("My module: Terminating...\n");
mod_exit();
}
module_init(od_init)
module_exit(od_exit)
MODULE_LICENSE("GPL");
Produces the following output in dmesg:
[ +0.031269] My module: Initializing...
[ +0.000086] My module: HW breakpoint at 0xffffffffc04ae4c8
[ +0.000191] My module: val changed!
[ +0.000002] My module: val: 1
[ +0.000003] My module: val changed!
[ +0.000001] My module: val: 2
[ +0.002405] My module: Opening...
[ +0.000003] My module: Ioctl...
[ +0.000003] My module: HW breakpoint at 0xffffffffc04ae4c8
[ +0.000019] My module: Breakpoint registration failed: -1
[ +0.000003] My module: Releasing...
I don't know the memory address to observe at module initialization. Is there any way I can add a data breakpoint at runtime?
When a process issues a system call, it switches to kernel mode, but the kernel code is running in "process context". The process could, in theory, do anything while running in kernel mode. However, typical kernel code will check that the calling process has the capability to do what it is trying to do. A process has a list of capabilities of things it is allowed to do: see capabilities(7).
In OP's particular case, the unprivileged process that is issuing the ioctl call that results in the call to register_wide_hw_breakpoint is probably failing when it fails the check in the hw_breakpoint_parse function in "kernel/events/hw_breakpoint.c":
if (arch_check_bp_in_kernelspace(hw)) {
if (attr->exclude_kernel)
return -EINVAL;
/*
* Don't let unprivileged users set a breakpoint in the trap
* path to avoid trap recursion attacks.
*/
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
}
I've this driver:
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <sound/soc-dapm.h>
static const struct snd_soc_dapm_route max9880_dapm_routes[] = {
{"Mono out", NULL, "Mono Mixer"}
};
static struct snd_soc_codec_driver soc_codec_dev_max9880 = {
.component_driver = {
.dapm_routes = max9880_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(max9880_dapm_routes)
}
};
static struct snd_soc_dai_driver max9880_dai = {
.name = "max9880",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 1
}
};
static int max9880_platform_probe(struct platform_device *pdev)
{
int ret;
snd_printk(KERN_ALERT "1. platform probe");
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_max9880,
&max9880_dai, 1);
return ret;
}
static int max9880_platform_remove(struct platform_device *pdev)
{
snd_printk(KERN_ALERT "2. platform remove");
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
static const struct of_device_id max9880_device_id[] = {
{ .compatible = "max9880" },
{}
};
MODULE_DEVICE_TABLE(of, max9880_device_id);
static struct platform_driver max9880_platform_driver = {
.driver = {
.name = "max9880",
.of_match_table = of_match_ptr(max9880_device_id),
},
.probe = &max9880_platform_probe,
.remove = &max9880_platform_remove,
};
module_platform_driver(max9880_platform_driver);
and I use insmod to load the module into the kernel. This all seems to work well, and I'm also able to do a rmmod without any problem. However I don't get any entries in /proc/asound/cards meaning that my module isn't recoqnized as a sound card. What am I missing?
Hellow I'm tring to learn writing kernel modules and device drivers. As a begginig I decided to start by making a driver for my tlc5947 led matrix. From simple kernel module with parameters I moved to char device driver but I'm having hard time with resource reference counting. Whole day I have been playing the restart game with my PI and still can't figure from where the bug is comming ...
This is the module header:
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#ifndef _TLC5947_LED_MATRIX_H
#define _TLC5947_LED_MATRIX_H
#define TLC5947_GPIOS 3
#define TLC5947_LEDS 24
#define TLC5947_MAXPWM 4096
#define GPIO_HIGH 1
#define GPIO_LOW 0
#define TLC5947_NAME "tlc5947"
#define CONST_PARAM S_IRUSR | S_IRGRP | S_IROTH
ushort tlc5947_chips = 255;
ushort tlc5947_data = 255;
ushort tlc5947_clock = 255;
ushort tlc5947_latch = 255;
static struct gpio tlc5947[TLC5947_GPIOS] = {
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 DATA"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 CLOCK"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 LATCH"},
};
static dev_t tlc5947_numbers;
static int tlc5947_major_number;
static int tlc5947_first_minor = 0;
static unsigned int tlc5947_minor_count = 1;
static struct file_operations tlc5947_file_operations;
static struct cdev* tlc5947_cdev;
static int tlc5947_file_opened = 0;
static int tlc5947_file_open(struct inode* inode, struct file* file);
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset);
static int tlc5947_file_close(struct inode* inode, struct file* file);
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name);
static int __init tlc5947_init(void);
static void __exit tlc5947_exit(void);
#endif
The source:
#include "tlc5947_led_matrix.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
module_param(tlc5947_chips, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_chips, "Number of tlc5967 chips that are chain connected.");
module_param(tlc5947_data, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_data, "Number of gpio pin on wich DATA signal is connected (BCM Enum).");
module_param(tlc5947_clock, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_clock, "Number of gpio pin on wich CLOCK signal is connected (BCM Enum).");
module_param(tlc5947_latch, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_latch, "Number of gpio pin on wich LATCH signal is connected (BCM Enum).");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ivo Stratev");
MODULE_DESCRIPTION("Basic Linux Kernel module using GPIOs to drive tlc5947");
MODULE_SUPPORTED_DEVICE(TLC5947_NAME);
static int tlc5947_file_open(struct inode* inode, struct file* file) {
if(tlc5947_file_opened == 1) {
printk(KERN_ERR "Fail to open file /dev/%s\n", TLC5947_NAME);
return -EBUSY;
}
tlc5947_file_opened = 1;
return 0;
}
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset) {
char data[10];
unsigned int i;
unsigned long copy_ret = copy_from_user(data, buffer, buffer_length);
if(copy_ret) {
printk(KERN_ERR "Error while copying data\nCalling copy_from_user reurned%ld\n", copy_ret);
return copy_ret;
}
data[0] -= '0';
i = tlc5947_chips * TLC5947_LEDS - 1;
gpio_set_value(tlc5947_latch, GPIO_LOW);
while(1) {
unsigned char bit = 11;
while(1) {
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_data, (data[0] & (1 << bit)) ? GPIO_HIGH : GPIO_LOW);
gpio_set_value(tlc5947_clock, GPIO_HIGH);
if(bit == 0) {
break;
}
bit--;
}
if(i == 0) {
break;
}
i--;
}
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_latch, GPIO_HIGH);
gpio_set_value(tlc5947_latch, GPIO_LOW);
return copy_ret;
}
static int tlc5947_file_close(struct inode* inode, struct file* file) {
tlc5947_file_opened = 0;
return 0;
}
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name) {
int is_255 = (*tlc5947_param) == 255;
if(is_255) {
printk(KERN_ERR "Parameter %s value not setted when loading the module\n", tlc5947_param_name);
}
return is_255;
}
static int __init tlc5947_init(void) {
int init_ret = 0;
init_ret |= is_tlc5947_param_set(&tlc5947_chips, "tlc5947_chips");
init_ret |= is_tlc5947_param_set(&tlc5947_data, "tlc5947_data");
init_ret |= is_tlc5947_param_set(&tlc5947_clock, "tlc5947_clock");
init_ret |= is_tlc5947_param_set(&tlc5947_latch, "tlc5947_latch");
if(init_ret) {
return -EINVAL;
}
tlc5947[0].gpio = tlc5947_data;
tlc5947[1].gpio = tlc5947_clock;
tlc5947[2].gpio = tlc5947_latch;
init_ret = gpio_request_array(tlc5947, TLC5947_GPIOS);
if(init_ret) {
printk(KERN_ERR "Unable to request GPIOs!\nCalling gpio_request_array returned %d\n", init_ret);
return init_ret;
}
init_ret = alloc_chrdev_region(&tlc5947_numbers, tlc5947_first_minor, tlc5947_minor_count, TLC5947_NAME);
if(init_ret) {
printk(KERN_ERR "Could not allocate device numbers\nCalling alloc_chrdev_region returned %d\n", init_ret);
return init_ret;
}
tlc5947_major_number = MAJOR(tlc5947_numbers);
printk(KERN_INFO "Device major number is %d. Use $ sudo make device\n", tlc5947_major_number);
tlc5947_cdev = cdev_alloc();
tlc5947_cdev->owner = THIS_MODULE;
tlc5947_file_operations.owner = THIS_MODULE;
tlc5947_file_operations.open = tlc5947_file_open;
tlc5947_file_operations.release = tlc5947_file_close;
tlc5947_file_operations.write = tlc5947_file_write;
tlc5947_cdev->ops = &tlc5947_file_operations;
init_ret = cdev_add(tlc5947_cdev, tlc5947_numbers, tlc5947_minor_count);
if(init_ret) {
printk(KERN_ERR "Failed to add device numbers to struct cdev\nCalling cdev_add returned %d\n", init_ret);
return init_ret;
}
return 0;
}
static void __exit tlc5947_exit(void) {
cdev_del(tlc5947_cdev);
unregister_chrdev_region(tlc5947_numbers, tlc5947_minor_count);
gpio_free_array(tlc5947, TLC5947_GPIOS);
}
module_init(tlc5947_init);
module_exit(tlc5947_exit);
And the makefile:
target = tlc5947
driver = tlc5947_led_matrix
obj-m := $(target).o
$(target)-objs := $(driver).o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f /dev/$(target)
activate:
insmod $(target).ko tlc5947_chips=8 tlc5947_data=17 tlc5947_clock=27 tlc5947_latch=22
remove:
rmmod -rf $(target)
modprobe -rf $(target)
device:
mknod /dev/$(target) c 243 0
chmod 777 /dev/$(target)
After performing the command "insmod demo_device" the modules listed in /proc/modules
**demo_device 2528 0 - Live 0xe02da000**
fp_indicators 5072 1 - Live 0xe02d2000 (P)
screader 22672 1 - Live 0xe02c5000 (P)
icamdescrambler 12912 0 - Live 0xe02b2000 (P)
icamemmfilter 16208 0 - Live 0xe02a4000 (P)
icamecmfilter 14992 0 - Live 0xe0294000 (P)
but "(P)" is not avail after that.
After firing the command cat /proc/devices the device "demo_device" is not listed there.
So my question is that: what (P) stands in (cat /proc/modules) and what could be the reason that the device is not listed in (cat /proc/devices).
Thanks in Advance !!
The source code is as:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include "query_ioctl.h"
#define FIRST_MINOR 0
#define MINOR_CNT 1
static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static int status = 1, dignity = 3, ego = 5;
static int my_open(struct inode *i, struct file *f)
{
return 0;
}
static int my_close(struct inode *i, struct file *f)
{
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
{
query_arg_t q;
switch (cmd)
{
case QUERY_GET_VARIABLES:
q.status = status;
q.dignity = dignity;
q.ego = ego;
if (copy_to_user((query_arg_t *)arg, &q, sizeof(query_arg_t)))
{
return -EACCES;
}
break;
case QUERY_CLR_VARIABLES:
status = 0;
dignity = 0;
ego = 0;
break;
case QUERY_SET_VARIABLES:
if (copy_from_user(&q, (query_arg_t *)arg, sizeof(query_arg_t)))
{
return -EACCES;
}
status = q.status;
dignity = q.dignity;
ego = q.ego;
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations query_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = my_ioctl
#else
.unlocked_ioctl = my_ioctl
#endif
};
static int __init query_ioctl_init(void)
{
int ret;
struct device *dev_ret;
printk("Before calling alloc\n");
dev=150;
if ((ret = register_chrdev_region(dev, MINOR_CNT, "demo_device")))
{
return ret;
}
else if((ret = alloc_chrdev_region(&dev,0,MINOR_CNT,"demo_device")))
{
return ret;
}
printk("After alloc %d %d\n",ret,dev);
cdev_init(&c_dev, &query_fops);
if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
{
return ret;
}
printk("After cdev_add\n");
if (IS_ERR(cl = class_create(THIS_MODULE, "char")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(cl);
}
printk("After class_create\n");
if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "demo")))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(dev_ret);
}
printk("After device_create\n");
return 0;
}
static void __exit query_ioctl_exit(void)
{
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
}
module_init(query_ioctl_init);
module_exit(query_ioctl_exit);
MODULE_LICENSE("GPL");
And after inserting the module I am able to see these messages:
$insmod demo_device.ko
Before calling alloc
After alloc 0 217055232
After cdev_add
After class_create
After device_create
$
Make sure that Major Number of the device is not preoccupied by some other device file. use the following command to check the occupied Major Numbers
cat /proc/devices
Use the following code to capture initialization error in init function
int t=register_chrdev(majorNumber,"mydev",&fops);
if(t<0)
printk(KERN_ALERT "device registration failed.");
Use dmesg to look into kernel logs
Look at module_flags_taint() in kernel/module.c.
The 'P' flag merely indicated the other modules are proprietary. The reason your device doesn't show up in /proc/devices is probably because something is wrong with the initialisation, but we can't help you with that unless you show us code.
After perfroming make clean to the linux/application source code and rebuilding it again...make it works. Now after inserting the module the corresponding entry is visibe in the /proc/devcies file :)