X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=UDI%2Fdrivers%2Fuart_16c550%2Fuart16c550.c;h=510bc47202e8b3a149a0e9d199d956fe45e407c4;hb=d7dcea0e5a8df0f479e99f168a10b9a9535c7ad6;hp=62b3de8077321f57aa14c10f43d2e18227246473;hpb=a32af8dfa5eb5184da620a4efd6484ef50f4a9de;p=tpg%2Facess2.git diff --git a/UDI/drivers/uart_16c550/uart16c550.c b/UDI/drivers/uart_16c550/uart16c550.c index 62b3de80..510bc472 100644 --- a/UDI/drivers/uart_16c550/uart16c550.c +++ b/UDI/drivers/uart_16c550/uart16c550.c @@ -5,13 +5,22 @@ * uart16c550.c * - UDI initialisation */ +#define UDI_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 #include #include +#include #include "uart16c550_common.h" - #include "uart16c550_pio.h" +#if 0 +# define DEBUG_OUT(fmt, v...) udi_debug_printf("%s: "fmt"\n", __func__ ,## v) +#else +# define DEBUG_OUT(...) do{}while(0) +#endif + #define __EXPJOIN(a,b) a##b #define _EXPJOIN(a,b) __EXPJOIN(a,b) #define _EXPLODE(params...) params @@ -25,6 +34,7 @@ void uart_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) { rdata_t *rdata = UDI_GCB(cb)->context; + //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, ); // TODO: Set up region data @@ -94,7 +104,7 @@ void uart_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, void uart_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) { rdata_t *rdata = gcb->context; - if( rdata->init.pio_index != -1 ) + if( rdata->init.pio_index != (udi_index_t)-1 ) { rdata->pio_handles[rdata->init.pio_index] = new_pio_handle; } @@ -118,7 +128,7 @@ void uart_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) rdata->interrupt_channel = new_channel; // Allocate an RX buffer - CONTIN( uart_bus_dev_bind, udi_buf_write, (NULL, RX_BUFFER_SIZE, NULL, 0, 0, UDI_NULL_BUF_PATH), + CONTIN( uart_bus_dev_bind, udi_buf_write, (NULL, 0, NULL, 0, 0, UDI_NULL_BUF_PATH), (udi_buf_t *new_buf)); if( !new_buf ) { @@ -141,8 +151,8 @@ void uart_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) } udi_intr_attach_cb_t *intr_cb = UDI_MCB(new_cb, udi_intr_attach_cb_t); intr_cb->interrupt_idx = 0; - intr_cb->min_event_pend = 2; - intr_cb->preprocessing_handle = rdata->pio_handles[PIO_RX]; + intr_cb->min_event_pend = 1; + intr_cb->preprocessing_handle = rdata->pio_handles[PIO_INTR]; // Attach interrupt udi_intr_attach_req(intr_cb); @@ -153,6 +163,27 @@ void uart_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb) } void uart_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status) { + udi_cb_t *gcb = UDI_GCB(intr_attach_cb); + rdata_t *rdata = gcb->context; + + // Allocate interrupt cbs + CONTIN(uart_bus_dev_intr_attach_ack, udi_cb_alloc_batch, + (UART_CB_INTR_EVENT, NUM_INTR_CBS, TRUE, INTR_CB_BUF_SIZE, UDI_NULL_BUF_PATH), + (udi_cb_t *first_new_cb)) + + while( first_new_cb ) + { + udi_intr_event_cb_t *cb = UDI_MCB(first_new_cb, udi_intr_event_cb_t); + first_new_cb = first_new_cb->initiator_context; + // - Set channel (udi_cb_alloc_batch sets the channel to gcb->channel) + cb->gcb.channel = rdata->interrupt_channel; + udi_intr_event_rdy(cb); + } + + udi_channel_event_cb_t *channel_cb = UDI_MCB(rdata->active_cb, udi_channel_event_cb_t); + + udi_channel_event_complete(channel_cb, UDI_OK); + // = = = = = } void uart_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb) { @@ -163,18 +194,59 @@ void uart_bus_irq_channel_event_ind(udi_channel_event_cb_t *cb) } void uart_bus_irq_intr_event_ind(udi_intr_event_cb_t *cb, udi_ubit8_t flags) { - udi_debug_printf("%s: flags=%x, intr_result=%x\n", __func__, flags, cb->intr_result); - if( cb->intr_result & 0x01 ) + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + DEBUG_OUT("flags=%x, intr_result=%x", flags, cb->intr_result); + if( cb->intr_result == 0 ) { - //ne2k_intr__rx_ok( UDI_GCB(cb) ); + // An IRQ from something other than RX + udi_intr_event_rdy(cb); + return ; } - // TODO: TX IRQs + + if( rdata->rx_buffer && rdata->rx_buffer->buf_size + cb->intr_result > MAX_RX_BUFFER_SIZE ) + { + // Drop, buffer is full + DEBUG_OUT("dropping %i bytes, full rx buffer", cb->intr_result); + udi_intr_event_rdy(cb); + return ; + } + + // Copy cb->intr_result bytes into the RX buffer + CONTIN(uart_bus_irq_intr_event_ind, udi_buf_copy, + (cb->event_buf, 0, cb->intr_result, + rdata->rx_buffer, rdata->rx_buffer->buf_size, 0, + UDI_NULL_BUF_PATH), + (udi_buf_t *new_buf)); + + udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t); + + rdata->rx_buffer = new_buf; + + DEBUG_OUT("copied %i bytes", cb->intr_result); + + // Emit a signal to GIO client + if( rdata->event_cb && !rdata->event_cb_used ) + { + rdata->event_pending = FALSE; + rdata->event_cb_used = TRUE; + udi_gio_event_ind(rdata->event_cb); + } + else + { + DEBUG_OUT("event_cb=%p, event_cb_used=%i - Queueing", + rdata->event_cb, rdata->event_cb_used); + rdata->event_pending = TRUE; + } + udi_intr_event_rdy(cb); } // --- void uart_gio_prov_channel_event_ind(udi_channel_event_cb_t *cb); void uart_gio_prov_bind_req(udi_gio_bind_cb_t *cb); void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb); +void uart_gio_read_complete_short(udi_cb_t *gcb, udi_buf_t *new_buf); void uart_gio_read_complete(udi_cb_t *gcb, udi_buf_t *new_buf); void uart_gio_write_complete(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t res); void uart_gio_prov_event_res(udi_gio_event_cb_t *cb); @@ -184,10 +256,33 @@ void uart_gio_prov_channel_event_ind(udi_channel_event_cb_t *cb) } void uart_gio_prov_bind_req(udi_gio_bind_cb_t *cb) { + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + // TODO: Should this device allow multiple children? + if( rdata->event_cb ) { + DEBUG_OUT("only one client allowed"); + udi_gio_bind_ack(cb, 0, 0, UDI_STAT_CANNOT_BIND_EXCL); + return; + } + + // Allocate the event CB + CONTIN( uart_gio_prov_bind_req, udi_cb_alloc, (UART_CB_GIO_EVENT, gcb->channel), + (udi_cb_t *new_cb)); + udi_gio_bind_cb_t *cb = UDI_MCB(gcb, udi_gio_bind_cb_t); + + rdata->event_cb = UDI_MCB(new_cb, udi_gio_event_cb_t); + rdata->event_cb_used = FALSE; + udi_gio_bind_ack(cb, 0, 0, UDI_OK); } void uart_gio_prov_unbind_req(udi_gio_bind_cb_t *cb) { + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + rdata->event_cb = NULL; + rdata->event_cb_used = FALSE; udi_gio_unbind_ack(cb); } void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb) @@ -196,21 +291,25 @@ void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb) rdata_t *rdata = gcb->context; switch(cb->op) { - case UDI_GIO_OP_READ: + case UDI_GIO_OP_READ: { + udi_buf_copy_call_t *callback; + udi_size_t len; // Read from local FIFO - if( rdata->rx_bytes < cb->data_buf->buf_size ) { - // Local FIFO was empty - udi_gio_xfer_nak(cb, UDI_STAT_DATA_UNDERRUN); + if( rdata->rx_buffer->buf_size < cb->data_buf->buf_size ) { + len = rdata->rx_buffer->buf_size; + callback = uart_gio_read_complete_short; } else { - udi_buf_copy(uart_gio_read_complete, gcb, - rdata->rx_buffer, - 0, cb->data_buf->buf_size, - cb->data_buf, - 0, cb->data_buf->buf_size, - UDI_NULL_BUF_PATH); + len = cb->data_buf->buf_size; + callback = uart_gio_read_complete; } - break; + 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, @@ -221,16 +320,35 @@ void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb) 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), + 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) @@ -241,6 +359,20 @@ void uart_gio_write_complete(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t sta } void uart_gio_prov_event_res(udi_gio_event_cb_t *cb) { + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + // If there was an event during dispatch, re-send + if( rdata->event_pending ) + { + udi_gio_event_ind(cb); + rdata->event_pending = FALSE; + } + // otherwise, clear 'Event CB used' flag + else + { + rdata->event_cb_used = FALSE; + } } // ==================================================================== @@ -311,6 +443,7 @@ udi_cb_init_t uart_cb_init_list[] = { {UART_CB_BUS_BIND, UART_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL}, {UART_CB_INTR, UART_META_BUS, UDI_BUS_INTR_ATTACH_CB_NUM, 0, 0,NULL}, {UART_CB_INTR_EVENT, UART_META_BUS, UDI_BUS_INTR_EVENT_CB_NUM, 0, 0,NULL}, + {UART_CB_GIO_EVENT, UART_META_GIO, UDI_GIO_EVENT_CB_NUM, 0, 0,NULL}, {0} }; const udi_init_t udi_init_info = {