技术标签: ARM开发之S5PV210(Cortex-A8)
210学习日记(15)
--移植DM9000网卡驱动
我想,大家学习到这里,写了一些裸板程序,对S5PV210应该算是比较了解了吧,而且已经写出了一个比较满意的bootloader来了,肯定是想上系统玩玩驱动了吧!
我在"Tiny210学习日记(1)"中提过,要在从内核官网上面下载的纯净的Linux系统上面玩驱动,那么你要不得支持网卡,要不得有MTD分区,因为我们要挂接系统。
接下来说说我是怎么一步一步移植DM9000网卡驱动的:
(在看以下具体操作步骤之前,强烈建议大家把韦东山视频里面关于dm9000的类容和在一起,拉通看一次,讲得太详细了)
1.当自己写好的bootloader成功引导内核时,查看内核的启动信息,发现没有任何网卡相关的启动信息;
注意:
问:这里是使用的官方提供的默认的配置文件s5pv210_defconfig去配置编译内核的。可是将编译出的 zImage烧写进开发板,启动的时候,发现串口无任何启动信息输出,这是为什么呢?
答:千万不要怀疑是我提供的bootloader有错误,从而不能够启动内核。而真正的原因是,我们需要 在make menuconfig中配置一下串口,选为串口0:(当然,大家得根据自己使用串口的具体情况)
Location:
-> System Type
(0) S3C UART to use for low-level messages
2.在make menuconfig中添加上DM9000选项,然后重新编译内核,下载新内核到开发板,观察启动信息,发现只打印了一句关于DM9000的信息,类容如下:
dm9000 Ethernet Driver, V1.31
3.分析内核内核自带的DM9000网卡的驱动程序dm9000.c,发现它是采用总线设备驱动模型写的,于是我怀疑网卡驱动的probe函数是不是没有被调用呢?于是加打印语句验证,果然没有被调用。从而说明没有注册平台设备资源。
4.
问:既然发现没有注册平台设备资料,那就自己去注册一个呗。那么需要添加些什么样的资源呢?
答:分析dm9000.c的probe函数,发现以下几行代码:
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
一看platform_get_resource()函数,那太熟悉了,获得资源(即获得基地址和中断号),条件反射,我们就应该注册平台资源(提供基地址和中断号)。当然,我们也可以像而且视频里面移植网卡的那样,直接在dm9000.c的初始化函数中ioremap()一下基地址,然后再赋值给对应的基地址变量(我相信这种方法,大家在听了二期视频和阅读完这章日志后,自己能够搞定)。我采用注册平台资源的方式。
问:既然选择了注册平台资源,那么在哪里去注册呢?
答:我们可以单独写一个注册平台资源的程序,然后编译进内核。但是为了省事情,我梦直接在arch\arm\
mach-s5pv210\mach-smdkv210.c中注册就好了。内容如下:
static struct resource dm9000_resources[] = {
[0] = {
.start = 0x88000000, /* 用于向DM9000发地址,后面有解释 */
.end = 0x88000000 + 3, /* 这里想加多少都可以,只要大于等于3就行 */
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x88000000 + 4, /* 用于向DM9000发数据,后面有解释 */
.end = 0x88000000 + 7, /* 这里想加多少都可以,只要大于等于3就行 */
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT(7), /* 中断号 */
.end = IRQ_EINT(7),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
},
};
static struct dm9000_plat_data dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM, /*位宽是16位,无EEPROM */
.dev_addr = { 0x08, 0x90, 0x00, 0xa0, 0x02, 0x10 }, /* MAC地址 */
};
struct platform_device tiny210_device_dm9000 = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(dm9000_resources),
.resource = dm9000_resources,
.dev = {
.platform_data = &dm9000_platdata,
},
};
问:如何知道基地址是多少呢?如何区分基地址是用于向DM9000发地址,还是发数据呢?
答:看Tiny210的原理图得知,DM9000的CS引脚接到了s5pv210的Xm0CSn1管脚,则对应于Bank 1,地址范围为0x8800_0000 到0x8FFF_FFFF,那么我们的基地址到底该设为多少呢?
我们先来看一下dm9000.c中是怎么来用这些地址的吧,以未经过修改的复位函数为例子:
static void dm9000_reset(board_info_t * db)
{
dev_dbg(db->dev, "resetting device\n"); /* 打印信息 */
/* RESET device */
writeb(DM9000_NCR, db->io_addr); /* 向DM9000发寄存器地址 */
udelay(200);
writeb(NCR_RST, db->io_data); /* 往上述寄存器写入数据 */
udelay(200);
}
从上面的复位函数中发现,我们只使用到了基地址(即注册的地址的平台资源的开始的第一地址),这也就.end = 0x88000000 + 3可以加大于等于3的任意地址的原因了,因为只用到了开始的四个字节,后面的无用。
另外,从上面的复位函数中看出,是向一个地址发送一个数据,很像SDRAM的操作。但是原理图上面发现,只用一个地址,即ADDR2(站在S5PV210的角度),那么是不是DM9000里面只有0和1两个地址呢?
看过视频和DM9000芯片手册的人一定知道,其实DM9000是地址线和数据线复用,通过DM9000上面的CMD引脚来区分(0为地址,1为数据),而该引脚和S5PV210的ADDR2连接。
所以,绕了那么远,说了那么多,最终就是告诉大家,发出的地址信息里面,只有ADDR2上面的地址信号(1或者0)有用,因此,如果是作为发地址的基地址的话,在0x8800_0000 到0x8FFF_FFFF里面(用的是Xm0CSn1,即Bank 1),任意一个能够让ADDR2输出低电平的地址就行;如果是作为发数据的基地址的话,在0x8800_0000 到0x8FFF_FFFF里面(用的是Xm0CSn1,即Bank 1),任意一个能够让ADDR2输出高电平的地址就行;
注意:
这里让ADDR2输出对应电平信号(高或低),而加一个偏移地址(如0x88000000 + 4中的4),有两种算法,因为在S5PV210中的基地址有两种对齐方式,我会在下面进行讲解。
5.由于在我的bootloader里面没有初始化Bank 1的相关类容(如位宽,时序等),而且为了让网卡驱动程序独立于其他任何程序,我们得做些初始化操作,类容如下:
static void __init tiny210_dm9000_set(void)
{
SROM_BW = ioremap(0xE8000000,4);
SROM_BC1 = ioremap(0xE8000008,4);
MP0_1CON = ioremap(0xE02002E0,4);
*SROM_BC1 = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0)); /* 设置时序,视频已详细 讲解了 */
*SROM_BW &= ~(0xf << 4);
*SROM_BW |= (0x1 << 4) | (1<<5); /* 位宽为16位,基地址按字节对齐(第5位很重要) */
*MP0_1CON |= 0x2<<4; /* 设置对应GPIO用于Bank 1的片选 */
}
既然上面我已经打开了arch\arm\mach-s5pv210\mach-smdkv210.c,就在该文件的入口函数添加该初始化函数吧(即在smdkv210_machine_init函数里添加tiny210_dm9000_set),当然也可以把该初始化函数设置在网卡驱动的入口函数里面。
问:初始化函数中说SROM_BW寄存器的bit5很重要,为什么呢?
答:还记得在4中讲的偏移值有两种算法吧!而这个算法就和该bit5息息相关,即:
当bit5设置为1时:(基地址按字节对齐)
开发板发出的地址信息 网卡收到的地址信息
A0 ------ A0
A1 ------ A1
A2 ------ A2
... ------ ....
所以,在这种情况下,和2440的设置基地址没有任何差别,开发板的A2就对应DM9000的CMD。上面注册平台资源就是属于这种情况,所以可以加4。
当bit5设置为0时:(基地址按半字对齐)
开发板发出的地址信息 网卡收到的地址信息
A0 ------ 无
A1 ------ A0
A2 ------ A1
... ------ ....
所以,在这种情况下,开发板的A0地址是无效的,那么A3才对应CMD,所以偏移值应该加8之类的值。(在我共享的dm9000的驱动中"half_word"文件中的网卡驱动中,就是用的这种方法)
6.在这里我得向大家道歉一下,我上传上传的驱动由于个人整理时的疏忽,编译时有个错误,如下:
drivers/net/dm9000.c:1612: error: 'struct dm9000_plat_data' has no member named 'param_addr'
怎么解决?说没有这个成员,我就给它添加一个这样的成员呗。在include\linux\dm9000.h中的dm9000_plat_data结构体中添加unsigned char param_addr[6]成员。接下来,我就说说该成员的作用吧:
在dm9000.c的probe函数里面添加了如下代码:
if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
mac_src = "param data";
memcpy(ndev->dev_addr, pdata->param_addr, 6);
}
该部分代码就是设置MAC地址的,当然大家也可以按照视频里面的方法进行设置,这里就不多说了。
7.到这里为止,自我感觉已经移植得差不多了,编译一下,实验一下吧,看看能行不?果然就ok了。
注意:
1).在共享的dm9000的驱动中"byte"文件中的驱动,对应基地址按字节对齐的方法;
2).在共享的dm9000的驱动中"half_word"文件中的驱动,对应基地址按字对齐的方法;
3).再在这里解释一下使用"half_word"的方法时,为什么修改了dm9000_reset函数,类容如下:
static void dm9000_reset(board_info_t *db)
{
dev_dbg(db->dev, "resetting device\n");
iow(db, DM9000_GPCR, 0x0f); /* 设置GPIO寄存器作为输出,(类似于单片机对IO端口的控制) */
iow(db, DM9000_GPR, 0); /* 往GPIO寄存器写值,清除PWER_DOWN信号,使能PHY */
iow(db, DM9000_NCR, 3); /* 复位 */
do {
udelay(100);
} while (ior(db, DM9000_NCR) & 0x1); /* 等待复位成功 */
iow(db, DM9000_NCR, 0);
iow(db, DM9000_NCR, 3); /* 再次服务 */
do {
udelay(100);
} while (ior(db, DM9000_NCR) & 0x1); /* 等待复位成功 */
if ((ior(db, DM9000_PIDL) != 0) || (ior(db, DM9000_PIDH) != 0x90)) /* 读ID */
printk(KERN_INFO "ERROR : resetting ");
}
注:
如有问题,请到韦东山LINUX视频讨论群里面,我们一起讨论学习,或者加我QQ:317312379
文章浏览阅读814次。相信很多人都见过这样的错误,通常是一个程序运行了很久很久,突然报一个快照过旧的红色错误。那么什么叫作快照过旧呢?它是如何产生的呢?我们应当如何避免呢?快照过旧是指Oracle尝试读取一个过去时间点的表的数据,然而这些数据已经不在回滚段中存在了。为什么会有这种情况呢?这要牵涉到Oracle独特的多版本特性,它会通过回滚段来保证读数据的一致性:Oracle读取的数据,总是某一个时间点的表数据,无论后面..._快照过旧 回退段号42
文章浏览阅读2.5k次,点赞2次,收藏13次。从Qt源码的角度分析QSerialPort可能存在的内存不断增长的原因。_qt程序内存只增不减
文章浏览阅读2.9k次,点赞2次,收藏3次。完整的报错日志:ERROR 2019-09-24 09:27:23,160 scheme:https path:/asset/api/interface/ method:POST data:<QueryDict: {}>Traceback (most recent call last): File "/code/asset_apps/main/views/error_Trace..._request body exceeded settings.data_upload_max_memory_size.
文章浏览阅读8.6k次,点赞7次,收藏40次。本文以下载钉钉的直播回放视频为例,介绍如何下载 M3U8 视频。_fiddler抓包,拿m3u8,然后n_m3u8dl-cli拉回来
文章浏览阅读5.7k次。使用的环境是: WinXP Professional + MSVC SP5TAO完全支持Win32API,(包括Windows NT, Windows 2000, Windows 95/98/ME)VC5.0和VC6.0均可编译。一. Win32+VC6.0下编译和安装ACE和TAO将网上下载的TAO软件包解压缩到某个目录,在该目录下会有ACE_wrappers目录。请按照以下步骤来执行:_vs2013编写tao
文章浏览阅读1.1k次。本文参考文章http://blog.csdn.net/yungis/article/details/8463077#include #include #include #include #include #include #include #include #include #include #include #include class Eas_inoutexpomotion
文章浏览阅读3.1k次。之前写了一个水平的ScrollView,想在里面加一个LinearLayout,并填充满父控件,但是发现无论如何LinearLayout都不能填充满ScrollView,后来找到了方法Mark一下:只要在ScrollView中加上一个android:fillViewport="true"就解决了。可以看出ScrollView里面的子控件是自适应大小的。_scrollview 允许子容器填充
文章浏览阅读2.6k次。SwaggerSwagger与RAML相比,RAML解决的问题是设计阶段的问题,而Swagger则是侧重解决现有API的文档问题,它们最大的不同是RAML需要单独维护一套文档,而Swagger则是通过一套反射机制从代码中生成文档,并且借助ajax可以直接在文档中对API进行交互。因为代码与文档是捆绑的所以在迭代代码的时候,就能方便的将文档也更新了。不会出现随着项目推移代码与文档不匹配的问题_swagger与raml的区别
文章浏览阅读2.5k次。交叉熵代价函数(Cross-entropy cost function)是用来衡量人工神经网络(ANN)的预测值与实际值的一种方式。与二次代价函数相比,它能更有效地促进ANN的训练。在介绍交叉熵代价函数之前,本文先简要介绍二次代价函数,以及其存在的不足。一、二次代价函数的不足ANN的设计目的之一是为了使机器可以像人一样学习知识。人在学习分析新事物时,当发现自己犯的错误越大时,改正的力度就越大。比如投篮:当运动员发现自己的投篮方向离正确方向越远,那么他调整的投篮角度就应该越大,篮球就更容易投进篮筐。同理,_bp神经网络交叉熵loss曲线图
文章浏览阅读1.2w次,点赞4次,收藏26次。在Systemverilog中有一些与时间相关的系统函数在TB打印log的时候会使用到,在打印log时间的时候,如果与我们预期的不一致,可以在这方面找原因。下面列出相关的系统函数$time$stime$realtime`timescale$printtimescale$time: 返回module 64bit 整数时间单位,这里的时间单位做一下说明,比如 `timescale 10ns/1ns , 时间单位就是10ns`timescale 10ns/1nsmodule test;_systemverilog 时间函数
文章浏览阅读285次。特效描述:html5倒计时插件 圆形计时器代码。计时器代码结构1. 引入CSS2. 引入JS3. HTML代码jQuery计时器插件TimeCircles演示1演示1(默认+美化)演示2(带控制)离2014年1月1日还有(2014年1月1日已过)倒计时10秒后结束页面开始时计时$(function(){$('#someTimer1').TimeCircles({time : {Days: {sho..._html5 圆形倒计时
文章浏览阅读2.8k次。ECharts 教程 基础篇ECharts数据可视化实验室,解读适合使用场景官网项目简介:ECharts 是一款由百度前端技术部开发的,基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。涵盖各行业图表,满足各种需求。项目地址:https://gitee.com/echarts/echarts现在公司刚分配一个任务,需要用到 echarts堆叠柱状图处理缺陷报表问题,以前也没有接触过,所以一边学习ECharts官网上的中文API(http://_echart 堆叠柱状图