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