当前位置: 首页 > news >正文

Linux视频学习笔记

 

1.Image zImage uImage 

tip:内核源码需要先进行比编译后才能对内核模块进行编译;(只有编译内核后才会生成autoconf.h文件该文件是给到驱动访问的一些宏定义)

2.宏内核与微内核

3.makefile

tip:obj-m 的一个全局变量(是针对整个内核来说不只是当前的文件中),且可以理解为这是一个全局数组里面是包含很多数据,所以用一般用"+="(添加一个新元素)

4.内核模块传参

权限字段解析 (-rw-r--r--)

在 ls -l 的输出中,权限字段通常由 10 个字符组成,例如:

text

-rw-r--r--

分解如下:

  1. 第1个字符:文件类型

    • -:普通文件

    • d:目录

    • l:符号链接

    • 其他字符可能表示设备文件、套接字等。

  2. 后续9个字符:权限分组(每3个字符一组)

    • 前3位:所有者(user)权限

    • 中间3位:所属组(group)权限

    • 最后3位:其他用户(others)权限

每组权限的字符含义:

  • r:读权限(read)

  • w:写权限(write)

  • x:执行权限(execute)

  • -:无对应权限


示例解释

在你的输出中:

text

-rw-r--r--

表示:

  • 这是一个普通文件-)。

  • 所有者读写权限(rw-)。

  • 所属组和其他用户只有权限(r--)。




