内核驱动相关

一.关键头文件及内含的结构体,函数:

  • linux/types.h:
    > 1.dev_t;
    2.int MAJOR(dev_t dev);
    3.int MINOR(dev_t dev);
    4.dev MKDEV(unsigned int major,unsigned int minor);

  • linux/fs.h:
    > 1.int register_chrdev_region(dev_t first,unsigned int count,char* name);
    2.int alloc_chrdev_region(dev_t* dev,unsigned int firstminor,unsigned int count,char* name);
    3.void unregister_chrdev_region(dev_t first,unsigned int count);
    4.struct file;
    5.struct file_operations;
    6.struct inode;

  • linux/cdev.h:
    > 1.struct cdev cdev_alloc(void);
    2.void cdev_init(struct cdev* dev,struct file_operations* fops);
    3.int cdev_add(struct cdev* dev,dev_t num,unsigned int count);
    4.void cdev_del(struct cdev* dev);

  • linux/kernel.h:
    > 1.container_of(pointer,type,field);

  • asm/uaccess.h:
    > 1. unsigned long copy_from_user(void* to,void* from,unsigned long count);
    1. unsigned long copy_to_user(void* to,void* from,unsigned long count);
  • asm/semaphore.h:
    > 1. DECLARE_MUTEX(name);
    1. DECLARE_MUTEX_LOCKED(name);
    2. init_MUTEX(struct semaphore* sem);
    3. init_MUTEX_LOCKED(struct semaphore* sem);
    4. void down(struct semaphore* sem);
    5. int down_interruptible(struct semaphore* sem);
    6. int down_trylock(struct semaphore* sem);
    7. void up(struct semaphore* sem);
    8. struct rw_semaphore;
    9. init_rwsemaphore(struct rw_semaphore* sem);
    10. void down_read(struct rw_semaphore* sem);
    11. int down_read_trylock(struct rw_semaphore* sem);
    12. void up_read(struct rw_semaphore* sem);
    13. void down_write(struct rw_semaphore* sem);
    14. int down_write_trylock(struct rw_semaphore* sem);
    15. void up_write(struct rw_semaphore* sem);
    16. void downgrade_write(struct rw_semaphore* sem);
  • linux/complition.h:
    > 1. DECLARE_COMPLITION(name);
    1. init_complition(struct complition* c);
    2. INIT_COMPLITION(struct complition* c);
    3. void wait_for_complition(struct complition* c);
    4. void complition(struct complition* c);
    5. void complition_all(struct complition* c);
    6. void complite_and_exit(struct complition*c,long retval);
  • linux/spinlock.h:
    > 1. spinlock_t lock=SPIN_LOCK_UNLOCKED;
    1. spinlock_init(spinlock_t* lock);
    2. void spin_lock(spinlock_t* lock);
    3. void spin_lock_irqsave(spinlock_t* lock,unsigned long flags);
    4. void spin_lock_irq(spinlock_t* lock);
    5. void spin_lock_bh(spinlock_t* lock);
    6. int spin_trylock(spinlock_t* lock);
    7. int spin_lock_trylock_bh(spinlock_t* lock);
    8. void spin_unlock(spinlock_t* lock);
    9. void spin_unlock_irqrestore(spinlock_t* lock,unsigned long flags);
    10. void spin_unlock_irq(spinlock_t* lock);
    11. void spin_unlock_bh(spinlock_t* lock);
    12. rwlock_t lock=RW_LOCK_UNLOCKED;
    13. rwlock_init(rwlock_t* lock);
    14. void read_lock(rwlock_t* lock);
    15. void read_lock_irqsave(rwlock_t* lock,unsigned long flags);
    16. void read_lock_irq(rwlock_t* lock);
    17. void read_lock_bh(rwlock_t* lock);
    18. void read_unlock(rwlock_t* lock);
    19. void read_unlock_irqrestore(rwlock_t* lock,unsigned long flags);
    20. void read_unlock_irq(rwlock_t* lock);
    21. void read_unlock_bh(rwlock_t* lock);
    22. void write_lock(rwlock_t* lock);
    23. void write_lock_irqsave(rwlock_t* lock,unsigned long flags);
    24. void write_lock_irq(rwlock_t* lock);
    25. void write_lock_bh(rwlock_t* lock);
    26. void write_unlock(rwlock_t* lock);
    27. void write_unlock_irqrestore(rwlock_t* lock,unsigned long flags);
    28. void write_unlock_irq(rwlock_t* lock);
    29. void write_unlock_bh(rwlock_t* lock);
  • asm/atomic.h:
    > 1. atomic_t v=ATOMIC_INIT(value);
    1. void atomic_set(atomic_t* v,int i);
    2. int atomic_read(atomic_t* v);
    3. void atomic_add(int i,atomic_t* v);
    4. void atomic_sub(int i,atomic_t* v) ;
    5. void atomic_inc(atomic_t* v);
    6. void atomic_dec(atomic* v);
    7. int atomic_inc_and_test(atomic_t* v);
    8. int atomic_dec_and_test(atomic_t* v);
    9. int atomic_sub_and_test(atomic_t* v);
    10. int atomic_add_negative(int i,atomic_t* v);
    11. int atomic_add_return(int i,atomic_t* v);
    12. int atomic_sub_return(int i,atomic_t* v);
    13. int atomic_inc_return(atomic_t* v);
    14. int atomic_dec_return(atomic_t* v);
  • asm/bitops.h:
    > 1. void set_bit(nr,void* addr);
    1. void clear_bit(nr,void* addr);
    2. void change_bit(nr,void* addr);
    3. test_bit(nr,void* addr);
    4. int test_and_set_bit(nr,void* addr);
    5. int test_and_clear_bit(nr,void* addr);
    6. int test_and_change_bit(nr,void* addr);
  • linux/seqlock.h:
    > 1. seqlock_t lock=SEQLOCK_UNLOCKED;
    1. seqlock_init(seqlock_t* lock);
    2. unsigned int read_seqbegin(seqlock_t* lock);
    3. unsigned int read_seqbegin_irqsave(seqlock_t* lock,unsigned long flags);
    4. int read_seqretry(seqlock_t* lock,unsigned int seq);
    5. int read_seqretry_irqrestore(seqlock_t* lock,unsigned int seq,unsigned long flags);
    6. void write_seqlock(seqlock_t* lock);
    7. void write_seqlock_irqsave(seqlock_t* lock,unsigned long flags);
    8. void write_seqlock_irq(seqlock_t* lock);
    9. void write_seqlock_bh(seqlock_t* lock);
  • linux/rcupdate.h:
    > 1. void rcu_read_lock;
    1. void rcu_read_unlock;
    2. void call_rcu(struct rcu_head* head,void (func)(void arg),void* arg);
  • linux/param.h:
    > 1. HZ;

  • linux/jiffies.h:
    > 1. volatile unsigned long jiffies;
    1. u64 jiffies_64;
    2. int time_after(unsigned long a,unsigned long b);
    3. int time_before(unsigned long a,unsigned long b);
    4. int time_after_eq(unsigned long a,unsigned long b);
    5. int time_before_eq(unsigned long a,unsigned long b);
    6. u64 get_jiffies_64(void);
  • linux/time.h:
    > 1. unsigned long timespec_to_jiffies(struct timespec* value);
    1. void jiffies_to_timespec(unsigned long jiffies,struct timespec* value);
    2. unsigned long timeval_to_jiffies(struct timeval* value);
    3. void jiffies_to_timeval(unsigned long jiffies,struct timeval* value);
  • asm/msr.h:
    > 1. rdtsc(low32,high32);
    1. rdtscl(low32);
  • linux/wait.h:
    > 1. long wait_event_interruptible_timeout(wait_queue_head_t* q,condition,signed long timeout)//睡眠直到condition为真或超时;

  • linux/sched.h:
    > 1. signed long schedule_timeout(signed long timeout);

  • linux/delay.h:
    > 1. void ndelay(unsigned long nsecs);
    1. void udelay(unsigned long usecs);
    2. void mdelay(unsigned long msecs);
    3. void msleep(unsigned int millisecs);
    4. unsigned long msleep_interruptible(unsigned int millisecs);
    5. void ssleep(unsigned int seconds);
  • asm/hardirq.h:
    > 1. int in_interrupt(void);
    1. int in_atomic(void);
  • linux/timer.h:
    > 1. void init_timer(struct timer_list* timer);
    1. struct timer_list TIMER_INITIALIZER( function,expires,data);
    2. void add_timer(struct timer_list* timer);
    3. int mod_timer(struct timer_list* timer,unsigned long expires);
    4. int timer_pending(struct timer_list* timer);
    5. void del_timer(struct timer_list* timer);
    6. void del_timer_sync(struct timer_list* timer);
  • linux/interrupt.h:
    > 1. DECLARE_TASKLET(name,func,data);
    1. DECLARE_TASKLET_DISABLE(name,func,data);
  • linux/workqueue.h:
    > 1. struct workqueue_struct;
    1. struct work_struct;
    2. struct workqueue_struct* create_workqueue(const char* name);
    3. struct workqueue_struct* create_singlethread_workqueue(const char* name);
    4. void destroy_workqueue(struct workqueue_struct* queue);
    5. DECLARE_WORK(name, void (*function)(void *), void *data);
    6. INIT_WORK(struct work_struct work, void (function)(void *), void *data);
    7. PREPARE_WORK(struct work_struct work, void (function)(void *), void *data);
    8. int queue_work(struct workqueue_struct* queue,struct work_struct* work);
    9. int queue_delayed_work(struct workqueue_struct* queue,struct work_struct* work,unsigned long delay);
    10. int cancel_delayed_work(struct work_struct* work);
    11. void flush_workqueue(struct workqueue_struct* queue);
    12. int schedule_work(struct work_struct* work);
    13. int schedule_delayed_work(struct work_struct* work,unsigned long delay);
    14. void flush_scheduled_work(void);
  • linux/slab.h:
    > 1. void* kmalloc(size_t size,int flags);
    1. void kfree(void* kobj);
  • linux/mm.h:
    > 1. GFP_USER;
    1. GFP_KERNEL;
    2. GFP_NOFS;
    3. GFP_NOIO;
    4. GFP_ATOMIC;
  • linux/malloc.h:
    > 1. kmem_cache_t* kmem_cache_create(char* name,size_t size,size_t offset,unsigned long flags,constructor(),destructor());
    1. int kmem_cache_destory(kmem_cache_t* cache);
    2. void* kmem_cache_alloc(kmem_cache_t* cache,int flags);
    3. void kmem_cache_free(kmem_cache_t* cache,const void* obj);
  • linux/mempool.h:
    > 1. mempool_t* mempool_create(int min_nr,mempool_alloc_t* alloc_fn,mempool_free_t* free_fn,void* data);
    1. void mempool_destory(mempool_t* pool);
    2. void mempool_alloc(mempool_t* pool,int gfp_mask);
    3. void mempool_free(void* element,mempool_t* pool);
    4. unsigned long get_zeroed_page(int flags);
    5. unsigned long __get_free_page(int flags);
    6. unsigned long __get_free_pages(int flags,unsigned long order);
    7. int get_order(unsigned long size);
    8. void free_page(unsigned long addr);
    9. void free_pages(unsigned long addr,unsigned long order);
    10. struct page* alloc_pages_node(int nid,unsigned int flags,unsigned int order);
    11. struct page* alloc_pages(unsigned int flags,unsigned int order);
    12. struct page* alloc_page(unsigned int flags);
    13. void __free_page(struct page* page);
    14. void __free_pages(struct page* page,unsigned int order);
    15. void free_hot_page(struct page* page);
  • linux/vmalloc.h:
    > 1. void* vmalloc(unsigned long size);
    1. void vfree(void* addr);
  • asm/io.h:
    > 1. void* ioremap(unsigned long offset,unsigned long size);
    1. void iounmap(void* addr);
  • linux/percpu.h:
    > 1. DEFINE_PER_CPU(type,name);
    1. DECLARE_PER_CPU(type,name);
    2. per_cpu(variable,int cpu_id);
    3. get_cpu_var(variable);
    4. put_cpu_var(variable);
    5. void* alloc_percpu(type);
    6. void* __alloc_percpu(size_t size,size_t align);
    7. free_percpu(void* variable);
    8. int get_cpu();
    9. void put_cpu();
    10. per_cpu_ptr(void* variable,int cpu_id);
  • linux/bootmem.h:
    > 1. void* alloc_bootmem(unsigned long size);
    1. void* alloc_bootmem_low(unsigned long size);
    2. void* alloc_bootmem_pages(unsigned long size);
    3. void* alloc_bootmem_low_pages(unsigned long size);
    4. void free_bootmem(unsigned long addr,unsigned long size);
  • linux/interrupt.h:
    > 1.int request_irq(unsigned int irq, irqreturn_t (*handler)( ), unsigned long flags, constchar *dev_name, void *dev_id);
    2.void free_irq(unsigned int irq, void *dev_id);

  • linux/irq.h:
    > 1. int can_request_irq(unsigned int irq, unsigned long flags);

  • asm/signal.h:
    > 1. unsigned long probe_irq_on(void);
    1. int probe_irq_off(unsigned long);
    2. void disable_irq(int irq);
    3. void disable_irq_nosync(int irq);
    4. void enable_irq(int irq);
    5. void local_irq_save(unsigned long flags);
    6. void local_irq_restore(unsigned long flags);
    7. void local_irq_disable(void);
    8. void local_irq_enable(void);

