我所理解的linux kernel的移植

11 篇文章 0 订阅

从林纳斯.托瓦兹(Linus B. Torvalds)执掌的网站www.kernel.org下载linux内核,比如:linux-4.9.30.tar.gz,解压:tar zxf linux-4.9.30.tar.gz,进入目录:cd linux-4.9.30,配置:make ARCH=arm64 menuconfig,编译:make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image,结果完全无警告、无错误地编译通过了,说明它是一个完整的源代码,但却无法拷贝至手机、机顶盒或开发板中使用,因为还未为其移植”驱动程序”。
 kernel是一套完整的源码,就象一张”会计报表”一样,为”驱动程序”留有很多空格,用于填写数据(函数指针)。比如,gpio驱动,内核定义一个struct gpio_chip,如下:

struct gpio_chip {
    const char      *label;
    struct gpio_device  *gpiodev;
    struct device       *parent;
    struct module       *owner;

    int         (*request)(struct gpio_chip *chip,
                        unsigned offset);
    void            (*free)(struct gpio_chip *chip,
                        unsigned offset);
    int         (*get_direction)(struct gpio_chip *chip,
                        unsigned offset);
    int         (*direction_input)(struct gpio_chip *chip,
                        unsigned offset);
    int         (*direction_output)(struct gpio_chip *chip,
                        unsigned offset, int value);
    int         (*get)(struct gpio_chip *chip,
                        unsigned offset);
    void            (*set)(struct gpio_chip *chip,
                        unsigned offset, int value);
    void            (*set_multiple)(struct gpio_chip *chip,
                        unsigned long *mask,
                        unsigned long *bits);
    int         (*set_debounce)(struct gpio_chip *chip,
                        unsigned offset,
                        unsigned debounce);
    int         (*set_single_ended)(struct gpio_chip *chip,
                        unsigned offset,
                        enum single_ended_mode mode);
#ifdef CONFIG_AMLOGIC_PINCTRL
    int         (*set_pull)(struct gpio_chip *chip,
                        unsigned int offset, int value);
#endif

    int         (*to_irq)(struct gpio_chip *chip,
                        unsigned offset);

    void            (*dbg_show)(struct seq_file *s,
                        struct gpio_chip *chip);
    int         base;
    u16         ngpio;
    const char      *const *names;
    bool            can_sleep;
    bool            irq_not_threaded;

#if IS_ENABLED(CONFIG_GPIO_GENERIC)
    unsigned long (*read_reg)(void __iomem *reg);
    void (*write_reg)(void __iomem *reg, unsigned long data);
    unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
    void __iomem *reg_dat;
    void __iomem *reg_set;
    void __iomem *reg_clr;
    void __iomem *reg_dir;
    int bgpio_bits;
    spinlock_t bgpio_lock;
    unsigned long bgpio_data;
    unsigned long bgpio_dir;
#endif

#ifdef CONFIG_GPIOLIB_IRQCHIP
    /*
     * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
     * to handle IRQs for most practical cases.
     */
    struct irq_chip     *irqchip;
    struct irq_domain   *irqdomain;
    unsigned int        irq_base;
    irq_flow_handler_t  irq_handler;
    unsigned int        irq_default_type;
    int         irq_parent;
    bool            irq_need_valid_mask;
    unsigned long       *irq_valid_mask;
    struct lock_class_key   *lock_key;
#endif

#if defined(CONFIG_OF_GPIO)
    /*
     * If CONFIG_OF is enabled, then all GPIO controllers described in the
     * device tree automatically may have an OF translation
     */
    struct device_node *of_node;
    int of_gpio_n_cells;
    int (*of_xlate)(struct gpio_chip *gc,
            const struct of_phandle_args *gpiospec, u32 *flags);
#endif
};

结构中的(*request)、(*free)、(*get_direction)、(*direction_input)等在移植前都是”空指针”,能被编译但却无法使用,需要我们根据具体的SOC芯片的数据编写一个个具体的、能工作的函数,并将函数的指针”填充”到gpio_chip结构中去,再调用gpiochip_add()函数一下,内核和应用程序就可以调用我们编写的驱动程序了。

domain->chip.label = domain->data->name;
/* domain->chip.dev = pc->dev; */
domain->chip.parent = pc->dev;
domain->chip.request = meson_gpio_request;
domain->chip.free = meson_gpio_free;
domain->chip.direction_input = meson_gpio_direction_input;
domain->chip.direction_output = meson_gpio_direction_output;
domain->chip.get = meson_gpio_get;
domain->chip.set = meson_gpio_set;
domain->chip.set_pull = meson_gpio_pull_set;
domain->chip.base = domain->data->pin_base;
domain->chip.ngpio = domain->data->num_pins;
domain->chip.can_sleep = false;
domain->chip.of_node = domain->of_node;
domain->chip.of_gpio_n_cells = 2;

ret = gpiochip_add(&domain->chip);

上面这段程序就是填充的过程。
以此来推,其它驱动也是”类似”填充的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值