总线设备驱动模型例子

总线设备驱动模型例子


嵌入式平台采用RK的,交叉编译工具链采用官方提供的交叉编译工具链。

1.向内核注册平台驱动
platform-dummy-char.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>      /* For platform devices */
#include <linux/cdev.h>
#include <linux/fs.h>

static unsigned int major; /* major number for device */
static struct class *dummy_class;
static struct cdev dummy_cdev;

int dummy_open(struct inode * inode, struct file * filp)
{
    pr_info("Someone tried to open me\n");
    return 0;
}

int dummy_release(struct inode * inode, struct file * filp)
{
    pr_info("Someone closed me\n");
    return 0;
}

ssize_t dummy_read (struct file *filp, char __user * buf, size_t count,
                                loff_t * offset)
{
    pr_info("Nothing to read guy\n");
    return 0;
}

ssize_t dummy_write(struct file * filp, const char __user * buf, size_t count,
                                loff_t * offset)
{
    pr_info("Can't accept any data guy\n");
    return count;
}

struct file_operations dummy_fops = {
    open:       dummy_open,
    release:    dummy_release,
    read:       dummy_read,
    write:      dummy_write,
};

static int my_pdrv_probe (struct platform_device *pdev)
{
        struct device *dummy_device;
    int error;
    dev_t devt = 0;

    /* Get a range of minor numbers (starting with 0) to work with */
    error = alloc_chrdev_region(&devt, 0, 1, "dummy_char");
    if (error < 0) {
        pr_err("Can't get major number\n");
        return error;
    }
    major = MAJOR(devt);
    pr_info("dummy_char major number = %d\n",major);

    /* Create device class, visible in /sys/class */
    dummy_class = class_create(THIS_MODULE, "dummy_char_class");
    if (IS_ERR(dummy_class)) {
        pr_err("Error creating sdma test module class.\n");
        unregister_chrdev_region(MKDEV(major, 0), 1);
        return PTR_ERR(dummy_class);
    }

    /* Initialize the char device and tie a file_operations to it */
    cdev_init(&dummy_cdev, &dummy_fops);
    dummy_cdev.owner = THIS_MODULE;
    /* Now make the device live for the users to access */
    cdev_add(&dummy_cdev, devt, 1);

    dummy_device = device_create(dummy_class,
                                &pdev->dev,   /* no parent device */
                                devt,    /* associated dev_t */
                                NULL,   /* no additional data */
                                "dummy_char");  /* device name */

    if (IS_ERR(dummy_device)) {
        pr_err("Error creating sdma test class device.\n");
        class_destroy(dummy_class);
        unregister_chrdev_region(devt, 1);
        return -1;
    }

    pr_info("dummy char module loaded\n");
    return 0;
}

static int my_pdrv_remove(struct platform_device *pdev)
{
    unregister_chrdev_region(MKDEV(major, 0), 1);
    device_destroy(dummy_class, MKDEV(major, 0));
    cdev_del(&dummy_cdev);
    class_destroy(dummy_class);

    pr_info("dummy char module Unloaded\n");
    return 0;
}

static struct platform_driver mypdrv = {
    .probe      = my_pdrv_probe,
    .remove     = my_pdrv_remove,
    .driver     = {
        .name     = "platform-dummy-char",
        .owner    = THIS_MODULE,
    },
};
module_platform_driver(mypdrv);
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_LICENSE("GPL");

2.注册平台设备
platform-dummy-ins.c

#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/types.h>

static struct platform_device *pdev;

static int __init platform_dummy_char_add(void)
{
    int inst_id = 0; /* instance unique ID: base address would be a good choice */
    pdev = platform_device_alloc("platform-dummy-char", inst_id);
    platform_device_add(pdev);
    pr_info("platform-dummy-char device added\n");
    return 0;
}

static void __exit fplatform_dummy_char_put(void)
{
    pr_info("platform-dummy-char device removed\n");
	platform_device_put(pdev);
}

