嵌入式Linux字符设备驱动开发流程——以LED为例

前言

留空

头文件

#include

查看系统设备类

ls /sys/class

设备类结构体

文件(路径):include/linux/device.h

/**

* struct class - device classes

* @name:   Name of the class.

* @owner:  The module owner.

* @class_attrs: Default attributes of this class.

* @dev_attrs:  Default attributes of the devices belong to the class.

* @dev_bin_attrs: Default binary attributes of the devices belong to the class.

* @dev_kobj:   The kobject that represents this class and links it into the hierarchy.

* @dev_uevent: Called when a device is added, removed from this class, or a

*      few other things that generate uevents to add the environment

*      variables.

* @devnode:    Callback to provide the devtmpfs.

* @class_release: Called to release this class.

* @dev_release: Called to release the device.

* @suspend:    Used to put the device to sleep mode, usually to a low power

*      state.

* @resume: Used to bring the device from the sleep mode.

* @ns_type:    Callbacks so sysfs can detemine namespaces.

* @namespace:  Namespace of the device belongs to this class.

* @pm:     The default device power management operations of this class.

* @p:      The private data of the driver core, no one other than the

*      driver core can touch this.

*

* A class is a higher-level view of a device that abstracts out low-level

* implementation details. Drivers may see a SCSI disk or an ATA disk, but,

* at the class level, they are all simply disks. Classes allow user space

* to work with devices based on what they do, rather than how they are

* connected or how they work.

*/

struct class {

const char      *name;

struct module       *owner;

struct class_attribute      *class_attrs;

struct device_attribute     *dev_attrs;

struct bin_attribute        *dev_bin_attrs;

struct kobject          *dev_kobj;

int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

char *(*devnode)(struct device *dev, mode_t *mode);

void (*class_release)(struct class *class);

void (*dev_release)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);

int (*resume)(struct device *dev);

const struct kobj_ns_type_operations *ns_type;

const void *(*namespace)(struct device *dev);

const struct dev_pm_ops *pm;

struct subsys_private *p;

};

创建设备类函数

所属文件名:class.c

/**

* class_create - create a struct class structure

* @owner: pointer to the module that is to "own" this struct class

* @name: pointer to a string for the name of this class.

* @key: the lock_class_key for this class; used by mutex lock debugging

*

* This is used to create a struct class pointer that can then be used

* in calls to device_create().

*

* Returns &struct class pointer on success, or ERR_PTR() on error.

*

* Note, the pointer created here is to be destroyed when finished by

* making a call to class_destroy().

*/

struct class *__class_create(struct module *owner, const char *name,

struct lock_class_key *key)

{

struct class *cls;

int retval;

cls = kzalloc(sizeof(*cls), GFP_KERNEL);

if (!cls) {

retval = -ENOMEM;

goto error;

}

cls->name = name;

cls->owner = owner;

cls->class_release = class_create_release;

retval = __class_register(cls, key);

if (retval)

goto error;

return cls;

error:

kfree(cls);

return ERR_PTR(retval);

}

释放设备类

所属文件名:class.c

/**

* class_destroy - destroys a struct class structure

* @cls: pointer to the struct class that is to be destroyed

*

* Note, the pointer to be destroyed must have been created with a call

* to class_create().

*/

void class_destroy(struct class *cls)

{

if ((cls == NULL) || (IS_ERR(cls)))

return;

class_unregister(cls);

}

创建设备节点函数

所属文件名:core.c

/**

* device_create - creates a device and registers it with sysfs

* @class: pointer to the struct class that this device should be registered to

* @parent: pointer to the parent struct device of this new device, if any

* @devt: the dev_t for the char device to be added

* @drvdata: the data to be added to the device for callbacks

* @fmt: string for the device's name

*

* This function can be used by char device classes.  A struct device

* will be created in sysfs, registered to the specified class.

*

* A "dev" file will be created, showing the dev_t for the device, if

* the dev_t is not 0,0.

* If a pointer to a parent struct device is passed in, the newly created

* struct device will be a child of that device in sysfs.

* The pointer to the struct device will be returned from the call.

* Any further sysfs files that might be required can be created using this

* pointer.

*

* Returns &struct device pointer on success, or ERR_PTR() on error.

*

* Note: the struct class passed to this function must have previously

* been created with a call to class_create().

*/

struct device *device_create(struct class *class, struct device *parent,

dev_t devt, void *drvdata, const char *fmt, ...)

