Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */ |
| 2 | |
| 3 | #define CARDTYPE_H_WANT_DATA 1 |
| 4 | #define CARDTYPE_H_WANT_IDI_DATA 0 |
| 5 | #define CARDTYPE_H_WANT_RESOURCE_DATA 0 |
| 6 | #define CARDTYPE_H_WANT_FILE_DATA 0 |
| 7 | |
| 8 | #include "platform.h" |
| 9 | #include "debuglib.h" |
| 10 | #include "cardtype.h" |
| 11 | #include "pc.h" |
| 12 | #include "di_defs.h" |
| 13 | #include "di.h" |
| 14 | #include "io.h" |
| 15 | #include "pc_maint.h" |
| 16 | #include "xdi_msg.h" |
| 17 | #include "xdi_adapter.h" |
| 18 | #include "diva_pci.h" |
| 19 | #include "diva.h" |
| 20 | |
| 21 | #ifdef CONFIG_ISDN_DIVAS_PRIPCI |
| 22 | #include "os_pri.h" |
| 23 | #endif |
| 24 | #ifdef CONFIG_ISDN_DIVAS_BRIPCI |
| 25 | #include "os_bri.h" |
| 26 | #include "os_4bri.h" |
| 27 | #endif |
| 28 | |
| 29 | PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; |
| 30 | extern IDI_CALL Requests[MAX_ADAPTER]; |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 31 | extern int create_adapter_proc(diva_os_xdi_adapter_t *a); |
| 32 | extern void remove_adapter_proc(diva_os_xdi_adapter_t *a); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 34 | #define DivaIdiReqFunc(N) \ |
| 35 | static void DivaIdiRequest##N(ENTITY *e) \ |
| 36 | { if (IoAdapters[N]) (*IoAdapters[N]->DIRequest)(IoAdapters[N], e); } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 | |
| 38 | /* |
| 39 | ** Create own 32 Adapters |
| 40 | */ |
| 41 | DivaIdiReqFunc(0) |
| 42 | DivaIdiReqFunc(1) |
| 43 | DivaIdiReqFunc(2) |
| 44 | DivaIdiReqFunc(3) |
| 45 | DivaIdiReqFunc(4) |
| 46 | DivaIdiReqFunc(5) |
| 47 | DivaIdiReqFunc(6) |
| 48 | DivaIdiReqFunc(7) |
| 49 | DivaIdiReqFunc(8) |
| 50 | DivaIdiReqFunc(9) |
| 51 | DivaIdiReqFunc(10) |
| 52 | DivaIdiReqFunc(11) |
| 53 | DivaIdiReqFunc(12) |
| 54 | DivaIdiReqFunc(13) |
| 55 | DivaIdiReqFunc(14) |
| 56 | DivaIdiReqFunc(15) |
| 57 | DivaIdiReqFunc(16) |
| 58 | DivaIdiReqFunc(17) |
| 59 | DivaIdiReqFunc(18) |
| 60 | DivaIdiReqFunc(19) |
| 61 | DivaIdiReqFunc(20) |
| 62 | DivaIdiReqFunc(21) |
| 63 | DivaIdiReqFunc(22) |
| 64 | DivaIdiReqFunc(23) |
| 65 | DivaIdiReqFunc(24) |
| 66 | DivaIdiReqFunc(25) |
| 67 | DivaIdiReqFunc(26) |
| 68 | DivaIdiReqFunc(27) |
| 69 | DivaIdiReqFunc(28) |
| 70 | DivaIdiReqFunc(29) |
| 71 | DivaIdiReqFunc(30) |
| 72 | DivaIdiReqFunc(31) |
| 73 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | /* |
| 75 | ** LOCALS |
| 76 | */ |
| 77 | static LIST_HEAD(adapter_queue); |
| 78 | |
| 79 | typedef struct _diva_get_xlog { |
| 80 | word command; |
| 81 | byte req; |
| 82 | byte rc; |
| 83 | byte data[sizeof(struct mi_pc_maint)]; |
| 84 | } diva_get_xlog_t; |
| 85 | |
| 86 | typedef struct _diva_supported_cards_info { |
| 87 | int CardOrdinal; |
| 88 | diva_init_card_proc_t init_card; |
| 89 | } diva_supported_cards_info_t; |
| 90 | |
| 91 | static diva_supported_cards_info_t divas_supported_cards[] = { |
| 92 | #ifdef CONFIG_ISDN_DIVAS_PRIPCI |
| 93 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 94 | PRI Cards |
| 95 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card}, |
| 97 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 98 | PRI Rev.2 Cards |
| 99 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card}, |
| 101 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 102 | PRI Rev.2 VoIP Cards |
| 103 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 | {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card}, |
| 105 | #endif |
| 106 | #ifdef CONFIG_ISDN_DIVAS_BRIPCI |
| 107 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 108 | 4BRI Rev 1 Cards |
| 109 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card}, |
| 111 | {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card}, |
| 112 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 113 | 4BRI Rev 2 Cards |
| 114 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card}, |
| 116 | {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card}, |
| 117 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 118 | 4BRI Based BRI Rev 2 Cards |
| 119 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card}, |
| 121 | {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card}, |
| 122 | {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card}, |
| 123 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 124 | BRI |
| 125 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 | {CARDTYPE_MAESTRA_PCI, diva_bri_init_card}, |
| 127 | #endif |
| 128 | |
| 129 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 130 | EOL |
| 131 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | {-1} |
| 133 | }; |
| 134 | |
| 135 | static void diva_init_request_array(void); |
| 136 | static void *divas_create_pci_card(int handle, void *pci_dev_handle); |
| 137 | |
| 138 | static diva_os_spin_lock_t adapter_lock; |
| 139 | |
| 140 | static int diva_find_free_adapters(int base, int nr) |
| 141 | { |
| 142 | int i; |
| 143 | |
| 144 | for (i = 0; i < nr; i++) { |
| 145 | if (IoAdapters[base + i]) { |
| 146 | return (-1); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | return (0); |
| 151 | } |
| 152 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 153 | static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head *what) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 | { |
| 155 | diva_os_xdi_adapter_t *a = NULL; |
| 156 | |
| 157 | if (what && (what->next != &adapter_queue)) |
| 158 | a = list_entry(what->next, diva_os_xdi_adapter_t, link); |
| 159 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 160 | return (a); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 164 | Add card to the card list |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 165 | -------------------------------------------------------------------------- */ |
| 166 | void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal) |
| 167 | { |
| 168 | diva_os_spin_lock_magic_t old_irql; |
| 169 | diva_os_xdi_adapter_t *pdiva, *pa; |
| 170 | int i, j, max, nr; |
| 171 | |
| 172 | for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) { |
| 173 | if (divas_supported_cards[i].CardOrdinal == CardOrdinal) { |
| 174 | if (!(pdiva = divas_create_pci_card(i, pdev))) { |
| 175 | return NULL; |
| 176 | } |
| 177 | switch (CardOrdinal) { |
| 178 | case CARDTYPE_DIVASRV_Q_8M_PCI: |
| 179 | case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI: |
| 180 | case CARDTYPE_DIVASRV_Q_8M_V2_PCI: |
| 181 | case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI: |
| 182 | max = MAX_ADAPTER - 4; |
| 183 | nr = 4; |
| 184 | break; |
| 185 | |
| 186 | default: |
| 187 | max = MAX_ADAPTER; |
| 188 | nr = 1; |
| 189 | } |
| 190 | |
| 191 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 192 | |
| 193 | for (i = 0; i < max; i++) { |
| 194 | if (!diva_find_free_adapters(i, nr)) { |
| 195 | pdiva->controller = i + 1; |
| 196 | pdiva->xdi_adapter.ANum = pdiva->controller; |
| 197 | IoAdapters[i] = &pdiva->xdi_adapter; |
| 198 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 199 | create_adapter_proc(pdiva); /* add adapter to proc file system */ |
| 200 | |
| 201 | DBG_LOG(("add %s:%d", |
| 202 | CardProperties |
| 203 | [CardOrdinal].Name, |
| 204 | pdiva->controller)) |
| 205 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 206 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 | pa = pdiva; |
| 208 | for (j = 1; j < nr; j++) { /* slave adapters, if any */ |
| 209 | pa = diva_q_get_next(&pa->link); |
| 210 | if (pa && !pa->interface.cleanup_adapter_proc) { |
| 211 | pa->controller = i + 1 + j; |
| 212 | pa->xdi_adapter.ANum = pa->controller; |
| 213 | IoAdapters[i + j] = &pa->xdi_adapter; |
| 214 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 215 | DBG_LOG(("add slave adapter (%d)", |
| 216 | pa->controller)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 217 | create_adapter_proc(pa); /* add adapter to proc file system */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 219 | } else { |
| 220 | DBG_ERR(("slave adapter problem")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 221 | break; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 222 | } |
| 223 | } |
| 224 | |
| 225 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 226 | return (pdiva); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card"); |
| 231 | |
| 232 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 233 | Not able to add adapter - remove it and return error |
| 234 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | DBG_ERR(("can not alloc request array")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 236 | diva_driver_remove_card(pdiva); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 237 | |
| 238 | return NULL; |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | return NULL; |
| 243 | } |
| 244 | |
| 245 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 246 | Called on driver load, MAIN, main, DriverEntry |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 | -------------------------------------------------------------------------- */ |
| 248 | int divasa_xdi_driver_entry(void) |
| 249 | { |
| 250 | diva_os_initialize_spin_lock(&adapter_lock, "adapter"); |
| 251 | memset(&IoAdapters[0], 0x00, sizeof(IoAdapters)); |
| 252 | diva_init_request_array(); |
| 253 | |
| 254 | return (0); |
| 255 | } |
| 256 | |
| 257 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 258 | Remove adapter from list |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 | -------------------------------------------------------------------------- */ |
| 260 | static diva_os_xdi_adapter_t *get_and_remove_from_queue(void) |
| 261 | { |
| 262 | diva_os_spin_lock_magic_t old_irql; |
| 263 | diva_os_xdi_adapter_t *a = NULL; |
| 264 | |
| 265 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload"); |
| 266 | |
| 267 | if (!list_empty(&adapter_queue)) { |
| 268 | a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link); |
| 269 | list_del(adapter_queue.next); |
| 270 | } |
| 271 | |
| 272 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload"); |
| 273 | return (a); |
| 274 | } |
| 275 | |
| 276 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 277 | Remove card from the card list |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 278 | -------------------------------------------------------------------------- */ |
| 279 | void diva_driver_remove_card(void *pdiva) |
| 280 | { |
| 281 | diva_os_spin_lock_magic_t old_irql; |
| 282 | diva_os_xdi_adapter_t *a[4]; |
| 283 | diva_os_xdi_adapter_t *pa; |
| 284 | int i; |
| 285 | |
| 286 | pa = a[0] = (diva_os_xdi_adapter_t *) pdiva; |
| 287 | a[1] = a[2] = a[3] = NULL; |
| 288 | |
| 289 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter"); |
| 290 | |
| 291 | for (i = 1; i < 4; i++) { |
| 292 | if ((pa = diva_q_get_next(&pa->link)) |
| 293 | && !pa->interface.cleanup_adapter_proc) { |
| 294 | a[i] = pa; |
| 295 | } else { |
| 296 | break; |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | for (i = 0; ((i < 4) && a[i]); i++) { |
| 301 | list_del(&a[i]->link); |
| 302 | } |
| 303 | |
| 304 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload"); |
| 305 | |
| 306 | (*(a[0]->interface.cleanup_adapter_proc)) (a[0]); |
| 307 | |
| 308 | for (i = 0; i < 4; i++) { |
| 309 | if (a[i]) { |
| 310 | if (a[i]->controller) { |
| 311 | DBG_LOG(("remove adapter (%d)", |
| 312 | a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL; |
| 313 | remove_adapter_proc(a[i]); |
| 314 | } |
| 315 | diva_os_free(0, a[i]); |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 321 | Create diva PCI adapter and init internal adapter structures |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 322 | -------------------------------------------------------------------------- */ |
| 323 | static void *divas_create_pci_card(int handle, void *pci_dev_handle) |
| 324 | { |
| 325 | diva_supported_cards_info_t *pI = &divas_supported_cards[handle]; |
| 326 | diva_os_spin_lock_magic_t old_irql; |
| 327 | diva_os_xdi_adapter_t *a; |
| 328 | |
| 329 | DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name)) |
| 330 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 331 | if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) { |
| 332 | DBG_ERR(("A: can't alloc adapter")); |
| 333 | return NULL; |
| 334 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | |
| 336 | memset(a, 0x00, sizeof(*a)); |
| 337 | |
| 338 | a->CardIndex = handle; |
| 339 | a->CardOrdinal = pI->CardOrdinal; |
| 340 | a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI; |
| 341 | a->xdi_adapter.cardType = a->CardOrdinal; |
| 342 | a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle); |
| 343 | a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle); |
| 344 | a->resources.pci.hdev = pci_dev_handle; |
| 345 | |
| 346 | /* |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 347 | Add master adapter first, so slave adapters will receive higher |
| 348 | numbers as master adapter |
| 349 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); |
| 351 | list_add_tail(&a->link, &adapter_queue); |
| 352 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); |
| 353 | |
| 354 | if ((*(pI->init_card)) (a)) { |
| 355 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); |
| 356 | list_del(&a->link); |
| 357 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); |
| 358 | diva_os_free(0, a); |
| 359 | DBG_ERR(("A: can't get adapter resources")); |
| 360 | return NULL; |
| 361 | } |
| 362 | |
| 363 | return (a); |
| 364 | } |
| 365 | |
| 366 | /* -------------------------------------------------------------------------- |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 367 | Called on driver unload FINIT, finit, Unload |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 | -------------------------------------------------------------------------- */ |
| 369 | void divasa_xdi_driver_unload(void) |
| 370 | { |
| 371 | diva_os_xdi_adapter_t *a; |
| 372 | |
| 373 | while ((a = get_and_remove_from_queue())) { |
| 374 | if (a->interface.cleanup_adapter_proc) { |
| 375 | (*(a->interface.cleanup_adapter_proc)) (a); |
| 376 | } |
| 377 | if (a->controller) { |
| 378 | IoAdapters[a->controller - 1] = NULL; |
| 379 | remove_adapter_proc(a); |
| 380 | } |
| 381 | diva_os_free(0, a); |
| 382 | } |
| 383 | diva_os_destroy_spin_lock(&adapter_lock, "adapter"); |
| 384 | } |
| 385 | |
| 386 | /* |
| 387 | ** Receive and process command from user mode utility |
| 388 | */ |
| 389 | void *diva_xdi_open_adapter(void *os_handle, const void __user *src, |
| 390 | int length, |
| 391 | divas_xdi_copy_from_user_fn_t cp_fn) |
| 392 | { |
| 393 | diva_xdi_um_cfg_cmd_t msg; |
| 394 | diva_os_xdi_adapter_t *a = NULL; |
| 395 | diva_os_spin_lock_magic_t old_irql; |
| 396 | struct list_head *tmp; |
| 397 | |
| 398 | if (length < sizeof(diva_xdi_um_cfg_cmd_t)) { |
| 399 | DBG_ERR(("A: A(?) open, msg too small (%d < %d)", |
| 400 | length, sizeof(diva_xdi_um_cfg_cmd_t))) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 401 | return NULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 402 | } |
| 403 | if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { |
| 404 | DBG_ERR(("A: A(?) open, write error")) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 405 | return NULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 406 | } |
| 407 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); |
| 408 | list_for_each(tmp, &adapter_queue) { |
| 409 | a = list_entry(tmp, diva_os_xdi_adapter_t, link); |
| 410 | if (a->controller == (int)msg.adapter) |
| 411 | break; |
| 412 | a = NULL; |
| 413 | } |
| 414 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); |
| 415 | |
| 416 | if (!a) { |
| 417 | DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 418 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 419 | |
| 420 | return (a); |
| 421 | } |
| 422 | |
| 423 | /* |
| 424 | ** Easy cleanup mailbox status |
| 425 | */ |
| 426 | void diva_xdi_close_adapter(void *adapter, void *os_handle) |
| 427 | { |
| 428 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; |
| 429 | |
| 430 | a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; |
| 431 | if (a->xdi_mbox.data) { |
| 432 | diva_os_free(0, a->xdi_mbox.data); |
| 433 | a->xdi_mbox.data = NULL; |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | int |
| 438 | diva_xdi_write(void *adapter, void *os_handle, const void __user *src, |
| 439 | int length, divas_xdi_copy_from_user_fn_t cp_fn) |
| 440 | { |
| 441 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; |
| 442 | void *data; |
| 443 | |
| 444 | if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) { |
| 445 | DBG_ERR(("A: A(%d) write, mbox busy", a->controller)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 446 | return (-1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | } |
| 448 | |
| 449 | if (length < sizeof(diva_xdi_um_cfg_cmd_t)) { |
| 450 | DBG_ERR(("A: A(%d) write, message too small (%d < %d)", |
| 451 | a->controller, length, |
| 452 | sizeof(diva_xdi_um_cfg_cmd_t))) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 453 | return (-3); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 454 | } |
| 455 | |
| 456 | if (!(data = diva_os_malloc(0, length))) { |
| 457 | DBG_ERR(("A: A(%d) write, ENOMEM", a->controller)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 458 | return (-2); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 459 | } |
| 460 | |
| 461 | length = (*cp_fn) (os_handle, data, src, length); |
| 462 | if (length > 0) { |
| 463 | if ((*(a->interface.cmd_proc)) |
| 464 | (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { |
| 465 | length = -3; |
| 466 | } |
| 467 | } else { |
| 468 | DBG_ERR(("A: A(%d) write error (%d)", a->controller, |
| 469 | length)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 470 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 471 | |
| 472 | diva_os_free(0, data); |
| 473 | |
| 474 | return (length); |
| 475 | } |
| 476 | |
| 477 | /* |
| 478 | ** Write answers to user mode utility, if any |
| 479 | */ |
| 480 | int |
| 481 | diva_xdi_read(void *adapter, void *os_handle, void __user *dst, |
| 482 | int max_length, divas_xdi_copy_to_user_fn_t cp_fn) |
| 483 | { |
| 484 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; |
| 485 | int ret; |
| 486 | |
| 487 | if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) { |
| 488 | DBG_ERR(("A: A(%d) rx mbox empty", a->controller)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 489 | return (-1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 490 | } |
| 491 | if (!a->xdi_mbox.data) { |
| 492 | a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; |
| 493 | DBG_ERR(("A: A(%d) rx ENOMEM", a->controller)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 494 | return (-2); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 495 | } |
| 496 | |
| 497 | if (max_length < a->xdi_mbox.data_length) { |
| 498 | DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)", |
| 499 | a->controller, max_length, |
| 500 | a->xdi_mbox.data_length)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 501 | return (-3); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 502 | } |
| 503 | |
| 504 | ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data, |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 505 | a->xdi_mbox.data_length); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 506 | if (ret > 0) { |
| 507 | diva_os_free(0, a->xdi_mbox.data); |
| 508 | a->xdi_mbox.data = NULL; |
| 509 | a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; |
| 510 | } |
| 511 | |
| 512 | return (ret); |
| 513 | } |
| 514 | |
| 515 | |
David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 516 | irqreturn_t diva_os_irq_wrapper(int irq, void *context) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 517 | { |
Jeff Garzik | 15aafa2 | 2008-02-06 01:36:20 -0800 | [diff] [blame] | 518 | diva_os_xdi_adapter_t *a = context; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 519 | diva_xdi_clear_interrupts_proc_t clear_int_proc; |
| 520 | |
Jeff Garzik | 15aafa2 | 2008-02-06 01:36:20 -0800 | [diff] [blame] | 521 | if (!a || !a->xdi_adapter.diva_isr_handler) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 522 | return IRQ_NONE; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 523 | |
| 524 | if ((clear_int_proc = a->clear_interrupts_proc)) { |
| 525 | (*clear_int_proc) (a); |
| 526 | a->clear_interrupts_proc = NULL; |
| 527 | return IRQ_HANDLED; |
| 528 | } |
| 529 | |
| 530 | (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter); |
| 531 | return IRQ_HANDLED; |
| 532 | } |
| 533 | |
| 534 | static void diva_init_request_array(void) |
| 535 | { |
| 536 | Requests[0] = DivaIdiRequest0; |
| 537 | Requests[1] = DivaIdiRequest1; |
| 538 | Requests[2] = DivaIdiRequest2; |
| 539 | Requests[3] = DivaIdiRequest3; |
| 540 | Requests[4] = DivaIdiRequest4; |
| 541 | Requests[5] = DivaIdiRequest5; |
| 542 | Requests[6] = DivaIdiRequest6; |
| 543 | Requests[7] = DivaIdiRequest7; |
| 544 | Requests[8] = DivaIdiRequest8; |
| 545 | Requests[9] = DivaIdiRequest9; |
| 546 | Requests[10] = DivaIdiRequest10; |
| 547 | Requests[11] = DivaIdiRequest11; |
| 548 | Requests[12] = DivaIdiRequest12; |
| 549 | Requests[13] = DivaIdiRequest13; |
| 550 | Requests[14] = DivaIdiRequest14; |
| 551 | Requests[15] = DivaIdiRequest15; |
| 552 | Requests[16] = DivaIdiRequest16; |
| 553 | Requests[17] = DivaIdiRequest17; |
| 554 | Requests[18] = DivaIdiRequest18; |
| 555 | Requests[19] = DivaIdiRequest19; |
| 556 | Requests[20] = DivaIdiRequest20; |
| 557 | Requests[21] = DivaIdiRequest21; |
| 558 | Requests[22] = DivaIdiRequest22; |
| 559 | Requests[23] = DivaIdiRequest23; |
| 560 | Requests[24] = DivaIdiRequest24; |
| 561 | Requests[25] = DivaIdiRequest25; |
| 562 | Requests[26] = DivaIdiRequest26; |
| 563 | Requests[27] = DivaIdiRequest27; |
| 564 | Requests[28] = DivaIdiRequest28; |
| 565 | Requests[29] = DivaIdiRequest29; |
| 566 | Requests[30] = DivaIdiRequest30; |
| 567 | Requests[31] = DivaIdiRequest31; |
| 568 | } |
| 569 | |
| 570 | void diva_xdi_display_adapter_features(int card) |
| 571 | { |
| 572 | dword features; |
| 573 | if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) { |
| 574 | return; |
| 575 | } |
| 576 | card--; |
| 577 | features = IoAdapters[card]->Properties.Features; |
| 578 | |
| 579 | DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1)) |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 580 | DBG_LOG((" DI_FAX3 : %s", |
| 581 | (features & DI_FAX3) ? "Y" : "N")) |
| 582 | DBG_LOG((" DI_MODEM : %s", |
| 583 | (features & DI_MODEM) ? "Y" : "N")) |
| 584 | DBG_LOG((" DI_POST : %s", |
| 585 | (features & DI_POST) ? "Y" : "N")) |
| 586 | DBG_LOG((" DI_V110 : %s", |
| 587 | (features & DI_V110) ? "Y" : "N")) |
| 588 | DBG_LOG((" DI_V120 : %s", |
| 589 | (features & DI_V120) ? "Y" : "N")) |
| 590 | DBG_LOG((" DI_POTS : %s", |
| 591 | (features & DI_POTS) ? "Y" : "N")) |
| 592 | DBG_LOG((" DI_CODEC : %s", |
| 593 | (features & DI_CODEC) ? "Y" : "N")) |
| 594 | DBG_LOG((" DI_MANAGE : %s", |
| 595 | (features & DI_MANAGE) ? "Y" : "N")) |
| 596 | DBG_LOG((" DI_V_42 : %s", |
| 597 | (features & DI_V_42) ? "Y" : "N")) |
| 598 | DBG_LOG((" DI_EXTD_FAX : %s", |
| 599 | (features & DI_EXTD_FAX) ? "Y" : "N")) |
| 600 | DBG_LOG((" DI_AT_PARSER : %s", |
| 601 | (features & DI_AT_PARSER) ? "Y" : "N")) |
| 602 | DBG_LOG((" DI_VOICE_OVER_IP : %s", |
| 603 | (features & DI_VOICE_OVER_IP) ? "Y" : "N")) |
| 604 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 605 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 606 | void diva_add_slave_adapter(diva_os_xdi_adapter_t *a) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 607 | { |
| 608 | diva_os_spin_lock_magic_t old_irql; |
| 609 | |
| 610 | diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave"); |
| 611 | list_add_tail(&a->link, &adapter_queue); |
| 612 | diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave"); |
| 613 | } |
| 614 | |
Joe Perches | 475be4d | 2012-02-19 19:52:38 -0800 | [diff] [blame] | 615 | int diva_card_read_xlog(diva_os_xdi_adapter_t *a) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 616 | { |
| 617 | diva_get_xlog_t *req; |
| 618 | byte *data; |
| 619 | |
| 620 | if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) { |
| 621 | return (-1); |
| 622 | } |
| 623 | if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) { |
| 624 | return (-1); |
| 625 | } |
| 626 | memset(data, 0x00, sizeof(struct mi_pc_maint)); |
| 627 | |
| 628 | if (!(req = diva_os_malloc(0, sizeof(*req)))) { |
| 629 | diva_os_free(0, data); |
| 630 | return (-1); |
| 631 | } |
| 632 | req->command = 0x0400; |
| 633 | req->req = LOG; |
| 634 | req->rc = 0x00; |
| 635 | |
| 636 | (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req); |
| 637 | |
| 638 | if (!req->rc || req->req) { |
| 639 | diva_os_free(0, data); |
| 640 | diva_os_free(0, req); |
| 641 | return (-1); |
| 642 | } |
| 643 | |
| 644 | memcpy(data, &req->req, sizeof(struct mi_pc_maint)); |
| 645 | |
| 646 | diva_os_free(0, req); |
| 647 | |
| 648 | a->xdi_mbox.data_length = sizeof(struct mi_pc_maint); |
| 649 | a->xdi_mbox.data = data; |
| 650 | a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; |
| 651 | |
| 652 | return (0); |
| 653 | } |
| 654 | |
| 655 | void xdiFreeFile(void *handle) |
| 656 | { |
| 657 | } |