module_init(platform_dummy_char_add);
module_exit(fplatform_dummy_char_put);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");

3.Makefile

KERN_DIR = /opt/RV1126/kernel

all:
	make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) modules 
clean:
	make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) clean
	rm -rf modules.order ./*.ko ./*.o

obj-m	+= platform-dummy-char.o platform-dummy-ins.o

4.挂载和测试

Bug

调试发现插入platform_dummy-ins.ko驱动时在第二次插入的时候会出现崩溃的问题

[  597.200800] sysfs: cannot create duplicate filename '/devices/platform/platform-dummy-char'
[  597.200852] CPU: 0 PID: 1170 Comm: insmod Tainted: G           O      4.19.111 #1
[  597.200864] Hardware name: Generic DT ba[root@RK:~]# sed system
[  597.200901] [<b010f408>] (unwind_backtrace) from [<b010b96c>] (show_stack+0x10/0x14)
[  597.200924] [<b010b96c>] (show_stack) from [<b0892824>] (dump_stack+0x90/0xa4)
[  597.200959] [<b0892824>] (dump_stack) from [<b0279860>] (sysfs_warn_dup+0x58/0x64)
[  597.200986] [<b0279860>] (sysfs_warn_dup) from [<b0279970>] (sysfs_create_dir_ns+0xbc/0xd0)
[  597.201013] [<b0279970>] (sysfs_create_dir_ns) from [<b089769c>] (kobject_add_internal+0x9c/0x2cc)
[  597.201042] [<b089769c>] (kobject_add_internal) from [<b0897928>] (kobject_add+0x5c/0xc0)
[  597.201069] [<b0897928>] (kobject_add) from [<b04add44>] (device_add+0xf4/0x784)
[  597.201097] [<b04add44>] (device_add) from [<b04b3774>] (platform_device_add+0x110/0x224)
[  597.201131] [<b04b3774>] (platform_device_add) from [<af093024>] (platform_dummy_char_add+0x24/0x1000 [platform_dummy_ins])
[  597.201165] [<af093024>] (platform_dummy_char_add [platform_dummy_ins]) from [<b010265c>] (do_one_initcall+0x54/0x194)
[  597.201193] [<b010265c>] (do_one_initcall) from [<b01a0670>] (do_init_module+0x60/0x1f0)
[  597.201219] [<b01a0670>] (do_init_module) from [<b019f588>] (load_module+0x1e90/0x22f8)
[  597.201243] [<b019f588>] (load_module) from [<b019fc20>] (sys_finit_module+0xc8/0xd8)
[  597.201267] [<b019fc20>] (sys_finit_module) from [<b0101000>] (ret_fast_syscall+0x0/0x4c)
[  597.201284] Exception stack(0xde3adfa8 to 0xde3adff0)
[  597.201306] dfa0:                   000d1150 ffffffff 00000003 000d1150 00000000 aee1dea3
[  597.201329] dfc0: 000d1150 ffffffff aee1dea3 0000017b 000d06bc 00000000 a6f22000 00000000
[  597.201348] dfe0: aee1dbf8 aee1dbe8 00025a14 a6e920f2
[  597.201367] kobject_add_internal failed for platform-dummy-char with -EEXIST, don't try to register things with the same name in the same directory.
[  597.201384] platform-dummy-char device added

这个问题查阅了一些资料,是平台的id值已经存在了,再次插入导致异常,platform_device_alloc申请的id修改过-1和1都不行,后面修改为10则问题解决了。

root# insmod platform-dummy-ins.ko
platform-dummy-char device added
root# insmod platform-dummy-char.ko
dummy_char major number = 240
dummy char module loaded

root# echo 'test' > /dev/dummy_char
Someone tried to open me
Can't accept any data guy
Someone closed me

root# cat /dev/dummy_char
Someone tried to open me
Nothing to read guy
Someone closed me

root# rmmod platform-dummy-char.ko
dummy char module Unloaded
root# rmmod platform-dummy-ins.ko
platform-dummy-char device removed
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值