/** fmReceiveNetworkData * \ingroup platformUtil * * \desc Receives data on a network socket. * * \param[in] socketInfo points to the socket information structure. * * \param[out] data points to the buffer in which the received data * should be stored. * * \param[in] maxBytes is the maximum number of bytes to receive. * * \param[out] numBytes points to a location in which the actual number * of received bytes will be stored. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmReceiveNetworkData(fm_socket *socketInfo, void * data, fm_int maxBytes, fm_int * numBytes) { fm_byte * ptr; struct sockaddr_in addrInfo; socklen_t addrLen; fm_int nb; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, data=%p, maxBytes=%d, numBytes=%p\n", (void *) socketInfo, (void *) data, maxBytes, (void *) numBytes); if (!socketInfo || !data || !numBytes) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } if (socketInfo->type == FM_SOCKET_TYPE_UDP) { *numBytes = recvfrom(socketInfo->sock, data, maxBytes, 0, (struct sockaddr *) &addrInfo, &addrLen); } else if (socketInfo->type == FM_SOCKET_TYPE_TCP) { ptr = data; *numBytes = 0; do { nb = recv(socketInfo->sock, ptr, maxBytes - *numBytes, 0); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, nb == -1); /* Closed connection */ if (nb == 0) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_NO_MORE); } ptr += nb; *numBytes += nb; } while (*numBytes < maxBytes); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmReceiveNetworkData */
/** fmResetLBGMember * \ingroup intLbg * * \desc Resets LBGMember to initial values. * * \param[out] lbgMember is the LBG member which should be reset. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmResetLBGMember(fm_LBGMember *lbgMember) { fm_status err = FM_OK; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_LBG, "lbgMember=%p\n", (void *) lbgMember ); if (lbgMember == NULL) { err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_LBG, err); } /* Reset lbgMember to default values */ FM_CLEAR(*lbgMember); lbgMember->lbgMemberType = FM_LBG_MEMBER_TYPE_PORT; lbgMember->port = FM_PORT_DROP; lbgMember->mcastGroup = -1; lbgMember->l234Lbg = -1; ABORT: FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_LBG, err); } /* end fmResetLBGMember */
/** fmSendNetworkData * \ingroup platformUtil * * \desc Transmits data on a network socket. * * \param[in] socketInfo points to the socket information structure. * * \param[out] data points to the data to be transmitted. * * \param[in] numBytes is the number of bytes to be transmitted. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmSendNetworkData(fm_socket *socketInfo, void *data, fm_int numBytes) { fm_int errResult; fm_int nb; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, data=%p, numBytes=%d\n", (void *) socketInfo, (void *) data, numBytes); if (!socketInfo || !data) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } if (socketInfo->type == FM_SOCKET_TYPE_UDP) { errResult = sendto(socketInfo->sock, data, numBytes, 0, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult != 0); } else if (socketInfo->type == FM_SOCKET_TYPE_TCP) { do { nb = send(socketInfo->sock, data, numBytes, 0); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, nb == -1); if (nb > 0) { data = (((fm_byte *) data) + nb); numBytes -= nb; } } while ((nb > 0) && numBytes); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmSendNetworkData */
/** fmCloseNetworkConnection * \ingroup platformUtil * * \desc Closes a network socket. * * \param[in,out] client points to the socket information structure. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCloseNetworkConnection(fm_socket *client) { FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "client=%p\n", (void *) client); if (!client) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } if (client->type == FM_SOCKET_TYPE_TCP) { close(client->sock); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmCloseNetworkConnection */
/** fmCopyLBGMember * \ingroup intLbg * * \desc Updates LBG member of bin based on the member type. This * function assumes that srcLbgMember is already validated. * * \param[out] destLbgMember is the destination LBG member in which values * should be stored. * * \param[in] srcLbgMember is the source LBG member from which values * should be retrieved. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCopyLBGMember(fm_LBGMember *destLbgMember, fm_LBGMember *srcLbgMember) { fm_status err = FM_OK; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_LBG, "destLbgMember=%p, srcLbgMember=%p\n", (void *) destLbgMember, (void *) srcLbgMember ); if (destLbgMember == NULL || srcLbgMember == NULL) { err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_LBG, err); } err = fmResetLBGMember(destLbgMember); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_LBG, err); /* Update specific fields based on LBG member type and leave the * remaining fields as default value. */ switch(srcLbgMember->lbgMemberType) { case FM_LBG_MEMBER_TYPE_PORT: destLbgMember->port = srcLbgMember->port; break; case FM_LBG_MEMBER_TYPE_MAC_ADDR: destLbgMember->dmac = srcLbgMember->dmac; destLbgMember->egressVlan = srcLbgMember->egressVlan; destLbgMember->vrid = srcLbgMember->vrid; break; case FM_LBG_MEMBER_TYPE_MCAST_GROUP: destLbgMember->mcastGroup = srcLbgMember->mcastGroup; break; case FM_LBG_MEMBER_TYPE_L234_LBG: destLbgMember->l234Lbg = srcLbgMember->l234Lbg; break; default: err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_LBG, err); } destLbgMember->lbgMemberType = srcLbgMember->lbgMemberType; ABORT: FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_LBG, err); } /* end fmCopyLBGMember */
/** fmPlatformMdioRead * \ingroup platformApp * * \desc Read 16 bits of data from the MDIO bus. * * \param[in] sw is the switch on which to operate. * * \param[in] type is a bit mask specifying MDIO access options. * See MDIO Management Options. * * \param[in] addr is the MDIO address. * * \param[in] dev is the device on the MDIO port. dev is only used if * type includes the FM_SMGMT_MDIO_10G bit, otherwise it * is ignored. * * \param[in] reg is the register number on the MDIO device. * * \param[out] data contains the value read from the MDIO device. * * \return FM_OK if successful. * *****************************************************************************/ fm_int fmPlatformMdioRead(fm_int sw, fm_int type, fm_int addr, fm_int dev, fm_int reg, fm_uint16 *data) { FM_NOT_USED(sw); FM_NOT_USED(type); FM_NOT_USED(addr); FM_NOT_USED(dev); FM_NOT_USED(reg); FM_NOT_USED(data); FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_UNSUPPORTED); } /* end fmPlatformMdioRead */
/** fmMapBitMaskLogicalToLinkUpMask * \ingroup intSwitch * * \desc maps logical port bit mask to link up mask * * \param[in] switchPtr points to the switch state entry * * \param[in] logMask is the logical port bit mask * * \param[out] upMask contains the link up mask, i.e., only those ports * that were set in the logMask and are also in a link up * state will be set in this mask. * * \return FM_OK if request succeeded. * *****************************************************************************/ fm_status fmMapBitMaskLogicalToLinkUpMask(fm_switch * switchPtr, fm_uint32 logMask, fm_uint32 * upMask) { fm_int limit; fm_int cpi; fm_int port; fm_uint32 um = 0; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_SWITCH, "sw = %d, logMask = 0x%08x, " "upMask = %p\n", switchPtr->switchNumber, logMask, (void *) upMask); limit = switchPtr->numCardinalPorts; if (limit > (fm_int)(sizeof(logMask) * 8)) { limit = sizeof(logMask) * 8; } for (cpi = 0 ; cpi < limit ; cpi++) { port = switchPtr->cardinalPortInfo.portMap[cpi].logPort; /* CPU port is always available to send to */ if ( switchPtr->portTable[port]->linkUp || switchPtr->portTable[port]->isPortForceUp || port == switchPtr->cpuPort) { um |= (1 << cpi); } } *upMask = logMask & um; FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_OK); } /* end fmMapBitMaskLogicalToLinkUpMask */
/** fmMapBitMaskPhysicalToLogical * \ingroup intSwitch * * \desc maps physical port bit mask to logical port bit mask * * \param[in] switchPtr points to the switch state entry * * \param[in] physMask is the physical port bit mask * * \param[out] logMask contains the logical port bit mask * * \return FM_OK if request succeeded. * *****************************************************************************/ fm_status fmMapBitMaskPhysicalToLogical(fm_switch * switchPtr, fm_uint32 physMask, fm_uint32 * logMask) { fm_int limit; fm_int cpi; fm_int physPort; fm_uint32 newMask = 0; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_SWITCH, "sw = %d, physMask = 0x%08x, " "logMask = %p\n", switchPtr->switchNumber, physMask, (void *) logMask); limit = switchPtr->numCardinalPorts; if (limit > (fm_int)(sizeof(physMask) * 8)) { limit = sizeof(physMask) * 8; } for (cpi = 0 ; cpi < limit ; cpi++) { physPort = switchPtr->cardinalPortInfo.portMap[cpi].physPort; if ( physMask & (1 << physPort) ) { newMask |= (1 << cpi); } } *logMask = newMask; FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_OK); } /* end fmMapBitMaskPhysicalToLogical */
/** fmWaitForNetworkEvent * \ingroup platformUtil * * \desc Waits for network events. * * \param[out] sockets points to an array of active and inactive sockets. * This function can activate inactive sockets when a client * attempts to make a connection. The array must be maxSockets * in length. * * \param[in] numSockets is the current number of active sockets; it must * be in the range [1..maxSockets). * * \param[in] maxSockets is the maximum number of sockets this function * can activate. * * \param[out] eventReceived points to an array where this function places * the network event type for each active socket. The array * must be maxSockets elements in length. * * \param[in] timeout is the amount of time to wait for a network event. * Set to ''FM_WAIT_FOREVER'' to wait indefinitely. * * \return FM_OK if successful. * \return Other ''Status Codes'' as appropriate in case of failure. * *****************************************************************************/ fm_status fmWaitForNetworkEvent(fm_socket ** sockets, fm_int * numSockets, fm_int maxSockets, fm_int * eventReceived, fm_timestamp *timeout) { fm_int currNumSockets; fm_int errResult; fm_int i; fm_int j; fm_int slot; fm_bool doIncrement; struct pollfd fds[FM_MAX_FDS_NUM] = { {0} }; fm_int fdsCnt; socklen_t addrLen = SOCKET_ADDRLEN; struct timeval ts; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "sockets=%p, numSockets=%p(%d), maxSockets=%d, " "eventReceived=%p, timeout=%p\n", (void *) sockets, (void *) numSockets, (numSockets ? *numSockets : -1), maxSockets, (void *) eventReceived, (void *) timeout); if ((!sockets || !eventReceived || !numSockets || (*numSockets == 0) || \ (maxSockets > FM_MAX_FDS_NUM) || (*numSockets > FM_MAX_FDS_NUM))) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } currNumSockets = *numSockets; for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++ ) { #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Watching descriptor %d\n", sockets[i]->sock); #endif if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED) { fds[fdsCnt].fd = sockets[i]->sock; fds[fdsCnt].events = POLLIN; fds[fdsCnt].revents = 0; fdsCnt++; } } if (timeout != FM_WAIT_FOREVER) { FM_CLEAR(ts); ts.tv_sec = (int) timeout->sec; ts.tv_usec = (int) timeout->usec; } errResult = poll(fds, fdsCnt, ((timeout == FM_WAIT_FOREVER) ? -1 : \ ((ts.tv_sec * 1000) + (ts.tv_usec / 1000)) )); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++, fdsCnt++) { /* Default case */ eventReceived[i] = FM_NETWORK_EVENT_NONE; if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED && fds[fdsCnt].revents & POLLIN) { /* Handle TCP connection on server socket */ if ((sockets[i]->type == FM_SOCKET_TYPE_TCP) && (sockets[i]->serverPort > 0)) { doIncrement = TRUE; slot = *numSockets; for ( j = 0 ; j < currNumSockets ; j++ ) { if (sockets[j]->type == FM_SOCKET_TYPE_CLOSED) { doIncrement = FALSE; slot = j; break; } } if (slot >= maxSockets) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Not enough socket slots left to accept client\n"); break; } FM_CLEAR(*sockets[slot]); sockets[slot]->sock = accept(sockets[i]->sock, (struct sockaddr *) &sockets[slot]->address, &addrLen); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, sockets[slot]->sock == -1); sockets[slot]->type = FM_SOCKET_TYPE_TCP; eventReceived[i] = FM_NETWORK_EVENT_NEW_CLIENT; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Handled new client connection\n"); #endif if (doIncrement) { (*numSockets)++; } break; } else { eventReceived[i] = FM_NETWORK_EVENT_DATA_AVAILABLE; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Data available on client #%d\n", i - 1); #endif } } } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmWaitForNetworkEvent */
/** fmCreateNetworkClient * \ingroup platformUtil * * \desc Creates a network client socket. * * \param[out] socketInfo points to the information structure for the * client socket. * * \param[in] type is the type of socket to create. * * \param[in] host points to a string specifying the hostname. * * \param[in] port is the port number. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCreateNetworkClient(fm_socket * socketInfo, fm_socketType type, fm_text host, fm_int port) { struct hostent h; struct hostent *hp; fm_int errResult; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; char buf[FM_GETHOSTBYNAME_BUF_SIZE]; int herrno; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, port=%d\n", (void *) socketInfo, port); if (!socketInfo) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } FM_CLEAR(*socketInfo); if (type == FM_SOCKET_TYPE_TCP) { socketInfo->sock = socket(AF_INET, SOCK_STREAM, 0); } else if (type == FM_SOCKET_TYPE_UDP) { socketInfo->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } if (socketInfo->sock == -1) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to create socket type %d\n", type); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_FAIL); } FM_CLEAR(socketInfo->address); socketInfo->address.sin_family = AF_INET; if ((gethostbyname_r(host, &h, buf, FM_GETHOSTBYNAME_BUF_SIZE, &hp, &herrno) != 0) || (hp == NULL)) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to resolve hostname: %s\n", host); } FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, !hp); FM_MEMCPY_S(&socketInfo->address.sin_addr.s_addr, sizeof(socketInfo->address.sin_addr.s_addr), hp->h_addr, hp->h_length); socketInfo->address.sin_port = htons(port); if (type == FM_SOCKET_TYPE_TCP) { errResult = connect(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult != 0); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmCreateNetworkClient */
/** fmCreateNetworkServer * \ingroup platformUtil * * \desc Creates a network server socket. * * \param[out] socketInfo points to the information structure for the * server socket. * * \param[in] type is the type of socket to create. * * \param[in] port is the port number for the socket. * * \param[in] backlog is unused. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCreateNetworkServer(fm_socket * socketInfo, fm_socketType type, fm_int port, fm_int backlog) { fm_status status = FM_OK; fm_int errResult; struct sockaddr_in addrInfo; socklen_t addrLen = sizeof(addrInfo); char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, port=%d, backlog=%d\n", (void *) socketInfo, port, backlog); if (!socketInfo) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } FM_CLEAR(*socketInfo); if (type == FM_SOCKET_TYPE_TCP) { socketInfo->sock = socket(AF_INET, SOCK_STREAM, 0); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, socketInfo->sock == -1); socketInfo->address.sin_family = AF_INET; socketInfo->address.sin_addr.s_addr = htonl(INADDR_ANY); socketInfo->address.sin_port = htons(port); errResult = bind(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); errResult = listen(socketInfo->sock, 3); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Socket descriptor %d initialized\n", socketInfo->sock); #endif } else if (type == FM_SOCKET_TYPE_UDP) { socketInfo->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, socketInfo->sock == -1); socketInfo->address.sin_addr.s_addr = htonl(INADDR_ANY); socketInfo->address.sin_port = htons(port); errResult = bind(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); } else { FM_LOG_ASSERT(FM_LOG_CAT_PLATFORM, FALSE, "Unexpected socket type %d\n", type); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } errResult = getsockname(socketInfo->sock, (struct sockaddr *) &addrInfo, &addrLen); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); socketInfo->serverPort = ntohs(addrInfo.sin_port); FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, status); } /* end fmCreateNetworkServer */
/* I2cWriteRead * \ingroup intSwitch * * \desc Write to then immediately read from an I2C device with * handling max response bytes using switch as I2C master. * * \param[in] sw is the switch number. * * \param[in] device is the I2C device address (0x00 - 0x7F). * * \param[in,out] data points to an array from which data is written and * into which data is read. * * \param[in] wl is the number of bytes to write. * * \param[in] rl is the number of bytes to read. * * \return FM_OK if successful. * \return Other ''Status Codes'' as appropriate in case of * failure. * *****************************************************************************/ static fm_status I2cWriteRead(fm_int sw, fm_uint device, fm_byte *data, fm_uint wl, fm_uint rl) { fm_status status; fm_switch *switchPtr; fm_uint32 regValue; fm_uint i; fm_uint j; fm_bool isTimeout; fm_timestamp start; fm_timestamp end; fm_timestamp diff; fm_uint delTime; fm_uint32 tmp; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_SWITCH, "sw=%d device=0x%x wl=%d rl=%d\n", sw, device, wl, rl); if (rl > I2C_MAX_LEN) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT); } if (wl > I2C_MAX_LEN) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT); } if (data == NULL) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT); } switchPtr = GET_SWITCH_PTR(sw); for (i = 0 ; i < (wl+3)/4 ; i++) { regValue = 0; for (j = 0 ; j < 4 ; j++) { if ((i*4 + j) < wl) { regValue |= (data[i*4 + j] << ((3 - j)*8)); } } status = switchPtr->WriteUINT32(sw, FM10000_I2C_DATA(i), regValue); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITEDATA#%d : 0x%08x\n",i, regValue); } regValue = 0; FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Addr, (device << 1)); FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 0); FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthW, wl); FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthR, rl); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITE: eg 0x%08x Cmd %d wl %d rl %d " "Comp %x LenSent %d intr %d\n", regValue, FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent), FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending)); status = switchPtr->WriteUINT32(sw, FM10000_I2C_CTRL(), regValue); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), &tmp); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "READ: %d reg 0x%08x Cmd %d wl %d rl %d " "Comp %x LenSent %d intr %d\n", status, tmp, FM_GET_FIELD(tmp, FM10000_I2C_CTRL, Command), FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthW), FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthR), FM_GET_FIELD(tmp, FM10000_I2C_CTRL, CommandCompleted), FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthSent), FM_GET_BIT(tmp, FM10000_I2C_CTRL, InterruptPending)); /* Now change command to start the transaction */ if (rl == 0) { /* Write only allow write of 0 length */ FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 1); } else if ((wl > 0) && (rl > 0)) { /* Write Read */ FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 2); } else { /* Read */ FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 3); } FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITE2: reg 0x%08x Cmd %d wl %d rl %d " "Comp %x LenSent %d intr %d\n", regValue, FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent), FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending)); status = switchPtr->WriteUINT32(sw, FM10000_I2C_CTRL(), regValue); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), ®Value); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "READ2: %d reg 0x%08x Cmd %d wl %d rl %d " "Comp %x LenSent %d intr %d\n", status, regValue, FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent), FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending)); /* Poll to check for command done */ fmGetTime(&start); isTimeout = FALSE; do { fmDelay(0, 1000*500); if (isTimeout) { FM_LOG_ERROR( FM_LOG_CAT_SWITCH, "Dev=0x%02x: Timeout (%d msec) waiting " "for I2C_CTRL(0x%x).CommandCompleted!=0. 0x%02x\n", device, I2C_TIMEOUT_MSEC, FM10000_I2C_CTRL(), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted)); FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_I2C_NO_RESPONSE); } fmGetTime(&end); fmSubTimestamps(&end, &start, &diff); delTime = diff.sec*1000 + diff.usec/1000; /* Variable isTimeout is used to improve the timeout detecting */ if (delTime > I2C_TIMEOUT_MSEC) { isTimeout = TRUE; } status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), ®Value); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "STATUS: %d reg 0x%08x cmd %d wl %d rl %d " "Comp %x LenSent %d intr %d\n", status, regValue, FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted), FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent), FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending)); if (status) break; } while (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) == 0); if (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) != 1) { FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "Dev=0x%02x: I2C Command completed with error 0x%x. " "I2C_CTRL(0x%x)=0x%x\n", device, FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted), FM10000_I2C_CTRL(), regValue); FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_I2C_NO_RESPONSE); } for (i = 0 ; i < (rl+3)/4 ; i++) { status = switchPtr->ReadUINT32(sw, FM10000_I2C_DATA(i), ®Value); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status); FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH,"READDATA#%d : 0x%08x\n",i, regValue); for (j = 0 ; j < 4 ; j++) { if ((i*4 + j) < rl) { data[i*4 + j] = (regValue >> ((3 - j)*8)) & 0xFF; } } }