top level

1, 调试前肩后肩的驱动,那个文件是那个设备的驱动?,lcd刷新频率。

2,MMC sdiosd驱动框架看下;大概了解记忆sdio协议。复读一下wifi驱动的框架,

3,i2c驱动框架。

4,Makefile基本常识基本语句

 

 

 

 

 

 

1,解决过什么问题:收货什么经验,自己的review的总结:

         1,解决当wifi没有连接到路由器上时,此时通过ioctl关闭wifi接口,导致死锁的问题:

         解决没有连接wifi时,关闭wifi功能,导致死锁的问题:

         原因如下:管理wifi的连接用的软件wpa_supplicant,当没有连接上wifi时,wpa_supplicant软件会一直执行搜索热点的代码,这部分代码中会获取了一个锁,而且不释放,直到搜索到热点。

         但是此时在应用程序用关闭接口wlan0是通过ioctl的方式。这个ioctl在内核中执行的时候,会尝试获取同一个锁,但是这个锁一直被wpa_supplicant程序的scan部分的代码占用而不释放,导致应用程序死锁。

 

         解决方法:关闭wlan接口不用ioctl和ifconfig的方式,而是用wpa_supplicant软件的命令关闭接口。因为用wpa_supplicant关闭接口时,wpa_supplicant自动回停止搜索热点的任务,释放这个锁,然后再关闭这个接口。

 

 

 

 

         (连接wifi用的软件:system("wpa_supplicant-Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -B &");)

         死锁的文件:/root/802/trunk/wl18xx/workplace/wl18xx/net/wireless/scan.c

         函数为:voidcfg80211_sched_scan_stopped(structwiphy *wiphy)

         //rtnl_lock();

         //rtnl_unlock();

         改正是在应用程序中,关闭wifi不用ifconfigwlan0 down,而是通过wpa_supplicant进程关闭wifi.

 

 

 

 

2,解决不能识别wifi模块的问题。装上wifi模块后,系统中没有wlan的接口。

         因为这个wifi模块时sdio协议的模块,所以我先查看了一下这个sdio设备是不是probe成功了。发现系统中的sd卡probe成功了,但是wifi模块的sdio设备没有probe成功。所以我用示波器量了一下mmc管脚的 CMD 管脚,发现mpu的probe命令确实发出来了,所以我猜测应该wifi模块硬件没有正常工作。但是量了一下wifi模块的晶振和周围的电阻电容都没啥问题。就让硬件工程师重新焊接了这个BGA的wifi芯片。重焊接后还是不行,后来重新购买了别的厂家的wifi模块,就正常工作了。

 

3, SD 卡在uboot中能正常读写,但是在kernel中不能正常读写。

         发现是是mmc管脚中的 DAT_2 管脚没有焊好。

         能在uboot中正常工作,是因为在uboot中,读写sd卡的模式没有用到中断,也没有 DAT_2 进行数据传输,只用到了 DAT_0 。所以能正常通信。但是在内核中,为了加快读写速度,用到了中断,而且读写模式中 DAT_0, DAT_1, DAT_2, DAT_3 都会进行数据传输。所以在内核中读写会出问题。

 

4,

 

 

 

 

 

 

 

 

1, u-boot.bin大小:208K

uImage大小:2.2M

 

2, MPU: Cortex-A8     ARMv7 architecture

  DSP: C64x 

 

 

 

3,缩短启动时间所做工作:

         1,bootDelay设置为1second     :#define CONFIG_BOOTDELAY                1

         2,设置uboot中的silent_console :  #defineCONFIG_SILENT_CONSOLE         1

         3,内核启动参数加上启动参数:  kernel启动参数添加loglevel=0

                   kernel启动参数添加loglevel=0:

                   "nandargs=setenvbootargsconsole=${console} root=${nandroot} vram=32M omapfb.vram=0:32M mem=${mem}mpurate=${mpurate} loglevel=0 \0"

         4,所有与视频显示无关的驱动都编译为模块,后续再modprobe加载,减少内核大小,缩短内核加载时间。

 

 

4, platform_device驱动框架:

   1,当调用函数platform_driver_register()注册设备驱动时,会把driver结构体里的name和所有注册的platform_device的id_table或者name(id_table不存在就用name)做匹配,如果匹配成功,就调用dirver里的probe函数,驱动就注册成功。如果没有匹配成功,那么driver注册失败。     

 

5,在中断处理函数中,经常把具体的操作函数放到workqueue中,然后调用schedule_work(mmc_carddetect_work)函数,让内核线程去执行这个任务,而不是直接在中断函数中去执行这些操作。

 

6,字符设备和块设备的区别:

    1,字符设备:提供连续的数据流,应用程序可以连续读取,通常不支持随即读取。调制解调器是字符设备。

    2,块设备:应用程序可以随机访问设备数据,程序可以自行确定读取数据的位置。硬盘是典型的块设备。

 

 

7,多个USB设备用VID PID区分;多个SDIO设备用CID (cardidetifier) 区分。

 

8, ti mmc驱动框架:

    1,初始化一个mmc_host的设备和驱动,并在驱动模块init的函数中调用mmc_host驱动的probe函数,在probe函数完成mmc_host驱动的初始化和注册,在probe的最后,执行scan函数,搜索在该mmc总线上是否存在mmc设备。搜索过程是,先发送sdio探测命令如果有回复,则断定是sdio设备,则这是就在系统中创建sdio设备,并初始化;然后发送sd探测命令,如果恢复证明是sd设备,并在系统中创建一个sd设备;然后发送mmc探测命令,如果有回复就断定mmc线上有mmc设备存在,并在系统中创建mmc设备。mmc设备是可以热插拔的,所以当有mmc设备插入时,此时触发管脚中断,中断会执行探测mmc设备的任务,并创建对应的设备。

 

9,通过c语言的“回调函数”实现C++的多态、虚函数的功能了。还有就是一个用i2c通信的电源管理芯片,有自己对应的驱动程序。但是这个驱动中肯定会创建一个i2c_client的设备,然后通过设这个i2c设备和硬件通信。这就像是这个电源的驱动程序继承了i2c的驱。

 

10,系统用的 UBI_FS

 

 

11, lcd刷新帧率为 60 f/s

#define FB_HFP               200 //8 /* front porch */

#define FB_HSW               0 //3  /* hsync width */

#define FB_HBP               46 //13 /* back porch */

 

#define FB_VFP               10 //5  /* front porch */

#define FB_VSW               12 //1  /* vsync width */

#define FB_VBP               23 //7  /* back porch */

 

#define FB_HRES              800     /* horizon pixel  x resolition */

#define FB_VRES              480     /* line cnt       y resolution */

 

#define FB_VFRAME_FREQ       60     /* frame rate freq */

#define FB_PIXEL_CLOCK       (FB_VFRAME_FREQ * (FB_HFP + FB_HSW +FB_HBP + FB_HRES) * (FB_VFP + FB_VSW + FB_VBP + FB_VRES))

 

 

 

12, 摄像头用的media框架。其中包括很多entity实体,entity通过media link来设置数据的流向。entity包括ccdc,resizer,preview,adv7280等等。

         视频采集过程:adv7280把cvbs信号转为bt656,ccdc采集bt656数据流,并保存为yuv数据。yuv数据传给isp模块,isp模块通过video2 layer处理,最终和grahpic layer根据color key叠加,最终输出为rgb888的并行数据,通过lcd的时序传给oled设备。

 

 

//

1, GNU C 增加了关键字typeof,gcc编译器能处理这个关键字。这个关键字能根据变量推导出表达式的类型(如定义int型指针变量:typeof(&var) pvar = &var;   ),这个typeof关键字实现了C++泛型编程中的模板的功能。

如:#define max(x, y)     ({   \

         typeof(x)_tmp_x = x;       \

         typeof(y)_tmp_y = y;       \

         _tmp_x>_tmp_y ? _tmp_x : _tmp_y})

 

这个typeof在内核的list中有重要应用。通过这个typeof实现了通过list_node找到对应的数据的功能。

 

 

 

//

宏定义:__init,用于告诉编译器相关函数或变量仅适用于初始化。编译器将标__init的所有代码存放在特殊的内存段中,初始化结束后释放这段内存。

如:

static void __initinit_mount_tree(void)

{

}

 

 

字符设备相关:/ /

文件char_dev.c

管理所有字符设备cdev的结构体:kobj_map,在文件中char_dev.c中。内核中所有的字符设备cdev都在这个哈希链表中。

static structkobj_map *cdev_map;

 

