📄 if_sitsang.c
字号:
//==========================================================================//// dev/if_sitsang.c//// Ethernet device driver for SMsC LAN91C96 on Sitsang////==========================================================================//####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND####//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD or other sources,// and are covered by the appropriate copyright disclaimers included herein.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): alvin// Contributors: gthomas// Date: 2002-08-30// Purpose: // Description: hardware driver for LAN91c96 ethernet// ////####DESCRIPTIONEND####////==========================================================================// Ethernet device driver#include <redboot.h>#include <pkgconf/system.h>#include <pkgconf/devs_eth_arm_sitsang.h>#ifdef CYGPKG_NET#include <pkgconf/net.h>#include <cyg/kernel/kapi.h>#endif#include <cyg/infra/cyg_type.h>#include <cyg/infra/cyg_ass.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/hal_io.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#include <netdev.h>#include <eth_drv.h>#include "../include/lan91c96API.h"#include "../include/lan91c96.h"#define lan91c96_BASE SITSANG_LAN91C96_ATTREG #define ETHER_ADDR_LEN 6// Instantiate the interfaces that we have:#define SITSANG_PCR_RW 0x08000000#define SITSANG_BCR_RW 0x08000004#define PXA_OSCR 0x40A00010#define PXA_MSC0 0x48000008LAN91C96_ContextT ctxSLan91c96; // LAN91c96 device info. structure// eth0ETH_DRV_SC(sitsang_sc0, 0, // Driver specific data "eth0", // Name for this interface lan91c96_start, //Hardware/Software initialzation lan91c96_stop, //Cleanup lan91c96_control, //Write configuration changes, etc. lan91c96_can_send, //is the device able to transmit lan91c96_send, //take data from redboot and write it to the device and command it to send lan91c96_recv, //empty device receive buffer and hand the data to redboot lan91c96_deliver, //looks to be related to threading lan91c96_int, //poll function and interrupt handling? lan91c96_int_vector // );NETDEVTAB_ENTRY(sitsang_netdev0, "sitsang-0", sitsang_lan91c96_init, // &sitsang_sc0);static void lan91c96_int(struct eth_drv_sc *sc);static cyg_interrupt lan91c96_interrupt;static cyg_handle_t lan91c96_interrupt_handle;#define MAX_PACKET_SIZE 1514char transferBuffer[MAX_PACKET_SIZE] ;static void Delay(int uSec){ int delaytime; int starttime; delaytime = (int)(uSec*3.6864); starttime = *(volatile unsigned long *)PXA_OSCR ; *(volatile unsigned long *)PXA_OSCR = 0; while ((*(volatile unsigned long *)PXA_OSCR) < delaytime);}// This ISR is called when the ethernet interrupt occursstatic intlan91c96_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs){ cyg_drv_interrupt_mask(0 /*CYGNUM_HAL_INTERRUPT_EINT3*/); //Does this mask the interrupt??????????????????? return (CYGNUM_HAL_INTERRUPT_ETHERNET); // Run the DSR}// The deliver function (ex-DSR) handles the ethernet [logical] processingstatic voidlan91c96_deliver(struct eth_drv_sc *sc){ lan91c96_int(sc); // Allow interrupts to happen again cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_ETHERNET); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETHERNET);}static intlan91c96_int_vector(struct eth_drv_sc *sc){ return (CYGNUM_HAL_INTERRUPT_ETHERNET /*Actually need to return the interrupt code*/);}static bool sitsang_lan91c96_init(struct cyg_netdevtab_entry *tab){ int i ; struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; cyg_uint8 enaddr[6] ; unsigned short status = 0 ; LAN91C96_ContextT *ctxP ; unsigned short PCR,BCR; unsigned long MSC0; PCR = *(volatile unsigned short *) SITSANG_PCR_RW; PCR |= 0x1<<14 | 0x1<<10; //turn LAN power on *(volatile unsigned short*) SITSANG_PCR_RW = PCR; BCR = *(volatile unsigned short *) SITSANG_BCR_RW; BCR |= 1<<2 | 1<<12; //turn bus open, and LAN reset *(volatile unsigned short*) SITSANG_BCR_RW = BCR; Delay(2000); BCR = *(volatile unsigned short *) SITSANG_BCR_RW; BCR &= ~(1<<12); //clear LAN reset *(volatile unsigned short*) SITSANG_BCR_RW = BCR; Delay(100000); BCR = *(volatile unsigned short *) SITSANG_BCR_RW; BCR |= (1<<13); //enable 8-bit mode *(volatile unsigned short*) SITSANG_BCR_RW = BCR; MSC0 = *(volatile unsigned long *) PXA_MSC0; MSC0 &= 0x0000ffff; MSC0 |= 0x7ff10000; *(volatile unsigned long *) PXA_MSC0 = MSC0; (LAN91C96_ContextT *)(sc->driver_private) = &ctxSLan91c96 ; ctxSLan91c96.transferBufferP = transferBuffer ; // Initialize environment, setup interrupt handler cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETHERNET, 99, // Priority - what goes here? (cyg_addrword_t)sc, // Data item passed to interrupt handler (cyg_ISR_t *)lan91c96_isr, (cyg_DSR_t *)eth_drv_dsr, // The logical driver DSR &lan91c96_interrupt_handle, &lan91c96_interrupt); cyg_drv_interrupt_attach(lan91c96_interrupt_handle); cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_ETHERNET); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETHERNET); LAN91C96SWInitX((LAN91C96_ContextT *)sc->driver_private, (PVOID)SITSANG_LAN91C96_IOREG, (PVOID)SITSANG_LAN91C96_ATTREG) ; // Get the address of the private data // This is a context structure that contains device specific data ctxP = sc->driver_private ; // Start the hardware LAN91C96HWSetup(ctxP, 1) ; // Fill in local MAC address so it can be passed // to the Redboot infrastructure enaddr[0] = (cyg_uint8)(ctxP->MACAddress[0]) ; enaddr[1] = (cyg_uint8)(ctxP->MACAddress[0] >> 8) ; enaddr[2] = (cyg_uint8)(ctxP->MACAddress[1]) ; enaddr[3] = (cyg_uint8)(ctxP->MACAddress[1] >> 8) ; enaddr[4] = (cyg_uint8)(ctxP->MACAddress[2]) ; enaddr[5] = (cyg_uint8)(ctxP->MACAddress[2] >> 8) ; // clear the transfer buffer // this buffer is used to transfer data to/from the hardware for(i=0; i<MAX_PACKET_SIZE; i++) { transferBuffer[i] = 0 ; } // initialize the Redboot ethernet driver infrastructure (sc->funs->eth_drv->init)(sc, enaddr);//printf("5. in function sitsang_lan91c96_init\n"); status -= status ; return true;}static voidlan91c96_stop(struct eth_drv_sc *sc){}//// This function is called to "start up" the interface. It may be called// multiple times, even when the hardware is already running. It will be// called whenever something "hardware oriented" changes and should leave// the hardware ready to send/receive packets.//static voidlan91c96_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){ LAN91C96_ContextT *ctxP = sc->driver_private ; //call LAN91C96HWSetup(LAN91C96_ContextT *ctxP, BOOL resetFlag) //LAN91C96HWSetup(ctxP, 1) ; return ;}//// This routine is called to perform special "control" operations//static intlan91c96_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length){ return(0) ;}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intlan91c96_can_send(struct eth_drv_sc *sc){ unsigned short canSend = 0 ; UINT16 frameHandle = 0; // Page number of allocated frame static unsigned long canSendCnt = 0 ; LAN91C96_ContextT *ctxP = (LAN91C96_ContextT *)sc->driver_private ;// BSPLOG(printf("lan91c96_can_send %d ", ++canSendCnt)) ; if(!ctxP->packetSent) { return(FALSE) ; } canSend = TRUE ; return (canSend);}//// This routine is called to send data to the hardware.static void lan91c96_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long txKey){ /* sg_list contains a pointer to a buffer and its length. This buffer contains the data to be transmitted. 'sg_len' is the length of the data buffers list. 'total_len' is the total number of bytes of data to transmit. */ int i, j; unsigned int lLength, index ; LAN91C96_ContextT *ctxP = sc->driver_private ; unsigned char *pTemp ; unsigned char *txDataBufferP; static unsigned long txCnt = 0 ; txDataBufferP = &transferBuffer[0] ; index = 0 ; ctxP->packetSent = 0 ; ctxP->txKey = txKey ; ctxP->event = ISQ_TxEvent ; memset(txDataBufferP, 0, MAX_PACKET_SIZE) ; // Put data into buffer for(i=0; i<sg_len; i++) { lLength = sg_list[i].len ; pTemp = (unsigned char *)sg_list[i].buf ; for(j=0; j<lLength; j++) { *txDataBufferP = *pTemp ; txDataBufferP++ ; pTemp++ ; } } //if total length is less than 64 bytes, pad the end of the message with zeroes#define MIN_LAN91C96_PACKET_SIZE 64 if(total_len < MIN_LAN91C96_PACKET_SIZE) { for(j=total_len; j<MIN_LAN91C96_PACKET_SIZE; j++) { *txDataBufferP++ = (unsigned char) 0x0 ; } total_len = MIN_LAN91C96_PACKET_SIZE ; } LAN91C96TransmitPacket(ctxP, (unsigned short *)transferBuffer, total_len) ; (sc->funs->eth_drv->tx_done)(sc, ctxP->txKey, 0);// BSPLOG(printf("lan91c96_send %d\n",++txCnt)) return ;}//// This function is called when a packet has been received. It's job is// to prepare to unload the packet from the hardware. Once the length of// the packet is known, the upper layer of the driver can be told. When// the upper layer is ready to unload the packet, the internal function// 'lan91c96_recv' will be called to actually fetch it from the hardware.//// This function will be called in response to an interrupt/event or due// to polling of the status of the lan91c96//static voidlan91c96_RxEvent(struct eth_drv_sc *sc){ UINT32 len; unsigned short *l_transferBufferP = (unsigned short *)&transferBuffer ; LAN91C96_ContextT *ctxP = (LAN91C96_ContextT *)sc->driver_private ; len = 0 ; /* query the device to determine the length of the packet so that space can be allocated by the Redboot layer amd to store the received packet in the transfer buffer. */ if( LAN91C96ReceivePacket(ctxP, l_transferBufferP, (unsigned int)(MAX_PACKET_SIZE), &len) ) {// printf("ethernet hardware receive error\n") ; return ; } ctxP->rxPacketLen = len ; (sc->funs->eth_drv->recv)(sc, len);//printf("end of function sitsang_lan91c96_RxEvent\n");}//// This function is called as a result of the "eth_drv_recv()" call above.// It's job is to actually fetch data for a packet from the transferBuffer of // the device layer to the receive buffers in the Redboot layer once the Redboot layer// memory buffers have been allocated for the packet. Note that the buffers// may come in pieces, using a scatter-gather list. This allows for more// efficient processing in the upper layers of the stack.//static voidlan91c96_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){ int i ; int sgBufLen; UINT16 *sgDataP ; // Redboot layer data buffer UINT16 *transferBufferP ; // index into transferBuffer ; LAN91C96_ContextT *ctxP = (LAN91C96_ContextT *)sc->driver_private ;//printf("In lan91c96_recv\n") ; transferBufferP = (UINT16 *)(&transferBuffer[0]) ; /* the following loop cycles through the Redboot layer data buffers */ /* the loop should continue until the transferBuffer is emptied of valid data. The loop will automatically use the number of sg_list indexes required to hold all of the data retrieved from the hardware */ for (i = 0; i < sg_len; i++) { sgDataP = (UINT16 *)sg_list[i].buf ; if(!sgDataP) {// printf("cleanup and get out of here because the system can't handle the message\n") ; return ; } sgBufLen = sg_list[i].len; while (sgBufLen >= sizeof(*sgDataP)) { *sgDataP++ = *(transferBufferP++) ; sgBufLen -= sizeof(*sgDataP); } if (sgBufLen) { // Fetch last odd byte *(char *)sgDataP = *(char *)transferBufferP & 0xFF ; } }//printf("returning from lan91c96_recv\n") ; return ;}static voidlan91c96_TxEvent(struct eth_drv_sc *sc, int stat){ struct LAN91C96_ContextS *ctxP = (struct LAN91C96_ContextS *)sc->driver_private; unsigned long status = 0 ; //status of the device status = ctxP->packetSent ;//printf("2. leaving TxEvent\n") ; (sc->funs->eth_drv->tx_done)(sc, ctxP->packetSent, 0);//printf("2. leaving TxEvent\n") ;}static voidlan91c96_BufEvent(struct eth_drv_sc *sc, int stat){// not sure this is needed}/* FUNCTION: lan91c96_int PURPOSE: Determines and services interrupts/events */static voidlan91c96_int(struct eth_drv_sc *sc){ struct LAN91C96_ContextS *ctxP = (struct LAN91C96_ContextS *)sc->driver_private ; if(LAN91C96ReceiveStatus(ctxP)) { lan91c96_RxEvent(sc); } return ; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -