DM9000网卡驱动源码分析系列02 - 读写

2023-12-11 11:59

本文主要是介绍DM9000网卡驱动源码分析系列02 - 读写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面列出的几段代码是dm9000驱动程序对一些常用的读写操作的封装,比如寄存器读写,IO内存块读写,eeprom读写,phy寄存器读写等等
/* routines for sending block to chip */
static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
{iowrite8_rep(reg, data, count);
}static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)
{iowrite16_rep(reg, data, (count+1) >> 1);
}static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
{iowrite32_rep(reg, data, (count+3) >> 2);
}/* input block from chip to memory */static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
{ioread8_rep(reg, data, count);
}static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
{ioread16_rep(reg, data, (count+1) >> 1);
}static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count)
{ioread32_rep(reg, data, (count+3) >> 2);
}/* dump block from chip to null */static void dm9000_dumpblk_8bit(void __iomem *reg, int count)
{int i;int tmp;for (i = 0; i < count; i++)tmp = readb(reg);
}static void dm9000_dumpblk_16bit(void __iomem *reg, int count)
{int i;int tmp;count = (count + 1) >> 1;for (i = 0; i < count; i++)tmp = readw(reg);
}static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
{int i;int tmp;count = (count + 3) >> 2;for (i = 0; i < count; i++)tmp = readl(reg);
}/* dm9000_set_io** select the specified set of io routines to use with the* device*/
static void dm9000_set_io(struct board_info *db, int byte_width)
{/* use the size of the data resource to work out what IO* routines we want to use*/switch (byte_width) {case 1:db->dumpblk = dm9000_dumpblk_8bit;db->outblk  = dm9000_outblk_8bit;db->inblk   = dm9000_inblk_8bit;break;case 3:dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n");case 2:db->dumpblk = dm9000_dumpblk_16bit;db->outblk  = dm9000_outblk_16bit;db->inblk   = dm9000_inblk_16bit;break;case 4:default:db->dumpblk = dm9000_dumpblk_32bit;db->outblk  = dm9000_outblk_32bit;db->inblk   = dm9000_inblk_32bit;break;}
}
这些封装的函数都是调用内核提供的IO内存读写函数,在LDD3中文版P250页有介绍
/**   Read a byte from I/O port*/
static u8 ior(struct board_info *db, int reg)
{writeb(reg, db->io_addr);return readb(db->io_data);
}/**   Write a byte to I/O port*/
static void iow(struct board_info *db, int reg, int value)
{writeb(reg, db->io_addr);writeb(value, db->io_data);
}
既然提到对设备IO内存的读写,这里也要说明一下对设备寄存器的读写
看到代码可以知道,对寄存器的读写分两个步骤,要对寄存器reg读或者写
首先把reg的值写入io_addr, 然后再对io_data进行读写操作

可以理解为我们要读写某些值,首先把存储这些值的地址赋值给io_addr, 接下来读写io_data

static int dm9000_wait_eeprom(struct board_info *db)
{unsigned int status;int timeout = 8;	/* wait max 8msec *//* The DM9000 data sheets say we should be able to* poll the ERRE bit in EPCR to wait for the EEPROM* operation. From testing several chips, this bit* does not seem to work.** We attempt to use the bit, but fall back to the* timeout (which is why we do not return an error* on expiry) to say that the EEPROM operation has* completed.*/while (1) {status = dm9000_read_locked(db, DM9000_EPCR);if ((status & EPCR_ERRE) == 0)break;msleep(1);if (timeout-- < 0) {dev_dbg(db->dev, "timeout waiting EEPROM\n");break;}}return 0;
}/**  Read a word data from EEPROM*/
static void
dm9000_read_eeprom(struct board_info *db, int offset, u8 *to)
{unsigned long flags;if (db->flags & DM9000_PLATF_NO_EEPROM) {to[0] = 0xff;to[1] = 0xff;return;}mutex_lock(&db->addr_lock);spin_lock_irqsave(&db->lock, flags);iow(db, DM9000_EPAR, offset);iow(db, DM9000_EPCR, EPCR_ERPRR);spin_unlock_irqrestore(&db->lock, flags);dm9000_wait_eeprom(db);/* delay for at-least 150uS */msleep(1);spin_lock_irqsave(&db->lock, flags);iow(db, DM9000_EPCR, 0x0);to[0] = ior(db, DM9000_EPDRL);to[1] = ior(db, DM9000_EPDRH);spin_unlock_irqrestore(&db->lock, flags);mutex_unlock(&db->addr_lock);
}/** Write a word data to SROM*/
static void
dm9000_write_eeprom(struct board_info *db, int offset, u8 *data)
{unsigned long flags;if (db->flags & DM9000_PLATF_NO_EEPROM)return;mutex_lock(&db->addr_lock);spin_lock_irqsave(&db->lock, flags);iow(db, DM9000_EPAR, offset);iow(db, DM9000_EPDRH, data[1]);iow(db, DM9000_EPDRL, data[0]);iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);spin_unlock_irqrestore(&db->lock, flags);dm9000_wait_eeprom(db);mdelay(1);	/* wait at least 150uS to clear */spin_lock_irqsave(&db->lock, flags);iow(db, DM9000_EPCR, 0);spin_unlock_irqrestore(&db->lock, flags);mutex_unlock(&db->addr_lock);
}

对eeprom的读写,一系列的读写寄存器操作

/** Sleep, either by using msleep() or if we are suspending, then* use mdelay() to sleep.*/
static void dm9000_msleep(struct board_info *db, unsigned int ms)
{if (db->in_suspend || db->in_timeout)mdelay(ms);elsemsleep(ms);
}/* Read a word from phyxcer */
static int dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
{struct board_info *db = netdev_priv(dev);unsigned long flags;unsigned int reg_save;int ret;mutex_lock(&db->addr_lock);spin_lock_irqsave(&db->lock, flags);/* Save previous register address */reg_save = readb(db->io_addr);/* Fill the phyxcer register into REG_0C */iow(db, DM9000_EPAR, DM9000_PHY | reg);/* Issue phyxcer read command */iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);dm9000_msleep(db, 1);		/* Wait read complete */spin_lock_irqsave(&db->lock, flags);reg_save = readb(db->io_addr);iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command *//* The read data keeps on REG_0D & REG_0E */ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);/* restore the previous address */writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);mutex_unlock(&db->addr_lock);dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);return ret;
}/* Write a word to phyxcer */
static void dm9000_phy_write(struct net_device *dev,int phyaddr_unused, int reg, int value)
{struct board_info *db = netdev_priv(dev);unsigned long flags;unsigned long reg_save;dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);if (!db->in_timeout)mutex_lock(&db->addr_lock);spin_lock_irqsave(&db->lock, flags);/* Save previous register address */reg_save = readb(db->io_addr);/* Fill the phyxcer register into REG_0C */iow(db, DM9000_EPAR, DM9000_PHY | reg);/* Fill the written data into REG_0D & REG_0E */iow(db, DM9000_EPDRL, value);iow(db, DM9000_EPDRH, value >> 8);/* Issue phyxcer write command */iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);dm9000_msleep(db, 1);		/* Wait write complete */spin_lock_irqsave(&db->lock, flags);reg_save = readb(db->io_addr);iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command *//* restore the previous address */writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);if (!db->in_timeout)mutex_unlock(&db->addr_lock);
}
对phy寄存器的读写操作,这些直接针对寄存器的读写看着头都大了,没有去深入学习

这篇关于DM9000网卡驱动源码分析系列02 - 读写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/480603

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者