all notes

持续更新中......


############################################################

linux kernel
1、
1)va


############################################################
擦除分区数据
1)mount,找出路径 :/dev/block/bootdevice/by-name # ls -l
2)可以看到个分区,没有的话,可以在pit.exe查找
3)dd if=/dev/zero of=/dev/block/xxx conv=notrunc


将/system分区、/cache分区和/data分区导入到sd卡
   dd if=/dev/block/mmcblk0p9 of=/storage/extSdCard/system.img bs=4096
   dd if=/dev/block/mmcblk0p8 of=/storage/extSdCard/cache.img bs=4096
   dd if=/dev/block/mmcblk0p12 of=/storage/extSdCard/data.img bs=4096
############################################################
RGB red green blue 16进制解析


#cc99bb //每两位16进制数代表一个颜色,前两位代表Red;中间Green;最后Blue
############################################################
Hash 算法,哈希算法




########################################################################################################################
java 两种for循环


1)对象的数组,
for(循环变量类型 循环变量名称 : 要被遍历的对象)  循环体
############################################################
android 应用获取root权限


############################################################
解压img文件
1)./simg2img source dest
  把dest用ext2explorer或者在服务器上Mount上去就行
############################################################
windows 批处理


1)创建文本文件,命名为xxx.bat
2)命令写到bat文件
3)运行bat文件
############################################################
kernel 动态库


lsmod 列出库
insmod rmmod //不够只能,识别不了库之前的依赖情况
modprobe //智能
depmod //功能:分析可加载模块的依赖性,生成modules.dep文件和映射文件。


########################################################################################################################
windows linux 怎么识别USB鼠标键盘的?通过VID PID吗?


.idVendor = (vend), \
.idProduct = (prod), \
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE



bInterfaceClass 


134#define USB_CLASS_PER_INTERFACE 0
135#define USB_CLASS_AUDIO 1
136#define USB_CLASS_COMM 2
137#define USB_CLASS_HID 3
138#define USB_CLASS_PHYSICAL 5
139#define USB_CLASS_STILL_IMAGE 6
140#define USB_CLASS_PRINTER 7
141#define USB_CLASS_MASS_STORAGE 8
142#define USB_CLASS_HUB 9
143#define USB_CLASS_CDC_DATA 0x0a
144#define USB_CLASS_CSCID 0x0b
145#define USB_CLASS_CONTENT_SEC 0x0d
146#define USB_CLASS_VIDEO 0x0e
147#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
148#define USB_CLASS_APP_SPEC 0xfe
149#define USB_CLASS_VENDOR_SPEC 0xff






2) int usb_match_one_id()
3) /* returns 0 if no match, 1 if match */
   int usb_match_device()




############################################################
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访
问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
 
mmap()系统调用形式如下:
void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset ) 
mmap的作用是映射文件描述符fd指定文件的 [off,off + len]区域至调用进程的[addr, addr + len]的内存区域, 如下图所示:
############################################################
Java 应用层 互斥 同步


互斥:
1)synchronized -- 类内所有synchronized 的方法不同同时被访问,非标记的方法可以被访问
############################################################
在注册表删除USB所连接手机信息的方法


一、 查询手机信息:
使用usbview.exe(百度/google可以下载)查询手机信息:


二、 打开注册表,进入
HKEY_LOCAL_MACHINESYSTEMCurrentControlSet
1) ControlUsbFlags 找到手机对应的
注册表信息,比如04e868680400,删除
2) EnumUSB 找到注册表信息,将所有Pid_6868开头的信息删除。
3)重启PC


再次连接手机则会提示进行驱动安装。


=====Win7没权限,获取方法
直接在命令行运行 psexec.exe -i -d -s regedit.exe ,就可以用 system 账户打开注册表。
psexec.exe 可以从 http://technet.microsoft.com/en-us/sysinternals/bb795533.aspx 下载
############################################################
canvas.drawBitmap 画全屏效果


Matrix matrix = new Matrix(); 
        matrix.postScale(canvas.getWidth()*1.01f/bmpBg.getWidth(), canvas.getHeight()*1.01f/bmpBg.getHeight(), bmpBg.getWidth() / 2, bmpBg.getHeight() / 2); 
        matrix.postTranslate( (canvas.getWidth()-bmpBg.getWidth()) / 2, (canvas.getHeight()-bmpBg.getHeight()) / 2); 
        canvas.drawBitmap(bmpBg, matrix, paint); 
-----------------------------
bitmap 画图步骤


1)Bitmap bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.pre7);
2)Bitmap foreImage = Bitmap.createScaledBitmap(bm1, width, height,false);//这一步是用来缩放图片的
3)canvas.drawBitmap(foreImage, 0, 0, null);


########################################################################################################################
class View{


public boolean onTouchEvent(MotionEvent event) {//触屏事件
点击 -- 0
保持 -- 2
放开 -- 1

滑动的时候就是保持+(getX,getY)
}
---------------------------------------
public void computeScroll() {//先运行computeScroll再运行onDraw




}
---------------------------------------



---------------------------------------



---------------------------------------



---------------------------------------


}
############################################################
android 内存使用情况查询


adb shell procrank


注:
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
############################################################
adb 过滤log


adb logcat -c && adb logcat -v time lmy:V *:S


adb logcat ActivityManager:I MyApp:D *:S 
/*上面表达式的最后的元素 *:S ,,是设置所有的标 签为”silent”,所有日志只显示有”View” and “MyApp”的,用 *:S 的另一个用处是 
能够确保日志输出的时候是按照过滤器的说明限制的,也让过滤器也作为一项输出到日志中. */


实时查看kernel log
adb shell
#cat /proc/kmsg


adb shell dmesg > ldmesg_kernel.log
adb shell cat /proc/kmsg >c:\001.c
############################################################
onDraw
01-13 13:35:31.510 W/System.err(14240): java.lang.Exception
01-13 13:35:31.510 W/System.err(14240):         at com.bn.lccx.GGViewCX.onDraw(GGViewCX.java:53)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15394)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15279)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15397)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15279)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15277)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15397)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15279)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.510 W/System.err(14240):         at android.view.View.draw(View.java:15277)
01-13 13:35:31.510 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.520 W/System.err(14240):         at android.view.View.draw(View.java:15277)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
01-13 13:35:31.520 W/System.err(14240):         at android.view.View.draw(View.java:15397)
01-13 13:35:31.520 W/System.err(14240):         at android.widget.FrameLayout.draw(FrameLayout.java:472)
01-13 13:35:31.520 W/System.err(14240):         at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2583)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2892)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl.draw(ViewRootImpl.java:2805)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2643)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2211)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
01-13 13:35:31.520 W/System.err(14240):         at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6630)
01-13 13:35:31.520 W/System.err(14240):         at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
01-13 13:35:31.520 W/System.err(14240):         at android.view.Choreographer.doCallbacks(Choreographer.java:603)
01-13 13:35:31.520 W/System.err(14240):         at android.view.Choreographer.doFrame(Choreographer.java:573)
01-13 13:35:31.520 W/System.err(14240):         at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
01-13 13:35:31.520 W/System.err(14240):         at android.os.Handler.handleCallback(Handler.java:733)
01-13 13:35:31.530 W/System.err(14240):         at android.os.Handler.dispatchMessage(Handler.java:95)
01-13 13:35:31.530 W/System.err(14240):         at android.os.Looper.loop(Looper.java:136)
01-13 13:35:31.530 W/System.err(14240):         at android.app.ActivityThread.main(ActivityThread.java:5479)
01-13 13:35:31.530 W/System.err(14240):         at java.lang.reflect.Method.invokeNative(Native Method)
01-13 13:35:31.530 W/System.err(14240):         at java.lang.reflect.Method.invoke(Method.java:515)
01-13 13:35:31.530 W/System.err(14240):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
01-13 13:35:31.530 W/System.err(14240):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
01-13 13:35:31.530 W/System.err(14240):         at dalvik.system.NativeStart.main(Native Method)
01-13 13:35:31.530 I/System.out(14240): *** onDrawCX
############################################################
onCreate启动过程,调用栈
01-02 08:52:31.319 W/System.err(28104):         at com.bn.lccx.LCCXActivity.onCreate(LCCXActivity.java:83)
01-02 08:52:31.319 W/System.err(28104):         at android.app.Activity.performCreate(Activity.java:5372)
01-02 08:52:31.319 W/System.err(28104):         at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2362)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3895)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread.access$800(ActivityThread.java:168)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)
01-02 08:52:31.319 W/System.err(28104):         at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 08:52:31.319 W/System.err(28104):         at android.os.Looper.loop(Looper.java:177)
01-02 08:52:31.319 W/System.err(28104):         at android.app.ActivityThread.main(ActivityThread.java:5493)
01-02 08:52:31.319 W/System.err(28104):         at java.lang.reflect.Method.invokeNative(Native Method)
01-02 08:52:31.319 W/System.err(28104):         at java.lang.reflect.Method.invoke(Method.java:525)
01-02 08:52:31.319 W/System.err(28104):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1225)
01-02 08:52:31.319 W/System.err(28104):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1041)
01-02 08:52:31.319 W/System.err(28104):         at dalvik.system.NativeStart.main(Native Method)
########################################################################################################################
RCU(Read-Copy Update),顾名思义就是读-拷贝修改,它是基于其原理命名的。
对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然后对副本进行修改,最后使用一个
回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的操作。
############################################################
getpid(void); 头文件 "unistd.h"
############################################################
fork execv


back = fork(); //有两个返回值因为fork运行在两个进程中,child进程中返回0,非0是parent产生的child pid
############################################################
查看 文件数量
find /path -type f |wc -l


find -name *.class -exec rm -rf {} \; //查找并删除,搜索并删除
############################################################
文件/进程,UID PID 是怎么设置分配的?




########################################################################################################################
获取uid方法,getuid


import android.content.pm.PackageManager;


String packageName = mContext.getPackageName();
PackageManager pm = mContext.getPackageManager();
ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
uid = info.uid;

Log.d(TAG, "check system UID : uid " + uid);
############################################################
文本处理




fread :以字节位计算长度,按照指定的长度和次数读取数据,遇到结尾或完成指定长度读取后停止.
fgets :整行读取,遇到回车换行或结尾停止.在文本方式时使用.


############################################################
UsbDeviceManager.java / 各service启动过程


SystemServer进程是zygote孵化出的第一个进程,该进程是从ZygoteInit.java的main()函数中调用 startSystemServer()开始的。


.../SystemServer.java


