从林纳斯.托瓦兹(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);上面这段程序就是填充的过程。 以此来推,其它驱动也是”类似”填充的。