前言:

在硬件系统出厂前要进行产品测试;在嵌入式系统工作之前,一般也要进行自检,其中DDR检测必不可少,可是有不少人对于测试目的、原因和方法存在错误理解。为什么要测试RAM,怎么测试呢?普遍的看法是:由于担心RAM芯片损坏,在出厂和使用前应该校验这两种芯片的好坏。测试RAM的方法是写读各个内存单元,检查是否能够正确写入;这种认识不能说错,但有些肤浅,照此编出的测试程序不完备。一般来说,RAM芯片本身不大会被损坏,用到次品的概率也比较小,真正出问题的,大都是其他硬件部分,因此,测试DDR往往是醉翁之意不在酒。


正文:

### RAM测试:
测试RAM的真正目的是保证硬件系统的可靠性。RAM真的是太不容易坏了,我至今还没有看见过一起因为RAM损坏导致的系统不正常现象。不过大部分问题却可以通过RAM测试反映出来。仔细想想,当硬件被生产出来/被插到背板上究竟会发生什么错误呢!是不是感到自己做的板子出问题的可能性更大!请考虑如下几点:

1.生产工艺不过关,过孔打歪了,与临近信号线距离不满足线规甚至打在了线上。<br>
2.由于搭锡引起的信号线粘连。
3.虚焊/漏焊引起的接触不良。
4.不按规程操作,把手印儿印在了高频线上。
5.板子脏了也不吹,覆盖了一层灰尘(内含金属微粒)。
......<br>