1. 权限的两种表示形式

  • 符号模式-rw-r--r--

    • 分解:

      • -:普通文件

      • rw-:所有者(user)有读(r)、写(w)权限

      • r--:所属组(group)和其他用户(others)只有读(r)权限

  • 数字模式0644

    • 分解:

      • 0:特殊权限位(无特殊权限时通常省略,写作 644

      • 6:所有者权限(rw-,即 4+2+0=6

      • 4:所属组权限(r--,即 4+0+0=4

      • 4:其他用户权限(r--,即 4+0+0=4


2. 开头的 0 的含义

数字模式开头的 0 表示特殊权限位(占3位),具体包括:

  • SUID(Set User ID)4

    • 文件执行时以所有者身份运行(如 /usr/bin/passwd)。

  • SGID(Set Group ID)2

    • 文件执行时以所属组身份运行,或目录中新建文件继承父目录组。

  • Sticky Bit1

    • 目录中的文件仅所有者可删除(如 /tmp)。

若特殊权限未设置(如普通文件),则用 0 表示。

  • 例如:

    • 4755:SUID 设置为 4,权限为 755

    • 1777:Sticky Bit 设置为 1,权限为 777


3. 为什么 0644 和 644 通常等价?

  • 当特殊权限位为 0 时,可以省略(如 chmod 644 file)。

  • 显式写成 0644 是为了强调无特殊权限(常见于脚本或编程中)。


4. 示例对比

符号模式数字模式解释
-rw-r--r--0644普通文件,所有者可读写,其他只读
-rwxr-xr-x0755普通文件,所有者可读写执行
drwxrwxrwt1777目录,设置 Sticky Bit

5. 总结

  • 0644 中的 0 表示无特殊权限(SUID/SGID/Sticky Bit 均未设置)。

  • 日常使用中,644 和 0644 完全等效,但显式写 0 更规范(尤其在编程时)。

5.全局符号表

6.查看ko的依赖

方法适用场景是否需要 root
modinfo <模块> | grep depends查看未加载模块的声明依赖
lsmod | grep <模块>查看已加载模块的实际依赖
modprobe --show-depends <模块>模拟加载过程显示依赖
objdump -p <模块>.ko分析二进制依赖(高级调试)

7.多个源文件组合成内核模块

8.字符设备

8.1设备号注销申请
静态注册

设备号:一个32位的数字,31~20:主设备号 19~0:次设备号

设备号文件相关规定见(kernel/Documention/devices.txt)不能随便申请一个设备号

动态注册

8.2字符设备结构体_cdev

添加字符设备
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>static dev_t led_num;
static struct cdev led_cdev;int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}static struct file_operations myled_fpos =
{.owner  =  THIS_MODULE,.open 	=  myled_open,.relaese =  myled_relaese,
};static int __init myled_init(void)
{int rt;/*1.动态申请设备号*/rt = alloc_chrdev_region(&led_num,0,1,"my_led");if(rt < 0){printk(KERN_ERR"register_chrdev_region fail\n");goto err_register_chrdev_region;}/*2.打印主次设备号*/printk(KERN_INFO"majro=%d minor=%d\n",MAJOR(led_num),NINOR(led_num));/*3.初始化字符设备的结构体,将led_cdev中的ops成员指向myled_fpos*/cdev_init(&led_cdev,&myled_fpos);/*4.将字符设备添加到内核*/rt = cdev_add(&led_cdev,led_num,1);if(rt < 0){printk(KERN_ERR"cdev_add fail\n");goto err_cdev_add;}printk(KERN_INFO"myled_init\n"); return 0;err_cdev_add:/*注销设备号*/unregister_chrdev_region(led_num,1);err_register_chrdev_region:return rt;
}static void __exit myled_exit(void)
{/*内核中删除字符设备*/cdev_del(&led_cdev);/*注销设备号*/unregister_chrdev_region(led_num,1);printk(KERN_INFO"myled_exit\n"); }module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
获取主次设备号手动创建手动创建设备文件

编写应用程序测试

8.3自动创建设备文件

class&device

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>static dev_t led_num;
static struct cdev led_cdev;static struct class 	*led_class;
static struct device 	*led_device;static char msg[100] = {0};int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}static ssize_t myled_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {int ret = copy_to_user(buf, msg, len);if (ret) {printk(KERN_ALERT "Failed to send data to user\n");return -EFAULT;}printk(KERN_INFO "Sent %zu bytes to user\n", len);return len;
}static ssize_t myled_write(struct file *file, const char __user *buf, size_t len, loff_t *offset) {if (len > sizeof(msg)) {printk(KERN_ALERT "Data too large\n");return -EINVAL;}if (copy_from_user(msg, buf, len)) {  /*返回写入失败的个数*/printk(KERN_ALERT "Failed to receive data from user\n");return -EFAULT;}printk(KERN_INFO "Received %zu bytes from user: %s\n", len, msg);return len;
}static struct file_operations myled_fpos =
{.owner  =  THIS_MODULE,.open 	=  myled_open,.relaese =  myled_relaese,.write	= 	myled_write,.read 	=	myled_read, 
};static int __init myled_init(void)
{int rt;/*1.动态申请设备号*/rt = alloc_chrdev_region(&led_num,0,1,"my_led");if(rt < 0){printk(KERN_ERR"register_chrdev_region fail\n");goto err_register_chrdev_region;}/*2.打印主次设备号*/printk(KERN_INFO"majro=%d minor=%d\n",MAJOR(led_num),NINOR(led_num));/*3.初始化字符设备的结构体,将led_cdev中的ops成员指向myled_fpos*/cdev_init(&led_cdev,&myled_fpos);/*4.将字符设备添加到内核*/rt = cdev_add(&led_cdev,led_num,1);if(rt < 0){printk(KERN_ERR"cdev_add fail\n");goto err_cdev_add;}/*5.创建设备类*/led_class = class_creat(THIS_MODULE,"myled");if(IS_ERR(led_class)){printk(KERN_ERR"class_creat fail\n");goto err_class_creat;}/*6.添加设备信息*/ /*(class:创建device是属于哪个类 parent:默认为NULL devt:设备号,设备号必须正确,因为这个函数会在/dev目录下帮我们自动创建文件设备 drvdata:私有数据 fmt:设备名字创建成功可在/dev目录看见该名字  )*/led_device = device_create(led_class,NULL,led_num,NULL,"myled");if(IS_ERR(led_device)){printk(KERN_ERR"device_create fail\n");goto err_device_create;}printk(KERN_INFO"myled_init\n"); return 0;err_device_create:/*销毁设备类*/class_destroy(led_class);err_class_creat:/*内核中删除字符设备*/cdev_del(&led_cdev);err_cdev_add:/*注销设备号*/unregister_chrdev_region(led_num,1);err_register_chrdev_region:return rt;
}static void __exit myled_exit(void)
{/*从类中销毁设备信息*/device_destroy(led_class,led_num);/*销毁设备类*/class_destroy(led_class);/*内核中删除字符设备*/cdev_del(&led_cdev);/*注销设备号*/unregister_chrdev_region(led_num,1);printk(KERN_INFO"myled_exit\n"); }module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");

9:GPIO标准接口函数

单个gpio

对于gpio的操作统一接口函数 实现跨平台,具体的几个接口函数使用见code

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>static dev_t led_num;
static struct cdev led_cdev;static struct class 	*led_class;
static struct device 	*led_device;static char msg[100] = {0};int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}static ssize_t myled_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {int ret = copy_to_user(buf, msg, len);if (ret) {printk(KERN_ALERT "Failed to send data to user\n");return -EFAULT;}printk(KERN_INFO "Sent %zu bytes to user\n", len);return len;
}static ssize_t myled_write(struct file *file, const char __user *buf, size_t len, loff_t *offset) {char kbuf[2]={0};if (len > sizeof(kbuf)) {printk(KERN_ALERT "Data too large\n");return -EINVAL;}if (copy_from_user(kbuf, buf, len)) {  /*返回写入失败的个数*/printk(KERN_ALERT "Failed to receive data from user\n");return -EFAULT;}printk(KERN_INFO "Received %zu bytes from user: %s\n", len, kbuf);//kbuf[0]:指定哪个led//kbuf[1]:1-亮 0-灭if(kbuf[0] == 7){gpio_set_value(PAD_GPIO_E+13,!kbuf[1]);}return len;
}static struct file_operations myled_fpos =
{.owner  =  THIS_MODULE,.open 	=  myled_open,.relaese =  myled_relaese,.write	= 	myled_write,.read 	=	myled_read, 
};static int __init myled_init(void)
{int rt;/*1.动态申请设备号*/rt = alloc_chrdev_region(&led_num,0,1,"my_led");if(rt < 0){printk(KERN_ERR"register_chrdev_region fail\n");goto err_register_chrdev_region;}/*2.打印主次设备号*/printk(KERN_INFO"majro=%d minor=%d\n",MAJOR(led_num),NINOR(led_num));/*3.初始化字符设备的结构体,将led_cdev中的ops成员指向myled_fpos*/cdev_init(&led_cdev,&myled_fpos);/*4.将字符设备添加到内核*/rt = cdev_add(&led_cdev,led_num,1);if(rt < 0){printk(KERN_ERR"cdev_add fail\n");goto err_cdev_add;}/*5.创建设备类*/led_class = class_creat(THIS_MODULE,"myled");if(IS_ERR(led_class)){printk(KERN_ERR"class_creat fail\n");goto err_class_creat;}/*6.添加设备信息*/ /*(class:创建device是属于哪个类 parent:默认为NULL devt:设备号,设备号必须正确,因为这个函数会在/dev目录下帮我们自动创建文件设备 drvdata:私有数据 fmt:设备名字创建成功可在/dev目录看见该名字  )*/led_device = device_create(led_class,NULL,led_num,NULL,"myled");if(IS_ERR(led_device)){printk(KERN_ERR"device_create fail\n");goto err_device_create;}/*7.添加一个GPIO*/rt = gpio_request(PAD_GPIO_E+13,"gpioe13");if(rt < 0){printk(KERN_ERR"gpio_request fail\n");goto err_gpio_request;}/*8.初始化gpio*/rt = gpio_direction_output(PAD_GPIO_E+13,1);if(rt < 0){printk(KERN_ERR"direction_output fail\n");goto err_direction_output;}printk(KERN_INFO"myled_init\n"); return 0;err_direction_output:/*释放gpio*/gpio_free(PAD_GPIO_E+13);err_gpio_request:/*从类中销毁设备信息*/device_destroy(led_class,led_num);err_device_create:/*销毁设备类*/class_destroy(led_class);err_class_creat:/*内核中删除字符设备*/cdev_del(&led_cdev);err_cdev_add:/*注销设备号*/unregister_chrdev_region(led_num,1);err_register_chrdev_region:return rt;
}static void __exit myled_exit(void)
{/*释放gpio*/gpio_free(PAD_GPIO_E+13);/*从类中销毁设备信息*/device_destroy(led_class,led_num);/*销毁设备类*/class_destroy(led_class);/*内核中删除字符设备*/cdev_del(&led_cdev);/*注销设备号*/unregister_chrdev_region(led_num,1);printk(KERN_INFO"myled_exit\n"); }module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
批量申请释放gpio

10:延时

睡眠延时

忙等待延时

11:miscdevices

作用

比如led、key、src_04等等这些字符设备统一归类为misc,用统一的主设备号,而不是每一个占用一个主设备号;

混杂设备主设备号为10;

Tip:输入子系统(如触摸屏)主设备号为13、fb0()主设备号29;

code

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/miscdevice.h>static char msg[100] = {0};int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}static ssize_t myled_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {int ret = copy_to_user(buf, msg, len);if (ret) {printk(KERN_ALERT "Failed to send data to user\n");return -EFAULT;}printk(KERN_INFO "Sent %zu bytes to user\n", len);return len;
}static ssize_t myled_write(struct file *file, const char __user *buf, size_t len, loff_t *offset) {char kbuf[2]={0};if (len > sizeof(kbuf)) {printk(KERN_ALERT "Data too large\n");return -EINVAL;}if (copy_from_user(kbuf, buf, len)) {  /*返回写入失败的个数*/printk(KERN_ALERT "Failed to receive data from user\n");return -EFAULT;}printk(KERN_INFO "Received %zu bytes from user: %s\n", len, kbuf);//kbuf[0]:指定哪个led//kbuf[1]:1-亮 0-灭if(kbuf[0] == 7){gpio_set_value(PAD_GPIO_E+13,!kbuf[1]);}return len;
}static struct file_operations myled_fpos =
{.owner  =  THIS_MODULE,.open 	=  myled_open,.relaese =  myled_relaese,.write	= 	myled_write,.read 	=	myled_read, 
};static struct miscdevice myled_misc = {.minor	=	MISC_DYNAMIC_MINO,.name	=	"my_led",.fops	=	&myled_fpos,};static int __init myled_init(void)
{int rt;/*miscdevice设备的注册*/rt = misc_register(&myled_misc);if(rt < 0){printk(KERN_ERR"misc_register fail\n");goto err_misc_register;}/*.添加一个GPIO*/rt = gpio_request(PAD_GPIO_E+13,"gpioe13");if(rt < 0){printk(KERN_ERR"gpio_request fail\n");goto err_gpio_request;}/*8.初始化gpio*/rt = gpio_direction_output(PAD_GPIO_E+13,1);if(rt < 0){printk(KERN_ERR"direction_output fail\n");goto err_direction_output;}printk(KERN_INFO"myled_init\n"); return 0;err_direction_output:/*释放gpio*/gpio_free(PAD_GPIO_E+13);err_gpio_request:/*注销miscdevice设备*/misc_deregister(&myled_misc);err_misc_register:return rt;
}static void __exit myled_exit(void)
{/*注销miscdevice设备*/misc_deregister(&myled_misc);/*释放gpio*/gpio_free(PAD_GPIO_E+13);printk(KERN_INFO"myled_exit\n"); }module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");