public static void main(String[] args) {} //这里是入口###


            try {
                Slog.i(TAG, "USB Service");
                usb = new UsbService(context);
                ServiceManager.addService(Context.USB_SERVICE, usb);
            }
.../UsbService.java
        if (new File("/sys/class/android_usb").exists()) {
            mDeviceManager = new UsbDeviceManager(context);
        }
############################################################
简单程序判别 32位/ 64位


#include <stdio.h>
int main()
{
    char *t;
    printf("%d\n", sizeof(t)); //4,32位;8,64位
    return 0;
}
############################################################
kernel 启动过程


vmlinux -> 


bootloader 跳到 vmlinux.lds 执行ENTRY(_start)


############################################################
什么是shell


shell 是在user和kernel之间的通道。用户空间通过shell向kernel发命令


########################################################################################################################47
pdflush 进程
·当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。
·当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘,以确保脏页不会无限期地驻留在内存中。
当dirty cache到了多少的时候,就启动pdflush进程,将dirty cache写回磁盘     当有dirty_background_bytes存在的时候,dirty_background_ratio是被自动计算的
############################################################48
修改文件属性
mount 查看文件类型
mount -o remount,rw -t rootfs(文件类型) rootfs(文件系统)
############################################################49
×成功之前专注一个有前景的领域,越小越好×


a)Linux的系统、网络、服务、集群、网站、网络应用方向: 
1、Web应用服务器,如sina、百度等大型网站 2、Mail应用服务器,如163或外企mail系统等 3、中间件或J2EE服务器,如为JBOSS Weblogic做平台 4、网络应用等。 
b)嵌入式开发、UNIX/Linux应用系统开发,Linux内核驱动开发方向,主要有以下几类: 
1、Linux下的C/C++ 系统程序开发
2、Linux平台Java体系开发和PHP开发 3、Linux下的图形界面开发 4、Linux底层内核/驱动开发 5、嵌入式Linux开发等。 
c)Linux下的数据库,如Mysql、oracle和windows下的SQL Server及DB2等。
############################################################
鲶鱼,必须是互补的,互助的。冲突的,重复的,互斥的鲶鱼比较危险(鸣人?)
############################################################50
内存寻址大小
32位机器是4G?  这个是由硬件RAM寻址线数量决定的,只有32条线。
PAE---intel引入36条线(64G)暂时解决了32位RAM不足的问题,转换32位地址到36位地址




############################################################
dump log 解释


栈地址 = 函数地址 + 偏移/函数大小
[<c03afcf0>] (enable_store+0x19c/0x238) from [<c02ffe8c>] (dev_attr_store+0x18/0x24)
[<c02ffe8c>] (dev_attr_store+0x18/0x24) from [<c018b058>] (sysfs_write_file+0x7c/0xb0)
[<c018b058>] (sysfs_write_file+0x7c/0xb0) from [<c013d53c>] (vfs_write+0xb0/0x128)
########################################################################################################################
open() 系统调用


mtpg_open()
misc_open()
chrdev_open()
__dentry_open()
nameidata_to_filp()
do_last() // ->may_open() -> error = inode_permission(inode, acc_mode);->
path_openat()
do_filp_open()
do_sys_open()
SYSCALL_DEFINE3(open


open(/dev/mtpg_usb)
############################################################
SElinux sepolicy, android4.4 加入的。


external/sepolicy/app.te //te文件规定了哪些进程有哪些访问权限
############################################################
char *p; p+1  //偏移一个字节
int *p; p+1 //偏移4个字节
char *p[5]; p+1//偏移1个字节?,首地址加1,指针数组
char (*p)[5]; p+1 //偏移几个字节?,5个,数组加1,指向数组的指针


############################################################
JAVA


1)package
java组织文件的虚拟文件系统? 包含java class xml resource等文件
package com.android.server.usb; //输出到这里
2)import
导入支持包
############################################################
JNI


/mtp/MTPJNIInterface.java
1)先声明
private native void testMtpCommands(int opCode, int transactionId);//有native关键词
2)调用
testMtpCommands();


/mtp_jni.cpp
3)
static JNINativeMethod gMTPRawContentMethods[] =
{
{"testMtpCommands","(II)V", (void *)Java_android_mtp_nativetestMptCommands},
....
{"java 函数名","参数",jni接口},
...
{"objectPlaRemoved","(Ljava/lang/String;)V", (void *)Java_android_mtp_nativePlaObjectRemovedCommands}
};


详解JNI -- 
1)结构体
typedef struct {
const char* name; //jni的名字
const char* signature; //参数,
void* fnPtr;
} JNINativeMethod;

参数格式
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
具体的每一个字符的对应关系如下
字符 Java类型 C类型
V      void            void
Z       jboolean     boolean
I        jint              int
J       jlong            long
D      jdouble       double
F      jfloat            float
B      jbyte            byte
C      jchar           char
S      jshort          short


数组则以"["开始,用两个字符表示
[I       jintArray      int[]
[F     jfloatArray    float[]
[B     jbyteArray    byte[]
[C    jcharArray    char[]
[S    jshortArray   short[]
[D    jdoubleArray double[]
[J     jlongArray     long[]
[Z    jbooleanArray boolean[]
上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring
Ljava/lang/String; String jstring
Ljava/net/Socket; Socket jobject
如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。
例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

2、JNI 调用java
JNIEnv *env = NULL ;
JavaVM* vm = AndroidRuntime::getJavaVM();
vm->AttachCurrentThread(&env, NULL);
jclass cls = env->GetObjectClass(gInterfaceObject);
jmethodID mid = env->GetMethodID(cls, "getObjectHandle", "(Ljava/lang/String;I)I"); // jni调用java层的getObjectHandle函数。
########################################################################################################################
Android四大基本组件分别是
Activity,-- 界面组件,第一个启动的组件
Service服务,--生命周期长,与activity binder的话,active终止,sevice也停止
BroadcastReceiver广播接收器。--生命周期短,10s左右,所以不能在onReceive做长时间的工作
ContentProvider内容提供者,--


-----------------------
AIDL -- 接口语言,可以直接调用
-----------------------
sendbroadcast 与 intent的区别


sendbroadcast -- (intent可替代sendbroadcast)


intent -- 协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,
Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用


-----------------------






-----------------------
############################################################
脚本语言


python




############################################################
RTOS


时间片的问题,如果相同优先级有多个进程,用时间片,否则不用时间片。
之前是不存在多个相同优先级的,所以不需要时间片


1)nucleus, /*不分内核空间用户空间。地址空间全部可以访问*/,微内核,内核只有调度/内存管理/ipc,driver/fs等在用户空间
############################################################
网络通信协议




7)应用层 (http)
6)表示层
5)会话层
4)传输层 UDP,TCP ?
3)网络层 (TCP/IP) ?
2)数据链路 (P-P,ethernet,高级数据链路协议,帧中继,异步传输模式)
1)物理层 (媒介光线)


############################################################
宏内核(Monolithic),微内核(Microkernel),混合内核(Hybrid)


宏内核--进程调度/内存管理/IPC,VFS,driver,等
微内核--进程调度/内存管理/IPC,基本的系统模块
混合内核--进程调度/内存管理/IPC,部分包含driver等


########################################################################################################################
############################################################


############################################################


############################################################


############################################################


########################################################################################################################




########################################################################################################################
############################################################


############################################################


############################################################


############################################################


########################################################################################################################






########################################################################################################################
############################################################


############################################################


############################################################


############################################################
内核与用户空间通信
1、socket
2、系统调用
3、ioctrl

4、proc文件系统


1、socket
########################################################################################################################


C++
1)函数默认是 extern的,所以,只要include的头文件有函数的声明就可以直接用。
变量需要加extern才能在其他文件使用。如果头文件没有声明,使用前需要加extern声明函数


2)函数重载只有在c++以后才有,c没有重载。重载是通过编译时实现的  //重载是同名函数不同参数,运行重载是同一个函数


3)局部static变量能不能在外部用?  不能,只能在定义的内部用,只初始化一次
############################################################
Trace debug
1)CPU寄存器


2)异常模式
Abort Mode
读写memory出错的时候,或者外部memory控制器报的错误

CPSR对应的状态
Mode Abbreviation privilegedMode[4:0]
Abort abtyes 10111
Fast interrupt requestfip yes10001
Interrupt requestirq yes10010
Supervisor svc yes 10011
System sys yes 11111
undefined und yes 11011
user usrNo 10000

(1)undefined
表象
PC=0x4;//如果undf exception发生的话,会跑到这个地址
LR对应的PC = LR - 0x4
(2)Data Abort Exception
memory或者mmu发现访问一个无效的地址,或者代码尝试访问没有权限的memory
表象
PC = 0x10;//
LR对应的PC = LR - 0x8



Reset uporidictable
Undefined instructionR14 - 0x4
Software abortR14 - 0x4
Prefetch abortR14 - 0x4
Data abort R14 - 0x8 //除了data abort其他的都是4字节
Interrupt requestR14 - 0x4
Fast inter reqR14 - 0x4


############################################################
大端小端(big-endian,little-endian)


小端-- 内存低地址存放低位,高地址放高位
大端-- 内存低地址存放高位,高地址放低位


############################################################
虚拟机与宿主互传文件方法:
1)FTP服务器
优点,不需要其他插件,不需要配置ip。
(1)使用FTP工具(守望mini)在宿主建立ftp服务器
(2)虚拟机通过ftpget -u lmy -p 111 ip 虚拟地址 需要的文件进行传输
2)winscp
3)samba


############################################################
代码技巧
1)ifdef 使用
#ifdef CONFIG_LMY
static init foo(void)
{
***;
}
#else
static incline int foo(void){}
#endif

//这样,即使CONFIG_LMY没有定义,其他应用仍可以安全的调用foo


########################################################################################################################
写时拷贝(copy-on-write)子进程写内存之前共享父进程的页表,直到子进程需要写虚拟地址的时候,才给子进程单独复制一个页表


fork 子进程复制了父进程的什么


1)写之前,系统调用之前,子进程复制了父进程的虚拟空间,虚拟空间的栈/堆/数据段。没有自己的物理空间。指向父进程的物理空间
2)写,再实际内存复制堆栈数据段等,代码段仍相同;系统调用,代码段复制
############################################################
栈为什么是向下生长的(限定大小?),堆为什么是向上生长的?


内核空间栈大小 -- 查看方法 
用户空间栈大小 -- 查看方法 ulimit -a


############################################################


SDP - 标准下行端口 500ma
CDP - 充电下行端口 1.5A
DCP - 专用充电端口 1.5A


############################################################
driver 结构体里面的resume suspend


.resume = xxxresume();