//调用函数cdev_add(structcdev*p, dev_tdev, unsigned count)把字符设备cdev添加到哈希链表cdev_map后,就能在内核中操作该设备了

 

 

structkobj_map {

         struct probe {

                   struct probe*next;               //主设备号相同的设备的链表

                   dev_tdev;

                   unsigned longrange;

                   struct module*owner;

                   kobj_probe_t*get;

                   int(*lock)(dev_t, void *);

                   void *data;

         } *probes[255];                      //主设备号作为索引

         structmutex *lock;

};

 

/*******************************************************************************************************************************

probe[255]               =>  probe[0]  probe[1]   probe[2]   probe[3]  probe[4]   probe[5]   probe[6] ...  probe[254]  

lock                                   |                     |

                                            |next    |next                                                       . 

                                           \/                      \/

              probe space  probe space                                .

              |                          |

                                            |next          |next                                           .

                                           \/         \/                                  

                      probe space   probe space                                        .

                                           .                        .

                                           .                        .

                                           .                        .

*******************************************************************************************************************************/

该文件对外提供的接口:

//设备cdev调用此函数添加到哈希链表cdev_map后,就能在内核中操作该设备了

intcdev_add(structcdev *p, dev_tdev, unsigned count)

{

              p->dev = dev;

              p->count = count;

              return kobj_map(cdev_map,dev, count, NULL, exact_match, exact_lock, p);//把设备添加到了哈希链表cdev_map中

}

 

//

structcdev{

              structkobjectkobj;                          //包含一个kobject结构体,相当于继承了基类kobject

              struct module*owner;

              conststructfile_operations*ops;

              structlist_headlist;                        //链接很多inode的链表头,删除该cdev时,要先释放该链表上所有的inode空间

              dev_tdev;

              unsigned int count;

};

 

/

块设备相关:/ //

块设备的注册和删除不在block_dev.c文件中,而在genhd.c文件中。设备的注册和删除与字符设备相似,也是用一个内部的哈希链表static structkobj_map *bdev_map;来维护。

 

该文件对外提供的接口

1,添加块设备的接口:voidadd_disk(structgendisk *disk)

/**

 *add_disk - add partitioning information to kernel list

 *@disk: per-device partitioning information

 *

 *This function registers the partitioning information in @disk

 *with the kernel.

 *

 *FIXME: error handling

 */

 

 

 

3,extern structkobject*block_depr;主要用于sysfs文件系统

 

 

 

看一个系统的模块,先看这个模块对外(其他模块)的接口(extern函数和extern的全局变量),然后看这个模块内定义的所有数据结构struct,就基本上能抓住这个模块的功能和框架。

 

 

 

系统调用syscall:

应用程序通过调用库函数(libc),在库函数里通过一个软中断指令swi(int 0x80),让系统转入内核态,然后通过传入参数,判断是哪个系统调用,找到对应的处理例程。处理完成后,返回到应用层。

 

就是通过让cpu执行一条软中断(swi)指令,让cpu从用户态(usr)模式陷入内核态(svc)模式。这样cpu就能访问所有资源。

 

内核同步与并发:

主要有中断屏蔽、原子操作、自旋锁、信号量,用的最多的是自旋锁和信号量。

 

 

阻塞读取与非阻塞读取:

阻塞读取时,当执行驱动程序的write read函数时,如果设备没有数据,write()和read()函数内部会把当前进程挂起,__set_current_state(TASK_INTERRUPTIBLE);,并执行调度程序schedule()。当有数据时,再唤醒当前进程。

 

 

中断处理:

在中断处理函数中,中底半部机制包括:tasklet工作队列软中断(面试题)

1,在需要调度tasklet的时候引用一个tasklet_schedule()函数就能是系统在适当的时候进行调度运行。

 

Irqreturn_txxx_interrupt(intirq,   void *dev_id)

{

….

Tasklet_schedule(&xxx_tasklet);

….

}

 

 

2,工作队列的使用方法和tasklet非常相似:

Irqreturn_txxx_interrupt(intirq, void*dev_id, structpt_regs *regs)

{

Schedule_work(&xxx_wq);

Return IRQ_HANDLED;

}

 

 

总线、设备与驱动:

在linux2.6的设备驱动模型中,关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配总有总线完成。

 

 

Platform

