From ad8ed64b7916f20a97d573b29642f567f9e43331 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 1 Feb 2014 16:16:12 +0800 Subject: [PATCH] UDI/Drivers - Adding 16550 UART driver --- UDI/drivers/uart_16c550/uart16c550.c | 256 ++++++++++++++++++++ UDI/drivers/uart_16c550/uart16c550_common.h | 64 +++++ UDI/drivers/uart_16c550/uart16c550_pio.h | 37 +++ UDI/drivers/uart_16c550/udiprops.txt | 39 +++ 4 files changed, 396 insertions(+) create mode 100644 UDI/drivers/uart_16c550/uart16c550.c create mode 100644 UDI/drivers/uart_16c550/uart16c550_common.h create mode 100644 UDI/drivers/uart_16c550/uart16c550_pio.h create mode 100644 UDI/drivers/uart_16c550/udiprops.txt diff --git a/UDI/drivers/uart_16c550/uart16c550.c b/UDI/drivers/uart_16c550/uart16c550.c new file mode 100644 index 00000000..d4637ffa --- /dev/null +++ b/UDI/drivers/uart_16c550/uart16c550.c @@ -0,0 +1,256 @@ +/* + * UDI Ne2000 NIC Driver + * By John Hodge (thePowersGang) + * + * uart16c550.c + * - UDI initialisation + */ +#include +#include +#include "uart16c550_common.h" + + +#include "uart16c550_pio.h" + +#define __EXPJOIN(a,b) a##b +#define _EXPJOIN(a,b) __EXPJOIN(a,b) +#define CONTIN(suffix, call, params, args...) extern void _EXPJOIN(suffix##__,__LINE__) params;\ + call(_EXPJOIN(suffix##__,__LINE__), gcb,## args); } \ + void _EXPJOIN(suffix##__,__LINE__) params { \ + rdata_t *rdata = gcb->context; + +// --- Management Metalang +void uart_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) +{ + rdata_t *rdata = UDI_GCB(cb)->context; + + // TODO: Set up region data + + udi_usage_res(cb); +} + +void uart_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) +{ + rdata_t *rdata = UDI_GCB(cb)->context; + udi_instance_attr_list_t *attr_list = cb->attr_list; + + switch(enumeration_level) + { + case UDI_ENUMERATE_START: + case UDI_ENUMERATE_START_RESCAN: + DPT_SET_ATTR_STRING(attr_list, "if_num", "uart", 4); + attr_list ++; + cb->attr_valid_length = attr_list - cb->attr_list; + udi_enumerate_ack(cb, UDI_ENUMERATE_OK, UART_OPS_GIO); + break; + case UDI_ENUMERATE_NEXT: + udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0); + break; + } +} +void uart_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID) +{ +} +void uart_final_cleanup_req(udi_mgmt_cb_t *cb) +{ +} +// --- +void uart_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb); +void uart_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status); +void uart_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle); +void uart_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel); +void uart_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb); + +void uart_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + switch(cb->event) + { + case UDI_CHANNEL_CLOSED: + break; + case UDI_CHANNEL_BOUND: { + rdata->active_cb = gcb; + udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t); + udi_bus_bind_req( bus_bind_cb ); + // continue at uart_bus_dev_bus_bind_ack + return; } + } +} +void uart_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, + udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + // Set up PIO handles + rdata->init.pio_index = -1; + uart_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE); + // V V V V +} +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 ) + { + rdata->pio_handles[rdata->init.pio_index] = new_pio_handle; + } + + rdata->init.pio_index ++; + if( rdata->init.pio_index < N_PIO ) + { + udi_pio_map(uart_bus_dev_bind__pio_map, gcb, + UDI_PCI_BAR_0, 0, 0x8, // TODO: Use system bus index and offset + uart_pio_ops[rdata->init.pio_index].trans_list, + uart_pio_ops[rdata->init.pio_index].list_length, + UDI_PIO_LITTLE_ENDIAN, 0, 0 + ); + return ; + } + + CONTIN( uart_bus_dev_bind, udi_channel_spawn, (udi_cb_t *gcb, udi_channel_t new_channel), gcb->channel, 0, UART_OPS_IRQ, rdata) +// udi_channel_spawn(uart_bus_dev_bind__intr_chanel, gcb, gcb->channel, 0, UART_OPS_IRQ, rdata); +//} +//void uart_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel) +//{ +// rdata_t *rdata = gcb->context; + + rdata->interrupt_channel = new_channel; + + CONTIN( uart_bus_dev_bind, udi_cb_alloc, (udi_cb_t *gcb, udi_cb_t *new_cb), UART_CB_INTR, gcb->channel) +// udi_cb_alloc(uart_bus_dev_bind__intr_attach, gcb, NE2K_CB_INTR, gcb->channel); +// // V V V V +//} +//void uart_bus_dev_bind__intr_attach(udi_cb_t *gcb, udi_cb_t *new_cb) +//{ +// rdata_t *rdata = gcb->context; + if( !new_cb ) + { + // Oh... + udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), + UDI_STAT_RESOURCE_UNAVAIL ); + return ; + } + 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]; + udi_intr_attach_req(intr_cb); + // continued in uart_bus_dev_intr_attach_ack +} +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) +{ +} +void uart_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb) +{ +} +// --- +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 ) + { + //ne2k_intr__rx_ok( UDI_GCB(cb) ); + } + // TODO: TX IRQs + 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_unbind_req(udi_gio_bind_cb_t *cb) +{ +} +void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb) +{ +} +void uart_gio_prov_event_res(udi_gio_event_cb_t *cb) +{ +} + +// ==================================================================== +// - Management ops +udi_mgmt_ops_t uart_mgmt_ops = { + uart_usage_ind, + uart_enumerate_req, + uart_devmgmt_req, + uart_final_cleanup_req +}; +udi_ubit8_t uart_mgmt_op_flags[4] = {0,0,0,0}; +// - Bus Ops +udi_bus_device_ops_t uart_bus_dev_ops = { + uart_bus_dev_channel_event_ind, + uart_bus_dev_bus_bind_ack, + uart_bus_dev_bus_unbind_ack, + uart_bus_dev_intr_attach_ack, + uart_bus_dev_intr_detach_ack +}; +udi_ubit8_t uart_bus_dev_ops_flags[5] = {0}; +// - IRQ Ops +udi_intr_handler_ops_t uart_bus_irq_ops = { + uart_bus_irq_channel_event_ind, + uart_bus_irq_intr_event_ind +}; +udi_ubit8_t uart_bus_irq_ops_flags[2] = {0}; +// - GIO provider ops +udi_gio_provider_ops_t uart_gio_prov_ops = { + uart_gio_prov_channel_event_ind, + uart_gio_prov_bind_req, + uart_gio_prov_unbind_req, + uart_gio_prov_xfer_req, + uart_gio_prov_event_res +}; +udi_ubit8_t uart_gio_prov_ops_flags[5] = {0}; +// -- +udi_primary_init_t uart_pri_init = { + .mgmt_ops = &uart_mgmt_ops, + .mgmt_op_flags = uart_mgmt_op_flags, + .mgmt_scratch_requirement = 0, + .enumeration_attr_list_length = 4, + .rdata_size = sizeof(rdata_t), + .child_data_size = 0, + .per_parent_paths = 0 +}; +udi_ops_init_t uart_ops_list[] = { + { + UART_OPS_DEV, UART_META_BUS, UDI_BUS_DEVICE_OPS_NUM, + 0, + (udi_ops_vector_t*)&uart_bus_dev_ops, + uart_bus_dev_ops_flags + }, + { + UART_OPS_IRQ, UART_META_BUS, UDI_BUS_INTR_HANDLER_OPS_NUM, + 0, + (udi_ops_vector_t*)&uart_bus_irq_ops, + uart_bus_irq_ops_flags + }, + { + UART_OPS_GIO, UART_META_GIO, UDI_GIO_PROVIDER_OPS_NUM, + 0, + (udi_ops_vector_t*)&uart_gio_prov_ops, + uart_gio_prov_ops_flags + }, + {0} +}; +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}, + {0} +}; +const udi_init_t udi_init_info = { + .primary_init_info = &uart_pri_init, + .ops_init_list = uart_ops_list, + .cb_init_list = uart_cb_init_list, +}; diff --git a/UDI/drivers/uart_16c550/uart16c550_common.h b/UDI/drivers/uart_16c550/uart16c550_common.h new file mode 100644 index 00000000..6f051e29 --- /dev/null +++ b/UDI/drivers/uart_16c550/uart16c550_common.h @@ -0,0 +1,64 @@ +#ifndef _UART16C550_COMMON_H_ +#define _UART16C550_COMMON_H_ + +enum { + UART_OPS_DEV = 1, + UART_OPS_IRQ, + UART_OPS_GIO, +}; + +enum { + UART_CB_BUS_BIND = 1, + UART_CB_INTR, + UART_CB_INTR_EVENT, +}; + +enum { + PIO_RESET, + PIO_TX, + PIO_RX, + N_PIO +}; + +typedef struct { + udi_cb_t *active_cb; + struct { + udi_index_t pio_index; + } init; + + udi_pio_handle_t pio_handles[N_PIO]; + udi_channel_t interrupt_channel; +} rdata_t; + +// === MACROS === +/* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */ +#define DPT_SET_ATTR_BOOLEAN(attr, name, val) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_BOOLEAN; \ + (attr)->attr_length = sizeof(udi_boolean_t); \ + UDI_ATTR32_SET((attr)->attr_value, (val)) + +#define DPT_SET_ATTR32(attr, name, val) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_UBIT32; \ + (attr)->attr_length = sizeof(udi_ubit32_t); \ + UDI_ATTR32_SET((attr)->attr_value, (val)) + +#define DPT_SET_ATTR_ARRAY8(attr, name, val, len) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_ARRAY8; \ + (attr)->attr_length = (len); \ + udi_memcpy((attr)->attr_value, (val), (len)) + +#define DPT_SET_ATTR_STRING(attr, name, val, len) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_STRING; \ + (attr)->attr_length = (len); \ + udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len)) +#define NE2K_SET_ATTR_STRFMT(attr, name, maxlen, fmt, v...) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_STRING; \ + (attr)->attr_length = udi_snprintf((char *)(attr)->attr_value, (maxlen), (fmt) ,## v ) + + +#endif diff --git a/UDI/drivers/uart_16c550/uart16c550_pio.h b/UDI/drivers/uart_16c550/uart16c550_pio.h new file mode 100644 index 00000000..7a4e2276 --- /dev/null +++ b/UDI/drivers/uart_16c550/uart16c550_pio.h @@ -0,0 +1,37 @@ +#define PIO_op_RI(op, reg, sz, val) {UDI_PIO_##op+UDI_PIO_DIRECT+UDI_PIO_##reg, UDI_PIO_##sz##BYTE, val} +#define PIO_MOV_RI1(reg, val) PIO_op_RI(LOAD_IMM, reg, 2, val) +#define PIO_OUT_RI1(reg, ofs) PIO_op_RI(OUT, reg, 1, ofs) +#define PIO_IN_RI1(reg, ofs) PIO_op_RI(IN, reg, 1, ofs) + +// +// Reset +// +udi_pio_trans_t uart_pio_reset[] = { + {UDI_PIO_END, UDI_PIO_2BYTE, 0} +}; +// +// Transmit +// +udi_pio_trans_t uart_pio_tx[] = { + {UDI_PIO_END, UDI_PIO_2BYTE, 0} +}; +// +// Recieve (interrupt) +// +udi_pio_trans_t uart_pio_rx[] = { + {UDI_PIO_END, UDI_PIO_2BYTE, 0} +}; + +#define ARRAY_SIZEOF(arr) (sizeof(arr)/sizeof(arr[0])) + +struct { + udi_pio_trans_t *trans_list; + udi_ubit16_t list_length; + udi_ubit16_t pio_attributes; +} uart_pio_ops[] = { + [PIO_RESET] = {uart_pio_reset, ARRAY_SIZEOF(uart_pio_reset), 0}, + [PIO_TX] = {uart_pio_tx, ARRAY_SIZEOF(uart_pio_tx), 0}, + [PIO_RX] = {uart_pio_rx, ARRAY_SIZEOF(uart_pio_rx), 0}, +}; +//const int UART_NUM_PIO_OPS = ARRAY_SIZEOF(uart_pio_ops); + diff --git a/UDI/drivers/uart_16c550/udiprops.txt b/UDI/drivers/uart_16c550/udiprops.txt new file mode 100644 index 00000000..714977c0 --- /dev/null +++ b/UDI/drivers/uart_16c550/udiprops.txt @@ -0,0 +1,39 @@ +properties_version 0x101 +supplier 1 +message 1 John Hodge (thePowersGang) +contact 2 +message 2 udi@mutabah.net +name 3 +message 3 16c550 UART Driver +shortname uart16c550 +release 5 1.0 +message 5 uart16c550 + +requires udi 0x101 +requires udi_physio 0x101 +requires udi_bridge 0x101 +requires udi_gio 0x101 + +meta 1 udi_bridge +meta 2 udi_gio + +parent_bind_ops 1 0 1 1 # bridge metalang, rgn 0, ops 1, cb 1 +child_bind_ops 2 0 2 # GIO metalang, rgn 0, ops 2 + +# PC Serial Port +device 101 1 bus_type string system sysbus_io_addr_lo ubit32 0x3F8 sysbus_io_size ubit32 16 sysbus_intr0 ubit32 4 +message 101 PC Serial (COM1) +device 102 1 bus_type string system sysbus_io_addr_lo ubit32 0x2F8 sysbus_io_size ubit32 16 sysbus_intr0 ubit32 3 +message 102 PC Serial (COM2) + +# PCI 16550 compatibles +device 103 1 bus_type string pci pci_baseclass ubit32 0x07 pci_sub_class ubit32 0x00 pci_prog_if ubit32 0x02 +message 103 PCI 16550 Compatible + +module uart16c550 +region 0 + +# Source-only udiprops +compile_options -DUART_META_BUS=1 -DUART_META_GIO=2 +source_files uart16c550.c + -- 2.20.1