device_resume >
dpm_run_callback >
platform_pm_resume >
msm_otg_pm_resume >


*******
suspend 过程


device_resume >
dpm_run_callback >
platform_pm_resume >
msm_otg_pm_resume
############################################################
HAL 就是android用来逃避GPL协议的一个虚拟接口层,处理在hal,接口在kernel?


########################################################################################################################
vold -- volume Daemon


android 使用 vold替代udev动态管理/dev


############################################################
namespace --一种资源隔离方案


device,driver各自有ns,所以即使命名相同也不冲突,但是在driver内部,因为
属于同一个ns,所以不能有相同的命名


static const struct sysfs_ops class_sysfs_ops = {
87 .show   = class_attr_show,
88 .store   = class_attr_store,
89 .namespace = class_attr_namespace,
90};
static struct kobj_type device_ktype = {
212 .release = device_release,
213 .sysfs_ops= &dev_sysfs_ops,
214 .namespace= device_namespace,
215};
############################################################
MTP PTP 在PC端显示的名称是怎么设置传递的?


弹窗和文件浏览器看到的名字不一样
1)修改 setting里面的设备名称->lmymtp
2)文件浏览器看到 lmymtp 但是弹窗还是原model name


1、浏览器中设备的名字


try{
case 1:修改ap的model name,烧ap,重置,浏览器中改变,弹窗没变;
case 2:修改csc的model name,烧csc,重置,浏览器中改变,弹窗没变;?
case 3:插别人电脑 显示修改起作用了....//这个只枚举一次,下次即使烧其他型号名仍然显示原型号名。需要重新枚举
case 4:读的是AP中的model name 不是csc


}
############################################################
EBP:栈基址,下一个运行的地址,ESP传过来的
EIP:将要执行的
ESP:正在执行的 //以上是x86的芯片


sp:(R13)堆栈指针寄存器,esp的前身?,sp的值会保存到栈中
LK:(R14)链接寄存器,执行BL时,LK可以得到pc的备份,保存程序的返回地址。
即,调用的时候,lk = pc,执行完调用返回的时候,pc = lk
PC:(R15)程序计数器,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节
CPSR:(R16)程序状态寄存器。
SPSR:保存的CPSR


>>总结:sp对应了栈过程,lk是调用的函数,pc-8是当前函数


CS为代码段寄存器,IP为指令指针寄存器
eax 累加缓存器


ARM
   ARM微处理器共有37个32位寄存器,其中31个为通用寄存器,6个为状态寄存器。
############################################################
进程上下文,中断上下文


什么是上下文?cpu状态,寄存器的值


CPU可在进程上下文切换,因为这个是基本的资源单位。
中断的上下文就是所在进程的上下文?


进程切换只能在内核态进行
如果当前进程在用户态,那么需要陷入到内核态再切换 ?
########################################################################################################################
中断屏蔽(http://kernelnewbies.org/New_Kernel_Hacking_HOWTO/Subsystems/Exceptions_and_Interrupts_Handling)
1)非共享中断
2)共享中断
3)高优先级中断(屏蔽不了)
之前----
x86 intel平台,有两条中断线,分为 NMI(none-maskable indicates)/ INTR, no-mask就是不能被屏蔽的意思,raising上升沿有效
拥有最高优先级,很少被触发,主要用于运算出错,等各种错误。对于可屏蔽中断,由PIC(可编程中断控制器)进行控制
PIC:有各种输入线(最多15条),但是只有一条输出到CPUs
当CPUs需要屏蔽中断的时候,就发送命令给PIC将对应位进行mask,再有对应的中断过来,PCI虽然能收到信号,但是不传给CPU
CPU也可以通过清空内部EFLAGS寄存器屏蔽所有的INTR中断


现在----
更加复杂,使用APIC(advanced PIC),可以支持256个中断线


中断向量表:
256个,前32个留给各种异常。 TASK Gates,Tap Gates,Interrupt Gates


开机之前连接USB,中断是怎么发出来的》?????pic中断缓存,内核启动后再传递?


spurious interrupts -- 假中断?
############################################################
系统休眠的时候,时钟是否停止/休眠
1)RTC(realtime clock)不会休眠,时钟是一个中断,中断怎么睡眠
############################################################
SMP --- “对称多处理“(Symmetrical Multi-Processing)
############################################################
linux命令
或符号(|),管道命令,或之前的结果是或之后的输入.注意,输出/输入都不用指明,注意前后多出来的两个“-”
tar -jcvf - usb | split -b 10M - usb.tar.bz2.
==
tar -jxvf usb.tar.bz2 usb
split -b 10M usb.tar.bz2 usb.tar.bz2.




统计文件夹下文件的个数,包括子文件夹里的
ls -lR|grep "^-"|wc -l


grep 转义字符
grep -rn "\->wk(" *   /** 符号'\'是转义字符*/

whole word, 整词/字搜索, 全词
grep -rn -w "pit" *

java文件下查找,先find java,再grep string
find -name "*.java" -exec grep -rHn --color=auto "folder_camera" {} \;
############################################################
spinlock--自旋锁


1)考虑中断使当前进程睡眠,等同一个锁的情况,spinlock_irqsave
2)考虑两个并行线程,A锁1,2,B锁2,1,那么A再等2解锁,B在等1 解锁,这样就死锁了.
--线程锁多个锁的时候,按照固定顺序进行,都是从低地址到高地址


########################################################################################################################
<<linux 设备模型>>
linux设备模型是一个复杂的数据结构


14.1 kobject ksets subsystems
struct kobject {
const char *name; //kobj有自己的名字
struct list_headentry; //kobject结构链表
struct kobject*parent;//有个parent
struct kset *kset; //指向kset集合
struct kobj_type*ktype; //有个ktype
struct sysfs_dirent*sd; //sysfs文件目录
struct kref kref; //引用计数,跟踪对象生命周期,引用为0,结束
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
kobject_register(kobj)是kobject_init kobject_add的结合。
kobject_unregister(kobj)是kobject_del kobject_put的结合。




》》》》》
struct kset {
struct list_head list; //连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
kset是嵌入到相同类型结构的kobject集合,一旦一个kset被建立,sysfs就会创建的目录给他


struct kobj_type {
void (*release)(struct kobject *kobj);//释放函数(驱动编写时提供),此函数会被kobject_put函数调用
const struct sysfs_ops *sysfs_ops; //属性文件的操作函数(只有读和写操作)
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};


sysfs_create_link//用来关联 /sys/devices,/sys/bus/drivers等
3、热插拔事件
只要kobject有添加删除的动作就有uevent的发送,
4、总线,设备,驱动
总线--处理器和多个设备的通道
5、类(class),block,bus,这个目录是从不同角度考察设备做的抽象
6、符号链接(sysble_link)
root@s3lite:/ # ls -l sys/class/switch
ls -l sys/class/switch
lrwxrwxrwx root     root              2013-12-25 04:36 dock -> ../../devices/virtual/switch/dock
lrwxrwxrwx root     root              2013-12-25 04:35 h2w -> ../../devices/virtual/switch/h2w
7、顶级目录创建(block bus class)
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
class_kset = kset_create_and_add("class", NULL, NULL);
module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);


//××××××××××××××××××××××××××××××××××××
《linux内核设计与实现》中的kobject


设备模型也是一个拓扑结构;
sysfs,一个用户空间的文件系统表示内核空间的kobject对象层次结构。
kobject一般不会单独使用,一般嵌入到具体的设备结构体中
ktype是为了描述一组kobject的普遍特性。kobject共享这一特性;
kset是相关kobject的集合体,可看作容器。与ktype的区别,具有相同ktype的obj可以分到不同的kset


使用kobject,
1)初始化,kobject_init(kobj)


&&&&&&&
1)什么是设备模型?--用统一的结构体,将设备组织为树形拓扑结构,实现多种便利性
2)kobject会被哪些函数,哪些需求引用?kref存在的意义?只要是sysfs的目录就对应一个obj,父obj被引用一次,kref就加1.
&&&&&&&
1)有几个结构体? --3个,kobject,kset,ktype
2)有几个属性? --一个,struct attribute
3)
4)有几组show/store? --bus,device,class,driver 等等,都是自定义一个结构体,包含attr和show/store
&&&&&&


############################################################
OTG


主机流通协议(Host Negotiatio n Protocol, HNP)
1)电流设置,在/usb/host 搜power,发现几个budget,ehci_msm2_dt_to_pdata()
可能性最大。
############################################################
.mk 脚本


同一个文件中对同一个变量重复赋值,先到先得???
########################################################################################################################
设备树--device tree


1、什么时候编译?
/kernel/Documentation/devicetree/booting-without-of.txt


2、什么时候加载设备?
<4>[    0.080398] [0:      swapper/0:    1] *** bus: bus_add_device, fe8050c8.android_usb
<4>[    0.080480] [0:      swapper/0:    1] [<c043e3e0>] (bus_add_device+0x90/0x1d4) from [<c043cbac>] (device_add+0x370/0x5a8)
<4>[    0.080516] [0:      swapper/0:    1] [<c043cbac>] (device_add+0x370/0x5a8) from [<c064f60c>] (of_platform_device_create_pdata+0x58/0x78)
<4>[    0.080553] [0:      swapper/0:    1] [<c064f60c>] (of_platform_device_create_pdata+0x58/0x78) from [<c064f758>] (of_platform_bus_create+0x12c/0x1e0)
<4>[    0.080588] [0:      swapper/0:    1] [<c064f758>] (of_platform_bus_create+0x12c/0x1e0) from [<c064f980>] (of_platform_populate+0x5c/0x8c)
<4>[    0.080624] [0:      swapper/0:    1] [<c064f980>] (of_platform_populate+0x5c/0x8c) from [<c0d0b244>] (msm8226_init+0x30/0x84)
<4>[    0.080660] [0:      swapper/0:    1] [<c0d0b244>] (msm8226_init+0x30/0x84) from [<c0d03618>] (customize_machine+0x1c/0x28)
<4>[    0.080693] [0:      swapper/0:    1] [<c0d03618>] (customize_machine+0x1c/0x28) from [<c010052c>] (do_one_initcall+0x90/0x160)
<4>[    0.080726] [0:      swapper/0:    1] [<c010052c>] (do_one_initcall+0x90/0x160) from [<c0d00d40>] (kernel_init+0xec/0x1a8)
<4>[    0.080759] [0:      swapper/0:    1] [<c0d00d40>] (kernel_init+0xec/0x1a8) from [<c0106aec>] (kernel_thread_exit+0x0/0x8)
3、规范
/{
}
,root结点"/"的compatible 属性compatible = "acme,coyotes-revenge";定义了系统的名称,compatible = "arm,vexpress-flash", "cfi-flash";  
第二个属性表示可以支持cfi-flash设备。
子节点命名:
<name>@<address>,sm5502@25
reg = <0x00> 是芯片地址
############################################################
kthread_create
查看进程信息 top;查看线程信息 top -t