一个现实的linux设备和驱动通常都需要挂接在一种总线,对于本身依附于PCI、USB、I2C、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,soc系统中集成的独立的外设控制器、挂接在soc内存空间的外设等却不依附于此类总线。基于这一背景,linux发明了一种虚拟总线,称为platform总线,相应的设备为paltform_device,而驱动称为platform_driver。

 

 

驱动的写法:

首先判断这个设备是否可以随机读写,如果可以随机读写就是块设备,不可以就是字符设备。因为linux的设备驱动模型是描述bus、device、driver。写驱动前,先判断这个设备是挂在什么总线(bus)上。如果是i2c的设备,那么可以确定挂在i2c 总线(bus)上,那么用系统提供的i2c接口函数,创建一个i2c的设备和i2c的驱动,然后注册到系统中就行。如果是设备是一个soc芯片里的外设(外围设备),那么可以确定这个总线是platform总线(虚拟总线),首先要创建一个platform设备,然后创建对应的platform驱动,然后加到系统中。

 

 

Bus device driver驱动模型的好处,将数据和操作分开,降低程序耦合,低耦合,易扩展。移植程序的时候,只需要更改device的数据就行。Device内是设备的数据,driver是设备的操作(函数)。

 

设备对字符设备cdev和块设备block_dev这两种设备的继承,实现了程序的复用。自己的设备只要继承这两个基类,就能在内核的驱动模型中正常工作。

 

在linux驱动中,包含有i2c、spi、mmc、power、rtc、input、platform等驱动接口,这些接口都是和具体的硬件平台无关的,三星的芯片和ti的soc芯片上都会有i2c的外设,都会有input型的设备,在这些平台上创建i2c设备和input设备只需要用linux提供的对应的接口就行,实现了代码的复用。这些驱动代码向下提供操作具体平台硬件(寄存器操作/填充相关数据,比如配置mmc host寄存器)的接口,向上提供具体设备的接口(比如自定义的旋钮开关的input设备)。

 

 

Linux的bus、device、driver模型能把硬件平台相关的host和具体的外设(比如i2c的eeprom,i2c的rtc;mmc的tf卡和mmc的wifi模块)通过bus来隔开,求耦合。

 

 

 

//自定义bus(总线)驱动的开发流程:

 

1,  首先通过/drivers/base/bus.c文件提供的接口bus_register(structbus_type *bus),注册自己的总线类型(bus_type)。

 

这个接口注册这个bus_type对象后,会把该bus_type添加到一个kset中:bus_kset。这个bus_kset串联了所有bus_type对象。这个bus_kset在sysfs中对应的目录是:/sys/bus。

 

2,然后通过文件/drivers/base/bus.c提供的接口bus_add_device(structdevice *dev)把device添加到内核(添加到device所在的bus上的klist_devices这个klist链表上)。

 

这个接口把device添加到对应的(在device内部保存它所在的bus)bus上的klist_devices链表中。只是添加,不会probe对应的驱动driver。

(但是文件/drivers/base/bus.c还提供了bus_probe_device(structdevice *dev)接口,供上层文件/drivers/base/core.c添加设备device_add()时:先调用bus.c文件的bus_add_device()添加设备,然后调用bus文件的bus_probe_device()探测设备。所以,其实内核添加设备时候,也会自动探测初始化设备devcie。)

 

3,然后通过/drivers/base/bus.c文件提供的接口bus_add_driver(structdevice_driver *drv)把device_driver添加到内核(添加到device_driver所在的bus上的klist_drivers这个klist链表上)。

这个接口把device_driver添加到所在bus的klist_drivers这个链表中。添加完后,和该bus上所有的device进行match匹配(这个match方法是bus的方法)。【匹配过程:如果比较dev_ID table或者比较name字符串相同,则继续调用bus上的probe方法,如果bus上的probe方法不存在,则调用devcie_driver上probe方法初始化device。】

 

 

 

注:一般情况下,设备和驱动都要在struct device和structdevice_driver的基础上添加自己的内容,继承它们。都要把struct device和structdevice_driver嵌套在自己的设备和驱动中。比如i2c bus的设备和驱动:struct i2c_client和struct i2c_driver,分别嵌套了struct device和structdevice_driver结构体。

 

 

所以如果要让设备和驱动互相能找到要符合的条件:

