注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

fancye的博客

 
 
 

日志

 
 

LAN921x驱动 for linux 2.4 part1  

2009-11-11 07:52:25|  分类: 嵌入式 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
来源:http://blog.chinaunix.net/u/3063/showart_265202.html

/***************************************************************************
*
* Copyright (C) 2004-2006 SMSC
* Copyright (C) 2005-2006 ARM
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
***************************************************************************
* Rewritten, heavily based on smsc911x simple driver by SMSC.
* Partly uses io macros from smc91x.c by Nicolas Pitre
*
* Supported devices:
*   LAN9115, LAN9116, LAN9117, LAN9118
*   LAN9215, LAN9216, LAN9217, LAN9218
*
* History:
*   05/05/2005 bahadir.balban <at> arm.com
*     - Transition to linux coding style
*     - Platform driver and module interface
*
*   17/07/2006 steve.glendinning <at> smsc.com
*     - Added support for LAN921x family
*     - Added workaround for multicast filters
*
*   31/07/2006 steve.glendinning <at> smsc.com
*     - Removed tasklet, using NAPI poll instead
*     - Multiple device support
*     - Large tidy-up following feedback from netdev list
*
*   03/08/2006 steve.glendinning <at> smsc.com
*     - Added ethtool support
*     - Convert to use generic MII interface
*
*   04/08/2006 bahadir.balban <at> arm.com
*     - Added ethtool eeprom r/w support
*
*   30/12/2006 steve.glendinning <at> smsc.com
*     - Fix for external PHY initialisation
*
*   26/03/2007 kf701.ye <at> gmail.com
*     - Modify it for kernel 2.4.20
*/

#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
//#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/version.h>
//#include <asm/bug.h>
#include <asm/bitops.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/io.h>
#include "smsc911x.h"

#define SMSC_CHIPNAME        "smsc911x"
#define SMSC_DRV_VERSION    "2007-03-26"

MODULE_LICENSE("GPL");

struct net_device *gl_dev;

/* define some function self,this function appear in 2.6 */
struct smsc911x_data *netdev_priv(struct net_device *dev)
{
return dev->priv;
}

static inline void random_ether_addr(u8 *addr)
{
addr [0] &= 0xfe;       /* clear multicast bit */
addr [0] |= 0x02;       /* set local assignment bit (IEEE802) */
addr [1] = 0x01;
addr [2] = 0x02;
addr [3] = 0x03;
addr [4] = 0x04;
addr [5] = 0x05;
}
/*
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
*/
static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
{
return (struct mii_ioctl_data *) &rq->ifr_ifru;
}
/* End, copy from 2.6 kernel */

#if SMSC_CAN_USE_32BIT

static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
{
return readl(pdata->ioaddr + reg);
}

static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata,
u32 reg)
{
writel(val, pdata->ioaddr + reg);
}

#else                /* SMSC_CAN_USE_32BIT */

static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
{
u32 reg_val;
unsigned long flags;

/* these two 16-bit reads must be performed consecutively, so must
* not be interrupted by our own ISR (which would start another
* read operation) */
local_irq_save(flags);
reg_val = ((readw(pdata->ioaddr + reg) & 0xFFFF) |
((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
local_irq_restore(flags);

return reg_val;
}

static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata,
u32 reg)
{
unsigned long flags;

/* these two 16-bit writes must be performed consecutively, so must
* not be interrupted by our own ISR (which would start another
* read operation) */
local_irq_save(flags);
writew(val & 0xFFFF, pdata->ioaddr + reg);
writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
local_irq_restore(flags);
}

#endif                /* SMSC_CAN_USE_32BIT */

/* Writes a packet to the TX_DATA_FIFO */
static inline void
smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
unsigned int wordcount)
{
while (wordcount--)
smsc911x_reg_write(*buf++, pdata, TX_DATA_FIFO);
}

/* Reads a packet out of the RX_DATA_FIFO */
static inline void
smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
unsigned int wordcount)
{
while (wordcount--)
*buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO);
}

/* waits for MAC not busy, with timeout.  Only called by smsc911x_mac_read
* and smsc911x_mac_write, so assumes phy_lock is held */
static int smsc911x_mac_notbusy(struct smsc911x_data *pdata)
{
int i;
u32 val;

for (i = 0; i < 40; i++) {
val = smsc911x_reg_read(pdata, MAC_CSR_CMD);
if (!(val & MAC_CSR_CMD_CSR_BUSY_))
return 1;
}
SMSC_WARNING("Timed out waiting for MAC not BUSY. "
"MAC_CSR_CMD: 0x%08X", val);
return 0;
}

/* Fetches a MAC register value. Assumes phy_lock is acquired */
static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
{
unsigned int temp;

#ifdef CONFIG_DEBUG_SPINLOCK
if (!spin_is_locked(&pdata->phy_lock))
SMSC_WARNING("phy_lock not held");
#endif                /* CONFIG_DEBUG_SPINLOCK */

temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
SMSC_WARNING("smsc911x_mac_read failed, MAC busy at entry");
return 0xFFFFFFFF;
}

