cs8900.c
来自「SMDK2440 boot code, base on vivi」· C语言 代码 · 共 320 行
C
320 行
/* * Cirrus Logic CS8900A Ethernet * * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> * * Copyright (C) 1999 Ben Williamson <benw@pobox.com> * * 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. * */#include <config.h>#include <machine.h>#include <vstring.h>#include <param.h>#include <net/net.h>#include "cs8900.h"extern void arch_udelay(unsigned int usec);extern void arch_mdelay(unsigned int msec);static bd_t *e_info = NULL;/* packet page register access functions */#ifdef CS8900_BUS32/* we don't need 16 bit initialisation on 32 bit bus */#define get_reg_init_bus(x) get_reg((x))#elsestatic unsigned shortget_reg_init_bus(int regno){ /* force 16 bit busmode */ volatile unsigned char c; c = CS8900_BUS16_0; c = CS8900_BUS16_1; c = CS8900_BUS16_0; c = CS8900_BUS16_1; c = CS8900_BUS16_0; CS8900_PPTR = regno; return (unsigned short) CS8900_PDATA;}#endifstatic unsigned shortget_reg(int regno){ CS8900_PPTR = regno; return (unsigned short) CS8900_PDATA;}static voidput_reg(int regno, unsigned short val){ CS8900_PPTR = regno; CS8900_PDATA = val;}static voideth_reset(void){ int tmo = 1000; // 1sec unsigned short us; if (get_reg_init_bus(PP_ChipID) != 0x630e) return; if (!e_info) return; /* reset NIC */ put_reg(PP_SelfCTL, get_reg(PP_SelfCTL) | PP_SelfCTL_Reset); /* wait for 200ms */ arch_mdelay(200); /* Wait until the chip is reset */ while ((((us = get_reg_init_bus(PP_SelfSTAT)) & PP_SelfSTAT_InitD) == 0) && (tmo-- > 0)) { arch_udelay(1000); } /* set the ethernet address */ put_reg(PP_IA + 0, e_info->bi_enetaddr[0] | (e_info->bi_enetaddr[1] << 8)); put_reg(PP_IA + 2, e_info->bi_enetaddr[2] | (e_info->bi_enetaddr[3] << 8)); put_reg(PP_IA + 4, e_info->bi_enetaddr[4] | (e_info->bi_enetaddr[5] << 8)); /* receive only error free packets addressed to this card */ put_reg(PP_RxCTL, PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK); /* do not generate any interrupts on receive operations */ put_reg(PP_RxCFG, 0); /* do not generate any interrupts on transmit operations */ put_reg(PP_TxCFG, 0); /* do not generate any interrupts on buffer operations */ put_reg(PP_BufCFG, 0); /* enable transmitter/receiver mode */ put_reg(PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);}voidcs8900_get_enetaddr(uchar * addr){ int i; /* verify chip id */ if (get_reg_init_bus(PP_ChipID) != 0x630e) return; eth_reset(); if ((get_reg(PP_SelfST) & (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) == (PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) { /* Load the MAC from EEPROM */ for (i = 0; i < 6 / 2; i++) { unsigned int Addr; Addr = get_reg(PP_IA + i * 2); addr[i * 2] = Addr & 0xFF; addr[i * 2 + 1] = Addr >> 8; } }}voideth_halt(void){ /* disable transmitter/receiver mode */ put_reg(PP_LineCTL, 0); /* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */ get_reg_init_bus(PP_ChipID);}unsigned charhstr_to_u8(char *inn){ unsigned char ret = 0; int i; for (i = 0; i < 2; i++, inn++) { if ((*inn >= '0') && (*inn <= '9')) ret |= *inn - '0'; if ((*inn >= 'a') && (*inn <= 'f')) ret |= (*inn - 'a') + 10; if ((*inn >= 'A') && (*inn <= 'F')) ret |= (*inn - 'A') + 10; ret <<= (1 - i) * 4; } return ret;}void inlineeth_random_enetaddr(unsigned char *mac){ *mac = arch_get_rand_seed() & 0xFE; arch_udelay(*mac++); *mac = arch_get_rand_seed() & 0xFE; arch_udelay(*mac++); *mac = arch_get_rand_seed() & 0xFF; arch_udelay(*mac++); *mac = arch_get_rand_seed() & 0xFF; arch_udelay(*mac++); *mac = arch_get_rand_seed() & 0xFF; arch_udelay(*mac++); *mac = arch_get_rand_seed() & 0xFF;}void inlineeth_set_enetaddr(unsigned char *mac, char *str){ char tmp_mac[18]; memset(&tmp_mac[0], 0, sizeof (tmp_mac)); strncpy(&tmp_mac[0], str, 17); if (strncmp(&tmp_mac[0], "random", 6)) { return eth_random_enetaddr(mac); } *mac++ = hstr_to_u8(&tmp_mac[0]); *mac++ = hstr_to_u8(&tmp_mac[3]); *mac++ = hstr_to_u8(&tmp_mac[6]); *mac++ = hstr_to_u8(&tmp_mac[9]); *mac++ = hstr_to_u8(&tmp_mac[12]); *mac = hstr_to_u8(&tmp_mac[15]);}inteth_init(bd_t * bd){ unsigned short cs8900_sig = 0; cs8900_sig = get_reg_init_bus(PP_ChipID); /* verify chip id */ if (cs8900_sig != 0x630e) { printk("\n%s: incorrect EISA code 0x%.4x\n", __FILE__, cs8900_sig); return 0; } else { cs8900_sig = get_reg(PP_ChipRev);#define REVISION(x) (((x) & 0x1f00) >> 8)#define REV_B 7 printk("\nCS8900A rev %c detected. ", 'B' + REVISION(cs8900_sig) - REV_B);#undef REVISION#undef REV_B }#ifdef CONFIG_NET_RANDOM_MAC eth_random_enetaddr(&(bd->bi_enetaddr[0]));#endif#ifdef CONFIG_NET_MANUAL_MAC eth_set_enetaddr(&(bd->bi_enetaddr[0]), CONFIG_NET_MAC);#endif#ifdef CONFIG_NET_PARAM_MAC eth_set_enetaddr(&(bd->bi_enetaddr[0]), get_param_str_p("ethaddr"));#endif#ifdef CONFIG_NET_EEPROM_MAC cs8900_get_enetaddr(&(bd->bi_enetaddr[0]));#endif printk("[%02X:%02X:%02X:%02X:%02X:%02X]\n", bd->bi_enetaddr[0], bd->bi_enetaddr[1] , bd->bi_enetaddr[2], bd->bi_enetaddr[3] , bd->bi_enetaddr[4], bd->bi_enetaddr[5]); e_info = bd; eth_reset(); return 0;}/* Get a data block via Ethernet */extern inteth_rx(void){ int i; unsigned short rxlen; unsigned short *addr; unsigned short status; status = get_reg(PP_RER); if ((status & PP_RER_RxOK) == 0) return 0; status = CS8900_RTDATA; /* stat */ rxlen = CS8900_RTDATA; /* len */ if (rxlen > PKTSIZE_ALIGN + PKTALIGN) printk("packet too big!\n"); for (addr = (unsigned short *) NetRxPackets[0], i = rxlen >> 1; i > 0; i--) *addr++ = CS8900_RTDATA; if (rxlen & 1) *addr++ = CS8900_RTDATA; /* Pass the packet up to the protocol layers. */ NetReceive(NetRxPackets[0], rxlen); return rxlen;}/* Send a data block via Ethernet. */extern inteth_send(volatile void *packet, int length){ volatile unsigned short *addr; int tmo; unsigned short s; NET_DEBUG("%s(%d): length = %d\n", __FUNCTION__, __LINE__, length); /* initiate a transmit sequence */ CS8900_TxCMD = PP_TxCmd_TxStart_Full; CS8900_TxLEN = length; /* Test to see if the chip has allocated memory for the packet */ if ((get_reg(PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) { /* Oops... this should not happen! */ printk ("CS8900: unable to send packet. check your network or server.\n"); return -1; } /* Write the contents of the packet */ /* assume even number of bytes */ for (addr = packet; length > 0; length -= 2) CS8900_RTDATA = *addr++; tmo = 10000; while (((s = get_reg(PP_TER) & ~0x1F) == 0) && (tmo-- > 0)) { arch_udelay(1); } /* nothing */ ; if ((s & (PP_TER_CRS | PP_TER_TxOK)) != PP_TER_TxOK) { printk("\ntransmission error %#x\n", s); eth_reset(); } else NET_DEBUG("%s(): transmission success.\n", __FUNCTION__); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?