UDI/Drivers - Adding 16550 UART driver
authorJohn Hodge <[email protected]>
Sat, 1 Feb 2014 08:16:12 +0000 (16:16 +0800)
committerJohn Hodge <[email protected]>
Sat, 1 Feb 2014 08:16:12 +0000 (16:16 +0800)
UDI/drivers/uart_16c550/uart16c550.c [new file with mode: 0644]
UDI/drivers/uart_16c550/uart16c550_common.h [new file with mode: 0644]
UDI/drivers/uart_16c550/uart16c550_pio.h [new file with mode: 0644]
UDI/drivers/uart_16c550/udiprops.txt [new file with mode: 0644]

diff --git a/UDI/drivers/uart_16c550/uart16c550.c b/UDI/drivers/uart_16c550/uart16c550.c
new file mode 100644 (file)
index 0000000..d4637ff
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * UDI Ne2000 NIC Driver
+ * By John Hodge (thePowersGang)
+ *
+ * uart16c550.c
+ * - UDI initialisation 
+ */
+#include <udi.h>
+#include <udi_physio.h>
+#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 (file)
index 0000000..6f051e2
--- /dev/null
@@ -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 (file)
index 0000000..7a4e227
--- /dev/null
@@ -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 (file)
index 0000000..714977c
--- /dev/null
@@ -0,0 +1,39 @@
+properties_version 0x101
+supplier 1
+message 1 John Hodge (thePowersGang)
+contact 2
+message 2 [email protected]
+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
+

UCC git Repository :: git.ucc.asn.au