/* Send the MAC cmd */
smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_
| MAC_CSR_CMD_R_NOT_W_), pdata, MAC_CSR_CMD);

/* Workaround for hardware read-after-write restriction */
temp = smsc911x_reg_read(pdata, BYTE_TEST);

/* Wait for the read to happen */
if (likely(smsc911x_mac_notbusy(pdata)))
return smsc911x_reg_read(pdata, MAC_CSR_DATA);

SMSC_WARNING("smsc911x_mac_read failed, MAC busy after read");
return 0xFFFFFFFF;
}

/* Set a mac register, phy_lock must be acquired before calling */
static void smsc911x_mac_write(struct smsc911x_data *pdata,
unsigned int offset, u32 val)
{
unsigned int temp;

#ifdef CONFIG_DEBUG_SPINLOCK
if (!spin_is_locked(&pdata->phy_lock))
SMSC_WARNING("phy_lock not held");
#endif                /* CONFIG_DEBUG_SPINLOCK */

temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
SMSC_WARNING("smsc911x_mac_write failed, MAC busy at entry");
return;
}

/* Send data to write */
smsc911x_reg_write(val, pdata, MAC_CSR_DATA);

/* Write the actual data */
smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_), pdata,
MAC_CSR_CMD);

/* Workaround for hardware read-after-write restriction */
temp = smsc911x_reg_read(pdata, BYTE_TEST);

/* Wait for the write to complete */
if (likely(smsc911x_mac_notbusy(pdata)))
return;

SMSC_WARNING("smsc911x_mac_write failed, MAC busy after write");
}

/* Gets a phy register, phy_lock must be acquired before calling */
static u16 smsc911x_phy_read(struct smsc911x_data *pdata, unsigned int index)
{
unsigned int addr;
int i;

#ifdef CONFIG_DEBUG_SPINLOCK
if (!spin_is_locked(&pdata->phy_lock))
SMSC_WARNING("phy_lock not held");
#endif                /* CONFIG_DEBUG_SPINLOCK */

/* Confirm MII not busy */
if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
SMSC_WARNING("MII is busy in smsc911x_phy_read???");
return 0;
}

/* Set the address, index & direction (read from PHY) */
addr = (((pdata->mii.phy_id) & 0x1F) << 11)
| ((index & 0x1F) << 6);
smsc911x_mac_write(pdata, MII_ACC, addr);

/* Wait for read to complete w/ timeout */
for (i = 0; i < 100; i++) {
/* See if MII is finished yet */
if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
return smsc911x_mac_read(pdata, MII_DATA);
}
}
SMSC_WARNING("Timed out waiting for MII write to finish");
return 0xFFFF;
}

/* Sets a phy register, phy_lock must be acquired before calling */
static void smsc911x_phy_write(struct smsc911x_data *pdata,
unsigned int index, u16 val)
{
unsigned int addr;
int i;

#ifdef CONFIG_DEBUG_SPINLOCK
if (!spin_is_locked(&pdata->phy_lock))
SMSC_WARNING("phy_lock not held");
#endif                /* CONFIG_DEBUG_SPINLOCK */

/* Confirm MII not busy */
if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
SMSC_WARNING("MII is busy in smsc911x_write_phy???");
return;
}

/* Put the data to write in the MAC */
smsc911x_mac_write(pdata, MII_DATA, val);

/* Set the address, index & direction (write to PHY) */
addr = (((pdata->mii.phy_id) & 0x1F) << 11) |
((index & 0x1F) << 6) | MII_ACC_MII_WRITE_;
smsc911x_mac_write(pdata, MII_ACC, addr);

/* Wait for write to complete w/ timeout */
for (i = 0; i < 100; i++) {
/* See if MII is finished yet */
if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_))
return;
}
SMSC_WARNING("Timed out waiting for MII write to finish");
}

static int smsc911x_mdio_read(struct net_device *dev, int phy_id, int location)
{
struct smsc911x_data *pdata = netdev_priv(dev);
unsigned long flags;
int reg;

spin_lock_irqsave(&pdata->phy_lock, flags);
reg = smsc911x_phy_read(pdata, location);
spin_unlock_irqrestore(&pdata->phy_lock, flags);

return reg;
}

static void smsc911x_mdio_write(struct net_device *dev, int phy_id,
int location, int val)
{
struct smsc911x_data *pdata = netdev_priv(dev);
unsigned long flags;

spin_lock_irqsave(&pdata->phy_lock, flags);
smsc911x_phy_write(pdata, location, val);
spin_unlock_irqrestore(&pdata->phy_lock, flags);
}

.......中间没有改动
  评论这张
 
阅读(110)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018