12:IOCTL

作用

IOCTL的cmd也是一个32位的数字:

关于'V'的解释

code
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/miscdevice.h>
#include <linux/ioctl.h>#define MY_IOCTL_MAGIC 'L'
#define CMD_LED_ON 	_IOW(MY_IOCTL_MAGIC, 0, unsigned long)
#define CMD_LED_OFF _IOW(MY_IOCTL_MAGIC, 1, unsigned long)
#define CMD_BUF_W 	_IOW(MY_IOCTL_MAGIC, 2, unsigned char[4])
#define CMD_BUF_R 	_IOR(MY_IOCTL_MAGIC, 3, unsigned char[4])int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}
long myled_unlocked_ioctl(struct file *, unsigned int cmd, unsigned long args)
{void __user *argp = (void __user *)args;unsigned char buf[4] = {'1','2','3','4'};if(_IOC_TYPE(cmd) != MY_IOCTL_MAGIC)return -ENOIOCTLCMD;switch(cmd){case CMD_LED_ON:{gpio_set_value(args,0);}break;case CMD_LED_OFF:{gpio_set_value(args,1);}break;case CMD_BUF_W:{copy_from_user(buf,argp,sizeof(buf)); //_IOC_SIZE(cmd) = sizeof(buf)}break;case CMD_BUF_R:{copy_to_user(argp,buf,sizeof(buf));}break;default:retun -ENOIOCTLCMD;}retun 0;
}static struct file_operations myled_fpos =
{.owner  	=  THIS_MODULE,.open 		=  myled_open,.relaese 	=  myled_relaese,.unlocked_ioctl		=  myled_unlocked_ioctl};static struct miscdevice myled_misc = {.minor	=	MISC_DYNAMIC_MINO,.name	=	"my_led",.fops	=	&myled_fpos,};static int __init myled_init(void)
{int rt;/*miscdevice设备的注册*/rt = misc_register(&myled_misc);if(rt < 0){printk(KERN_ERR"misc_register fail\n");goto err_misc_register;}/*.添加一个GPIO*/rt = gpio_request(PAD_GPIO_E+13,"gpioe13");if(rt < 0){printk(KERN_ERR"gpio_request fail\n");goto err_gpio_request;}/*8.初始化gpio*/rt = gpio_direction_output(PAD_GPIO_E+13,1);if(rt < 0){printk(KERN_ERR"direction_output fail\n");goto err_direction_output;}printk(KERN_INFO"myled_init\n"); return 0;err_direction_output:/*释放gpio*/gpio_free(PAD_GPIO_E+13);err_gpio_request:/*注销miscdevice设备*/misc_deregister(&myled_misc);err_misc_register:return rt;
}static void __exit myled_exit(void)
{/*注销miscdevice设备*/misc_deregister(&myled_misc);/*释放gpio*/gpio_free(PAD_GPIO_E+13);printk(KERN_INFO"myled_exit\n"); }module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>#define MY_IOCTL_MAGIC 'L'
#define CMD_LED_ON 	_IOW(MY_IOCTL_MAGIC, 0, unsigned long)
#define CMD_LED_OFF _IOW(MY_IOCTL_MAGIC, 1, unsigned long)
#define CMD_BUF_W 	_IOW(MY_IOCTL_MAGIC, 2, unsigned char[4])
#define CMD_BUF_R 	_IOR(MY_IOCTL_MAGIC, 3, unsigned char[4])int main(int agrc,char **argv)
{unsigned char buf[4] = {'1','2','3','4'};int fd_led = open("/dev/myled",O_RDWR);if(fd_led < 0){perror("open /dev/myled");retun -1;}ioctl(fd_led,CMD_BUF_W,buf);sleep(1);ioctl(fd_led,CMD_BUF_R,buf);printf("value:%d\n",value);while(1){ioctl(fd_led,CMD_LED_ON,1);sleep(1);ioctl(fd_led,CMD_LED_OFF,1);}
}

传递结构体

13:内核裁剪与配置

概念

将驱动编译进内核

Kconfig

uImage的固化

14:中断

ps:禁止硬中断嵌套(没有了smt32中的中断抢占优先级因为CPU速度足够快了,同时会屏蔽所有其他中断)

单个按键中断
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);static unsigned int data = 100;
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{// 打印中断发生的消息unsigned int b = *(unsigned int *)dev_id;printk(KERN_INFO "My IRQ: Interrupt occurred! (IRQ: %d)\n  data:%d", irq ,b);// 返回 IRQ_HANDLED 表示中断已被处理// 如果有多个设备共享同一 IRQ,且不确定是否是本设备触发,可返回 IRQ_NONEreturn IRQ_HANDLED;
}static int __init my_key_init(void)
{result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_SHARED,                // 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称&data                        // dev_id, 用于共享中断时区分设备,这里用 NULL);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:return result;}static void __exit my_key_exit(void)
{free_irq(MY_IRQ_NUMBER, &data);printk(KERN_INFO"my_key_exit\n"); }module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");

多个按键驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);struct key_data {int 			irq_n;irq_handler_t 	fun;unsigned long 	irq_f;char 			*name;void 			*dev;
};static irqreturn_t my_interrupt_handler(int irq, void *dev_id);tatic struct key_data keys[NUM_KEYS] = {{18,my_interrupt_handler,IRQF_TRIGGER_RISING,"Key18",NULL},{19,my_interrupt_handler,IRQF_TRIGGER_RISING,"Key19",NULL},{20,my_interrupt_handler,IRQF_TRIGGER_RISING,"Key20",NULL},
};static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{int i;for (i = 0; i < ARRAY_SIZE(keys); i++){if(irq == keys[i].irq_n){printk(KERN_INFO "My %s IRQ: Interrupt occurred! (IRQ: %d)\n",keys[i].name,irq);}}return IRQ_HANDLED;
}
static int __init my_key_init(void)
{int result;int i;for (i = 0; i < ARRAY_SIZE(keys); i++){result = request_irq(keys[i].irq_n,keys[i].fun,keys[i].irq_f,keys[i].name,keys[i].dev);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}}printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:while(i--)free_irq(keys[i].irq_n, keys[i].dev);return result;}static void __exit my_key_exit(void)
{int i = ARRAY_SIZE(keys);while(i--)free_irq(keys[i].irq_n, keys[i].dev);printk(KERN_INFO"my_key_exit\n"); }module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
中断服务程序与原子上下文

