Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $ |
| 2 | * |
| 3 | * ISDN interface module for Eicon active cards DIVA. |
| 4 | * CAPI Interface common functions |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 5 | * |
| 6 | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 8 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | * This software may be used and distributed according to the terms |
| 10 | * of the GNU General Public License, incorporated herein by reference. |
| 11 | * |
| 12 | */ |
| 13 | |
| 14 | #include "platform.h" |
| 15 | #include "os_capi.h" |
| 16 | #include "di_defs.h" |
| 17 | #include "capi20.h" |
| 18 | #include "divacapi.h" |
| 19 | #include "divasync.h" |
| 20 | #include "capifunc.h" |
| 21 | |
| 22 | #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) |
| 23 | #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) |
| 24 | |
| 25 | DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL; |
| 26 | APPL *application = (APPL *) NULL; |
| 27 | byte max_appl = MAX_APPL; |
| 28 | byte max_adapter = 0; |
| 29 | static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL; |
| 30 | |
| 31 | byte UnMapController(byte); |
| 32 | char DRIVERRELEASE_CAPI[32]; |
| 33 | |
| 34 | extern void AutomaticLaw(DIVA_CAPI_ADAPTER *); |
| 35 | extern void callback(ENTITY *); |
| 36 | extern word api_remove_start(void); |
| 37 | extern word CapiRelease(word); |
| 38 | extern word CapiRegister(word); |
| 39 | extern word api_put(APPL *, CAPI_MSG *); |
| 40 | |
| 41 | static diva_os_spin_lock_t api_lock; |
| 42 | |
| 43 | static LIST_HEAD(cards); |
| 44 | |
| 45 | static dword notify_handle; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 46 | static void DIRequest(ENTITY *e); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | static DESCRIPTOR MAdapter; |
| 48 | static DESCRIPTOR DAdapter; |
| 49 | static byte ControllerMap[MAX_DESCRIPTORS + 1]; |
| 50 | |
| 51 | |
| 52 | static void diva_register_appl(struct capi_ctr *, __u16, |
| 53 | capi_register_params *); |
| 54 | static void diva_release_appl(struct capi_ctr *, __u16); |
| 55 | static char *diva_procinfo(struct capi_ctr *); |
| 56 | static u16 diva_send_message(struct capi_ctr *, |
| 57 | diva_os_message_buffer_s *); |
| 58 | extern void diva_os_set_controller_struct(struct capi_ctr *); |
| 59 | |
| 60 | extern void DIVA_DIDD_Read(DESCRIPTOR *, int); |
| 61 | |
| 62 | /* |
| 63 | * debug |
| 64 | */ |
| 65 | static void no_printf(unsigned char *, ...); |
| 66 | #include "debuglib.c" |
| 67 | static void xlog(char *x, ...) |
| 68 | { |
| 69 | #ifndef DIVA_NO_DEBUGLIB |
| 70 | va_list ap; |
| 71 | if (myDriverDebugHandle.dbgMask & DL_XLOG) { |
| 72 | va_start(ap, x); |
| 73 | if (myDriverDebugHandle.dbg_irq) { |
| 74 | myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id, |
| 75 | DLI_XLOG, x, ap); |
| 76 | } else if (myDriverDebugHandle.dbg_old) { |
| 77 | myDriverDebugHandle.dbg_old(myDriverDebugHandle.id, |
| 78 | x, ap); |
| 79 | } |
| 80 | va_end(ap); |
| 81 | } |
| 82 | #endif |
| 83 | } |
| 84 | |
| 85 | /* |
| 86 | * info for proc |
| 87 | */ |
| 88 | static char *diva_procinfo(struct capi_ctr *ctrl) |
| 89 | { |
| 90 | return (ctrl->serial); |
| 91 | } |
| 92 | |
| 93 | /* |
| 94 | * stop debugging |
| 95 | */ |
| 96 | static void stop_dbg(void) |
| 97 | { |
| 98 | DbgDeregister(); |
| 99 | memset(&MAdapter, 0, sizeof(MAdapter)); |
| 100 | dprintf = no_printf; |
| 101 | } |
| 102 | |
| 103 | /* |
| 104 | * dummy debug function |
| 105 | */ |
| 106 | static void no_printf(unsigned char *x, ...) |
| 107 | { |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | * Controller mapping |
| 112 | */ |
| 113 | byte MapController(byte Controller) |
| 114 | { |
| 115 | byte i; |
| 116 | byte MappedController = 0; |
| 117 | byte ctrl = Controller & 0x7f; /* mask external controller bit off */ |
| 118 | |
| 119 | for (i = 1; i < max_adapter + 1; i++) { |
| 120 | if (ctrl == ControllerMap[i]) { |
| 121 | MappedController = (byte) i; |
| 122 | break; |
| 123 | } |
| 124 | } |
| 125 | if (i > max_adapter) { |
| 126 | ControllerMap[0] = ctrl; |
| 127 | MappedController = 0; |
| 128 | } |
| 129 | return (MappedController | (Controller & 0x80)); /* put back external controller bit */ |
| 130 | } |
| 131 | |
| 132 | /* |
| 133 | * Controller unmapping |
| 134 | */ |
| 135 | byte UnMapController(byte MappedController) |
| 136 | { |
| 137 | byte Controller; |
| 138 | byte ctrl = MappedController & 0x7f; /* mask external controller bit off */ |
| 139 | |
| 140 | if (ctrl <= max_adapter) { |
| 141 | Controller = ControllerMap[ctrl]; |
| 142 | } else { |
| 143 | Controller = 0; |
| 144 | } |
| 145 | |
| 146 | return (Controller | (MappedController & 0x80)); /* put back external controller bit */ |
| 147 | } |
| 148 | |
| 149 | /* |
| 150 | * find a new free id |
| 151 | */ |
| 152 | static int find_free_id(void) |
| 153 | { |
| 154 | int num = 0; |
| 155 | DIVA_CAPI_ADAPTER *a; |
| 156 | |
| 157 | while (num < MAX_DESCRIPTORS) { |
| 158 | a = &adapter[num]; |
| 159 | if (!a->Id) |
| 160 | break; |
| 161 | num++; |
| 162 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 163 | return (num + 1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | /* |
| 167 | * find a card structure by controller number |
| 168 | */ |
| 169 | static diva_card *find_card_by_ctrl(word controller) |
| 170 | { |
| 171 | struct list_head *tmp; |
| 172 | diva_card *card; |
| 173 | |
| 174 | list_for_each(tmp, &cards) { |
| 175 | card = list_entry(tmp, diva_card, list); |
| 176 | if (ControllerMap[card->Id] == controller) { |
| 177 | if (card->remove_in_progress) |
| 178 | card = NULL; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 179 | return (card); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 | } |
| 181 | } |
| 182 | return (diva_card *) 0; |
| 183 | } |
| 184 | |
| 185 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 186 | * Buffer RX/TX |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 188 | void *TransmitBufferSet(APPL *appl, dword ref) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | { |
Richard Knutsson | 986c4bb | 2007-02-12 00:53:24 -0800 | [diff] [blame] | 190 | appl->xbuffer_used[ref] = true; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 192 | return (void *)(long)ref; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 193 | } |
| 194 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 195 | void *TransmitBufferGet(APPL *appl, void *p) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 | { |
Andrew Morton | 241be8d | 2007-05-23 13:58:22 -0700 | [diff] [blame] | 197 | if (appl->xbuffer_internal[(dword)(long)p]) |
| 198 | return appl->xbuffer_internal[(dword)(long)p]; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 | |
Andrew Morton | 241be8d | 2007-05-23 13:58:22 -0700 | [diff] [blame] | 200 | return appl->xbuffer_ptr[(dword)(long)p]; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | } |
| 202 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 203 | void TransmitBufferFree(APPL *appl, void *p) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | { |
Andrew Morton | 241be8d | 2007-05-23 13:58:22 -0700 | [diff] [blame] | 205 | appl->xbuffer_used[(dword)(long)p] = false; |
| 206 | DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword)(long)p) + 1)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 207 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 209 | void *ReceiveBufferGet(APPL *appl, int Num) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 210 | { |
| 211 | return &appl->ReceiveBuffer[Num * appl->MaxDataLength]; |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | * api_remove_start/complete for cleanup |
| 216 | */ |
| 217 | void api_remove_complete(void) |
| 218 | { |
| 219 | DBG_PRV1(("api_remove_complete")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 220 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | |
| 222 | /* |
| 223 | * main function called by message.c |
| 224 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 225 | void sendf(APPL *appl, word command, dword Id, word Number, byte *format, ...) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 226 | { |
| 227 | word i, j; |
| 228 | word length = 12, dlength = 0; |
| 229 | byte *write; |
| 230 | CAPI_MSG msg; |
| 231 | byte *string = NULL; |
| 232 | va_list ap; |
| 233 | diva_os_message_buffer_s *dmb; |
| 234 | diva_card *card = NULL; |
| 235 | dword tmp; |
| 236 | |
| 237 | if (!appl) |
| 238 | return; |
| 239 | |
| 240 | DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)", |
| 241 | appl->Id, command, (byte *) format)) |
| 242 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 243 | PUT_WORD(&msg.header.appl_id, appl->Id); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 | PUT_WORD(&msg.header.command, command); |
| 245 | if ((byte) (command >> 8) == 0x82) |
| 246 | Number = appl->Number++; |
| 247 | PUT_WORD(&msg.header.number, Number); |
| 248 | |
| 249 | PUT_DWORD(&msg.header.controller, Id); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 250 | write = (byte *)&msg; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 | write += 12; |
| 252 | |
| 253 | va_start(ap, format); |
| 254 | for (i = 0; format[i]; i++) { |
| 255 | switch (format[i]) { |
| 256 | case 'b': |
| 257 | tmp = va_arg(ap, dword); |
| 258 | *(byte *) write = (byte) (tmp & 0xff); |
| 259 | write += 1; |
| 260 | length += 1; |
| 261 | break; |
| 262 | case 'w': |
| 263 | tmp = va_arg(ap, dword); |
| 264 | PUT_WORD(write, (tmp & 0xffff)); |
| 265 | write += 2; |
| 266 | length += 2; |
| 267 | break; |
| 268 | case 'd': |
| 269 | tmp = va_arg(ap, dword); |
| 270 | PUT_DWORD(write, tmp); |
| 271 | write += 4; |
| 272 | length += 4; |
| 273 | break; |
| 274 | case 's': |
| 275 | case 'S': |
| 276 | string = va_arg(ap, byte *); |
| 277 | length += string[0] + 1; |
| 278 | for (j = 0; j <= string[0]; j++) |
| 279 | *write++ = string[j]; |
| 280 | break; |
| 281 | } |
| 282 | } |
| 283 | va_end(ap); |
| 284 | |
| 285 | PUT_WORD(&msg.header.length, length); |
| 286 | msg.header.controller = UnMapController(msg.header.controller); |
| 287 | |
| 288 | if (command == _DATA_B3_I) |
| 289 | dlength = GET_WORD( |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 290 | ((byte *)&msg.info.data_b3_ind.Data_Length)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 291 | |
| 292 | if (!(dmb = diva_os_alloc_message_buffer(length + dlength, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 293 | (void **) &write))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 294 | DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 295 | return; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | /* copy msg header to sk_buff */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 299 | memcpy(write, (byte *)&msg, length); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 300 | |
| 301 | /* if DATA_B3_IND, copy data too */ |
| 302 | if (command == _DATA_B3_I) { |
| 303 | dword data = GET_DWORD(&msg.info.data_b3_ind.Data); |
Andrew Morton | 241be8d | 2007-05-23 13:58:22 -0700 | [diff] [blame] | 304 | memcpy(write + length, (void *)(long)data, dlength); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | #ifndef DIVA_NO_DEBUGLIB |
| 308 | if (myDriverDebugHandle.dbgMask & DL_XLOG) { |
| 309 | switch (command) { |
| 310 | default: |
| 311 | xlog("\x00\x02", &msg, 0x81, length); |
| 312 | break; |
| 313 | case _DATA_B3_R | CONFIRM: |
| 314 | if (myDriverDebugHandle.dbgMask & DL_BLK) |
| 315 | xlog("\x00\x02", &msg, 0x81, length); |
| 316 | break; |
| 317 | case _DATA_B3_I: |
| 318 | if (myDriverDebugHandle.dbgMask & DL_BLK) { |
| 319 | xlog("\x00\x02", &msg, 0x81, length); |
| 320 | for (i = 0; i < dlength; i += 256) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 321 | DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i, |
| 322 | ((dlength - i) < 256) ? (dlength - i) : 256)) |
| 323 | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) |
| 324 | break; /* not more if not explicitly requested */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 325 | } |
| 326 | } |
| 327 | break; |
| 328 | } |
| 329 | } |
| 330 | #endif |
| 331 | |
| 332 | /* find the card structure for this controller */ |
| 333 | if (!(card = find_card_by_ctrl(write[8] & 0x7f))) { |
| 334 | DBG_ERR(("sendf - controller %d not found, incoming msg dropped", |
| 335 | write[8] & 0x7f)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 336 | diva_os_free_message_buffer(dmb); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | return; |
| 338 | } |
| 339 | /* send capi msg to capi layer */ |
| 340 | capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb); |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | * cleanup adapter |
| 345 | */ |
| 346 | static void clean_adapter(int id, struct list_head *free_mem_q) |
| 347 | { |
| 348 | DIVA_CAPI_ADAPTER *a; |
| 349 | int i, k; |
| 350 | |
| 351 | a = &adapter[id]; |
| 352 | k = li_total_channels - a->li_channels; |
| 353 | if (k == 0) { |
| 354 | if (li_config_table) { |
| 355 | list_add((struct list_head *)li_config_table, free_mem_q); |
| 356 | li_config_table = NULL; |
| 357 | } |
| 358 | } else { |
| 359 | if (a->li_base < k) { |
| 360 | memmove(&li_config_table[a->li_base], |
| 361 | &li_config_table[a->li_base + a->li_channels], |
| 362 | (k - a->li_base) * sizeof(LI_CONFIG)); |
| 363 | for (i = 0; i < k; i++) { |
| 364 | memmove(&li_config_table[i].flag_table[a->li_base], |
| 365 | &li_config_table[i].flag_table[a->li_base + a->li_channels], |
| 366 | k - a->li_base); |
| 367 | memmove(&li_config_table[i]. |
| 368 | coef_table[a->li_base], |
| 369 | &li_config_table[i].coef_table[a->li_base + a->li_channels], |
| 370 | k - a->li_base); |
| 371 | } |
| 372 | } |
| 373 | } |
| 374 | li_total_channels = k; |
| 375 | for (i = id; i < max_adapter; i++) { |
| 376 | if (adapter[i].request) |
| 377 | adapter[i].li_base -= a->li_channels; |
| 378 | } |
| 379 | if (a->plci) |
| 380 | list_add((struct list_head *)a->plci, free_mem_q); |
| 381 | |
| 382 | memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER)); |
| 383 | while ((max_adapter != 0) && !adapter[max_adapter - 1].request) |
| 384 | max_adapter--; |
| 385 | } |
| 386 | |
| 387 | /* |
| 388 | * remove a card, but ensures consistent state of LI tables |
| 389 | * in the time adapter is removed |
| 390 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 391 | static void divacapi_remove_card(DESCRIPTOR *d) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 392 | { |
| 393 | diva_card *card = NULL; |
| 394 | diva_os_spin_lock_magic_t old_irql; |
| 395 | LIST_HEAD(free_mem_q); |
| 396 | struct list_head *link; |
| 397 | struct list_head *tmp; |
| 398 | |
| 399 | /* |
| 400 | * Set "remove in progress flag". |
| 401 | * Ensures that there is no call from sendf to CAPI in |
| 402 | * the time CAPI controller is about to be removed. |
| 403 | */ |
| 404 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); |
| 405 | list_for_each(tmp, &cards) { |
| 406 | card = list_entry(tmp, diva_card, list); |
| 407 | if (card->d.request == d->request) { |
| 408 | card->remove_in_progress = 1; |
| 409 | list_del(tmp); |
| 410 | break; |
| 411 | } |
| 412 | } |
| 413 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); |
| 414 | |
| 415 | if (card) { |
| 416 | /* |
| 417 | * Detach CAPI. Sendf cannot call to CAPI any more. |
| 418 | * After detach no call to send_message() is done too. |
| 419 | */ |
| 420 | detach_capi_ctr(&card->capi_ctrl); |
| 421 | |
| 422 | /* |
| 423 | * Now get API lock (to ensure stable state of LI tables) |
| 424 | * and update the adapter map/LI table. |
| 425 | */ |
| 426 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card"); |
| 427 | |
| 428 | clean_adapter(card->Id - 1, &free_mem_q); |
| 429 | DBG_TRC(("DelAdapterMap (%d) -> (%d)", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 430 | ControllerMap[card->Id], card->Id)) |
| 431 | ControllerMap[card->Id] = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 432 | DBG_TRC(("adapter remove, max_adapter=%d", |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 433 | max_adapter)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 434 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 435 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 436 | /* After releasing the lock, we can free the memory */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 437 | diva_os_free(0, card); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 438 | } |
| 439 | |
| 440 | /* free queued memory areas */ |
| 441 | list_for_each_safe(link, tmp, &free_mem_q) { |
| 442 | list_del(link); |
| 443 | diva_os_free(0, link); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | /* |
| 448 | * remove cards |
| 449 | */ |
| 450 | static void divacapi_remove_cards(void) |
| 451 | { |
| 452 | DESCRIPTOR d; |
| 453 | struct list_head *tmp; |
| 454 | diva_card *card; |
| 455 | diva_os_spin_lock_magic_t old_irql; |
| 456 | |
| 457 | rescan: |
| 458 | diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards"); |
| 459 | list_for_each(tmp, &cards) { |
| 460 | card = list_entry(tmp, diva_card, list); |
| 461 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); |
| 462 | d.request = card->d.request; |
| 463 | divacapi_remove_card(&d); |
| 464 | goto rescan; |
| 465 | } |
| 466 | diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards"); |
| 467 | } |
| 468 | |
| 469 | /* |
| 470 | * sync_callback |
| 471 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 472 | static void sync_callback(ENTITY *e) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 473 | { |
| 474 | diva_os_spin_lock_magic_t old_irql; |
| 475 | |
| 476 | DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind)) |
| 477 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 478 | diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 479 | callback(e); |
| 480 | diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback"); |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | * add a new card |
| 485 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 486 | static int diva_add_card(DESCRIPTOR *d) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 487 | { |
| 488 | int k = 0, i = 0; |
| 489 | diva_os_spin_lock_magic_t old_irql; |
| 490 | diva_card *card = NULL; |
| 491 | struct capi_ctr *ctrl = NULL; |
| 492 | DIVA_CAPI_ADAPTER *a = NULL; |
| 493 | IDI_SYNC_REQ sync_req; |
| 494 | char serial[16]; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 495 | void *mem_to_free; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 | LI_CONFIG *new_li_config_table; |
| 497 | int j; |
| 498 | |
| 499 | if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) { |
| 500 | DBG_ERR(("diva_add_card: failed to allocate card struct.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 501 | return (0); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 502 | } |
| 503 | memset((char *) card, 0x00, sizeof(diva_card)); |
| 504 | memcpy(&card->d, d, sizeof(DESCRIPTOR)); |
| 505 | sync_req.GetName.Req = 0; |
| 506 | sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 507 | card->d.request((ENTITY *)&sync_req); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 508 | strlcpy(card->name, sync_req.GetName.name, sizeof(card->name)); |
| 509 | ctrl = &card->capi_ctrl; |
| 510 | strcpy(ctrl->name, card->name); |
| 511 | ctrl->register_appl = diva_register_appl; |
| 512 | ctrl->release_appl = diva_release_appl; |
| 513 | ctrl->send_message = diva_send_message; |
| 514 | ctrl->procinfo = diva_procinfo; |
| 515 | ctrl->driverdata = card; |
| 516 | diva_os_set_controller_struct(ctrl); |
| 517 | |
| 518 | if (attach_capi_ctr(ctrl)) { |
| 519 | DBG_ERR(("diva_add_card: failed to attach controller.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 520 | diva_os_free(0, card); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 521 | return (0); |
| 522 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 523 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 524 | diva_os_enter_spin_lock(&api_lock, &old_irql, "find id"); |
| 525 | card->Id = find_free_id(); |
| 526 | diva_os_leave_spin_lock(&api_lock, &old_irql, "find id"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 527 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 528 | strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu)); |
| 529 | ctrl->version.majorversion = 2; |
| 530 | ctrl->version.minorversion = 0; |
| 531 | ctrl->version.majormanuversion = DRRELMAJOR; |
| 532 | ctrl->version.minormanuversion = DRRELMINOR; |
| 533 | sync_req.GetSerial.Req = 0; |
| 534 | sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL; |
| 535 | sync_req.GetSerial.serial = 0; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 536 | card->d.request((ENTITY *)&sync_req); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 537 | if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) { |
| 538 | sprintf(serial, "%ld-%d", |
| 539 | sync_req.GetSerial.serial & 0x00ffffff, i + 1); |
| 540 | } else { |
| 541 | sprintf(serial, "%ld", sync_req.GetSerial.serial); |
| 542 | } |
| 543 | serial[CAPI_SERIAL_LEN - 1] = 0; |
| 544 | strlcpy(ctrl->serial, serial, sizeof(ctrl->serial)); |
| 545 | |
| 546 | a = &adapter[card->Id - 1]; |
| 547 | card->adapter = a; |
| 548 | a->os_card = card; |
| 549 | ControllerMap[card->Id] = (byte) (ctrl->cnr); |
| 550 | |
| 551 | DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id)) |
| 552 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 553 | sync_req.xdi_capi_prms.Req = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 554 | sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS; |
| 555 | sync_req.xdi_capi_prms.info.structure_length = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 556 | sizeof(diva_xdi_get_capi_parameters_t); |
| 557 | card->d.request((ENTITY *)&sync_req); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 558 | a->flag_dynamic_l1_down = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 559 | sync_req.xdi_capi_prms.info.flag_dynamic_l1_down; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 | a->group_optimization_enabled = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 561 | sync_req.xdi_capi_prms.info.group_optimization_enabled; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 562 | a->request = DIRequest; /* card->d.request; */ |
| 563 | a->max_plci = card->d.channels + 30; |
| 564 | a->max_listen = (card->d.channels > 2) ? 8 : 2; |
| 565 | if (! |
| 566 | (a->plci = |
| 567 | (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) { |
| 568 | DBG_ERR(("diva_add_card: failed alloc plci struct.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 569 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 570 | return (0); |
| 571 | } |
| 572 | memset(a->plci, 0, sizeof(PLCI) * a->max_plci); |
| 573 | |
| 574 | for (k = 0; k < a->max_plci; k++) { |
| 575 | a->Id = (byte) card->Id; |
| 576 | a->plci[k].Sig.callback = sync_callback; |
| 577 | a->plci[k].Sig.XNum = 1; |
| 578 | a->plci[k].Sig.X = a->plci[k].XData; |
| 579 | a->plci[k].Sig.user[0] = (word) (card->Id - 1); |
| 580 | a->plci[k].Sig.user[1] = (word) k; |
| 581 | a->plci[k].NL.callback = sync_callback; |
| 582 | a->plci[k].NL.XNum = 1; |
| 583 | a->plci[k].NL.X = a->plci[k].XData; |
| 584 | a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000); |
| 585 | a->plci[k].NL.user[1] = (word) k; |
| 586 | a->plci[k].adapter = a; |
| 587 | } |
| 588 | |
| 589 | a->profile.Number = card->Id; |
| 590 | a->profile.Channels = card->d.channels; |
| 591 | if (card->d.features & DI_FAX3) { |
| 592 | a->profile.Global_Options = 0x71; |
| 593 | if (card->d.features & DI_CODEC) |
| 594 | a->profile.Global_Options |= 0x6; |
| 595 | #if IMPLEMENT_DTMF |
| 596 | a->profile.Global_Options |= 0x8; |
| 597 | #endif /* IMPLEMENT_DTMF */ |
| 598 | a->profile.Global_Options |= 0x80; /* Line Interconnect */ |
| 599 | #if IMPLEMENT_ECHO_CANCELLER |
| 600 | a->profile.Global_Options |= 0x100; |
| 601 | #endif /* IMPLEMENT_ECHO_CANCELLER */ |
| 602 | a->profile.B1_Protocols = 0xdf; |
| 603 | a->profile.B2_Protocols = 0x1fdb; |
| 604 | a->profile.B3_Protocols = 0xb7; |
| 605 | a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF; |
| 606 | } else { |
| 607 | a->profile.Global_Options = 0x71; |
| 608 | if (card->d.features & DI_CODEC) |
| 609 | a->profile.Global_Options |= 0x2; |
| 610 | a->profile.B1_Protocols = 0x43; |
| 611 | a->profile.B2_Protocols = 0x1f0f; |
| 612 | a->profile.B3_Protocols = 0x07; |
| 613 | a->manufacturer_features = 0; |
| 614 | } |
| 615 | |
| 616 | a->li_pri = (a->profile.Channels > 2); |
| 617 | a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI; |
| 618 | a->li_base = 0; |
| 619 | for (i = 0; &adapter[i] != a; i++) { |
| 620 | if (adapter[i].request) |
| 621 | a->li_base = adapter[i].li_base + adapter[i].li_channels; |
| 622 | } |
| 623 | k = li_total_channels + a->li_channels; |
| 624 | new_li_config_table = |
| 625 | (LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3)); |
| 626 | if (new_li_config_table == NULL) { |
| 627 | DBG_ERR(("diva_add_card: failed alloc li_config table.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 628 | memset(a, 0, sizeof(DIVA_CAPI_ADAPTER)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 629 | return (0); |
| 630 | } |
| 631 | |
| 632 | /* Prevent access to line interconnect table in process update */ |
| 633 | diva_os_enter_spin_lock(&api_lock, &old_irql, "add card"); |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 634 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 635 | j = 0; |
| 636 | for (i = 0; i < k; i++) { |
| 637 | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) |
| 638 | memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG)); |
| 639 | else |
| 640 | memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG)); |
| 641 | new_li_config_table[i].flag_table = |
| 642 | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3)); |
| 643 | new_li_config_table[i].coef_table = |
| 644 | ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3)); |
| 645 | if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) { |
| 646 | new_li_config_table[i].adapter = a; |
| 647 | memset(&new_li_config_table[i].flag_table[0], 0, k); |
| 648 | memset(&new_li_config_table[i].coef_table[0], 0, k); |
| 649 | } else { |
| 650 | if (a->li_base != 0) { |
| 651 | memcpy(&new_li_config_table[i].flag_table[0], |
| 652 | &li_config_table[j].flag_table[0], |
| 653 | a->li_base); |
| 654 | memcpy(&new_li_config_table[i].coef_table[0], |
| 655 | &li_config_table[j].coef_table[0], |
| 656 | a->li_base); |
| 657 | } |
| 658 | memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels); |
| 659 | memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels); |
| 660 | if (a->li_base + a->li_channels < k) { |
| 661 | memcpy(&new_li_config_table[i].flag_table[a->li_base + |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 662 | a->li_channels], |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 663 | &li_config_table[j].flag_table[a->li_base], |
| 664 | k - (a->li_base + a->li_channels)); |
| 665 | memcpy(&new_li_config_table[i].coef_table[a->li_base + |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 666 | a->li_channels], |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 667 | &li_config_table[j].coef_table[a->li_base], |
| 668 | k - (a->li_base + a->li_channels)); |
| 669 | } |
| 670 | j++; |
| 671 | } |
| 672 | } |
| 673 | li_total_channels = k; |
| 674 | |
| 675 | mem_to_free = li_config_table; |
| 676 | |
| 677 | li_config_table = new_li_config_table; |
| 678 | for (i = card->Id; i < max_adapter; i++) { |
| 679 | if (adapter[i].request) |
| 680 | adapter[i].li_base += a->li_channels; |
| 681 | } |
| 682 | |
| 683 | if (a == &adapter[max_adapter]) |
| 684 | max_adapter++; |
| 685 | |
| 686 | list_add(&(card->list), &cards); |
| 687 | AutomaticLaw(a); |
| 688 | |
| 689 | diva_os_leave_spin_lock(&api_lock, &old_irql, "add card"); |
| 690 | |
| 691 | if (mem_to_free) { |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 692 | diva_os_free(0, mem_to_free); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 693 | } |
| 694 | |
| 695 | i = 0; |
| 696 | while (i++ < 30) { |
| 697 | if (a->automatic_law > 3) |
| 698 | break; |
| 699 | diva_os_sleep(10); |
| 700 | } |
| 701 | |
| 702 | /* profile information */ |
| 703 | PUT_WORD(&ctrl->profile.nbchannel, card->d.channels); |
| 704 | ctrl->profile.goptions = a->profile.Global_Options; |
| 705 | ctrl->profile.support1 = a->profile.B1_Protocols; |
| 706 | ctrl->profile.support2 = a->profile.B2_Protocols; |
| 707 | ctrl->profile.support3 = a->profile.B3_Protocols; |
| 708 | /* manufacturer profile information */ |
| 709 | ctrl->profile.manu[0] = a->man_profile.private_options; |
| 710 | ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads; |
| 711 | ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads; |
| 712 | ctrl->profile.manu[3] = 0; |
| 713 | ctrl->profile.manu[4] = 0; |
| 714 | |
| 715 | capi_ctr_ready(ctrl); |
| 716 | |
| 717 | DBG_TRC(("adapter added, max_adapter=%d", max_adapter)); |
| 718 | return (1); |
| 719 | } |
| 720 | |
| 721 | /* |
| 722 | * register appl |
| 723 | */ |
| 724 | static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 725 | capi_register_params *rp) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 726 | { |
| 727 | APPL *this; |
| 728 | word bnum, xnum; |
| 729 | int i = 0; |
| 730 | unsigned char *p; |
| 731 | void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used; |
| 732 | void **xbuffer_ptr, **xbuffer_internal; |
| 733 | diva_os_spin_lock_magic_t old_irql; |
| 734 | unsigned int mem_len; |
| 735 | int nconn = rp->level3cnt; |
| 736 | |
| 737 | |
| 738 | if (diva_os_in_irq()) { |
| 739 | DBG_ERR(("CAPI_REGISTER - in irq context !")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 740 | return; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 741 | } |
| 742 | |
| 743 | DBG_TRC(("application register Id=%d", appl)) |
| 744 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 745 | if (appl > MAX_APPL) { |
| 746 | DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL")) |
| 747 | return; |
| 748 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 749 | |
| 750 | if (nconn <= 0) |
| 751 | nconn = ctrl->profile.nbchannel * -nconn; |
| 752 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 753 | if (nconn == 0) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 754 | nconn = ctrl->profile.nbchannel; |
| 755 | |
| 756 | DBG_LOG(("CAPI_REGISTER - Id = %d", appl)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 757 | DBG_LOG((" MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt)) |
| 758 | DBG_LOG((" MaxBDataBuffers = %d", rp->datablkcnt)) |
| 759 | DBG_LOG((" MaxBDataLength = %d", rp->datablklen)) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 760 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 761 | if (nconn < 1 || |
| 762 | nconn > 255 || |
| 763 | rp->datablklen < 80 || |
| 764 | rp->datablklen > 2150 || rp->datablkcnt > 255) { |
| 765 | DBG_ERR(("CAPI_REGISTER - invalid parameters")) |
| 766 | return; |
| 767 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 768 | |
| 769 | if (application[appl - 1].Id == appl) { |
| 770 | DBG_LOG(("CAPI_REGISTER - appl already registered")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 771 | return; /* appl already registered */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 772 | } |
| 773 | |
| 774 | /* alloc memory */ |
| 775 | |
| 776 | bnum = nconn * rp->datablkcnt; |
| 777 | xnum = nconn * MAX_DATA_B3; |
| 778 | |
| 779 | mem_len = bnum * sizeof(word); /* DataNCCI */ |
| 780 | mem_len += bnum * sizeof(word); /* DataFlags */ |
| 781 | mem_len += bnum * rp->datablklen; /* ReceiveBuffer */ |
| 782 | mem_len += xnum; /* xbuffer_used */ |
| 783 | mem_len += xnum * sizeof(void *); /* xbuffer_ptr */ |
| 784 | mem_len += xnum * sizeof(void *); /* xbuffer_internal */ |
| 785 | mem_len += xnum * rp->datablklen; /* xbuffer_ptr[xnum] */ |
| 786 | |
| 787 | DBG_LOG((" Allocated Memory = %d", mem_len)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 788 | if (!(p = diva_os_malloc(0, mem_len))) { |
| 789 | DBG_ERR(("CAPI_REGISTER - memory allocation failed")) |
| 790 | return; |
| 791 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 792 | memset(p, 0, mem_len); |
| 793 | |
| 794 | DataNCCI = (void *)p; |
| 795 | p += bnum * sizeof(word); |
| 796 | DataFlags = (void *)p; |
| 797 | p += bnum * sizeof(word); |
| 798 | ReceiveBuffer = (void *)p; |
| 799 | p += bnum * rp->datablklen; |
| 800 | xbuffer_used = (void *)p; |
| 801 | p += xnum; |
| 802 | xbuffer_ptr = (void **)p; |
| 803 | p += xnum * sizeof(void *); |
| 804 | xbuffer_internal = (void **)p; |
| 805 | p += xnum * sizeof(void *); |
| 806 | for (i = 0; i < xnum; i++) { |
| 807 | xbuffer_ptr[i] = (void *)p; |
| 808 | p += rp->datablklen; |
| 809 | } |
| 810 | |
| 811 | /* initialize application data */ |
| 812 | diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl"); |
| 813 | |
| 814 | this = &application[appl - 1]; |
| 815 | memset(this, 0, sizeof(APPL)); |
| 816 | |
| 817 | this->Id = appl; |
| 818 | |
| 819 | for (i = 0; i < max_adapter; i++) { |
| 820 | adapter[i].CIP_Mask[appl - 1] = 0; |
| 821 | } |
| 822 | |
| 823 | this->queue_size = 1000; |
| 824 | |
| 825 | this->MaxNCCI = (byte) nconn; |
| 826 | this->MaxNCCIData = (byte) rp->datablkcnt; |
| 827 | this->MaxBuffer = bnum; |
| 828 | this->MaxDataLength = rp->datablklen; |
| 829 | |
| 830 | this->DataNCCI = DataNCCI; |
| 831 | this->DataFlags = DataFlags; |
| 832 | this->ReceiveBuffer = ReceiveBuffer; |
| 833 | this->xbuffer_used = xbuffer_used; |
| 834 | this->xbuffer_ptr = xbuffer_ptr; |
| 835 | this->xbuffer_internal = xbuffer_internal; |
| 836 | for (i = 0; i < xnum; i++) { |
| 837 | this->xbuffer_ptr[i] = xbuffer_ptr[i]; |
| 838 | } |
| 839 | |
| 840 | CapiRegister(this->Id); |
| 841 | diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl"); |
| 842 | |
| 843 | } |
| 844 | |
| 845 | /* |
| 846 | * release appl |
| 847 | */ |
| 848 | static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl) |
| 849 | { |
| 850 | diva_os_spin_lock_magic_t old_irql; |
| 851 | APPL *this = &application[appl - 1]; |
| 852 | void *mem_to_free = NULL; |
| 853 | |
| 854 | DBG_TRC(("application %d(%d) cleanup", this->Id, appl)) |
| 855 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 856 | if (diva_os_in_irq()) { |
| 857 | DBG_ERR(("CAPI_RELEASE - in irq context !")) |
| 858 | return; |
| 859 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 860 | |
| 861 | diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl"); |
| 862 | if (this->Id) { |
| 863 | CapiRelease(this->Id); |
| 864 | mem_to_free = this->DataNCCI; |
| 865 | this->DataNCCI = NULL; |
| 866 | this->Id = 0; |
| 867 | } |
| 868 | diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl"); |
| 869 | |
| 870 | if (mem_to_free) |
| 871 | diva_os_free(0, mem_to_free); |
| 872 | |
| 873 | } |
| 874 | |
| 875 | /* |
| 876 | * send message |
| 877 | */ |
| 878 | static u16 diva_send_message(struct capi_ctr *ctrl, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 879 | diva_os_message_buffer_s *dmb) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 880 | { |
| 881 | int i = 0; |
| 882 | word ret = 0; |
| 883 | diva_os_spin_lock_magic_t old_irql; |
| 884 | CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb); |
| 885 | APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1]; |
| 886 | diva_card *card = ctrl->driverdata; |
| 887 | __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb); |
| 888 | word clength = GET_WORD(&msg->header.length); |
| 889 | word command = GET_WORD(&msg->header.command); |
| 890 | u16 retval = CAPI_NOERROR; |
| 891 | |
| 892 | if (diva_os_in_irq()) { |
| 893 | DBG_ERR(("CAPI_SEND_MSG - in irq context !")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 894 | return CAPI_REGOSRESOURCEERR; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 895 | } |
| 896 | DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command)) |
| 897 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 898 | if (card->remove_in_progress) { |
| 899 | DBG_ERR(("CAPI_SEND_MSG - remove in progress!")) |
| 900 | return CAPI_REGOSRESOURCEERR; |
| 901 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 902 | |
| 903 | diva_os_enter_spin_lock(&api_lock, &old_irql, "send message"); |
| 904 | |
| 905 | if (!this->Id) { |
| 906 | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); |
| 907 | return CAPI_ILLAPPNR; |
| 908 | } |
| 909 | |
| 910 | /* patch controller number */ |
| 911 | msg->header.controller = ControllerMap[card->Id] |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 912 | | (msg->header.controller & 0x80); /* preserve external controller bit */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 913 | |
| 914 | switch (command) { |
| 915 | default: |
| 916 | xlog("\x00\x02", msg, 0x80, clength); |
| 917 | break; |
| 918 | |
| 919 | case _DATA_B3_I | RESPONSE: |
| 920 | #ifndef DIVA_NO_DEBUGLIB |
| 921 | if (myDriverDebugHandle.dbgMask & DL_BLK) |
| 922 | xlog("\x00\x02", msg, 0x80, clength); |
| 923 | #endif |
| 924 | break; |
| 925 | |
| 926 | case _DATA_B3_R: |
| 927 | #ifndef DIVA_NO_DEBUGLIB |
| 928 | if (myDriverDebugHandle.dbgMask & DL_BLK) |
| 929 | xlog("\x00\x02", msg, 0x80, clength); |
| 930 | #endif |
| 931 | |
| 932 | if (clength == 24) |
| 933 | clength = 22; /* workaround for PPcom bug */ |
| 934 | /* header is always 22 */ |
| 935 | if (GET_WORD(&msg->info.data_b3_req.Data_Length) > |
| 936 | this->MaxDataLength |
| 937 | || GET_WORD(&msg->info.data_b3_req.Data_Length) > |
| 938 | (length - clength)) { |
| 939 | DBG_ERR(("Write - invalid message size")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 940 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 941 | goto write_end; |
| 942 | } |
| 943 | |
| 944 | for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 945 | && this->xbuffer_used[i]; i++); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 946 | if (i == (MAX_DATA_B3 * this->MaxNCCI)) { |
| 947 | DBG_ERR(("Write - too many data pending")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 948 | retval = CAPI_SENDQUEUEFULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 949 | goto write_end; |
| 950 | } |
| 951 | msg->info.data_b3_req.Data = i; |
| 952 | |
| 953 | this->xbuffer_internal[i] = NULL; |
| 954 | memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength], |
| 955 | GET_WORD(&msg->info.data_b3_req.Data_Length)); |
| 956 | |
| 957 | #ifndef DIVA_NO_DEBUGLIB |
| 958 | if ((myDriverDebugHandle.dbgMask & DL_BLK) |
| 959 | && (myDriverDebugHandle.dbgMask & DL_XLOG)) { |
| 960 | int j; |
| 961 | for (j = 0; j < |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 962 | GET_WORD(&msg->info.data_b3_req.Data_Length); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 963 | j += 256) { |
| 964 | DBG_BLK((((char *) this->xbuffer_ptr[i]) + j, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 965 | ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) < |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 966 | 256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 967 | if (!(myDriverDebugHandle.dbgMask & DL_PRV0)) |
| 968 | break; /* not more if not explicitly requested */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 969 | } |
| 970 | } |
| 971 | #endif |
| 972 | break; |
| 973 | } |
| 974 | |
| 975 | memcpy(mapped_msg, msg, (__u32) clength); |
| 976 | mapped_msg->header.controller = MapController(mapped_msg->header.controller); |
| 977 | mapped_msg->header.length = clength; |
| 978 | mapped_msg->header.command = command; |
| 979 | mapped_msg->header.number = GET_WORD(&msg->header.number); |
| 980 | |
| 981 | ret = api_put(this, mapped_msg); |
| 982 | switch (ret) { |
| 983 | case 0: |
| 984 | break; |
| 985 | case _BAD_MSG: |
| 986 | DBG_ERR(("Write - bad message")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 987 | retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 988 | break; |
| 989 | case _QUEUE_FULL: |
| 990 | DBG_ERR(("Write - queue full")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 991 | retval = CAPI_SENDQUEUEFULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 992 | break; |
| 993 | default: |
| 994 | DBG_ERR(("Write - api_put returned unknown error")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 995 | retval = CAPI_UNKNOWNNOTPAR; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 996 | break; |
| 997 | } |
| 998 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 999 | write_end: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1000 | diva_os_leave_spin_lock(&api_lock, &old_irql, "send message"); |
| 1001 | if (retval == CAPI_NOERROR) |
| 1002 | diva_os_free_message_buffer(dmb); |
| 1003 | return retval; |
| 1004 | } |
| 1005 | |
| 1006 | |
| 1007 | /* |
| 1008 | * cards request function |
| 1009 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1010 | static void DIRequest(ENTITY *e) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1011 | { |
| 1012 | DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]); |
| 1013 | diva_card *os_card = (diva_card *) a->os_card; |
| 1014 | |
| 1015 | if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) { |
| 1016 | a->FlowControlSkipTable[e->ReqCh] = 1; |
| 1017 | } |
| 1018 | |
| 1019 | (*(os_card->d.request)) (e); |
| 1020 | } |
| 1021 | |
| 1022 | /* |
| 1023 | * callback function from didd |
| 1024 | */ |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1025 | static void didd_callback(void *context, DESCRIPTOR *adapter, int removal) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1026 | { |
| 1027 | if (adapter->type == IDI_DADAPTER) { |
| 1028 | DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); |
| 1029 | return; |
| 1030 | } else if (adapter->type == IDI_DIMAINT) { |
| 1031 | if (removal) { |
| 1032 | stop_dbg(); |
| 1033 | } else { |
| 1034 | memcpy(&MAdapter, adapter, sizeof(MAdapter)); |
| 1035 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; |
| 1036 | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); |
| 1037 | } |
| 1038 | } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */ |
| 1039 | if (removal) { |
| 1040 | divacapi_remove_card(adapter); |
| 1041 | } else { |
| 1042 | diva_add_card(adapter); |
| 1043 | } |
| 1044 | } |
| 1045 | return; |
| 1046 | } |
| 1047 | |
| 1048 | /* |
| 1049 | * connect to didd |
| 1050 | */ |
| 1051 | static int divacapi_connect_didd(void) |
| 1052 | { |
| 1053 | int x = 0; |
| 1054 | int dadapter = 0; |
| 1055 | IDI_SYNC_REQ req; |
| 1056 | DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; |
| 1057 | |
| 1058 | DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); |
| 1059 | |
| 1060 | for (x = 0; x < MAX_DESCRIPTORS; x++) { |
| 1061 | if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */ |
| 1062 | memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); |
| 1063 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; |
| 1064 | DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT); |
| 1065 | break; |
| 1066 | } |
| 1067 | } |
| 1068 | for (x = 0; x < MAX_DESCRIPTORS; x++) { |
| 1069 | if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ |
| 1070 | dadapter = 1; |
| 1071 | memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); |
| 1072 | req.didd_notify.e.Req = 0; |
| 1073 | req.didd_notify.e.Rc = |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1074 | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1075 | req.didd_notify.info.callback = (void *)didd_callback; |
| 1076 | req.didd_notify.info.context = NULL; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1077 | DAdapter.request((ENTITY *)&req); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1078 | if (req.didd_notify.e.Rc != 0xff) { |
| 1079 | stop_dbg(); |
| 1080 | return (0); |
| 1081 | } |
| 1082 | notify_handle = req.didd_notify.info.handle; |
| 1083 | } |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1084 | else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1085 | diva_add_card(&DIDD_Table[x]); |
| 1086 | } |
| 1087 | } |
| 1088 | |
| 1089 | if (!dadapter) { |
| 1090 | stop_dbg(); |
| 1091 | } |
| 1092 | |
| 1093 | return (dadapter); |
| 1094 | } |
| 1095 | |
| 1096 | /* |
| 1097 | * diconnect from didd |
| 1098 | */ |
| 1099 | static void divacapi_disconnect_didd(void) |
| 1100 | { |
| 1101 | IDI_SYNC_REQ req; |
| 1102 | |
| 1103 | stop_dbg(); |
| 1104 | |
| 1105 | req.didd_notify.e.Req = 0; |
| 1106 | req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; |
| 1107 | req.didd_notify.info.handle = notify_handle; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1108 | DAdapter.request((ENTITY *)&req); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1109 | } |
| 1110 | |
| 1111 | /* |
| 1112 | * we do not provide date/time here, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1113 | * the application should do this. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1114 | */ |
| 1115 | int fax_head_line_time(char *buffer) |
| 1116 | { |
| 1117 | return (0); |
| 1118 | } |
| 1119 | |
| 1120 | /* |
| 1121 | * init (alloc) main structures |
| 1122 | */ |
| 1123 | static int DIVA_INIT_FUNCTION init_main_structs(void) |
| 1124 | { |
| 1125 | if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) { |
| 1126 | DBG_ERR(("init: failed alloc mapped_msg.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1127 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1128 | } |
| 1129 | |
| 1130 | if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) { |
| 1131 | DBG_ERR(("init: failed alloc adapter struct.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1132 | diva_os_free(0, mapped_msg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1133 | return 0; |
| 1134 | } |
| 1135 | memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS); |
| 1136 | |
| 1137 | if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) { |
| 1138 | DBG_ERR(("init: failed alloc application struct.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1139 | diva_os_free(0, mapped_msg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1140 | diva_os_free(0, adapter); |
| 1141 | return 0; |
| 1142 | } |
| 1143 | memset(application, 0, sizeof(APPL) * MAX_APPL); |
| 1144 | |
| 1145 | return (1); |
| 1146 | } |
| 1147 | |
| 1148 | /* |
| 1149 | * remove (free) main structures |
| 1150 | */ |
| 1151 | static void remove_main_structs(void) |
| 1152 | { |
| 1153 | if (application) |
| 1154 | diva_os_free(0, application); |
| 1155 | if (adapter) |
| 1156 | diva_os_free(0, adapter); |
| 1157 | if (mapped_msg) |
| 1158 | diva_os_free(0, mapped_msg); |
| 1159 | } |
| 1160 | |
| 1161 | /* |
| 1162 | * api_remove_start |
| 1163 | */ |
| 1164 | static void do_api_remove_start(void) |
| 1165 | { |
| 1166 | diva_os_spin_lock_magic_t old_irql; |
| 1167 | int ret = 1, count = 100; |
| 1168 | |
| 1169 | do { |
| 1170 | diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start"); |
| 1171 | ret = api_remove_start(); |
| 1172 | diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start"); |
| 1173 | |
| 1174 | diva_os_sleep(10); |
| 1175 | } while (ret && count--); |
| 1176 | |
| 1177 | if (ret) |
| 1178 | DBG_ERR(("could not remove signaling ID's")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1179 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1180 | |
| 1181 | /* |
| 1182 | * init |
| 1183 | */ |
| 1184 | int DIVA_INIT_FUNCTION init_capifunc(void) |
| 1185 | { |
| 1186 | diva_os_initialize_spin_lock(&api_lock, "capifunc"); |
| 1187 | memset(ControllerMap, 0, MAX_DESCRIPTORS + 1); |
| 1188 | max_adapter = 0; |
| 1189 | |
| 1190 | |
| 1191 | if (!init_main_structs()) { |
| 1192 | DBG_ERR(("init: failed to init main structs.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1193 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1194 | return (0); |
| 1195 | } |
| 1196 | |
| 1197 | if (!divacapi_connect_didd()) { |
| 1198 | DBG_ERR(("init: failed to connect to DIDD.")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 1199 | do_api_remove_start(); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1200 | divacapi_remove_cards(); |
| 1201 | remove_main_structs(); |
| 1202 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); |
| 1203 | return (0); |
| 1204 | } |
| 1205 | |
| 1206 | return (1); |
| 1207 | } |
| 1208 | |
| 1209 | /* |
| 1210 | * finit |
| 1211 | */ |
| 1212 | void DIVA_EXIT_FUNCTION finit_capifunc(void) |
| 1213 | { |
| 1214 | do_api_remove_start(); |
| 1215 | divacapi_disconnect_didd(); |
| 1216 | divacapi_remove_cards(); |
| 1217 | remove_main_structs(); |
| 1218 | diva_os_destroy_spin_lock(&api_lock, "capifunc"); |
| 1219 | } |