1、申请设备号

int register_chrdev_region(dev_t from, unsigned count, const char *name)

指定从设备号from开始,申请count个设备号,在/proc/devices中的名字为name。返回值:成功返回0,失败返回错误码。

2、动态的申请设备号

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

动态申请从次设备号baseminor开始的count个设备号,在/proc/devices中的名字为name,并通过dev指针把分配到的设备号返回给调用函数者。返回值:成功返回0,失败返回错误码。

3、卸载申请的设备号

void unregister_chrdev_region(dev_t from, unsigned count)

使用:释放从from开始count个设备号。

4、注册字符设备

1)分配cdev;

2)初始化cdev;

3)添加cdev;

  4.1  分配cdev

struct cdev* test_cdev;
test_cdev = cdev_alloc();

  4.2 初始化cdev

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

cdev:之前我定义的cdev结构体;fops:设备对应的文件操作结构体。返回值:(函数有可能失败,查看返回值是必须的);成功返回0,示范返回对应的错误码;

  4.3 添加cdev

int cdev_add(struct cdev *cdev, dev_t dev, unsigned count)

cdev:指定要被添加的cdev结构体;dev:对应的设备号;count:从设备号dev开始添加count个设备.返回值:成功返回0,失败返回对应的错误码。

  4.3 卸载cdev

void cdev_del(struct cdev *p)

5、error

Linux的出错处理在设计的时候是考虑了跟平台架构相关。

6、驱动、设备文件、设备号、应用程序之间的关系

设备号的申请通过register_chrdev_region()调用这个函数进行申请设备号,之后调用cdev_init()将设备注册进内核,要将设备号与驱动关联起来调用cdev_add(),要给应用程序提供一个接口去访问内核的驱动,需要创建一个文本文件可以手动的创建

mknod /dev/test c 250 0    应用程序通过open这个路径"/dev/test"就可以访问内核。

7、struct file

在内核中,file结构体是用来维护打开的文件的。每打开一次文件,内核空间里就会多增加一个file来维护,当文件关闭是释放。

loff_t f_pos;这是用来记录文件的偏移量。

8、等待队列

 定义
wait_queue_head_t test_queue;
初始化
init_waitqueue_head(&test_queue); 如果condition为真,将进程加入等待队列并等待唤醒
wait_event_interruptible(wq, condition)函数调用成功会进入可中断休眠
wait_event(queue, condition)函数成功会进入不可中断休眠,不推荐 void wake_up(wait_queue_head_t *queue); //唤醒等待队列中所有休眠的进程
void wake_up_interruptible(wait_queue_head_t *queue); //唤醒等待队列中所有可中断睡眠的进

9、自旋锁、

使用静态定义并初始化:spinlock_t lock = SPIN_LOCK_UNLOCKED;

使用动态定义并初始化:spinlock_t lock; spin_lock_init(&lock);

在进入临界区前,必须先获得锁,使用函数:spin_lock(&lock);

在退出临界区后,需要释放锁,使用函数:spin_unlock(&lock);

10、信号量

定义并初始化一个叫name的计数信号量,允许conut个进程同时持有锁:static DECLARE_SEMAPHORE_GENERIC(name, count)

定义并初始化一个叫name的互斥信号量:static DECLARE_MUTEX(name)\

第二种是动态定义并初始化:

struct semaphore sem;

sema_init(&sem, count);

/*初始化一个互斥信号量*/

#define init_MUTEX(sem) sema_init(sem, 1)

/*初始化一个互斥信号量并加锁*/

#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)

获取信号量:

1/*获取信号量sem,如果不能获取,切换状态至TASK_UNINTERRUPTIBLE*/

voud down(struct semaphore *sem)

上面的函数不太常用,因为它的睡眠不能被中断打断,一般使用下面的函数

2/*获取信号量sem,如果不能获取,切换状态至TASK_INTERRUPTIBLE,如果睡眠期间被中断打断,函数返回非0值*/

int down_interruputible(struct semaphore *sem)

3/*尝试获得信号量,如果获得信号量就返回零,不能获得也不睡眠,返回非零值*/

int down_try_lock(struct semaphore *sem)

11、使用kmalloc需要包含的头文件

 #include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/fs.h>

12、IO内存

物理地址映射虚拟地址的函数

void *ioremap(unsigned long phys_addr, unsigned long size);

撤销映射的函数

void ioumap(void *addr);

13、注册中断处理函数

