// // Copyright (C) 2011 Andy Pugh, 2016 Boris Skegin // // 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. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERinstTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // #include #include "rtapi.h" #include "rtapi_string.h" #include "rtapi_math.h" #include "hal.h" #include "hostmot2.h" // PktUART specific error codes #include "pktuart_errno.h" #define MaxTrFrames (16) // Send counts are written to 16 deep FIFO, burst mode int hm2_pktuart_parse_md(hostmot2_t *hm2, int md_index) { // All this function actually does is allocate memory // and give the uart modules names. // // some standard sanity checks // int i, r = -EINVAL; hm2_module_descriptor_t *md = &hm2->md[md_index]; static int last_gtag = -1; //The PktUART declares a TX and RX module separately //And Rx can currently be v1 or v2 if (md->gtag == HM2_GTAG_PKTUART_TX && !hm2_md_is_consistent(hm2,md_index, 0, 4, 4, 0x000F) && !hm2_md_is_consistent(hm2,md_index, 1, 4, 4, 0x000F) && !hm2_md_is_consistent(hm2,md_index, 2, 4, 4, 0x000F)) { HM2_ERR("Unsupported or inconsistent PktUART TX module (version %i)" "not loading driver \n", md->version); return -EINVAL; } if (md->gtag == HM2_GTAG_PKTUART_RX && !hm2_md_is_consistent(hm2, md_index, 0, 4, 4, 0x000F) && !hm2_md_is_consistent(hm2, md_index, 1, 4, 4, 0x000F) && !hm2_md_is_consistent(hm2, md_index, 2, 4, 4, 0x000F)) { HM2_ERR("Unsupported or inconsistent PktUART RX module (version %i)" "not loading driver \n", md->version); return -EINVAL; } if (hm2->pktuart.num_instances > 1 && last_gtag == md->gtag) { HM2_ERR( "found duplicate Module Descriptor for %s (inconsistent " "firmware), not loading driver %i %i\n", hm2_get_general_function_name(md->gtag), md->gtag, last_gtag ); return -EINVAL; } last_gtag = md->gtag; if (hm2->config.num_pktuarts > md->instances) { HM2_ERR( "config defines %d pktuarts, but only %d are available, " "not loading driver\n", hm2->config.num_pktuarts, md->instances ); return -EINVAL; } if (hm2->config.num_pktuarts == 0) { return 0; } // // looks good, start, or continue, initializing // if (hm2->pktuart.num_instances == 0){ if (hm2->config.num_pktuarts == -1) { hm2->pktuart.num_instances = md->instances; } else { hm2->pktuart.num_instances = hm2->config.num_pktuarts; } hm2->pktuart.instance = (hm2_pktuart_instance_t *)hal_malloc(hm2->pktuart.num_instances * sizeof(hm2_pktuart_instance_t)); if (hm2->pktuart.instance == NULL) { HM2_ERR("out of memory!\n"); r = -ENOMEM; goto fail0; } } // Register automatic updating of the Rx and Tx mode (status) registers if (md->gtag == HM2_GTAG_PKTUART_RX){ hm2->pktuart.rx_version = md->version; r = hm2_register_tram_read_region(hm2, md->base_address + 3 * md->register_stride, (hm2->pktuart.num_instances * sizeof(rtapi_u32)), &hm2->pktuart.rx_status_reg); if (r < 0) { HM2_ERR("error registering tram read region for PktUART Rx status(%d)\n", r); goto fail0; } } else if (md->gtag == HM2_GTAG_PKTUART_TX) { hm2->pktuart.tx_version = md->version; r = hm2_register_tram_read_region(hm2, md->base_address + 3 * md->register_stride, (hm2->pktuart.num_instances * sizeof(rtapi_u32)), &hm2->pktuart.tx_status_reg); if (r < 0) { HM2_ERR("error registering tram read region for PktUART Tx status(%d)\n", r); goto fail0; } } for (i = 0 ; i < hm2->pktuart.num_instances ; i++){ hm2_pktuart_instance_t *inst = &hm2->pktuart.instance[i]; // For the time being we assume that all PktUARTS come on pairs if (inst->clock_freq == 0){ inst->clock_freq = md->clock_freq; r = rtapi_snprintf(inst->name, sizeof(inst->name), "%s.pktuart.%01d", hm2->llio->name, i); HM2_PRINT("created PktUART Interface function %s.\n", inst->name); } if (md->gtag == HM2_GTAG_PKTUART_TX){ inst->tx_addr = md->base_address + i * md->instance_stride; inst->tx_fifo_count_addr = (md->base_address + md->register_stride + i * md->instance_stride); inst->tx_bitrate_addr = (md->base_address + 2 * md->register_stride + i * md->instance_stride); inst->tx_mode_addr = (md->base_address + 3 * md->register_stride +i * md->instance_stride); } else if (md->gtag == HM2_GTAG_PKTUART_RX){ inst->rx_addr = md->base_address + i * md->instance_stride; inst->rx_fifo_count_addr = (md->base_address + md->register_stride + i * md->instance_stride); inst->rx_bitrate_addr = (md->base_address + 2 * md->register_stride + i * md->instance_stride); inst->rx_mode_addr = (md->base_address + 3 * md->register_stride +i * md->instance_stride); } else{ HM2_ERR("Something very weird happened"); goto fail0; } } return hm2->pktuart.num_instances; fail0: return r; } EXPORT_SYMBOL_GPL(hm2_pktuart_setup_rx); int hm2_pktuart_setup_rx(char *name, unsigned int bitrate, unsigned int filter_hz, unsigned int parity, int frame_delay, bool rx_enable, bool rx_mask){ hostmot2_t *hm2; hm2_pktuart_instance_t *inst = 0; rtapi_u32 buff1, buff2; int i; int r = 0; rtapi_u32 filter; i = hm2_get_pktuart(&hm2, name); if (i < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } inst = &hm2->pktuart.instance[i]; /* PktUART V2+ RX regmap Bit 30 BadPop Error (read data FIFO with no data) RO Bits 29..22 RX data digital filter bits (7..0) (in ClockLow periods) Should be set to 1/2 bit time (or max=65535 if it cannot be set long enough) Bit 21 FrameBuffer has data RO Bits 20..16 Frames received RO Bit 17 Parity enable WO Bit 18 Odd Parity WO (1=odd, 0=even) Bits 15..8 InterFrame delay in bit times RW Bit 7 RXBusy (serial state machine busy) Bit 6 RXMask RO Bit 5 Parity Error RW Bit 4 RCFIFO Error RW Bit 3 RXEnable (must be set to receive packets) RW Bit 2 RXMask Enable (enables input data masking when transmitting) RW Bit 1 Overrun error (no stop bit when expected) (sticky) RW Bit 0 False Start bit error (sticky) RW*/ filter = inst->clock_freq / filter_hz; if (hm2->pktuart.rx_version >= 2){ if (filter > 0xFFFF) filter = 0xFFFF; buff1 = (rtapi_u32)((bitrate * 16777216.0)/inst->clock_freq); //24 bits in v2+ buff1 |= (rtapi_u32)((filter & 0xFF00) << 16); } else { if (filter > 0xFF) filter = 0xFF; buff1 = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in v0 & v1 } buff2 = (rtapi_u32)((filter & 0xFF) << 22); buff2 |= (rtapi_u32)(rx_mask << 2); buff2 |= (rtapi_u32)(rx_enable << 3); buff2 |= (rtapi_u32)((frame_delay & 0xFF) << 8); if (parity > 0) buff2 |= 0x20000; if (parity == 1) buff2 |= 0x40000; if (buff1 != inst->rx_bitrate){ inst->rx_bitrate = buff1; r += hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, &buff1, sizeof(rtapi_u32)); } if (buff2 != inst->rx_mode){ inst->rx_mode = buff2; r += hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff2, sizeof(rtapi_u32)); } if (r < 0) { HM2_ERR("PktUART: hm2->llio->write failure %s setting up RX\n", name); return -1; } return 0; } EXPORT_SYMBOL_GPL(hm2_pktuart_setup_tx); int hm2_pktuart_setup_tx(char *name, unsigned int bitrate, unsigned int parity, int frame_delay, bool drive_enable, bool drive_auto, int enable_delay){ hostmot2_t *hm2; hm2_pktuart_instance_t *inst = 0; rtapi_u32 buff1, buff2; int i; int r = 0; i = hm2_get_pktuart(&hm2, name); if (i < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } inst = &hm2->pktuart.instance[i]; /* PktUART V2+ TX regmap Bit 21 FrameBuffer Has Data RO Bits 20..16 Frames to send RO Bit 17 Parity enable WO Bit 18 Odd Parity WO (1=odd, 0=even) Bits 15..8 InterFrame delay in bit times RW Bit 7 Send busy RO Bit 6 Drive Enable bit (enables external RS-422/485 Driver when set) RW Bit 5 Drive enable Auto (Automatic external drive enable) RW Drive Enable Auto has priority over Drive Enable (bit 6 is a no-op if bit 5 is set) Bit 4 SCFIFO Error RO Bits 3..0 Drive enable delay (delay from asserting drive enable to start of data transmit. In CLock Low periods RW Drive enable delay is important to avoid start bit timing errors at high baud rates in RS-485 (half duplex) modes */ if (hm2->pktuart.tx_version >= 2){ buff1 = (rtapi_u32)((bitrate * 16777216.0)/inst->clock_freq); //24 bits in v2+ } else { buff1 = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in v0 & v1 } buff2 = (rtapi_u32)(enable_delay & 0x0F); if (drive_auto) buff2 |= 0x00020; if (drive_enable) buff2 |= 0x00040; if (parity > 0) buff2 |= 0x20000; if (parity == 1) buff2 |= 0x40000; buff2 |= (rtapi_u32)((frame_delay & 0xFF) << 8); if (buff1 != inst->tx_bitrate){ inst->tx_bitrate = buff1; r += hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, &buff1, sizeof(rtapi_u32)); } if (buff2 != inst->tx_mode){ inst->tx_mode = buff2; r += hm2->llio->write(hm2->llio, inst->tx_mode_addr, &buff2, sizeof(rtapi_u32)); } if (r < 0) { HM2_ERR("PktUART: hm2->llio->write failure %s setting up TX\n", name); return -1; } return 0; } EXPORT_SYMBOL_GPL(hm2_pktuart_reset); void hm2_pktuart_reset(char *name){ hostmot2_t *hm2; hm2_pktuart_instance_t *inst = 0; rtapi_u32 buff; int i; i = hm2_get_pktuart(&hm2, name); if (i < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return; } inst = &hm2->pktuart.instance[i]; buff = 0x80010000; hm2->llio->write(hm2->llio, inst->tx_mode_addr, &buff, sizeof(rtapi_u32)); // clear sends, data FIFO and count register hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(rtapi_u32)); // clear receives, data FIFO and count register } EXPORT_SYMBOL_GPL(hm2_pktuart_setup); // use -1 for bitrate, tx_mode and rx_mode to leave the mode unchanged // use 1 for txclear or rxclear to issue a clear command for Tx or Rx registers int hm2_pktuart_setup(char *name, unsigned int bitrate, rtapi_s32 tx_mode, rtapi_s32 rx_mode, int txclear, int rxclear){ hostmot2_t *hm2; hm2_pktuart_instance_t *inst = 0; rtapi_u32 buff; int i; int r = 0; i = hm2_get_pktuart(&hm2, name); if (i < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } inst = &hm2->pktuart.instance[i]; if (bitrate > 0){ if (hm2->pktuart.tx_version >= 2){ buff = (rtapi_u32)((bitrate * 16777216.0)/inst->clock_freq); //24 bits in v2+ } else { buff = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in v0 & v1 } if (buff != inst->tx_bitrate){ inst->tx_bitrate = buff; r += hm2->llio->write(hm2->llio, inst->tx_bitrate_addr, &buff, sizeof(rtapi_u32)); } if (hm2->pktuart.rx_version >= 2){ buff = (rtapi_u32)((bitrate * 16777216.0)/inst->clock_freq); //24 bits in v2+ } else { buff = (rtapi_u32)((bitrate * 1048576.0)/inst->clock_freq); //20 bits in v0 & v1 } if (buff != inst->rx_bitrate){ inst->rx_bitrate = buff; r += hm2->llio->write(hm2->llio, inst->rx_bitrate_addr, &buff, sizeof(rtapi_u32)); } } /* http://freeby.mesanet.com/regmap The PktUARTxMode register is used for setting and checking the PktUARTx's operation mode, timing and status: Bit 21 FrameBuffer Has Data Bits 20..16 Frames to send (input and output ports can overlap with an FPGA) Bit 17 Parity enable WO Bit 18 Odd Parity WO (1=odd, 0=even) Bits 15..8 InterFrame delay in bit times Bit 7 Transmit Logic active, not an error Bit 6 Drive Enable bit (enables external RS-422/485 Driver when set) Bit 5 Drive enable Auto (Automatic external drive enable) Bit 4 unused Bits 3..0 Drive enable delay (delay from asserting drive enable to start of data transmit). In CLock Low periods */ if (tx_mode >= 0) { buff = ((rtapi_u32)tx_mode) & 0x3ffff; r += hm2->llio->write(hm2->llio, inst->tx_mode_addr, &buff, sizeof(rtapi_u32)); } /* http://freeby.mesanet.com/regmap The PktUARTrMode register is used for setting and checking the PktUARTr's operation mode, timing, and status Bits 29..22 RX data digital filter (in ClockLow periods) Should be set to 1/2 bit time (or max=255 if it cannot be set long enough) Bit 21 FrameBuffer has data Bit 17 Parity enable WO Bit 18 Odd Parity WO (1=odd, 0=even) Bits 20..16 Frames received Bits 15..8 InterFrame delay in bit times Bit 7 Receive Logic active, not an error Bit 6 RXMask Bit 5 Unused Bit 4 RCFIFO Error Bit 3 RXEnable (must be set to receive packets) Bit 2 RXMask Enable (enables input data masking when transmitting) Bit 1 Overrun error (no stop bit when expected) (sticky) Bit 0 False Start bit error (sticky) */ if (rx_mode >= 0) { buff = ((rtapi_u32)rx_mode) & 0x3FFFFFFF; r += hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(rtapi_u32)); } /* http://freeby.mesanet.com/regmap The PktUARTx/PktUARTr mode register has a special data command that clears the PktUARTx/PktUARTr Clearing aborts any sends/receives in process, clears the data FIFO and clears the send count FIFO. To issue a clear command, you write 0x80010000 to the PktUARTx/PktUARTr mode register. */ buff = 0x80010000; if (txclear==1) r += hm2->llio->write(hm2->llio, inst->tx_mode_addr, &buff, sizeof(rtapi_u32)); // clear sends, data FIFO and count register if (rxclear==1) r += hm2->llio->write(hm2->llio, inst->rx_mode_addr, &buff, sizeof(rtapi_u32)); // clear receives, data FIFO and count register if (r < 0) { HM2_ERR("PktUART: hm2->llio->write failure %s\n", name); return -1; } return 0; } EXPORT_SYMBOL_GPL(hm2_pktuart_send); int hm2_pktuart_send(char *name, unsigned char data[], rtapi_u8 *num_frames, rtapi_u16 frame_sizes[]) { hostmot2_t *hm2; rtapi_u32 buff; int c = 0; int r = 0; rtapi_u16 count = 0; int inst; /* we work with nframes as a local copy of num_frames, so that we can return the num_frames sent out in case of SCFIFO error. */ rtapi_u8 nframes; inst = hm2_get_pktuart(&hm2, name); if (inst < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } if (hm2->pktuart.instance[inst].tx_bitrate == 0){ HM2_ERR("%s has not been configured.\n", name); return -EINVAL; } /* http://freeby.mesanet.com/regmap Send counts are written to 16 deep FIFO allowing up to 16 packets to be sent in a burst (subject to data FIFO depth limits). */ // Test if num_frames <= MaxTrFrames if ((*num_frames) > MaxTrFrames){ nframes = MaxTrFrames; } else{ nframes = *num_frames; } *num_frames = 0; rtapi_u8 i; for (i = 0; i < nframes; i++){ count = count + frame_sizes[i]; while (c < count - 3){ buff = (data[c] + (data[c+1] << 8) + (data[c+2] << 16) + (data[c+3] << 24)); r = hm2->llio->queue_write(hm2->llio, hm2->pktuart.instance[inst].tx_addr, &buff, sizeof(rtapi_u32)); if (r < 0) { HM2_ERR("%s send: hm2->llio->queue_write failure\n", name); return -1; } c = c + 4; } // Now write the last bytes with bytes number < 4 switch(count - c){ case 0: break; case 1: buff = data[c]; r = hm2->llio->queue_write(hm2->llio, hm2->pktuart.instance[inst].tx_addr, &buff, sizeof(rtapi_u32)); if (r < 0){ HM2_ERR("%s send: hm2->llio->queue_write failure\n", name); return -1; } break; case 2: buff = (data[c] + (data[c+1] << 8)); r = hm2->llio->queue_write(hm2->llio, hm2->pktuart.instance[inst].tx_addr, &buff, sizeof(rtapi_u32)); if (r < 0){ HM2_ERR("%s send: hm2->llio->queue_write failure\n", name); return -1; } break; case 3: buff = (data[c] + (data[c+1] << 8) + (data[c+2] << 16)); r = hm2->llio->queue_write(hm2->llio, hm2->pktuart.instance[inst].tx_addr, &buff, sizeof(rtapi_u32)); if (r < 0){ HM2_ERR("%s send: hm2->llio->queue_write failure\n", name); return -1; } break; default: HM2_ERR("%s send error in buffer parsing: count = %i, i = %i\n", name, count, c); return -1; } // end switch (*num_frames)++; c = count; } // for loop // Write the number of bytes to be sent to PktUARTx sendcount register for (i = 0; i < nframes; i++){ buff = (rtapi_u32) frame_sizes[i]; r = hm2->llio->queue_write(hm2->llio, hm2->pktuart.instance[inst].tx_fifo_count_addr, &buff, sizeof(rtapi_u32)); // Check for Send Count FIFO error r = hm2->llio->queue_read(hm2->llio, hm2->pktuart.instance[inst].tx_mode_addr, &buff, sizeof(rtapi_u32)); if ((buff >> 4) & 0x01) { HM2_ERR_NO_LL("%s: SCFFIFO error\n", name); return -HM2_PKTUART_TxSCFIFOError; } if (r < 0){ HM2_ERR("%s send: hm2->llio->queue_write failure\n", name); return -1; } } return count; } /* The function hm2_pktuart_read performs reads/writes outside of the normal * thread cycles. This is espacially a problem with the Ethernet and p-port * connected cards where the reads and writes should be packeted. * This function has been left in place for backwards compatibility, but it * is recommended to use the hm2_pktuart_queue_* functions instead */ EXPORT_SYMBOL_GPL(hm2_pktuart_read); int hm2_pktuart_read(char *name, unsigned char data[], rtapi_u8 *num_frames, rtapi_u16 *max_frame_length, rtapi_u16 frame_sizes[]) { hostmot2_t *hm2; int r, c; int bytes_total = 0; // total amount of bytes read rtapi_u16 countp; // packets count rtapi_u16 countb; // bytes count for the oldest packet received int inst; rtapi_u32 buff; rtapi_u16 data_size=(*num_frames)*(*max_frame_length); inst = hm2_get_pktuart(&hm2, name); if (inst < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); *num_frames=0; return -EINVAL; } if (hm2->pktuart.instance[inst].rx_bitrate == 0 ) { HM2_ERR("%s has not been configured.\n", name); *num_frames=0; return -EINVAL; } // First poll the mode register for a non zero frames received count // (mode register bits 20..16) r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_mode_addr, &buff, sizeof(rtapi_u32)); if (r < 0) { HM2_ERR("%s read: hm2->llio->queue_read failure\n", name); return -1; // make the error message more detailed } if (buff & (0x1 << 21)){ countp = (buff >> 16) & 0x1f; } else { countp = 0; } HM2_INFO("hm2_pktuart: buffer = %08x\n", buff); HM2_INFO("hm2_pktuart: %i frames received\n", countp); // We expect to read at least 1 frame. // If there is no complete frame yet in the buffer, // we'll deal with this by checking error bits. *num_frames = 0; // Bit 7 set does not really indicate any error condition, // but very probably means that the cycle time of the thread, // which you attach this function to, is not appropriate. if ((buff >> 7) & 0x1){ HM2_INFO("%s: Buffer error (RX idle but data in RX data FIFO)\n", name); } // Now check the error bits if ((buff >> 1) & 0x1){ HM2_ERR_NO_LL("%s: Overrun error, no stop bit\n", name); return -HM2_PKTUART_RxOverrunError; } if (buff & 0x1){ HM2_ERR_NO_LL("%s: False Start bit error\n", name); return -HM2_PKTUART_RxStartbitError; } // RCFIFO Error will get sticky if it is a consequence of either Overrun or False Start bit error? if ((buff >> 4) & 0x1){ HM2_ERR_NO_LL("%s: RCFIFO Error\n", name); return -HM2_PKTUART_RxRCFIFOError; } if (countp==0){ HM2_INFO_NO_LL("%s: no new frames \n", name); return 0; // return zero bytes and zero frames } rtapi_u16 i=0; while ( i < countp ) { buff=0; /* The receive count register is a FIFO that contains the byte counts of received packets. Since it is a FIFO it must only be read once after it has be determined that there are packets available to read. */ r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_fifo_count_addr, &buff, sizeof(rtapi_u32)); countb = buff & 0x3ff; // PktUARTr receive count register Bits 9..0 : bytes in receive packet if ((buff >> 14) & 0x1) { HM2_ERR_NO_LL("%s has False Start bit error in this packet.\n", name); return -HM2_PKTUART_RxPacketStartbitError; } if ((buff >> 15) & 0x1) { HM2_ERR_NO_LL("%s has Overrun error in this packet\n", name); return -HM2_PKTUART_RxPacketOverrrunError; } // a packet is completely received, but its byte count is zero // is very unprobable, however we intercept this error too if (countb==0) { HM2_ERR_NO_LL("%s: packet %d has %d bytes.\n", name, countp+1, countb); return -HM2_PKTUART_RxPacketSizeZero; } if (( bytes_total+countb)> data_size) { HM2_ERR_NO_LL("%s: bytes available %d are more than data array size %d\n", name, bytes_total+countb, data_size); return -HM2_PKTUART_RxArraySizeError ; countb = data_size - bytes_total; } (*num_frames)++; // increment num_frames to be returned at the end c = 0; buff = 0; frame_sizes[i]=countb; while (c < countb - 3){ r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_addr, &buff, sizeof(rtapi_u32)); if (r < 0) { HM2_ERR("%s read: hm2->llio->queue_read failure\n", name); return r; } data[bytes_total+c] = (buff & 0x000000FF); // i*frame_sizes[i] data[bytes_total+c+1] = (buff & 0x0000FF00) >> 8; data[bytes_total+c+2] = (buff & 0x00FF0000) >> 16; data[bytes_total+c+3] = (buff & 0xFF000000) >> 24; c = c + 4; } switch(countb - c){ case 0: break; case 1: r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_addr, &buff, sizeof(rtapi_u32)); data[bytes_total+c] = (buff & 0x000000FF); break; case 2: r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_addr, &buff, sizeof(rtapi_u32)); data[bytes_total+c] = (buff & 0x000000FF); data[bytes_total+c+1] = (buff & 0x0000FF00) >> 8; break; case 3: r = hm2->llio->read(hm2->llio, hm2->pktuart.instance[inst].rx_addr, &buff, sizeof(rtapi_u32)); data[bytes_total+c] = (buff & 0x000000FF); data[bytes_total+c+1] = (buff & 0x0000FF00) >> 8; data[bytes_total+c+2] = (buff & 0x00FF0000) >> 16; break; default: HM2_ERR_NO_LL("PktUART READ: Error in buffer parsing.\n"); return -EINVAL; } if (r < 0) { HM2_ERR("%s read: hm2->llio->queue_write failure\n", name); return -1; } bytes_total = bytes_total + countb; i++; // one frame/datagram read }// frame loop return bytes_total; } /* This function queues sufficient reads to get the available frame sizes * data is loaded into the *fsizes array on the next read cycle. * fsizes should be u32 x 16 * FIXME: decide how to work out that the data has all been transferred */ int hm2_pktuart_queue_get_frame_sizes(char *name, rtapi_u32 fsizes[]){ // queue as many reads of the FIFO as there are frames hostmot2_t *hm2; int inst; int j; int r; inst = hm2_get_pktuart(&hm2, name); if (inst < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } if (hm2->pktuart.instance[inst].rx_bitrate == 0 ) { HM2_ERR("%s has not been configured.\n", name); return -EINVAL; } for (j = 0; j < ((hm2->pktuart.rx_status_reg[inst] >> 16) & 0x1F); j++ ){ rtapi_print_msg(RTAPI_MSG_INFO, "j = %i\n", j); r = hm2->llio->queue_read(hm2->llio, hm2->pktuart.instance[inst].rx_fifo_count_addr, &fsizes[j], sizeof(rtapi_u32)); if (r < 0){ HM2_ERR("Unable to queue Rx FIFO count read"); } } return j - 1; } EXPORT_SYMBOL_GPL(hm2_pktuart_queue_get_frame_sizes); /* This function queues sufficient reads to extract the available data. * It does no error checking and does not explicitly check if there is * data to read (it will just queue zero reads in that case) * The using function should use the hm2_pktuart_get_rx_status functions * to determine whether data exists and error status. * The function queues enough reads to read the given number of 32 bit * frames, which should have been previously read by * hm2_pktuart_queue_get_frame_sizes returns the number of frame reads queued. */ int hm2_pktuart_queue_read_data(char *name, rtapi_u32 data[], int bytes) { hostmot2_t *hm2; int r; int i; int inst; inst = hm2_get_pktuart(&hm2, name); if (inst < 0){ HM2_ERR_NO_LL("Can not find PktUART instance %s.\n", name); return -EINVAL; } if (hm2->pktuart.instance[inst].rx_bitrate == 0 ) { HM2_ERR("%s has not been configured.\n", name); return -EINVAL; } /* queue enough reads to get the whole frame. Data will be transferred * to data[] next thread cycle, direct from FPGA, no serial latency */ for (i = 0; i < ((bytes % 4 == 0)? bytes / 4 : bytes / 4 + 1 ); i++ ){ r = hm2->llio->queue_read(hm2->llio, hm2->pktuart.instance[inst].rx_addr, &data[i], sizeof(rtapi_u32)); if (r < 0){ HM2_ERR("Unable to queue Rx FIFO read"); } } return i - 1; } EXPORT_SYMBOL_GPL(hm2_pktuart_queue_read_data); rtapi_u32 hm2_pktuart_get_rx_status(char *name){ hostmot2_t *hm2; int i = hm2_get_pktuart(&hm2, name); return hm2->pktuart.rx_status_reg[i]; } EXPORT_SYMBOL_GPL(hm2_pktuart_get_rx_status); rtapi_u32 hm2_pktuart_get_tx_status(char *name){ hostmot2_t *hm2; int i = hm2_get_pktuart(&hm2, name); return hm2->pktuart.tx_status_reg[i]; } EXPORT_SYMBOL_GPL(hm2_pktuart_get_tx_status); int hm2_pktuart_get_clock(char* name){ hostmot2_t *hm2; int i = hm2_get_pktuart(&hm2, name); hm2_pktuart_instance_t inst = hm2->pktuart.instance[i]; return inst.clock_freq; } EXPORT_SYMBOL_GPL(hm2_pktuart_get_clock); int hm2_pktuart_get_version(char* name){ hostmot2_t *hm2; hm2_get_pktuart(&hm2, name); return hm2->pktuart.tx_version + 16 * hm2->pktuart.rx_version ; } EXPORT_SYMBOL_GPL(hm2_pktuart_get_version); void hm2_pktuart_print_module(hostmot2_t *hm2){ int i; HM2_PRINT("PktUART: %d\n", hm2->pktuart.num_instances); if (hm2->pktuart.num_instances <= 0) return; HM2_PRINT(" version: %d\n", hm2->pktuart.version); HM2_PRINT(" channel configurations\n"); for (i = 0; i < hm2->pktuart.num_instances; i ++) { HM2_PRINT(" clock_frequency: %d Hz (%s MHz)\n", hm2->pktuart.instance[i].clock_freq, hm2_hz_to_mhz(hm2->pktuart.instance[i].clock_freq)); HM2_PRINT(" instance %d:\n", i); HM2_PRINT(" HAL name = %s\n", hm2->pktuart.instance[i].name); } } // The following standard Hostmot2 functions are not currently used by pktuart. void hm2_pktuart_cleanup(hostmot2_t *hm2) { } void hm2_pktuart_write(hostmot2_t *hm2) { }