历史上的今天
今天是:2024年11月10日(星期日)
2021年11月10日 | mini2440 dm9000 网卡驱动详解 (三)
2021-11-10 来源:eefocus
*dm9000_get_drvinfo()
该函数去的设备的基本信息(设备名,版本,总线名)传给ethtool_drvinfo结构体变量。代码清单如下:
static void dm9000_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
board_info_t *dm = to_dm9000_board(dev); /*to_dm9000_board实际上就是调用了netdev_priv(dev)*/
strcpy(info->driver, CARDNAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, to_platform_device(dm->dev)->name);
}
*dm9000_get_settings()
该函数得到由参数cmd指定的设置信息。
*dm9000_set_settings()
该函数设置由参数cmd指定的信息。
*dm9000_get_msglevel()
*dm9000_set_msglevel()
这两个函数设置和取得messagelevel,实际是设置和取得board_info中的msg_enable信息。
*dm9000_nway_reset()
重启mii的自动协商
*dm9000_get_link()
该函数的到link状态。如果带外部PHY,则返回mii链接状态。 否则返回DM9000 NSR寄存器数值。
*dm9000_get_eeprom_len()
dm9000_get_eeprom()
dm9000_set_eeprom()
这三个函数用来读写eeprom。
5. 与数据传输有关的函数。
上面已经分析了一个与数据传输有关的函数,那就是发送数据的函数dm9000_start_xmit()。这里再来分析数据的接收。再看具体代码之前还是来看看DM9000的数据接收的过程。
接收的数据存储在RX SRAM中,地址是0C00h~3FFFh。存储在RX_SRAM中的每个包都有4个字节的信息头。可以使用MRCMDX和MRCMD寄存器来得到这些信息。第一个字节用来检查数据包是否接收到了RX_SRAM中,如果这个字节是"01",意味着一个包已经接收。如果是"00",则还没有数据包被接收到RX_SRAM中。第二个字节保存接收到的数据包的信息,格式和RSR寄存器一样。根据这个格式,接收到的包能被校验是正确的还是错误的包。第三和第四字节保存了接收的数据包的长度。这四个字节以外的其他字节就是接收包的数据。看下图可以更好的理解这种格式。

