驱动代码
创建timed_output类 kernel/drivers/staging/android/Timed_output.c 在sys/class目录创建timed_output子目录和文件enable timed_output_class = class_create(THIS_MODULE, "timed_output");创建timed_output子目录 ret = device_create_file(tdev->dev, &dev_attr_enable);在sys/class/timed_output子目录创建文件enable
static int create_timed_output_class(void) return 0; int timed_output_dev_register(struct timed_output_dev *tdev) if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) ret = create_timed_output_class(); tdev->index = atomic_inc_return(&device_count); ret = device_create_file(tdev->dev, &dev_attr_enable); dev_set_drvdata(tdev->dev, tdev); err_create_file: return ret; 驱动注册马达的驱动,注册一个定时器用于控制震动时间(回调函数vibrator_timer_func),注册两个队列,一共给马达打开用,一共为马达震动关闭用。
static void pmic_vibrator_on(struct work_struct *work) static void pmic_vibrator_off(struct work_struct *work) static void timed_vibrator_on(struct timed_output_dev *sdev) static void timed_vibrator_off(struct timed_output_dev *sdev) static void vibrator_enable(struct timed_output_dev *dev, int value) if (value == 0) timed_vibrator_on(dev); hrtimer_start(&vibe_timer, static int vibrator_get_time(struct timed_output_dev *dev) static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) static struct timed_output_dev pmic_vibrator = { void __init pxa_init_pmic_vibrator(void) hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); timed_output_dev_register(&pmic_vibrator); 当上层要设置马达震动时,往文件/sys/class/timed_output/vibrator/enable写入振动的时间长度,通过 static ssize_t enable_store( sscanf(buf, "%d", &value); return size; 调用驱动的enable函数也就是vibrator_enable( .enable = vibrator_enable,)
vibrator_enable | | v timed_vibrator_on(dev); | | v schedule_work(&work_vibrator_on); | | v pmic_vibrator_on | | v set_pmic_vibrator(1); //给马达供电震动 | | v hrtimer_start(&vibe_timer, 最终是设置马达的硬件控制驱动管给马达供电,并且启动定时器,定时时间是上层给的参数。 定时时间到了就调用定时器的回调函数vibrator_timer_func | | v timed_vibrator_off(NULL); | | v schedule_work(&work_vibrator_off); | | v pmic_vibrator_off | | v set_pmic_vibrator(0); //断开马达的供电,马达停止震动 最终是设置马达的硬件控制驱动管断开马达供电,停止马达震动
led类驱动 4.1,驱动创建leds类,系统启动时执行leds_init在目录/sys/class/创建子目录leds kernel/drivers/leds/Led-class.c
static int __init leds_init(void)
4.2,led_classdev_register,调用这个函数就在目录/sys/class/leds创建子目录led_cdev->name和属性文件brightness 对brightness文件写就执行led_brightness_store,对brightness文件读就执行led_brightness_show,为下面的lcd,led注册做好准备 kernel/drivers/leds/Led-class.c static ssize_t led_brightness_show(struct device *dev, /* no lock needed for this */ return sprintf(buf, "%u/n", led_cdev->brightness); static ssize_t led_brightness_store(struct device *dev, if (*after && isspace(*after)) if (count == size) { if (state == LED_OFF) return ret; static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, /* register the attributes */ #ifdef CONFIG_LEDS_TRIGGERS led_update_brightness(led_cdev); #ifdef CONFIG_LEDS_TRIGGERS led_trigger_set_default(led_cdev); printk(KERN_INFO "Registered led device: %s/n", return 0; #ifdef CONFIG_LEDS_TRIGGERS
4.3,lcd驱动调用led_classdev_register,在目录/sys/class/leds创建子目录lcd-backlight和属性文件brightness kernel/drivers/video/msm/Msm_fb.c static int lcd_backlight_registered; static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, if (value > MAX_BACKLIGHT_BRIGHTNESS) /* This maps android backlight level 0 to 255 into if (!bl_lvl && value) msm_fb_set_backlight(mfd, bl_lvl, 1); static struct led_classdev backlight_led = {
if (!lcd_backlight_registered) { 就在目录/sys/class/leds创建子目录 lcd-backlight和属性文件brightness 当按键或者来的或者改变lcd亮度时,上层对属性文件/sys/class/leds/lcd-backlight/brightness写入背光的亮度数值就 调用led_brightness_store 调用simple_strtoul(buf, &after, 10);将输入的字符串转换为10进制的数字 执行led_set_brightness 执行led_cdev->brightness_set(led_cdev, value 调用msm_fb_set_bl_brightness ,因为 .brightness_set = msm_fb_set_bl_brightness, /* This maps android backlight level 0 to 255 into driver backlight level 0 to bl_max with rounding */ 调用 msm_fb_set_backlight(mfd, bl_lvl, 1); 最终改变LCD的背光驱动电路的设置,调节LCD的背光的亮度
4.4 键盘背光灯 上层对属性文件/sys/class/leds/keyboard-backlight/brightness写入背光的亮度数值
(kernel/drivers/leds/Leds-msm-pmic.c #define MAX_KEYPAD_BL_LEVEL 16 static void msm_keypad_bl_led_set(struct led_classdev *led_cdev, ret = pmic_set_led_intensity(LED_KEYPAD, value / MAX_KEYPAD_BL_LEVEL); static struct led_classdev msm_kp_bl_led = { static int msm_pmic_led_probe(struct platform_device *pdev) rc = led_classdev_register(&pdev->dev, &msm_kp_bl_led); static int __devexit msm_pmic_led_remove(struct platform_device *pdev) return 0; #ifdef CONFIG_PM return 0; static int msm_pmic_led_resume(struct platform_device *dev) return 0; static struct platform_driver msm_pmic_led_driver = { static int __init msm_pmic_led_init(void) static void __exit msm_pmic_led_exit(void) MODULE_DESCRIPTION("MSM PMIC LEDs driver");
系统行动执行msm_pmic_led_init(void) 调用msm_pmic_led_probe 调用 led_classdev_register(&pdev->dev, &msm_kp_bl_led); 就在目录/sys/class/leds创建子目录 keyboard-backlight和属性文件brightness 当按键时,上层对属性文件/sys/class/leds/keyboard-backlight/brightness写入背光的亮度数值就 调用led_brightness_store 调用simple_strtoul(buf, &after, 10);将输入的字符串转换为10进制的数字 执行led_set_brightness 执行led_cdev->brightness_set(led_cdev, value 调用msm_keypad_bl_led_set ,因为 .brightness_set = msm_keypad_bl_led_set, 调用 ret = pmic_set_led_intensity(LED_KEYPAD, value / MAX_KEYPAD_BL_LEVEL); |