这些现象比较有趣,试举几例:

1.地址线A0和A1粘连。读出XXX00、XXX01、XXX10三个字节的数据完全一样。
2.数据线D0和D1粘连。D0和D1只要有一个为0,那么两条线都为0。
3.接触不良。时好时坏。
4.器件表面处理不干净,有助焊剂残留。低速访问正常,大负荷高速访问频繁死机。 <br>

总之,我们做的板子在生产中和使用中都会有出错机会,所以出厂前必须测试,使用前必须自检。(当然如果你做的不是实际产品而是实验室样品的话,可以简化步骤。)
如何测试RAM呢?写一个数然后读出来判断显然测不出所有问题,单个测试数据不易覆盖全部测试内容,更不用说定位错误原因了(RAM坏、地址/数据线粘连、接触不良)。好的测试应尽可能测出粘连、RAM坏、单板高频特性。
我总结的方法是这样的:(如测试一个FFH字节的RAM)

首先,测试地址线,
1.'0'滑动,随机选择一个数如55、AA之类,依次写到FEH、FDH、FBH、F7H、EFH、DFH、BFH、7FH地址单元里去,把地址写成二进制数,可以看到比特0在地址总线上从低到高滑动,谓之'0'滑动。目的是测试这些地址线在依次变0时是否稳定正常。当每一根线由1变0,会产生下冲,如果下冲控制不好,在高频时会引起错误。单板上地址线不一定一样长,下冲也就不会完全一样,因此,每一根线都单独测一下下冲性能。
2.'1'滑动,随机选择一个数如55、AA之类,依次写到1H、2H、4H、8H、10H、20H、40H、80H地址单元里去,把地址写成二进制数,可以看到比特1在地址总线上从低到高滑动,谓之'1'滑动。,目的是测试这些地址线在依次变1时是否稳定正常。当每一根线由0变1,会产生上冲,如果上冲控制不好,在高频时会引起错误。单板上地址线不一定一样长,上冲也就不会完全一样,因此,每一根线都单独测一下上冲性能。上冲和下冲是不同的指标,要分别测一下。
3."全0变全1",随机选择一个数如55、AA之类,写到FFH单元,再写到00H单元,然后写到FFH单元。把地址写成二进制数,可以看到地址线从全'0'变到全'1'。由信号处理理论知,在电压阶跃跳变时包含无限宽频谱,其中高频部分对外产生辐射,这些辐射信号是干扰源,对临近线路产生较大影响。地址线一般集束布线,同时跳变会引起最大干扰。地址线从全'0'变到全'1',干扰、上冲、扇出电流影响最大。
4."全1变全0",紧接上一步,随机选择一个数如55、AA之类,写到00H单元。把地址写成二进制数,可以看到地址线从全'1'变到全'0',产生最大下冲干扰。
5."粘连测试"。依次向不同地址单元写入不同数据并读出判断,如:1、2、3、4......此步骤捎带测试了RAM好坏。注意,千万别用相同数据测试,否则测不出粘连。
6.可选"全0全1连续高速变化"。目的是模拟最恶劣情况(大扇出电流、强干扰、上/下冲)。
<br>

