obj-y
obj-m += test.o
obj-y += test.o
obj-m表示把文件test.o作为"模块"进行编译,不会编译到内核,但是会生成一个独立的 "test.ko" 文件。obj-y表示把test.o文件编译进内核;
arm
swi
SWI指令来产生一个软中断,包含了一个24位的立即数,这个立即数指示了用户请求的特定的SWI功能,即这个立即数表示的是SWI指令所想要触发中断的中断号。
当SWI指令触发了一次异常后进入异常处理的程序时,异常程序必须要从SWI指令中提取出来中断号,
BIC r0,r0,#0xff000000
提取指令编码的后24位,放r0寄存器,函数返回。从而得到用户请求的特定的SWI功能。
用户态的应用程序要访问硬件,不能直接读写那些地址,调用库函数open/wirte/read,它通过汇编SWI #0
切内核态,cpu会走SWI的异常处理函数,swith(reg r0) case val1:func; case val2:func;... default:return;这样根据r0的值决定调用。找到驱动,调用driver的open/write/read函数。
debounce time
it's like the time after clicking that the mouse won't allow another click to register. a low denounce time can cause double clicks.
it affects click latency, so lower is typically better (as long as you aren't getting double click issues). just set it to 4ms, you shouldn't get double clicking at 4ms.
boot
编译地址和运行地址
钩子
注册
把 对象ops结构体 的地址传给 类register函数,在函数内 g_类名->p_ops[obj_ID]
get
做一个包含判空的函数,返回 g_类名->p_ops[obj_ID],每次调用这个函数注意在主调函数体内,声明一个 class结构体型的locol_ops, 判空,locol_ops->func.
char_dev.c by Linus Torvalds
static struct char_device_struct {
>-------struct char_device_struct *next;
>-------unsigned int major; //这是主设备号
>-------unsigned int baseminor; //次设备号
>-------int minorct;
>-------char name[64];
>-------struct cdev *cdev;>----->-------/* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
构建自己驱动的open之类的操作,用这个linux/fs.h下面的结构体file_operations,有int (*open) (struct inode *, struct file *);项。上面写的挂钩子,用这种挂法,
static const struct file_operations pd_cdev_fops = {
.owner = THIS_MODULE,
(...)
.open = pd_cdev_open,
.release = pd_cdev_release,
};
file_operations结构体原型在include/linux/fs.h。下面是usb注册的回调。
static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
.llseek = noop_llseek,
};
注册一下,第一个参数是主设备号,第二个参数是文件节点名,第三个就是上面构建的这个结构体的地址。
register_chrdev(USB_MAJOR, "usb", &usb_fops);
注册完了以后,把usb_fops放到chrdevs数组里面
找到空缺的主设备号
/dev$ cat /proc/devices
read&write
file_operations的成员,
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
原型是这样的,我注册时候驱动的操作可以表达为drv_read。
驱动是运行在内核地址空间的,应用程序是运行在用户地址空间的。我去年写了一个led.ko,当我在shell上面运行那个.sh,进一个CLI,我输入1令led点亮,这里会调用sys_write(),它把1写入buff,但是swi以后切内核态,gpio_led_dri不能直接读那个buff,
linux读写节点
生成device节点示例:Linux设备属性节点读写操作----cat 、echo_linux设备节点实现echo-CSDN博客
感谢熊工~
linux:/sys/xxx 读写节点使用方法_linux读取节点值-CSDN博客
kernel资料
shell
cflow des.c > out.log
ctags -R *
cscope -bqR
vim
:vsplit 左右分屏
:%s/from/to/g
bms
感谢~~
寄存器(low level)写值
例如:
-
*GPFSEL0 &= ~(0x6 << 12);//12-14 13、14置0
-
*GPFSEL0 |= (0x1 << 12);//12置1
例如:
val &= ~mask;//clear
val |= ((value << shift) & mask);//write val
例如:
#define BIT(x) (1 << (x)) //把 1 左移x位的2进制值。
kernel space地址映射
PAGE_OFFSET偏移量
对于内核空间而言,给定一个虚地址x,其物理地址为“x- PAGE_OFFSET”,给定一个物理地址x,其虚地址为“x+ PAGE_OFFSET”。
/proc/iomem
This file displays the physical (and/or bus) addresses currently being mapped by the kernel and/or various device drivers. However, the exact display format is very arch- and device-dependent. Note that the memory addresses here are not virtual, they are physical addresses.
ioremap
第1个参是寄存器的物理起始地址,第2个是所要映射长度。init_dri要用下。
I/O地址空间
可参考这篇,Linux中的地址空间以及I/O地址空间_證i0區-CSDN博客
函数指针
指针是一个变量,是用来指向内存地址的。一个程序运行时,所有和运行相关的物件都是需要加载到内存中,这就决定了程序运行时的任何物件都可以用指针来指向它。函数是存放在内存代码区域内的,它们同样有地址,因此同样可以用指针来存取函数,把这种指向函数入口地址的指针称为函数指针。
function pointer
pmic
A power management integrated circuit (PMIC) is a highly integrated device with many functional circuit blocks onboard. The high level of integration provides many benefits, including reduced printed circuit board (PCB) space, simpler design, faster time to market, and a reduced bill of material (BoM) cost.
#fastboot
进入fastboot模式的方式:插入usb,同时按住音量下键和电源键,等屏幕黑掉后松开电源键,继续按着音量下键等进入fastboot界面后松开。
#电池
电池的容量等于体积乘以能量密度。
#手机行业
BP(baseband):基带处理器。即手机中的modem,运行手机射频通讯控制软件,负责发送和接收数据。
CP:基带芯片加协处理器 or 多媒体加速器。可以处理虚拟现实,增强现实,图像处理,HIFI,HDR,传感器(sensor)等