// Read file descriptor to buffer BSP_DECLARE(ssize_t) bsp_buffer_io_read(BSP_BUFFER *b, int fd, size_t len) { if (!b || !fd || !len) { return 0; } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } // Try read ssize_t ret = read(fd, B_DATA(b) + B_LEN(b), len); if (ret > 0) { bsp_trace_message(BSP_TRACE_DEBUG, _tag_, "Read %d bytes from fd %d to buffer", (int) ret, fd); B_LEN(b) += ret; } return ret; }
// Append data to buffer BSP_DECLARE(size_t) bsp_buffer_append(BSP_BUFFER *b, const char *data, ssize_t len) { if (!b || !data || B_ISCONST(b)) { return 0; } if (len < 0) { len = strnlen(data, _BSP_MAX_UNSIZED_STRLEN); } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { // Space not enough, realloc buffer if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } memcpy(B_DATA(b) + B_LEN(b), data, len); B_LEN(b) = need; return len; }
// Cancellation a buffer BSP_DECLARE(void) bsp_del_buffer(BSP_BUFFER *b) { if (b) { if (!B_ISCONST(b)) { if (_BSP_BUFFER_HIGHWATER < B_SIZE(b)) { // Buffer too big, just clean bsp_free(B_DATA(b)); B_DATA(b) = NULL; B_SIZE(b) = 0; B_LEN(b) = 0; B_NOW(b) = 0; } if (_BSP_BUFFER_UNSATURATION < (B_SIZE(b) - B_LEN(b))) { _shrink_buffer(b); } } else { B_DATA(b) = NULL; B_SIZE(b) = 0; } bsp_mempool_free(mp_buffer, (void *) b); } return; }
// Read all data from file descriptor to buffer BSP_DECLARE(ssize_t) bsp_buffer_io_read_all(BSP_BUFFER *b, int fd) { if (!b || !fd) { return 0; } ssize_t len = 0, tlen = 0; while (BSP_TRUE) { size_t need = B_LEN(b) + _BSP_FD_READ_ONCE; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error break; } } len = read(fd, B_DATA(b) + B_LEN(b), _BSP_FD_READ_ONCE); if (len < 0) { if (EINTR == errno || EWOULDBLOCK == errno || EAGAIN == errno) { // Break break; } } else if (0 == len) { // TCP FIN tlen = 0; break; } else { // Data already in buffer -_- tlen += len; B_LEN(b) += len; bsp_trace_message(BSP_TRACE_DEBUG, _tag_, "Read %d bytes from fd %d to buffer", (int) len, fd); if (len < _BSP_FD_READ_ONCE) { // All gone break; } } } return tlen; }
int ct_send_packet (ct_chan_t *c, unsigned char *data, int len, void *attachment) { int dsr, ne; if (len > DMABUFSZ) return -2; /* Is it really free? */ ne = (c->te+1) % NBUF; if (ne == c->tn) return -1; /* Set up the tx descriptor. */ B_LEN (c->tdesc[c->te]) = len; B_STATUS (c->tdesc[c->te]) = FST_EOM; c->attach[c->te] = attachment; if (c->tbuf[c->te] != data) memcpy (c->tbuf[c->te], data, len); /* Start the transmitter. */ c->te = ne; outw (c->TX.EDA, (unsigned short) c->tdphys[ne]); dsr = inb (c->TX.DSR); if (! (dsr & DSR_DMA_ENABLE)) outb (c->TX.DSR, DSR_DMA_ENABLE); return 0; }
// Set const data to en empty buffer BSP_DECLARE(size_t) bsp_buffer_set_const(BSP_BUFFER *b, const char *data, ssize_t len) { if (!b || !data || B_ISCONST(b)) { return 0; } if (len < 0) { len = strnlen(data, _BSP_MAX_UNSIZED_STRLEN); } if (B_DATA(b)) { bsp_free(B_DATA(b)); } B_DATA(b) = (char *) data; B_SIZE(b) = 0; B_LEN(b) = len; // Set to const b->is_const = BSP_TRUE; return len; }
BSP_PRIVATE(int) _shrink_buffer(BSP_BUFFER *b) { if (b) { size_t new_size = 2 << (int) log2(B_LEN(b)); if (new_size < B_SIZE(b)) { char *new_data = bsp_realloc(B_DATA(b), new_size); if (new_data) { B_DATA(b) = new_data; B_SIZE(b) = new_size; return BSP_RTN_SUCCESS; } return BSP_RTN_ERR_MEMORY; } else { // May not shrink return BSP_RTN_SUCCESS; } } return BSP_RTN_ERR_GENERAL; }
// New buffer BSP_DECLARE(BSP_BUFFER *) bsp_new_buffer() { BSP_BUFFER *b = bsp_mempool_alloc(mp_buffer); if (b) { B_LEN(b) = 0; B_NOW(b) = 0; b->is_const = BSP_FALSE; } return b; }
// Fill seriate character to buffer BSP_DECLARE(size_t) bsp_buffer_fill(BSP_BUFFER *b, int code, size_t len) { if (!b || !len) { return 0; } size_t need = B_LEN(b) + len; if (need > B_SIZE(b)) { if (BSP_RTN_SUCCESS != _enlarge_buffer(b, need)) { // Enlarge error return 0; } } memset(B_DATA(b) + B_LEN(b), code, len); B_LEN(b) = need; return len; }
// Clear buffer data BSP_DECLARE(void) bsp_clear_buffer(BSP_BUFFER *b) { if (b) { B_LEN(b) = 0; B_NOW(b) = 0; if (B_ISCONST(b)) { b->is_const = BSP_FALSE; b->data = NULL; } } return; }
static void ct_hdlc_interrupt (ct_chan_t *c, int imvr) { int i, dsr, st1, st2, cda; switch (imvr & IMVR_VECT_MASK) { case IMVR_RX_DMOK: /* receive DMA normal end */ dsr = inb (c->RX.DSR); cda = inw (c->RX.CDA); for (i=0; i<NBUF; ++i) if (cda == (unsigned short) c->rdphys[i]) break; if (i >= NBUF) i = c->rn; /* cannot happen */ while (c->rn != i) { int cst = B_STATUS (c->rdesc[c->rn]); if (cst == FST_EOM) { /* process data */ if (c->call_on_rx) c->call_on_rx (c, c->rbuf[c->rn], B_LEN(c->rdesc[c->rn])); ++c->ipkts; c->ibytes += B_LEN(c->rdesc[c->rn]); } else if (cst & ST2_OVRN) { /* Receive overrun error */ if (c->call_on_err) c->call_on_err (c, CT_OVERRUN); ++c->ierrs; } else if (cst & (ST2_HDLC_RBIT | ST2_HDLC_ABT | ST2_HDLC_SHRT)) { /* Receive frame error */ if (c->call_on_err) c->call_on_err (c, CT_FRAME); ++c->ierrs; } else if ((cst & ST2_HDLC_EOM) && (cst & ST2_HDLC_CRCE)) { /* Receive CRC error */ if (c->call_on_err) c->call_on_err (c, CT_CRC); ++c->ierrs; } else if (! (cst & ST2_HDLC_EOM)) { /* Frame dose not fit in the buffer.*/ if (c->call_on_err) c->call_on_err (c, CT_OVERFLOW); ++c->ierrs; } B_NEXT (c->rdesc[c->rn]) = c->rdphys[(c->rn+1) % NBUF] & 0xffff; B_PTR (c->rdesc[c->rn]) = c->rphys[c->rn]; B_LEN (c->rdesc[c->rn]) = DMABUFSZ; B_STATUS (c->rdesc[c->rn]) = 0; c->rn = (c->rn + 1) % NBUF; } outw (c->RX.EDA, (unsigned short) c->rdphys[(i+NBUF-1)%NBUF]); /* Clear DMA interrupt. */ if (inb (c->RX.DSR) & DSR_DMA_ENABLE) { outb (c->RX.DSR, dsr); } else { outb (c->RX.DSR, (dsr & 0xfc) | DSR_DMA_ENABLE); } ++c->rintr; break; case IMVR_RX_INT: /* receive status */ st1 = inb (c->ST1); st2 = inb (c->ST2); if (st1 & ST1_CDCD){ if (c->call_on_msig) c->call_on_msig (c); ++c->mintr; } /* Clear interrupt. */ outb (c->ST1, st1); outb (c->ST2, st2); ++c->rintr; break; case IMVR_RX_DMERR: /* receive DMA error */ dsr = inb (c->RX.DSR); if (dsr & (DSR_CHAIN_BOF | DSR_CHAIN_COF)) { if (c->call_on_err) c->call_on_err (c, CT_OVERFLOW); ++c->ierrs; for (i=0; i<NBUF; ++i) { B_LEN (c->rdesc[i]) = DMABUFSZ; B_STATUS (c->rdesc[i]) = 0; } ct_start_receiver (c, 1, c->rphys[0], DMABUFSZ, c->rdphys[0], c->rdphys[NBUF-1]); c->rn = 0; } /* Clear DMA interrupt. */ outb (c->RX.DSR, dsr); ++c->rintr; break; case IMVR_TX_DMOK: /* transmit DMA normal end */ case IMVR_TX_DMERR: /* transmit DMA error */ dsr = inb (c->TX.DSR); cda = inw (c->TX.CDA); for (i=0; i<NBUF && cda != (unsigned short)c->tdphys[i]; ++i) continue; if (i >= NBUF) i = 1; /* cannot happen */ if (dsr & DSR_CHAIN_COF) { if (c->call_on_err) c->call_on_err (c, CT_UNDERRUN); ++c->oerrs; } while (c->tn != i) { if (c->call_on_tx) c->call_on_tx (c, c->attach[c->tn], B_LEN(c->tdesc[c->tn])); ++c->opkts; c->obytes += B_LEN(c->tdesc[c->tn]); c->tn = (c->tn + 1) % NBUF; /* Clear DMA interrupt. */ outb (c->TX.DSR, DSR_CHAIN_EOM | DSR_DMA_CONTINUE); } outb (c->TX.DSR, dsr & ~DSR_CHAIN_EOM); ++c->tintr; break; case IMVR_TX_INT: /* transmit error, HDLC only */ st1 = inb (c->ST1); if (st1 & ST1_HDLC_UDRN) { if (c->call_on_err) c->call_on_err (c, CT_UNDERRUN); ++c->oerrs; } outb (c->ST1, st1); ++c->tintr; break; default: /* Unknown interrupt - cannot happen. */ break; } }
/* * Start HDLC channel. */ void ct_start_chan (ct_chan_t *c, ct_buf_t *cb, unsigned long phys) { int i, ier0; unsigned long bound; if (cb) { /* Set up descriptors, align to 64k boundary. * If 64k boundary is inside buffers * buffers will begin on this boundary * (there were allocated additional space for this) */ c->tdesc = cb->descbuf; c->tdphys[0] = phys + ((char*)c->tdesc - (char*)cb); bound = ((c->tdphys[0] + 0xffff) & ~(0xffffUL)); if (bound < c->tdphys[0] + 2*NBUF*sizeof(ct_desc_t)) { c->tdesc = (ct_desc_t*) ((char*) c->tdesc + (bound - c->tdphys[0])); c->tdphys[0] = bound; } c->rdesc = c->tdesc + NBUF; /* Set buffers. */ for (i=0; i<NBUF; ++i) { c->rbuf[i] = cb->rbuffer[i]; c->tbuf[i] = cb->tbuffer[i]; } /* Set buffer physical addresses */ for (i=0; i<NBUF; ++i) { c->rphys[i] = phys + ((char*)c->rbuf[i] - (char*)cb); c->tphys[i] = phys + ((char*)c->tbuf[i] - (char*)cb); c->rdphys[i] = phys + ((char*)(c->rdesc+i) - (char*)cb); c->tdphys[i] = phys + ((char*)(c->tdesc+i) - (char*)cb); } } /* Set up block chains. */ /* receive buffers */ for (i=0; i<NBUF; ++i) { B_NEXT (c->rdesc[i]) = c->rdphys[(i+1) % NBUF] & 0xffff; B_PTR (c->rdesc[i]) = c->rphys[i]; B_LEN (c->rdesc[i]) = DMABUFSZ; B_STATUS (c->rdesc[i]) = 0; } /* transmit buffers */ for (i=0; i<NBUF; ++i) { B_NEXT (c->tdesc[i]) = c->tdphys[(i+1) % NBUF] & 0xffff; B_PTR (c->tdesc[i]) = c->tphys[i]; B_LEN (c->tdesc[i]) = DMABUFSZ; B_STATUS (c->tdesc[i]) = FST_EOM; c->attach[i] = 0; } if (c->type & T_E1) { c->mode = M_E1; if (c->num && c->board->opt.cfg == CFG_B) c->mode = M_HDLC; } if (c->type & T_G703) { c->mode = M_G703; if (c->num && c->board->opt.cfg == CFG_B) c->mode = M_HDLC; } ct_update_chan (c); /* enable receiver */ c->rn = 0; ct_start_receiver (c, 1 , c->rphys[0], DMABUFSZ, c->rdphys[0], c->rdphys[NBUF-1]); outb (c->IE1, inb (c->IE1) | IE1_CDCDE); outb (c->IE0, inb (c->IE0) | IE0_RX_INTE); ier0 = inb (IER0(c->board->port)); ier0 |= c->num ? IER0_RX_INTE_1 : IER0_RX_INTE_0; outb (IER0(c->board->port), ier0); /* Enable transmitter */ c->tn = 0; c->te = 0; ct_start_transmitter (c, 1 , c->tphys[0], DMABUFSZ, c->tdphys[0], c->tdphys[0]); outb (c->TX.DIR, DIR_CHAIN_EOME | DIR_CHAIN_BOFE | DIR_CHAIN_COFE); /* Clear DTR and RTS */ ct_set_dtr (c, 0); ct_set_rts (c, 0); }