1,首先是两者挂在的bus相同,即device的structbus_type      *bus成员和devcie_driver的structbus_type*bus成员。

2,然后两者的id_table或name相同,这样bus在match的时候,当符合“两者的id_table或name相同”这个条件后,才会继续调用bus或device_driver的probe初始化设备device。

 

 

 

 

 

 

 

 

 

TiDM3730 SOC芯片的驱动中,除了一般通用的i2c、platform(虚拟)、mmc、usb等总线外,还添加了两个虚拟总线:omapdss和media两条虚拟总线。其中omapdss是实现了ti平台的显示模块的驱动,media是实现了多个视频相关的entity之间的互联的功能。(这部分需要继续看!!!)

 

//字符/块设备是驱动模型driver-model和文件系统的交界概念。

 

 

 

 

 

 

 

 

 

 

视频信号编解码:

入口:通过解码芯片把cvbs信号解码成数字信号ITU-R BT.656,

出口1:通过编码芯片把rgb888编成模拟信号。

出口2:通过oled屏显示rgb888

 

 

 

ADV7280是Decoder芯片

Adv7280把模拟信号解码成数字信号

 

 

 

CH7025/CH7026 TV/VGA Encoder芯片

Ch7026是encoder芯片:把数字信号编码成模拟信号

 

 

 

 

 

 

Driver-model中的bus的match函数:

Platform总线和i2c总线和spi总线的匹配函数都是比较(device_driver中的id_table中的name字符串)和devcie中name字符串项。

Sdio总线的match函数:比较: class、vendor_id、device_id

structsdio_device_id {

__u8       class;                                  /*Standard interface or SDIO_ANY_ID */

              __u16     vendor;                               /*Vendor or SDIO_ANY_ID */

              __u16     device;                                /*Device ID or SDIO_ANY_ID */

              kernel_ulong_tdriver_data      /* Data private to the driver */

                            __attribute__((aligned(sizeof(kernel_ulong_t))));

};

 

 

 

 

 

内核中每一个kobject都对应sysfs文件系统中的一个目录。kobject的每个属性attribute都对应着该目录下的一个文件,这些attribute(文件)保存的内容一般都是ascii字符串,用户可读的。(有时候也是二进制,比如上传设备固件)

 

 

 

 

什么时候用spin_lock()spin_lock_irq()spin_lock_irqsave():

1,   如果是内核中不同进程共享资源,则用spin_lock()就行。

2,   如果进程和中断处理函数中都用到了共享资源,要用spin_lock_irq()。因为当进程A获得了spin_lock后,此时产生中断,该进程A被设置为TASK_INTERRUPT不会被执行,所以不会释放锁,中断程序会一直尝试获取锁spin_lock而忙等busy_wait,所以产生了死锁。

3,   如果不能确定获取锁之前的中断使能状态,就要用spin_lock_irqsave(),获取锁之前,先保存当前中断使能状态,当使用完锁后,再恢复原来的中断使能状态。(因为spin_unlock_irq()执行后,默认会使能系统中断)

 

日志:

如果在终端上看不到printk输出,可以通过查看 /var/log/messages文件,或者直接运行dmesg命令查看,或者查看 /proc/kmsg。

/var/log/messages  : 几乎所有的开机系统发生的错误都会在此记录。

dmesg命令:kernel会将开机信息存储在ring buffer中,dmesg用来显示内核缓冲区(kernel ring buffer)内容,内核将各种信息存放在这里。内核将与硬件和模块初始化相关的信息填到这个缓冲区中。

 

printk打印的时间单位是秒,“.”之前的是s,  ”.”之后的是us

如:

[   27.576202] usb usb1:Manufacturer: Linux 2.6.37 ehci_hcd

27秒576202微妙的时候

 

我做的内容:

在oled_panel驱动中,给i2c_client包含的device内的kobject (i2c bus 上的device) 添加了亮度、对比度等属性attribute。这样在用户空间可以读写oled_panel的属性。(看看lcd的驱动中是不是包含这个i2c配置寄存器的驱动代码)

1,在gpio_key旋钮开关的驱动里,在timer定时器对应的处理函数中,当访问4个gpio对应的4bit的数值code时,要加上一个自旋锁spin_lock_irq()避免并发存取的问题(或者使用原子操作)。因为和管脚触发的中断程序要写入往这个code变量里写入数据。

 

 