然后,测试数据线,(原理与测试地址线相同,1、2两步顺带测试了数据线粘连)

1.'0'滑动,向某一固定地址依次写入FEH、FDH、FBH、F7H、EFH、DFH、BFH、7FH并读出判断。
2.'1'滑动,向某一固定地址依次写入1H、2H、4H、8H、10H、20H、40H、80H并读出判断。
3."全0变全1",所有单元置1(先清零再置1并读出判断)。
4."全1变全0",所有单元清零(清零并读出判断)。
5.可选"全0全1连续高速变化"。向某一单元高速交替写入若干全'0'和全'1',最后以全'0'结束。 <br>

至此,RAM测试完毕,同时全部存储单元清零。对于出厂检测程序,有较大发挥余地,如可以加入错误定位代码,自动指出错误原因和错误位置。 每一块单板的高频特性都会因为生产工艺误差(制板、材料、焊接、组装等)和使用情况而各不相同。同一块板子的高频特性在不同情况下表现也不相同。

** 综上所述,除了测试RAM好坏,大部分代码测的是单板硬件可靠性。 如果不关心高频特性,用原来的测试方法就差不多了(如果测试数据没选好,可能测不出数据线粘连),但应该认识到,测试RAM的主要对象不是RAM本身的好坏,而是连接RAM的单板硬件和线路。**

