41491457737166d691ccd3913256f77b0e090bde
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / trans / gio_uart.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * trans/gio_uart.c
6  * - GIO UART translation (presents "uart" type GIO drivers as serial ports)
7  */
8 #define DEBUG   1
9 #include <udi.h>
10 //#include <udi_gio.h>
11 #include <acess.h>
12 #include <drv_pty.h>
13 #include <trans_uart.h>
14 #include <workqueue.h>
15
16 #define NUM_TX_CBS      1
17
18 typedef struct {
19         udi_init_context_t      init_context;
20         udi_cb_t        *active_cb;
21         tPTY    *PTYInstance;
22         tWorkqueue      CBWorkQueue;
23 } rdata_t;
24
25 enum {
26         ACESSUART_CB_BIND = 1,
27         ACESSUART_CB_XFER
28 };
29 enum {
30         ACESSUART_OPS_GIO = 1
31 };
32 enum {
33         ACESSUART_META_GIO = 1,
34 };
35
36 // === PROTOTYPES ===
37 void    acessuart_pty_output(void *Handle, size_t Length, const void *Data);
38
39 // === CODE ===
40 void acessuart_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
41 {
42         udi_cb_t        *gcb = UDI_GCB(cb);
43         rdata_t *rdata = gcb->context;
44         Workqueue_Init(&rdata->CBWorkQueue, "UDI UART TX", offsetof(udi_gio_xfer_cb_t, gcb.initiator_context));
45         udi_usage_res(cb);
46 }
47 void acessuart_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
48 {
49         UNIMPLEMENTED();
50 }
51 void acessuart_final_cleanup_req(udi_mgmt_cb_t *cb)
52 {
53         UNIMPLEMENTED();
54 }
55 // ----
56 void acessuart_channel_event_ind(udi_channel_event_cb_t *cb);
57 void acessuart_channel_event_ind__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_cb);
58 void acessuart_bind_ack(udi_gio_bind_cb_t *cb, udi_ubit32_t device_size_lo, udi_ubit32_t device_size_hi, udi_status_t status);
59
60 void acessuart_channel_event_ind(udi_channel_event_cb_t *cb)
61 {
62         udi_cb_t        *gcb = UDI_GCB(cb);
63         rdata_t *rdata = gcb->context;
64         ASSERT(rdata);
65         switch(cb->event)
66         {
67         case UDI_CHANNEL_CLOSED:
68                 break;
69         case UDI_CHANNEL_BOUND: {
70                 rdata->active_cb = gcb;
71                 // 
72                 udi_cb_alloc_batch(acessuart_channel_event_ind__tx_cbs_allocated, cb->params.parent_bound.bind_cb,
73                         ACESSUART_CB_XFER, NUM_TX_CBS, FALSE, 0, UDI_NULL_BUF_PATH);
74                 // V V V V
75                 break; }
76         }
77 }
78 void acessuart_channel_event_ind__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_cb)
79 {
80         rdata_t *rdata = gcb->context;
81         udi_gio_bind_cb_t       *cb = UDI_MCB(gcb, udi_gio_bind_cb_t);
82         ASSERT(rdata);
83
84         while( first_cb )
85         {
86                 udi_cb_t        *next = first_cb->initiator_context;
87                 first_cb->initiator_context = NULL;
88                 Workqueue_AddWork(&rdata->CBWorkQueue, first_cb);
89                 first_cb = next;
90         }
91
92         udi_gio_bind_req(cb);
93         // continued in acessuart_bind_ack
94 }
95 void acessuart_bind_ack(udi_gio_bind_cb_t *cb, udi_ubit32_t device_size_lo, udi_ubit32_t device_size_hi, udi_status_t status)
96 {
97         udi_cb_t        *gcb = UDI_GCB(cb);
98         rdata_t *rdata = gcb->context;
99         udi_channel_event_cb_t  *channel_cb = UDI_MCB(rdata->active_cb, udi_channel_event_cb_t);
100         
101         if( device_size_lo != 0 || device_size_hi != 0 ) {
102                 // Oops... binding failed. UARTS should not have a size
103                 udi_channel_event_complete( channel_cb, UDI_STAT_NOT_UNDERSTOOD);
104                 return ;
105         }
106         
107         // bound, create PTY instance
108         rdata->PTYInstance = PTY_Create("serial#", rdata, acessuart_pty_output, NULL, NULL);
109         if( !rdata->PTYInstance ) {
110                 udi_channel_event_complete(channel_cb, UDI_STAT_RESOURCE_UNAVAIL);
111                 return ;
112         }
113         
114         udi_channel_event_complete(channel_cb, UDI_OK);
115 }
116 void acessuart_unbind_ack(udi_gio_bind_cb_t *cb)
117 {
118         UNIMPLEMENTED();
119 }
120 void acessuart_xfer_ack(udi_gio_xfer_cb_t *cb)
121 {
122         udi_cb_t        *gcb = UDI_GCB(cb);
123         rdata_t *rdata = gcb->context;
124         if( cb->op == UDI_GIO_OP_WRITE ) {
125                 // Write, no action required except returning the CB to the pool
126                 udi_buf_free(cb->data_buf);
127                 Workqueue_AddWork(&rdata->CBWorkQueue, cb);
128                 return ;
129         }
130         else if( cb->op == UDI_GIO_OP_READ ) {
131                 // Send data to PTY
132                 UNIMPLEMENTED();
133         }
134         else {
135                 // Well, that was unexpected
136         }
137 }
138 void acessuart_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status)
139 {
140         UNIMPLEMENTED();
141 }
142 void acessuart_event_ind(udi_gio_event_cb_t *cb)
143 {
144         // grab the input CB, and request data
145         UNIMPLEMENTED();
146 }
147
148
149 void acessuart_pty_output(void *Handle, size_t Length, const void *Data);
150 void acessuart_pty_output__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer);
151
152 void acessuart_pty_output(void *Handle, size_t Length, const void *Data)
153 {
154         LOG("Output '%.*s'", Length, Data);
155         
156         rdata_t *rdata = Handle;
157         udi_gio_xfer_cb_t       *cb = Workqueue_GetWork(&rdata->CBWorkQueue);
158         udi_cb_t        *gcb = UDI_GCB(cb);
159         
160         UDI_BUF_ALLOC(acessuart_pty_output__buf_allocated, gcb, Data, Length, UDI_NULL_BUF_PATH);
161         // don't bother waiting for tx to complete, workqueue will block when everything is in use
162 }
163 void acessuart_pty_output__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer)
164 {
165         //rdata_t       *rdata = gcb->context;
166         LOG("buffer = %p\n", buffer);
167         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
168
169         cb->op = UDI_GIO_OP_WRITE;
170         cb->tr_params = NULL;
171         cb->data_buf = buffer;  
172
173         udi_gio_xfer_req(cb);
174 }
175
176
177 // --------------------------------------------------------------------
178 udi_mgmt_ops_t  acessuart_mgmt_ops = {
179         acessuart_usage_ind,
180         udi_enumerate_no_children,
181         acessuart_devmgmt_req,
182         acessuart_final_cleanup_req
183 };
184 udi_ubit8_t     acessuart_mgmt_ops_flags[4] = {0,0,0,0};
185
186 udi_primary_init_t      acessuart_pri_init = {
187         .mgmt_ops = &acessuart_mgmt_ops,
188         .mgmt_op_flags = acessuart_mgmt_ops_flags,
189         .mgmt_scratch_requirement = 0,
190         .enumeration_attr_list_length = 0,
191         .rdata_size = sizeof(rdata_t),
192         .child_data_size = 0,
193         .per_parent_paths = 0
194 };
195
196 udi_gio_client_ops_t    acessuart_gio_ops = {
197         acessuart_channel_event_ind,
198         acessuart_bind_ack,
199         acessuart_unbind_ack,
200         acessuart_xfer_ack,
201         acessuart_xfer_nak,
202         acessuart_event_ind
203 };
204 udi_ubit8_t     acessuart_gio_op_flags[7] = {0};
205
206 udi_ops_init_t  acessuart_ops_list[] = {
207         {
208                 ACESSUART_OPS_GIO, ACESSUART_META_GIO, UDI_GIO_CLIENT_OPS_NUM,
209                 0, (udi_ops_vector_t*)&acessuart_gio_ops, acessuart_gio_op_flags
210         },
211         {0}
212 };
213 udi_cb_init_t   acessuart_cb_init_list[] = {
214         {ACESSUART_CB_BIND, ACESSUART_META_GIO, UDI_GIO_BIND_CB_NUM, 0, 0,NULL},
215         {ACESSUART_CB_XFER, ACESSUART_META_GIO, UDI_GIO_XFER_CB_NUM, 0, 0,NULL},
216         {0}
217 };
218 const udi_init_t        acessuart_init = {
219         .primary_init_info = &acessuart_pri_init,
220         .ops_init_list = acessuart_ops_list,
221         .cb_init_list = acessuart_cb_init_list,
222 };
223 const char      acessuart_udiprops[] = 
224         "properties_version 0x101\0"
225         "message 1 Acess2 Kernel\0"
226         "message 2 John Hodge ([email protected])\0"
227         "message 3 Acess2 UART\0"
228         "supplier 1\0"
229         "contact 2\0"
230         "name 3\0"
231         "module acess_uart\0"
232         "shortname acessuart\0"
233         "requires udi 0x101\0"
234         "requires udi_gio 0x101\0"
235         "meta 1 udi_gio\0"
236         "message 101 UART\0"
237         "device 101 1 gio_type string uart\0"
238         "parent_bind_ops 1 0 1 1\0"
239         "\0";
240 size_t  acessuart_udiprops_size = sizeof(acessuart_udiprops);

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