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

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

MySQL主从复制与读写分离的用法解读

《MySQL主从复制与读写分离的用法解读》:本文主要介绍MySQL主从复制与读写分离的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、主从复制mysql主从复制原理实验案例二、读写分离实验案例安装并配置mycat 软件设置mycat读写分离验证mycat读

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

关于MyISAM和InnoDB对比分析

《关于MyISAM和InnoDB对比分析》:本文主要介绍关于MyISAM和InnoDB对比分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录开篇:从交通规则看存储引擎选择理解存储引擎的基本概念技术原理对比1. 事务支持:ACID的守护者2. 锁机制:并发控制的艺

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三