中断&等待队列头

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>
#include <linux/sched.h>
#include <mach/miscdevice.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);static wait_queue_head_t button_waitq;
static int key_press_flag = 0;
static unsigned int data = 100;static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{unsigned int b = *(unsigned int *)dev_id;wake_up_interruptible(&button_waitq); //唤醒等待队列头key_press_flag = 1;printk(KERN_INFO "My IRQ: Interrupt occurred! (IRQ: %d)\n  data:%d", irq ,b);return IRQ_HANDLED;
}int my_key_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"my_key_open\n"); return 0;
}
int my_key_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"my_key_relaese\n"); return 0;
}static ssize_t my_key_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {char key_val;wait_event_interruptible(&button_waitq,&key_press_flag);//让进程在 wait_queue_head_t 上睡眠。等待key_press_flag为真key_press_flag = 0;key_val |= gpio_get_value(PAD_GPIO_A+28) ? 0 : 1;copy_to_user(buf, &key_val, sizeof key_val);return len;
}static struct file_operations my_key_fpos =
{.owner  =  THIS_MODULE,.open 	=  my_key_open,.relaese =  my_key_relaese,.read 	=	my_key_read, 
};static struct miscdevice my_key_misc = {.minor	=	MISC_DYNAMIC_MINO,.name	=	"my_key",.fops	=	&my_key_fpos,};static int __init my_key_init(void)
{int result;/*miscdevice设备的注册*/result = misc_register(&my_key_misc);if(result < 0){printk(KERN_ERR"misc_register fail\n");goto err_misc_register;}result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_SHARED,                // 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称&data                        // dev_id, 用于共享中断时区分设备,这里用 NULL);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}//初始化等待队列头init_waitqueue_head(&button_waitq); // <<< 关键:初始化等待队列头 >>>printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:return result;
err_misc_register:return result;}static void __exit my_key_exit(void)
{free_irq(MY_IRQ_NUMBER, &data);/*注销miscdevice设备*/misc_deregister(&myled_misc);printk(KERN_INFO"my_key_exit\n"); }module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");/****************************************/
int main(int agrc,char **argv)
{int key_val;int fd_key = open("/dev/my_key",O_RDWR);if(fd_led < 0){perror("open /dev/my_key");retun -1;}while(1){read(fd_key,&key_val,sizeof key_val);}
}
中断下半部

