UDI/uart_16c550 - Silence debug output
[tpg/acess2.git] / UDI / drivers / uart_16c550 / uart16c550.c
1 /*
2  * UDI Ne2000 NIC Driver
3  * By John Hodge (thePowersGang)
4  *
5  * uart16c550.c
6  * - UDI initialisation 
7  */
8 #include <udi.h>
9 #include <udi_physio.h>
10 #include "uart16c550_common.h"
11
12 #include "uart16c550_pio.h"
13
14 #if 0
15 # define DEBUG_OUT(fmt, v...)   udi_debug_printf("%s: "fmt"\n", __func__ ,## v) 
16 #else
17 # define DEBUG_OUT(...) do{}while(0)
18 #endif
19
20 #define __EXPJOIN(a,b)  a##b
21 #define _EXPJOIN(a,b)   __EXPJOIN(a,b)
22 #define _EXPLODE(params...)     params
23 #define _ADDGCB(params...)      (udi_cb_t *gcb, params)
24 #define CONTIN(suffix, call, args, params)      extern void _EXPJOIN(suffix##__,__LINE__) _ADDGCB params;\
25         call( _EXPJOIN(suffix##__,__LINE__), gcb, _EXPLODE args); } \
26         void _EXPJOIN(suffix##__,__LINE__) _ADDGCB params { \
27         rdata_t *rdata = gcb->context;
28
29 // --- Management Metalang
30 void uart_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
31 {
32         rdata_t *rdata = UDI_GCB(cb)->context;
33         //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
34
35         // TODO: Set up region data     
36
37         udi_usage_res(cb);
38 }
39
40 void uart_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
41 {
42         rdata_t *rdata = UDI_GCB(cb)->context;
43         udi_instance_attr_list_t *attr_list = cb->attr_list;
44         
45         switch(enumeration_level)
46         {
47         case UDI_ENUMERATE_START:
48         case UDI_ENUMERATE_START_RESCAN:
49                 DPT_SET_ATTR_STRING(attr_list, "gio_type", "uart", 4);
50                 attr_list ++;
51                 cb->attr_valid_length = attr_list - cb->attr_list;
52                 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, UART_OPS_GIO);
53                 break;
54         case UDI_ENUMERATE_NEXT:
55                 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
56                 break;
57         }
58 }
59 void uart_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
60 {
61 }
62 void uart_final_cleanup_req(udi_mgmt_cb_t *cb)
63 {
64 }
65 // ---
66 void uart_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb);
67 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);
68 void uart_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle);
69 void uart_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel);
70 void uart_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb);
71
72 void uart_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
73 {
74         udi_cb_t        *gcb = UDI_GCB(cb);
75         rdata_t *rdata = gcb->context;
76         
77         switch(cb->event)
78         {
79         case UDI_CHANNEL_CLOSED:
80                 break;
81         case UDI_CHANNEL_BOUND: {
82                 rdata->active_cb = gcb;
83                 udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
84                 udi_bus_bind_req( bus_bind_cb );
85                 // continue at uart_bus_dev_bus_bind_ack
86                 return; }
87         }
88 }
89 void uart_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
90         udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
91 {
92         udi_cb_t        *gcb = UDI_GCB(cb);
93         rdata_t *rdata = gcb->context;
94         
95         // Set up PIO handles
96         rdata->init.pio_index = -1;
97         uart_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
98         // V V V V
99 }
100 void uart_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
101 {
102         rdata_t *rdata = gcb->context;
103         if( rdata->init.pio_index != -1 )
104         {
105                 rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
106         }
107         
108         rdata->init.pio_index ++;
109         if( rdata->init.pio_index < N_PIO )
110         {
111                 udi_pio_map(uart_bus_dev_bind__pio_map, gcb,
112                         UDI_PCI_BAR_0, 0, 0x8,  // TODO: Use system bus index and offset
113                         uart_pio_ops[rdata->init.pio_index].trans_list,
114                         uart_pio_ops[rdata->init.pio_index].list_length,
115                         UDI_PIO_LITTLE_ENDIAN, 0, 0
116                         );
117                 return ;
118         }
119
120         // Spawn the interrupt channel
121         CONTIN( uart_bus_dev_bind, udi_channel_spawn, (gcb->channel, 0, UART_OPS_IRQ, rdata),
122                 (udi_channel_t new_channel))
123         
124         rdata->interrupt_channel = new_channel;
125
126         // Allocate an RX buffer
127         CONTIN( uart_bus_dev_bind, udi_buf_write, (NULL, 0, NULL, 0, 0, UDI_NULL_BUF_PATH),
128                 (udi_buf_t *new_buf));  
129         if( !new_buf )
130         {
131                 // Oh...
132                 udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t),
133                         UDI_STAT_RESOURCE_UNAVAIL );
134                 return ;
135         }
136         rdata->rx_buffer = new_buf;
137
138         // Create interrupt CB
139         CONTIN( uart_bus_dev_bind, udi_cb_alloc, (UART_CB_INTR, gcb->channel),
140                 (udi_cb_t *new_cb))
141         if( !new_cb )
142         {
143                 // Oh...
144                 udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t),
145                         UDI_STAT_RESOURCE_UNAVAIL );
146                 return ;
147         }
148         udi_intr_attach_cb_t    *intr_cb = UDI_MCB(new_cb, udi_intr_attach_cb_t);
149         intr_cb->interrupt_idx = 0;
150         intr_cb->min_event_pend = 1;
151         intr_cb->preprocessing_handle = rdata->pio_handles[PIO_INTR];
152         
153         // Attach interrupt
154         udi_intr_attach_req(intr_cb);
155         // continued in uart_bus_dev_intr_attach_ack
156 }
157 void uart_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
158 {
159 }
160 void uart_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
161 {
162         udi_cb_t        *gcb = UDI_GCB(intr_attach_cb);
163         rdata_t *rdata = gcb->context;
164
165         // Allocate interrupt cbs
166         CONTIN(uart_bus_dev_intr_attach_ack, udi_cb_alloc_batch,
167                 (UART_CB_INTR_EVENT, NUM_INTR_CBS, TRUE, INTR_CB_BUF_SIZE, UDI_NULL_BUF_PATH),
168                 (udi_cb_t *first_new_cb))
169
170         while( first_new_cb )
171         {
172                 udi_intr_event_cb_t *cb = UDI_MCB(first_new_cb, udi_intr_event_cb_t);
173                 first_new_cb = first_new_cb->initiator_context;
174                 // - Set channel (udi_cb_alloc_batch sets the channel to gcb->channel)
175                 cb->gcb.channel = rdata->interrupt_channel;
176                 udi_intr_event_rdy(cb);
177         }
178
179         udi_channel_event_cb_t  *channel_cb = UDI_MCB(rdata->active_cb, udi_channel_event_cb_t);
180         
181         udi_channel_event_complete(channel_cb, UDI_OK);
182         // = = = = =
183 }
184 void uart_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
185 {
186 }
187 // ---
188 void uart_bus_irq_channel_event_ind(udi_channel_event_cb_t *cb)
189 {
190 }
191 void uart_bus_irq_intr_event_ind(udi_intr_event_cb_t *cb, udi_ubit8_t flags)
192 {
193         udi_cb_t        *gcb = UDI_GCB(cb);
194         rdata_t *rdata = gcb->context;
195         
196         DEBUG_OUT("flags=%x, intr_result=%x", flags, cb->intr_result);
197         if( cb->intr_result == 0 )
198         {
199                 // An IRQ from something other than RX
200                 udi_intr_event_rdy(cb);
201                 return ;
202         }
203
204         if( rdata->rx_buffer && rdata->rx_buffer->buf_size + cb->intr_result > MAX_RX_BUFFER_SIZE )
205         {
206                 // Drop, buffer is full
207                 DEBUG_OUT("dropping %i bytes, full rx buffer", cb->intr_result);
208                 udi_intr_event_rdy(cb);
209                 return ;
210         }
211
212         // Copy cb->intr_result bytes into the RX buffer
213         CONTIN(uart_bus_irq_intr_event_ind, udi_buf_copy,
214                 (cb->event_buf, 0, cb->intr_result,
215                         rdata->rx_buffer, rdata->rx_buffer->buf_size, 0,
216                         UDI_NULL_BUF_PATH),
217                 (udi_buf_t *new_buf));
218         
219         udi_intr_event_cb_t     *cb = UDI_MCB(gcb, udi_intr_event_cb_t);
220         
221         rdata->rx_buffer = new_buf;
222
223         DEBUG_OUT("copied %i bytes", cb->intr_result);
224
225         // Emit a signal to GIO client
226         if( rdata->event_cb && !rdata->event_cb_used )
227         {
228                 rdata->event_pending = FALSE;
229                 rdata->event_cb_used = TRUE;
230                 udi_gio_event_ind(rdata->event_cb);
231         }
232         else
233         {
234                 DEBUG_OUT("event_cb=%p, event_cb_used=%i - Queueing",
235                         rdata->event_cb, rdata->event_cb_used);
236                 rdata->event_pending = TRUE;
237         }
238
239         udi_intr_event_rdy(cb);
240 }
241 // ---
242 void uart_gio_prov_channel_event_ind(udi_channel_event_cb_t *cb);
243 void uart_gio_prov_bind_req(udi_gio_bind_cb_t *cb);
244 void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb);
245 void uart_gio_read_complete_short(udi_cb_t *gcb, udi_buf_t *new_buf);
246 void uart_gio_read_complete(udi_cb_t *gcb, udi_buf_t *new_buf);
247 void uart_gio_write_complete(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t res);
248 void uart_gio_prov_event_res(udi_gio_event_cb_t *cb);
249
250 void uart_gio_prov_channel_event_ind(udi_channel_event_cb_t *cb)
251 {
252 }
253 void uart_gio_prov_bind_req(udi_gio_bind_cb_t *cb)
254 {
255         udi_cb_t        *gcb = UDI_GCB(cb);
256         rdata_t *rdata = gcb->context;
257         
258         // TODO: Should this device allow multiple children?
259         if( rdata->event_cb ) {
260                 DEBUG_OUT("only one client allowed");
261                 udi_gio_bind_ack(cb, 0, 0, UDI_STAT_CANNOT_BIND_EXCL);
262                 return;
263         }
264         
265         // Allocate the event CB
266         CONTIN( uart_gio_prov_bind_req, udi_cb_alloc, (UART_CB_GIO_EVENT, gcb->channel),
267                 (udi_cb_t *new_cb));
268         udi_gio_bind_cb_t       *cb = UDI_MCB(gcb, udi_gio_bind_cb_t);
269         
270         rdata->event_cb = UDI_MCB(new_cb, udi_gio_event_cb_t);
271         rdata->event_cb_used = FALSE;
272         
273         udi_gio_bind_ack(cb, 0, 0, UDI_OK);
274 }
275 void uart_gio_prov_unbind_req(udi_gio_bind_cb_t *cb)
276 {
277         udi_cb_t        *gcb = UDI_GCB(cb);
278         rdata_t *rdata = gcb->context;
279         
280         rdata->event_cb = NULL;
281         rdata->event_cb_used = FALSE;
282         udi_gio_unbind_ack(cb);
283 }
284 void uart_gio_prov_xfer_req(udi_gio_xfer_cb_t *cb)
285 {
286         udi_cb_t        *gcb = UDI_GCB(cb);
287         rdata_t *rdata = gcb->context;
288         switch(cb->op)
289         {
290         case UDI_GIO_OP_READ: {
291                 udi_buf_copy_call_t     *callback;
292                 udi_size_t      len;
293                 // Read from local FIFO
294                 if( rdata->rx_buffer->buf_size < cb->data_buf->buf_size ) {
295                         len = rdata->rx_buffer->buf_size;
296                         callback = uart_gio_read_complete_short;
297                 }
298                 else {
299                         len = cb->data_buf->buf_size;
300                         callback = uart_gio_read_complete;
301                 }
302                 DEBUG_OUT("Read %i/%i bytes", len, rdata->rx_buffer->buf_size);
303                 // Replace entire destination buffer with `len` bytes from source
304                 udi_buf_copy(callback, gcb,
305                         rdata->rx_buffer, 0, len,
306                         cb->data_buf, 0, cb->data_buf->buf_size,
307                         UDI_NULL_BUF_PATH);
308                 break; }
309         case UDI_GIO_OP_WRITE:
310                 // Send to device
311                 udi_pio_trans(uart_gio_write_complete, gcb,
312                         rdata->pio_handles[PIO_TX], 0, cb->data_buf, &cb->data_buf->buf_size);
313                 break;
314         default:
315                 udi_gio_xfer_nak(cb, UDI_STAT_NOT_SUPPORTED);
316                 break;
317         }
318 }
319 void uart_gio_read_complete_short(udi_cb_t *gcb, udi_buf_t *new_buf)
320 {
321         rdata_t *rdata = gcb->context;
322         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
323         cb->data_buf = new_buf;
324         
325         // Delete read bytes from the RX buffer
326         CONTIN(uart_gio_read_complete, udi_buf_write,
327                 (NULL, 0, rdata->rx_buffer, 0, cb->data_buf->buf_size, UDI_NULL_BUF_PATH),
328                 (udi_buf_t *new_buf))
329         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
330         rdata->rx_buffer = new_buf;
331         
332         // Return underrun
333         udi_gio_xfer_nak(cb, UDI_STAT_DATA_UNDERRUN);
334 }
335 void uart_gio_read_complete(udi_cb_t *gcb, udi_buf_t *new_buf)
336 {
337         rdata_t *rdata = gcb->context;
338         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
339         cb->data_buf = new_buf;
340         // Delete read bytes from the RX buffer
341         CONTIN(uart_gio_read_complete, udi_buf_write,
342                 (NULL, 0, rdata->rx_buffer, 0, cb->data_buf->buf_size, UDI_NULL_BUF_PATH),
343                 (udi_buf_t *new_buf))
344         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
345         rdata->rx_buffer = new_buf;
346         
347         // Return completed
348         udi_gio_xfer_ack(cb);
349 }
350 void uart_gio_write_complete(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t res)
351 {
352         udi_gio_xfer_cb_t       *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
353         cb->data_buf = new_buf;
354         udi_gio_xfer_ack(cb);
355 }
356 void uart_gio_prov_event_res(udi_gio_event_cb_t *cb)
357 {
358         udi_cb_t        *gcb = UDI_GCB(cb);
359         rdata_t *rdata = gcb->context;
360         
361         // If there was an event during dispatch, re-send
362         if( rdata->event_pending )
363         {
364                 udi_gio_event_ind(cb);
365                 rdata->event_pending = FALSE;
366         }
367         // otherwise, clear 'Event CB used' flag
368         else
369         {
370                 rdata->event_cb_used = FALSE;
371         }
372 }
373
374 // ====================================================================
375 // - Management ops
376 udi_mgmt_ops_t  uart_mgmt_ops = {
377         uart_usage_ind,
378         uart_enumerate_req,
379         uart_devmgmt_req,
380         uart_final_cleanup_req
381 };
382 udi_ubit8_t     uart_mgmt_op_flags[4] = {0,0,0,0};
383 // - Bus Ops
384 udi_bus_device_ops_t    uart_bus_dev_ops = {
385         uart_bus_dev_channel_event_ind,
386         uart_bus_dev_bus_bind_ack,
387         uart_bus_dev_bus_unbind_ack,
388         uart_bus_dev_intr_attach_ack,
389         uart_bus_dev_intr_detach_ack
390 };
391 udi_ubit8_t     uart_bus_dev_ops_flags[5] = {0};
392 // - IRQ Ops
393 udi_intr_handler_ops_t  uart_bus_irq_ops = {
394         uart_bus_irq_channel_event_ind,
395         uart_bus_irq_intr_event_ind
396 };
397 udi_ubit8_t     uart_bus_irq_ops_flags[2] = {0};
398 // - GIO provider ops
399 udi_gio_provider_ops_t  uart_gio_prov_ops = {
400         uart_gio_prov_channel_event_ind,
401         uart_gio_prov_bind_req,
402         uart_gio_prov_unbind_req,
403         uart_gio_prov_xfer_req,
404         uart_gio_prov_event_res
405 };
406 udi_ubit8_t     uart_gio_prov_ops_flags[5] = {0};
407 // --
408 udi_primary_init_t      uart_pri_init = {
409         .mgmt_ops = &uart_mgmt_ops,
410         .mgmt_op_flags = uart_mgmt_op_flags,
411         .mgmt_scratch_requirement = 0,
412         .enumeration_attr_list_length = 4,
413         .rdata_size = sizeof(rdata_t),
414         .child_data_size = 0,
415         .per_parent_paths = 0
416 };
417 udi_ops_init_t  uart_ops_list[] = {
418         {
419                 UART_OPS_DEV, UART_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
420                 0,
421                 (udi_ops_vector_t*)&uart_bus_dev_ops,
422                 uart_bus_dev_ops_flags
423         },
424         {
425                 UART_OPS_IRQ, UART_META_BUS, UDI_BUS_INTR_HANDLER_OPS_NUM,
426                 0,
427                 (udi_ops_vector_t*)&uart_bus_irq_ops,
428                 uart_bus_irq_ops_flags
429         },
430         {
431                 UART_OPS_GIO, UART_META_GIO, UDI_GIO_PROVIDER_OPS_NUM,
432                 0,
433                 (udi_ops_vector_t*)&uart_gio_prov_ops,
434                 uart_gio_prov_ops_flags
435         },
436         {0}
437 };
438 udi_cb_init_t uart_cb_init_list[] = {
439         {UART_CB_BUS_BIND,   UART_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL},
440         {UART_CB_INTR,       UART_META_BUS, UDI_BUS_INTR_ATTACH_CB_NUM, 0, 0,NULL},
441         {UART_CB_INTR_EVENT, UART_META_BUS, UDI_BUS_INTR_EVENT_CB_NUM, 0, 0,NULL},
442         {UART_CB_GIO_EVENT,  UART_META_GIO, UDI_GIO_EVENT_CB_NUM, 0, 0,NULL},
443         {0}
444 };
445 const udi_init_t        udi_init_info = {
446         .primary_init_info = &uart_pri_init,
447         .ops_init_list = uart_ops_list,
448         .cb_init_list = uart_cb_init_list,
449 };

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