2e0dbfccf98f10eb78ceaeb59c7d71bec3325899
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / udi_lib / core / cb.c
1 /**
2  * \file cb.c
3  * \author John Hodge (thePowersGang)
4  * \brief Control block code
5  */
6 #define DEBUG   1
7 #include <udi.h>
8 #include <acess.h>
9 #include <udi_internal.h>
10 #include <udi_internal_ma.h>    // for cUDI_MgmtCbInitList
11
12 typedef struct sUDI_CBHeader
13 {
14         tUDI_MetaLang   *Metalang;
15         udi_index_t     MetaCBNum;
16         udi_cb_t        cb;
17 } tUDI_CBHeader;
18
19 // === CODE ===
20 tUDI_MetaLang *UDI_int_GetCbType(udi_cb_t *cb, udi_index_t *meta_cb_num)
21 {
22         tUDI_CBHeader   *hdr = (void*)cb - offsetof(tUDI_CBHeader, cb);
23         if(meta_cb_num)
24                 *meta_cb_num = hdr->MetaCBNum;
25         return hdr->Metalang;
26 }
27
28 udi_cb_t *udi_cb_alloc_internal_v(tUDI_MetaLang *Meta, udi_index_t MetaCBNum,
29         size_t inline_size, size_t scratch_size, udi_channel_t channel)
30 {
31         ASSERTC(MetaCBNum, <, Meta->nCbTypes);
32         size_t  base = Meta->CbTypes[MetaCBNum].Size;
33         ASSERTC(base, >=, sizeof(udi_cb_t));
34         base -= sizeof(udi_cb_t);
35         tUDI_CBHeader   *cbhdr = NEW(tUDI_CBHeader, + base + inline_size + scratch_size);
36         cbhdr->Metalang = Meta;
37         cbhdr->MetaCBNum = MetaCBNum;
38         udi_cb_t *ret = &cbhdr->cb;
39         ret->channel = channel;
40         ret->scratch = (void*)(ret + 1) + base + inline_size;
41         LOG("(%s) udi_cb_t + %i + %i + %i = %p",
42                 Meta->Name, base, inline_size, scratch_size, ret);
43         return ret;
44 }
45 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
46 {
47         const udi_cb_init_t     *cb_init;
48         ASSERT(Inst);
49         ASSERT(Inst->Module);
50         LOG("Inst=%p(%s), bind_cb_idx=%i, channel=%p",
51                 Inst, Inst->Module->ModuleName, bind_cb_idx, channel);
52         ASSERT(Inst->Module->InitInfo);
53         ASSERT(Inst->Module->InitInfo->cb_init_list);
54         
55         for( cb_init = Inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
56         {
57                 if( cb_init->cb_idx == bind_cb_idx )
58                 {
59                         // TODO: Get base size using meta/cbnum
60                         tUDI_MetaLang *metalang = UDI_int_GetMetaLang(Inst->Module, cb_init->meta_idx);
61                         if( !metalang ) {
62                                 Log_Warning("UDI", "Metalang referenced in %s CB %i is invalid (%i)",
63                                         Inst->Module->ModuleName, bind_cb_idx, cb_init->meta_idx);
64                                 return NULL;
65                         }
66                         return udi_cb_alloc_internal_v(metalang, cb_init->meta_cb_num,
67                                 cb_init->inline_size, cb_init->scratch_requirement, channel);
68                 }
69         }
70         Log_Warning("UDI", "Cannot find CB init def %i for '%s'",
71                 bind_cb_idx, Inst->Module->ModuleName);
72         return NULL;
73 }
74
75 void udi_cb_alloc (
76         udi_cb_alloc_call_t     *callback,      //!< Function to be called when the CB is allocated
77         udi_cb_t        *gcb,   //!< Parent Control Block
78         udi_index_t     cb_idx,
79         udi_channel_t   default_channel
80         )
81 {
82         tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance(gcb, false, NULL);
83         void *ret = udi_cb_alloc_internal(inst, cb_idx, default_channel);
84         callback(gcb, ret);
85 }
86
87 void udi_cb_alloc_dynamic(
88         udi_cb_alloc_call_t     *callback,
89         udi_cb_t        *gcb,
90         udi_index_t     cb_idx,
91         udi_channel_t   default_channel,
92         udi_size_t      inline_size,
93         udi_layout_t    *inline_layout
94         )
95 {
96         UNIMPLEMENTED();
97 }
98
99 void udi_cb_alloc_batch(
100         udi_cb_alloc_batch_call_t       *callback,      //!< 
101         udi_cb_t        *gcb,   //!< 
102         udi_index_t     cb_idx,
103         udi_index_t     count,
104         udi_boolean_t   with_buf,
105         udi_size_t      buf_size,
106         udi_buf_path_t  path_handle
107         )
108 {
109         tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance(gcb, false, NULL);
110         udi_cb_init_t   *cb_init;
111         for( cb_init = inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
112         {
113                 if( cb_init->cb_idx == cb_idx )
114                         break;
115         }
116         if( cb_init->cb_idx == 0 ) {
117                 callback(gcb, NULL);
118                 return ;
119         }
120         tUDI_MetaLang *metalang = UDI_int_GetMetaLang(inst->Module, cb_init->meta_idx);
121         if( !metalang ) {
122                 Log_Warning("UDI", "Metalang referenced in %s CB %i is invalid (%i)",
123                         inst->Module->ModuleName, cb_idx, cb_init->meta_idx);
124                 callback(gcb, NULL);
125                 return ;
126         }
127
128         if( cb_init->meta_cb_num >= metalang->nCbTypes ) {      
129                 Log_Warning("UDI", "Metalang CB referenced in %s CB %i is invalid (%s %i>=%i)",
130                         inst->Module->ModuleName, cb_idx,
131                         metalang->Name, cb_init->meta_cb_num, metalang->nCbTypes);
132                 callback(gcb, NULL);
133                 return ;
134         }       
135
136         // Get chain offset and buffer offset
137         size_t  buf_ofs = 0;    // TODO: Multiple buffers are to be supported
138         size_t  chain_ofs = 0;
139         {
140                 udi_layout_t    *layout = metalang->CbTypes[cb_init->meta_cb_num].Layout;
141                 if( !layout ) {
142                         Log_Warning("UDI", "Metalang CB %s:%i does not define a layout. Bulk alloc impossible",
143                                 metalang->Name, cb_init->meta_cb_num);
144                         callback(gcb, NULL);
145                         return ;
146                 }
147                 
148                 size_t  cur_ofs = sizeof(udi_cb_t);
149                 while( *layout != UDI_DL_END )
150                 {
151                         if( *layout == UDI_DL_BUF ) {
152                                 if( buf_ofs ) {
153                                         Log_Notice("UDI", "TODO Multiple buffers in cb_alloc_batch (%s:%i)",
154                                                 metalang->Name, cb_init->meta_cb_num);
155                                 }
156                                 buf_ofs = cur_ofs;
157                         }
158                         else if( *layout == UDI_DL_CB ) {
159                                 if( chain_ofs ) {
160                                         Log_Warning("UDI", "Cb %s:%i has multiple DL_CB entries",
161                                                 metalang->Name, cb_init->meta_cb_num);
162                                 }
163                                 chain_ofs = cur_ofs;
164                         }
165                         else {
166                                 // No-op        
167                         }
168                         
169                         cur_ofs += _udi_marshal_step(NULL, 0, &layout, NULL);
170                         layout ++;
171                 }
172         }
173
174         // Use initiator context if there's no chain
175         if( !chain_ofs ) {
176                 chain_ofs = offsetof(udi_cb_t, initiator_context);
177                 LOG("chain_ofs = %i (initiator_context)", chain_ofs);
178         }
179         else {
180                 LOG("chain_ofs = %i", chain_ofs);
181         }
182
183         udi_cb_t *first_cb = NULL, *cur_cb;
184         udi_cb_t **prevptr = &first_cb;
185         for( int i = 0; i < count; i ++ )
186         {
187                 cur_cb = udi_cb_alloc_internal_v(metalang, cb_init->meta_cb_num,
188                         cb_init->inline_size, cb_init->scratch_requirement, gcb->channel);
189
190                 // Allocate buffer
191                 if( with_buf && buf_ofs ) {
192                         *(void**)((char*)cur_cb + buf_ofs) =_udi_buf_allocate(NULL, buf_size, path_handle);
193                 }
194
195                 LOG("*%p = %p", prevptr, cur_cb);
196                 *prevptr = cur_cb;
197                 prevptr = (void*)cur_cb + chain_ofs;
198         }
199         *prevptr = NULL;
200         
201         callback(gcb, first_cb);
202 }
203
204 void udi_cb_free(udi_cb_t *cb)
205 {
206         tUDI_CBHeader   *hdr = (void*)cb - offsetof(tUDI_CBHeader, cb);
207         // TODO: Ensure that cb is inactive
208         free(hdr);
209 }
210
211 void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb)
212 {
213         UNIMPLEMENTED();
214 }
215
216 // === EXPORTS ===
217 EXPORT(udi_cb_alloc);
218 EXPORT(udi_cb_alloc_dynamic);
219 EXPORT(udi_cb_alloc_batch);
220 EXPORT(udi_cb_free);
221 EXPORT(udi_cancel);

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