/* * unix_history_back * * Copy last available string to str, if possible. Return 1 if successful. * Only lines of at most maxlen characters will be considered. In addition * the first searchlen characters of the history entry must match those of str. */ static int unix_history_back(zchar *str, int searchlen, int maxlen) { char **prev = history_view; do { RING_DEC( history_view, history_buffer, history_end); if ((history_view == history_next) || (*history_view == NULL)) { os_beep(BEEP_HIGH); history_view = prev; return 0; } } while (strlen( *history_view) > maxlen || (searchlen != 0 && strncmp( (char *)str, *history_view, searchlen))); strcpy((char *)str + searchlen, *history_view + searchlen); return 1; }
/** * \brief Send a frame splitted into buffers. If the frame size is larger than transfer buffer size * error returned. If frame transfer status is monitored, specify callback for each frame. * \param gmacd Pointer to GMAC Driver instance. * \param sgl Pointer to a scatter-gather list describing the buffers of the ethernet frame. * \param fTxCb Pointer to callback function. */ uint8_t gmacd_send_sg(struct _gmacd* gmacd, uint8_t queue, const struct _gmac_sg_list* sgl, gmacd_callback_t callback) { Gmac* gmac = gmacd->gmac; struct _gmacd_queue* q = &gmacd->queues[queue]; struct _gmac_desc* desc; uint16_t idx, tx_head; int i; if (callback && !q->tx_callbacks) { trace_error("Cannot set send callback, no tx_callbacks "\ "buffer configured for queue %u", queue); } /* Check parameter */ if (!sgl->size) { trace_error("gmacd_send_sg: ethernet frame is empty.\r\n"); return GMACD_PARAM; } if (sgl->size >= q->tx_size) { trace_error("gmacd_send_sg: ethernet frame has too many buffers.\r\n"); return GMACD_PARAM; } /* Check available space */ if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) < sgl->size) { trace_error("gmacd_send_sg: not enough free buffers in TX queue.\r\n"); return GMACD_TX_BUSY; } /* Tag end of TX queue */ tx_head = fixed_mod(q->tx_head + sgl->size, q->tx_size); idx = tx_head; if (q->tx_callbacks) q->tx_callbacks[idx] = NULL; desc = &q->tx_desc[idx]; desc->status |= GMAC_TX_STATUS_USED; /* Update buffer descriptors in reverse order to avoid a race * condition with hardware. */ for (i = sgl->size - 1; i >= 0; i--) { const struct _gmac_sg *sg = &sgl->entries[i]; uint32_t status; if (sg->size > GMAC_TX_UNITSIZE) { trace_error("gmacd_send_sg: buffer size is too big.\r\n"); return GMACD_PARAM; } RING_DEC(idx, q->tx_size); /* Reset TX callback */ if (q->tx_callbacks) q->tx_callbacks[idx] = NULL; desc = &q->tx_desc[idx]; /* Copy data into transmittion buffer */ if (sg->buffer && sg->size) { memcpy((void*)desc->addr, sg->buffer, sg->size); l2cc_clean_region(desc->addr, desc->addr + sg->size); } /* Compute buffer descriptor status word */ status = sg->size & GMAC_RX_STATUS_LENGTH_MASK; if (i == (sgl->size - 1)) { status |= GMAC_TX_STATUS_LASTBUF; if (q->tx_callbacks) q->tx_callbacks[idx] = callback; } if (idx == (q->tx_size - 1)) { status |= GMAC_TX_STATUS_WRAP; } /* Update buffer descriptor status word: clear USED bit */ desc->status = status; DSB(); } /* Update TX ring buffer pointers */ q->tx_head = tx_head; /* Now start to transmit if it is not already done */ gmac_start_transmission(gmac); return GMACD_OK; }