1. 程式人生 > >我所理解的linux kernel的移植

我所理解的linux kernel的移植

從林納斯.託瓦茲(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);

上面這段程式就是填充的過程。
以此來推,其它驅動也是”類似”填充的。