块设备 - 在不使用探测功能的情况下获取结构设备

时间:2018-05-15 17:50:16

标签: c io linux-kernel linux-device-driver block-device

我正在学习linux设备驱动程序编程,我想使用块设备驱动程序来控制硬件设备。

我的硬件设备使用三个引脚与环境进行通信

  • 时钟 - 输出 - >数据时钟
  • 数据 - bidirectionnal - >将数据传输到设备/从设备传输数据的行
  • 电力 - 输出 - >设备的电源

此设备使用专有协议。它存储的数据可以分成几个文件。

我做了什么

我目前开发了一个字符设备,它被导出到用户空间并实现了几个ioctl。然后,我使用用户空间应用程序从/向设备读取/写入,该应用程序将设备的拆分内存抽象为单个内存区域。

实施了以下ioctl:

  • POWER_ON
  • POWER_OFF
  • RESET
  • SEND_COMMAND

这个实现功能齐全,我希望通过将一对{char_driver,userspace_app}转换为可直接读/写的单块设备驱动程序,进一步深入设备驱动程序编程。

我想做什么

对于char驱动程序,我在设备树中填写了相关信息,以将其用作 platform_device 。有关I / O引脚的信息已从中加载,我使用 gpio 稳定器子系统来定义I / O.

我希望通过在插入时将相关引脚提供给驱动程序来实现块驱动程序。然后我将它用作 platform_device ,但我的主要目标是了解底层机制,以便我尝试几种解决方案。

这是我已经完成的事情

#define EMERG(fmt, ...)                printk(KERN_EMERG fmt, ##__VA_ARGS__)
#define ALERT(fmt, ...)                printk(KERN_ALERT fmt, ##__VA_ARGS__)
#define CRIT(fmt, ...)                 printk(KERN_CRIT fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...)                printk(KERN_ERR fmt, ##__VA_ARGS__)
#define WARNING(fmt, ...)              printk(KERN_WARNING fmt, ##__VA_ARGS__)
#define NOTICE(fmt, ...)               printk(KERN_NOTICE fmt, ##__VA_ARGS__)
#define INFO(fmt, ...)                 printk(KERN_INFO fmt, ##__VA_ARGS__)
#define DEBUG(fmt, ...)                printk(KERN_DEBUG fmt, ##__VA_ARGS__)

/* Driver name */
#define DRIVER_NAME     "devtest"

#define GPIO_CLK_NAME       DRIVER_NAME"-clk"
#define GPIO_CLK_PIN        85
#define GPIO_IO_NAME        DRIVER_NAME"-io"
#define GPIO_IO_PIN         98
#define GPIO_RST_NAME       DRIVER_NAME"-rst"
#define GPIO_RST_PIN        73

static unsigned int device_counter = 0;

typedef struct {
    const char *name;
    int major;
    int minor;
    struct device *dev;
    struct regulator *power_reg;
}devtest_dev_t;

