zoukankan      html  css  js  c++  java
  • linux内核编程笔记【原创】

    以下为本人学习笔记,如有转载请注明出处,谢谢

    1. service用法 oneshot

    DEFINE_MUTEX(buzzer_mutex);

    mutex_lock(&buzzer_mutex);

    mutex_unlock(&buzzer_mutex);

    static void WriteNumber(const char *fileName, int number)

    {                                                

             FILE *fp;                                                                                    

             fp = fopen(fileName, "w");                   

             if (fp == NULL) {                            

                 LCD_DEBUG("open %s error, errno %d ", fileName, errno);

                 return; 

             }     

            fprintf(fp, "%d", number);

            fclose(fp);

     }

    service aa /usr/bin/aa
    class core
    user root
    group root
    critical
    onrestart restart aa
    onrestart restart tt

    #service bbd /usr/bin/bb
    service bb /usr/bin/app_bbl_read
    user root
    group root
    oneshot

    2.【Shell脚本】怎样表示一个for循环

    作者:gnuhpc 
    出处:http://www.cnblogs.com/gnuhpc/

    在此说一下我常用的两个结构: 
    1. 
    for i in $(seq 1 100); do 
            echo $i 
    done 
    2. 
    for (( i = 1 ; $i <= 100; i++ )) ;do 
             echo $i; 
    done

    作者:gnuhpc 
    出处:http://www.cnblogs.com/gnuhpc/

    3.对于关闭抢占的内核接口

    看内核接口是同步还是异步,比方说msleep就是异步接口,会休眠让出cpu

    mdelay是忙等待,不会让出cpu

    如果是同步接口的话,对于单核cpu,就不会出现多进程同时调用同一个接口出错的情况

    如果是异步接口的话,就得具体问题具体分析,如果是仅仅避免多个进程调度同一个接口的情况的话,加信号量或者普通的锁就可以,不一定要加互斥锁,

    如果是又有中间层调度接口,又有用户态上层调度接口,那么就另当别论了

    spin_lock这种锁是用来多核cpu共同调用同个接口的问题,

    mutex_lock这种是会休眠,同个cpu的互斥锁,如果是进程上下文就可以用,如果是中断上下文就不能用这种锁,因为这种锁会休眠,中断中是不允许休眠的

    local_irq_save(flags);

    local_irq_restore(flags);

    spin_lock_irqsave(&iproc_bbl->lock, flags);

    spin_unlock_irqrestore(&iproc_bbl->lock, flags);

    4.网上大家经常碰到的不能连接问题:

    请在运行-cmd输入netstat -n 查看5222端口是否在建立状态 ESTABLISHED,这个方法来源自网络,部落没有遇到过.另外,还有一个,就是清空本地本地DNS缓存,具体步骤如下:

    在windows下运行运行菜单,开始->运行,输入"CMD"进行命令行窗口,然后输入 ipconfig/flushdns 按回车键

    5.休眠唤醒调试

    kernel/power/main.c中可以通过打印链表的信息,在休眠唤醒的时候将每个唤醒的源消耗的时间打印出来

     dpm_run_callback() ----》drivers/base/power

    6.中断中不可以加入打印

    中断处理函数应该避免调用不可重入函数, 因为新的中断可能发生并打断正在执行任务中,如果当前任务调用了一些不可重入的函数,将会产生错误。
    一些常用库函数如printf,malloc,free等都是不可重入函数,因为在函数中引用了全局变量, 这个道理因该很容易明白了吧?
    例如, printf会引用全局变量stdout,malloc,free会引用全局的内存分配表。

    arch/arm/kernel/debug.S:157: Error: too many positional arguments

    7.sys文件节点要注意返回值

    static inline ssize_t show_counter_sysfs(struct device *dev,
    struct device_attribute *attr, char *buf)
    {
    struct asiu_pwm_chip *asiu_pwm = dev_get_drvdata(dev);
    int i, n;
    long value;

    n=0;
    if(asiu_pwm) {
    for (i=0; i<6; i++) {
    value = __onepulse_pwm_counter_extend(i);
    n += sprintf(buf + n, "pwm_id(%d)----0x%x ", i, value);
    }
    return n;
    }
    else
    return -1;
    }

    static struct device_attribute sysfs_misc_list[] = {
    __ATTR(onepluse_counter,S_IRUGO , show_counter_sysfs, NULL),
    };

    /* tp info show include tp sw version, fw version, cfg csum, hw version */
    static ssize_t tp_show(struct kobject *kobj, struct kobj_attribute *attr,
    char *buf)
    {
    struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
    int len = 0;
    int retval;
    unsigned char config_id[4];

    if (NULL == rmi4_data || !f34_ctrl_base_addr)
    return -1;
    /* Get device config ID */
    retval = synaptics_rmi4_reg_read(rmi4_data,
    f34_ctrl_base_addr,
    config_id, sizeof(config_id));
    if (retval < 0) {
    dev_err(rmi4_data->pdev,
    "%s: Failed to read device config ID ", __func__);
    return -1;
    }
    len =
    scnprintf(buf + len, PAGE_SIZE, "SW:%s ",
    SYNAPTICS_DSX_DRV_VERSION);

    /* combine FW and CFG CSUM */
    #define SPLIT_TAG "_CFGID"

    len +=
    scnprintf(buf + len, PAGE_SIZE, "FW:%u%s%02x%02x%02x%02x ", rmi4_data->firmware_id,
    SPLIT_TAG,
    config_id[0],
    config_id[1],
    config_id[2],
    config_id[3]);
    /*
    len +=
    scnprintf(buf + len, PAGE_SIZE,
    "CFG ID:0x%02x 0x%02x 0x%02x 0x%02x ", config_id[0],
    config_id[1], config_id[2], config_id[3]);
    */
    /* add for chipset name */
    len += scnprintf(buf + len, PAGE_SIZE, "CHIP NAME:%s ", "synaptics");

    return len;
    }

    sys 文件节点写函数的时候,sh: write error: Bad address,这种错误一般是return没有返回正确的值,

    什么值是正确的呢?那就是count,长度这些才可以,那么系统是怎么识别的呢?要取决于文件系统和echo的实现

    static ssize_t test_sysfs_get_report_store(struct device *dev,
            struct device_attribute *attr, const char *buf, size_t count)
    {
        int retval;
        unsigned char command;
        unsigned long setting;
        struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;

        retval = sstrtoul(buf, 10, &setting);
        if (retval)
            return retval;

        printk("zbh 111 ");
        
        if (setting != 1) {
            printk("zbh %s(): ---> %d ", __func__, __LINE__);
            return -EINVAL;
        }

        mutex_lock(&f54->status_mutex);

        retval = test_check_for_idle_status();
        if (retval < 0) {
            printk("zbh %s(): ---> %d ", __func__, __LINE__);

            goto exit;
        }

        if (!test_report_type_valid(f54->report_type)) {
            dev_err(rmi4_data->pdev,
                    "%s: Invalid report type ",
                    __func__);
            retval = -EINVAL;
            printk("zbh %s(): ---> %d ", __func__, __LINE__);
            goto exit;
        }

        test_set_interrupt(true);

        command = (unsigned char)COMMAND_GET_REPORT;

        retval = synaptics_rmi4_reg_write(rmi4_data,
                f54->command_base_addr,
                &command,
                sizeof(command));
        if (retval < 0) {
            dev_err(rmi4_data->pdev,
                    "%s: Failed to write get report command ",
                    __func__);
            goto exit;
        }

    /* tddi f54 test reporting + */
    #ifdef F54_POLLING_GET_REPORT

        retval = test_sysfs_get_report_polling();
        if (retval < 0) {
            dev_err(rmi4_data->pdev,
                    "%s: Failed to get report image ",
                    __func__);
            printk("zbh 222 ");
            goto exit;
        }

    #else
    /* tddi f54 test reporting - */

        f54->status = STATUS_BUSY;
        f54->report_size = 0;
        f54->data_pos = 0;

        hrtimer_start(&f54->watchdog,
                ktime_set(GET_REPORT_TIMEOUT_S, 0),
                HRTIMER_MODE_REL);

        retval = count;

    #endif
        retval = count; // ===》如果去掉这一行的话,那么echo  1 > get_report 的话就会出现错误 sh: write error: Bad address

    exit:
        mutex_unlock(&f54->status_mutex);

        printk("zbh %s(): retval=%d---> %d ", __func__, retval, __LINE__);

        return retval;
    }

    因为bbl会影响打印机,1s=1000000us

    Bbl的时钟是32.768kHz,

    所以1000000/32768=30us左右

    也就是这个时钟的精度是30us,而bbl寄存器读status状态是延时10us,太短了,至少要在一个clock完成后再读,所以改成延时35us,

    8.shell脚本循环

    #!/bin/sh

    while true
    do
    let "i++"
    echo "is $i"
    done

    9.查看这些宏CONFIG_SMP在linux内核中是否有定义

    #ifndef CONFIG_SMP

    要去linux3.6.5目录下.config文件

    10.书写代码框架注意

    goto 和return

    static int asiu_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,

                                int duty_ns, int period_ns)

    {

           struct asiu_pwm_chip *asiu_pwm = to_asiu_pwm_chip(chip);

           struct asiu_pwm_cfg *pwm_cfg;

           unsigned long period_counts, dutyhi_counts;

           unsigned long prescale = 0;

           unsigned long long ticks;

           if (pwm_cfg->enabled) {

                  /* Change the PWM output with the new config */

            asiu_pwmc_disable(chip, pwm);

                  //asiu_pwmc_enable(chip, pwm);

           }

    #ifdef PWMC_DEBUG

           dev_info(chip->dev, "%s : [pwm-%d] duty_ns = %d, period_ns = %d ",

                                __FUNCTION__, pwm->hwpwm, duty_ns, period_ns);

    #endif

           if (duty_ns == 0 && period_ns ==0) {

                  /* PWM stay low, duty cycle = 0% */

                  prescale = 0;

                  period_counts = 0;

                  dutyhi_counts = 0;

           }

           else if (duty_ns >= period_ns) {

                  /* PWM stay high, duty cycle = 100% */

                  prescale = 0;

                  period_counts = ASIU_PWM_PERIOD_MASK;

                  dutyhi_counts = ASIU_PWM_DUTYHI_MASK;

           }

           else {

                  ticks = (unsigned long long)period_ns * asiu_pwm->tick_hz;

                  do_div(ticks, NSEC_PER_SEC);

                  period_counts = ticks;

                  prescale = period_counts >> ASIU_PWM_PEROID_WIDTH;

                  if(prescale & ~ASIU_PWM_PRESCALE_MASK) {

                         dev_warn(chip->dev, "%s(%d) : period_counts = %d, prescale = 0x%x ",

                                       __FUNCTION__, __LINE__, period_counts, prescale);

                         return -EINVAL;

                  }

                  ticks = (unsigned long long)duty_ns * asiu_pwm->tick_hz;

                  do_div(ticks, NSEC_PER_SEC);

                  dutyhi_counts = ticks;

           }

           pwm_cfg = pwm_get_chip_data(pwm);

           if (!pwm_cfg) {

                  dev_warn(chip->dev, "fail to get pwm config data ");

                  return -ENOMEM;

           }

           pwm_cfg->prescale = prescale;

           pwm_cfg->period_cnt = period_counts;

           pwm_cfg->dutyhi_cnt = dutyhi_counts;

       

           if (pwm_cfg->enabled) {

                  /* Change the PWM output with the new config */

                 //asiu_pwmc_disable(chip, pwm);

                  asiu_pwmc_enable(chip, pwm);

           }

    #ifdef PWMC_DEBUG

           dev_info(chip->dev, "%s : pwm_cfg->prescale = %d, period_cnt = %d, dutyhi_cnt = %d ",

                         __FUNCTION__, pwm_cfg->prescale, pwm_cfg->period_cnt, pwm_cfg->dutyhi_cnt);

    #endif

           return 0;

    }

    对于如上框架:

    进入config函数时先pwm_disable, 然后中间计算,最后enable

    但是中间有很多return,我们做接口的目的有个宗旨

    函数是为了改变原来的状态的,如果此函数运行失败返回,那么就要还原原来的场景,不要改变原来的场景

    如上例子如果用中间用return,一开始执行了disable,那么中间如果执行失败return了,后面就不会执行enable,那么pwm状态就会变了,那么对于这种情况我们要使用goto到后面,然后再进行enable,就算失败了,也要还原之前的场景去enable,所以需要把上一次的值保存起来。

    11.vim快捷键

    vi  -d   a.c   b.c,可以对比

    对比过程中,如果拷贝的话,可以用快捷键dp

    12.对触摸屏中断的理解

    触摸屏与cpu是由一个gpio中断口线相连,所有的中断都是由tp那端抛给cpu的,

    Tp通过设定各种参数,刷新频率,扫描频率,电容值(即基准点),tp通过计算触摸屏上的点来决定是否发送中断给cpu,如果计算到没点,就不发送中断给cpu,如果计算到有点,那么就会发送中断给cpu,(注意:tp只要上电启动了那么就会一直进行运算),每次触摸屏上只要有按下,不管几个手指都会产生一个中断,抬起又产生一个中断,最小单位产生两个中断,如果是电平中断,一直按着手指,会不停的产生中断,产生中断的时间和次数由tp的运算速度决定,很难去量化,按下的手指越多,tp运算时间越长,至于有时候发现log有10个finger,和10个status状态,那是驱动代码在一个中断产生时遍历了report动作10次,这些finger和status是通过tp寄存器读取到再由驱动上报内核空间,最终通过input子系统发送给用户空间

     ===========================================================================================

    13.怎么样让编译器对某些函数不再抱怨warning: unused parameter ‘xxx’?

    转自:https://segmentfault.com/q/1010000002395334

    #define UNUSED_PARAMETER(x) (void)x 

    int main(int argc, char **argv)

    {

    // 这两行是为了避免编译报警告

      UNUSED_PARAMETER(argc);
      UNUSED_PARAMETER(argv);

    }

    如果可能,请务必用正常方法消除 warning,真的多余就去掉吧

    方法一:

    void foo(int a) {
        (void)a;
        // ...
    }
    

    方法二:

    #ifdef __GNUC__
    #  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
    #else
    #  define UNUSED(x) UNUSED_ ## x
    #endif
    
    void foo(int UNUSED(a)) {
        // ...
    }
    

    参考:http://stackoverflow.com/a/12891181

     ===========================================================================================

    字符串比较时,strncmp   strcmp 需要注意的地方,要注意比较长度 

    if ((strlen(ts_keyword) != strlen(fw_ugd->ts_keyid)) ||
    strcasecmp(ts_keyword, fw_ugd->ts_keyid)) {
    printf("%s: check ts_keyword[%s],fw_ugd->ts_keyid[%s] ",
    __FUNCTION__, ts_keyword, fw_ugd->ts_keyid);
    retval = TP_FW_ERR_TS_KEYID_COMPARE;
    goto error;
    }

    中断 IRQF_ONESHOT 与 IRQF_SHARED 不能同时使用
    当多个设备共享中断时,由于IRQF_ONESHOT会关闭中断线程的中断,而线程一般执行时间会比较长,所以是不允许的
    当hardirq函数为NULL时,必须声明IRQF_ONESHOT, 表示threadirq线程中关闭该中断,在某些情况下,这个标志会非常有用
    例如:设备是低电平产生中断,而硬中断函数为NULL,如果不使用IRQF_ONESHOT,就会一直产生中断执行NULL函数,中断线程
    得不到执行,声明IRQF_ONESHOT后,会执行完线程才使能该中断  


    14.devm_request_irq---- 这种架构会自己释放资源,不需要自己释放,交由devr内核链表管理

    http://lxr.free-electrons.com/ident?i=devm_request_irq

    15.这个网址可以查询内核源码

    16.rm命令

    删除除了 tt.c的所有文件,只保留tt.c不被删除
    rm -rf !(tt.c)

    17.查看当前项目有哪些远程仓库

    $ git remote 
    

    bixiaopeng@bixiaopengtekiMacBook-Pro wirelessqa$ git remote origin

    查看远程仓库

    $ git remote -v 
    
    bixiaopeng@bixiaopengtekiMacBook-Pro wirelessqa$ git remote -v
    origin     git@gitlab.***.com:xiaopeng.bxp/wirelessqa.git (fetch)
    origin     git@gitlab.***.com:xiaopeng.bxp/wirelessqa.git (push)


    0x1000 16*16*16=4096bit = 4KB


    18.堆栈的限制

      堆栈空间的最大值是由setrlimit系统调用确定的,也可以通过bash内建的ulimit命令来设定和查看.

      例如:

      查看当前可使用的最大堆栈(以KB为单位)

      ulimit -s

      8192 //栈的大小默认是8M

      设定为最大的使用堆栈为15KB

      ulimit -s 15

      此时执行ls将会得到一个段错误.

      ls -l /etc/

      total 1040

      Segmentation fault

      通过用strace跟踪ls命令,将发现有如下的系统调用

      getrlimit(RLIMIT_STACK, {rlim_cur=15*1024, rlim_max=15*1024}) = 0

      说明当前可用的堆栈空间,已经不足以运行strace命令了.

    19.Linux驱动调试中的Debugfs的使用简介

    http://blog.csdn.net/wealoong/article/details/7992071

    Linux DebugFS 子目录也是用debugfs_create_dir来实现

    http://blog.csdn.net/superkris/article/details/8626517

    mount来调试文件节点, sysfs节点调试方法

    make menuconfig ----

    Global build settings ------

    Compile the kernel with Debug FileSystem enabled

    Make kernel_menuconfig  --------------

    Kernel hacking --------

    Debug Filesystem

    mount -t debugfs none /sys/kernel/debug

    20.grep 命令

    grep -run "< abc >"


    21.检测内存泄露的方法

    Make  kernel_menuconfig

    Kernel hacking =======>

    [*] Kernel memory leak detector  

    (40000) Maximum kmemleak early log entries

    [*] Compile the kernel with debug info  

    make menuconfig

    [*] Compile the kernel with Debug FileSystem enabled

    [*] Compile the kernel with debug information

    开机后

    mount -t debugfs none /sys/kernel/debug

    cd  /sys/kernel/debug

    cat kmemleak

    make  kernel_menuconfig

    这个选项是说明

    General setup ================>

    Choose SLAB allocator (SLUB (Unqueued Allocator))

    (X) SLUB (Unqueued Allocator)

    [*] Enable SLUB debugging support

    22.这里使用slub分配内存比slab更高效

    我们在调试内核时,如果出现系统响应非常慢的情况

    先看有没有死锁,用lockdep来检测

    检测出来后再用ftrace来跟踪函数

    如果出现kernel内存泄露,可以 用kmemleak来查看,查看前要确认内核使用哪个分配器,一般是slab或者slub

     cat /proc/meminfo     查看内存泄露

    23.Linux设备驱动之semaphore机制

    static noinline void __down(struct semaphore *sem);
    static noinline int __down_interruptible(struct semaphore *sem);
    static noinline int __down_killable(struct semaphore *sem);
    static noinline int __down_timeout(struct semaphore *sem, long jiffies);
    static noinline void __up(struct semaphore *sem);

    #define DEFINE_SEMAPHORE(name)
    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

    static inline void sema_init(struct semaphore *sem, int val)
    {
    static struct lock_class_key __key;
    *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
    lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
    }

    一个核,执行了两个死循环进程,那么这两个进程是通过内核的调度算法去选择要执行哪个进程的,最终会执行arm的指令,这两个进程在单和上是永远不可能同时执行的,MMU里面会有进程id寄存器

    24.获得内核函数地址的四种方法 

     本文以获取内核函数 sys_open()的地址为例。
       1)从System.map文件中直接得到地址
          $ grep sys_open /usr/src/linux/System.map
       
       2)使用 nm 命令
          $ nm vmlinuz | grep sys_open
       
       3)从 /proc/kallsyms 文件获得地址
          $ cat /proc/kallsyms | grep sys_open
       
       4)使用 kallsyms_lookup_name() 函数
          是在kernel/kallsyms.c文件中定义的,要使用它必须启用CONFIG_KALLSYMS编译内核。
          kallsyms_lookup_name()接受一个字符串格式内核函数名,返回那个内核函数的地址。
            kallsyms_lookup_name("sys_open");

    方法一、

    通过打印函数地址,可以查看函数在哪里调用

    例如:

    Core.c   driverspwm

    int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)

    {

             if (!pwm || period_ns == 0 || duty_ns > period_ns)

                       return -EINVAL;

        printk("%s  driverspwm Core.c----(%d) ", __func__, __LINE__);

        printk("pwm->chip->ops->config=%p----(%d) ", pwm->chip->ops->config, __LINE__);

             return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);

    }

    终端显示如下:

    [   42.550000] pwm->chip->ops->config=c001b0c0----(378)

    然后可以在

    如下目录

    Z:linux-3.6.5

    中的System.map中找到

    c001b0c0  t  asiu_pwmc_config

    就调用的是这个函数asiu_pwmc_config

    方法二、

    dump_stack()函数

    25.打印语句的使用,带颜色的打印

    #define RESETCOLOR "33[0m"
    #define GREEN "33[0;32m"
    #define RED "33[0;31m"
    #define LIGHT_RED "33[1;31m"
    #define YELLOW "33[1;33m"
    #define BLUE "33[0;34m"
    #define LIGHT_BLUE "33[1;34m"
    #define CYAN "33[0;36m"
    #define PURPLE "33[0;35m"
    #define LIGHT_PURPLE "33[1;35m"
    #define BROWN "33[0;33m"
    #define WHITE "33[1;37m"
    #define LIGHT_GRAY "33[0;37m"
    #define DARY_GRAY "33[1;30m"

    printf(YELLOW"**   10. set asiu_pwm while                               **"RESETCOLOR" ");

    printf(YELLOW"**"LIGHT_RED" 4. onepluse pwm disable "YELLOW"**"RESETCOLOR" ");

    RC文件延时方法

    wait  /dev/zhangb   随便一个不存在的节点都可以,固定为延时5s 

    如何增加打印信息---灵活使用宏定义:

    #include <stdio.h>
    #include <stdlib.h>

    #define qWiFiDebug(format, ...) printf("[WiFi] "format" File:%s, Line:%d, Function:%s ", ##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__);


    int main(void)
    -{
    | qWiFiDebug("aaaaaa -----");
    |
    | return 0;
    |}

    打印输出:

      ./a.out 

    [WiFi] aaaaaa ----- File:a.c, Line:9, Function:main

    #define RESETCOLOR    "33[0m"
    #define GREEN         "33[0;32m"
    #define RED           "33[0;31m"
    #define LIGHT_RED     "33[1;31m"
    #define YELLOW        "33[1;33m"
    #define BLUE          "33[0;34m"
    #define LIGHT_BLUE    "33[1;34m"
    #define CYAN          "33[0;36m"
    #define PURPLE        "33[0;35m"
    #define LIGHT_PURPLE  "33[1;35m"
    #define BROWN         "33[0;33m"
    #define WHITE         "33[1;37m"
    #define LIGHT_GRAY    "33[0;37m"
    #define DARY_GRAY     "33[1;30m"
    
    #define ZBH_TRACE_DEBUG            (1 << 0)
    #define ZBH_TRACE_INIT                (1 << 1)
    #define ZBH_TRACE_INT              (1 << 2)
    #define ZBH_TRACE_X_Y_COORDINATE   (1 << 3)
    #define ZBH_TRACE_FINGER_UP        (1 << 4)
    
    
    #ifdef __BASE_FILE_NAME__
    #define printk_get_basename(x)   __BASE_FILE_NAME__
    #else
    static char *printk_get_basename(char *path)
    {
        char *p1 = path, *p2 = p1;
        while (*p1 != '') {
            if (*p1 == '/')
                p2 = p1 + 1;
            p1++;
        }
        return (p2);
    }
    #endif
    
    //printk(KERN_INFO "[%s]"format"File:%s, Line:%d, Function:%s 
    ", 
            //      ##__VA_ARGS__, printk_get_basename(__FILE__), __LINE__, __FUNCTION__); 
    //printk(KERN_INFO "[%s%4d@%18s] "format, GT1X_PREFIX, __LINE__, printk_get_basename(__FILE__), ##arg); 
    //printk(KERN_INFO "[%s]"format"[File:%s, Line:%d, Function:%s] 
    ", ZBH_PREFIX, ##arg, printk_get_basename(__FILE__), __LINE__, __FUNCTION__); 
    
    #define ZBH_PREFIX   "ZBH: "
    #define zbh_trace(flag, format, arg...) 
    do { 
        if (zbh_trace_param & flag) 
            printk(KERN_INFO "[%s%4d@ %s] %s(): "format, ZBH_PREFIX, __LINE__, 
                printk_get_basename(__FILE__), __FUNCTION__, ##arg);             
    } while (0)
    
    #define zbh_printk(format, arg...) 
            printk(KERN_INFO "%s"format, ZBH_PREFIX, ##arg)

    26.linux用户栈和内核栈的设置

    http://stackoverflow.com/questions/2562602/how-does-fork-return-for-child-process

    http://blog.csdn.net/u011279649/article/details/18795547

    copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct * p, struct pt_regs * regs)

    How to set the new process entry

    int

    copy_thread(unsigned long clone_flags, unsigned long stack_start,
            unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
    {
        struct thread_info *thread = task_thread_info(p);
        struct pt_regs *childregs = task_pt_regs(p);

        *childregs = *regs;
        childregs->ARM_r0 = 0;
        childregs->ARM_sp = stack_start;

        memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
        thread->cpu_context.sp = (unsigned long)childregs;
        thread->cpu_context.pc = (unsigned long)ret_from_fork;

    27.makefile编写注意:

    EXTRA_CFLAGS += -DDO_TEST_REPORTING

    ifeq ($(CONFIG_ENABLE_PCI),y)

    EXTRA_CPPFLAGS += -DCONFIG_ENABLE_PCI

    endif

    28.好的网址

    http://web.mit.edu/gnu/www/index.html -------》麻省理工大学的校网,gnu  , automake , autoconf

    www.yoctoproject.org --------》飞思卡尔搞的非常强大的linux开发环境

    29.文件系统操作,查看内核一些信息

     cat /proc/meminfo 

    /data/app # cat /proc/meminfo
    MemTotal: 60488 kB
    MemFree: 19200 kB
    Buffers: 0 kB
    Cached: 27028 kB
    SwapCached: 0 kB
    Active: 11276 kB
    Inactive: 22708 kB
    Active(anon): 11256 kB
    Inactive(anon): 13432 kB
    Active(file): 20 kB
    Inactive(file): 9276 kB
    Unevictable: 0 kB
    Mlocked: 0 kB
    SwapTotal: 0 kB
    SwapFree: 0 kB
    Dirty: 0 kB
    Writeback: 0 kB
    AnonPages: 6976 kB
    Mapped: 2832 kB
    Shmem: 17732 kB
    Slab: 3448 kB
    SReclaimable: 668 kB
    SUnreclaim: 2780 kB
    KernelStack: 496 kB
    PageTables: 312 kB
    NFS_Unstable: 0 kB
    Bounce: 0 kB
    WritebackTmp: 0 kB
    CommitLimit: 30244 kB
    Committed_AS: 46220 kB
    VmallocTotal: 319488 kB
    VmallocUsed: 21720 kB
    VmallocChunk: 294908 kB

    /data/app # cat /proc/mtd
    dev: size erasesize name
    mtd0: 000c0000 00020000 "boot"
    mtd1: 00080000 00020000 "nvram_fac"
    mtd2: 000c0000 00020000 "boot_res"
    mtd3: 00400000 00020000 "kernel"
    mtd4: 00600000 00020000 "ramdisk"
    mtd5: 00600000 00020000 "base"
    mtd6: 06e00000 00020000 "data"

    30.find 命令和grep命令

     find . "*sdio*" -maxdepth 2

    find . README -maxdepth 1 | xargs grep -nri "a"

    find target/linux/brcm5830/files/arch/arm/mach-iproc/pm_iproc/ -name "*.c" -print | xargs grep "USB"

    find ./package/kmod-prolin/bbl/ -maxdepth 1 -print | xargs grep -rni "PCI" 

    find ./ -name "synaptics_dsx_core.h"  | xargs grep -rwi "reset_device"

     find ./package/kmod-brcm5830x/input/keypad_matrix/src/keypad_matrix.c -print0 |xargs grep -run -B8 -A2 "buzzer_level"

     find ./ -name "*.c" |xargs grep --colour -run printf

    dev_dbg(rmi4_data->pdev,
    "%s: rmi4_data->report_type = %d "
    "rmi4_data->finger_limit = %d "
    "fhandler->num_of_data_points = %d ",
    __func__, rmi4_data->report_type,
    rmi4_data->finger_limit, fhandler->num_of_data_points);

    这是个小技巧,grep的A(after,后)选项和B(before,前)选项可以同时输出其匹配行的前后几行。
    
    比如包含有如下文本的message.txt:
    
    Aug 5 02:43:12 zion kernel: [ 0.000000] Zone PFN ranges: Aug 5 02:43:12 zion kernel: [ 0.000000] DMA 0 -> 4096 Aug 5 02:43:12 zion kernel: [ 0.000000] Normal 4096 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] HighMem 130730 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] early_node_map[1] active PFN ranges Aug 5 02:43:12 zion kernel: [ 0.000000] 0: 0 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] DMI 2.3 present.
    
    用带-B1和-A2选项的grep匹配搜索"DMA"。
    
    grep -B1 -A2 "DMA" message.txt
    
    输出:
    
    Aug 5 02:43:12 zion kernel: [ 0.000000] Zone PFN ranges: Aug 5 02:43:12 zion kernel: [ 0.000000] DMA 0 -> 4096 Aug 5 02:43:12 zion kernel: [ 0.000000] Normal 4096 -> 130730 Aug 5 02:43:12 zion kernel: [ 0.000000] HighMem 130730 -> 130730
    
    grep匹配一个结果,输出多行的功能,在搜索日志文件时很有用。
    Linux下find一次查找多个指定文件或者排除某类文件,在 GREP 中匹配多个关键字的方法
    (1)Linux下find一次查找多个指定文件:
    查找a.html和b.html
    find . -name "a.html"  -name "b.html"  
    
    find . -regex '.*.txt|.*.doc|.*.mp3'
    find . -regex '.*.txt|.*.doc|.*.mp3'  
    ./a.txt  
    ./a.doc  
    ./a.mp3  
    
    (2)排除某些文件类型:
    排除目录下所有以html结尾的文件:
    find . -type f ! -name "*.html"    
    
    find . -type f ! -name "*.html"       
    ./ge.bak.02.09  
    ./ge.html.changed.by.jack  
    ./a.txt  
    ./a.doc  
    ./a.mp3  
    
    (3)排除多种文件类型的示例:
    find . -type f ! -name "*.html" -type  f ! -name "*.php" -type  f ! -name "*.svn-base"  -type  f ! -name "*.js"  -type  f ! -name "*.gif"  -type  f ! -name "*.png"  -type  f ! -name "*.cpp"  -type  f ! -name "*.h"  -type  f ! -name "*.o"  -type  f ! -name "*.jpg"  -type  f ! -name "*.so"  -type  f ! -name "*.bak"  -type  f ! -name "*.log"3)在 GREP 中匹配多个关键字的方法:
    grep查找多个数字的文件:
    -r 递归,-E:正则  -l:只显示文件名
    root@116.255.139.240:~/a# grep -r -E '0341028|100081|10086|10001' *  
    a.txt:100081  
    b.txt:10086  
    c/cc.txt:0341028  
    c/cc.txt:100081  
    c/cc.txt:10086  
    c/cc.txt:10001  
    c.txt:10001  
    d.txt:0341028  
    
    grep -r  -E -l '0341028|100081|10086|10001' *     
    a.txt  
    b.txt  
    c/cc.txt  
    c.txt  
    d.txt  
    
    多种类型文件示例:
    view plainprint?
    find . -name "*.html" -o -name "*.js"|xargs grep -r "BusiTree"   

    31.printk 调试方法

    内核中打印回调函数的名称

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <asm/current.h>
    #include <linux/utsname.h>
    #include <asm/cacheflush.h>
    #include <asm/processor.h>
    #include <asm/thread_notify.h>
    #include <asm/stacktrace.h>
    #include <asm/mach/time.h>

    // add by zbh
    int get_func_name(void *ip)
    {    

        printk("[<%p>] %pS ", (void *) ip, (void *) ip);
        
        printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s ",
            KERN_DEFAULT, raw_smp_processor_id(),
            current->pid, current->comm,
            print_tainted(), init_utsname()->release,
            (int)strcspn(init_utsname()->version, " "),
            init_utsname()->version);
        
        return 0;
    }

    void *ip = NULL;
      ip = keydata->buzzer->enable; printk("[<%p>] %pS ", (void *) ip, (void *) ip); printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s ", KERN_DEFAULT, raw_smp_processor_id(), current->pid, current->comm, print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), init_utsname()->version); keydata->buzzer->enable(keydata,freq,duty);


    再在panic.c中 找到print_tainted
    EXPORT_SYMBOL(print_tainted);
    这样可以给其他驱动调用此函数

    print_hex_dump ===>内核一个不错的打印方式

    此网址是我记录的一个printk 打印函数地址的方法

     http://www.cnblogs.com/sky-heaven/p/7161373.html

        unsigned char input[0x28];
        unsigned char output[0x28];

            print_hex_dump(KERN_CRIT, "bbl_ram@ ", DUMP_PREFIX_OFFSET,
                           16, 1, output, sizeof(output), true);
            printk(" "); 

     __builtin_return_address

    http://www.cnblogs.com/sky-heaven/p/7161404.html

    printk("33[1;31m %p---%pS 33[0m
    ", __builtin_return_address(0), __builtin_return_address(0));
    #define BF3005_PREFIX   "bf3005: "
    #define bf3005_trace(flag, format, arg...) 
    do { 
        if (bf3005_trace_param & flag) 
            printk(KERN_ERR "[%s%4d@%18s] "format, BF3005_PREFIX, __LINE__, printk_get_basename(__FILE__), ##arg);  
    } while (0)
    
    #define bf3005_printk(format, arg...) 
        printk(KERN_ERR "%s"format, BF3005_PREFIX, ##arg)
    
    bf3005_trace(BF3005_TRACE_DESCR, "enter %s(initialized = %d)
    ",
                 __func__, bf3005->initialized);

    方法1:

    //#define MY_DEBUG
    #ifdef MY_DEBUG
    #define MY_DBG(x...) do{printk(x);}while(0)
    #else
    #define MY_DBG(x...)
    #endif

    方法2:

    驱动可以如下写:

    #define MY_LEVEL1 (1 << 0)
    #define MY_LEVEL2 (1 << 1)

    unsigned int my_trace_param=0;
    module_param_named(trace, my_trace_param, uint, S_IRUGO|S_IWUSR);


    #define MY_DBG(flag, msg...)
    do {
    if (my_trace_param & flag)
    printk(KERN_ERR "zbh-debug: " msg);
    } while (0)

    MY_DBG(MY_LEVEL1, "Goodbye module exit1. ");
    MY_DBG(MY_LEVEL2, "Goodbye module exit2. ");
    MY_DBG(MY_LEVEL2, "Goodbye module exit3. ");

    测试:

    insmod my_printk_driver.ko 

    echo 2 > /sys/module/my_printk_driver/parameters/trace 

    这样就可以选择到底打印哪一条语句,用来动态调试开关,默认关打印

    code:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/kernel.h>
    #include<linux/slab.h>        //kmalloc
    #include<asm/io.h>            //ioremap
    #include<linux/device.h>    //class_create/device_create
    #include <asm/uaccess.h>
    #include <linux/pwm.h>
    #include <linux/cdev.h>
    #include <pax/gpio_cfg.h>
    #include <pax/bcm5830x_gpio_def.h>
    #include <mach/iproc_regs.h>
    #include <mach/memory.h>
    #include <mach/iomux.h>
    #include <linux/delay.h>
    #include <linux/gpio.h>
    #include <linux/timer.h>
    #include <linux/hrtimer.h>
    #include <linux/ktime.h>
    
    #define PWM_IOC_MAGIC         'n'
    #define PWM_CONFIG            _IOW(PWM_IOC_MAGIC, 1, int)
    #define PWM_DISABLE            _IOW(PWM_IOC_MAGIC, 2, int)
    #define ONE_PWM_CONFIG      _IOW(PWM_IOC_MAGIC, 3, int)
    #define ONE_PWM_DISABLE     _IOW(PWM_IOC_MAGIC, 4, int)
    #define ONE_PWM_WHILE_10000 _IOW(PWM_IOC_MAGIC, 5, int)
    #define SET_PWM_GPIO        _IOW(PWM_IOC_MAGIC, 6, int)
    #define SET_PWM_POLATIRY    _IOW(PWM_IOC_MAGIC, 7, int)
    #define READ_ONEPLUSE_COUNTER  _IOW(PWM_IOC_MAGIC, 8, int)
    #define SET_PWM_FUNC           _IOW(PWM_IOC_MAGIC, 9, int)
    #define SET_PWM_WHILE           _IOW(PWM_IOC_MAGIC, 10, int)
    #define ONE_PWM_DOORBELL           _IOW(PWM_IOC_MAGIC, 11, int)
    
    
    #define MY_LEVEL1                    (1 << 0)
    #define MY_LEVEL2                    (1 << 1)
    
    unsigned int my_trace_param = 0;
    module_param_named(trace, my_trace_param, uint, S_IRUGO|S_IWUSR);
    
    
    #define MY_DBG(flag, msg...) 
        do { 
            if (my_trace_param & flag) 
                printk(KERN_ERR "zbh-bbl: " msg); 
        } while (0)
    
    
    static int ttime = 0;
    static int pmode = 0; // pmode=0 ----> asiu_pwmc , pmode=1 ----> onepluse
    
    module_param(ttime, int, 0);
    module_param(pmode, int, 0);
    
    
    //module_param(period, int, 0);
    
    #define HELLO_MAJOR 230
    int hello_major = HELLO_MAJOR;
    
    module_param(hello_major, int, 0);
    
    static struct cdev *hello_cdev = NULL;
    static struct class *dev_class = NULL;
    static struct device *dev_device = NULL;
    
    
    static int hello_open(struct inode *inode, struct file *filp);
    static int hello_release(struct inode *inode, struct file *filp);
    
    static int hello_open(struct inode *inode, struct file *filp)
    {
        printk("hello_open is OK
    ");
        return 0;
    }
    
    static int hello_release(struct inode *inode, struct file *filp)
    {
        printk("hello_release is OK
    ");
    
        printk("pwm disable and free
    ");
        return 0;
    }
    
    struct file_operations hello_ops = {
        .owner    = THIS_MODULE,
        .open    = hello_open,
        .release     = hello_release,
        //.unlocked_ioctl = hello_ioctl,
    };
    
    static int __init hello_init(void)
    {
        dev_t devno;
        int ret;
    
        devno = MKDEV(hello_major, 0);
        ret = register_chrdev_region(devno, 1, "zbh_hello");
        if (!ret) {
            printk("register dev OK.
    ");
        }
        else {
            printk("register dev failed.
    ");
        }
    
        hello_cdev = cdev_alloc();
        cdev_init(hello_cdev, &hello_ops);
        cdev_add(hello_cdev, devno, 1);
        hello_cdev->owner = THIS_MODULE;
        hello_cdev->ops = &hello_ops;
    
        dev_class = class_create(THIS_MODULE, "dev_class");
        if (IS_ERR(dev_class)) {
            printk(KERN_ERR "class_create() failed for dev_class
    ");
            ret = -EINVAL;
            goto out_err_1;
        }
    
        dev_device = device_create(dev_class, NULL, devno, NULL, "zbh_hello");
        if (IS_ERR(dev_device)) {
            printk(KERN_ERR "device_create failed.
    ");
            ret = -ENODEV;
            goto out_err_2;
        }
        
        printk("Hello module init OK.
    ");
    
        return 0;
    
    out_err_2:
        class_destroy(dev_class);
    
    out_err_1:
        unregister_chrdev_region(MKDEV(hello_major, 0), 1);
        cdev_del(hello_cdev);
        return ret;
    }
    
    static void __exit hello_exit(void)
    {
        cdev_del(hello_cdev);
    
        device_destroy(dev_class, MKDEV(hello_major, 0));
        class_destroy(dev_class);
    
        unregister_chrdev_region(MKDEV(hello_major, 0), 1);
    
        MY_DBG(MY_LEVEL1, "Goodbye module exit1.
    ");
        MY_DBG(MY_LEVEL2, "Goodbye module exit2.
    ");
        MY_DBG(MY_LEVEL2, "Goodbye module exit3.
    ");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("zhangbinghua");
    MODULE_DESCRIPTION("zhangbh debug driver");
    View Code

     32.container_of的用法

    typedef struct
    {
    u32* row_gpios;
    u8 row_size;
    u32* col_gpios;
    u8 col_size;
    tKEYCODE* keytable;
    u16 keytable_size;
    u8 debounce_ms;
    int bl_gpio;
    int buzzer_gpio; /* if gpio dimming */
    int buzzer_pwm_id; /* if pwm controllor */
    int ped_enable;
    struct delayed_work work;
    char * amp_pwr;
    HOT_KEY_TAB *hot_key_table;
    int hot_key_table_size;
    struct delayed_work hot_key_work;
    }tKEYPAD_MATRIX_DATA;
    #endif

    INIT_DELAYED_WORK(&matrix_global_dat.key_data->hot_key_work, hot_key_scan);

    static void hot_key_scan(struct work_struct *work)
    {
    int index;
    int has_evnet=0;
    tKEYPAD_REPORT_DATA report_key;

    tKEYPAD_MATRIX_DATA *keypad = container_of(work,tKEYPAD_MATRIX_DATA, hot_key_work.work);

    if(get_hot_key_scan_code(keypad))

    }

    INIT_WORK(&wnet_power_on_wq, gprs_mu709_power_on);

    schedule_work(&wnet_power_on_wq);
    flush_work(&wnet_power_on_wq); //  flush_work可以阻塞,是同步机制,如果去掉此函数就是异步机制

    static void gprs_mu709_power_on(struct work_struct *work __attribute__((unused)))
    {
    gprs_mu709_opt(WNET_POWER_ON_WQ);
    }

    vim使用

    Vim

    zR  全部展开

    zM全部合并

    vim  快捷键

    shift   +  i      (‘I’)    进行编辑

    shift   +  4     (‘$’)    跳到行尾

    shift   +  v      (‘V’)   选中行 

    shift   +  0      (‘)’)    跳到行首

    先ctrl  +  v  模块编辑

    再s,或者shift + $, shift + i进行编辑即可,编辑完后就esc就可以更改局部内容

    s    删除

    Ctrl+wl或wh是切换窗口来编辑

    vs a.c 打开一个文件

    BundleSearch 查找所有插件,找到后,yy复制想要的那一行插件到vimrc中即可vi ~/.vimrc

    然后再执行BundleInstall

    BundleList 当前插件

    vim安装后,要把.vimrc放在里面保存即可,然后还有几个隐藏的文件夹也要放在里面

    查看函数被哪些调用的话,快捷键:ctrl+ ,然后再按s即可

    或者cs find main也可以

    先要安装了ctags,在程序的根目录下运行ctags -R,生成tags文件,然后在编辑程序时按Ctrl+]就会跳转到当前光标所在东西的定义处。若有多个tag,执行:ts,进行选择。按Ctrl+o即可跳回。不过,当修改过代码后,需要重新生成tags。

    33.git操作,检查代码log技巧

    Linux kernel  的官方 GIT地址是:

    http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git

    可以从这个地址拿到 kernel 的 代码仓库。

    git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git 

    在家目录下(也就是自己的目录下)

    将git执行文件放在家目录的bin下面,没有就自己创一个bin目录

    将文件git-completion.bash修改文件名为 .git-completion.bash

    在家目录下的.bashrc 的最后一行增加source  ~/.git-completion.bash

    source .bashrc

    source .profile

    这样git就有了补全功能

    git-completion.bash文件里面有说明。

    git remote -v

    如果是跟踪着某个开发者的git代码库,

    git blame <文件名>

    然后, 找出感兴趣行上的commit ID  ,用

    git show  <commit ID>

     git log --pretty=oneline  b.c 

    查看这次改动是由哪次提交引入的.一般可能会附加提交说明,

    解释这次提交的初衷,作用等.

    还可以记下作者的名字 

    然后放狗(google)搜: lkml +作者名字+关于这个修改或主题的一两个重要关键词,

    这样可能可以直接搜到当时提交时作者发在内核列表的邮件,可能有更详细的讨论.

    这么做去找找引入这些重要变化的源由.

    34.内核关抢占

     Symbol: PREEMPT_NONE [=y]                                                                                                                            |  
      | Type  : boolean                                                                                                                                      |  
      | Prompt: No Forced Preemption (Server)                                                                                                                |  
      |   Defined at kernel/Kconfig.preempt:6                                                                                                                |  
      |   Depends on: <choice>                                                                                                                               |  
      |   Location:                                                                                                                                          |  
      |     -> Kernel Features                                                                                                                               |  
      |       -> Preemption Model (<choice> [=y])   

    35. 处理DDR跑飞问题:

    某些处理器可以处理,如果是系统休眠唤醒后出现系统乱飞的情况,可以在休眠前对DDR进行CRC校验,唤醒后再进行一次校验,两次一样即可,但是必须保证DDR无任何操作。

    36.开机自启动,需要用脚本启动脚本,rc文件中

     #camera drivers
       if property:ro.fac.camera_number!= chmod 755 /startup/camera_drv_load.sh
       if property:ro.fac.camera_number!= exec /startup/bin/sh /startup/camera_drv_load.sh

    37.一个拆包的方法,i2c

    /* define in iproc_smbus.c */
    #define I2C_RX_LENGTH_MAX_SUPPORT 62
    
    static int __synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
                        unsigned short addr, unsigned char *data,
                        unsigned short length)
    {
        int ret = 0;
        int count = 0;
    
        for (count = 0; count < length / I2C_RX_LENGTH_MAX_SUPPORT; count++) {
            ret = synaptics_rmi4_i2c_write(rmi4_data, addr, 
                                           data + count * I2C_RX_LENGTH_MAX_SUPPORT, 
                                           I2C_RX_LENGTH_MAX_SUPPORT);
            if (ret < 0) {
                 dev_err(rmi4_data->pdev,
                    "%s: I2C write over retry limit
    ", __func__);               
                return ret;
            }
        }
        
        ret = synaptics_rmi4_i2c_write(rmi4_data, addr, 
                                       data + count * I2C_RX_LENGTH_MAX_SUPPORT, 
                                       length % I2C_RX_LENGTH_MAX_SUPPORT);
        if (ret < 0) {
             dev_err(rmi4_data->pdev,
                "%s: I2C write over retry limit
    ", __func__);      
            return ret;
        }
        
        return ret;
    }
    View Code

    38.网络配置相关命令

    udhcpc -i usb0

    route

    ping www.baidu.com -I usb0

    有时ping不通,可以试下只保留lo和usb0,其余的全down掉

    一种拆包算法

    #define I2C_RX_LENGTH_MAX_SUPPORT 62
    
    static int __synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
                        unsigned short addr, unsigned char *data,
                        unsigned short length)
    {
        int ret = 0;
        int count = 0;
    
        for (count = 0; count < length / I2C_RX_LENGTH_MAX_SUPPORT; count++) {
            ret = synaptics_rmi4_i2c_write(rmi4_data, addr,
                                           data + count * I2C_RX_LENGTH_MAX_SUPPORT,
                                           I2C_RX_LENGTH_MAX_SUPPORT);
            if (ret < 0) {
                 dev_err(rmi4_data->pdev,
                    "%s: I2C write over retry limit
    ", __func__);               
                return ret;
            }
        }
        
        ret = synaptics_rmi4_i2c_write(rmi4_data, addr,
                                       data + count * I2C_RX_LENGTH_MAX_SUPPORT,
                                       length % I2C_RX_LENGTH_MAX_SUPPORT);
        if (ret < 0) {
             dev_err(rmi4_data->pdev,
                "%s: I2C write over retry limit
    ", __func__);      
            return ret;
        }
        
        return ret;
    }
    View Code

    39.windows下保存网页的方法:

    ctrl + p  就是打印,然后选择adobe PDF,确定 即可

    40.gcc编译器内置选项

     arm-none-linux-gnueabi-gcc -E -dM -< /dev/null

    #define __DBL_MIN_EXP__ (-1021)
    #define __HQ_FBIT__ 15
    #define __UINT_LEAST16_MAX__ 65535
    #define __SFRACT_IBIT__ 0
    #define __FLT_MIN__ 1.1754943508222875e-38F
    #define __UFRACT_MAX__ 0XFFFFP-16UR
    #define __UINT_LEAST8_TYPE__ unsigned char
    #define __DQ_FBIT__ 63
    #define __INTMAX_C(c) c ## LL
    #define __CS_SOURCERYGXX_REV__ 57
    #define __ULFRACT_FBIT__ 32
    #define __SACCUM_EPSILON__ 0x1P-7HK
    #define __CHAR_BIT__ 8
    #define __USQ_IBIT__ 0
    #define __UINT8_MAX__ 255
    #define __ACCUM_FBIT__ 15
    #define __WINT_MAX__ 4294967295U
    #define __USFRACT_FBIT__ 8
    #define __ORDER_LITTLE_ENDIAN__ 1234
    #define __SIZE_MAX__ 4294967295U
    #define __WCHAR_MAX__ 4294967295U
    #define __LACCUM_IBIT__ 32
    #define __DBL_DENORM_MIN__ ((double)4.9406564584124654e-324L)
    #define __FLT_EVAL_METHOD__ 0
    #define __unix__ 1
    #define __LLACCUM_MAX__ 0X7FFFFFFFFFFFFFFFP-31LLK
    #define __FRACT_FBIT__ 15
    #define __UINT_FAST64_MAX__ 18446744073709551615ULL
    #define __SIG_ATOMIC_TYPE__ int
    #define __UACCUM_FBIT__ 16
    #define __DBL_MIN_10_EXP__ (-307)
    #define __FINITE_MATH_ONLY__ 0
    #define __ARMEL__ 1
    #define __LFRACT_IBIT__ 0
    #define __GNUC_PATCHLEVEL__ 3
    #define __LFRACT_MAX__ 0X7FFFFFFFP-31LR
    #define __UINT_FAST8_MAX__ 255
    #define __DEC64_MAX_EXP__ 385
    #define __INT8_C(c) c
    #define __UINT_LEAST64_MAX__ 18446744073709551615ULL
    #define __SA_FBIT__ 15
    #define __SHRT_MAX__ 32767
    #define __LDBL_MAX__ 1.7976931348623157e+308L
    #define __FRACT_MAX__ 0X7FFFP-15R
    #define __ARM_ARCH_5TE__ 1
    #define __UFRACT_FBIT__ 16
    #define __UFRACT_MIN__ 0.0UR
    #define __UINT_LEAST8_MAX__ 255
    #define __GXX_TYPEINFO_EQUALITY_INLINE 0
    #define __UINTMAX_TYPE__ long long unsigned int
    #define __LLFRACT_EPSILON__ 0x1P-63LLR
    #define __linux 1
    #define __DEC32_EPSILON__ 1E-6DF
    #define __CHAR_UNSIGNED__ 1
    #define __UINT32_MAX__ 4294967295U
    #define __ULFRACT_MAX__ 0XFFFFFFFFP-32ULR
    #define __TA_IBIT__ 64
    #define __LDBL_MAX_EXP__ 1024
    #define __WINT_MIN__ 0U
    #define __linux__ 1
    #define __ULLFRACT_MIN__ 0.0ULLR
    #define __SCHAR_MAX__ 127
    #define __WCHAR_MIN__ 0U
    #define __INT64_C(c) c ## LL
    #define __DBL_DIG__ 15
    #define __LLACCUM_MIN__ (-0X1P31LLK-0X1P31LLK)
    #define __SIZEOF_INT__ 4
    #define __SIZEOF_POINTER__ 4
    #define __USACCUM_IBIT__ 8
    #define __USER_LABEL_PREFIX__ 
    #define __STDC_HOSTED__ 1
    #define __LDBL_HAS_INFINITY__ 1
    #define __LFRACT_MIN__ (-0.5LR-0.5LR)
    #define __HA_IBIT__ 8
    #define __TQ_IBIT__ 0
    #define __FLT_EPSILON__ 1.1920928955078125e-7F
    #define __APCS_32__ 1
    #define __USFRACT_IBIT__ 0
    #define __LDBL_MIN__ 2.2250738585072014e-308L
    #define __FRACT_MIN__ (-0.5R-0.5R)
    #define __DEC32_MAX__ 9.999999E96DF
    #define __DA_IBIT__ 32
    #define __INT32_MAX__ 2147483647
    #define __UQQ_FBIT__ 8
    #define __SIZEOF_LONG__ 4
    #define __UACCUM_MAX__ 0XFFFFFFFFP-16UK
    #define __UINT16_C(c) c
    #define __DECIMAL_DIG__ 17
    #define __LFRACT_EPSILON__ 0x1P-31LR
    #define __ULFRACT_MIN__ 0.0ULR
    #define __gnu_linux__ 1
    #define __LDBL_HAS_QUIET_NAN__ 1
    #define __ULACCUM_IBIT__ 32
    #define __UACCUM_EPSILON__ 0x1P-16UK
    #define __GNUC__ 4
    #define __ULLACCUM_MAX__ 0XFFFFFFFFFFFFFFFFP-32ULLK
    #define __HQ_IBIT__ 0
    #define __FLT_HAS_DENORM__ 1
    #define __SIZEOF_LONG_DOUBLE__ 8
    #define __BIGGEST_ALIGNMENT__ 8
    #define __DQ_IBIT__ 0
    #define __DBL_MAX__ ((double)1.7976931348623157e+308L)
    #define __ULFRACT_IBIT__ 0
    #define __INT_FAST32_MAX__ 2147483647
    #define __DBL_HAS_INFINITY__ 1
    #define __ACCUM_IBIT__ 16
    #define __DEC32_MIN_EXP__ (-94)
    #define __THUMB_INTERWORK__ 1
    #define __LACCUM_MAX__ 0X7FFFFFFFFFFFFFFFP-31LK
    #define __INT_FAST16_TYPE__ int
    #define __LDBL_HAS_DENORM__ 1
    #define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
    #define __INT_LEAST32_MAX__ 2147483647
    #define __ARM_PCS 1
    #define __DEC32_MIN__ 1E-95DF
    #define __ACCUM_MAX__ 0X7FFFFFFFP-15K
    #define __DBL_MAX_EXP__ 1024
    #define __USACCUM_EPSILON__ 0x1P-8UHK
    #define __DEC128_EPSILON__ 1E-33DL
    #define __SFRACT_MAX__ 0X7FP-7HR
    #define __FRACT_IBIT__ 0
    #define __PTRDIFF_MAX__ 2147483647
    #define __UACCUM_MIN__ 0.0UK
    #define __UACCUM_IBIT__ 16
    #define __LONG_LONG_MAX__ 9223372036854775807LL
    #define __SIZEOF_SIZE_T__ 4
    #define __ULACCUM_MAX__ 0XFFFFFFFFFFFFFFFFP-32ULK
    #define __SIZEOF_WINT_T__ 4
    #define __SA_IBIT__ 16
    #define __ULLACCUM_MIN__ 0.0ULLK
    #define __GXX_ABI_VERSION 1002
    #define __UTA_FBIT__ 64
    #define __SOFTFP__ 1
    #define __FLT_MIN_EXP__ (-125)
    #define __USFRACT_MAX__ 0XFFP-8UHR
    #define __UFRACT_IBIT__ 0
    #define __INT_FAST64_TYPE__ long long int
    #define __DBL_MIN__ ((double)2.2250738585072014e-308L)
    #define __LACCUM_MIN__ (-0X1P31LK-0X1P31LK)
    #define __ULLACCUM_FBIT__ 32
    #define __ULLFRACT_EPSILON__ 0x1P-64ULLR
    #define __DEC128_MIN__ 1E-6143DL
    #define __REGISTER_PREFIX__ 
    #define __UINT16_MAX__ 65535
    #define __DBL_HAS_DENORM__ 1
    #define __ACCUM_MIN__ (-0X1P15K-0X1P15K)
    #define __SQ_IBIT__ 0
    #define __UINT8_TYPE__ unsigned char
    #define __UHA_FBIT__ 8
    #define __NO_INLINE__ 1
    #define __SFRACT_MIN__ (-0.5HR-0.5HR)
    #define __UTQ_FBIT__ 128
    #define __FLT_MANT_DIG__ 24
    #define __VERSION__ "4.6.3"
    #define __UINT64_C(c) c ## ULL
    #define __ULLFRACT_FBIT__ 64
    #define __FRACT_EPSILON__ 0x1P-15R
    #define __ULACCUM_MIN__ 0.0ULK
    #define __UDA_FBIT__ 32
    #define __LLACCUM_EPSILON__ 0x1P-31LLK
    #define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
    #define __USFRACT_MIN__ 0.0UHR
    #define __UQQ_IBIT__ 0
    #define __INT32_C(c) c
    #define __DEC64_EPSILON__ 1E-15DD
    #define __ORDER_PDP_ENDIAN__ 3412
    #define __DEC128_MIN_EXP__ (-6142)
    #define __UHQ_FBIT__ 16
    #define __LLACCUM_FBIT__ 31
    #define __INT_FAST32_TYPE__ int
    #define __UINT_LEAST16_TYPE__ short unsigned int
    #define unix 1
    #define __INT16_MAX__ 32767
    #define __SIZE_TYPE__ unsigned int
    #define __UINT64_MAX__ 18446744073709551615ULL
    #define __UDQ_FBIT__ 64
    #define __INT8_TYPE__ signed char
    #define __ELF__ 1
    #define __ULFRACT_EPSILON__ 0x1P-32ULR
    #define __LLFRACT_FBIT__ 63
    #define __FLT_RADIX__ 2
    #define __INT_LEAST16_TYPE__ short int
    #define __LDBL_EPSILON__ 2.2204460492503131e-16L
    #define __UINTMAX_C(c) c ## ULL
    #define __SACCUM_MAX__ 0X7FFFP-7HK
    #define __SIG_ATOMIC_MAX__ 2147483647
    #define __VFP_FP__ 1
    #define __SIZEOF_PTRDIFF_T__ 4
    #define __CS_SOURCERYGXX_MIN__ 3
    #define __LACCUM_EPSILON__ 0x1P-31LK
    #define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
    #define __INT_FAST16_MAX__ 2147483647
    #define __UINT_FAST32_MAX__ 4294967295U
    #define __UINT_LEAST64_TYPE__ long long unsigned int
    #define __USACCUM_MAX__ 0XFFFFP-8UHK
    #define __SFRACT_EPSILON__ 0x1P-7HR
    #define __FLT_HAS_QUIET_NAN__ 1
    #define __FLT_MAX_10_EXP__ 38
    #define __LONG_MAX__ 2147483647L
    #define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
    #define __FLT_HAS_INFINITY__ 1
    #define __unix 1
    #define __USA_FBIT__ 16
    #define __UINT_FAST16_TYPE__ unsigned int
    #define __DEC64_MAX__ 9.999999999999999E384DD
    #define __CHAR16_TYPE__ short unsigned int
    #define __PRAGMA_REDEFINE_EXTNAME 1
    #define __CS_SOURCERYGXX_MAJ__ 2012
    #define __INT_LEAST16_MAX__ 32767
    #define __DEC64_MANT_DIG__ 16
    #define __INT64_MAX__ 9223372036854775807LL
    #define __UINT_LEAST32_MAX__ 4294967295U
    #define __SACCUM_FBIT__ 7
    #define __INT_LEAST64_TYPE__ long long int
    #define __INT16_TYPE__ short int
    #define __INT_LEAST8_TYPE__ signed char
    #define __SQ_FBIT__ 31
    #define __DEC32_MAX_EXP__ 97
    #define __INT_FAST8_MAX__ 127
    #define __INTPTR_MAX__ 2147483647
    #define __QQ_FBIT__ 7
    #define linux 1
    #define __UTA_IBIT__ 64
    #define __LDBL_MANT_DIG__ 53
    #define __SFRACT_FBIT__ 7
    #define __SACCUM_MIN__ (-0X1P7HK-0X1P7HK)
    #define __DBL_HAS_QUIET_NAN__ 1
    #define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)
    #define __INTPTR_TYPE__ int
    #define __UINT16_TYPE__ short unsigned int
    #define __WCHAR_TYPE__ unsigned int
    #define __SIZEOF_FLOAT__ 4
    #define __USQ_FBIT__ 32
    #define __UINTPTR_MAX__ 4294967295U
    #define __DEC64_MIN_EXP__ (-382)
    #define __ULLACCUM_IBIT__ 32
    #define __INT_FAST64_MAX__ 9223372036854775807LL
    #define __FLT_DIG__ 6
    #define __UINT_FAST64_TYPE__ long long unsigned int
    #define __INT_MAX__ 2147483647
    #define __LACCUM_FBIT__ 31
    #define __USACCUM_MIN__ 0.0UHK
    #define __UHA_IBIT__ 8
    #define __INT64_TYPE__ long long int
    #define __FLT_MAX_EXP__ 128
    #define __UTQ_IBIT__ 0
    #define __DBL_MANT_DIG__ 53
    #define __INT_LEAST64_MAX__ 9223372036854775807LL
    #define __DEC64_MIN__ 1E-383DD
    #define __WINT_TYPE__ unsigned int
    #define __UINT_LEAST32_TYPE__ unsigned int
    #define __SIZEOF_SHORT__ 2
    #define __ULLFRACT_IBIT__ 0
    #define __LDBL_MIN_EXP__ (-1021)
    #define __arm__ 1
    #define __UDA_IBIT__ 32
    #define __INT_LEAST8_MAX__ 127
    #define __LFRACT_FBIT__ 31
    #define __LDBL_MAX_10_EXP__ 308
    #define __DBL_EPSILON__ ((double)2.2204460492503131e-16L)
    #define __UINT8_C(c) c
    #define __INT_LEAST32_TYPE__ int
    #define __SIZEOF_WCHAR_T__ 4
    #define __UINT64_TYPE__ long long unsigned int
    #define __LLFRACT_MAX__ 0X7FFFFFFFFFFFFFFFP-63LLR
    #define __TQ_FBIT__ 127
    #define __INT_FAST8_TYPE__ signed char
    #define __ULLACCUM_EPSILON__ 0x1P-32ULLK
    #define __UHQ_IBIT__ 0
    #define __LLACCUM_IBIT__ 32
    #define __DBL_DECIMAL_DIG__ 17
    #define __DEC_EVAL_METHOD__ 2
    #define __TA_FBIT__ 63
    #define __UDQ_IBIT__ 0
    #define __ORDER_BIG_ENDIAN__ 4321
    #define __ACCUM_EPSILON__ 0x1P-15K
    #define __UINT32_C(c) c ## U
    #define __INTMAX_MAX__ 9223372036854775807LL
    #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
    #define __FLT_DENORM_MIN__ 1.4012984643248171e-45F
    #define __LLFRACT_IBIT__ 0
    #define __INT8_MAX__ 127
    #define __UINT_FAST32_TYPE__ unsigned int
    #define __CHAR32_TYPE__ unsigned int
    #define __FLT_MAX__ 3.4028234663852886e+38F
    #define __USACCUM_FBIT__ 8
    #define __INT32_TYPE__ int
    #define __SIZEOF_DOUBLE__ 8
    #define __FLT_MIN_10_EXP__ (-37)
    #define __UFRACT_EPSILON__ 0x1P-16UR
    #define __INTMAX_TYPE__ long long int
    #define __DEC128_MAX_EXP__ 6145
    #define __GNUC_MINOR__ 6
    #define __UINTMAX_MAX__ 18446744073709551615ULL
    #define __DEC32_MANT_DIG__ 7
    #define __HA_FBIT__ 7
    #define __DBL_MAX_10_EXP__ 308
    #define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
    #define __INT16_C(c) c
    #define __STDC__ 1
    #define __PTRDIFF_TYPE__ int
    #define __LLFRACT_MIN__ (-0.5LLR-0.5LLR)
    #define __DA_FBIT__ 31
    #define __UINT32_TYPE__ unsigned int
    #define __UINTPTR_TYPE__ unsigned int
    #define __USA_IBIT__ 16
    #define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
    #define __ARM_EABI__ 1
    #define __DEC128_MANT_DIG__ 34
    #define __LDBL_MIN_10_EXP__ (-307)
    #define __SIZEOF_LONG_LONG__ 8
    #define __ULACCUM_EPSILON__ 0x1P-32ULK
    #define __SACCUM_IBIT__ 8
    #define __LDBL_DIG__ 15
    #define __FLT_DECIMAL_DIG__ 9
    #define __UINT_FAST16_MAX__ 4294967295U
    #define __GNUC_GNU_INLINE__ 1
    #define __ULLFRACT_MAX__ 0XFFFFFFFFFFFFFFFFP-64ULLR
    #define __UINT_FAST8_TYPE__ unsigned char
    #define __USFRACT_EPSILON__ 0x1P-8UHR
    #define __ULACCUM_FBIT__ 32
    #define __ARM_FEATURE_DSP 1
    #define __QQ_IBIT__ 0
    View Code

    linux-3.6.5/scripts

    vi gcc-x86_32-has-stack-protector.sh

    #!/bin/sh
    
    echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
    if [ "$?" -eq "0" ] ; then
            echo y
    else
            echo n
    fi

    %gs为栈保护

    41.如果反汇编后有%gs,就说明内核有栈保护

    arm_build.sh

    arm-none-linux-gnueabi-gcc -S -fstack-protector -o stack test_stack_protector.c

    test_stack_protector.c

    int foo(void) { char X[200]; return 3; }

    ./arm_build.sh

    vi stack

            .arch armv5te
            .fpu softvfp
            .eabi_attribute 20, 1
            .eabi_attribute 21, 1
            .eabi_attribute 23, 3
            .eabi_attribute 24, 1
            .eabi_attribute 25, 1
            .eabi_attribute 26, 2
            .eabi_attribute 30, 6
            .eabi_attribute 34, 0
            .eabi_attribute 18, 4
            .file   "test_stack_protector.c"
            .text
            .align  2
            .global foo
            .type   foo, %function
    foo:
            .fnstart
            @ args = 0, pretend = 0, frame = 208
            @ frame_needed = 1, uses_anonymous_args = 0
            stmfd   sp!, {fp, lr}
            .save {fp, lr}
            .setfp fp, sp, #4
            add     fp, sp, #4
            .pad #208
            sub     sp, sp, #208
            ldr     r3, .L3
            ldr     r3, [r3, #0]
            str     r3, [fp, #-8]
            mov     r3, #3
            mov     r0, r3
            ldr     r3, .L3
            ldr     r2, [fp, #-8]
            ldr     r3, [r3, #0]
            cmp     r2, r3
            beq     .L2
            bl      __stack_chk_fail
    .L2:
            sub     sp, fp, #4
            ldmfd   sp!, {fp, pc}
    .L4:
            .align  2
    .L3:
            .word   __stack_chk_guard
            .fnend
            .size   foo, .-foo
            .ident  "GCC: (Sourcery CodeBench Lite 2012.03-57) 4.6.3"
            .section        .note.GNU-stack,"",%progbits
    View Code

    42.为了保证代码不乱序,内存屏障的建立

     #define readb(c)        ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
    #define readw(c)        ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
    #define readl(c)        ({ u32 __v = readl_relaxed(c); __iormb(); __v; })

    eg:

    aaa();

    wmb();

    bbb();

     no_console_suspend

    initcall_debug 

    说明initcall_debug是一个内核参数,可以跟踪initcall,用来定位内核初始化的问题。在cmdline中增加initcall_debug后,内核启动过程中会增加如下形式的日志,在调用每一个init函数前有一句打印,结束后再有一句打印并且输出了该Init函数运行的时间,通过这个信息可以用来定位启动过程中哪个init函数运行失败以及哪些init函数运行时间较长

     休眠唤醒调试还可以打开【Power management options】===》

    [*] Power Management Debug Support | |
    | | [*] Extra PM attributes in sysfs for low-level debugging/testing | |
    | | [*] Test suspend/resume and wakealarm during bootup

    43.网络 netstate

    netstate –nao

    svn co svn:xxx --depth=empty

     ls

     svn ls

     cd aa/

     ls

     svn ls

     svn up release_branches --depth=empty

     cd release_branches/

     ls

     svn ls

     svn up xxx

    44.内核异步通知


    retval = request_irq(pdev->irq, MioSoC_isr, IRQF_SHARED  , "MioSoC", pmio);

    中断处理程序:
    static irqreturn_t MioSoC_isr(int irq, void *data)
    {
       
        struct MioSoC_device *dev = data;
        spin_lock(&dev->regs_lock);
            dwIntStatus = inw(pmio->caddr +0x4c); // 读取卡上的控制缓存器中断状态
                if (dwIntStatus & 0x4)              // 检查是否为本卡的中断
                {
                    outw((dwIntStatus & (~0x43)),pmio->caddr+0x4c);
                    if (pmio->async_queue )
                            kill_fasync(&dev->async_queue, SIGIO, POLL_IN); //发出异步通知信号
                    outw(dwIntStatus,pmio->caddr + 0x4c);
                }
        spin_unlock(&dev->regs_lock);
         wake_up_interruptible(&dev->wait);
        return IRQ_HANDLED;
    }

    45.线程处理,线程安全

    futex

    46.unicore32

    unicore32的代码写的很好,可以参考

    47.defio 双缓冲机制

    48.strace命令

    strace -o t.log ./a.out

    49.Linux上搭建web服务器,实现web控制嵌入式设备

    随着Internet技术的兴起,在嵌入式设备的管理与交互中,基于Web方式的应用成为目 前的主流,这种程序结构也就是大家非常熟悉的B/S结构,即在嵌入式设备上运行一个支持脚本或CGI功能的Web服务器,能够生成动态页面,在用户端只需 要通过Web浏览器就可以对嵌入式设备进行管理和监控,非常方便实用。

    路由器上现在不用boa服务器了,一般用uhttpd和goahead,这样可以对CGI进行控制

    50. 内核中的set_freezable与wait_event_freezable_timeout,进程等待

    到目前为止,我们的控制线程就已经分析完了,不过我们发现,这个控制线程是在usb_stor_acquire_resources中定义的,在usb_stor_acquire_resources之后,我们还创建了usb_stor_scan_thread线程,这是一个扫描线程。

    static int usb_stor_scan_thread(void * __us)

    {

        struct us_data *us = (struct us_data *)__us;

        printk(KERN_DEBUG

                "usb-storage: device found at %d ", us->pusb_dev->devnum);

        set_freezable();  //设备在一定时间内没有响应,会挂起

        if (delay_use > 0) {  // delay_use秒后如果U盘没拔出则继续执行,否则执行disconnect

                printk(KERN_DEBUG "usb-storage: waiting for device "

                              "to settle before scanning ");

                      wait_event_freezable_timeout(us->delay_wait,test_bit(US_FLIDX_DONT_SCAN, &us->dflags), delay_use * HZ);

        }

        if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {

                if (us->protocol == US_PR_BULK &&

                              !(us->fflags & US_FL_SINGLE_LUN)) {

                      mutex_lock(&us->dev_mutex);

                      us->max_lun = usb_stor_Bulk_max_lun(us);  //询问设备支持多少个LUN

                      mutex_unlock(&us->dev_mutex);

                }

                scsi_scan_host(us_to_host(us));

                printk(KERN_DEBUG "usb-storage: device scan complete ");

        }

        complete_and_exit(&us->scanning_done, 0);  //本进程结束,唤醒disconnect中的进程

    }

    对于上面这个扫描线程,里面的usb_stor_Bulk_max_lun函数完成了主机控制器与设备之间的第一次通信。USB驱动程序首先发送一个命令,然后设备根据命令返回一些信息,这里显示的是一个表示LUN个数的数字,usb_stor_Bulk_max_lun完成的是一次控制传输。

    51.Linux resume

    linux的resume是根据device的加载顺序来执行的

    52.setup_time中断

    这种虽然是软中断处理,但一样是中断上下文,不可以在处理函数中休眠,或者发生进程调度的事情,这样会死机,workqueue.c中只有一种机制才可以这样做,tasklet

    53.休眠唤醒

    休眠唤醒除了在配置文件中cmdline增加no_console_suspend,还可以开机如下操作,即可打印出休眠唤醒的全部log

    echo N > /sys/module/printk/parameters/console_suspend

    54.pwm使用

    // disable pwm 的正确流程是:

    pwm_config(prn_stb_pwm, 0, period_ns); ===》这样才是安全的

    pwm_disable(prn_stb_pwm);

    而不是:

    pwm_disable(prn_stb_pwm);

    55. 算一张表里有多少个1

    hweight8

    56.通过Sys节点名字反查pid

    fs/sysfs/file.c

    sysfs_open_file() ======>

        char *name1, *name2;

        name1 = "buzzer_user_trigger";
        name2 = "buzzer_keypad_enable";
        if ((0 == strncmp(attr_sd->s_name, name1, strlen(name1))) ||
            (0 == strncmp(attr_sd->s_name, name2, strlen(name2))) ) {
            printk("zbh %s():--->%s (%d)  ", 
                __func__, attr_sd->s_name, __LINE__);
            printk("zbh %s():--->pid=%d (%d)  ", 
                __func__, current->pid, __LINE__);
        }

    57.文件系统知识点

    cat /proc/filesystems

    58.spi透传?

    spi能否透传?如果master与slave不对称,一边带宽高,一边带宽少,从机接收的时候接收不过来,如果要用dma方式,并且协定好底层数据传输大小,每次发送时候要发送数据长度

     可以参考stm32官网的 spi IAP固件升级的例程代码

    59.实现自己的系统调用

    http://www.cnblogs.com/sky-heaven/p/8080885.html

    60.唤醒后通知方法

    #define wait_event_interruptible_locked(wq, condition)            
        ((condition)                            
         ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0))

    61.1G, 1M, 1K的10进制与16进制转换

    1G ---> 0x40 000 000

    1M ---> 0x100 000

    1KB ---> 0x400

    62.帧率,时钟,数据量计算

    对于camera

    每个像素需占用 32 bit 容量(三原色各8 bit,亮度8 bit),即 4 字节(Byte)。每帧图像容量为 4*640*480 = 1228800 字节,

    每秒25帧,则每秒容量为 1228800*25 = 30720000 字节。即每秒数据容量为 约 29.30兆(1024进位),带宽是以 bit 为单位,因此占用带宽约234.38兆/秒

    30720000 / 1024 / 1024 = 29.30Mb

    29.30Mb * 8 = 234.38M/s

    对于lcd

    94*845 分辨率

    30 fps

    494*845*30 = 12522900Hz = 12.5229Mhz

    转自:http://blog.csdn.net/bmw7bmw7/article/details/45876487
    我们先来看一个公式:Mipiclock = [ (width+hsync+hfp+hbp) x (height+vsync+vfp+vbp) ] x(bus_width) x fps/ (lane_num)/2
    即mipi 屏的传输时钟频率(CLKN,CLKP)等于(屏幕分辨率宽width+hsync+hfp+hbp)x ( 屏幕分辨率高height+vsync+vfp+vbp) x(RGB显示数据宽度) x 帧率/ (lane_num)/2
     
    简单解释下:
          一帧画面需要的数据量为(单位bit):FRAME_BIT = (屏幕有效显示宽度+hsync+hfp+hbp) x ( 屏幕有效显示高度+vsync+vfp+vbp) x(RGB显示数据宽度24)
         一秒钟内需要传输的数据量为(单位bps):FRAME_BIT  x  fps(帧率)。
         那为何要除以lane_num----因为mipi通讯协议中,一个CLOCK几个lane是可以同时传输数据的。
         为何又要除以2----因为根据mipi通讯协议,CLK_N、CLK_P这两根时钟线的上升沿/下降沿可以获取到数据。
    因此我们可以得出如下结论:
    1.在相同的时钟频率下,lane数越多,则单位时间内可以传输的数据越多。若显示帧率固定不变,则可以支持的更大的分辨率;而分辨率固定不变的情况下,则我们可以考虑支持更高的帧率显示。
    2.在lane数固定的情况下,提高传输的时钟频率,则单位时间内也可以传输更多的显示数据。进而我们可以考虑是提高帧率还是提高分辨率,或两者做出平衡。
     
    那么我们是否可以任意无限制的提高mipi的传输时钟频率及lane数目呢?mipi通讯协议对此进行了限制,一组CLOCK最高只能支持4组lane,一组lane的传输速度最高只能支持到1 Gbps。也就是说一组CLOCK最高只能支持到4 Gbps速度传输。
    此时就引出了一个新问题:4Gbps速度传输,是满足不了现在市场上推出的4K电视的带宽要求的,怎么办?答案是使用8组lane,使用两组clock来传输。
    下面我们以展讯7731平台下EK79023这款LCD 驱动IC的配置参数进行实例说明:
    static struct timing_rgb lcd_ek79023_mipi_timing = {
             .hfp = 100,  /* unit: pixel */
             .hbp = 60,
             .hsync = 24,
             .vfp = 22, /*unit:line*/
             .vbp = 10,
             .vsync = 2,
    };
     
     
    static struct info_mipi lcd_ek79023_mipi_info = {
             .work_mode  = SPRDFB_MIPI_MODE_VIDEO,
             .video_bus_width =24, /*18,16*/
             .lan_number =         2,
             .phy_feq=660*1000,
             .h_sync_pol =SPRDFB_POLARITY_POS,
             .v_sync_pol = SPRDFB_POLARITY_POS,
             .de_pol =SPRDFB_POLARITY_POS,
             .te_pol =SPRDFB_POLARITY_POS,
             .color_mode_pol =SPRDFB_POLARITY_NEG,
             .shut_down_pol =SPRDFB_POLARITY_NEG,
             .timing =&lcd_ek79023_mipi_timing,
             .ops = NULL,
    };
     
    struct panel_spec lcd_ek79023_mipi_spec = {
             .width = 600,
             .height = 1024,
             .fps =57,//62,//67,//52,//57,//60,
             .type =LCD_MODE_DSI,
             .direction =LCD_DIRECT_NORMAL,
             .info = {
                       .mipi =&lcd_ek79023_mipi_info
             },
             .ops =&lcd_ek79023_mipi_operations,
    };
    从中可知,该LCD的分辨率为600 x 1024,帧率为57 HZ。
    一帧图像的数据量为:FRAME_BIT=(600+24+100+60) x (1024+2+22+10) x(24)=19907328 bit
    一秒钟的数据量为:19907328  x 57 = 1134.717696  Mbps
    所需的mipi时钟频率为:1134717696/2(lane)/2= 283.679424 Mhz
    一组lane的传输速度是:283.679424  x  2= 576.358848 Mbps

    63.kernel开启debug

    Init/main.c

    early_param("debug", debug_kernel);

    early_param("quiet", quiet_kernel);

    early_param("loglevel", loglevel);

    配置文件加入debug,或者loglevel=8

    想开启全部的debug,在kernel顶层的makefile中加入:

    KCFLAGS += -DDEBUG

     

     

    打印module_init(函数)这个的调用顺序

    int __init_or_module do_one_initcall(initcall_t fn)

    {

             int count = preempt_count();

             int ret;

     

             if (initcall_debug)

                       ret = do_one_initcall_debug(fn);

             else

                       ret = fn();

     

     

    在配置文件中加入红色字体即可

    bootargs=console=ttyAMA3,115200 CONSOLE=ttyAMA3,115200 initcall_debug mem=512M mtdparts=nand_iproc.0:768k(boot),512k(nvram_fac),768k(boot_res),4m(boot_logo),12m(kernel),24m(ramdisk),24m(base),-(data)

     

    运行后dmesg

     

    Linux内核解析配置文件

    __setup(“console”)

    parse_args

    vmlinux.lds.S

     

    查看这些宏是否有定义

    #ifndef CONFIG_SMP

    要去linux3.6.5目录下.config文件

     

    系统下载后出现各种init服务都起不来,机器直接重启的话,也有可能是配置文件的data分区缺少,或者缺少其他分区空间导致

     

    no_console_suspend节点调试

    echo no_console_suspend > /sys/module/printk/parameters/console_suspend

    64. 结构体定义方法

    struct VideoDevice;
    struct VideoOpr;
    typedef struct VideoDevice T_VideoDevice, *PT_VideoDevice;
    typedef struct VideoOpr T_VideoOpr, *PT_VideoOpr;
    
    struct VideoDevice {
        int iFd;
        int iPixelFormat;
        int iWidth;
        int iHeight;
    
        int iVideoBufCnt;
        int iVideoBufMaxLen;
        int iVideoBufCurIndex;
        unsigned char *pucVideBuf[NB_BUFFER];
    
        /* 函数 */
        PT_VideoOpr ptOPr;
    };
    
    typedef struct VideoBuf {
        T_PixelDatas tPixelDatas;
        int iPixelFormat;
    }T_VideoBuf, *PT_VideoBuf;
    
    struct VideoOpr {
        char *name;
        int (*InitDevice)(char *strDevName, PT_VideoDevice ptVideoDevice);
        int (*ExitDevice)(PT_VideoDevice ptVideoDevice);
        int (*GetFrame)(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);
        int (*GetFormat)(PT_VideoDevice ptVideoDevice);
        int (*PutFrame)(PT_VideoDevice ptVideoDevice, PT_VideoBuf ptVideoBuf);
        int (*StartDevice)(PT_VideoDevice ptVideoDevice);
        int (*StopDevice)(PT_VideoDevice ptVideoDevice);
        struct VideoOpr *ptNext;
    };

     65.Ubuntu下的终端多标签操作和多标签切换

    ctrl+alt+t       打开一个terminal

    打开terminal后,ctrl+shift+t ===》在terminal中打开多个标签

    在多个标签中切换的方法:

    【方法一】

    alt+1 alt+2 alt+3.......

    【方法二】

    ctrl + pageUp
    ctrl + pageDown.

    ctrl+ d   关闭一个terminal快捷键   

    66. 求余与与运算

    #include <stdio.h>
    
    /*
     * 0x3FF = 0x400 - 1;
     * 1024 = 0x400
     * */
    
    #define CALC_A(x) (x % 1024)
    #define CALC_B(x) (x & 0x3FF)
    #define INPUT_DATA  123
    
    int main(int argc, char **argv)
    {
        int res;
    
        res = CALC_A(INPUT_DATA);
        printf("CALC_A return : %d 
    ", res);
    
        res = CALC_B(INPUT_DATA);
        printf("CALC_B return : %d 
    ", res);
    
        return 0;
    }

    67. makrdown博客编辑

    https://www.mdeditor.com/ 

    68.find查找文件并打印大小

    find ./ -name "*.o" | xargs du -sh -c | tail -1

    find ./ -name "*.o" | xargs du -sh -c

    欢迎交流,如有转载请注明出处

    新浪博客:http://blog.sina.com.cn/u/2049150530
    博客园:http://www.cnblogs.com/sky-heaven/
    知乎:http://www.zhihu.com/people/zhang-bing-hua

  • 相关阅读:
    Android Studio Gradle 添加.so 支持文件
    poj 3270 更换使用
    linux通过使用mail发送电子邮件
    php 上传文件 $_FILES['']['type']的值
    浅谈Base64编码
    expect实现ssh自动登录
    C++ 多源码文件简单组织
    linux下修改hostid
    SQLite/嵌入式数据库
    类内数组声明,“类外”指定大小
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5279334.html
Copyright © 2011-2022 走看看