Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ksz8851.c Source File

ksz8851.c

Go to the documentation of this file.
00001 /**
00002  * @file ksz8851.c
00003  * @brief KSZ8851 Ethernet controller
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "drivers/ksz8851.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief KSZ8851 driver
00040  **/
00041 
00042 const NicDriver ksz8851Driver =
00043 {
00044    NIC_TYPE_ETHERNET,
00045    ETH_MTU,
00046    ksz8851Init,
00047    ksz8851Tick,
00048    ksz8851EnableIrq,
00049    ksz8851DisableIrq,
00050    ksz8851EventHandler,
00051    ksz8851SendPacket,
00052    ksz8851SetMulticastFilter,
00053    NULL,
00054    NULL,
00055    NULL,
00056    TRUE,
00057    TRUE,
00058    TRUE,
00059    FALSE
00060 };
00061 
00062 
00063 /**
00064  * @brief KSZ8851 controller initialization
00065  * @param[in] interface Underlying network interface
00066  * @return Error code
00067  **/
00068 
00069 error_t ksz8851Init(NetInterface *interface)
00070 {
00071    //Point to the driver context
00072    Ksz8851Context *context = (Ksz8851Context *) interface->nicContext;
00073 
00074    //Debug message
00075    TRACE_INFO("Initializing KSZ8851 Ethernet controller...\r\n");
00076 
00077 #if (KSZ8851_SPI_SUPPORT == ENABLED)
00078    //Initialize SPI
00079    interface->spiDriver->init();
00080 #endif
00081 
00082    //Initialize external interrupt line
00083    interface->extIntDriver->init();
00084 
00085    //Debug message
00086    TRACE_DEBUG("CIDER=0x%04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_CIDER));
00087    TRACE_DEBUG("PHY1ILR=0x%04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_PHY1ILR));
00088    TRACE_DEBUG("PHY1IHR=0x%04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_PHY1IHR));
00089 
00090    //Check device ID and revision ID
00091    if(ksz8851ReadReg(interface, KSZ8851_REG_CIDER) != KSZ8851_REV_A3_ID)
00092       return ERROR_WRONG_IDENTIFIER;
00093 
00094    //Dump registers for debugging purpose
00095    ksz8851DumpReg(interface);
00096 
00097    //Initialize driver specific variables
00098    context->frameId = 0;
00099 
00100    //Allocate TX and RX buffers
00101    context->txBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00102    context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
00103 
00104    //Failed to allocate memory?
00105    if(context->txBuffer == NULL || context->rxBuffer == NULL)
00106    {
00107       //Clean up side effects
00108       memPoolFree(context->txBuffer);
00109       memPoolFree(context->rxBuffer);
00110 
00111       //Report an error
00112       return ERROR_OUT_OF_MEMORY;
00113    }
00114 
00115    //Initialize MAC address
00116    ksz8851WriteReg(interface, KSZ8851_REG_MARH, htons(interface->macAddr.w[0]));
00117    ksz8851WriteReg(interface, KSZ8851_REG_MARM, htons(interface->macAddr.w[1]));
00118    ksz8851WriteReg(interface, KSZ8851_REG_MARL, htons(interface->macAddr.w[2]));
00119 
00120    //Packets shorter than 64 bytes are padded and the CRC is automatically generated
00121    ksz8851WriteReg(interface, KSZ8851_REG_TXCR, TXCR_TXFCE | TXCR_TXPE | TXCR_TXCE);
00122    //Automatically increment TX data pointer
00123    ksz8851WriteReg(interface, KSZ8851_REG_TXFDPR, TXFDPR_TXFPAI);
00124 
00125    //Configure address filtering
00126    ksz8851WriteReg(interface, KSZ8851_REG_RXCR1,
00127       RXCR1_RXPAFMA | RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXME | RXCR1_RXUE);
00128 
00129    //No checksum verification
00130    ksz8851WriteReg(interface, KSZ8851_REG_RXCR2,
00131       RXCR2_SRDBL2 | RXCR2_IUFFP | RXCR2_RXIUFCEZ);
00132 
00133    //Enable automatic RXQ frame buffer dequeue
00134    ksz8851WriteReg(interface, KSZ8851_REG_RXQCR, RXQCR_RXFCTE | RXQCR_ADRFE);
00135    //Automatically increment RX data pointer
00136    ksz8851WriteReg(interface, KSZ8851_REG_RXFDPR, RXFDPR_RXFPAI);
00137    //Configure receive frame count threshold
00138    ksz8851WriteReg(interface, KSZ8851_REG_RXFCTR, 1);
00139 
00140    //Force link in half-duplex if auto-negotiation failed
00141    ksz8851ClearBit(interface, KSZ8851_REG_P1CR, P1CR_FORCE_DUPLEX);
00142    //Restart auto-negotiation
00143    ksz8851SetBit(interface, KSZ8851_REG_P1CR, P1CR_RESTART_AN);
00144 
00145    //Clear interrupt flags
00146    ksz8851SetBit(interface, KSZ8851_REG_ISR, ISR_LCIS | ISR_TXIS |
00147       ISR_RXIS | ISR_RXOIS | ISR_TXPSIS | ISR_RXPSIS | ISR_TXSAIS |
00148       ISR_RXWFDIS | ISR_RXMPDIS | ISR_LDIS | ISR_EDIS | ISR_SPIBEIS);
00149 
00150    //Configure interrupts as desired
00151    ksz8851SetBit(interface, KSZ8851_REG_IER, IER_LCIE | IER_TXIE | IER_RXIE);
00152 
00153    //Enable TX operation
00154    ksz8851SetBit(interface, KSZ8851_REG_TXCR, TXCR_TXE);
00155    //Enable RX operation
00156    ksz8851SetBit(interface, KSZ8851_REG_RXCR1, RXCR1_RXE);
00157 
00158    //Accept any packets from the upper layer
00159    osSetEvent(&interface->nicTxEvent);
00160 
00161    //Force the TCP/IP stack to poll the link state at startup
00162    interface->nicEvent = TRUE;
00163    //Notify the TCP/IP stack of the event
00164    osSetEvent(&netEvent);
00165 
00166    //Successful initialization
00167    return NO_ERROR;
00168 }
00169 
00170 
00171 /**
00172  * @brief KSZ8851 timer handler
00173  * @param[in] interface Underlying network interface
00174  **/
00175 
00176 void ksz8851Tick(NetInterface *interface)
00177 {
00178 }
00179 
00180 
00181 /**
00182  * @brief Enable interrupts
00183  * @param[in] interface Underlying network interface
00184  **/
00185 
00186 void ksz8851EnableIrq(NetInterface *interface)
00187 {
00188    //Enable interrupts
00189    interface->extIntDriver->enableIrq();
00190 }
00191 
00192 
00193 /**
00194  * @brief Disable interrupts
00195  * @param[in] interface Underlying network interface
00196  **/
00197 
00198 void ksz8851DisableIrq(NetInterface *interface)
00199 {
00200    //Disable interrupts
00201    interface->extIntDriver->disableIrq();
00202 }
00203 
00204 
00205 /**
00206  * @brief KSZ8851 interrupt service routine
00207  * @param[in] interface Underlying network interface
00208  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
00209  **/
00210 
00211 bool_t ksz8851IrqHandler(NetInterface *interface)
00212 {
00213    bool_t flag;
00214    uint16_t ier;
00215    uint16_t isr;
00216 
00217    //This flag will be set if a higher priority task must be woken
00218    flag = FALSE;
00219 
00220    //Save IER register value
00221    ier = ksz8851ReadReg(interface, KSZ8851_REG_IER);
00222    //Disable interrupts to release the interrupt line
00223    ksz8851WriteReg(interface, KSZ8851_REG_IER, 0);
00224 
00225    //Read interrupt status register
00226    isr = ksz8851ReadReg(interface, KSZ8851_REG_ISR);
00227 
00228    //Link status change?
00229    if(isr & ISR_LCIS)
00230    {
00231       //Disable LCIE interrupt
00232       ier &= ~IER_LCIE;
00233 
00234       //Set event flag
00235       interface->nicEvent = TRUE;
00236       //Notify the TCP/IP stack of the event
00237       flag |= osSetEventFromIsr(&netEvent);
00238    }
00239 
00240    //Packet transmission complete?
00241    if(isr & ISR_TXIS)
00242    {
00243       //Clear interrupt flag
00244       ksz8851WriteReg(interface, KSZ8851_REG_ISR, ISR_TXIS);
00245 
00246       //Notify the TCP/IP stack that the transmitter is ready to send
00247       flag |= osSetEventFromIsr(&interface->nicTxEvent);
00248    }
00249 
00250    //Packet received?
00251    if(isr & ISR_RXIS)
00252    {
00253       //Disable RXIE interrupt
00254       ier &= ~IER_RXIE;
00255 
00256       //Set event flag
00257       interface->nicEvent = TRUE;
00258       //Notify the TCP/IP stack of the event
00259       flag |= osSetEventFromIsr(&netEvent);
00260    }
00261 
00262    //Re-enable interrupts once the interrupt has been serviced
00263    ksz8851WriteReg(interface, KSZ8851_REG_IER, ier);
00264 
00265    //A higher priority task must be woken?
00266    return flag;
00267 }
00268 
00269 
00270 /**
00271  * @brief KSZ8851 event handler
00272  * @param[in] interface Underlying network interface
00273  **/
00274 
00275 void ksz8851EventHandler(NetInterface *interface)
00276 {
00277    uint16_t status;
00278    uint_t frameCount;
00279 
00280    //Read interrupt status register
00281    status = ksz8851ReadReg(interface, KSZ8851_REG_ISR);
00282 
00283    //Check whether the link status has changed?
00284    if(status & ISR_LCIS)
00285    {
00286       //Clear interrupt flag
00287       ksz8851WriteReg(interface, KSZ8851_REG_ISR, ISR_LCIS);
00288       //Read PHY status register
00289       status = ksz8851ReadReg(interface, KSZ8851_REG_P1SR);
00290 
00291       //Check link state
00292       if(status & P1SR_LINK_GOOD)
00293       {
00294          //Get current speed
00295          if(status & P1SR_OPERATION_SPEED)
00296             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00297          else
00298             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00299 
00300          //Determine the new duplex mode
00301          if(status & P1SR_OPERATION_DUPLEX)
00302             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00303          else
00304             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00305 
00306          //Link is up
00307          interface->linkState = TRUE;
00308       }
00309       else
00310       {
00311          //Link is down
00312          interface->linkState = FALSE;
00313       }
00314 
00315       //Process link state change event
00316       nicNotifyLinkChange(interface);
00317    }
00318 
00319    //Check whether a packet has been received?
00320    if(status & ISR_RXIS)
00321    {
00322       //Clear interrupt flag
00323       ksz8851WriteReg(interface, KSZ8851_REG_ISR, ISR_RXIS);
00324       //Get the total number of frames that are pending in the buffer
00325       frameCount = MSB(ksz8851ReadReg(interface, KSZ8851_REG_RXFCTR));
00326 
00327       //Process all pending packets
00328       while(frameCount > 0)
00329       {
00330          //Read incoming packet
00331          ksz8851ReceivePacket(interface);
00332          //Decrement frame counter
00333          frameCount--;
00334       }
00335    }
00336 
00337    //Re-enable LCIE and RXIE interrupts
00338    ksz8851SetBit(interface, KSZ8851_REG_IER, IER_LCIE | IER_RXIE);
00339 }
00340 
00341 
00342 /**
00343  * @brief Send a packet
00344  * @param[in] interface Underlying network interface
00345  * @param[in] buffer Multi-part buffer containing the data to send
00346  * @param[in] offset Offset to the first data byte
00347  * @return Error code
00348  **/
00349 
00350 error_t ksz8851SendPacket(NetInterface *interface,
00351    const NetBuffer *buffer, size_t offset)
00352 {
00353    size_t n;
00354    size_t length;
00355    Ksz8851TxHeader header;
00356    Ksz8851Context *context;
00357 
00358    //Point to the driver context
00359    context = (Ksz8851Context *) interface->nicContext;
00360 
00361    //Retrieve the length of the packet
00362    length = netBufferGetLength(buffer) - offset;
00363 
00364    //Check the frame length
00365    if(length > ETH_MAX_FRAME_SIZE)
00366    {
00367       //The transmitter can accept another packet
00368       osSetEvent(&interface->nicTxEvent);
00369       //Report an error
00370       return ERROR_INVALID_LENGTH;
00371    }
00372 
00373    //Get the amount of free memory available in the TX FIFO
00374    n = ksz8851ReadReg(interface, KSZ8851_REG_TXMIR) & TXMIR_TXMA_MASK;
00375 
00376    //Make sure enough memory is available
00377    if((length + 8) > n)
00378       return ERROR_FAILURE;
00379 
00380    //Copy user data
00381    netBufferRead(context->txBuffer, buffer, offset, length);
00382 
00383    //Format control word
00384    header.controlWord = TX_CTRL_TXIC | (context->frameId++ & TX_CTRL_TXFID);
00385    //Total number of bytes to be transmitted
00386    header.byteCount = length;
00387 
00388    //Enable TXQ write access
00389    ksz8851SetBit(interface, KSZ8851_REG_RXQCR, RXQCR_SDA);
00390    //Write TX packet header
00391    ksz8851WriteFifo(interface, (uint8_t *) &header, sizeof(Ksz8851TxHeader));
00392    //Write data
00393    ksz8851WriteFifo(interface, context->txBuffer, length);
00394    //End TXQ write access
00395    ksz8851ClearBit(interface, KSZ8851_REG_RXQCR, RXQCR_SDA);
00396 
00397    //Start transmission
00398    ksz8851SetBit(interface, KSZ8851_REG_TXQCR, TXQCR_METFE);
00399 
00400    //Successful processing
00401    return NO_ERROR;
00402 }
00403 
00404 
00405 /**
00406  * @brief Receive a packet
00407  * @param[in] interface Underlying network interface
00408  * @return Error code
00409  **/
00410 
00411 error_t ksz8851ReceivePacket(NetInterface *interface)
00412 {
00413    size_t n;
00414    uint16_t status;
00415    Ksz8851Context *context;
00416 
00417    //Point to the driver context
00418    context = (Ksz8851Context *) interface->nicContext;
00419 
00420    //Read received frame status from RXFHSR
00421    status = ksz8851ReadReg(interface, KSZ8851_REG_RXFHSR);
00422 
00423    //Make sure the frame is valid
00424    if(status & RXFHSR_RXFV)
00425    {
00426       //Check error flags
00427       if(!(status & (RXFHSR_RXMR | RXFHSR_RXFTL | RXFHSR_RXRF | RXFHSR_RXCE)))
00428       {
00429          //Read received frame byte size from RXFHBCR
00430          n = ksz8851ReadReg(interface, KSZ8851_REG_RXFHBCR) & RXFHBCR_RXBC_MASK;
00431 
00432          //Ensure the frame size is acceptable
00433          if(n > 0 && n <= ETH_MAX_FRAME_SIZE)
00434          {
00435             //Reset QMU RXQ frame pointer to zero
00436             ksz8851WriteReg(interface, KSZ8851_REG_RXFDPR, RXFDPR_RXFPAI);
00437             //Enable RXQ read access
00438             ksz8851SetBit(interface, KSZ8851_REG_RXQCR, RXQCR_SDA);
00439             //Read data
00440             ksz8851ReadFifo(interface, context->rxBuffer, n);
00441             //End RXQ read access
00442             ksz8851ClearBit(interface, KSZ8851_REG_RXQCR, RXQCR_SDA);
00443 
00444             //Pass the packet to the upper layer
00445             nicProcessPacket(interface, context->rxBuffer, n);
00446             //Valid packet received
00447             return NO_ERROR;
00448          }
00449       }
00450    }
00451 
00452    //Release the current error frame from RXQ
00453    ksz8851SetBit(interface, KSZ8851_REG_RXQCR, RXQCR_RRXEF);
00454    //Report an error
00455    return ERROR_INVALID_PACKET;
00456 }
00457 
00458 
00459 /**
00460  * @brief Configure multicast MAC address filtering
00461  * @param[in] interface Underlying network interface
00462  * @return Error code
00463  **/
00464 
00465 error_t ksz8851SetMulticastFilter(NetInterface *interface)
00466 {
00467    uint_t i;
00468    uint_t k;
00469    uint32_t crc;
00470    uint16_t hashTable[4];
00471    MacFilterEntry *entry;
00472 
00473    //Debug message
00474    TRACE_DEBUG("Updating KSZ8851 hash table...\r\n");
00475 
00476    //Clear hash table
00477    memset(hashTable, 0, sizeof(hashTable));
00478 
00479    //The MAC filter table contains the multicast MAC addresses
00480    //to accept when receiving an Ethernet frame
00481    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00482    {
00483       //Point to the current entry
00484       entry = &interface->macMulticastFilter[i];
00485 
00486       //Valid entry?
00487       if(entry->refCount > 0)
00488       {
00489          //Compute CRC over the current MAC address
00490          crc = ksz8851CalcCrc(&entry->addr, sizeof(MacAddr));
00491          //Calculate the corresponding index in the table
00492          k = (crc >> 26) & 0x3F;
00493          //Update hash table contents
00494          hashTable[k / 16] |= (1 << (k % 16));
00495       }
00496    }
00497 
00498    //Write the hash table to the KSZ8851 controller
00499    ksz8851WriteReg(interface, KSZ8851_REG_MAHTR0, hashTable[0]);
00500    ksz8851WriteReg(interface, KSZ8851_REG_MAHTR1, hashTable[1]);
00501    ksz8851WriteReg(interface, KSZ8851_REG_MAHTR2, hashTable[2]);
00502    ksz8851WriteReg(interface, KSZ8851_REG_MAHTR3, hashTable[3]);
00503 
00504    //Debug message
00505    TRACE_DEBUG("  MAHTR0 = %04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_MAHTR0));
00506    TRACE_DEBUG("  MAHTR1 = %04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_MAHTR1));
00507    TRACE_DEBUG("  MAHTR2 = %04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_MAHTR2));
00508    TRACE_DEBUG("  MAHTR3 = %04" PRIX16 "\r\n", ksz8851ReadReg(interface, KSZ8851_REG_MAHTR3));
00509 
00510    //Successful processing
00511    return NO_ERROR;
00512 }
00513 
00514 
00515 /**
00516  * @brief Write KSZ8851 register
00517  * @param[in] interface Underlying network interface
00518  * @param[in] address Register address
00519  * @param[in] data Register value
00520  **/
00521 
00522 void ksz8851WriteReg(NetInterface *interface, uint8_t address, uint16_t data)
00523 {
00524 #if (KSZ8851_SPI_SUPPORT == ENABLED)
00525    uint8_t command;
00526 
00527    //Form the write command
00528    if(address & 0x02)
00529       command = KSZ8851_CMD_WR_REG | KSZ8851_CMD_B3 | KSZ8851_CMD_B2;
00530    else
00531       command = KSZ8851_CMD_WR_REG | KSZ8851_CMD_B1 | KSZ8851_CMD_B0;
00532 
00533    //Pull the CS pin low
00534    interface->spiDriver->assertCs();
00535 
00536    //Command phase
00537    interface->spiDriver->transfer(command | (address >> 6));
00538    interface->spiDriver->transfer(address << 2);
00539 
00540    //Data phase
00541    interface->spiDriver->transfer(LSB(data));
00542    interface->spiDriver->transfer(MSB(data));
00543 
00544    //Terminate the operation by raising the CS pin
00545    interface->spiDriver->deassertCs();
00546 #else
00547    //Set register address
00548    if(address & 0x02)
00549       KSZ8851_CMD_REG = KSZ8851_CMD_B3 | KSZ8851_CMD_B2 | address;
00550    else
00551       KSZ8851_CMD_REG = KSZ8851_CMD_B1 | KSZ8851_CMD_B0 | address;
00552 
00553    //Write register value
00554    KSZ8851_DATA_REG = data;
00555 #endif
00556 }
00557 
00558 
00559 /**
00560  * @brief Read KSZ8851 register
00561  * @param[in] interface Underlying network interface
00562  * @param[in] address Register address
00563  * @return Register value
00564  **/
00565 
00566 uint16_t ksz8851ReadReg(NetInterface *interface, uint8_t address)
00567 {
00568 #if (KSZ8851_SPI_SUPPORT == ENABLED)
00569    uint8_t command;
00570    uint16_t data;
00571 
00572    //Form the read command
00573    if(address & 0x02)
00574       command = KSZ8851_CMD_RD_REG | KSZ8851_CMD_B3 | KSZ8851_CMD_B2;
00575    else
00576       command = KSZ8851_CMD_RD_REG | KSZ8851_CMD_B1 | KSZ8851_CMD_B0;
00577 
00578    //Pull the CS pin low
00579    interface->spiDriver->assertCs();
00580 
00581    //Command phase
00582    interface->spiDriver->transfer(command | (address >> 6));
00583    interface->spiDriver->transfer(address << 2);
00584 
00585    //Data phase (lower 8 bits)
00586    data = interface->spiDriver->transfer(0x00);
00587    //Data phase (upper 8 bits)
00588    data |= interface->spiDriver->transfer(0x00) << 8;
00589 
00590    //Terminate the operation by raising the CS pin
00591    interface->spiDriver->deassertCs();
00592 
00593    //Return register value
00594    return data;
00595 #else
00596    //Set register address
00597    if(address & 0x02)
00598       KSZ8851_CMD_REG = KSZ8851_CMD_B3 | KSZ8851_CMD_B2 | address;
00599    else
00600       KSZ8851_CMD_REG = KSZ8851_CMD_B1 | KSZ8851_CMD_B0 | address;
00601 
00602    //Return register value
00603    return KSZ8851_DATA_REG;
00604 #endif
00605 }
00606 
00607 
00608 /**
00609  * @brief Write TX FIFO
00610  * @param[in] interface Underlying network interface
00611  * @param[in] data Pointer to the data being written
00612  * @param[in] length Number of data to write
00613  **/
00614 
00615 void ksz8851WriteFifo(NetInterface *interface, const uint8_t *data, size_t length)
00616 {
00617 #if (KSZ8851_SPI_SUPPORT == ENABLED)
00618    uint_t i;
00619 
00620    //Pull the CS pin low
00621    interface->spiDriver->assertCs();
00622 
00623    //Command phase
00624    interface->spiDriver->transfer(KSZ8851_CMD_WR_FIFO);
00625 
00626    //Data phase
00627    for(i = 0; i < length; i++)
00628       interface->spiDriver->transfer(data[i]);
00629 
00630    //Maintain alignment to 4-byte boundaries
00631    for(; i % 4; i++)
00632       interface->spiDriver->transfer(0x00);
00633 
00634    //Terminate the operation by raising the CS pin
00635    interface->spiDriver->deassertCs();
00636 #else
00637    uint_t i;
00638 
00639    //Data phase
00640    for(i = 0; i < length; i+=2)
00641       KSZ8851_DATA_REG = data[i] | data[i+1]<<8;
00642 
00643    //Maintain alignment to 4-byte boundaries
00644    for(; i % 4; i+=2)
00645       KSZ8851_DATA_REG = 0x0000;
00646 #endif
00647 }
00648 
00649 
00650 /**
00651  * @brief Read RX FIFO
00652  * @param[in] interface Underlying network interface
00653  * @param[in] data Buffer where to store the incoming data
00654  * @param[in] length Number of data to read
00655  **/
00656 
00657 void ksz8851ReadFifo(NetInterface *interface, uint8_t *data, size_t length)
00658 {
00659 #if (KSZ8851_SPI_SUPPORT == ENABLED)
00660    uint_t i;
00661 
00662    //Pull the CS pin low
00663    interface->spiDriver->assertCs();
00664 
00665    //Command phase
00666    interface->spiDriver->transfer(KSZ8851_CMD_RD_FIFO);
00667 
00668    //The first 4 bytes are dummy data and must be discarded
00669    for(i = 0; i < 4; i++)
00670       interface->spiDriver->transfer(0x00);
00671 
00672    //Ignore RX packet header
00673    for(i = 0; i < 4; i++)
00674       interface->spiDriver->transfer(0x00);
00675 
00676    //Data phase
00677    for(i = 0; i < length; i++)
00678       data[i] = interface->spiDriver->transfer(0x00);
00679 
00680    //Maintain alignment to 4-byte boundaries
00681    for(; i % 4; i++)
00682       interface->spiDriver->transfer(0x00);
00683 
00684    //Terminate the operation by raising the CS pin
00685    interface->spiDriver->deassertCs();
00686 #else
00687    uint_t i;
00688    uint16_t temp;
00689 
00690    //The first 2 bytes are dummy data and must be discarded
00691    temp = KSZ8851_DATA_REG;
00692 
00693    //Ignore RX packet header
00694    temp = KSZ8851_DATA_REG;
00695    temp = KSZ8851_DATA_REG;
00696 
00697    //Data phase
00698    for(i = 0; i < length; i+=2)
00699    {
00700       temp = KSZ8851_DATA_REG;
00701       data [i] = temp & 0xFF;
00702       data [i+1] = (temp>>8) & 0xFF;
00703    }
00704 
00705    //Maintain alignment to 4-byte boundaries
00706    for(; i % 4; i+=2)
00707       temp = KSZ8851_DATA_REG;
00708 #endif
00709 }
00710 
00711 
00712 /**
00713  * @brief Set bit field
00714  * @param[in] interface Underlying network interface
00715  * @param[in] address Register address
00716  * @param[in] mask Bits to set in the target register
00717  **/
00718 
00719 void ksz8851SetBit(NetInterface *interface, uint8_t address, uint16_t mask)
00720 {
00721    uint16_t value;
00722 
00723    //Read current register value
00724    value = ksz8851ReadReg(interface, address);
00725    //Set specified bits
00726    ksz8851WriteReg(interface, address, value | mask);
00727 }
00728 
00729 
00730 /**
00731  * @brief Clear bit field
00732  * @param[in] interface Underlying network interface
00733  * @param[in] address Register address
00734  * @param[in] mask Bits to clear in the target register
00735  **/
00736 
00737 void ksz8851ClearBit(NetInterface *interface, uint8_t address, uint16_t mask)
00738 {
00739    uint16_t value;
00740 
00741    //Read current register value
00742    value = ksz8851ReadReg(interface, address);
00743    //Clear specified bits
00744    ksz8851WriteReg(interface, address, value & ~mask);
00745 }
00746 
00747 
00748 /**
00749  * @brief CRC calculation
00750  * @param[in] data Pointer to the data over which to calculate the CRC
00751  * @param[in] length Number of bytes to process
00752  * @return Resulting CRC value
00753  **/
00754 
00755 uint32_t ksz8851CalcCrc(const void *data, size_t length)
00756 {
00757    uint_t i;
00758    uint_t j;
00759 
00760    //Point to the data over which to calculate the CRC
00761    const uint8_t *p = (uint8_t *) data;
00762    //CRC preset value
00763    uint32_t crc = 0xFFFFFFFF;
00764 
00765    //Loop through data
00766    for(i = 0; i < length; i++)
00767    {
00768       //The message is processed bit by bit
00769       for(j = 0; j < 8; j++)
00770       {
00771          //Update CRC value
00772          if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
00773             crc = (crc << 1) ^ 0x04C11DB7;
00774          else
00775             crc = crc << 1;
00776       }
00777    }
00778 
00779    //Return CRC value
00780    return crc;
00781 }
00782 
00783 
00784 /**
00785  * @brief Dump registers for debugging purpose
00786  * @param[in] interface Underlying network interface
00787  **/
00788 
00789 void ksz8851DumpReg(NetInterface *interface)
00790 {
00791 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
00792    uint_t i;
00793    uint_t j;
00794    uint_t address;
00795 
00796    //Loop through register addresses
00797    for(i = 0; i < 256; i += 16)
00798    {
00799       //Display register address
00800       TRACE_DEBUG("%02" PRIu8 ": ", i);
00801 
00802       //Display 8 registers at a time
00803       for(j = 0; j < 16; j += 2)
00804       {
00805          //Format register address
00806          address = i + j;
00807          //Display register contents
00808          TRACE_DEBUG("0x%04" PRIX16 "  ", ksz8851ReadReg(interface, address));
00809       }
00810 
00811       //Jump to the following line
00812       TRACE_DEBUG("\r\n");
00813    }
00814 
00815    //Terminate with a line feed
00816    TRACE_DEBUG("\r\n");
00817 #endif
00818 }
00819