3 * \author John Hodge (thePowersGang)
4 * \brief Control block code
9 #include <udi_internal.h>
10 #include <udi_internal_ma.h> // for cUDI_MgmtCbInitList
12 typedef struct sUDI_CBHeader
14 tUDI_MetaLang *Metalang;
15 udi_index_t MetaCBNum;
20 tUDI_MetaLang *UDI_int_GetCbType(udi_cb_t *cb, udi_index_t *meta_cb_num)
22 tUDI_CBHeader *hdr = (void*)cb - offsetof(tUDI_CBHeader, cb);
24 *meta_cb_num = hdr->MetaCBNum;
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)
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);
45 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
47 const udi_cb_init_t *cb_init;
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);
55 for( cb_init = Inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
57 if( cb_init->cb_idx == bind_cb_idx )
59 // TODO: Get base size using meta/cbnum
60 tUDI_MetaLang *metalang = UDI_int_GetMetaLang(Inst->Module, cb_init->meta_idx);
62 Log_Warning("UDI", "Metalang referenced in %s CB %i is invalid (%i)",
63 Inst->Module->ModuleName, bind_cb_idx, cb_init->meta_idx);
66 return udi_cb_alloc_internal_v(metalang, cb_init->meta_cb_num,
67 cb_init->inline_size, cb_init->scratch_requirement, channel);
70 Log_Warning("UDI", "Cannot find CB init def %i for '%s'",
71 bind_cb_idx, Inst->Module->ModuleName);
76 udi_cb_alloc_call_t *callback, //!< Function to be called when the CB is allocated
77 udi_cb_t *gcb, //!< Parent Control Block
79 udi_channel_t default_channel
82 tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance(gcb, false, NULL);
83 void *ret = udi_cb_alloc_internal(inst, cb_idx, default_channel);
87 void udi_cb_alloc_dynamic(
88 udi_cb_alloc_call_t *callback,
91 udi_channel_t default_channel,
92 udi_size_t inline_size,
93 udi_layout_t *inline_layout
99 void udi_cb_alloc_batch(
100 udi_cb_alloc_batch_call_t *callback, //!<
104 udi_boolean_t with_buf,
106 udi_buf_path_t path_handle
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 ++ )
113 if( cb_init->cb_idx == cb_idx )
116 if( cb_init->cb_idx == 0 ) {
120 tUDI_MetaLang *metalang = UDI_int_GetMetaLang(inst->Module, cb_init->meta_idx);
122 Log_Warning("UDI", "Metalang referenced in %s CB %i is invalid (%i)",
123 inst->Module->ModuleName, cb_idx, cb_init->meta_idx);
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);
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 = metalang->CbTypes[cb_init->meta_cb_num].ChainOfs;
140 udi_layout_t *layout = metalang->CbTypes[cb_init->meta_cb_num].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);
148 size_t cur_ofs = sizeof(udi_cb_t);
149 while( *layout != UDI_DL_END )
151 if( *layout == UDI_DL_BUF ) {
153 Log_Notice("UDI", "TODO Multiple buffers in cb_alloc_batch (%s:%i, %s:%i)",
154 metalang->Name, cb_init->meta_cb_num,
155 inst->Module->ModuleName, cb_idx);
163 size_t sz = _udi_marshal_step(NULL, 0, &layout, NULL);
165 Log_Warning("UDI", "Metalang CB %s:%i has an invalid layout",
166 metalang->Name, cb_init->meta_cb_num);
174 // Use initiator context if there's no chain
176 chain_ofs = offsetof(udi_cb_t, initiator_context);
177 LOG("chain_ofs = %i (initiator_context)", chain_ofs);
180 LOG("chain_ofs = %i", chain_ofs);
182 LOG("buf_ofs = %i", buf_ofs);
184 udi_cb_t *first_cb = NULL, *cur_cb;
185 udi_cb_t **prevptr = &first_cb;
186 for( int i = 0; i < count; i ++ )
188 cur_cb = udi_cb_alloc_internal_v(metalang, cb_init->meta_cb_num,
189 cb_init->inline_size, cb_init->scratch_requirement, gcb->channel);
192 if( with_buf && buf_ofs ) {
193 udi_buf_t *buf = _udi_buf_allocate(NULL, buf_size, path_handle);
194 LOG("buf +%i = %p", buf_ofs, buf);
195 *(void**)((char*)cur_cb + buf_ofs) = buf;
198 LOG("*%p = %p", prevptr, cur_cb);
200 prevptr = (void*)cur_cb + chain_ofs;
204 callback(gcb, first_cb);
207 void udi_cb_free(udi_cb_t *cb)
209 tUDI_CBHeader *hdr = (void*)cb - offsetof(tUDI_CBHeader, cb);
210 // TODO: Ensure that cb is inactive
214 void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb)
220 EXPORT(udi_cb_alloc);
221 EXPORT(udi_cb_alloc_dynamic);
222 EXPORT(udi_cb_alloc_batch);