内核创建线程方法
kthread_run == 
kthread_create
wake_up_process(t_task);


查看当前线程信息方法
static struct task_struct *thread;


current_thread_info() ????
############################################################
tar 压缩 分割大小


壓縮備份:


tar -cjvf- ./targrt-path/ | split -a 1 -b 600m – ./`date +%Y-%m-%d`.tar.bz2.


解壓縮還原:


cat *.bz2* | tar -jxvf-


2、解压指定的文件
tar -zxvf xxl.tar.gz ./ xxl/date/test.sql
############################################################
Makefile
1)targets : prerequisites
command //命令前面加Tab;其他的不用加
2)Ex.
obj = he.o shuf.o //obj是全局变量
game:$(obj)
cc -o game $(obj)
he.o:head.h
shuf.o:head.h
clean:
rm game $(ob)
3)
############################################################
1、进程与线程
进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共
享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源。
"进程——资源分配的最小单位,线程——程序执行的最小单位"
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单
独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行
并且又要共享某些变量的并发操作,只能用线程,不能用进程。
总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。(下面的内容摘自Linux下的多线程编程)


2\进程状态
(1)TASK_RUNNING(运行),可以执行,准备执行,正在执行
(2)TASK_INTERRUPTIBLE(可中断),进程正在休眠
(3)TASK_UNINTERRUPTIBLE(不可中断),休眠,不会因信号而唤醒
(4)TASK_ZOMBIE(僵尸),进程已经结束,但是父进程还没调用wait4,进程描述符仍被保留。父进程调用wait4,描述符才被释放
(5)TASK_STOPPED(停止),进程停止.
############################################################


########################################################################################################################
多线程 并发


原子操作--全局变量保护,i++,汇编为3个语句;
012B1408  mov         eax,dword ptr [i] 
012B140B  add         eax,1 
012B140E  mov         dword ptr [i],eax 
主线程与子线程同步--
子线程互斥--


互斥--资源,A在用的时候,B等待,spinlock
同步--B需要的资源由A提供。complete,mb,barrier


信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
############################################################
文件位置
MUIC kobj
i2c_add_driver();/sys/bus/i2c/drivers/sm5502/15-0025/control;device_type


定位寻找obj函数,path,查找路径
char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask);kobject_get_path(&client->dev.kobj, GFP_KERNEL);
『函数实现 for(parent = kobj;;parent == parent->parent)』
############################################################
pipe连接usb的两端,一端是host的 transfer_buf,另一端是device的endpoint,主机没有端点。
主机通过pipe传输urb到指定的ep来请求数据
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)


struct usb_device ep_out,ep_in <--> struct usb_host_endpoint
############################################################
bind(bound) 本质是让 dev drv互相指
############################################################
常用汇编指令
ldr r0,[r4]--把r4做地址的内存数据装载到r0寄存器
str --把寄存器数据写到内存
int --中断指令
########################################################################################################################
不用trace,查找调用栈
1)准备问题log,对应的vmlinux
2)objdump -x vmlinux > map.txt
3) 根据sp 地址在map.txt查找函数 ???


PC地址是问题函数地址,lr地址是当前函数将要返回调用函数的地址,通过lr可以找到PC的调用函数


############################################################
USB phy 对应phy硬件,是连接UTMI+和USB连接器的接口


############################################################


############################################################
cdev -- 字符设备
 
struct cdev {
struct kobject kobj;         
struct module *owner; 
  const struct file_operations *ops;         
struct list_head list;         
dev_t dev; //高12为为主设备号,低20位为次设备号
  unsigned int count; 
};
使用以下宏可以从 dev_t 获得主设备号和次设备号: MAJOR (dev_t dev); MINOR (dev_t dev);
而使用下面宏可以通过主设备号和次设备号生成 dev_t MKDEV (int major, int minor); 
alloc_chrdev_region     --自动分配设备号
register_chrdev_region  --分配已设定的设备号。
############################################################
每种传输类型都有自己的urb,填充urb结构体,实现不同的对象;
interrrupt/ISO 低速/全速传输,使用帧,高速使用微帧(micro frame)
########################################################################################################################
USB 速度换算--
480Mbps,一个symbol含有一个开始一个结束bit,8bit数据。所以,数据传输速度是48M/s。///????????
< As the scheme name suggests, 8 bits of data are transmitted as a 10-bit entity called a symbol, or character. >


对于1200 b/s这个速率来说,由于每个字节含有8 bit数据、1 bit起始位和1 bit结束位,因此传输速率是每秒1 2 0个字节,或者说每个字节8.33 ms。
照这句话的理解,一个字节就是10bit,这跟我们平时说的不一样啊
到底一个字节是8bit还是10bit///////
“1个字节绝对是8bit,”这是绝对没有错误的!
但是在网络传输的时候为了区别一个字节的开始和结束需要在每个字节前加一位,后面加一位,就这样而已,所以这个时候就是10个b了,也就是说网络传输了10个b的数据,而其中有8个b是表示一个字节,另外2b是控制信息!!而不是什么“每个字节含有8 bit数据、1 bit起始位和1 bit结束位,说的比较含糊,其实意思是8bit中包括1 bit起始位和1 bit结束位。”
明白了吗?
############################################################
四大描述符
设备(device):
203 /* USB_DT_DEVICE: Device descriptor */ 
204 struct usb_device_descriptor { 
205         __u8  bLength; 
206         __u8  bDescriptorType; 
208         __le16 bcdUSB; 
209         __u8  bDeviceClass; 
210         __u8  bDeviceSubClass; 
211         __u8  bDeviceProtocol; 
212         __u8  bMaxPacketSize0; 
213         __le16 idVendor; 
214         __le16 idProduct; 
215         __le16 bcdDevice; 
216         __u8  iManufacturer; 
217         __u8  iProduct; 
218         __u8  iSerialNumber; 
219         __u8  bNumConfigurations; 
220 } __attribute__ ((packed)); 
配置(configuration):
    155 /* Configuration descriptor information.. */
    156 #define USB_MAXCONFIG 8
    157 struct usb_config_descriptor {
    158 u_int8_t  bLength;
    159 u_int8_t  bDescriptorType;
    160 u_int16_t wTotalLength;
    161 u_int8_t  bNumInterfaces;
    162 u_int8_t  bConfigurationValue;
    163 u_int8_t  iConfiguration;
    164 u_int8_t  bmAttributes;
    165 u_int8_t  MaxPower;
    167 struct usb_interface *interface;
    169 unsigned char *extra;/* Extra descriptors */
    170 int extralen;
    171 };
端口(interface):
    129 /* Interface descriptor */
    130 #define USB_MAXINTERFACES 32
    131 struct usb_interface_descriptor {
    132 u_int8_t  bLength;
    133 u_int8_t  bDescriptorType;
    134 u_int8_t  bInterfaceNumber;
    135 u_int8_t  bAlternateSetting;
    136 u_int8_t  bNumEndpoints;
    137 u_int8_t  bInterfaceClass;
    138 u_int8_t  bInterfaceSubClass;
    139 u_int8_t  bInterfaceProtocol;
    140 u_int8_t  iInterface;
    142 struct usb_endpoint_descriptor *endpoint;
    144 unsigned char *extra;/* Extra descriptors */
    145 int extralen;
    146 };
端点(endpoint):
    104 /* Endpoint descriptor */
    105 #define USB_MAXENDPOINTS 32
    106 struct usb_endpoint_descriptor {
    107 u_int8_t  bLength;
    108 u_int8_t  bDescriptorType;
    109 u_int8_t  bEndpointAddress;
    110 u_int8_t  bmAttributes;
    111 u_int16_t wMaxPacketSize;
    112 u_int8_t  bInterval;
    113 u_int8_t  bRefresh;
    114 u_int8_t  bSynchAddress;
    116 unsigned char *extra;/* Extra descriptors */
    117 int extralen;
    118 };
############################################################
localhost:/usr/src/linux/drivers/usb/core # ls /sys/bus/usb/devices/usb1/ep_00/ 
bEndpointAddress bits 0~3 端点号;bits8,方向
############################################################
kernel versions, USB 变更内容
############################################################
craterve/s3lite
qpnp_charger_probe > qpnp_chg_usb_usbin_valid_irq_handler >power_supply_set_present
>otg_power_set_property_usb >msm_otg_set_vbus_state > queue_wok(sm_work) >pm_runtime_resume(>msm_otg_resume) && msm_chg_detect_work(queue_work(chg_work)) >ulpi_read
############################################################
remote_wakeup--slave 唤醒 host 叫remote wakeup
########################################################################################################################37
tty** 终端设备
ttySn--串行终端;pty--伪终端; /dev/tty当前控制台终端;ttyGS*-- Serail Gadget设备,modem,gadget_serial.txt
############################################################38
/**
 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
 *
 * @subsys - the struct kset that defines this subsystem
 * @devices_kset - the subsystem's 'devices' directory
 * @interfaces - list of subsystem interfaces associated
 * @mutex - protect the devices, and interfaces lists.
 *
 * @drivers_kset - the list of drivers associated
 * @klist_devices - the klist to iterate over the @devices_kset
 * @klist_drivers - the klist to iterate over the @drivers_kset
 * @bus_notifier - the bus notifier list for anything that cares about things
 *                 on this bus.
 * @bus - pointer back to the struct bus_type that this structure is associated
 *        with.
 *
 * @glue_dirs - "glue" directory to put in-between the parent device to
 *              avoid namespace conflicts
 * @class - pointer back to the struct class that this structure is associated
 *          with.
 *
 * This structure is the one that is the actual kobject allowing struct
 * bus_type/class to be statically allocated safely.  Nothing outside of the
 * driver core should ever touch these fields.
 */
struct subsys_private { //一个bus总线,class设备类,有一个subsys_private,提供设备链表,驱动链表
struct kset subsys;
struct kset *devices_kset;
struct list_head interfaces;
struct mutex mutex;


struct kset *drivers_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;


struct kset glue_dirs;
struct class *class;
};
############################################################39
DMA--- direct memory access 直接操作物理地址。而一般的数据处理使用虚拟地址


