设备节点的动态建立 class
来源:互联网 发布:ubuntu命令行复制粘贴 编辑:程序博客网 时间:2024/04/30 18:43
我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同,而且里面的参数设置也有一些变化。
struct class和device_create(…) 以及device_create(…)都定义在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。
例子:创建/sys/class/leds 目录
在/sys/class/leds 目录keyboard-backlight子目录创建led_brightness文件
/*
* LED Class Core
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
* Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
#include <linux/err.h>
#include <linux/ctype.h>
#include <linux/leds.h>
#include "leds.h"
static struct class *leds_class;
static void led_update_brightness(struct led_classdev *led_cdev)
{
if (led_cdev->brightness_get)
led_cdev->brightness = led_cdev->brightness_get(led_cdev);
}
static ssize_t led_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
/* no lock needed for this */
led_update_brightness(led_cdev);
return sprintf(buf, "%u/n", led_cdev->brightness);
}
static ssize_t led_brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
if (*after && isspace(*after))
count++;
if (count == size) {
ret = count;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state);
}
return ret;
}
static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
#ifdef CONFIG_LEDS_TRIGGERS
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
#endif
/**
* led_classdev_suspend - suspend an led_classdev.
* @led_cdev: the led_classdev to suspend.
*/
void led_classdev_suspend(struct led_classdev *led_cdev)
{
led_cdev->flags |= LED_SUSPENDED;
led_cdev->brightness_set(led_cdev, 0);
}
EXPORT_SYMBOL_GPL(led_classdev_suspend);
/**
* led_classdev_resume - resume an led_classdev.
* @led_cdev: the led_classdev to resume.
*/
void led_classdev_resume(struct led_classdev *led_cdev)
{
led_cdev->brightness_set(led_cdev, led_cdev->brightness);
led_cdev->flags &= ~LED_SUSPENDED;
}
EXPORT_SYMBOL_GPL(led_classdev_resume);
static int led_suspend(struct device *dev, pm_message_t state)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
led_classdev_suspend(led_cdev);
return 0;
}
static int led_resume(struct device *dev)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
led_classdev_resume(led_cdev);
return 0;
}
/**
* led_classdev_register - register a new object of led_classdev class.
* @parent: The device to register.
* @led_cdev: the led_classdev structure for this device.
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
int rc;
led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
"%s", led_cdev->name);//在/sys/class/leds目录创建keyboard-backlight子目录
if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
/* register the attributes */
rc = device_create_file(led_cdev->dev, &dev_attr_brightness); //在/sys/class/leds/keyboard-backlight子目录创建led_brightness文件
if (rc)
goto err_out;
#ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock);
#endif
/* add to the list of leds */
down_write(&leds_list_lock);
list_add_tail(&led_cdev->node, &leds_list);
up_write(&leds_list_lock);
led_update_brightness(led_cdev);
#ifdef CONFIG_LEDS_TRIGGERS
rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
if (rc)
goto err_out_led_list;
led_trigger_set_default(led_cdev);
#endif
printk(KERN_INFO "Registered led device: %s/n",
led_cdev->name);
return 0;
#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
device_remove_file(led_cdev->dev, &dev_attr_brightness);
list_del(&led_cdev->node);
#endif
err_out:
device_unregister(led_cdev->dev);
return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);
/**
* led_classdev_unregister - unregisters a object of led_properties class.
* @led_cdev: the led device to unregister
*
* Unregisters a previously registered via led_classdev_register object.
*/
void led_classdev_unregister(struct led_classdev *led_cdev)
{
device_remove_file(led_cdev->dev, &dev_attr_brightness);
#ifdef CONFIG_LEDS_TRIGGERS
device_remove_file(led_cdev->dev, &dev_attr_trigger);
down_write(&led_cdev->trigger_lock);
if (led_cdev->trigger)
led_trigger_set(led_cdev, NULL);
up_write(&led_cdev->trigger_lock);
#endif
device_unregister(led_cdev->dev);
down_write(&leds_list_lock);
list_del(&led_cdev->node);
up_write(&leds_list_lock);
}
EXPORT_SYMBOL_GPL(led_classdev_unregister);
static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE, "leds");
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
leds_class->suspend = led_suspend;
leds_class->resume = led_resume;
return 0;
}
static void __exit leds_exit(void)
{
class_destroy(leds_class);
}
subsys_initcall(leds_init);
module_exit(leds_exit);
MODULE_AUTHOR("John Lenz, Richard Purdie");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LED Class Interface");
在/sys/class/leds 目录创建lcd-backlight子目录
static struct led_classdev sapphire_backlight_led = {
.name = "lcd-backlight",
.brightness = SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS,
.brightness_set = sapphire_brightness_set,
};
static int sapphire_backlight_probe(struct platform_device *pdev)
{
led_classdev_register(&pdev->dev, &sapphire_backlight_led);
return 0;
}
在/sys/class/leds 目录创建keyboard-backlight子目录
/*
* leds-msm-pmic.c - MSM PMIC LEDs driver.
*
* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can find it at http://www.fsf.org.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <mach/pmic.h>
#define MAX_KEYPAD_BL_LEVEL 16
static void msm_keypad_bl_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
int ret;
ret = pmic_set_led_intensity(LED_KEYPAD, value / MAX_KEYPAD_BL_LEVEL);
if (ret)
dev_err(led_cdev->dev, "can't set keypad backlight/n");
}
static struct led_classdev msm_kp_bl_led = {
.name = "keyboard-backlight",
.brightness_set = msm_keypad_bl_led_set,
.brightness = LED_OFF,
};
static int msm_pmic_led_probe(struct platform_device *pdev)
{
int rc;
rc = led_classdev_register(&pdev->dev, &msm_kp_bl_led);
if (rc) {
dev_err(&pdev->dev, "unable to register led class driver/n");
return rc;
}
msm_keypad_bl_led_set(&msm_kp_bl_led, LED_OFF);
return rc;
}
static int __devexit msm_pmic_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&msm_kp_bl_led);
return 0;
}
#ifdef CONFIG_PM
static int msm_pmic_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&msm_kp_bl_led);
return 0;
}
static int msm_pmic_led_resume(struct platform_device *dev)
{
led_classdev_resume(&msm_kp_bl_led);
return 0;
}
#else
#define msm_pmic_led_suspend NULL
#define msm_pmic_led_resume NULL
#endif
static struct platform_driver msm_pmic_led_driver = {
.probe = msm_pmic_led_probe,
.remove = __devexit_p(msm_pmic_led_remove),
.suspend = msm_pmic_led_suspend,
.resume = msm_pmic_led_resume,
.driver = {
.name = "pmic-leds",
.owner = THIS_MODULE,
},
};
static int __init msm_pmic_led_init(void)
{
return platform_driver_register(&msm_pmic_led_driver);
}
module_init(msm_pmic_led_init);
static void __exit msm_pmic_led_exit(void)
{
platform_driver_unregister(&msm_pmic_led_driver);
}
module_exit(msm_pmic_led_exit);
MODULE_DESCRIPTION("MSM PMIC LEDs driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:pmic-leds");
- 设备节点的动态建立 class
- 设备节点的动态建立
- 设备节点的动态建立
- 动态建立设备节点class_creat/device_creat
- udev建立设备节点的规则
- 动态改变子节点下面的class
- Android设备节点的动态管理
- Android设备节点的动态管理
- Android设备节点的动态管理
- 在linux 2.6内核下建立字符设备,自动获取设备号,建立设备节点的简单例子
- 驱动添加设备节点/sys/class/
- 一个字符设备实例,以及自动建立设备节点
- Android 的设备节点
- Android 的设备节点
- Android 的设备节点
- 在linux中动态的申请设备号,怎么在文件系统中创建设备节点
- 为动态增加节点添加class属性
- 用脚本动态创建设备节点
- Vim的学习笔记【一】
- 这一眨眼,6年就过去了。
- django创建表时附加数据库自定义选项的方法——如指定数据库的存储引擎
- Android中ListView的自定义显示
- 行者无疆——自行车也“拉高速”
- 设备节点的动态建立 class
- 面试中问到的几个问题
- msm7227平台linux I2C驱动分析(2.6.29)
- 阶段总结
- Android 中的ListView被选中项的背景怎么改
- 当前Java软件开发中几种认识误区
- 坚持收获
- SqlDataReader和SqlDataAdapter 区别
- CxImage的简单使用(编译-->项目设置-->代码示例(PNG透明贴图))