根据包的结构可以知道接收一个包应该按照下面的步骤来进行:
第一步:判断包是否已经接收过来了。需要用到MRCMDX寄存器。MRCMDX寄存器是存储数据读命令寄存器(地址不增加)。这个寄存器只是用来读接收包标志位"01"。下面这段代码是一个例子,用来判断RX ready:
u8 RX_ready = ior( IOaddr, 0xF0 ); /* dummy read the packet ready flag */
RX_ready = (u8) inp( IOaddr + 4 ); /* got the most updated data */
if ( RX_ready == 1 ) { /* ready check: this byte must be 0 or 1 */
/* check the RX status and to get RX length (see datasheet ch.5.6.3) */
/* income RX a packet (see datasheet ch.5.6.4) */
} else if ( RX_ready != 0 ) { /* stop device and wait to reset device */
iow( IOaddr, 0xFF, 0x80 ); /* stop INT request */
iow( IOaddr, 0xFE, 0x0F ); /* clear ISR status */
iow( IOaddr, 0x05, 0x00 ); /* stop RX function */
u8 device_wait_reset = TRUE; /* raise the reset flag */
}
第二步:检查包的状态和长度。需要用到MRCMD寄存器(存储数据读命令,读指针自动增加)。下面这段例子代码用来读RX状态和长度。
u8 io_mode = ior( IOaddr, 0xFE ) >> 6; /* ISR bit[7:6] keep I/O mode */
outp( IOaddr, 0xF2 ); /* trigger MRCMD reg_F2h with read_ptr++ */
/* int RX_status : the RX packet status, int RX_length : the RX packet length */
if ( io_mode == 2 ) { /* I/O byte mode */
RX_status = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 );
RX_length = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 ); }
else if ( io_mode == 0 ) { /* I/O word mode */
RX_status = inpw( IOaddr + 4 );
RX_length = inpw( IOaddr + 4 ); }
else if ( io_mode == 1 ) { /* I/O dword mode */
(u32) status_tmp = inpl( IOaddr + 4 ); /* got the RX 32-bit dword data */
RX_status = (u16)( status_tmp & 0xFFFF );
RX_length = (u16)( ( status_tmp >> 16 ) & 0xFFFF ); }
第三步:读包的数据。也需要MRCMD寄存器。例子代码如下:
/* u8 RX_data[] : the data of the received packet */
if ( io_mode == 2 ) { /* I/O byte mode */
for ( i = 0 ; i < RX_length ; i++ ) /* loop to read a byte data from RX SRAM */
RX_data[ i ] = (u8) inp( IOaddr + 4 ); }
else if ( io_mode == 0 ) { /* I/O word mode */
int length_tmp = ( RX_length + 1 ) / 2;
for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a word data from RX SRAM */
( (u16 *)RX_data)[ i ] = inpw( IOaddr + 4 ); }
else if ( io_mode == 1 ) { /* I/O dword mode */
int length_tmp = ( RX_length + 3 ) / 4;
for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a dword data from RX SRAM */
( (u32 *)RX_data)[ i ] = inpl( IOaddr + 4 ); } /* inpl() is inport 32-bit I/O */
下面的dm9000_rx()函数实际上是按照上面这三个步骤来实现的,具体实现并不一定是要参照例子代码。注意这里按照DM9000接收包的格式定义了一个结构体dm9000_rxhdr用来表示头部的四个字节。代码清单如下:
struct dm9000_rxhdr {
u8 RxPktReady;
u8 RxStatus;
__le16 RxLen;
} __attribute__((__packed__));
接收函数代码如下:
/*
* Received a packet and pass to upper layer
*/
static void
dm9000_rx(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
struct dm9000_rxhdr rxhdr;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
bool GoodPacket;
int RxLen;
/* Check packet ready or not */
do {
ior(db, DM9000_MRCMDX); /* Dummy read */
/* Get most updated data */
/*读一下最新数据的第一个字节*/
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
/*DM9000_PKT_RDY定义是0x01,如果第一个字节大于0x01,则不是正确的状态。因为第一个字节只能是01h或00h*/
if (rxbyte > DM9000_PKT_RDY) {
dev_warn(db->dev, "status check fail: %dn", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
return;
}
if (rxbyte != DM9000_PKT_RDY)
return;
/* A packet ready now & Get status/length */
GoodPacket = true;
writeb(DM9000_MRCMD, db->io_addr);
(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));/*一次性读入四个字节的内容到rxhdr变量*/
RxLen = le16_to_cpu(rxhdr.RxLen);
if (netif_msg_rx_status(db))
dev_dbg(db->dev, "RX: status %02x, length %04xn",
rxhdr.RxStatus, RxLen);
/* Packet Status check */
if (RxLen < 0x40) {
GoodPacket = false;
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "RX: Bad Packet (runt)n");
}
if (RxLen > DM9000_PKT_MAX) {
dev_dbg(db->dev, "RST: RX Len:%xn", RxLen);
}
史海拾趣
|
新手提问,请勿取笑,呵呵。 S3C2410在管脚复用的时候有这样一段代码: //set GPG1 as EINT9 for CS8900A value = INREG32(&pOalPortRegs->GPGCON); OUTREG32(&pOalPortRegs->GPGCON,(value & ~(3… 查看全部问答> |
|
产品最初正常工作,内核和应用程序都好的。过了一段时间后启动异常。 步骤是开机Bootloader启动,启动时加载了LOGO界面填充了液晶的显示缓冲区,后来就停在这里了。 我可以按照原来的方式烧内核,更换了画面也可以显示。 重烧了BOOTLOADER后也没 ...… 查看全部问答> |
|
在应用程序里如何查询某个USB连在哪一个USB controller上 在具有多个USB controller和多个USB设备的情况下, 如何查询这些USB设备连接在哪个USB controller上。 设备管理器中,如果选择“依连接排序设备”,就可以看到所 有设备的Device Tree,VC里有什么API或者什么方法可以获得 类似的信息吗? 请高 ...… 查看全部问答> |
|
看看有没有问题,第一次玩STM32,没有什么经验,硬件是按照st-link制作的,做了一些修改(st-link本来也是一块开发板)。准备自己做JTAG下载工具或者调试工具,呵呵,如果搞的定的话。PCB还没铺地,其他都OK了。发现一个错误,应该BOOT1接地,BO ...… 查看全部问答> |
|
μC/OS-II实时性能测试指标 衡量嵌入式实时操作系统的好坏一般主要参考以下主要性能指标参数: 任务切换时间、中断响应时间、任务响应时间、任务创建/删除时间、交替信号量时间、取得/释放信号量时间、交替消息队列传输时间等。本文仅对前2个 ...… 查看全部问答> |




