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

相关文章

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结