1/* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $ 2 * 3 * Driver for Eicon DIVA Server ISDN cards. 4 * User Mode IDI Interface 5 * 6 * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 7 * Copyright 2000-2003 Cytronics & Melware (info@melware.de) 8 * 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#include "platform.h" 14#include "di_defs.h" 15#include "divasync.h" 16#include "um_xdi.h" 17#include "um_idi.h" 18 19#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) 20#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) 21 22extern char *DRIVERRELEASE_IDI; 23 24extern void DIVA_DIDD_Read(void *, int); 25extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int); 26extern void diva_user_mode_idi_remove_adapter(int); 27 28static dword notify_handle; 29static DESCRIPTOR DAdapter; 30static DESCRIPTOR MAdapter; 31 32static void no_printf(unsigned char *x, ...) 33{ 34 /* dummy debug function */ 35} 36 37#include "debuglib.c" 38 39/* 40 * stop debug 41 */ 42static void stop_dbg(void) 43{ 44 DbgDeregister(); 45 memset(&MAdapter, 0, sizeof(MAdapter)); 46 dprintf = no_printf; 47} 48 49typedef struct _udiva_card { 50 struct list_head list; 51 int Id; 52 DESCRIPTOR d; 53} udiva_card; 54 55static LIST_HEAD(cards); 56static diva_os_spin_lock_t ll_lock; 57 58/* 59 * find card in list 60 */ 61static udiva_card *find_card_in_list(DESCRIPTOR *d) 62{ 63 udiva_card *card; 64 struct list_head *tmp; 65 diva_os_spin_lock_magic_t old_irql; 66 67 diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card"); 68 list_for_each(tmp, &cards) { 69 card = list_entry(tmp, udiva_card, list); 70 if (card->d.request == d->request) { 71 diva_os_leave_spin_lock(&ll_lock, &old_irql, 72 "find card"); 73 return (card); 74 } 75 } 76 diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card"); 77 return ((udiva_card *) NULL); 78} 79 80/* 81 * new card 82 */ 83static void um_new_card(DESCRIPTOR *d) 84{ 85 int adapter_nr = 0; 86 udiva_card *card = NULL; 87 IDI_SYNC_REQ sync_req; 88 diva_os_spin_lock_magic_t old_irql; 89 90 if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) { 91 DBG_ERR(("cannot get buffer for card")); 92 return; 93 } 94 memcpy(&card->d, d, sizeof(DESCRIPTOR)); 95 sync_req.xdi_logical_adapter_number.Req = 0; 96 sync_req.xdi_logical_adapter_number.Rc = 97 IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER; 98 card->d.request((ENTITY *)&sync_req); 99 adapter_nr = 100 sync_req.xdi_logical_adapter_number.info.logical_adapter_number; 101 card->Id = adapter_nr; 102 if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) { 103 diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card"); 104 list_add_tail(&card->list, &cards); 105 diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card"); 106 } else { 107 DBG_ERR(("could not create user mode idi card %d", 108 adapter_nr)); 109 diva_os_free(0, card); 110 } 111} 112 113/* 114 * remove card 115 */ 116static void um_remove_card(DESCRIPTOR *d) 117{ 118 diva_os_spin_lock_magic_t old_irql; 119 udiva_card *card = NULL; 120 121 if (!(card = find_card_in_list(d))) { 122 DBG_ERR(("cannot find card to remove")); 123 return; 124 } 125 diva_user_mode_idi_remove_adapter(card->Id); 126 diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card"); 127 list_del(&card->list); 128 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card"); 129 DBG_LOG(("idi proc entry removed for card %d", card->Id)); 130 diva_os_free(0, card); 131} 132 133/* 134 * remove all adapter 135 */ 136static void __exit remove_all_idi_proc(void) 137{ 138 udiva_card *card; 139 diva_os_spin_lock_magic_t old_irql; 140 141rescan: 142 diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all"); 143 if (!list_empty(&cards)) { 144 card = list_entry(cards.next, udiva_card, list); 145 list_del(&card->list); 146 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); 147 diva_user_mode_idi_remove_adapter(card->Id); 148 diva_os_free(0, card); 149 goto rescan; 150 } 151 diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); 152} 153 154/* 155 * DIDD notify callback 156 */ 157static void *didd_callback(void *context, DESCRIPTOR *adapter, 158 int removal) 159{ 160 if (adapter->type == IDI_DADAPTER) { 161 DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); 162 return (NULL); 163 } else if (adapter->type == IDI_DIMAINT) { 164 if (removal) { 165 stop_dbg(); 166 } else { 167 memcpy(&MAdapter, adapter, sizeof(MAdapter)); 168 dprintf = (DIVA_DI_PRINTF) MAdapter.request; 169 DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT); 170 } 171 } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */ 172 if (removal) { 173 um_remove_card(adapter); 174 } else { 175 um_new_card(adapter); 176 } 177 } 178 return (NULL); 179} 180 181/* 182 * connect DIDD 183 */ 184static int __init connect_didd(void) 185{ 186 int x = 0; 187 int dadapter = 0; 188 IDI_SYNC_REQ req; 189 DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; 190 191 DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); 192 193 for (x = 0; x < MAX_DESCRIPTORS; x++) { 194 if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ 195 dadapter = 1; 196 memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); 197 req.didd_notify.e.Req = 0; 198 req.didd_notify.e.Rc = 199 IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; 200 req.didd_notify.info.callback = (void *)didd_callback; 201 req.didd_notify.info.context = NULL; 202 DAdapter.request((ENTITY *)&req); 203 if (req.didd_notify.e.Rc != 0xff) { 204 stop_dbg(); 205 return (0); 206 } 207 notify_handle = req.didd_notify.info.handle; 208 } else if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */ 209 memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); 210 dprintf = (DIVA_DI_PRINTF) MAdapter.request; 211 DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT); 212 } else if ((DIDD_Table[x].type > 0) 213 && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ 214 um_new_card(&DIDD_Table[x]); 215 } 216 } 217 218 if (!dadapter) { 219 stop_dbg(); 220 } 221 222 return (dadapter); 223} 224 225/* 226 * Disconnect from DIDD 227 */ 228static void __exit disconnect_didd(void) 229{ 230 IDI_SYNC_REQ req; 231 232 stop_dbg(); 233 234 req.didd_notify.e.Req = 0; 235 req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; 236 req.didd_notify.info.handle = notify_handle; 237 DAdapter.request((ENTITY *)&req); 238} 239 240/* 241 * init 242 */ 243int __init idifunc_init(void) 244{ 245 diva_os_initialize_spin_lock(&ll_lock, "idifunc"); 246 247 if (diva_user_mode_idi_init()) { 248 DBG_ERR(("init: init failed.")); 249 return (0); 250 } 251 252 if (!connect_didd()) { 253 diva_user_mode_idi_finit(); 254 DBG_ERR(("init: failed to connect to DIDD.")); 255 return (0); 256 } 257 return (1); 258} 259 260/* 261 * finit 262 */ 263void __exit idifunc_finit(void) 264{ 265 diva_user_mode_idi_finit(); 266 disconnect_didd(); 267 remove_all_idi_proc(); 268} 269