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 + -
显示快捷键?