一. 前言

现在虽然出现了很多EMMC,并且在很多公司也开始更多的使用EMMC,但EMMC里使用的也是NandFlash,EMMC只是一个标准接口。在使用NandFlash时最重要的是对坏块的识别,避免将数据写入坏块中从而导致数据的丢失。既然是对坏块做检测,首先得明确什么是坏块:坏块就是无法通过program,erase操作改变相应的存储位且无法通过ECC究错来还原回原来的数据信息的块.下面我将对NandFlash的一些常识及对坏块识别的方法作出说明。


二. 正文:

  1. 首先得明确NandFlash的数据线,地址线(包括行列地址,块地址),指令线都是共用的8根信号线。一般通过把它们组合成5个字节,分5次送入NandFlash控制器中。
  2. 里面每一页的布局(8位的NandFlash):
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ++++ vector0 || vector1 || vector2 ||…|| vector7 || 预留区 || ECC校验区 || ++++
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    其中1vector=512Bytes , 1page=8vector=4K , 1block=64 / 32page;
  3. NandFlash坏块成员:
    1. NandFlash在出厂时就有的坏块(在出厂时由生产商在坏块头部标记成坏块,不同的生产商标记的地方不一样且标记的符号也不同,Micron镁光是在坏块的第一页的预留区的第一字节标记成0x00,即在首页的第4096字节处)
    2. 在用户使用过程中用坏了的坏块。

  4. 检测用户使用过程中出现的新的坏块的方法:
    通过在进行program/erase操作后和向NandFlash发送一个 statue command指令,它会返回操作是否正确,如果操作failed,说明可能是坏块(记住只是可能,呆会会说明原因)。
  5. NandFlash在出厂时就被标记了的坏块在擦除操作下会把坏块标志也擦除,因此在擦除前要先把这些被标记了的坏块地址存下来。
  6. 检测出的坏块的管理方式:
    首先要把NandFlash中由厂商标记了的坏块记录到一个坏块表bad block table中,然后再把检测出来的新坏块添加到坏块表中(有的人不光只维护一个坏块表,还在表中添加坏块映射,具体的就不在这说明了).
  7. 坏块检测的应用:
    在一些手机,平板等嵌入式产品中,通常用NandFlash,EMMC来存放boot loader,系统映像(多为linux kernel),用户数据,然而要确保系统能正确的装载到ram中就必须保证存放boot loader,kernel区中无坏块,用户数据区可以有坏块,因为linux kernel中有对NandFlash坏块进行动态维护,其代码路径为:…/linux-dir/dirvers/mtd/nand/nand_ttb.c;在用户空间我们不须要去管所存的地方是否是个坏块,因为kernel把ECC,坏块检测,坏块管理,负载均衡全做好了。