软中断

中断处理->软中断->小任务   

进程的 只有工作队列中允许睡眠阻塞(eg:按键消抖)

软中断实际基本不使用

小任务

小任务(小任务运行在中断的上下文、会优先于运行在进程上下文的工作队列,小任务只能使用忙等待延时工作队列则都可以,所有中断处理完后还会来处理tasklet,中断下半部是能被其他人中断打断的)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);void mytasklet_handler(unsigned long)
{mdealy(20);printk(KERN_INFO "My IRQ: Interrupt occurred! (IRQ: %d)\n  data:%d", irq ,b);}DECLARE_TASKLET(mytasklet,mytasklet_handler,0);static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{// 打印中断发生的消息unsigned int b = *(unsigned int *)dev_id;//登记任务    tasklet_schedule(&mytasklet);return IRQ_HANDLED;
}static int __init my_key_init(void)
{result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_SHARED,                // 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称&data                        // dev_id, 用于共享中断时区分设备,这里用 NULL);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:return result;}static void __exit my_key_exit(void)
{free_irq(MY_IRQ_NUMBER, &data);printk(KERN_INFO"my_key_exit\n"); }module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
工作队列

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);static struct work_struct my_work;
void mywork_handler(struct work_struct *work)
{msleep(20);printk(KERN_INFO "My IRQ: Interrupt occurred! (IRQ: %d)\n  data:%d", irq ,b);}
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{schedule_work(&my_work);return IRQ_HANDLED;
}static int __init my_key_init(void)
{result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_SHARED,                // 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称&data                        // dev_id, 用于共享中断时区分设备,这里用 NULL);INIT_WORK(&my_work,mywork_handler);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:return result;}static void __exit my_key_exit(void)
{free_irq(MY_IRQ_NUMBER, &data);printk(KERN_INFO"my_key_exit\n"); cancel_work_sync(&my_work);}module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
延迟工作队列

可以实现不需要直接用msleep的延迟方式

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);static struct delay_work my_work;
void mywork_handler(struct work_struct *work)
{//msleep(20);printk(KERN_INFO "My IRQ: Interrupt occurred! (IRQ: %d)\n  data:%d", irq ,b);}
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{schedule_delayed_work(&my_work,	HZ*0.2);return IRQ_HANDLED;
}static int __init my_key_init(void)
{result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_SHARED,                // 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称&data                        // dev_id, 用于共享中断时区分设备,这里用 NULL);INIT_DELAYED_WORK(&my_work,mywork_handler);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}printk(KERN_INFO"my_key_init\n"); return 0;
err_request_irq:return result;}static void __exit my_key_exit(void)
{free_irq(MY_IRQ_NUMBER, &data);printk(KERN_INFO"my_key_exit\n"); cancel_delayed_work(&my_work);}module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
container_of

获得指定成员结构体的首地址这里获取到的是gi[0]的地址然后再强转为结构体类型就可以访问它内部的所有成员了

15:内核动态定时器

基础概念
内核时钟

HZ

jiffies

 

动态定时器

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timer.h>     // 包含 timer_list 和相关函数
#include <linux/jiffies.h>   // 包含 HZ 定义和 jiffies// 定义我们的定时器结构体
static struct timer_list my_timer;// 定时器回调函数
// 注意:参数是 timer_list 结构体的指针,使用 from_timer() 宏来获取数据
static void my_timer_callback(struct timer_list *t)
{// 使用 from_timer 宏从 timer_list 结构体中提取数据// 这里我们没有额外数据,所以只是演示用法// int *data = from_timer(data, t, fieldname); // 如果你有嵌入 timer_list 的结构体printk(KERN_INFO "My dynamic timer fired! Jiffies: %lu\n", jiffies);// 为了创建周期性定时器,我们需要在回调函数中重新启动定时器// 将定时器的到期时间设置为当前 jiffies + 2 秒(以 jiffies 为单位)mod_timer(&my_timer, jiffies + msecs_to_jiffies(2000));
}// 模块初始化函数
static int __init timer_init(void)
{printk(KERN_INFO "Dynamic timer example module loaded.\n");// 初始化定时器// timer_setup() 是现代内核推荐的方式// 第三个参数 '0' 表示没有特殊标志timer_setup(&my_timer, my_timer_callback, 0);// 设置定时器的首次到期时间// HZ 是每秒的 jiffies 数,2 * HZ 表示 2 秒后到期my_timer.expires = jiffies + msecs_to_jiffies(2000);// 将定时器添加到内核的定时器列表中add_timer(&my_timer);printk(KERN_INFO "Timer started, will fire every 2 seconds.\n");return 0;
}// 模块退出函数
static void __exit timer_exit(void)
{// 在删除模块前,必须确保定时器已停止// del_timer() 会停止定时器并等待任何正在运行的回调完成(如果在不同CPU上)// 如果定时器未激活,此调用是安全的if (del_timer(&my_timer))printk(KERN_INFO "Timer was active and has been deleted.\n");elseprintk(KERN_INFO "Timer was not active, deleted anyway.\n");printk(KERN_INFO "Dynamic timer example module unloaded.\n");
}// 注册模块的初始化和退出函数
module_init(timer_init);
module_exit(timer_exit);// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple example of using a dynamic kernel timer.");
MODULE_VERSION("0.1");

16:内存分配_kmalloc

概述

kmalloc/kfree

kmalloc最大可分配128KB大小内存

kmalloc 虚拟地址与物理地址偏移一般为 0x8 7个0

get_free_page

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gfp.h>     // 包含 GFP_KERNEL 等标志
#include <linux/mm.h>      // 包含 PAGE_SIZE 宏// 全局变量,存储分配的内存地址
static unsigned long page_addr = 0; // 用于存储 get_free_pages 返回的地址// 模块初始化函数
static int __init mem_init(void)
{printk(KERN_INFO "get_free_pages example module loaded.\n");// 使用 get_free_pages() 申请 1 页内存// 参数说明://   gfp_mask: GFP_KERNEL - 表示在进程上下文中进行睡眠等待内存//   order: 0 - 表示申请 2^0 = 1 页内存page_addr = __get_free_pages(GFP_KERNEL, 0);// 检查分配是否成功if (!page_addr) {printk(KERN_ERR "Failed to allocate a page of memory!\n");return -ENOMEM; // 内存不足}printk(KERN_INFO "Successfully allocated 1 page (order 0) at virtual address: %p, physical address: %pa\n", (void *)page_addr, &page_addr);// 演示:向分配的内存写入数据// 注意:page_addr 是内核虚拟地址,可以直接访问char *ptr = (char *)page_addr;snprintf(ptr, PAGE_SIZE, "Hello from kernel page! Allocated at %lu jiffies.\n", jiffies);// 确保数据写入内存// barrier(); // 通常不需要,但如果是多处理器同步可能需要内存屏障// 打印写入的内容printk(KERN_INFO "Data in page: %s", ptr);return 0; // 成功加载
}// 模块退出函数
static void __exit mem_exit(void)
{// 如果之前成功分配了内存,则释放它if (page_addr) {// 使用 free_pages() 释放内存// 参数:地址和 order (必须与分配时相同)free_pages(page_addr, 0);printk(KERN_INFO "Freed the allocated page of memory.\n");page_addr = 0; // 清空指针,避免悬空指针} else {printk(KERN_WARNING "No page was allocated to free.\n");}printk(KERN_INFO "get_free_pages example module unloaded.\n");
}// 注册模块的初始化和退出函数
module_init(mem_init);
module_exit(mem_exit);// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple example of using get_free_pages() to allocate kernel memory.");
MODULE_VERSION("0.1");

vmalloc

vmalloc不能用在中断它会睡眠、也不能用在DMA他分配的物理地址不连续,效率低因为需要不断创建页表维护映射、优势在于可以分配大块空间比如100MB大小

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>  // 包含 vmalloc 和 vfree 声明
#include <linux/string.h>   // 包含 memset, memcpy 等// 定义要分配的内存大小,例如 1MB
#define ALLOC_SIZE (1024 * 1024) // 1 MiB// 全局变量,存储分配的内存地址
static void *vmalloc_ptr = NULL;// 模块初始化函数
static int __init vmalloc_init(void)
{printk(KERN_INFO "vmalloc example module loaded.\n");// 使用 vmalloc() 分配指定大小的内存// 参数: size - 要分配的字节数vmalloc_ptr = vmalloc(ALLOC_SIZE);// 检查分配是否成功if (!vmalloc_ptr) {printk(KERN_ERR "vmalloc failed to allocate %d bytes!\n", ALLOC_SIZE);return -ENOMEM; // 内存不足}printk(KERN_INFO "Successfully allocated %d bytes using vmalloc() at virtual address: %p\n", ALLOC_SIZE, vmalloc_ptr);// 演示:向分配的内存写入数据// 注意:vmalloc_ptr 是内核虚拟地址,可以直接访问memset(vmalloc_ptr, 0, ALLOC_SIZE); // 清零内存snprintf(vmalloc_ptr, ALLOC_SIZE, "Hello from vmalloc! Allocated %d bytes at %lu jiffies.\n", ALLOC_SIZE, jiffies);// 打印写入的内容printk(KERN_INFO "Data in vmalloc'd memory: %s", (char *)vmalloc_ptr);return 0; // 成功加载
}// 模块退出函数
static void __exit vmalloc_exit(void)
{// 如果之前成功分配了内存,则释放它if (vmalloc_ptr) {// 使用 vfree() 释放由 vmalloc() 分配的内存vfree(vmalloc_ptr);printk(KERN_INFO "Freed the vmalloc'd memory block.\n");vmalloc_ptr = NULL; // 清空指针,避免悬空指针} else {printk(KERN_WARNING "No vmalloc'd memory was allocated to free.\n");}printk(KERN_INFO "vmalloc example module unloaded.\n");
}// 注册模块的初始化和退出函数
module_init(vmalloc_init);
module_exit(vmalloc_exit);// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple example of using vmalloc() to allocate kernel memory.");
MODULE_VERSION("0.1");
总结

17:输入子系统

 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrup.h>
#include <linux/gpio.h>
#include <linux/input.h>#define MY_IRQ_NUMBER gpio_to_irq(PAD_GPIO_A+28);static struct input_dev *button_dev;static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{/*向内核汇报按键状态*/input_report_key(button_dev, KEY_ENTER, !gpio_get_value(PAD_GPIO_A+28)); // 取反,因为低电平表示按下!gpio_get_value(PAD_GPIO_A+28) 会赋值给key_dev.value/*汇报结束*/input_sync(button_dev);return IRQ_HANDLED;
}static int __init my_key_init(void)
{int error;result = request_irq(MY_IRQ_NUMBER,              // 中断号my_interrupt_handler,       // 中断处理函数IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,// 标志位,IRQF_SHARED 表示允许共享中断// 其他常见标志: IRQF_TRIGGER_RISING (上升沿触发)"gpioa_28_irq",            // /proc/interrupts 中显示的设备名称NULL                        // dev_id, 用于共享中断时区分设备,这里用 NULL);if (result) {// request_irq 失败,返回非0值printk(KERN_ERR "My IRQ: Failed to register IRQ %d, error %d\n", MY_IRQ_NUMBER, result);goto err_request_irq;}// --- 1. 分配输入设备 内存空间 ---button_dev = input_allocate_device();if (!button_dev) {printk(KERN_ERR "Failed to allocate input device\n");error = -ENOMEM;goto free_irq;}// --- 2. 设置输入设备能力 (事件类型 编码支持哪些按键)---set_bit(EV_KEY, button_dev->evbit);       // 支持按键事件set_bit(KEY_ENTER, button_dev->keybit);    // 支持 ENTER 键set_bit(KEY_UP, button_dev->keybit);    set_bit(KEY_DOWN, button_dev->keybit);    set_bit(KEY_LEFT, button_dev->keybit);   button_dev->name = "mykey_input";      // 设备名称button_dev->phys = "gpio-keys/input0";    // 物理路径 (惯例)button_dev->id.bustype = 0x0000;        // 总线类型button_dev->id.vendor = 0x1688;button_dev->id.product = 0x6666;button_dev->id.version = 0x1001;// --- 3. 注册输入设备 ---error = input_register_device(button_dev);if (error) {printk(KERN_ERR "gpio_key_irq: Failed to register input device: %d\n", error);goto free_input_dev;}printk(KERN_INFO"my_key_init\n"); return 0;free_input_dev:input_free_device(button_dev);
free_irq:free_irq(MY_IRQ_NUMBER, NULL);
err_request_irq:return result;}static void __exit my_key_exit(void)
{input_unregister_device(button_dev);input_free_device(button_dev);free_irq(MY_IRQ_NUMBER,NULL);printk(KERN_INFO"my_key_exit\n"); }module_init(my_key_init);
module_exit(my_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");/**************************************************/int main(int argc,char **argv){struct input_event key_dev;int fd_key = open("/dev/input/event5",O_RDWE);if(fd_key < 0){return -1;}while(1){read(fd_key,&key_dev,sizeof(key_dev));if(key_dev.type == EV_KEY){if(key_dev.code == KEY_ENTER){printf("KEY_ENTER:%d",key_dev.value);}}}}

 整体逻辑:注册一个I2C设备=》probe函数中注册输入设备配置输入事件和类型=》注册工作队列=》注册中断=》触发中断h唤醒工作队列=》工作队列中获取坐标位置上报

18:platform设备驱动模型

led_driver
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/platform_device.h>
#include <mach/miscdevice.h>
#include <linux/ioctl.h>#define MY_IOCTL_MAGIC 'L'
#define CMD_LED_ON 	_IOW(MY_IOCTL_MAGIC, 0, unsigned long)
#define CMD_LED_OFF _IOW(MY_IOCTL_MAGIC, 1, unsigned long)static unsigned int gpio_num;
static const char *gpio_name;int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}
long myled_unlocked_ioctl(struct file *, unsigned int cmd, unsigned long args)
{if(_IOC_TYPE(cmd) != MY_IOCTL_MAGIC)return -ENOIOCTLCMD;switch(cmd){case CMD_LED_ON:{gpio_set_value(gpio_num,0);}break;case CMD_LED_OFF:{gpio_set_value(gpio_num,1);}break;default:retun -ENOIOCTLCMD;}retun 0;
}static struct file_operations myled_fpos =
{.owner  	=  THIS_MODULE,.open 		=  myled_open,.relaese 	=  myled_relaese,.unlocked_ioctl		=  myled_unlocked_ioctl};static struct miscdevice myled_misc = {.minor	=	MISC_DYNAMIC_MINO,.name	=	"my_led",.fops	=	&myled_fpos,};static int __devinit myled_probe(struct platform_device * pdev)
{int rt;struct resource *res;/*miscdevice设备的注册*/rt = misc_register(&myled_misc);if(rt < 0){printk(KERN_ERR"misc_register fail\n");goto err_misc_register;}/*获取平台设备传递的资源*/res = platform_get_resource(pdev,IORESOURCE_IO,0);gpio_num = res->start;gpio_name = res->name;/*.添加一个GPIO*/rt = gpio_request(gpio_num,gpio_name);if(rt < 0){printk(KERN_ERR"gpio_request fail\n");goto err_gpio_request;}/*8.初始化gpio*/rt = gpio_direction_output(gpio_num,1);if(rt < 0){printk(KERN_ERR"direction_output fail\n");goto err_direction_output;}printk(KERN_INFO"myled_init\n"); return 0;err_direction_output:/*释放gpio*/gpio_free(gpio_num);
err_gpio_request:/*注销miscdevice设备*/misc_deregister(&myled_misc);
err_misc_register:return rt;
}static int __devexit myled_remove(struct platform_device * pdev)
{/*注销miscdevice设备*/misc_deregister(&myled_misc);/*释放gpio*/gpio_free(gpio_num);printk(KERN_INFO"myled_exit\n");return 0;
}static struct platform_driver led_plat_driver = {.probe 	=	myled_probe,.remove	=	myled_remove,.driver =	{.name = 	"myled",.owner	=	THIS_MODULE,},
}static int __init myled_init(void)
{return platform_driver_register(&led_plat_driver);
}static void __exit myled_exit(void)
{return platform_driver_unregister(&led_plat_driver);
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
led_device
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/platform_device.h>void myled_release (struct device *dev)
{return;
}static struct resource led_resource[] = {[0] = {.start	= 	PAD_GPIO_E+13,.end	=	PAD_GPIO_E+13,.flags	=	IORESOURCE_IO,.name	=	"gpioe_13",},
};static struct platform_device led_plat_device = {.name			=	"myled",.id				=	-1,.num_resources	=	ARRAY_SIZE(led_resource),.resource		=	led_resource,.device			=	{.platform_data 	= 	NULL,.release		=	myled_release,}
}static int __init myled_init(void)
{int rt;rt = platform_device_register(&led_plat_device);if( rt < 0){goto err_platform_device_register;}return 0;printk(KERN_INFO"my_key_init\n"); 
err_platform_device_register:return rt;
}static void __exit myled_exit(void)
{platform_device_unregister(&led_plat_device);printk(KERN_INFO"myled_exit\n"); 
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
led_driver_platform_data
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/platform_device.h>
#include <mach/miscdevice.h>
#include <linux/ioctl.h>#define MY_IOCTL_MAGIC 'L'
#define CMD_LED_ON 	_IOW(MY_IOCTL_MAGIC, 0, unsigned long)
#define CMD_LED_OFF _IOW(MY_IOCTL_MAGIC, 1, unsigned long)#define CMD_LED_ALL_ON 	_IO(MY_IOCTL_MAGIC, 0)
#define CMD_LED_ALL_OFF _IO(MY_IOCTL_MAGIC, 1)struct gpio_t
{
#define GPIO_MAX_NUMBER 32struct gpio io[GPIO_MAX_NUMBER];unsigned int num;
};static struct gpio_t *leds_gpios_p = NULL;int myled_open(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_open\n"); return 0;
}
int myled_relaese(struct inode *inode,struct file *file)
{printk(KERN_INFO"myled_relaese\n"); return 0;
}
long myled_unlocked_ioctl(struct file *, unsigned int cmd, unsigned long args)
{int n = args-7;if(_IOC_TYPE(cmd) != MY_IOCTL_MAGIC)return -ENOIOCTLCMD;switch(cmd){case CMD_LED_ON:{gpio_set_value(leds_gpios_p->io[n].gpio,0);}break;case CMD_LED_OFF:{gpio_set_value(leds_gpios_p->io[n].gpio,1);}break;default:retun -ENOIOCTLCMD;}retun 0;
}static struct file_operations myled_fpos =
{.owner  	=  THIS_MODULE,.open 		=  myled_open,.relaese 	=  myled_relaese,.unlocked_ioctl		=  myled_unlocked_ioctl};static struct miscdevice myled_misc = {.minor	=	MISC_DYNAMIC_MINO,.name	=	"my_led",.fops	=	&myled_fpos,};static int __devinit myled_probe(struct platform_device * pdev)
{int rt;struct resource *res;/*miscdevice设备的注册*/rt = misc_register(&myled_misc);if(rt < 0){printk(KERN_ERR"misc_register fail\n");goto err_misc_register;}/*获取平台设备传递的资源*/leds_gpios_p = (struct gpio_t *)pdev->dev.platform_data;rt = gpio_request_array(leds_gpios_p->io,leds_gpios_p->num);if(rt < 0){printk(KERN_ERR"gpio_request fail\n");goto err_gpio_request_array;}printk(KERN_INFO"myled_init\n"); return 0;err_gpio_request_array:/*注销miscdevice设备*/misc_deregister(&myled_misc);
err_misc_register:return rt;
}static int __devexit myled_remove(struct platform_device * pdev)
{/*注销miscdevice设备*/misc_deregister(&myled_misc);/*释放gpio*/gpio_free_array(leds_gpios_p->io,leds_gpios_p->num);printk(KERN_INFO"myled_exit\n");return 0;
}static struct platform_driver led_plat_driver = {.probe 	=	myled_probe,.remove	=	myled_remove,.driver =	{.name = 	"myled",.owner	=	THIS_MODULE,},
}static int __init myled_init(void)
{return platform_driver_register(&led_plat_driver);
}static void __exit myled_exit(void)
{return platform_driver_unregister(&led_plat_driver);
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");
led_device_platform_data
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/platform_device.h>struct gpio_t
{
#define GPIO_MAX_NUMBER 32struct gpio io[GPIO_MAX_NUMBER];unsigned int num;
};void myled_release (struct device *dev)
{return;
}static struct gpio_t leds_gpios=
{.io[0]={PAD_GPIO_E+13,GPIO_OUT_INIT_HIGH,"LED_1"},.io[1]={PAD_GPIO_E+14,GPIO_OUT_INIT_HIGH,"LED_2"},.io[2]={PAD_GPIO_E+15,GPIO_OUT_INIT_HIGH,"LED_3"},.io[3]={PAD_GPIO_E+16,GPIO_OUT_INIT_HIGH,"LED_4"},.num = 4,
}static struct platform_device led_plat_device = {.name			=	"myled",.id				=	-1,.device			=	{.platform_data 	= 	&leds_gpios,.release		=	myled_release,}
}static int __init myled_init(void)
{int rt;rt = platform_device_register(&led_plat_device);if( rt < 0){goto err_platform_device_register;}return 0;printk(KERN_INFO"my_key_init\n"); 
err_platform_device_register:return rt;
}static void __exit myled_exit(void)
{platform_device_unregister(&led_plat_device);printk(KERN_INFO"myled_exit\n"); 
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux char driver example");

19:电源管理

misc:

1)编辑器试图

2)modeinfo

3)printk

4)管道

http://www.dtcms.com/a/394168.html

相关文章:

  • 2014/12 JLPT听力原文 问题四
  • Elasticsearch面试精讲 Day 21:地理位置搜索与空间查询
  • 华为数字化实战指南:从顶层设计到行业落地的系统方法论
  • 外部 Tomcat 部署详细
  • 【回文数猜想】2022-11-9
  • 216. 组合总和 III
  • Bugku-请攻击这个压缩包
  • 2. NumPy数组属性详解:形状、维度与数据类型
  • 【css特效】:实现背景色跟随图片相近色处理
  • vuex原理
  • 内存泄露怎么排查?
  • nginx配置防盗链入门
  • Kafka 多机房、跨集群复制、多租户、硬件与操作系统、全栈监控
  • leetcode136.只出现一次的数字
  • 力扣hot100:环形链表II(哈希算法与快慢指针法思路讲解)
  • 【算法】【Leetcode】【数学】统计1的个数 数位统计法
  • Kafka面试精讲 Day 21:Kafka Connect数据集成
  • MySQL 主从复制完整配置指南
  • 力扣每日一刷Day 23
  • LeetCode 53. 最大子数组和(四种解题思路)包含扩展返回最大和的数组
  • RTX 4090助力深度学习:从PyTorch到生产环境的完整实践指南——高效模型训练与优化策略
  • 23种设计模式之【桥接模式】-核心原理与 Java实践
  • LabVIEW手部运动机能实验
  • 669. 修剪二叉搜索树
  • 大QMT自动可转债申购
  • PolarCTF PWN 网络安全2023秋季个人挑战赛刷题
  • MySQL-day4_02(事务)
  • JUC(8)线程安全集合类
  • springboot中@EnableAsync有什么作用
  • Spark专题-第二部分:Spark SQL 入门(6)-算子介绍-Generate