?? s3c4510.c
字號:
priv->stats.tx_carrier_errors++;
if(status & Under)
priv->stats.tx_fifo_errors++;
if(status & LateColl)
priv->stats.tx_window_errors++;
if(status & ExColl)
priv->stats.collisions++;
}
}
// Clear Framedata pointer already used
FD_ptr->StatusAndFrameLength = 0x0;
priv->gtx_ptr = (unsigned long) FD_ptr->NextFrameDescriptor;
}
spin_unlock(&priv->lock);
return;
}
/*
* Open and Close
*/
int s3c4510_open(struct net_device *dev)
{
int i;
#if 0
unsigned long status;
#endif
MOD_INC_USE_COUNT;
TRACE("open\n");
// Disable irqs
disable_irq(INT_BDMATX);
disable_irq(INT_BDMARX);
disable_irq(INT_MACTX);
disable_irq(INT_MACRX);
// register rx isr
if(request_irq(INT_BDMARX, &s3c4510_rx, SA_INTERRUPT, "eth rx isr", dev)) {
printk(KERN_ERR "s3c4510: Can't get irq %d\n", INT_BDMARX);
return -EAGAIN;
}
// register tx isr
if(request_irq(INT_MACTX, &s3c4510_tx, SA_INTERRUPT, "eth tx isr", dev)) {
printk(KERN_ERR "s3c4510: Can't get irq %d\n", INT_MACTX);
return -EAGAIN;
}
printk("Reseting PHY\n");
MIIWrite(0x0, 0x0, 1<<15);
// while((MIIRead(0x0, 0x0) & (1<<15)));
#if 0
printk("Perform AN again\n");
MIIWrite(0x0, 0x0, MIIRead(0x0, 0x0) & ~(1<<12));
// while(!(MIIRead(0x11, 0x0) & (1<<4)));
MIIWrite(0x0, 0x0, 1<<13|1<<8);
status = MIIRead(0x11, 0x0);
if(status & 1<<15)
printk("10M/b ");
else
printk("100M/b ");
if(status & 1<<14)
printk("Full duplex\n");
else printk("Half duplex\n");
#endif
// reset BDMA and MAC
CSR_WRITE(BDMARXCON, BRxRS);
CSR_WRITE(BDMATXCON, BTxRS);
CSR_WRITE(MACON, Reset);
CSR_WRITE(BDMARXLSZ, sizeof(struct ethframe));
CSR_WRITE(MACON, gMACCON);
FD_Init(dev);
for(i = 0; i < (int)dev->addr_len-2; i++)
CAM_Reg(0) = (CAM_Reg(0) << 8) | dev->dev_addr[i];
for(i = (int)dev->addr_len-2; i < (int)dev->addr_len; i++)
CAM_Reg(1) = (CAM_Reg(1) << 8) | dev->dev_addr[i];
CAM_Reg(1) = (CAM_Reg(1) << 16);
CSR_WRITE(CAMEN, 0x0001);
CSR_WRITE(CAMCON, gCAMCON);
enable_irq(INT_BDMARX);
enable_irq(INT_MACTX);
// ReadyMACTx();
CSR_WRITE(BDMATXCON, gBDMATXCON);
CSR_WRITE(MACTXCON, gMACTXCON);
// ReadyMACRx();
CSR_WRITE(BDMARXCON, gBDMARXCON);
CSR_WRITE(MACRXCON, gMACRXCON);
// Start the transmit queue
netif_start_queue(dev);
return 0;
}
int s3c4510_stop(struct net_device *dev)
{
TRACE("stop\n");
CSR_WRITE(BDMATXCON, 0);
CSR_WRITE(BDMARXCON, 0);
CSR_WRITE(MACTXCON, 0);
CSR_WRITE(MACRXCON, 0);
free_irq(INT_BDMARX, dev);
free_irq(INT_MACTX, dev);
netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
return 0;
}
int s3c4510_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
// int i;
int len;
char *data;
struct s3c4510_priv *priv = (struct s3c4510_priv *) dev->priv;
struct FrameDesc *FD_ptr; // frame descriptor pointer
volatile unsigned long *FB_ptr; // frame data pointer
unsigned char *FB_data; // frame data
unsigned long ulFlags;
spin_lock_irqsave(&priv->lock, ulFlags);
TRACE("start_xmit\n");
/*
printk("sk_buff->len: %d\n", skb->len);
printk("sk_buff->data_len: %d\n", skb->data_len);
for(i = 0; i < skb->len; i++) {
printk("%4x", skb->data[i]);
if((i+1)%16 ==0)
printk("\n");
}
printk("\n");
*/
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
data = skb->data;
dev->trans_start = jiffies;
// 1. Get Tx frame descriptor & data pointer
FD_ptr = (struct FrameDesc *) priv->tx_ptr;
FB_ptr = (unsigned long *) &FD_ptr->FrameDataPtr;
FB_data = (unsigned char *) FD_ptr->FrameDataPtr;
// 2. Check BDMA ownership
if(*FB_ptr & BDMA_owner) {
printk("no tx buffer\n");
// check it later
// netif_stop_queue(dev);
spin_unlock_irqrestore(&priv->lock, ulFlags);
return 1;
}
// 3. Prepare Tx Frame data to Frame buffer
memcpy(FB_data, data, len);
// 4. Set Tx Frame flag & Length Field
FD_ptr->Reserved = (Padding | CRCMode | FrameDataPtrInc | LittleEndian | WA00 | MACTxIntEn);
FD_ptr->StatusAndFrameLength = (len & 0xFFFF);
// 5. Change ownership to BDMA
FD_ptr->FrameDataPtr |= BDMA_owner;
// 6. Enable MAC and BDMA Tx control register
CSR_WRITE(BDMATXCON, gBDMATXCON);
CSR_WRITE(MACTXCON, gMACTXCON);
// 7. Change the Tx frame descriptor for next use
priv->tx_ptr = (unsigned long)(FD_ptr->NextFrameDescriptor);
spin_unlock_irqrestore(&priv->lock, ulFlags);
dev_kfree_skb(skb);
return 0;
}
struct net_device_stats *s3c4510_get_stats(struct net_device *dev)
{
struct s3c4510_priv *priv = (struct s3c4510_priv *) dev->priv;
TRACE("get_stats\n");
return &priv->stats;
}
/*
* change mac address when up
*/
static int s3c4510_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *p=(struct sockaddr *)addr;
int i=0;
s3c4510_stop(dev);
memcpy(dev->dev_addr, p->sa_data,dev->addr_len);
//Set CAM register
for(i = 0; i < (int)dev->addr_len-2; i++)
CAM_Reg(0) = (CAM_Reg(0) << 8) | dev->dev_addr[i];
for(i = (int)dev->addr_len-2; i < (int)dev->addr_len; i++)
CAM_Reg(1) = (CAM_Reg(1) << 8) | dev->dev_addr[i];
CAM_Reg(1) = (CAM_Reg(1) << 16);
CSR_WRITE(CAMEN, 0x0001);
CSR_WRITE(CAMCON, gCAMCON);
s3c4510_open(dev);
return 0;
}
/*
* The init function, invoked by register_netdev()
*/
int s3c4510_init(struct net_device *dev)
{
int i;
TRACE("init\n");
ether_setup(dev); // Assign some of the fields
// set net_device methods
dev->open = s3c4510_open;
dev->stop = s3c4510_stop;
// dev->ioctl = s3c4510_ioctl;
dev->get_stats = s3c4510_get_stats;
// dev->tx_timeout = s3c4510_tx_timeout;
dev->hard_start_xmit = s3c4510_start_xmit;
dev->set_mac_address=s3c4510_set_mac_address;
// set net_device data members
dev->watchdog_timeo = timeout;
dev->irq = 17;
dev->dma = 0;
// set MAC address manually
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x40;
dev->dev_addr[2] = 0x95;
dev->dev_addr[3] = 0x36;
dev->dev_addr[4] = 0x35;
dev->dev_addr[5] = 0x34;
printk(KERN_INFO "%s: ", dev->name);
for(i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], (i==5) ? ' ' : ':');
printk("\n");
SET_MODULE_OWNER(dev);
dev->priv = kmalloc(sizeof(struct s3c4510_priv), GFP_KERNEL);
if(dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct s3c4510_priv));
spin_lock_init(&((struct s3c4510_priv *) dev->priv)->lock);
return 0;
}
struct net_device s3c4510_netdevs = {
init: s3c4510_init,
};
/*
* Finally, the module stuff
*/
int __init s3c4510_init_module(void)
{
int result;
TRACE("init_module\n");
//Print version information
printk(KERN_INFO "%s", version);
//register_netdev will call s3c4510_init()
if((result = register_netdev(&s3c4510_netdevs)))
printk("S3C4510 eth: Error %i registering device \"%s\"\n", result, s3c4510_netdevs.name);
return result ? 0 : -ENODEV;
}
void __exit s3c4510_cleanup(void)
{
TRACE("cleanup\n");
kfree(s3c4510_netdevs.priv);
unregister_netdev(&s3c4510_netdevs);
return;
}
module_init(s3c4510_init_module);
module_exit(s3c4510_cleanup);
MODULE_DESCRIPTION("Samsung 4510B ethernet driver");
MODULE_AUTHOR("Mac Wang <mac@os.nctu.edu.tw>");
MODULE_LICENSE("GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -