210学习日记(15)_移植DM9000_s5pv210移植dm9000-程序员宅基地

技术标签: 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.cprobe函数,发现以下几行代码:

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的原理图得知,DM9000CS引脚接到了s5pv210Xm0CSn1管脚,则对应于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里面只有01两个地址呢?

看过视频和DM9000芯片手册的人一定知道,其实DM9000是地址线和数据线复用,通过DM9000上面的CMD引脚来区分(0为地址,1为数据),而该引脚和S5PV210ADDR2连接。

所以,绕了那么远,说了那么多,最终就是告诉大家,发出的地址信息里面,只有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就对应DM9000CMD。上面注册平台资源就是属于这种情况,所以可以加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.cprobe函数里面添加了如下代码:

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视频讨论群里面,我们一起讨论学习,或者加我QQ317312379

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wanyong89/article/details/8125640

智能推荐

oracle 回滚段快照过旧,关于快照过旧和无法扩展回滚段-程序员宅基地

文章浏览阅读814次。相信很多人都见过这样的错误,通常是一个程序运行了很久很久,突然报一个快照过旧的红色错误。那么什么叫作快照过旧呢?它是如何产生的呢?我们应当如何避免呢?快照过旧是指Oracle尝试读取一个过去时间点的表的数据,然而这些数据已经不在回滚段中存在了。为什么会有这种情况呢?这要牵涉到Oracle独特的多版本特性,它会通过回滚段来保证读数据的一致性:Oracle读取的数据,总是某一个时间点的表数据,无论后面..._快照过旧 回退段号42

使用QSerialPort内存不断增长以及原因剖析_qt程序内存只增不减-程序员宅基地

文章浏览阅读2.5k次,点赞2次,收藏13次。从Qt源码的角度分析QSerialPort可能存在的内存不断增长的原因。_qt程序内存只增不减

Request body exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE.-程序员宅基地

文章浏览阅读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.

Fiddler 抓包下载 M3U8 视频_fiddler抓包,拿m3u8,然后n_m3u8dl-cli拉回来-程序员宅基地

文章浏览阅读8.6k次,点赞7次,收藏40次。本文以下载钉钉的直播回放视频为例,介绍如何下载 M3U8 视频。_fiddler抓包,拿m3u8,然后n_m3u8dl-cli拉回来

TAO使用指南 -- 编译ACE和TAO_vs2013编写tao-程序员宅基地

文章浏览阅读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

osg示例程序解析2---osganimationeasemotion_inoutexpomotion-程序员宅基地

文章浏览阅读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

随便推点

ScrollView中设置子控件填充满ScrollView_scrollview 允许子容器填充-程序员宅基地

文章浏览阅读3.1k次。之前写了一个水平的ScrollView,想在里面加一个LinearLayout,并填充满父控件,但是发现无论如何LinearLayout都不能填充满ScrollView,后来找到了方法Mark一下:只要在ScrollView中加上一个android:fillViewport="true"就解决了。可以看出ScrollView里面的子控件是自适应大小的。_scrollview 允许子容器填充

API设计:Swagger, Blueprint和RAML_swagger与raml的区别-程序员宅基地

文章浏览阅读2.6k次。SwaggerSwagger与RAML相比,RAML解决的问题是设计阶段的问题,而Swagger则是侧重解决现有API的文档问题,它们最大的不同是RAML需要单独维护一套文档,而Swagger则是通过一套反射机制从代码中生成文档,并且借助ajax可以直接在文档中对API进行交互。因为代码与文档是捆绑的所以在迭代代码的时候,就能方便的将文档也更新了。不会出现随着项目推移代码与文档不匹配的问题_swagger与raml的区别

损失函数——交叉熵损失函数_bp神经网络交叉熵loss曲线图-程序员宅基地

文章浏览阅读2.5k次。交叉熵代价函数(Cross-entropy cost function)是用来衡量人工神经网络(ANN)的预测值与实际值的一种方式。与二次代价函数相比,它能更有效地促进ANN的训练。在介绍交叉熵代价函数之前,本文先简要介绍二次代价函数,以及其存在的不足。一、二次代价函数的不足ANN的设计目的之一是为了使机器可以像人一样学习知识。人在学习分析新事物时,当发现自己犯的错误越大时,改正的力度就越大。比如投篮:当运动员发现自己的投篮方向离正确方向越远,那么他调整的投篮角度就应该越大,篮球就更容易投进篮筐。同理,_bp神经网络交叉熵loss曲线图

Systemverilog中时间单位以及相关系统函数_systemverilog 时间函数-程序员宅基地

文章浏览阅读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 时间函数

html5游戏加入计时器,html5倒计时插件制作圆形计时器代码-程序员宅基地

文章浏览阅读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 圆形倒计时

ECharts -堆叠柱状图_echart 堆叠柱状图-程序员宅基地

文章浏览阅读2.8k次。ECharts 教程 基础篇ECharts数据可视化实验室,解读适合使用场景官网项目简介:ECharts 是一款由百度前端技术部开发的,基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。涵盖各行业图表,满足各种需求。项目地址:https://gitee.com/echarts/echarts现在公司刚分配一个任务,需要用到 echarts堆叠柱状图处理缺陷报表问题,以前也没有接触过,所以一边学习ECharts官网上的中文API(http://_echart 堆叠柱状图