====bus层==================
/driver/base/bus.c:
struct bus_type_private {
struct kset subsys; --kset --hid usb platform i2c scsi usb 挂接在/sys/bus 下
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
int bus_register(struct bus_type *bus)
/sys/bus/usb 下创建了device driver 两个kset
do_basic_setup->driver_init->
devices_init
buses_init
classes_init
firmware_init
platform_bus_init
system_bus_init
cpu_dev_init
memory_dev_init
======================
/driver/base/class.c
class_kset
struct class_private {
struct kset class_subsys;----bdi tty misc input rtc net mtd sound graphic
struct klist class_devices;
struct list_head class_interfaces;
struct kset class_dirs;
struct mutex class_mutex;
struct class *class;
};
int class_register(struct class *cls, struct lock_class_key *key)
/sys/bus/input
========device层=========
driver/base/core.c
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct device_type *type;
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
}
int __init devices_init(void)
void device_initialize(struct device *dev)
int device_add(struct device *dev)
=========platform_bus 属于bus================
driver/base/platform.c
platform 本身是bus,又是一个device
int __init platform_bus_init(void)
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
};
对其他模块提供的api
platform_add_devices(struct platform_device **devs, int num)
platform_drv_probe(struct device *_dev)
====device register/driver register 及probe =============================
Linux 2.6的设备驱动模型中,所有的device都是通过Bus相连。device_register() / driver_register()执行时通过枚举BUS上的Driver/Device来实现绑定,本文详解这一过程。这是整个LINUX设备驱动的基础,PLATFORM设备,I2C上的设备等诸设备的注册最终也是调用本文讲述的注册函数来实现的。
Linux Device的注册最终都是通过device_register()实现,Driver的注册最终都是通过driver_register()实现。下图对照说明了Device和Driver的注册过程。
上面的图解一目了然,详细过程不再赘述。注意以下几点说明:
-
- BUS的p->drivers_autoprobe;1默认是true。
- bus_for_each_drv()是对BUS上所有的Driver都进行__device_attach()操作;同样的,bus_for_each_dev()是对BUS上所有的Device都进行__driver_attach()操作。
- BUS上实现的.match()函数,定义了Device和Driver绑定时的规则。比如Platform实现的就是先比较id_table,然后比较name的规则。如果BUS的match()函数没实现,认为BUS上的所有的Device和Driver都是match的,具体后续过程要看probe()的实现了。
- Probe的规则是:如果BUS上实现了probe就用BUS的probe;否则才会用driver的probe。
- driver和device 的match规则看了部分代码,是比较name来实现的
Device一般是先于Driver注册,但也不全是这样的顺序。Linux的Device和Driver的注册过程分别枚举挂在该BUS上所有的Driver和Device实现了这种时序无关性。
设备驱动的probe、remove以及shutdown的顺序http://blog.chinaunix.net/uid-29955651-id-5175102.html
======start_kernel->setup_arch与驱动部分的关系2.6.33.7 S3C2440A==================
start_kernel
->setup_arch
->paging_init
->devicemaps_init
-> mdesc->map_io()
->smdk2440_map_io
->s3c24xx_init_io/s3c24xx_init_clocks/s3c24xx_init_uarts
start_kernel
->init_IRQ()
->init_arch_irq = mdesc->init_irq
->s3c24xx_init_irq
start_kernel
->time_init()
-> system_timer = mdesc->timer;
->system_timer->init();
->s3c2410_timer_init(void)
arch_initcall(customize_machine);
-> init_machine->init_machine = mdesc->init_machine;
-> smdk2440_machine_init
/*
nr : MACH_TYPE_S3C2440 ,与uboot machid 做比较
setup_arch->setup_machine
->arch_initcall(customize_machine)
->customize_machine
->init_machine
->smdk2440_machine_init
*/
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <[email protected]> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
/*
machine_desc会被放入 __arch_info_begin段
kernel启动的时候在head-common.s 中 __lookup_machine_type 找到匹配的machine
MACH_TYPE_##_type 匹配与uboot的setenv machid 环境变量
*/
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
对于平台设备等无法热插拔的设备,必须在内核初始化的时候就生成(对于PCI设备,及热拔插设备以后会补充)
这里会调用device_add函数在系统中添加device; driver目录实现这里device的驱动程序
arch_initcall(customize_machine);
-> init_machine->init_machine = mdesc->init_machine;
-> smdk2440_machine_init
->platform_device_add(struct platform_device *pdev)
-> device_add(struct device *dev)
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
=======linux内核device生成流程===
https://blog.csdn.net/mrcc_yy/article/details/51393718
一、前言
在驱动模型的框架下,设备驱动的开发主要包含以下两个步骤:
步骤1:分配一个struct device类型的变量,填充必要的信息后,把它注册到内核中。
步骤2:分配一个struct device_driver类型的变量,填充必要的信息后,把它注册到内核中。
上述两个步骤完成后,内核会在合适的时机(注册device、注册device_driver等)执行probe等回调函数,那么每个设备对应的struct device结构是何时创建的呢?本文主要针对这个问题分析。
注:本文涉及的代码基于linux 3.10版本
二、device初始化流程
对于平台设备等无法热插拔的设备,必须在内核初始化的时候就生成对应的struct device结构体。而对于挂在真正总线(如i2c、usb等)上的设备,struct device结构体由对应的总线驱动在初始化或设备热插拔时生成。本文只对前一种设备做介绍。
S3C2440驱动简析——看门狗驱动https://blog.csdn.net/jarvis_xian/article/details/6525528
menuconfig:
Kernel Features --->
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
Device Drivers --->
Character devices --->
Serial drivers --->
<*> Samsung SoC serial support
[*] Support for console on Samsung SoC serial port
<*> Samsung S3C2440/S3C2442 Serial port support