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

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