u_int16_t fifo_data_put(struct fifo *fifo, u_int16_t len, u_int8_t *data) { if (len > fifo_available(fifo)) { len = fifo_available(fifo); fifo->irq |= FIFO_IRQ_OFLOW; } if (len + fifo->producer <= fifo->size) { /* easy case */ memcpy(&fifo->data[fifo->producer], data, len); fifo->producer += len; } else { /* difficult: wrap around */ u_int16_t chunk_len; chunk_len = fifo->size - fifo->producer; memcpy(&fifo->data[fifo->producer], data, chunk_len); memcpy(&fifo->data[0], data + chunk_len, len - chunk_len); fifo->producer = len - chunk_len; } fifo_check_water(fifo); return len; }
static void pci_uart_drain(int fd, enum ev_type ev, void *arg) { struct pci_uart_softc *sc; int ch; sc = arg; assert(fd == STDIN_FILENO); assert(ev == EVF_READ); /* * This routine is called in the context of the mevent thread * to take out the softc lock to protect against concurrent * access from a vCPU i/o exit */ pthread_mutex_lock(&sc->mtx); if ((sc->mcr & MCR_LOOPBACK) != 0) { (void) ttyread(); } else { while (fifo_available(&sc->rxfifo) && ((ch = ttyread()) != -1)) { fifo_putchar(&sc->rxfifo, ch); } pci_uart_toggle_intr(sc); } pthread_mutex_unlock(&sc->mtx); }
void fifo_check_water(struct fifo *fifo) { int avail = fifo_available(fifo); if (avail <= fifo->watermark) fifo->irq |= FIFO_IRQ_LO; else fifo->irq &= FIFO_IRQ_LO; if (fifo->size - avail >= fifo->watermark) fifo->irq |= FIFO_IRQ_HI; else fifo->irq &= FIFO_IRQ_HI; }
/** * Use interrupt to reload out buffer and continue transmission */ void SPI0_TWI0_Handler() { // event must be cleared SPI_EVENT_READY(my_spi) = 0; if (fifo_available(spi_buffer)) { // enqueue next byte for transmission char c; fifo_read(&buffer, &c); spi_write(my_spi, c); } else { // transmission sequence completed spi_disable(my_spi); } }
u_int16_t fifo_data_get(struct fifo *fifo, u_int16_t len, u_int8_t *data) { u_int16_t avail = fifo_available(fifo); if (avail < len) len = avail; if (fifo->producer > fifo->consumer) { /* easy case */ memcpy(data, &fifo->data[fifo->consumer], len); } else { /* difficult case: wrap */ u_int16_t chunk_len = fifo->size - fifo->consumer; memcpy(data, &fifo->data[fifo->consumer], chunk_len); memcpy(data+chunk_len, &fifo->data[0], len - chunk_len); } fifo_check_water(fifo); return len; }
int tty_read(struct inode* inode, void* ptr, off_t pos, size_t len) { if(unlikely(!inode || !ptr)) { errno = EINVAL; return -1; } if(unlikely(!inode->userdata)) { errno = EINVAL; return -1; } if(unlikely(!len)) return 0; struct tty_context* tio = (struct tty_context*) inode->userdata; uint8_t* buf = (uint8_t*) ptr; int p = 0; if(tio->pgrp != current_task->pgid) sys_exit((1 << 31) | W_STOPCODE(SIGTTIN)); int fd = sys_open(TTY_DEFAULT_INPUT_DEVICE, O_RDONLY, 0); if(fd < 0) { errno = EIO; return -1; } if(fifo_available(&tio->in)) { char tmp[BUFSIZ]; for(int j = 0; (j = fifo_read(&tio->in, tmp, sizeof(tmp))) > 0;) fifo_write(&tio->uin, tmp, j); } while(p < len) { uint8_t ch; if(fifo_available(&tio->uin)) fifo_read(&tio->uin, &ch, sizeof(ch)); else ch = process_keyboard(inode, tio, fd, &p); switch(ch) { case 0: continue; case '\b': case '\x7f': if(tio->ios.c_lflag & ICANON) { if(p > 0) { fifo_peek(&tio->in, 1); p--; if(tio->ios.c_lflag & ECHOE) ch = '\b'; else ch = '\x7f'; if(tio->ios.c_lflag & ECHO) tty_output_write(inode, &ch, 0, 1); } continue; } /* No processing */ ch = '\b'; break; default: break; } if(unlikely(ch < 32)) { for(int i = 0; i < NCCS; i++) { if(ch != tio->ios.c_cc[i]) continue; fifo_write(&tio->in, &ch, 1); p++; ch = 0; break; } if(unlikely(!ch)) continue; } if(!(tio->ios.c_iflag & IGNCR)) { if(ch == '\n') break; } char utf8[UTF8_MAX_LENGTH]; size_t utf8len = ucs2_to_utf8((int32_t) ch, utf8); fifo_write(&tio->in, utf8, utf8len); p += utf8len; if(tio->ios.c_lflag & ECHO) tty_output_write(inode, utf8, 0, utf8len); } if(p < len) { if(!(tio->ios.c_iflag & IGNCR)) { char ch = '\n'; fifo_write(&tio->in, &ch, 1); p++; if((tio->ios.c_lflag & ECHO) || (tio->ios.c_lflag & ICANON && tio->ios.c_lflag & ECHONL)) tty_output_write(inode, &ch, 0, 1); } } else p = len; if(fifo_available(&tio->in)) fifo_read(&tio->in, buf, p); sys_close(fd); return p; }