Linux如何返回线程退出时的数据:https://www.cnblogs.com/Older-Driver-of-Newer/p/6739316.html
GPIO相关:
struct keyinfo{}; //用于存放按键信息
gpio_request(gpio,name); //gpio资源申请
gpio_request(unsigned gpio, const char * label)
s3c_gpio_cfgpin(gpio,S3C_GPIO_INPUT); //gpio口初始化
s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
gpio_free(); //gpio资源释放
gpio_get_value(gpio); //读取gpio的电平 0/1
外部中断:
gpio_to_irq(gpio); //申请中断,返回值为中断号irq
request_irq(irq, key_handler, IRQF_SHARED | IRQF_TRIGGER_RISING, name, &g_arrkey[i]); //根据irq配置中断
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev)
irq:中断号,作为中断服务函数的第二个传参
dev:当前中断的私有数据! <用来识别当前中断> <作为中断服务函数的第二个传参>
key_handler(int irq,char * dev); //服务中断函数 第二个传参由request_irq()的dev传过来的
typedef irqreturn_t (*irq_handler_t)(int, void *); (虽然可以自定义函数,但传参已规定)
(不同版本,函数返回类型不一样,值得注意下)
free_irq(irq,&g_arrkey[i]) //中断资源的释放
free_irq(unsigned int irq, void *dev_id);
等待队列:(wait_event()、wake_up()是一个函数族)
wait_event(wq,condition); //把进程置入等待队列 等待标志位 condition=1 (真)继续往下
wait_event(wait_queue_head_t wq, bool condition); // 注意condition声明类型为bool
wake_up(&wq); //将对应的进程切回就绪态(唤醒)
wake_up(wait_queue_head_t * wq);
DECLARE_WAIT_QUEUE_HEAD(wq); // 等待队列头结构体静态定义初始化(调用内核函数)(程序前声明处定义)
等待队列详细分析:https://blog.csdn.net/qq_35769746/article/details/81006405
定时器中断:
setup_timer(&timer, fn, data); //初始化定时器
setup_timer(timer, fn, data); timer:定时器结构体 fn:->function 定时器中断函数 data:fn的传参
mod_timer(&timer, jiffies + HZ / 200); //设置时间戳,启动定时器(jiffies为当前系统时间戳,HZ系统默认为1s)
int mod_timer(struct timer_list *timer, unsigned long expires); expires:时间戳
定时器结构体: struct timer_list { //结构体只需要声明
struct list_head entry;
unsigned long expires; //定时的时间戳
struct tvec_base *base; //定时器时钟来源
void (*function)(unsigned long); //定时器中断服务函数
unsigned long data; //定时器中断服务函数传参
int slack; //时间校验
//默认值:-1
}
定时器结构体使用方法:static struct timer_list g_ttimer;
poll机制(同步):
驱动层:
DECLARE_WAIT_QUEUE_HEAD(wq); //声明并初始化等待列表头
unsigned int (*poll) (struct file *, struct poll_table_struct *); // file_operations结构体中.poll 的函数原型
poll_wait(filp,&wq,table) // file和table 有.poll传过来的 wq是开头声明的
poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
应用层:
poll(struct pollfd *fds, nfds_t nfds, int timeout); //timeout:(ms) 负数表示无限阻塞
struct pollfd {
int fd; /* 文件描述符 */
short events; /*指定的事件类型 */ 输入:POLLIN 输出:POLLOUT 异常:POLLERR
short revents; /* 返回的事件类型 */
当有事件触发,drv_poll将会把返回值写入到该变量中!
通过判断revents的值,就可以知道是否是该事件触发的poll机制。
};
struct pollfd keyinfo[] = {
{fd1, POLLIN, 0},
{fd2, POLLIN, 0},
{fd3, POLLIN, 0},
{fd4, POLLIN, 0},
}
fasync机制(异步):
驱动层:
fasync(int fd, struct file* filp, int on) //驱动获取进程的PID
int (*fasync) (int, struct file *, int);
fasync_helper(fd, filp, on, &g_ptfasync); //on为真--->应用层fd和filp赋值给fapp
fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp);
kill_fasync(&g_ptfasync, SIGIO, POLL_IN); // 驱动发送信号给进程,通过结构体实现信号传递
kill_fasync(struct fasync_struct **fp, int sig, int band);
应用层:
fcntl(); //对文件描述符进行操作的操作函数 使用了三次
fcntl(int fd, int cmd, ... /* arg */ ); //
signal(SIGIO, sig_handler); //接受SIGIO信号,执行中断函数sig_handler
中断底半部:
工作队列:
INIT_WORK(&g_twork, work_thread); //对工作队列结构体变量进行初始化赋值! (主要指定一个线程函数)
INIT_WORK(_work, _func) //_func为线程函数,执行想要的程序工作
struct work_struct g_twork //声明工作队列
flush_work_sync(&g_twork); //同步清除内核中的work工作队列
内核微线程tasklet:
tasklet_init(&g_ttasklet, tasklet_thread, (unsigned long)"hello world"); //初始化,指定线程函数
tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
// t:要初始化的内核微线程结构体 func:线程函数 data:给线程函数的传参
struct tasklet_struct g_ttasklet // 申明内核微线程结构体
tasklet_schedule(&g_ttasklet); // 调度内核微线程结构体! (调用tasklet_thread线程函数,与主线程公用时间片)
tasklet_kill(&g_ttasklet); // 清除一个内核微线程
C语言chdir()函数:改变当前的工作目录
相关函数:getcwd, chroot
头文件:#include <unistd.h>
定义函数:int chdir(const char * path);
函数说明:chdir()用来将当前的工作目录改变成以参数path 所指的目录.
返回值执:行成功则返回0, 失败返回-1, errno 为错误代码.
范例
#include <unistd.h>
main()
{
chdir("/tmp");
printf("current working directory: %s\n", getcwd(NULL, NULL));
}
执行结果:
current working directory :/tmp