1-1 使用大块DMA一致性缓冲区(dma-coherent buffers)
void * dma_alloc_coherent(struct device *dev, size_t size,//将物理地址和虚拟地址对应,并将该物理页的总线地址保存于dma_handle(&ui->dma),返回该物理页的虚拟地址ui->buf,
                    dma_addr_t *dma_handle, gfp_t flag)//这样,dma_handle 的是物理地址,其他函数处理的是虚拟地址。


A = dma_alloc_writecombine(B,C,D,GFP_KERNEL);
我对此函数的理解是,调用此函数将会分配一段内存,D将返回这段内存的实际物理地址供DMA来使用,A将是D对应的
虚拟地址供操作系统调用,对A和D的的任意一个进行操作,都会改变这段内存缓冲区的内容。
1-2 使用小块DMA一致性缓冲区
许多驱动程序需要为DMA描述符或者I/O内存申请大量小块DMA一致性内存。
你可以使用DMA 内存池,而不是申请以页为单位的内存块或者调用dma_alloc_coherent()。
struct dma_pool * dma_pool_create(const char *name, struct device *dev, 
                size_t size, size_t align, size_t alloc);
create( )函数为设备初始化DMA一致性内存的内存池。它必须要在可睡眠上下文调用。


void *dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags, 
                dma_addr_t *dma_handle);
从内存池中分配内存。






############################################################40
libmtp.so,libmtp_samsung.so,libmtp_samsung_jni.so,MtpApplication.apk
############################################################41
/* use a define to avoid include chaining to get THIS_MODULE & friends */
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)  /////define的精华在于屏蔽了owner赋值过程,直接使用THIS_MODULE 宏进行赋值

retval = driver_register(&new_driver->drvwrap.driver);
/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver *drv)
{
if ((drv->bus->probe && drv->probe) ||
   (drv->bus->remove && drv->remove) ||
   (drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
/////
/**
 * driver_find - locate driver on a bus by its name.
 * @name: name of the driver.
 * @bus: bus to scan for the driver.
 * Call kset_find_obj() to iterate over list of drivers on
 * a bus to find driver by name. Return driver if found.
 * This routine provides no locking to prevent the driver it returns
 * from being unregistered or unloaded while the caller is using it.
 * The caller is responsible for preventing this.
 */
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);//在bus -》 private-》kset list链表查找name相同的kobj,找到kobj就说明已经存在这个driver了
struct driver_private *priv;
if (k) {
kobject_put(k);
priv = to_driver(k);//container_of(obj, struct driver_private, kobj),根据kobj找到driver结构体指针
return priv->driver; //priv 与driver互指
}
return NULL;
}
///
/**
 * bus_add_driver - Add a driver to the bus.
 * @drv: driver.
 */
int bus_add_driver(struct device_driver *drv) //1、创建了一个driver_private,创建了对应的kobj指向bus的kset,并加入到buskset的list中,以后可以通过buskset的list遍历driver
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;


bus = bus_get(drv->bus);//drvbus不直接指给bus,是为了bus的kobj kref++,便于obj继承管理
if (!bus)
return -EINVAL;


pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);


priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;//kset将在下面管理新增的kobj
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,// 》kobject_add_varg(kobj, parent, fmt, args); 》kobject_add_internal(kobj);》kobj_kset_join(kobj);》list_add_tail(&kobj->entry, &kobj->kset->list);
    "%s", drv->name);
if (error)
goto out_unregister;


klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
module_add_driver(drv->owner, drv);// module name 已在#define usb_register usb_register_driver定义


error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}


if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}


kobject_uevent(&priv->kobj, KOBJ_ADD); //每增加一个kobj,就发送一个KOBJ_ADD的uevent
return 0;


out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
/**
 * driver_attach - try to bind driver to devices.
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
    void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
klist_iter_init_node(&bus->p->klist_devices, &i,//klist_device 是保存挂在bus上面的设备链表,init_node函数初始化一个klist_iter结构体
    (start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i); //释放klist_iter结构体
return error;
}
static int __driver_attach(struct device *dev, void *data) //这里开始比较dev 和 driver的name,如果不同返回0,否则继续
{
struct device_driver *drv = data;
/* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
* driver_probe_device() will spit a warning if there
* is an error.*/
if (!driver_match_device(drv, dev)) //通过drv->bus->match(dev, drv)回调usb_device_match
return 0;
if (dev->parent)/* Needed for USB *///usb设备,parent设备都锁住才能继续bind
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)//dev没有自带的driver
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
static int usb_device_match(struct device *dev, struct device_driver *drv)
{/* devices and interfaces are handled separately */
if (is_usb_device(dev)) { //return dev->type == &usb_device_type;
if (!is_usb_device_driver(drv))/* interface drivers never match devices */
return 0;
return 1;/* TODO: Add real matching code */
} else if (is_usb_interface(dev)) { //return dev->type == &usb_if_device_type; ??????
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
if (is_usb_device_driver(drv))/* device drivers never match interfaces */
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
}
return 0;
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pm_runtime_get_noresume(dev);///??????
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);//开始回调driver的probe函数
pm_runtime_put_sync(dev);
return ret;
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;


atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));


dev->driver = drv; //dev-driver 指向bind的driver
if (driver_sysfs_add(dev)) { //ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,kobject_name(&dev->kobj)); 让devobj 和 drvobj产生关系;;;以objname的名义
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->bus->probe) { //有bus probe先用bus的,没有就用drv的probe
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev);
ret = 1;
goto done;
done:
atomic_dec(&probe_count); ////probe初始化也要排队,一个一个来
wake_up(&probe_waitqueue);
return ret;
}
static void driver_bound(struct device *dev) //这个有什么用 ?????就是把dev drv 里面的private参数互相指
{
if (klist_node_attached(&dev->p->knode_driver)) {//return (n->n_klist != NULL);
printk(KERN_WARNING "%s: device %s already bound\n",__func__, kobject_name(&dev->kobj));
return;
}
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),__func__, dev->driver->name);
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);//klist_node_init(k, n);add_tail(k, n);
//* Make sure the device is no longer in one of the deferred lists and kick off retrying all pending devices
driver_deferred_probe_del(dev); //?????
driver_deferred_probe_trigger(); //
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_BOUND_DRIVER, dev);
}
########################################################################################################################42
kobj,kset,kobj_type
struct kobject {
const char *name; //kobj有自己的名字
struct list_headentry; //kobject结构链表
struct kobject*parent;//有个parent
struct kset *kset; //指向kset集合
struct kobj_type*ktype; //有个ktype
struct sysfs_dirent*sd; //sysfs文件目录
struct kref kref; //reference 计数,引用(get)加一,释放(put)减一.0释放当前kobj
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
/**
 * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
 *
 * A kset defines a group of kobjects.  They can be individually
 * different "types" but overall these kobjects all want to be grouped
 * together and operated on in the same manner.  ksets are used to
 * define the attribute callbacks and other common events that happen to
 * a kobject.
 *
 * @list: the list of all kobjects for this kset
 * @list_lock: a lock for iterating over the kobjects
 * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
 * @uevent_ops: the set of uevent operations for this kset.  These are
 * called whenever a kobject has something happen to it so that the kset
 * can add new environment variables, or filter out the uevents if so
 * desired.
 */
struct kset {
struct list_head list; //连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
struct kobj_type {
void (*release)(struct kobject *kobj);//释放函数(驱动编写时提供),此函数会被kobject_put函数调用
const struct sysfs_ops *sysfs_ops; //属性文件的操作函数(只有读和写操作)
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};


所以kobject和kset的关系简单来讲,就是
1.kset是kobject的一个顶层容器,它包含了相同类型的kobject,kset中有链表成员保存所有的kobject指向。
2.kobject中的kset指针指向了一个kset
3.kset中有kobject对象,表明了kset也可以有kobject相关的操作。
4.kset链表中的kobject对象的parent指针一般都指向kset内嵌的kobject对象。
讨论kobj_type和kobject的关系,就要先说说kobject的引用。引用一个kobject使用函数kobject_get()这个函数会增加kobject
的引用并返回kobject的指针。增加其引用是通过其kobject中断哦kref变量完成的。对kobject的引用管理主要是为了知道被引用
的情况,如引用不为0就不能销毁kobject对象,引用为0时则调用相应的释放函数等。


一个目录代表一个kset的kobject,目录下的文件是指向kset的一类kbject
############################################################43
Linux 文件系统
procfs --
sysfs --
root:/sys/
sysfs_create_dir(kobj);//如果kobj有parent,那么在parent kobj的sd目录下创建文件/文件夹,如果没有parent在sysfsroot目录下创建文件/文件夹
典型应用:ATTR,attr本质是填充device_attibute结构体,最终还是要调用device_create_file创建文件
sysfs比proc先进?//???
debugfs --
debugfs_create_file("devices", 0444, usb_debug_root, NULL, &usbfs_devices_fops);
root:/sys/kernel/debug,parent是NULL的时候,在root目录创建


devfs --
root:/dev/
内核空间/用户空间,固定的设备
优缺点:相对于udev,devfs不知道/dev下的文件对应的设备设否存在
udev --
root:/dev/
/etc/udev/udev.conf
sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间。
和namedev,libsysfs一起工作?
用户空间,动态的设备,根据uevent(kobject)添加删除设备,屏蔽主次设备号




udev取代devfs




############################################################44
usb MTP


mtp_bool __mtp_handler_process_request
mtp_usb_mtp_initialize()
usb_initialize(g_pDevice->pState); // At final linking, mtp_change_usb_mode() is called
_mtp_usb_initialize();
mtp_change_usb_mode();
mtp_thread_mtp_usb_init(&th1_MtpUsb);
mtp_thread_mtpusb_initialize
mtp_usb_initialize();
mtp_init_device();


############################################################45
MTP 启动流程


1)插入usb,上报uevent,manifest注册的receiver收到usbstate的消息
MtpReceiver.java
public class MtpReceiver extends BroadcastReceiver {
context.startService(intent);//intent是mtpservice
// tell MediaProvider MTP is connected so it can bind to the service
         context.getContentResolver().insert(Uri.parse(
                    "content://media/none/mtp_connected"), null);
}
2)MtpService.java
第一次启动,先运行public void onCreate() {},再运行onstartcommand。
以后再收到startservice的话,只运行onstartcommand,不再运行onCreate。
public void onCreate() {
mtpstorage();//JNI
}
public int onStartCommand(Intent intent, int flags, int startId)
{
mDatabase = new MtpDatabase
 
mServer = new MtpServer(mDatabase, mPtpMode);
}
3)MtpServer.java
native_setup(database, usePtp);
/android_mtp_MtpServer.cpp
MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),usePtp, AID_MEDIA_RW, 0664, 0775);
/MtpServer.cpp
void MtpServer::run() {

}

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


