初探linux子系統集之led子系統(一)
就像學程式設計第一個範例helloworld一樣,學嵌入式,微控制器、fpga之類的第一個範例就是點亮一盞燈。對於龐大的linux系統,當然可以編寫一個字元裝置驅動來實現我們需要的led燈,也可以直接利用gpio口,應用程式來拉高拉低管腳控制。不過,既然linux系統自己本來就帶有led子系統,那麼就可以好好利用之。好處不用多說了,主要對於應用層來說,不同平臺都用linux的led子系統,那麼應用程式不用做任何的改變,就可以在新的平臺上執行,可移植性好。
linux的led子系統的原始碼路徑:
Include/Linux/leds.h /drivers/leds
首先看一下led子系統中的主要檔案:
# LED Core obj-$(CONFIG_NEW_LEDS) +=led-core.o obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_TRIGGERS) +=led-triggers.o # LED PlatformDrivers obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) +=ledtrig-timer.o obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) +=ledtrig-ide-disk.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) +=ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) +=ledtrig-backlight.o obj-$(CONFIG_LEDS_TRIGGER_GPIO) +=ledtrig-gpio.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
主要由leds.h、led-core.c、led-class.c、led-triggers.c,其中led-triggers又分為了timer、ide-disk、heartbeat、backlight、gpio、default-on等演算法。
例子程式是leds-gpio,接下去會主要分析這個驅動實現。
首先簡單看一下主要的檔案
Leds.h
1、enum led_brightness{ LED_OFF = 0, LED_HALF = 127, LED_FULL = 255, };
Led的亮度,分為三等級,關、中間、最亮。
2、struct led_classdev{
constchar *name; // Led的名字
int brightness; //led亮度
int max_brightness; //led最大亮度
int flags;
/*Lower 16 bits reflect status */
#define LED_SUSPENDED (1 << 0)
/*Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME (1 << 16)
/*Set LED brightness level */
/*Must not sleep, use a workqueue if needed */
void (*brightness_set)(struct led_classdev*led_cdev,
enum led_brightness brightness); //亮度設定函式指標
/*Get LED brightness level */
enumled_brightness (*brightness_get)(struct led_classdev *led_cdev); //獲取亮度函式指標
int (*blink_set)(struct led_classdev*led_cdev,
unsigned long *delay_on,
unsigned long *delay_off); //閃爍時點亮和熄滅的時間設定
structdevice *dev;
structlist_head node; //leds-list的node
constchar *default_trigger; //預設trigger的名字
unsignedlong blink_delay_on,blink_delay_off; //閃爍的開關時間
structtimer_list blink_timer; //閃爍的定時器連結串列
int blink_brightness; //閃爍的亮度
#ifdef CONFIG_LEDS_TRIGGERS
/*Protects the trigger data below */
structrw_semaphore trigger_lock; //trigger的鎖
structled_trigger *trigger; //led的trigger
structlist_head trig_list; //trigger的連結串列
void *trigger_data; //trigger的資料
#endif
};
3、struct led_trigger {
/*Trigger Properties */
constchar *name; //trigger的名字
void (*activate)(struct led_classdev*led_cdev); //啟用trigger
void (*deactivate)(struct led_classdev*led_cdev);
/*LEDs under control by this trigger (for simple triggers) */
rwlock_t leddev_list_lock;
structlist_head led_cdevs; //led裝置的連結串列
/*Link to next registered trigger */
structlist_head next_trig;
};
4、/* For the leds-gpiodriver */
struct gpio_led {
constchar *name; //led的名字
constchar *default_trigger; //預設的trigger
unsigned gpio; //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) */
};
5、structgpio_led_platform_data {
int num_leds; led的個數
conststruct 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,
unsignedlong *delay_on,
unsignedlong *delay_off);
};
led-core.c
DECLARE_RWSEM(leds_list_lock);
EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
主要是聲明瞭leds的連結串列和鎖。
Led-class.c
1、 leds_init
主要是建立leds_class,賦值suspend和resume以及dev_attrs。
led_class_attrs
static struct device_attribute led_class_attrs[] = {
__ATTR(brightness,0644, led_brightness_show, led_brightness_store),
__ATTR(max_brightness,0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
__ATTR(trigger,0644, led_trigger_show, led_trigger_store),
#endif
__ATTR_NULL,
};
2、led_classdev_register
建立classdev裝置,也即Leds_class類中例項化一個物件,類似於c++的new一個物件,leds有很多種,而這裡是註冊一個特定的led,核心中的面向物件思想也極其豐富。
加到leds_list連結串列中,初始化blinktimer,指定blink_timer的function和data,設定trigger,然後一個新的led裝置就註冊好了,就可以使用了。
led-triggers.c
1、led_trigger_register
掃描trigger連結串列中是否有同名的trigger,接著把當前trigger加入到連結串列中,如果led_classdev中有預設的trigger,那麼就設定這個預設的。
好了,簡單看了下led子系統中比較重要的結構體和函式,那麼接下去就可以通過leds-gpio這個驅動來進一步瞭解led子系統了。