完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
3个回答
|
|
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 ” 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、u***等总线外,还添加了两个虚拟总线: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] u*** u***1: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设备和驱动进行绑定。 系统上电后,初始化系统子模块的时候,通过初始化函数***usystem_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收到的帧) 与此类似,cpu从RX_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-endian。Instructions 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 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1867浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
650浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
518浏览 3评论
536浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 14:37 , Processed in 0.885433 second(s), Total 83, Slave 66 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号