int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
使用:
将中断号irq与中断处理函数handler对应
参数:
irq:指定要分配的中断号,中断号的定义在“include/mach/irqs.h”中。注意,不管是单独占有中断请求线的中断,还是共享中断请求线的每个中断,都有一个对应的中断号。,所以,调用该函数不需要考虑是哪种中断(是否共享寄存器),你想哪种中断响应,你就填对应的中断号。
handler:中断处理函数指针。
irqflags:中断处理标记,待会介绍:
devname:该字符串将显示在/proc/irq和/pro/interrupt中。
dev_id:ID 号,待会会介绍。
返回值:成功返回0,失败返回非0。

释放中断

void free_irq(unsigned int irq, void *dev_id)

中断处理函数

static irqreturn_t intr_handler(int irq, void *dev_id)

第一个参数irq,这是调用中断处理函数时传给它的中断号,第二个参数dev_id,这个参数与request_irq()的参数dev_id一致

cat /proc/interrupts 查看自己申请中断的名称

14、tasklet的使用

 定义一个结构体
struct tasklet_struct test_tasklet;
初始化结构体的tasklet的中断处理函数
void tasklet_fun(unsigned long data)
{
printk("---------%s---------\r\n",__func__);
printk("data[%ld]\r\n",data);
}
调用中断处理函数
tasklet_schedule(&test_tasklet);
初始化tasklet结构体将中断处理函数与之关联
tasklet_init(&test_tasklet,tasklet_fun,(unsigned long));
13 卸载tasklet_kill(&xiaobai_tasklet);

15、工作队列的使用

 定义与创建工作队列:
struct workqueue_struct *test_wq;
test_wq = create_workqueue("test workqueue");
定义工作与处理函数
struct work_struct test_work;
void test_func(struct work_struct *work)
{
printk("hello test work!\n");
}
将工作与处理函数想关联
INIT_WORK(&test_work,test_func);
将工作加入工作队列进行调度
queue_work(test_wq,&test_work);
销毁工作队列
flush_workqueue(test_wq);
destroy_workqueue(test_wq);

16、定时器的使用

 定义一个定时器
struct timer_list my_timer;
初始化定时器
init_timer(&my_timer);
设置超时时间和定时器的处理函数
my_timer.expires = jiffies + *HZ;
my_timer.function = timer_func,
my_timer.data = (unsigned long);
void timer_func(unsigned long data)
{
printk("-----------%s------------\r\n",__func__);
printk("time out![%ld][%s]\r\n",data,current->comm); //my_timer.expires = jiffies + 2*HZ;
//add_timer(&my_timer);
mod_timer(&my_timer,jiffies + *HZ);
} 激活定时器
add_timer(&my_timer);
在定时器的处理函数添加,每隔2秒就会执行一次定时器的处理函数
mod_timer(&my_timer,jiffies + *HZ);

最新文章

  1. Jaunt登陆索尼PSVR,为其提供大量VR视频
  2. Visual Studio 2015上安装Entity Framework Power Tools
  3. Uva 11988 Broken Keyboard
  4. eclipse中改变默认的workspace的方法及说明
  5. 不错的jQuery图表插件 .
  6. (转).net项目技术选型总结
  7. AngularJs练习Demo18 Resource
  8. hdu 1421 搬寝室(dp)
  9. 摘记:IIS长时间任务超时处理
  10. webstorm安装express报错
  11. Linux 虚拟机忘记root密码
  12. 使用IDEA运行Spark程序
  13. vue HTTP 请求(vue-resource)
  14. 小米5查看设备号信息及验证type-c数据线
  15. JavaScript: Constructor and Object Oriented Programming
  16. python day 07-数据类型补充,集合,深浅拷贝
  17. Bellman-Ford 最短路径算法
  18. Log4j在Java工程中使用方法
  19. AssemblyVersion,AssemblyFileVersion解释以及获取
  20. systemtap 探针定制

热门文章

  1. 新版本号的tlplayer for android ,TigerLeapMC for windows公布了
  2. PhoneNumber
  3. Android开发之WebView具体解释
  4. apue学习笔记(第九章 进程关系)
  5. 一个JavaScript Function Outliner插件 第三个版本 让你的JavaScript代码也支持折叠
  6. hive分区(partition)简介
  7. css:选择器
  8. 工作总结 a标签 &lt;a href=&quot;/meetingtheme&quot;&gt;Back to List&lt;/a&gt; 返回上一级 指向 控制器 默认Index @Html.ActionLink(&quot;Edit59&quot;, &quot;Edit&quot;, new { id = item.ID }) 默认当前控制器
  9. iOS中UDP的使用
  10. jquery中的clone()方法