Wifi相关:
1,上电后系统启动,通过系统模块接口subsys_initcall(mmc_init);在这个模块初始化函数中,注册了两个总线类型bus_type,分别是mmc总线和sdio总线。Wifi模块用的是sdio总线。这样,driver-model的bus就注册到系统中了。

2,系统加载mmc_host这个外设的驱动的模块时,在module_init(omap_hsmmc_init)这个模块初始化函数中,初始化了mmc_host这个外设的寄存器,申请了一个管脚中断,并注册中断处理函数,这个管脚中断判断卡的插入和拔出。   在这个初始化函数的最后,(mmc_rescan函数)搜索mmc总线上是否存在设备,host先发命令探测是否存在sdio卡,再探测是否存在sd卡,最后探测mmc卡。

当host收到sdio卡的回复response后,就读取sdio卡的vendor id(供应商id)和device id(设备id),然后创建sdio_func设备并注册到sdio bus上。

3, wifi模块的驱动device_driver是注册到sdio总线上的驱动。sdio总线通过match匹配sdio_func设备的vendor id和device id将wifi设备和驱动进行绑定。

 

 

 

 

 

系统上电后,初始化系统子模块的时候,通过初始化函数sbusystem_init()函数里,注册了mmc_bus和sdio总线。然后系统加载platform设备的mmc_host这个外设的platform总线的设备的驱动。mmc_host模块module初始化过程中,初始化外设的寄存器,申请检测sdio插入拔出的管脚的中断。注册中断处理函数。最后在mmc总线上搜索mmc_rescan总线上的设备。先探测sdio卡,然后是sd卡,然后是mmc卡。如果收到sdio卡的response,说明存在sdio卡,然后读取sdio卡的vendor id供应商id和device id设备id,并且创建sdio_func这个设备对象,并注册到sdio总线上。这个vendor id和deviceid就是sdio总线就行驱动和设备进行match的比较的东西。这个wlt1833模块有两个function,一个是wifi,一个sdio_uart,在本系统中没有用到串口。这是sdio的device(sdio_func)已经注册到sdio 总线上了。然后就是wlcore的驱动模块的加载,当加载这个wlcore驱动时,就是把这个sdio总线上上的驱动注册到这个sdio总线上,通过他们的vendor id 和device id 把wifi驱动和设备进行了绑定。然后就是驱动中probe函数对设备进行初始化。

 

 

1, 感觉块设备block_device和字符设备cdev的区别,就是块设备多了一个请求队列request_queue_t,让访问硬件的效率和系统效率变高了。

 

 

 

 

 

 

网络接口的event:

内核中网络接口的驱动模块和网络协议模块是分开的(没有耦合)。网络协议模块对网络接口的访问就是通过net_device对象,它代表着一个网络接口硬件。  当硬件net_device状态有什么变化时,就会通过事件event通知内核的网络模块(事件evetn定义在notifier.h文件中)。

 

启动过程中的net event相关的log:

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

=== Loading App...===

Root filesystem already rw,not remounting

logger: mount: mount point /dev/shmdoes not exist

Configuring networkinterfaces... [    8.248657]<---file:net/ipv4/devinet.c func:inetdev_event line:1041 -->

[    8.255706] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0xd -->

[    8.264221] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1041 -->

[    8.271209] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0x1 -->

[    8.325012] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1041 -->

[    8.332061] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0xd -->

[    8.340637] net eth0: SMSC911x/921xidentified at 0xd60d4000, IRQ: 217

[    8.347686] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1041 -->

[    8.354705] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0x1 -->

done.

Setting up IP spoofingprotection: rp_filter.

INIT: Entering runlevel: 5

#############################File:/etc/init.d/rc ... ##############################################

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

therunlevel is :

5

the previous runlevel is:

N

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

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

Find the rc* directory,andthe run-level is:

5

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

Starting system message bus:dbus.

#################################File: /etc/init.d/rc.local #####################################

Starting telnet daemon.

Starting syslogd/klogd: done

 

http://www.bd-corp.cnbd-corp ttyO0

BD 2015.10 bd-corp ttyO0

 

bd-corp login: [   10.196105] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1041 -->

[   10.203155] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0x4 -->

[   11.195495] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1041 -->

[   11.202484] <---file:net/ipv4/devinet.cfunc:inetdev_event line:1061 event_value:0x4 -->

 

 

 

 

 

 

 

 

 

