日期:2014-05-16  浏览次数:20795 次

linux驱动实践(三)--不大一般的LED驱动

        看了这么多内核代码,终于要自己开始做驱动了.按照由易到难,由浅入深的顺序,就从LED开始.

        LED驱动可以说是hello world之后最简单的驱动模块了.如果自己写一个LED驱动那是很简单的,其实用linux内核中的leds子系统来做也是比较简单的,内核中的leds子系统是将led抽象成platform_device,并有leds_class.这样,在/sys/class/leds/目录下面就可以利用sysfs文件系统来实现LED的操作.其实,也可以在此基础上添加/dev访问的接口,甚至用不着包含mknod的脚本和udev等工具,在模块注册后就可以生成/dev下的设备文件.

        一步一步的来,首先利用platform虚拟总线来实现sysfs文件系统下的LED操作.

        在mach-smdk2440.c中新增platform_device如下:

static struct platform_device smdk_led5 = {
	.name		= "s3c24xx_led",
	.id		= 0,
	.dev		= {
		.platform_data = &smdk_pdata_led5,
		.release = &platform_led_release,
	},
};
        对于具体的板子,是GPB5-8对应四个LED,所以这里smdk_pdata_led5的定义如下:

static struct s3c24xx_led_platdata smdk_pdata_led5 = {
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW ,//| S3C24XX_LEDF_TRISTATE,
	.name		= "led5",
	//.def_trigger	= "nand-disk",
};
        接着在static struct platform_device *smdk2440_devices[] __initdata中新增&smdk_led5,这样系统在启动时就会由smdk2440_machine_init调用platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));来添加刚才加上的platform_device.

        看完了platform_device再看下platform_driver是如何注册的:

        在drivers/leds目录下的Makefile中有obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o

        所以在make menuconfig的时候记得将其选为M.

        这样,注册leds-s3c24xx.ko就会在/sys/class/leds中有

        led5  led6  led7  led8四个目录,进入led5目录,有

        brightness      device          power           trigger
        dev             max_brightness  subsystem       uevent

        执行echo 0 > brightness就可以关闭led,而echo 1 > brightness就可以打开led.

        因为有leds_class,而在led-class.c中leds-init函数中有leds_class->dev_attrs = led_class_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,
};
        根据sysfs的属性文件,读写属性文件最终调用的就是show和store函数,在这里就是led_brightness_show和led_brightness_store函数.
        顺着调用其实设置寄存器的动作是在leds-s3c24xx.c中的s3c24xx_led_set实现的.从这里可以看出,LEDS这个子系统也做了抽象,与平台相关的放在一个文件中,而与平台无关的抽象出来放在led-class中.

        到此,就可以通过sysfs文件系统来访问led设备了.

        那么,开头说的在此基础如何做/dev访问的接口呢?

        在leds目录下新建一个文件led-dev.c

        在Makefile中添加obj-$(CONFIG_LEDS_INTF_DEV) += led-dev.o