mtpreceiver -->mtpservice -->mtpdatabase
! ||^ mtpserver
! ||bindser !
! || !
! |--------->mediaprovider!
! !
=========================================JNI
! !
uevent !
! mtpserver
!
usbdriver

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
############################################################45
????
frameworks/libmtp/src/transport/mtp-usb-driver.c
mtp_write_gadget_event();
    usleep(10000);
    status = ioctl (fd, MTP_ONLY_ENABLE, 0);

~~#~~
用户空间
fd = path;
ioctl(fd,cmd,xx)
内核空间
/* file operations for MTP device /dev/usb_mtp_gadget */
.unlocked_ioctl = mtpg_ioctl,
~~#~~
????
/android/kernel/arch/arm/kernel/entry-common.S ,sys_call_table
__sys_trace_return
回调-> sys_ioctl ->
回调-> do_vfs_ioctl ->
回调-> vfs_ioctl ->
回调-> mtpg_ioctl ->
case MTP_ONLY_ENABLE:
usb_gadget_disconnect(cdev->gadget); //先断后连,why ?????
msleep(20);
usb_gadget_connect(cdev->gadget);
回调-> ci13xxx_pullup ->
回调-> ->
回调-> ->
回调-> ->
回调-> ->
回调-> ->
回调-> ->
ioctl系统调用流程
sys_ioctl()是整个ioctl系统调用过程中的最顶级函数,它需要对输入的参数进行预处理,检查参数的合法性,然后调用底层的处理函数作更进一步的处理。
############################################################46
java 打印调用栈


new Exception().printStackTrace();
system.err.println("xxxx");
throw new RuntimeException(functions);
########################################################################################################################47
gcc命令objdump用法
gcc命令之 objdump 
---------------objdump是用查看目标文件或者可执行的目标文件的构成的GCC工具----------
以下3条命令足够那些喜欢探索目标文件与源代码之间的丝丝的关系的朋友。
objdump -x obj >xxx以某种分类信息的形式把目标文件的数据组织(被分为几大块)输出 <可查到该文件的所有动态库>   
objdump -t obj 输出目标文件的符号表() /***符号表*/
objdump -h obj 输出目标文件的所有段概括()
objdump -j .text/.data -S obj 输出指定段的信息,大概就是反汇编源代码把
objdump -S obj C语言与汇编语言同时显示
以下为网上摘录文章。
#if############################################################1
1.1.5   Special Sections
一些典型section的名和内容解释如下表所示:
名称
内容
.text
机器指令, 常值数据和常值串.
.data
初始化数据.
.sdata
小初始化数据.
.bss
未初始化变量.
.sbss
小未初始化变量.
.comment
Comments from #ident directives in C.
.init
Main()函数之前执行的代码.
.fini
程序执行完成后执行的代码.
.eini
.fini代码的最后指令;.init,.fini和eini section应以序放入内存.
.debug
DWARF格式的符号调试信息.
.line
符号调试的行号信息.
.relaname
Section name的重定位信息.
.shstrtab
Section名.
.strtab
串表for符号表中的符号.
.symtab
包含符号表.
#end############################################################2
vmlinux.lds.S--/kernel/arch/arm/kernel/vmlinux.lds.S,内核链接脚本文件
vmlinux.lds --链接生成的文件,/obj/KERNEL_OBJ/arch/arm/kernel/vmlinux.lds


ENTRY(stext)--stext作为入口


 .init.data : {
  *(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .;
  . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;
  __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
  __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;
  __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;
  . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)
 }
#if###########################################################3
\wilcoxctc\obj\KERNEL_OBJ\System.map
#end###########################################################4
static int __init lmy_init()
{
printk("***lmy test __init without subsys_init\n");
}
subsys_initcall(lmy_init);
1、有subxxxinitcall,没有调用 放入init.text执行
2、没有subxxxinitcall,没有调用 不执行,不在符号表。(?)
2、没有subxxxxx ,调用执行,不在符号表?
#if###########################################################5
执行的时候通过do_one_initcall(*fn); fn地址从__initcall_start开始,__initcall_end结束(从system.map看到的是指针地址,
实际对应的地址在__init_begin~__init_end 之间)。初始化所有.init.text函数执行结束,调用 free_initmem(),从__init_begin
到__init_end 释放内存;
#end###########################################################6
__exit修饰词标记函数只在模块卸载时使用。 
\android\kernel\include\linux\init.h


#define module_init(x) __initcall(x); #define __initcall(fn) device_initcall(fn)


__define_initcall("1",fn,1)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn

__attribute__((section("section_name")))其作用是将作用的函数或数据放入指定名为"section_name"输入段。
#if###########################################################7
platform_device_register 过程




asmlinkage void __init start_kernel(void)
setup_arch(&command_line);
setup_machine_tags(machine_arch_type);
for_each_machine_desc(p)==for (p = __arch_info_begin; p < __arch_info_end; p++) ¥¥.init.arch.info : {
160 __arch_info_begin = .;
161 *(.arch.info.init)
162 __arch_info_end = .;
163 }
if (nr == p->nr) { //在 section寻找匹配变量(结构体)
    875 printk("Machine: %s\n", p->name);

/kernel/arch/arm/tools/mach-types/


/*找到machine*/
static int __init customize_machine(void)
{
/* customizes platform devices, or adds new ones */
if (machine_desc->init_machine)
machine_desc->init_machine();
return 0;
}
arch_initcall(customize_machine);
#define arch_initcall(fn) __define_initcall("3",fn)

#end###########################################################8
usb启动顺序
Line 3: Line 6: Line 13783: c08e23b0 l     F .init.text 00000098 qrd7627a_otg_gadget ----LEVEL(arch.info.init)--add (msm_otg,msm_hsusb,android_usb,msm_hsusb_host.0,) device.
Line 28: Line 139: Line 78156: c08f27c4 l     F .init.text 00000174 usb_init -----LEVEL(4)--add usb_bus(subbus),core driver
Line 5: Line 17: Line 79977: c08f2a0c l     F .init.text 00000014 msm_otg_init -----LEVEL( 6 )--add otg driver
#if###########################################################9
#define bus_register(subsys) \
    116 ({ \
    117 static struct lock_class_key __key;\
    118 __bus_register(subsys, &__key);\
    119 })

#ls sys/bus
clocksource
cpu
event_source
hid
i2c
mdio_bus
media
mmc
platform {msm_otg
scsi
sdio
serio
ttsp4
usb  //subsystem bus 里面包含device 和 driver。
#end###########################################################10
mb(); # define mb() barrier() barrier用于多个线程同步某个任务的完成状态,比如循环处理数组的多线程程序并行。
//barrier,内嵌汇编,不进行优化,前面执行完才执行这个汇编--保证前面都执行完。
#if###########################################################11
msm_rpcrouter_init_devices
msm_rpc_register_client
#end#######################################################################################################################12
userspace 与 kernelspace 通信方式


1         概述
Linux内核将这4G字节的空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),
供各个进程使用,称为“用户空间“)。除了进程之间的通信外,在嵌入式设计中还经常需要进行内核空间和用户空间的信息交互。本文主要讨论内核空间和用户空间信息交互的方法。
1.1 处理器状态
处理器总处于以下状态中的一种:
A、内核态,运行于进程上下文,内核代表进程运行于内核空间;
B、内核态,运行于中断上下文,包括硬中断和软中断;
C、用户态,运行于用户空间。
#if###########################################################13
CSP716088_technical_report.pdf
DC offset The  DC-offset  issue  is  well-known  at  Asic  side  and  the  reason  of  DC-offset  is  because  the 
internal switch of BCD is enabled. Per BC 1.2 official specification, Vdp_src(0.5 – 0.7V) needs to 
be  driven  on  to  the  USB  D+  line  when  DCP(dedicated  charging  port)  or  SDP(standard 
downstream port, such as generic USB host) is connected outside. For SDP to be functional in 
its traditional USB role, the Vdp_src needs to  be disabled since  it interferes with USB charp 
which is +/- 400mV signal. When we faced to download failure issue, then we could see that 
too many usbReset and usbEnumDone interrupt is triggered continuously and the reason of this 
infinite interrupts(UsbReset/UsbEnumDone) is due to the same thing which interfaers with USB 
charp. That is, when DC-offset is occurred, then this make to interference with USB charp and 
as a result, USB Block of BaseBand can’t complete the USB reset/EnumDone procedure. 


其实就是Vdp_src干扰了D+/D-信号
#end###########################################################14
share memory driver (SMD) /android/kernel/arch/arm/mach-msm/smd_rpc_sym


C:\zb\dd (28 hits)
Line 523: <6>[    0.290864] c1     34 __msm_rpc_connect: server not found 30000002:20001
Line 785: <4>[    1.247856] c1      1 msm_hsusb_rpc_connect: rpc connect success vers = 10001
Line 1295: <6>[    2.996253] c1      1 __msm_rpc_connect: server not found 30000002:20001
Line 1297: <7>[    2.996338] c1      1 msm_snd_rpc_connect failed (compatible VERS = 131073)trying again with another API
Line 1457: <6>[    3.035536] c1      1 __msm_rpc_connect: server not found 30000089:40001
Line 1461: <6>[    3.035646] c1      1 __msm_rpc_connect: server not found 30000089:10001
Line 1465: <6>[    3.035748] c1      1 __msm_rpc_connect: server not found 30000089:20001
Line 2437: <6>[    6.810278] c0    459 __msm_rpc_connect: server not found 30000013:30001
[1.251076] c1      1 *** __msm_rpc_connect[]: prog=0x30000064,vers=0x10001,found_prog=1

《《《ONCRPC》》》远程过程调用(RPC)
ret = dev->pdata->rpc_connect(1);????? 屏蔽此调用,MTP adb modem,serial都可以用,切换也正常。。
在modem端初始化service 
api/rapi/wiredconnectivity/inc/hsu_mdm_apis_rpc.h
/core/api/rapi/wiredconnectivity/src/hsu_mdm_apis_clnt.c
#if###########################################################15
十六进制/二进制 换算字节算法
先16进制换算到二进制
1)byte数除以1024(0000,0000,00) 是 kbyte数,即右移10位
2)再右移十位是 Mbyte,从byte右移20位(16进制右移5位)
3)再右移十位是 Gbyte,从byte右移30位(16进制右移7位+两个二进制位)


