Modules/UDI - Working on more framework and PCI bus
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / channels.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * channels.c
6  * - Channel code
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <udi.h>
11 #include "udi_internal.h"
12 #define LOCK_CHANNELS   1
13
14 struct sUDI_ChannelSide {
15         struct sUDI_Channel     *BackPtr;
16         udi_index_t     MetaOpsNum;
17         const void      *Ops;
18         void    *Context;
19 };
20
21 typedef struct sUDI_Channel
22 {
23         tUDI_MetaLang   *MetaLang;
24         bool    Locked;
25         struct sUDI_ChannelSide  Side[2];
26 } tUDI_Channel;
27
28 // === CODE ===
29 udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang)
30 {
31         tUDI_Channel    *ret = NEW(tUDI_Channel,);
32
33         ret->MetaLang = metalang;
34         ret->Side[0].BackPtr = ret;     
35         ret->Side[1].BackPtr = ret;     
36
37         return (udi_channel_t)&ret->Side[0].BackPtr;
38 }
39
40 struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side)
41 {
42         tUDI_Channel *ch = *(tUDI_Channel**)channel;
43         if(!ch) return NULL;
44         
45         int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) != other_side;
46
47         return &ch->Side[side_idx];
48 }
49
50 int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num,  void *context, const void *ops)
51 {
52         struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
53         side->Context = context;
54         side->MetaOpsNum = meta_ops_num;
55         side->Ops = ops;
56         return 0;
57 }
58
59 int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region)
60 {
61         tUDI_Channel *ch = *(tUDI_Channel**)channel;
62         
63         tUDI_DriverRegion       *rgn = inst->Regions[region];
64         
65         udi_ops_init_t *ops = UDI_int_GetOps(inst, ops_idx);
66         if( !ops ) {
67                 Log_Warning("UDI", "Ops ID invalid for '%s' (%i)", inst->Module, ops_idx);
68                 return 1;
69         }
70
71         tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, ops->meta_idx);
72         if( ops_ml != ch->MetaLang ) {
73                 Log_Warning("UDI", "Attempt by %s to bind with mismatched channel '%s' op '%s' channel",
74                         inst->Module, ops_ml->Name, ch->MetaLang->Name);
75                 return 3;
76         }
77
78         void *context;
79         if( ops->chan_context_size ) {
80                 context = malloc( ops->chan_context_size );
81                 ((udi_chan_context_t*)context)->rdata = rgn->InitContext;
82         }
83         else {
84                 context = rgn->InitContext;
85         }
86         
87         UDI_BindChannel_Raw(channel, other_side, ops->meta_ops_num, context, ops->ops_vector);
88         return 0;
89 }
90
91 /**
92  * \brief Prepare a cb for a channel call
93  * \param gcb   Generic control block for this request
94  * \param metalang      UDI metalanguage (used for validation)
95  * \return Pointer to ops list
96  * \retval NULL Metalangage validation failed
97  *
98  * Updates the channel and context fields of the gcb, checks the metalanguage and returns
99  * the handler list for the other end of the channel.
100  */
101 const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num)
102 {
103         ASSERT(gcb);
104         ASSERT(gcb->channel);
105         tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
106         ASSERT(ch);
107
108         // TODO: Allow calls without auto-lock
109         #if LOCK_CHANNELS
110         if( ch->Locked ) {
111                 Log_Warning("UDI", "Channel %s:%i used while blocked (before handler was fired)",
112                         ch->MetaLang->Name, meta_ops_num);
113                 return NULL;
114         }       
115         ch->Locked = true;
116         #endif
117         
118         struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
119         if( metalang == NULL )
120         {
121                 if( ch->MetaLang == &cMetaLang_Management ) {
122                         Log_Warning("UDI", "Invalid udi_channel_event_ind on Management metalang");
123                         return NULL;
124                 }
125         }
126         else
127         {
128                 if( ch->MetaLang != metalang || newside->MetaOpsNum != meta_ops_num ) {
129                         Log_Warning("UDI", "Metalanguage mismatch %s:%i req != %s:%i ch",
130                                 metalang->Name, meta_ops_num,
131                                 ch->MetaLang->Name, newside->MetaOpsNum);
132                         return NULL;
133                 }
134         }
135
136         gcb->channel = (udi_channel_t)&newside->BackPtr;
137         gcb->context = newside->Context;
138         if( !newside->Ops ) {
139                 Log_Warning("UDI", "Target end of %p(%s:%i) is unbound",
140                         ch, ch->MetaLang->Name, newside->MetaOpsNum);
141         }
142         return newside->Ops;
143 }
144
145 void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb)
146 {
147         #if LOCK_CHANNELS
148         ASSERT(gcb);
149         ASSERT(gcb->channel);
150         tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
151         ASSERT(ch);
152         
153         ch->Locked = false;
154         #endif
155 }
156

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