+ udi_cb_t *gcb = UDI_GCB(cb);
+ rdata_t *rdata = gcb->context;
+ switch(cb->op)
+ {
+ case UDI_GIO_OP_READ: {
+ udi_buf_copy_call_t *callback;
+ udi_size_t len;
+ // Read from local FIFO
+ if( rdata->rx_buffer->buf_size < cb->data_buf->buf_size ) {
+ len = rdata->rx_buffer->buf_size;
+ callback = uart_gio_read_complete_short;
+ }
+ else {
+ len = cb->data_buf->buf_size;
+ callback = uart_gio_read_complete;
+ }
+ DEBUG_OUT("Read %i/%i bytes", len, rdata->rx_buffer->buf_size);
+ // Replace entire destination buffer with `len` bytes from source
+ udi_buf_copy(callback, gcb,
+ rdata->rx_buffer, 0, len,
+ cb->data_buf, 0, cb->data_buf->buf_size,
+ UDI_NULL_BUF_PATH);
+ break; }
+ case UDI_GIO_OP_WRITE:
+ // Send to device
+ udi_pio_trans(uart_gio_write_complete, gcb,
+ rdata->pio_handles[PIO_TX], 0, cb->data_buf, &cb->data_buf->buf_size);
+ break;
+ default:
+ udi_gio_xfer_nak(cb, UDI_STAT_NOT_SUPPORTED);
+ break;
+ }
+}
+void uart_gio_read_complete_short(udi_cb_t *gcb, udi_buf_t *new_buf)
+{
+ rdata_t *rdata = gcb->context;
+ udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
+ cb->data_buf = new_buf;
+
+ // Delete read bytes from the RX buffer
+ CONTIN(uart_gio_read_complete, udi_buf_write,
+ (NULL, 0, rdata->rx_buffer, 0, cb->data_buf->buf_size, UDI_NULL_BUF_PATH),
+ (udi_buf_t *new_buf))
+ udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
+ rdata->rx_buffer = new_buf;
+
+ // Return underrun
+ udi_gio_xfer_nak(cb, UDI_STAT_DATA_UNDERRUN);
+}
+void uart_gio_read_complete(udi_cb_t *gcb, udi_buf_t *new_buf)
+{
+ rdata_t *rdata = gcb->context;
+ udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
+ cb->data_buf = new_buf;
+ // Delete read bytes from the RX buffer
+ CONTIN(uart_gio_read_complete, udi_buf_write,
+ (NULL, 0, rdata->rx_buffer, 0, cb->data_buf->buf_size, UDI_NULL_BUF_PATH),
+ (udi_buf_t *new_buf))
+ udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
+ rdata->rx_buffer = new_buf;
+
+ // Return completed
+ udi_gio_xfer_ack(cb);
+}
+void uart_gio_write_complete(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t res)
+{
+ udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
+ cb->data_buf = new_buf;
+ udi_gio_xfer_ack(cb);