bit换算byte
1)除以8(000个比特)是byte数
#end###########################################################16
Linux在io.h头文件中声明了函数ioremap(),用来将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中//只有映射到虚拟空间,各个线程才能根据寄存器地址,来操作寄存器
void * ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
iounmap函数用于取消ioremap()所做的映射,原型如下:
void iounmap(void * addr);
这两个函数都是实现在mm/ioremap.c文件中。
#if#######################################################################################################################17
shared_irq  INT_USB_HS
resources_hsusb_otg[]
resources_gadget_peripheral[]
resources_hsusb_host[]
#end###########################################################18


#define INIT_WORK(_work, _func) \
do { \
__INIT_WORK((_work), (_func), 0);\
} while (0)

kworker 


參考檔案kernel/workqueue.c,kworker主要提供系統非同步執行的共用WorkerPool方案(WorkQueue),一般而言會區分為每個處理器專屬的WorkerPool或是屬於整個系統使用的WorkerPool
“kworker/A:B”後方的數字意義分別是A為CPU ID而B為透過ida_get_new配置的ID(範圍從0-0x7fffffff).以筆者雙核心的環境為例,以CPU#0來說,會透過kthread_create_on_node產生固
定在CPU#0上執行的[kworker/0:0],[kworker/0:1],[kworker/1:0]與[kworker/1:1].並透過kthread_create產生不固定在特定處理器上執行的[kworker/u:0]與[kworker/u:1].總共呼叫
create_worker執行六個執行gcwq(GlobalCPU Workqueue) worker thread function的KernelThread.
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
2 4 0 0 ? -1 S 0 0:01 \_[kworker/0:0]
2 5 0 0 ? -1 S 0 0:00 \_[kworker/u:0]
2 8 0 0 ? -1 S 0 0:00 \_[kworker/1:0]
2 10 0 0 ? -1 S 0 0:00 \_[kworker/0:1]
2 30 0 0 ? -1 S 0 0:00 \_[kworker/1:1]
2 46 0 0 ? -1 S 0 0:00 \_[kworker/u:1]
worker_thread 為WorkQueue機制的核心,包括新的WorkQueue產生(alloc_workqueue),指派工作到WorkQueue(queue_work),把工作指派到特定的處理器(queue_work_on),指派工作並設定延遲
執行(queue_delayed_work),在指定的處理器上指派工作並延遲執行(queue_delayed_work_on)..等.限於本次預定的篇幅,有關WorkQueue的進一步討論,會在後續文章中介紹.需要進一步資訊
的開發者,可以自行參閱LinuxKernel文件Documentation/workqueue.txt.
#if###########################################################19
97 static DECLARE_COMPLETION(pmic_vbus_init);
2501 wait_for_completion(&pmic_vbus_init);
3376 complete(&pmic_vbus_init);


wait_for_completion 把当前进程置为 TASK_UNINTERRUPTIBLE,可以多次锁定,并且等到每个调用者都complete后才会返回;
wait_event_interruptible 把当前进程置为TASK_INTERRUPTIBLE,只要wake_up_process就返回;
#end###########################################################20
adb shell
~#


/proc/interrupts
/proc/kmsg
/data/property/persist.xxx.xxx
#if###########################################################21
文件节点创建
/*linux-2.6.22/include/linux/device.h
struct class *class_create(struct module *owner, const char *name)
    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.*/
struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key)
android_class = class_create(THIS_MODULE, "android_usb");
/**
 * 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().
 */  device_create
 struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
 dev->dev = device_create(android_class, NULL,MKDEV(0, 0), NULL, "android0");
/**
608  * device_create_file - create sysfs attribute file for device.
609  * @dev: device.
610  * @attr: device attribute descriptor.
611  */
612 int device_create_file(struct device *dev,const struct device_attribute *attr)
err = device_create_file(dev->dev, attr);
///
create_group
#end#######################################################################################################################22
EHCI -- USB2.0 / OHCI -- USB1.1,配置EHCI的时候要配置OHCI,否则识别不了1.1的键盘/鼠标
host urb(usb request block),HCD
gadet udc
#if###########################################################23
USB 测试
Sencitivity--set_squelch_level


#end###########################################################24
log 缓存区大小设置


user_space


/CRATER-VE/android/kernel/drivers/staging/android/logger.clogger_init
    751 DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, LOGGER_1MB_SIZE)
    752 DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, LOGGER_512KB_SIZE)
    753 DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, LOGGER_2MB_SIZE)
    754 DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, LOGGER_512KB_SIZE)
kernel_space
/CRATER-VE/android/frameworks/native/cmds/dumpstate/utils.c
void do_dmesg() {
int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
int retval = klogctl(KLOG_READ_ALL, buf, size);
buf[retval] = '\0';
    printf("%s\n\n", buf);
}


CONFIG_LOG_BUF_SHIFT=17 /////??????
/CRATER-VE/android/system/core/toolbox/dmesg.c
/CRATER-VE/android/bootable/recovery/system.cpp
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) ///=131 072,与dmesg 出来的大小相同
#define KLOG_BUF_LEN (1 << KLOG_BUF_SHIFT)
defconfig CONFIG_LOG_BUF_SHIFT=17
1)单独修改defconfig中的SHIFT值到19,没有效果
2)继续修改dmesg.c中的值到19,单独编译覆盖toolbox,dmesg提示no permission,dumpstate大小增大,可以看到00开始的log
#if###########################################################25


############################################################26


########################################################################################################################27