经常提到的rtnl和文件rtnetlink.c文件相关,文件路径是:/net/core/rtnetlink.c

 

Rtnl可能是 Routing netlink的缩写。

 

*      Routingnetlink socket interface: protocol independent part.

 

 

 

 

 

 

 

用户空间user space访问字符设备、块设备是通过/dev/ 目录下的设备节点来访问;而网络设备是通过 socket接口来让用户空间访问。

 

用的是bsd socket:

* INET                An implementation of the TCP/IPprotocol suite for the LINUX

 *              operatingsystem.  INET is implemented usingthe  BSD Socket

 *              interfaceas the means of communication with the user level.

 

 

 

 

ifconfig源码中:

ifconfig源码中,程序先创建了一个socket,然后通过ioctl来对接口进行操作:创建socket的语句: int s =socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0))或者s =socket(AF_LOCAL, SOCK_DGRAM, 0))

 

执行ifconfig eth1 192.168.2.18  命令时,也是通过ioctl(s,SIOCAIFADDR, param)来设置的接口的ip。

执行ifconfig eth1 up   时,也是通过  ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr)

 

 

 

Ethernet芯片smsc  LAN9220驱动相关:

SmscLAN9220的驱动挂platform总线上。因为smscLAN9220芯片(sram-likeinterface)挂在系统总线上。

在这个platform设备的寄存器等初始化完成后,创建一个net_device设备,并(调用register_netdev()函数把net_device)注册到到网络子系统中,这样,系统就能用这个网络接口interface了。

 

每一个net_device里面都有一个供发送用的队列queue,如果队列不满的时候,网络子系统还能继续往队列里放数据,从而从接口往外发送;如果满了,就不能继续往队列发了。当接口往外发了数据后,queue的数据不满了,就通知网络子系统,这个queue又能收数据了。

 

 

SMSC LAN9220里的PHY物理收发模块这个设备是挂在mdio总线上的。PHY是用一个状态机(相关函数phy_state_machine())来管理的。当PHY外部状态(cable 、carrie、speed等)有所改变时,产生phy中断,此时就调用phy_state_machine()来处理状态的改变。

 

 

 

硬件设备的驱动一般都是用中断的方式,除非设备的数据量太大,导致对cpu的中断过于频繁,反而影响了cpu的效率。这是就采用轮询poll的模式。所以网络设备一般都有一个napi的功能接口。(之前之所以说poll的方式效率低,是因为数据量小,如果每次轮询都能获取数据的话,那就不存在效率低的问题)

 

 

内核的网络模块(/net/core/…)和网络硬件驱动模块(/driver/net/… ) 是通过net_device这个结构体连接起来的。

 

 

 

FIFO(First In First Out全称是先进先出的存储器:
   FIFO只允许两端一个写,一个读,因此FIFO是一种半共享式存储器。在双机系统中,只允许一个CPU往FIFO写数据,另一个CPU从FIFO读数据。FIFO的仲裁控制简单,但其容量不如双口RAM。由于先进先出的特点,特别适合数据缓冲和突发传送数据。某些芯片的内部就集成小容量FIFO,例如,DSP的同步串口就集成两个FIFO,用于接收和发送数据缓冲。FIFO只给外部提供一个读和一个写信号,因此CPU用一个I/O地址便可读或写FIFO,使硬件趋于简单,给编程也带来一些方便,但CPU不能对FIFO内部的存储器进行寻址
 
 

 

 

 

SMSC LAN9220里写数据的时候,都是写到同一个地址(在芯片挂在系统总线的基地址的基础上加上TX_DATA_FIFO所在的偏移地址0x20)写),这个地址就是芯片SMSC LAN9220内部的硬件FIFO的地址。

 

Uboot中往LAN9220里写数据的代码为:

         while(tmplen--)

                   pkt_data_push(dev, TX_DATA_FIFO, *data++);

 

其中pkt_data_push()函数就是语句:*(volatile u32*)(dev->iobase + offset) = val;

 

从内存中往smsc Lan9220的硬件TX_DATA_FIFO传输的数据,是完整的以太帧(mac frame),包括硬件mac目地地址、硬件mac源地址等mac层信息,(就是说mac目的源地址信息不是mac硬件自动添加上的,那mac内保存的自己的mac地址,可能就只是用来filter收到的帧)

 

