继上次研究ADC驱动,开始接触platform这个东西。不过坦白讲,还是理解的不是很透彻。所以准备今天爬一次code。以加深这方面的理解。
我们来看一个led灯的驱动是如何用平台总线来实现的:
struct gpio_led {
const char *name;
const char *default_trigger;//触发方式
unsigned gpio;
unsigned active_low : 1;//是高电平点亮还是低电平点亮
unsigned retain_state_suspended : 1;//休眠时是否保存状态,等到唤醒后恢复
unsigned default_state : 2;//初始化的状态
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
};
struct gpio_led_platform_data {
int num_leds;//led的个数
const struct gpio_led *leds;//led的结构数组
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Please, blink */
int (*gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on,
unsigned long *delay_off);/*闪烁的函数指针,这里就比较像c++ 类的思想了*/
};
构造一个平台设备,然后将设备挂载到platform的总线上。
驱动会遍历相同总线下的所有设备,找到和本身驱动列表中name相同的设备。如果有,则绑定驱动到具体的设备,如果无,则不做任何处理。
一般情况下,设备挂载成功会在sys/bus/platform/devices 目录下面找到你的设备
如果驱动挂载成功,会在sys/bus/platform/drivers目录下找到你的驱动文件
那platform是一种虚拟总线,下面挂着平台设备和平台驱动。
1.如何构造一个平台设备?
struct platform_device {
const char *name;//设备名称,没什么好讲的,一般这边的name要和对应的驱动或者驱动列表里面的name一致,否则驱动无法绑定成功
int id;//设备id,linux内核允许多个同名设备,同名设备间的区别用id来鉴别,PLATFORM_DEVID_NONE(-1)
PLATFORM_DEVID_AUTO(-2)
bool id_auto;// 初始化此flag,可以让内核自动分配id
struct device dev;//设备结构体,platform_device是由这个结构体抽象来的
u32 num_resources;//资源数
struct resource *resource;//资源列表,2者同时出现,用于描述资源,一般包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型
const struct platform_device_id *id_entry;//平台设备列表
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
我们粗略看完了platform_device 这个结构体。然后继续分析它里面的一些结构体:
device结构体
/**
* struct device - The basic device structure
* @parent: The device's "parent" device, the device to which it is attached.
* In most cases, a parent device is some sort of bus or host
* controller. If parent is NULL, the device, is a top-level device,
* which is not usually what you want.
* @p: Holds the private data of the driver core portions of the device.
* See the comment of the struct device_private for detail.
* @kobj: A top-level, abstract class from which other classes are derived.
* @init_name: Initial name of the device.
* @type: The type of device.
* This identifies the device type and carries type-specific
* information.
* @mutex: Mutex to synchronize calls to its driver.
* @bus: Type of bus device is on.
* @driver: Which driver has allocated this
* @platform_data: Platform data specific to the device.
* Example: For devices on custom boards, as typical of embedded
* and SOC based hardware, Linux often uses platform_data to point
* to board-specific structures describing devices and how they
* are wired. That can include what ports are available, chip
* variants, which GPIO pins act in what additional roles, and so
* on. This shrinks the "Board Support Packages" (BSPs) and
* minimizes board-specific #ifdefs in drivers.
* @power: For device power management.
* See Documentation/power/devices.txt for details.
* @pm_domain: Provide callbacks that are executed during system suspend,
* hibernation, system resume and during runtime PM transitions
* along with subsystem-level and driver-level callbacks.
* @pins: For device pin management.
* See Documentation/pinctrl.txt for details.
* @numa_node: NUMA node this device is close to.
* @dma_mask: Dma mask (if dma'ble device).
* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
* hardware supports 64-bit addresses for consistent allocations
* such descriptors.
* @dma_parms: A low level driver may set these to teach IOMMU code about
* segment limitations.
* @dma_pools: Dma pools (if dma'ble device).
* @dma_mem: Internal for coherent mem override.
* @archdata: For arch-specific additions.
* @of_node: Associated device tree node.
* @acpi_node: Associa