/************************************************ // //TWKJ STM32开发板 // //作者: //版本:V1.0 //修改日期:2020/06/30 //程序功能:TFT彩屏显示方法 //V1.0 完成基本功能 ************************************************/ #include "my_lcd_spi_gui.h" #include "my_lcd_spi_font.h" /******************************************************************* * @name :void GUI_DrawPoint(u16 x,u16 y,u16 color) * @date :2018-08-09 * @function :draw a point in LCD screen * @parameters :x:the x coordinate of the point y:the y coordinate of the point color:the color value of the point * @retvalue :None ********************************************************************/ void GUI_DrawPoint(u16 x,u16 y,u16 color) { LCD_SetCursor(x,y);//设置光标位置 LCD_WriteData_16Bit(color); } /***************************************************************************** * @name :void TP_Draw_Big_Point(u16 x,u16 y,u16 color) * @date :2018-08-09 * @function :Draw a big point(2*2) * @parameters :x:Read x coordinate of the point y:Read y coordinate of the point color:the color value of the point * @retvalue :None ******************************************************************************/ void LCD_DrawPoint_big(u16 x,u16 y) { LCD_DrawPoint(x,y);//中心点 LCD_DrawPoint(x+1,y); LCD_DrawPoint(x,y+1); LCD_DrawPoint(x+1,y+1); } /******************************************************************* * @name :void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color) 填充一个矩形 * @function :fill the specified area * @parameters :sx:the bebinning x coordinate of the specified area sy:the bebinning y coordinate of the specified area ex:the ending x coordinate of the specified area ey:the ending y coordinate of the specified area color:the filled color value * @retvalue :None ********************************************************************/ void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color) { u16 i,j; u16 width=ex-sx+1;//得到填充的宽度 u16 height=ey-sy+1;//高度//**All notes can be deleted and modified**// for(i=0;i<height;i++) { for(j=0;j<width;j++) LCD_WriteData_16Bit(color);//写入数据 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口设置为全屏 } /******************************************************************* * @name :void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2) 绘制一条线 * @function :Draw a line between two points * @parameters :x1:the bebinning x coordinate of the line y1:the bebinning y coordinate of the line x2:the ending x coordinate of the line y2:the ending y coordinate of the line * @retvalue :None ********************************************************************/ void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { LCD_DrawPoint(uRow,uCol);//画点 //**All notes can be deleted and modified**// if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } /***************************************************************************** * @name :void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2) 绘制一个矩形框 * @function :Draw a rectangle * @parameters :x1:the bebinning x coordinate of the rectangle y1:the bebinning y coordinate of the rectangle x2:the ending x coordinate of the rectangle y2:the ending y coordinate of the rectangle * @retvalue :None ******************************************************************************/ void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2) { LCD_DrawLine(x1,y1,x2,y1); LCD_DrawLine(x1,y1,x1,y2); LCD_DrawLine(x1,y2,x2,y2); LCD_DrawLine(x2,y1,x2,y2); } /***************************************************************************** * @name :void LCD_DrawFillRectangle(u16 x1, u16 y1, u16 x2, u16 y2) 填充一个矩形 * @function :Filled a rectangle * @parameters :x1:the bebinning x coordinate of the filled rectangle y1:the bebinning y coordinate of the filled rectangle x2:the ending x coordinate of the filled rectangle y2:the ending y coordinate of the filled rectangle * @retvalue :None ******************************************************************************/ void LCD_DrawRectangle_Fill(u16 x1, u16 y1, u16 x2, u16 y2) { LCD_Fill(x1,y1,x2,y2,FRONT_COLOR); } /***************************************************************************** * @name :void _draw_circle_8(int xc, int yc, int x, int y, u16 c) 圆绘制方法 * @function :8 symmetry circle drawing algorithm (internal call) * @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center x:the x coordinate relative to the Circular center y:the y coordinate relative to the Circular center c:the color value of the circle * @retvalue :None ******************************************************************************/ void _draw_circle_8(int xc, int yc, int x, int y, u16 c) { GUI_DrawPoint(xc + x, yc + y, c); GUI_DrawPoint(xc - x, yc + y, c); GUI_DrawPoint(xc + x, yc - y, c); GUI_DrawPoint(xc - x, yc - y, c); GUI_DrawPoint(xc + y, yc + x, c); GUI_DrawPoint(xc - y, yc + x, c); GUI_DrawPoint(xc + y, yc - x, c); GUI_DrawPoint(xc - y, yc - x, c); } /***************************************************************************** * @name :void gui_circle(int xc, int yc,u16 c,int r, int fill) 绘制一个圆 实心或空心 * @function :Draw a circle of specified size at a specified location * @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radius fill:1-filling,0-no filling * @retvalue :None ******************************************************************************/ void LCD_DrawCircle(int xc, int yc,int r, int fill) { int x = 0, y = r, yi, d; d = 3 - 2 * r; if (fill) { // 如果填充(画实心圆) while (x <= y) { for (yi = x; yi <= y; yi++) { _draw_circle_8(xc, yc, x, yi, FRONT_COLOR); } if (d < 0) { d = d + 4 * x + 6; } else { d = d + 4 * (x - y) + 10; y--; } x++; } } else { // 如果不填充(画空心圆) while (x <= y) { _draw_circle_8(xc, yc, x, y, FRONT_COLOR); if (d < 0) { d = d + 4 * x + 6; } else { d = d + 4 * (x - y) + 10; y--; } x++; } } } /***************************************************************************** * @name :void Draw_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2) 绘制一个三角形框 * @function :Draw a triangle at a specified position * @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangular y1:the vertex y coordinate of the triangular x2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge * @retvalue :None ******************************************************************************/ void LCD_DrawTriangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2) { LCD_DrawLine(x0,y0,x1,y1); LCD_DrawLine(x1,y1,x2,y2); LCD_DrawLine(x2,y2,x0,y0); } static void _swap(u16 *a, u16 *b) { u16 tmp; tmp = *a; *a = *b; *b = tmp; } /***************************************************************************** * @name :void Fill_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2) 绘制一个三角形框填充 * @function :filling a triangle at a specified position * @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangular y1:the vertex y coordinate of the triangular x2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge * @retvalue :None ******************************************************************************/ void LCD_DrawTriangel_Fill(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2) { u16 a, b, y, last; int dx01, dy01, dx02, dy02, dx12, dy12; long sa = 0; long sb = 0; if (y0 > y1) { _swap(&y0,&y1); _swap(&x0,&x1); } if (y1 > y2) { _swap(&y2,&y1); _swap(&x2,&x1); } if (y0 > y1) { _swap(&y0,&y1); _swap(&x0,&x1); } if(y0 == y2) { a = b = x0; if(x1 < a) { a = x1; } else if(x1 > b) { b = x1; } if(x2 < a) { a = x2; } else if(x2 > b) { b = x2; } LCD_Fill(a,y0,b,y0,FRONT_COLOR); return; } dx01 = x1 - x0; dy01 = y1 - y0; dx02 = x2 - x0; dy02 = y2 - y0; dx12 = x2 - x1; dy12 = y2 - y1; if(y1 == y2) { last = y1; } else { last = y1-1; } for(y=y0; y<=last; y++) { a = x0 + sa / dy01; b = x0 + sb / dy02; sa += dx01; sb += dx02; if(a > b) { _swap(&a,&b); } LCD_Fill(a,y,b,y,FRONT_COLOR); } sa = dx12 * (y - y1); sb = dx02 * (y - y0); for(; y<=y2; y++) { a = x1 + sa / dy12; b = x0 + sb / dy02; sa += dx12; sb += dx02; if(a > b) { _swap(&a,&b); } LCD_Fill(a,y,b,y,FRONT_COLOR); } } /***************************************************************************** * @name :void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p) * @date :2018-08-09 * @function :Display a 16-bit BMP image * @parameters :x:the bebinning x coordinate of the BMP image y:the bebinning y coordinate of the BMP image p:the start address of image array * @retvalue :None ******************************************************************************/ void GUI_Drawbmp16(u16 x,u16 y,const u8 *p) //显示40*40 QQ图片 { int i; unsigned char picH,picL; LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置 for(i=0;i<40*40;i++) { picL=*(p+i*2);//数据低位在前 picH=*(p+i*2+1); LCD_WriteData_16Bit(picH<<8|picL); } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏 } /***************************************************************************** * @name :void LCD_ShowString(u16 x,u16 y,u8 size,u8 *p,u8 mode) 显示遗传英文字符 只限英文 * @function :Display English string * @parameters :x:the bebinning x coordinate of the English string y:the bebinning y coordinate of the English string p:the start address of the English string size:the size of display character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_JustString(u16 x,u16 y,char *p,u8 size) { while((*p<='~')&&(*p>=' '))//判断是不是非法字符! { if(x>(lcddev.width-1)||y>(lcddev.height-1)) return; LCD_ShowChar(x,y,*p,size,false); x+=size/2; p++; } } /***************************************************************************** * @name :u32 mypow(u8 m,u8 n) * @date :2018-08-09 * @function :get the nth power of m (internal call) * @parameters :m:the multiplier n:the power * @retvalue :the nth power of m ******************************************************************************/ u32 mypow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } /***************************************************************************** * @name :void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size) * @date :2018-08-09 * @function :Display number * @parameters :x:the bebinning x coordinate of the number y:the bebinning y coordinate of the number num:the number(0~4294967295) len:the length of the display number size:the size of display number * @retvalue :None ******************************************************************************/ void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/mypow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { LCD_ShowChar(x+(size/2)*t,y,' ',size,false); continue; }else enshow=1; } LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,false); } } //计算汉字字模的大小(字节数) u8 My_Font_GetCodeSize_CH(u8 charSize) { return charSize*(charSize/8 + (charSize%8?1:0)); } //计算ASCII字模的大小(字节数) u8 My_Font_GetCodeSize_ASCII(u8 charSize) { //**All notes can be deleted and modified**// return charSize*(charSize/8 + (charSize%8?1:0))*2; } void LCD_ScanLine_Byte(u16 x, u16 y, u8 *charPtr,u8 pointCount,bool overlap) { u8 i; if(pointCount>8) { pointCount = 8; } for(i=0;i<pointCount;i++) { // if((*charPtr)&(0x01<<i))//逆向扫描 if(((*charPtr)&(0x80>>i)))//顺向扫描 { if(overlap) { LCD_DrawPoint(x,y);//画一个点 } else { LCD_WriteData_16Bit(FRONT_COLOR); } } else { if(!overlap) { LCD_WriteData_16Bit(BACK_COLOR); } } x++; } } //显示字符或图片取模后的数据,如自定义特殊字符 void LCD_DrawMatrixCode(u16 x, u16 y, u8 width,u8 high,u8 *charPtr,bool overlap) { u8 i,scanPointCount; u16 x0 = x; LCD_SetWindows(x,y,x+width-1,y+high-1); for(i=0;i<high;i++)//逐行扫描 { scanPointCount = width;//计算出每一行的点数 while(scanPointCount>0)//如果这一行的点数大于7 { if(scanPointCount>7) { LCD_ScanLine_Byte(x,y,charPtr,8,overlap); scanPointCount -= 8; charPtr++; x += 8; } else { LCD_ScanLine_Byte(x,y,charPtr,scanPointCount,overlap); charPtr++; break; } } x = x0; y++; } } /***************************************************************************** * @name :void LCD_ShowChinese(u16 x, u16 y, u8 *s, u8 charSize,u8 mode) * @date :2018-08-09 * @function :Display a single Chinese character * @parameters :x:the bebinning x coordinate of the Chinese character y:the bebinning y coordinate of the Chinese character s:the start address of the Chinese character charSize:size of the Chinese character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_ShowChinese(u16 x, u16 y, u8 *s, u8 charSize,bool overlap) { u8 fontCodeSize,fontCharCount,*fontCodePtr; u16 k;//**All notes can be deleted and modified**// fontCodeSize = My_Font_GetCodeSize_CH(charSize)+2; switch(charSize) { case 12:fontCharCount = ArrayCount(fontGBK12);fontCodePtr = (u8 *)fontGBK12;break; case 16:fontCharCount = ArrayCount(tfont16);fontCodePtr = (u8 *)tfont16;break; case 24:fontCharCount = ArrayCount(tfont24);fontCodePtr = (u8 *)tfont24;break; case 32:fontCharCount = ArrayCount(tfont32);fontCodePtr = (u8 *)tfont32;break; default:break; } for (k=0;k<fontCharCount;k++)//遍历每个字模 { if ((*(fontCodePtr)==*(s))&&(*(fontCodePtr+1)==*(s+1)))//对比字符编码 { fontCodePtr+=2; LCD_DrawMatrixCode(x,y,charSize,charSize,fontCodePtr,overlap); break; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响 } fontCodePtr += fontCodeSize;//指向下一个字模的地址 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode) * @date :2018-08-09 * @function :Display a single English character * @parameters :x:the bebinning x coordinate of the Character display position y:the bebinning y coordinate of the Character display position num:the ascii code of display character(0~94) size:the size of display character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_ShowChar(u16 x,u16 y, u8 charCode,u8 charSize,bool overlap) { u8 *matrixPtr; if(x>(lcddev.width-charSize/2)||y>(lcddev.height-charSize)) return; charCode=charCode-' ';//得到偏移后的值 LCD_SetWindows(x,y,x+charSize/2-1,y+charSize-1);//设置单个文字显示窗口 switch(charSize) { case 12:matrixPtr=(u8 *)asc2_1206;break; case 16:matrixPtr=(u8 *)asc2_1608;break; #ifdef ACS_2412 case 24:matrixPtr=(u8 *)asc2_2412;break; #endif #ifdef ACS_3216 case 32:matrixPtr=(u8 *)asc2_3216;break; #endif default:break; } //**All notes can be deleted and modified**// LCD_DrawMatrixCode(x,y,charSize/2,charSize,matrixPtr,overlap); LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode) 显示一个字符串 可以为中文 显示的中文取模必须在放到lcd_font.h中 * @function :Display Chinese and English strings * @parameters :x:the bebinning x coordinate of the Chinese and English strings y:the bebinning y coordinate of the Chinese and English strings str:the start address of the Chinese and English strings size:the size of Chinese and English strings mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_ShowString(u16 x, u16 y, char *str,u8 charSize,bool overlap) { u16 x0=x; if(charSize>32)// { charSize = 32; } while(*str!=0)//数据未结束 { if((u8)(*str)<0x80) { if(*str=='\r')//回车符号 { y+=charSize; x=x0; if(*(str+1)=='\n')//换行符号 { str++; } } else { LCD_ShowChar(x,y,*str,charSize,overlap); x+=charSize/2; //字符,为全字的一半 } str++; } else//中文 { LCD_ShowChinese(x,y,(u8 *)str,charSize,overlap); str+=2; x+=charSize;//下一个汉字偏移 } } } /***************************************************************************** * @name :void Gui_StrCenter(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode) * @date :2018-08-09 * @function :Centered display of English and Chinese strings * @parameters :x:the bebinning x coordinate of the Chinese and English strings y:the bebinning y coordinate of the Chinese and English strings str:the start address of the Chinese and English strings size:the size of Chinese and English strings mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_StrCenter(u16 x, u16 y, char *str,u8 charSize,bool overlap) { u16 len=strlen((const char *)str); u16 x1=(lcddev.width-len*8)/2; LCD_ShowString(x1,y,str,charSize,overlap); } u16 LCD_GetPos_X(u8 charSize,u8 index)// { if(index<=lcddev.width/(charSize>>1)) { return index*(charSize>>1); } return 0; } u16 LCD_GetPos_Y(u8 charSize,u8 index)// { if(index<=lcddev.height/(charSize)) { return index*(charSize); } return 0; }
最新发布
05-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值