{

va_list vargs;

struct device *dev;

va_start(vargs, fmt);

dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);

va_end(vargs);

return dev;

}

释放设备节点

所属文件名:core.c

/**

* device_destroy - removes a device that was created with device_create()

* @class: pointer to the struct class that this device was registered with

* @devt: the dev_t of the device that was previously registered

*

* This call unregisters and cleans up a device that was created with a

* call to device_create().

*/

void device_destroy(struct class *class, dev_t devt)

{

struct device *dev;

dev = class_find_device(class, NULL, &devt, __match_devt);

if (dev) {

put_device(dev);

device_unregister(dev);

}

}

程序

#include            //模块头文件

#include            //内核头文件

#include              //内核初始化

#include                //字符设备函数

#include              //字符设备描述

#include            //系列设备号处理宏

#include              //内存分配头文件

#include            //设备类节点头文件

#define DEVICE_NAME     "leds"      //字符设备名称

#define NODE_NAME       "led"

#define DEVICE_MINOR_NUM    2       //字符设备数量

#define DEV_MAJOR   0               //主设备号

#define DEV_MINOR   0               //次设备号,0为自动分配

#define REGDEV_SIZE 3000

static int leds_major = DEV_MAJOR;  //主设备号变量

static int leds_minor = DEV_MINOR;  //次设备号变量

static dev_t leds_dev;              //设备号

struct cdev *leds_cdev;             //字符设备结构体变量

static struct class *leds_class;    //类结构体变量

struct file_operations leds_fops = {

.owner = THIS_MODULE,

};

static __init int leds_init(void)

{

int ret = 0;

int i;

ret = alloc_chrdev_region(&leds_dev, leds_minor, DEVICE_MINOR_NUM, DEVICE_NAME);

if(ret < 0){

printk(KERN_EMERG "register_chrdev_region req %d is failed!\n", DEV_MAJOR);

return ret;

}

leds_major = MAJOR(leds_dev);   //主设备号

leds_minor = MINOR(leds_dev);   //次设备号

printk(KERN_EMERG "leds chrdev major=%d, minor=%d\n", leds_major, leds_minor);

leds_class = class_create(THIS_MODULE,DEVICE_NAME);

leds_cdev = kmalloc(DEVICE_MINOR_NUM * sizeof(struct cdev), GFP_KERNEL);

if(leds_cdev == NULL)

{

printk(KERN_EMERG "kmalloc failed");

unregister_chrdev_region(leds_dev, DEVICE_MINOR_NUM);

return -ENOMEM;

}

//memset(leds_cdev, 0, DEVICE_MINOR_NUM * sizeof(struct dev_cdev));

for(i=0; i

cdev_init(&leds_cdev[i], &leds_fops);

leds_cdev[i].owner = THIS_MODULE;

leds_cdev[i].ops = &leds_fops;

ret = cdev_add(&leds_cdev[i], MKDEV(leds_major, leds_minor+i), 1);  //注册到设备

device_create(leds_class, NULL, MKDEV(leds_major, leds_minor+i), NULL, NODE_NAME"%d", i);

if(ret < 0){

printk(KERN_EMERG "cdev_add %d failed!\n", i);

}

else{

printk(KERN_EMERG "cdev_add %d success!\n", i);

}

}

return ret;

}

static __exit void leds_exit(void)

{

int i;

for(i=0; i

cdev_del(&leds_cdev[i]);                            //注销设备

device_destroy(leds_class, MKDEV(leds_major, leds_minor+i));

}

class_destroy(leds_class);

kfree(leds_cdev);                                       //释放内存

unregister_chrdev_region(leds_dev, DEVICE_MINOR_NUM);   //注销设备号

printk(KERN_EMERG "leds chrdev exit \n");

}

module_init(leds_init);

module_exit(leds_exit);

MODULE_LICENSE("GPL");

编译

make

加载编译后的模块

insmod leds.ko

查看字符设备节点

ls /dev/l*

红框内为系统动态分配的设备号

结束语

以上则为嵌入式Linux设备节点生成的相关内容。

~谢谢支持~

如果文章对您有帮助,欢迎移至上方按钮打赏博主;

linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点相关推荐

  1. 查看linux驱动使用的头文件,[转载]linux下usb驱动头文件的usb.h(二)

    #define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_ZERO_PACKET 0x0040 /* 完成大块分解成小包输出 #define ...

  2. Linux驱动开发常用头文件

    头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下: 1.主目录 <a.out.h> ...

  3. glibc的头文件 linux_求助,编译glibc头文件时出错

    我用的软件包如下: binutils-2.16.tar.gz gcc-3.4.4.tar.bz2 glibc-2.3.5.tar.gz glibc-linuxthreads-2.3.5.tar.gz ...

  4. linux-gcc 编译时头文件和库文件搜索路径

    linux-gcc 编译时头文件和库文件搜索路径 一.头文件    gcc 在编译时寻找所需要的头文件 :    ※搜寻会从-I开始    ※然后找gcc的环境变量 C_INCLUDE_PATH,CP ...

  5. 如何下载linux内核头文件,在Linux系统上安装Linux内核头文件的教程

    当你在编译一个设备驱动模块时,你需要在系统中安装内核头文件.内核头文件同样在你编译与内核直接链接的用户空间程序时需要.当你在这些情况下安装内核头文件时,你必须确保内核头文件精确地与你当前内核版本匹配( ...

  6. Linux socket 网络编程 常用头文件

    一 三种类型的套接字: 1.流式套接字(SOCKET_STREAM) 提供面向连接的可靠的数据传输服务.数据被看作是字节流,无长度限制.例如FTP协议就采用这种. 2.数据报式套接字(SOCKET_D ...

  7. gcc编译自定义头文件

    2019独角兽企业重金招聘Python工程师标准>>> C中外部函数实例 内部函数:static声明,只对本文件域生效,外部不可引用 外部函数,使用extern声明,默认可以去掉,在 ...

  8. linux快速查找系统库函数头文件:man命令

    Linux提供了丰富的帮助手册,使用Linux man命令来查看一些不熟悉的命令的使用方法,还可以用来查询系统库文件中的一些函数定义和使用方法. 例如:linux中read需要什么头文件 输入: ma ...

  9. 嵌入式linux零基础培训,零基础精通嵌入式linux系统有那么容易吗

    嵌入式linux系统让你从入门到精通,新手必备学习技术你要不要来试试.对于新手来说,嵌入式linux系统应该如何更快更好的学习,首先可以告诉你:你要有C语言基础,看你走哪方面,看是底层系统还是应用层开 ...

最新文章

  1. 本地连接受限制或无法连接怎么办?
  2. Oracle什么时候需要Commit?
  3. 想知道Java程序如何才能提高性能吗?
  4. matlab中任意两边之和大于第三边,无法赋值,左侧大小1*1,右侧1*3,代码报错,但是看不出来两边大小不相等啊...
  5. 聊聊Synchronized
  6. C ++ STL中的set :: upper_bound()函数
  7. 保姆级!!前端必会Taro入门级教学!!
  8. url 加密解密, email 加密
  9. 谷歌将反欺诈系统绕过纳入漏洞奖励计划
  10. R语言grid包just参数如何just图形位置
  11. 利用ENVI自带全球DEM数据计算区域平距高程
  12. 高等数理统计(part4)--充分统计量
  13. 【STM8】STM8在STVD平台生成HEX和S19文件的方法
  14. 手机端解决2倍图3倍图自适应
  15. UVA 10041-Vito's Family
  16. 九龙证券|这一刻,资本市场进入全新时代!
  17. odoo11在win10环境搭建
  18. 图解 Paxos 一致性协议
  19. 知识图谱关键技术总览
  20. ArcGIS api for javascript——查找任务-在地图上查找要素

热门文章

  1. Markdown公式输入(very nice!!!)
  2. linux python3.8源码安装_linux 下从源码安装 Python——小白踩坑记
  3. 安卓车机root改流浪地球_教你王者荣耀改战区
  4. excel撤销工作表保护默认密码_我的表格我做主:Excel工作表不想被别人改动,设置一个密码保护...
  5. 启明云端分享|SSD20X_烧录mac地址文档参考
  6. lg g7 android9,随着Android 11的临近 LG G7 ThinQ在其最后一家美国运营商处获得了Android 9更新...
  7. 编程三角形面积公式_三角形面积公式110式(英文版)
  8. Android 抓包工具r0capture使用
  9. windows下挂载ext4_WSL2 支持挂载物理磁盘,Windows 可直接访问 ext4
  10. mysql中的逻辑类型如何定义_MYSQL存储过程即常用逻辑知识点总结