static int devtest_io_init(devtest_dev_t* devtest, unsigned int io_pin, unsigned int clk_pin, unsigned int rst_pin)
{
    int ret = 0;

    if(0 > devm_gpio_request(devtest->dev, io_pin, GPIO_IO_NAME))
    {
        ERROR("%s : Unable to allocate IO pin (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_input(io_pin))
    {
        ERROR("%s : Unable to set IO pin direction (%d)\n", DRIVER_NAME, io_pin);
        ret = -EIO;
    }
    else if(0 > devm_gpio_request(devtest->dev, clk_pin, GPIO_CLK_NAME))
    {
        ERROR("%s : Unable to allocate CLK pin (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_output(clk_pin, 0))
    {
        ERROR("%s : Unable to set CLK pin direction (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > devm_gpio_request(devtest->dev, rst_pin, GPIO_RST_NAME))
    {
        ERROR("%s : Unable to allocate RST pin (%d)\n", DRIVER_NAME, rst_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_output(rst_pin, 0))
    {
        ERROR("%s : Unable to set RST pin direction (%d)\n", DRIVER_NAME, rst_pin);
        ret = -EIO;
    }

    return ret;
}

static int __init devtest_init(void)
{
    struct regulator *pwr_reg = NULL;
    nf4tag_dev_t* self = NULL;

    if(NULL == (self = vmalloc(sizeof(devtest_dev_t))))
    {
        ERROR("%s : Unable to allocate memory for device\n", DRIVER_NAME);
        return -1;
    }
    memset(self, 0, sizeof(devtest_dev_t));
    DEBUG("%s : Device allocated and initialized\n", DRIVER_NAME);

    if(NULL == (self->dev = vmalloc(sizeof(struct device))))
    {
        ERROR("%s : Unable to allocate memory for device structure\n", DRIVER_NAME);
        return -2;
    }
    DEBUG("%s : Device struct allocated (%p)\n", DRIVER_NAME, self->dev);

    if(NULL == (pwr_reg = devm_regulator_get(self->dev, "power_regulator")))
    {
        ERROR("%s : Unable to allocate power regulator\n", DRIVER_NAME);
        return -EIO;
    }
    self->power_reg = pwr_reg;
    DEBUG("%s : Power regulator initialized\n", DRIVER_NAME);

    if(0 > devtest_io_init(self, GPIO_IO_PIN, GPIO_CLK_PIN, GPIO_RST_PIN))
    {
        ERROR("%s : Unable to allocate gpios\n", DRIVER_NAME);
        return -EIO;
    }
    DEBUG("%s : gpios allocated\n", DRIVER_NAME);

    device_counter += 1;

    return 0;
}
module_init(devtest_init);

通过这个实现,我能够分配gpios,但是我遇到了调节器子系统的问题,因为我在插入时有一个内核Oops。

# insmod devtest.ko 
devtest: loading out-of-tree module taints kernel.
devtest : Device allocated and initialized
devtest : Device struct allocated (e089d000)
Unable to handle kernel paging request at virtual address e8bd8028
pgd = d4574000
[e8bd8028] *pgd=00000000
Internal error: Oops: 5 [#1] ARM
Modules linked in: nf4(O+)
CPU: 0 PID: 217 Comm: insmod Tainted: G           O    4.9.30 #1
Hardware name: Atmel SAMA5
task: d457b400 task.stack: d44f4000
PC is at __of_find_property+0x10/0x64
LR is at of_phandle_iterator_init+0x38/0x8c
pc : [<c03f4e98>]    lr : [<c03f69b4>]    psr: a00d0093
sp : d44f5cb8  ip : 00000000  fp : 00000001
r10: 00000000  r9 : 00280000  r8 : 00000000
r7 : d44f5d80  r6 : d44f5ccc  r5 : e8bd8010  r4 : d44f5cf4
r3 : 00000000  r2 : d44f5ccc  r1 : d44f5d80  r0 : e8bd8010
Flags: NzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c53c7d  Table: 34574059  DAC: 00000051
Process insmod (pid: 217, stack limit = 0xd44f4208)
Stack: (0xd44f5cb8 to 0xd44f6000)
5ca0:                                                       d44f5cf4 e8bd8010
5cc0: 400d0013 c03f69b4 ffffffff d44f5d0c e089d000 00000000 d44f5dbc c084af48
5ce0: bf000110 c03f6c38 00000000 00000000 bf00010f 00000000 00000000 00000000
5d00: 00000000 00000000 00000000 00000000 00000000 00000000 c05a702c e089d000
5d20: bf000110 c03f6d00 00000000 d44f5d30 00000020 d44f5d80 ffffff00 ffff0a00
5d40: c083b7a0 e089d000 bf000110 d44f5dbc c084af48 bf000110 00280000 00000000
5d60: 00000001 c02c3fcc e089d000 d44f5d7c d44f5dbc c0305648 c05a702c c0305658
5d80: 65776f70 65725f72 616c7567 2d726f74 70707573 0000796c 00000000 600d0013
5da0: 00000000 00000000 e089d000 e089d000 c084af48 c0308e58 bf000348 ffffffed
5dc0: 00000000 00000000 d4518050 e089d000 bf000110 00000000 00000001 2bae759c
5de0: bf000300 c030b080 e089b000 bf002000 d4516240 bf000348 00000000 bf0020a0
5e00: bf000300 c01016e0 d45b3c00 c084e7cc 00000001 a00e0013 d4851000 c05a23c4
5e20: 00000000 d45b3c00 d40bb800 c0812f98 c0812f98 c01a1088 00000012 d4516280
5e40: 00000001 a00e0013 d4516240 e0898000 00000001 d4518a80 bf000300 00000001
5e60: d4516240 bf000348 d4518a80 c016b5bc 00000001 2bae759c d44f5f54 00000001
5e80: d4518a88 c0160720 bf00030c 00007fff bf000300 c015e0e4 bf00030c 000003e8
5ea0: bf000450 e0899610 c05015f0 bf00030c 00000000 00000000 d44f5f48 d44f5f44
5ec0: 00001688 c01ac6f4 00001688 00000000 00000000 00000000 00000000 00000000
5ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
5f00: 00000000 00000000 7fffffff 00000000 00000003 00093008 0000017b c0107664
5f20: d44f4000 00000000 00000000 c0160d40 7fffffff 00000000 00000003 a00e0013
5f40: d45506c0 e0898000 00001688 00000000 00000020 e0898000 00001688 e08992a0
5f60: e089918c e0898c84 00000484 000004c4 00000000 00000000 00000000 000008a0
5f80: 00000016 00000017 00000010 00000000 0000000d 00000000 00093008 bef79f3e
5fa0: 00000002 c01074a0 00093008 bef79f3e 00000003 00093008 00000000 bef79f3e
5fc0: 00093008 bef79f3e 00000002 0000017b bef79f3e 00000000 b6fc5000 00000000
5fe0: bef79ca0 bef79c90 0001f899 b6f43972 800e0030 00000003 00000000 00000000
[<c03f4e98>] (__of_find_property) from [<c03f69b4>] (of_phandle_iterator_init+0x38/0x8c)
[<c03f69b4>] (of_phandle_iterator_init) from [<c03f6c38>] (__of_parse_phandle_with_args+0x24/0xc4)
[<c03f6c38>] (__of_parse_phandle_with_args) from [<c03f6d00>] (of_parse_phandle+0x28/0x4c)
[<c03f6d00>] (of_parse_phandle) from [<c0305658>] (regulator_dev_lookup+0x60/0x190)
[<c0305658>] (regulator_dev_lookup) from [<c0308e58>] (_regulator_get+0x60/0x264)
[<c0308e58>] (_regulator_get) from [<c030b080>] (_devm_regulator_get+0x9c/0xc0)
[<c030b080>] (_devm_regulator_get) from [<bf0020a0>] (nf4tag_init+0xa0/0x260 [nf4])
[<bf0020a0>] (devtest_init [nf4]) from [<c01016e0>] (do_one_initcall+0x40/0x170)
[<c01016e0>] (do_one_initcall) from [<c016b5bc>] (do_init_module+0x60/0x1b0)
[<c016b5bc>] (do_init_module) from [<c0160720>] (load_module+0x1b74/0x1f80)
[<c0160720>] (load_module) from [<c0160d40>] (SyS_finit_module+0xa8/0xb8)
[<c0160d40>] (SyS_finit_module) from [<c01074a0>] (ret_fast_syscall+0x0/0x3c)
Code: e3500000 012fff1e e92d4070 e1a06002 (e5904018) 
---[ end trace 39a2cd9292b80271 ]---

显然有些事我不明白。我认为问题来自于我正在使用的struct device被分配但从未初始化的事实,因此devm_regulator_get函数找不到名为'power_regulator'的监管器。

所以我的问题是:

  • 我的假设是对的吗?
  • 未探测到设备驱动程序时,是否可以使用struct regulator
  • 如果是的话怎么办?
  • 如果没有什么是最佳选择?

0 个答案:

没有答案