三.内容补充:

  1. 网上有很多网友都说NandFlash被标记的坏块中存在伪坏块(在正常环境下能正确存取数据的块),厂商所标记的坏块是在厂商安排的最恶劣的环境下进行数据存取测试的,那些没通过在恶劣环境下的块都被标记成坏块,而我们使用的环境一般都是在正常环境下,所以被标记的坏块有部分是可以使用的。但生产商在芯片datasheet中也明确说明了如果使用这些伪坏块存在很大的风险,所以还是不要用它们吧.
  2. 在正文中的tag 4中所说的只是可能为坏块现在在此说明原因:
    因为是正常的块中有时也会出现program,erase失败的情况(在读扰动,写扰动等情况下),那如何分辨是否是坏块呢?由扰动所引起的失败是有它们具体的表现形式的,这点可以看各大半导体开发商官方芯片手册,英文原版的说明的最清晰,我不喜欢把它们翻成中文.
  3. 以上的坏块检测与管理是最基本的方式,然而在很多实际工程中对Landflash进行坏块检测时并不仅仅是为了检测与管理坏块,其更重要的目的是为了检测硬件引脚的连接(是否有虚焊,引脚是否有沾连等)和引脚时序的可靠性.因此在一些大公司里就很少用软件方式去检测硬件的可靠性,而是通过套件进行边界扫描(Boundary scan),用的是JTAG接口,可以实时显示出硬件出问题的引脚.

正文:

  1. 在通过修改udev内的规则文件时,得注意键要大写.而且/etc/udev/在不同的主机里其里面的规则文件也不尽相同,所以在做嵌入式开发时只要复制所要的规则文件就行,不要把整个目录给替换掉.
  2. 内核信息存储在一个环形队列中,超过打印等级的内核信息会打印到/proc/kmsg文件中.当用cat,less查看此文件时,当内核无日志信息时此进程会阻塞.
  3. 如果不小心把/dev下的设备文件全删除了,可以重启主机就可以重新获得设备文件.

正文:

在PC机平台下的linux系统下都知道怎么用mount来挂载自己想用要的设备,
及各种文件系统,比如通过网络在嵌入式设备中挂载网络文件系统,方便把在
宿主机上编译好了的目标机可执行文件放到目标机上;然而在嵌入式设备上
要挂载一个U盘可不是那么容易,因为嵌入式设备系统要做得小,命令使用
busybox,其它的文件也不多,所以在为嵌入式设备编译内核时不会选择过多
的不用的组件进来,在本讲当中所要说的就是不会把所支持的所有文件系统
选择进来,从而导致只能挂载个别几个所选择的文件系统,因此如果要支持
挂载其它的文件系统时,最快最省事的方法就是重新编译内核;另一种方式
就是用类似ntfs-3g的方式来支持.