Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * | |
475be4d8 | 3 | Copyright (c) Eicon Networks, 2002. |
1da177e4 | 4 | * |
475be4d8 JP |
5 | This source file is supplied for the use with |
6 | Eicon Networks range of DIVA Server Adapters. | |
1da177e4 | 7 | * |
475be4d8 | 8 | Eicon File Revision : 2.1 |
1da177e4 | 9 | * |
475be4d8 JP |
10 | This program is free software; you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2, or (at your option) | |
13 | any later version. | |
1da177e4 | 14 | * |
475be4d8 JP |
15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY | |
17 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
18 | See the GNU General Public License for more details. | |
1da177e4 | 19 | * |
475be4d8 JP |
20 | You should have received a copy of the GNU General Public License |
21 | along with this program; if not, write to the Free Software | |
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
1da177e4 LT |
23 | * |
24 | */ | |
25 | #include "platform.h" | |
26 | #include "pc.h" | |
27 | #include "debuglib.h" | |
28 | #include "di_defs.h" | |
29 | #include "divasync.h" | |
30 | #include "dadapter.h" | |
31 | /* -------------------------------------------------------------------------- | |
475be4d8 | 32 | Adapter array change notification framework |
1da177e4 LT |
33 | -------------------------------------------------------------------------- */ |
34 | typedef struct _didd_adapter_change_notification { | |
475be4d8 JP |
35 | didd_adapter_change_callback_t callback; |
36 | void IDI_CALL_ENTITY_T *context; | |
37 | } didd_adapter_change_notification_t, \ | |
38 | * IDI_CALL_ENTITY_T pdidd_adapter_change_notification_t; | |
1da177e4 | 39 | #define DIVA_DIDD_MAX_NOTIFICATIONS 256 |
475be4d8 JP |
40 | static didd_adapter_change_notification_t \ |
41 | NotificationTable[DIVA_DIDD_MAX_NOTIFICATIONS]; | |
1da177e4 | 42 | /* -------------------------------------------------------------------------- |
475be4d8 | 43 | Array to held adapter information |
1da177e4 LT |
44 | -------------------------------------------------------------------------- */ |
45 | static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS]; | |
aade0e82 | 46 | static dword Adapters = 0; /* Number of adapters */ |
1da177e4 | 47 | /* -------------------------------------------------------------------------- |
475be4d8 JP |
48 | Shadow IDI_DIMAINT |
49 | and 'shadow' debug stuff | |
1da177e4 | 50 | -------------------------------------------------------------------------- */ |
475be4d8 | 51 | static void no_printf(unsigned char *format, ...) |
1da177e4 LT |
52 | { |
53 | #ifdef EBUG | |
54 | va_list ap; | |
475be4d8 | 55 | va_start(ap, format); |
1da177e4 | 56 | debug((format, ap)); |
475be4d8 | 57 | va_end(ap); |
1da177e4 LT |
58 | #endif |
59 | } | |
60 | ||
61 | /* ------------------------------------------------------------------------- | |
475be4d8 JP |
62 | Portable debug Library |
63 | ------------------------------------------------------------------------- */ | |
1da177e4 | 64 | #include "debuglib.c" |
475be4d8 | 65 | |
1da177e4 | 66 | static DESCRIPTOR MAdapter = {IDI_DIMAINT, /* Adapter Type */ |
475be4d8 JP |
67 | 0x00, /* Channels */ |
68 | 0x0000, /* Features */ | |
69 | (IDI_CALL)no_printf}; | |
1da177e4 | 70 | /* -------------------------------------------------------------------------- |
475be4d8 JP |
71 | DAdapter. Only IDI clients with buffer, that is huge enough to |
72 | get all descriptors will receive information about DAdapter | |
73 | { byte type, byte channels, word features, IDI_CALL request } | |
1da177e4 | 74 | -------------------------------------------------------------------------- */ |
475be4d8 | 75 | static void IDI_CALL_LINK_T diva_dadapter_request(ENTITY IDI_CALL_ENTITY_T *); |
1da177e4 | 76 | static DESCRIPTOR DAdapter = {IDI_DADAPTER, /* Adapter Type */ |
475be4d8 JP |
77 | 0x00, /* Channels */ |
78 | 0x0000, /* Features */ | |
79 | diva_dadapter_request }; | |
1da177e4 | 80 | /* -------------------------------------------------------------------------- |
475be4d8 | 81 | LOCALS |
1da177e4 | 82 | -------------------------------------------------------------------------- */ |
475be4d8 JP |
83 | static dword diva_register_adapter_callback(\ |
84 | didd_adapter_change_callback_t callback, | |
85 | void IDI_CALL_ENTITY_T *context); | |
86 | static void diva_remove_adapter_callback(dword handle); | |
87 | static void diva_notify_adapter_change(DESCRIPTOR *d, int removal); | |
1da177e4 LT |
88 | static diva_os_spin_lock_t didd_spin; |
89 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
90 | Should be called as first step, after driver init |
91 | -------------------------------------------------------------------------- */ | |
92 | void diva_didd_load_time_init(void) { | |
93 | memset(&HandleTable[0], 0x00, sizeof(HandleTable)); | |
94 | memset(&NotificationTable[0], 0x00, sizeof(NotificationTable)); | |
95 | diva_os_initialize_spin_lock(&didd_spin, "didd"); | |
1da177e4 LT |
96 | } |
97 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
98 | Should be called as last step, if driver does unload |
99 | -------------------------------------------------------------------------- */ | |
100 | void diva_didd_load_time_finit(void) { | |
101 | diva_os_destroy_spin_lock(&didd_spin, "didd"); | |
1da177e4 LT |
102 | } |
103 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
104 | Called in order to register new adapter in adapter array |
105 | return adapter handle (> 0) on success | |
106 | return -1 adapter array overflow | |
107 | -------------------------------------------------------------------------- */ | |
108 | static int diva_didd_add_descriptor(DESCRIPTOR *d) { | |
109 | diva_os_spin_lock_magic_t irql; | |
110 | int i; | |
111 | if (d->type == IDI_DIMAINT) { | |
112 | if (d->request) { | |
113 | MAdapter.request = d->request; | |
114 | dprintf = (DIVA_DI_PRINTF)d->request; | |
115 | diva_notify_adapter_change(&MAdapter, 0); /* Inserted */ | |
116 | DBG_TRC(("DIMAINT registered, dprintf=%08x", d->request)) | |
117 | } else { | |
118 | DBG_TRC(("DIMAINT removed")) | |
119 | diva_notify_adapter_change(&MAdapter, 1); /* About to remove */ | |
120 | MAdapter.request = (IDI_CALL)no_printf; | |
121 | dprintf = no_printf; | |
122 | } | |
123 | return (NEW_MAX_DESCRIPTORS); | |
124 | } | |
125 | for (i = 0; i < NEW_MAX_DESCRIPTORS; i++) { | |
126 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_add"); | |
127 | if (HandleTable[i].type == 0) { | |
128 | memcpy(&HandleTable[i], d, sizeof(*d)); | |
129 | Adapters++; | |
130 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_add"); | |
131 | diva_notify_adapter_change(d, 0); /* we have new adapter */ | |
132 | DBG_TRC(("Add adapter[%d], request=%08x", (i + 1), d->request)) | |
133 | return (i + 1); | |
134 | } | |
135 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_add"); | |
136 | } | |
137 | DBG_ERR(("Can't add adapter, out of resources")) | |
138 | return (-1); | |
1da177e4 LT |
139 | } |
140 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
141 | Called in order to remove one registered adapter from array |
142 | return adapter handle (> 0) on success | |
143 | return 0 on success | |
144 | -------------------------------------------------------------------------- */ | |
145 | static int diva_didd_remove_descriptor(IDI_CALL request) { | |
146 | diva_os_spin_lock_magic_t irql; | |
147 | int i; | |
148 | if (request == MAdapter.request) { | |
149 | DBG_TRC(("DIMAINT removed")) | |
150 | dprintf = no_printf; | |
151 | diva_notify_adapter_change(&MAdapter, 1); /* About to remove */ | |
152 | MAdapter.request = (IDI_CALL)no_printf; | |
153 | return (0); | |
154 | } | |
155 | for (i = 0; (Adapters && (i < NEW_MAX_DESCRIPTORS)); i++) { | |
156 | if (HandleTable[i].request == request) { | |
157 | diva_notify_adapter_change(&HandleTable[i], 1); /* About to remove */ | |
158 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_rm"); | |
159 | memset(&HandleTable[i], 0x00, sizeof(HandleTable[0])); | |
160 | Adapters--; | |
161 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_rm"); | |
162 | DBG_TRC(("Remove adapter[%d], request=%08x", (i + 1), request)) | |
163 | return (0); | |
164 | } | |
165 | } | |
166 | DBG_ERR(("Invalid request=%08x, can't remove adapter", request)) | |
167 | return (-1); | |
1da177e4 LT |
168 | } |
169 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
170 | Read adapter array |
171 | return 1 if not enough space to save all available adapters | |
1da177e4 | 172 | -------------------------------------------------------------------------- */ |
475be4d8 JP |
173 | static int diva_didd_read_adapter_array(DESCRIPTOR *buffer, int length) { |
174 | diva_os_spin_lock_magic_t irql; | |
175 | int src, dst; | |
176 | memset(buffer, 0x00, length); | |
177 | length /= sizeof(DESCRIPTOR); | |
178 | DBG_TRC(("DIDD_Read, space = %d, Adapters = %d", length, Adapters + 2)) | |
179 | ||
180 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_read"); | |
181 | for (src = 0, dst = 0; | |
182 | (Adapters && (src < NEW_MAX_DESCRIPTORS) && (dst < length)); | |
183 | src++) { | |
184 | if (HandleTable[src].type) { | |
185 | memcpy(&buffer[dst], &HandleTable[src], sizeof(DESCRIPTOR)); | |
186 | dst++; | |
187 | } | |
188 | } | |
189 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_read"); | |
190 | if (dst < length) { | |
191 | memcpy(&buffer[dst], &MAdapter, sizeof(DESCRIPTOR)); | |
192 | dst++; | |
193 | } else { | |
194 | DBG_ERR(("Can't write DIMAINT. Array too small")) | |
195 | } | |
196 | if (dst < length) { | |
197 | memcpy(&buffer[dst], &DAdapter, sizeof(DESCRIPTOR)); | |
198 | dst++; | |
199 | } else { | |
200 | DBG_ERR(("Can't write DADAPTER. Array too small")) | |
201 | } | |
202 | DBG_TRC(("Read %d adapters", dst)) | |
203 | return (dst == length); | |
1da177e4 LT |
204 | } |
205 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
206 | DAdapter request function. |
207 | This function does process only synchronous requests, and is used | |
208 | for reception/registration of new interfaces | |
1da177e4 | 209 | -------------------------------------------------------------------------- */ |
475be4d8 JP |
210 | static void IDI_CALL_LINK_T diva_dadapter_request( \ |
211 | ENTITY IDI_CALL_ENTITY_T *e) { | |
212 | IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e; | |
213 | if (e->Req) { /* We do not process it, also return error */ | |
214 | e->Rc = OUT_OF_RESOURCES; | |
215 | DBG_ERR(("Can't process async request, Req=%02x", e->Req)) | |
216 | return; | |
217 | } | |
218 | /* | |
219 | So, we process sync request | |
220 | */ | |
221 | switch (e->Rc) { | |
222 | case IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY: { | |
223 | diva_didd_adapter_notify_t *pinfo = &syncReq->didd_notify.info; | |
224 | pinfo->handle = diva_register_adapter_callback( \ | |
225 | (didd_adapter_change_callback_t)pinfo->callback, | |
226 | (void IDI_CALL_ENTITY_T *)pinfo->context); | |
227 | e->Rc = 0xff; | |
228 | } break; | |
229 | case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY: { | |
230 | diva_didd_adapter_notify_t *pinfo = &syncReq->didd_notify.info; | |
231 | diva_remove_adapter_callback(pinfo->handle); | |
232 | e->Rc = 0xff; | |
233 | } break; | |
234 | case IDI_SYNC_REQ_DIDD_ADD_ADAPTER: { | |
235 | diva_didd_add_adapter_t *pinfo = &syncReq->didd_add_adapter.info; | |
236 | if (diva_didd_add_descriptor((DESCRIPTOR *)pinfo->descriptor) < 0) { | |
237 | e->Rc = OUT_OF_RESOURCES; | |
238 | } else { | |
239 | e->Rc = 0xff; | |
240 | } | |
241 | } break; | |
242 | case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER: { | |
243 | diva_didd_remove_adapter_t *pinfo = &syncReq->didd_remove_adapter.info; | |
244 | if (diva_didd_remove_descriptor((IDI_CALL)pinfo->p_request) < 0) { | |
245 | e->Rc = OUT_OF_RESOURCES; | |
246 | } else { | |
247 | e->Rc = 0xff; | |
248 | } | |
249 | } break; | |
250 | case IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY: { | |
251 | diva_didd_read_adapter_array_t *pinfo =\ | |
252 | &syncReq->didd_read_adapter_array.info; | |
253 | if (diva_didd_read_adapter_array((DESCRIPTOR *)pinfo->buffer, | |
254 | (int)pinfo->length)) { | |
255 | e->Rc = OUT_OF_RESOURCES; | |
256 | } else { | |
257 | e->Rc = 0xff; | |
258 | } | |
259 | } break; | |
260 | default: | |
261 | DBG_ERR(("Can't process sync request, Req=%02x", e->Rc)) | |
262 | e->Rc = OUT_OF_RESOURCES; | |
263 | } | |
1da177e4 LT |
264 | } |
265 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
266 | IDI client does register his notification function |
267 | -------------------------------------------------------------------------- */ | |
268 | static dword diva_register_adapter_callback( \ | |
269 | didd_adapter_change_callback_t callback, | |
270 | void IDI_CALL_ENTITY_T *context) { | |
271 | diva_os_spin_lock_magic_t irql; | |
272 | dword i; | |
273 | ||
274 | for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) { | |
275 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_nfy_add"); | |
276 | if (!NotificationTable[i].callback) { | |
277 | NotificationTable[i].callback = callback; | |
278 | NotificationTable[i].context = context; | |
279 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_nfy_add"); | |
280 | DBG_TRC(("Register adapter notification[%d]=%08x", i + 1, callback)) | |
281 | return (i + 1); | |
282 | } | |
283 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_nfy_add"); | |
284 | } | |
285 | DBG_ERR(("Can't register adapter notification, overflow")) | |
286 | return (0); | |
1da177e4 LT |
287 | } |
288 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
289 | IDI client does register his notification function |
290 | -------------------------------------------------------------------------- */ | |
291 | static void diva_remove_adapter_callback(dword handle) { | |
292 | diva_os_spin_lock_magic_t irql; | |
293 | if (handle && ((--handle) < DIVA_DIDD_MAX_NOTIFICATIONS)) { | |
294 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_nfy_rm"); | |
295 | NotificationTable[handle].callback = NULL; | |
296 | NotificationTable[handle].context = NULL; | |
297 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_nfy_rm"); | |
298 | DBG_TRC(("Remove adapter notification[%d]", (int)(handle + 1))) | |
299 | return; | |
300 | } | |
301 | DBG_ERR(("Can't remove adapter notification, handle=%d", handle)) | |
302 | } | |
1da177e4 | 303 | /* -------------------------------------------------------------------------- |
475be4d8 JP |
304 | Notify all client about adapter array change |
305 | Does suppose following behavior in the client side: | |
306 | Step 1: Redister Notification | |
307 | Step 2: Read Adapter Array | |
308 | -------------------------------------------------------------------------- */ | |
309 | static void diva_notify_adapter_change(DESCRIPTOR *d, int removal) { | |
310 | int i, do_notify; | |
311 | didd_adapter_change_notification_t nfy; | |
312 | diva_os_spin_lock_magic_t irql; | |
313 | for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) { | |
314 | do_notify = 0; | |
315 | diva_os_enter_spin_lock(&didd_spin, &irql, "didd_nfy"); | |
316 | if (NotificationTable[i].callback) { | |
317 | memcpy(&nfy, &NotificationTable[i], sizeof(nfy)); | |
318 | do_notify = 1; | |
319 | } | |
320 | diva_os_leave_spin_lock(&didd_spin, &irql, "didd_nfy"); | |
321 | if (do_notify) { | |
322 | (*(nfy.callback))(nfy.context, d, removal); | |
323 | } | |
324 | } | |
1da177e4 LT |
325 | } |
326 | /* -------------------------------------------------------------------------- | |
475be4d8 JP |
327 | For all systems, that are linked by Kernel Mode Linker this is ONLY one |
328 | function thet should be exported by this device driver | |
329 | IDI clients should look for IDI_DADAPTER, and use request function | |
330 | of this adapter (sync request) in order to receive appropriate services: | |
331 | - add new adapter | |
332 | - remove existing adapter | |
333 | - add adapter array notification | |
334 | - remove adapter array notification | |
335 | (read adapter is redundant in this case) | |
336 | INPUT: | |
1da177e4 LT |
337 | buffer - pointer to buffer that will receive adapter array |
338 | length - length (in bytes) of space in buffer | |
475be4d8 | 339 | OUTPUT: |
1da177e4 LT |
340 | Adapter array will be written to memory described by 'buffer' |
341 | If the last adapter seen in the returned adapter array is | |
342 | IDI_DADAPTER or if last adapter in array does have type '0', then | |
343 | it was enougth space in buffer to accommodate all available | |
344 | adapter descriptors | |
475be4d8 | 345 | *NOTE 1 (debug interface): |
1da177e4 LT |
346 | The IDI adapter of type 'IDI_DIMAINT' does register as 'request' |
347 | famous 'dprintf' function (of type DI_PRINTF, please look | |
348 | include/debuglib.c and include/debuglib.h) for details. | |
349 | So dprintf is not exported from module debug module directly, | |
350 | instead of this IDI_DIMAINT is registered. | |
351 | Module load order will receive in this case: | |
475be4d8 JP |
352 | 1. DIDD (this file) |
353 | 2. DIMAINT does load and register 'IDI_DIMAINT', at this step | |
354 | DIDD should be able to get 'dprintf', save it, and | |
355 | register with DIDD by means of 'dprintf' function. | |
356 | 3. any other driver is loaded and is able to access adapter array | |
357 | and debug interface | |
1da177e4 LT |
358 | This approach does allow to load/unload debug interface on demand, |
359 | and save memory, it it is necessary. | |
475be4d8 JP |
360 | -------------------------------------------------------------------------- */ |
361 | void IDI_CALL_LINK_T DIVA_DIDD_Read(void IDI_CALL_ENTITY_T *buffer, | |
362 | int length) { | |
363 | diva_didd_read_adapter_array(buffer, length); | |
1da177e4 | 364 | } |