blob: 51420999418d8bdaf4ad7ad06a845ba029196902 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
Joe Perches475be4d2012-02-19 19:52:38 -08003 Copyright (c) Eicon Networks, 2002.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Joe Perches475be4d2012-02-19 19:52:38 -08005 This source file is supplied for the use with
6 Eicon Networks range of DIVA Server Adapters.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Joe Perches475be4d2012-02-19 19:52:38 -08008 Eicon File Revision : 2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
Joe Perches475be4d2012-02-19 19:52:38 -080010 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
Joe Perches475be4d2012-02-19 19:52:38 -080015 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Joe Perches475be4d2012-02-19 19:52:38 -080020 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 *
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/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080032 Adapter array change notification framework
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 -------------------------------------------------------------------------- */
34typedef struct _didd_adapter_change_notification {
Joe Perches475be4d2012-02-19 19:52:38 -080035 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define DIVA_DIDD_MAX_NOTIFICATIONS 256
Joe Perches475be4d2012-02-19 19:52:38 -080040static didd_adapter_change_notification_t \
41NotificationTable[DIVA_DIDD_MAX_NOTIFICATIONS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070042/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080043 Array to held adapter information
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 -------------------------------------------------------------------------- */
45static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS];
Adrian Bunkaade0e82005-06-28 20:44:56 -070046static dword Adapters = 0; /* Number of adapters */
Linus Torvalds1da177e2005-04-16 15:20:36 -070047/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080048 Shadow IDI_DIMAINT
49 and 'shadow' debug stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 -------------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -080051static void no_printf(unsigned char *format, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052{
53#ifdef EBUG
54 va_list ap;
Joe Perches475be4d2012-02-19 19:52:38 -080055 va_start(ap, format);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 debug((format, ap));
Joe Perches475be4d2012-02-19 19:52:38 -080057 va_end(ap);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#endif
59}
60
61/* -------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080062 Portable debug Library
63 ------------------------------------------------------------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include "debuglib.c"
Joe Perches475be4d2012-02-19 19:52:38 -080065
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static DESCRIPTOR MAdapter = {IDI_DIMAINT, /* Adapter Type */
Joe Perches475be4d2012-02-19 19:52:38 -080067 0x00, /* Channels */
68 0x0000, /* Features */
69 (IDI_CALL)no_printf};
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080071 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 -------------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -080075static void IDI_CALL_LINK_T diva_dadapter_request(ENTITY IDI_CALL_ENTITY_T *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static DESCRIPTOR DAdapter = {IDI_DADAPTER, /* Adapter Type */
Joe Perches475be4d2012-02-19 19:52:38 -080077 0x00, /* Channels */
78 0x0000, /* Features */
79 diva_dadapter_request };
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080081 LOCALS
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 -------------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -080083static dword diva_register_adapter_callback(\
84 didd_adapter_change_callback_t callback,
85 void IDI_CALL_ENTITY_T *context);
86static void diva_remove_adapter_callback(dword handle);
87static void diva_notify_adapter_change(DESCRIPTOR *d, int removal);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static diva_os_spin_lock_t didd_spin;
89/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080090 Should be called as first step, after driver init
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 -------------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -080092void 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -080098 Should be called as last step, if driver does unload
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 -------------------------------------------------------------------------- */
Joe Perches475be4d2012-02-19 19:52:38 -0800100void diva_didd_load_time_finit(void) {
101 diva_os_destroy_spin_lock(&didd_spin, "didd");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -0800104 Called in order to register new adapter in adapter array
105 return adapter handle (> 0) on success
106 return -1 adapter array overflow
107 -------------------------------------------------------------------------- */
108static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -0800141 Called in order to remove one registered adapter from array
142 return adapter handle (> 0) on success
143 return 0 on success
144 -------------------------------------------------------------------------- */
145static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -0800170 Read adapter array
171 return 1 if not enough space to save all available adapters
172 -------------------------------------------------------------------------- */
173static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205/* --------------------------------------------------------------------------
Joe Perches475be4d2012-02-19 19:52:38 -0800206 DAdapter request function.
207 This function does process only synchronous requests, and is used
208 for reception/registration of new interfaces
209 -------------------------------------------------------------------------- */
210static 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 }
264}
265/* --------------------------------------------------------------------------
266 IDI client does register his notification function
267 -------------------------------------------------------------------------- */
268static 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);
287}
288/* --------------------------------------------------------------------------
289 IDI client does register his notification function
290 -------------------------------------------------------------------------- */
291static 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 }
303/* --------------------------------------------------------------------------
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 -------------------------------------------------------------------------- */
309static 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 }
325}
326/* --------------------------------------------------------------------------
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:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 buffer - pointer to buffer that will receive adapter array
338 length - length (in bytes) of space in buffer
Joe Perches475be4d2012-02-19 19:52:38 -0800339 OUTPUT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 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
Joe Perches475be4d2012-02-19 19:52:38 -0800345 *NOTE 1 (debug interface):
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 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:
Joe Perches475be4d2012-02-19 19:52:38 -0800352 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 This approach does allow to load/unload debug interface on demand,
359 and save memory, it it is necessary.
Joe Perches475be4d2012-02-19 19:52:38 -0800360 -------------------------------------------------------------------------- */
361void IDI_CALL_LINK_T DIVA_DIDD_Read(void IDI_CALL_ENTITY_T *buffer,
362 int length) {
363 diva_didd_read_adapter_array(buffer, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}