与此类似,cpuRX_DATA_FIFO读出的数据,也是一个完整的以太帧(mac frame),也是包含硬件mac源地址、目的地址等mac层信息。

 

 

 

 

 

 

看当前在uboot中,smsc Lan9220没有使用中断,都是往FIFO写入一帧数据后,一直查看LAN9220的状态位。

 

 

 

 

 

 

 

 

驱动调试工具:

 

1,查看当前存在的死锁的工具:

 

 

 

1, 要做到事:!!!

 

解决那个lan920,一开始不插网线启动板子,之后再插入网线,依然不能网络通信的问题。

 

 

 

 

什么是架构:

片面上讲,我们可以将架构理解为内核所使用的指令集。例如:用于高端的(手机等)Cortex-A8,Cortex-A9等内核用的是ARMv7-A架构,或者说用的是ARMv7-A指令集架构,我们常用到的STM32的Cortex-M3内核用到的是ARMv7-M架构

 

Cortex是ARM公司设计的内核系列名称,如Cortex-A8、Cortex-A9等,ARMv7是一种内核的架构。

一种内核架构会被厂商用于多种内核中,如ARM Cortex-A5、ARM-Cortex-A7、Cortex-A8、Cortex-A9……都采用ARMv7-A架构。

 

The ARMCortex-A8 is a 32-bit processor corelicensed by ARM Holdingsimplementing the ARMv7-A architecture.

 

The 32-bit ARMarchitecture, such as ARMv7-A,is the most widely used architecture in mobile devices.[32]

 

大小端格式:

Little-Endian:高字节在高位(arm cpu内部处理的指令就是little-endianInstructions are always treated aslittle-endian

Big-Endian:高字节在低位(一般通信用大端格式big-endian

举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

1)大端模式:

低地址 -----------------> 高地址
0x12  |  0x34  |  0x56  |  0x78

2)小端模式:

低地址 ------------------> 高地址
0x78  |  0x56  |  0x34  |  0x12

可见,大端模式和字符串的存储模式类似。

 

 

内核的文件系统file_system_type有很多种,比如ext2、ext3、jff2、ramfs、rootfs、bdev、chardev等,内核启动的时候,先注册了rootfs文件系统,然后调用该文件系统的rootfs_mount函数,rootfs_mount调用power.c中的mount_nodev(),在这个函数中分配了一个跟file_system_type rootfs类型对应的超级块super_block,然后调用ramfs_fill_super填充了这个超级块的一些基本参数(比如s_magic等等),并用ramfs_get_inode()分配了一个节点inode,然后分配了一个名称为"\" 目录dentry,并把这个dentry和inode对应起来。同时把这个dentry赋值给这个super_block中的s_root,到此这个根目录"\"就挂载完成了。每个文件系统类型file_system_type可以对应着多个超级块super_block对象(比如两个硬盘设备对应两个super_block)。每个超级块中保存着该(外存中)文件系统的相关信息。同时super_block中还保存着很多链表头,比如已经分配所有的inode的链表头s_inodes,已经分配的file的链表头s_files。所以通过这个super_block对象保存着与该文件系统相关的所有信息。而file_system_type是通过自己的成员fs_supers(是一个super_block的链表头)来找到已经分配的所有的super_block。

 

 

 

 

环境变量

1,系统中环境变量的作用:

Environment variables are aset of dynamic named values that can affect the way running processes willbehave on a computer.

They are part of theenvironment in which a process runs. For example, a running process can querythe value of the TEMP environment variable to discover a suitable location tostore temporary files, or the HOME or USERPROFILE variable to find thedirectory structure owned by the user running the process.

 

 

1,PATH环境变量的作用:指定命令的搜索路径

 

 

 

linux 下设置环境变量:

1, 永久设置:修改/etc/profile文件或者修改/etc/profile.d目录下的文件。

如:$vim /etc/profile

         $source /etc/profile (或者 $./profile )

 

2, 临时设置:用export命令,在当前终端下声明环境变量,关闭shell终端失效。

如:export PATH=$PATH:/usr/local/new/bin

 

 

 

 

 

常用命令:

查看某个环境变量:

$echo $PATH

 

设置一个新的环境变量:

$export HELLO=hello

 

查看所有环境变量:

$env

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值