UDI/GFX - fiddling
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / trans / nsr.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * trans/nsr.c
6  * - "Network Service Requester" (UDI->IP Translation)
7  */
8 #define DEBUG   1
9 #include <udi.h>
10 #include <udi_nic.h>
11 #include <acess.h>
12 #include <trans_nsr.h>
13 #include <IPStack/include/adapters_api.h>
14 #include <workqueue.h>
15
16 #define NUM_RX_BUFFERS  4
17 #define NUM_TX_DESCS    4
18
19 enum {
20         ACESSNSR_OPS_CTRL = 1,
21         ACESSNSR_OPS_TX,
22         ACESSNSR_OPS_RX,
23 };
24 enum {
25         ACESSNSR_META_NIC = 1
26 };
27 enum {
28         ACESSNSR_CB_CTRL = 1,
29         ACESSNSR_CB_RX,
30         ACESSNSR_CB_TX,
31         ACESSNSR_CB_STD,
32 };
33
34 // === TYPES ===
35 typedef struct acessnsr_txdesc_s
36 {
37         //udi_nic_tx_cb_t       cb;
38         tMutex  CompleteMutex;
39          int    BufIdx;
40         tIPStackBuffer  *IPBuffer;
41 } acessnsr_txdesc_t;
42
43 typedef struct
44 {
45         udi_init_context_t      init_context;   
46         udi_cb_t        *active_cb;
47         udi_channel_t   saved_active_channel;
48
49         tWorkqueue      RXQueue;
50
51         tIPStack_AdapterType    AdapterType;
52         void    *ipstack_handle;
53
54         tWorkqueue      TXWorkQueue;
55         acessnsr_txdesc_t       TXDescs[NUM_TX_DESCS];
56         
57         udi_channel_t   rx_channel;
58         udi_channel_t   tx_channel;
59 } acessnsr_rdata_t;
60
61 // === PROTOTYPES ===
62 // --- Management metalang
63 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
64 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
65 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb);
66 // --- NSR Control
67 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb);
68 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
69 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
70 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status);
71 void acessnsr_ctrl_bind_ack__rx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb);
72 void acessnsr_ctrl_bind_ack__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb);
73 void acessnsr_ctrl_bind_ack__std_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb);
74 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status);
75 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status);
76 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status);
77 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status);
78 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb);
79 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb);
80 // --- NSR TX
81 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb);
82 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb);
83 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf);
84 // --- NSR RX
85 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb);
86 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb);
87 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb);
88 // --- Acess IPStack
89  int    acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer);
90 void    acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf);
91 tIPStackBuffer  *acessnsr_WaitForPacket(void *Card);
92
93 // === CODE ===
94 // --- Management metalang
95 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
96 {
97         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
98         switch(resource_level)
99         {
100         }
101
102         Workqueue_Init(&rdata->RXQueue, "AcessNSR RX", offsetof(udi_nic_rx_cb_t, chain));
103         Workqueue_Init(&rdata->TXWorkQueue, "AcessNSR TX", offsetof(udi_nic_tx_cb_t, chain));
104
105         udi_usage_res(cb);
106 }
107 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
108 {
109         UNIMPLEMENTED();
110 }
111 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb)
112 {
113         UNIMPLEMENTED();
114 }
115 // --- NSR Control
116 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb)
117 {
118         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
119         switch(cb->event)
120         {
121         case UDI_CHANNEL_CLOSED:
122                 break;
123         case UDI_CHANNEL_BOUND: {
124                 rdata->active_cb = UDI_GCB(cb);
125                 udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__rx_channel_spawned,
126                         cb->params.parent_bound.bind_cb, UDI_GCB(cb)->channel,
127                         1, ACESSNSR_OPS_RX, rdata);
128                 // V V V V
129                 break; }
130         }
131 }
132 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
133 {
134         acessnsr_rdata_t *rdata = gcb->context;
135         rdata->rx_channel = channel;
136         udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__tx_channel_spawned, gcb, gcb->channel,
137                 2, ACESSNSR_OPS_TX, rdata);
138         // V V V V
139 }
140 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
141 {
142         acessnsr_rdata_t *rdata = gcb->context;
143         rdata->tx_channel = channel;
144         udi_nic_bind_cb_t *bind_cb = UDI_MCB(gcb, udi_nic_bind_cb_t);
145         udi_nd_bind_req(bind_cb, 2, 1);
146         // V V V V
147 }
148 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status)
149 {
150         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
151         // TODO: Parse cb and register with IPStack
152         // - Pass on capabilities and media type
153         switch(cb->media_type)
154         {
155         case UDI_NIC_ETHER:     rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_10M;     break;
156         case UDI_NIC_FASTETHER: rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_100M;    break;
157         case UDI_NIC_GIGETHER:  rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_1G;      break;
158         default:
159                 udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
160                 break;
161         }
162
163         // - Register with IPStack
164         if(cb->capabilities & UDI_NIC_CAP_TX_IP_CKSUM)
165                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_IP4;
166         if(cb->capabilities & UDI_NIC_CAP_TX_TCP_CKSUM)
167                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_TCP;
168         if(cb->capabilities & UDI_NIC_CAP_TX_UDP_CKSUM)
169                 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_UDP;
170         rdata->AdapterType.Name = "udi";
171         rdata->AdapterType.SendPacket = acessnsr_SendPacket;
172         rdata->AdapterType.WaitForPacket = acessnsr_WaitForPacket;
173         rdata->ipstack_handle = IPStack_Adapter_Add(&rdata->AdapterType, rdata, cb->mac_addr);
174
175         // Allocate RX CBs and buffers
176         // EVIL: Save and change channel of event CB
177         rdata->saved_active_channel = rdata->active_cb->channel;
178         rdata->active_cb->channel = rdata->rx_channel;
179         udi_cb_alloc_batch( acessnsr_ctrl_bind_ack__rx_cbs_allocated, rdata->active_cb,
180                 ACESSNSR_CB_RX, NUM_RX_BUFFERS, TRUE, 0, NULL);
181         // V V V V
182 }
183 void acessnsr_ctrl_bind_ack__rx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb)
184 {
185         acessnsr_rdata_t *rdata = gcb->context;
186         // Send of the entire list
187         ASSERT(first_new_cb);
188         udi_nd_rx_rdy( UDI_MCB(first_new_cb, udi_nic_rx_cb_t) );
189         
190         // Allocate batch (no buffers)
191         gcb->channel = rdata->tx_channel;
192         udi_cb_alloc_batch( acessnsr_ctrl_bind_ack__tx_cbs_allocated, gcb,
193                 ACESSNSR_CB_TX, NUM_TX_DESCS, FALSE, 0, NULL);
194         // V V V V
195 }
196 void acessnsr_ctrl_bind_ack__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb)
197 {
198         acessnsr_rdata_t *rdata = gcb->context;
199         ASSERT(first_new_cb);
200         
201         {
202                 udi_nic_tx_cb_t *cb, *next_cb;
203                 cb = UDI_MCB(first_new_cb, udi_nic_tx_cb_t);
204                 ASSERT(cb);
205                 do {
206                         next_cb = cb->chain;
207                         cb->chain = NULL;
208                         Workqueue_AddWork( &rdata->TXWorkQueue, cb );
209                 } while(next_cb);
210         }
211         
212         // Allocate standard control CB (for enable/disable)
213         udi_cb_alloc(acessnsr_ctrl_bind_ack__std_cb_allocated, gcb,
214                 ACESSNSR_CB_STD, rdata->saved_active_channel);
215         // V V V V
216 }
217 void acessnsr_ctrl_bind_ack__std_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb)
218 {
219         // Final Operations:
220         // - Enable card (RX won't happen until this is called)
221         udi_nd_enable_req( UDI_MCB(new_cb, udi_nic_cb_t) );
222         // Continued in acessnsr_ctrl_enable_ack
223 }
224 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status)
225 {
226         UNIMPLEMENTED();
227 }
228 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status)
229 {
230         udi_cb_t        *gcb = UDI_GCB(cb);
231         acessnsr_rdata_t *rdata = gcb->context;
232         
233         rdata->active_cb->channel = rdata->saved_active_channel;
234         udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
235         // = = = =
236 }
237 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status)
238 {
239         UNIMPLEMENTED();
240 }
241 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status)
242 {
243         UNIMPLEMENTED();
244 }
245 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb)
246 {
247         UNIMPLEMENTED();
248 }
249 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb)
250 {
251         UNIMPLEMENTED();
252 }
253 // --- NSR TX
254 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb)
255 {
256         UNIMPLEMENTED();
257 }
258 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb)
259 {
260         //acessnsr_txdesc_t *tx = UDI_GCB(cb)->context;
261         // TODO: Can errors be detected here?
262         UDI_BUF_DELETE(acessnsr_tx_rdy__buffer_cleared, UDI_GCB(cb), cb->tx_buf->buf_size, cb->tx_buf, 0);
263 }
264 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf)
265 {
266         acessnsr_txdesc_t *tx = gcb->scratch;
267         udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
268         cb->tx_buf = buf;
269         Mutex_Release(&tx->CompleteMutex);      // triggers acessnsr_SendPacket
270 }
271 // --- NSR RX
272 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb)
273 {
274         UNIMPLEMENTED();
275 }
276 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb)
277 {
278         acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
279         udi_nic_rx_cb_t *next;
280         do {
281                 next = cb->chain;
282                 Workqueue_AddWork(&rdata->RXQueue, cb);
283         } while( (cb = next) );
284 }
285 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb)
286 {
287         acessnsr_rx_ind(cb);
288         //UNIMPLEMENTED();
289 }
290 // --- Acess IPStack
291 int acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer)
292 {
293         acessnsr_rdata_t *rdata = Card;
294         LOG("Card=%p,Buffer=%p", Card, Buffer);
295         udi_nic_tx_cb_t *cb = Workqueue_GetWork(&rdata->TXWorkQueue);
296         ASSERT(cb);
297         acessnsr_txdesc_t *tx = UDI_GCB(cb)->scratch;
298         ASSERT(tx);
299
300         LOG("Mutex acquire #1 %p", cb);
301         Mutex_Acquire(&tx->CompleteMutex);
302         tx->IPBuffer = Buffer;
303         tx->BufIdx = -1;
304         acessnsr_SendPacket__buf_write_complete(UDI_GCB(cb), NULL);
305
306         // Double lock is resolved once TX is complete
307         Mutex_Acquire(&tx->CompleteMutex);
308         Mutex_Release(&tx->CompleteMutex);
309         // TODO: TX status
310         
311         LOG("Release %p", cb);  
312         Workqueue_AddWork(&rdata->TXWorkQueue, cb);
313         return 0;
314 }
315 void acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf)
316 {
317         acessnsr_txdesc_t *tx = gcb->scratch;
318         udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
319         if( tx->BufIdx >= 0 ) {
320                 cb->tx_buf = buf;
321         }
322         size_t  buflen;
323         const void      *bufptr;
324         if( (tx->BufIdx = IPStack_Buffer_GetBuffer(tx->IPBuffer, tx->BufIdx, &buflen, &bufptr )) != -1 )
325         {
326                 Debug_HexDump("NSR", bufptr, buflen);
327                 udi_buf_write(acessnsr_SendPacket__buf_write_complete, gcb,
328                         bufptr, buflen, cb->tx_buf, (cb->tx_buf ? cb->tx_buf->buf_size : 0), 0, NULL);
329                 // A A A A
330                 return ;
331         }
332         
333         udi_nd_tx_req(cb);
334         // continued in acessnsr_tx_rdy
335 }
336 static void _FreeHeapSubBuf(void *Arg, size_t Pre, size_t Post, const void *DataBuf)
337 {
338         free(Arg);
339 }
340 tIPStackBuffer *acessnsr_WaitForPacket(void *Card)
341 {
342         acessnsr_rdata_t *rdata = Card;
343         udi_nic_rx_cb_t *cb = Workqueue_GetWork(&rdata->RXQueue);
344
345         tIPStackBuffer  *ret = IPStack_Buffer_CreateBuffer(1);
346         void    *data = malloc( cb->rx_buf->buf_size );
347         udi_buf_read(cb->rx_buf, 0, cb->rx_buf->buf_size, data);
348         Debug_HexDump("NSR WaitForPacket", data, cb->rx_buf->buf_size);
349         IPStack_Buffer_AppendSubBuffer(ret, cb->rx_buf->buf_size, 0, data, _FreeHeapSubBuf, data);
350
351         udi_nd_rx_rdy(cb);
352         return ret;
353 }
354
355 // === UDI Bindings ===
356 udi_mgmt_ops_t  acessnsr_mgmt_ops = {
357         acessnsr_usage_ind,
358         udi_enumerate_no_children,
359         acessnsr_devmgmt_req,
360         acessnsr_final_cleanup_req
361 };
362 udi_ubit8_t     acessnsr_mgmt_ops_flags[4] = {0,0,0,0};
363
364 udi_primary_init_t      acessnsr_pri_init = {
365         .mgmt_ops = &acessnsr_mgmt_ops,
366         .mgmt_op_flags = acessnsr_mgmt_ops_flags,
367         .mgmt_scratch_requirement = 0,
368         .enumeration_attr_list_length = 4,
369         .rdata_size = sizeof(acessnsr_rdata_t),
370         .child_data_size = 0,
371         .per_parent_paths = 0
372 };
373
374 udi_nsr_ctrl_ops_t      acessnsr_ctrl_ops = {
375         acessnsr_ctrl_channel_event_ind,
376         acessnsr_ctrl_bind_ack,
377         acessnsr_ctrl_unbind_ack,
378         acessnsr_ctrl_enable_ack,
379         acessnsr_ctrl_ctrl_ack,
380         acessnsr_ctrl_info_ack,
381         acessnsr_ctrl_status_ind
382 };
383 udi_ubit8_t     acessnsr_ctrl_op_flags[7] = {0};
384
385 udi_nsr_tx_ops_t        acessnsr_tx_ops = {
386         acessnsr_tx_channel_event_ind,
387         acessnsr_tx_rdy
388 };
389 udi_ubit8_t     acessnsr_tx_ops_flags[2] = {0};
390
391 udi_nsr_rx_ops_t        acessnsr_rx_ops = {
392         acessnsr_rx_channel_event_ind,
393         acessnsr_rx_ind,
394         acessnsr_rx_exp_ind
395 };
396 udi_ubit8_t     acessnsr_rx_ops_flags[3] = {0};
397
398 udi_ops_init_t  acessnsr_ops_list[] = {
399         {
400                 ACESSNSR_OPS_CTRL, ACESSNSR_META_NIC, UDI_NSR_CTRL_OPS_NUM,
401                 0, (udi_ops_vector_t*)&acessnsr_ctrl_ops, acessnsr_ctrl_op_flags
402         },
403         {
404                 ACESSNSR_OPS_TX, ACESSNSR_META_NIC, UDI_NSR_TX_OPS_NUM,
405                 0, (udi_ops_vector_t*)&acessnsr_tx_ops, acessnsr_tx_ops_flags
406         },
407         {
408                 ACESSNSR_OPS_RX, ACESSNSR_META_NIC, UDI_NSR_RX_OPS_NUM,
409                 0, (udi_ops_vector_t*)&acessnsr_rx_ops, acessnsr_rx_ops_flags
410         },
411         {0}
412 };
413 udi_cb_init_t   acessnsr_cb_init_list[] = {
414         {ACESSNSR_CB_CTRL, ACESSNSR_META_NIC, UDI_NIC_BIND_CB_NUM, 0, 0,NULL},
415         {ACESSNSR_CB_RX, ACESSNSR_META_NIC, UDI_NIC_RX_CB_NUM, 0, 0,NULL},
416         {ACESSNSR_CB_TX, ACESSNSR_META_NIC, UDI_NIC_TX_CB_NUM, sizeof(acessnsr_txdesc_t), 0,NULL},
417         {ACESSNSR_CB_STD, ACESSNSR_META_NIC, UDI_NIC_TX_CB_NUM, 0, 0,NULL},
418         {0}
419 };
420 const udi_init_t        acessnsr_init = {
421         .primary_init_info = &acessnsr_pri_init,
422         .ops_init_list = acessnsr_ops_list,
423         .cb_init_list = acessnsr_cb_init_list,
424 };
425 const char      acessnsr_udiprops[] = 
426         "properties_version 0x101\0"
427         "message 1 Acess2 Kernel\0"
428         "message 2 John Hodge ([email protected])\0"
429         "message 3 Acess2 NSR\0"
430         "supplier 1\0"
431         "contact 2\0"
432         "name 3\0"
433         "module acess_nsr\0"
434         "shortname acessnsr\0"
435         "requires udi 0x101\0"
436         "requires udi_nic 0x101\0"
437         "meta 1 udi_nic\0"
438         "message 101 Ethernet Adapter\0"
439         "device 101 1 if_media string eth\0"
440         "parent_bind_ops 1 0 1 1\0"
441         "\0";
442 size_t  acessnsr_udiprops_size = sizeof(acessnsr_udiprops);
443

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