Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: os_bri.c,v 1.21 2004/03/21 17:26:01 armin Exp $ */ |
| 2 | |
| 3 | #include "platform.h" |
| 4 | #include "debuglib.h" |
| 5 | #include "cardtype.h" |
| 6 | #include "pc.h" |
| 7 | #include "pr_pc.h" |
| 8 | #include "di_defs.h" |
| 9 | #include "dsp_defs.h" |
| 10 | #include "di.h" |
| 11 | #include "io.h" |
| 12 | |
| 13 | #include "xdi_msg.h" |
| 14 | #include "xdi_adapter.h" |
| 15 | #include "os_bri.h" |
| 16 | #include "diva_pci.h" |
| 17 | #include "mi_pc.h" |
| 18 | #include "pc_maint.h" |
Adrian Bunk | 6e21bd9 | 2006-01-08 01:05:15 -0800 | [diff] [blame] | 19 | #include "dsrv_bri.h" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | |
| 21 | /* |
| 22 | ** IMPORTS |
| 23 | */ |
| 24 | extern void prepare_maestra_functions(PISDN_ADAPTER IoAdapter); |
| 25 | extern void diva_xdi_display_adapter_features(int card); |
| 26 | extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a); |
| 27 | |
| 28 | /* |
| 29 | ** LOCALS |
| 30 | */ |
| 31 | static int bri_bar_length[3] = { |
| 32 | 0x80, |
| 33 | 0x80, |
| 34 | 0x20 |
| 35 | }; |
| 36 | static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a); |
| 37 | static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a); |
| 38 | static int diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a, |
| 39 | diva_xdi_um_cfg_cmd_t * cmd, int length); |
| 40 | static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a); |
| 41 | static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter); |
| 42 | static int diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter, |
| 43 | dword address, |
| 44 | const byte * data, dword length); |
| 45 | static int diva_bri_start_adapter(PISDN_ADAPTER IoAdapter, |
| 46 | dword start_address, dword features); |
| 47 | static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a); |
| 48 | |
| 49 | static void diva_bri_set_addresses(diva_os_xdi_adapter_t * a) |
| 50 | { |
| 51 | a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0; |
| 52 | a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 1; |
| 53 | a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2; |
| 54 | a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 1; |
| 55 | a->resources.pci.mem_type_id[MEM_TYPE_PORT] = 2; |
| 56 | a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 2; |
| 57 | |
| 58 | a->xdi_adapter.ram = a->resources.pci.addr[0]; |
| 59 | a->xdi_adapter.cfg = a->resources.pci.addr[1]; |
| 60 | a->xdi_adapter.Address = a->resources.pci.addr[2]; |
| 61 | |
| 62 | a->xdi_adapter.reset = a->xdi_adapter.cfg; |
| 63 | a->xdi_adapter.port = a->xdi_adapter.Address; |
| 64 | |
| 65 | a->xdi_adapter.ctlReg = a->xdi_adapter.port + M_PCI_RESET; |
| 66 | |
| 67 | a->xdi_adapter.reset += 0x4C; /* PLX 9050 !! */ |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | ** BAR0 - MEM Addr - 0x80 - NOT USED |
| 72 | ** BAR1 - I/O Addr - 0x80 |
| 73 | ** BAR2 - I/O Addr - 0x20 |
| 74 | */ |
| 75 | int diva_bri_init_card(diva_os_xdi_adapter_t * a) |
| 76 | { |
| 77 | int bar; |
| 78 | dword bar2 = 0, bar2_length = 0xffffffff; |
| 79 | word cmd = 0, cmd_org; |
| 80 | byte Bus, Slot; |
| 81 | void *hdev; |
| 82 | byte __iomem *p; |
| 83 | |
| 84 | /* |
| 85 | Set properties |
| 86 | */ |
| 87 | a->xdi_adapter.Properties = CardProperties[a->CardOrdinal]; |
| 88 | DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name)) |
| 89 | |
| 90 | /* |
| 91 | Get resources |
| 92 | */ |
| 93 | for (bar = 0; bar < 3; bar++) { |
| 94 | a->resources.pci.bar[bar] = |
| 95 | divasa_get_pci_bar(a->resources.pci.bus, |
| 96 | a->resources.pci.func, bar, |
| 97 | a->resources.pci.hdev); |
| 98 | if (!a->resources.pci.bar[bar]) { |
| 99 | DBG_ERR(("A: can't get BAR[%d]", bar)) |
| 100 | return (-1); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | a->resources.pci.irq = |
| 105 | (byte) divasa_get_pci_irq(a->resources.pci.bus, |
| 106 | a->resources.pci.func, |
| 107 | a->resources.pci.hdev); |
| 108 | if (!a->resources.pci.irq) { |
| 109 | DBG_ERR(("A: invalid irq")); |
| 110 | return (-1); |
| 111 | } |
| 112 | |
| 113 | /* |
| 114 | Get length of I/O bar 2 - it is different by older |
| 115 | EEPROM version |
| 116 | */ |
| 117 | Bus = a->resources.pci.bus; |
| 118 | Slot = a->resources.pci.func; |
| 119 | hdev = a->resources.pci.hdev; |
| 120 | |
| 121 | /* |
| 122 | Get plain original values of the BAR2 CDM registers |
| 123 | */ |
| 124 | PCIread(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev); |
| 125 | PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev); |
| 126 | /* |
| 127 | Disable device and get BAR2 length |
| 128 | */ |
| 129 | PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev); |
| 130 | PCIwrite(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev); |
| 131 | PCIread(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev); |
| 132 | /* |
| 133 | Restore BAR2 and CMD registers |
| 134 | */ |
| 135 | PCIwrite(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev); |
| 136 | PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev); |
| 137 | |
| 138 | /* |
| 139 | Calculate BAR2 length |
| 140 | */ |
| 141 | bar2_length = (~(bar2_length & ~7)) + 1; |
| 142 | DBG_LOG(("BAR[2] length=%lx", bar2_length)) |
| 143 | |
| 144 | /* |
| 145 | Map and register resources |
| 146 | */ |
| 147 | if (!(a->resources.pci.addr[0] = |
| 148 | divasa_remap_pci_bar(a, 0, a->resources.pci.bar[0], |
| 149 | bri_bar_length[0]))) { |
| 150 | DBG_ERR(("A: BRI, can't map BAR[0]")) |
| 151 | diva_bri_cleanup_adapter(a); |
| 152 | return (-1); |
| 153 | } |
| 154 | |
| 155 | sprintf(&a->port_name[0], "BRI %02x:%02x", |
| 156 | a->resources.pci.bus, a->resources.pci.func); |
| 157 | |
| 158 | if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1], |
| 159 | bri_bar_length[1], &a->port_name[0], 1)) { |
| 160 | DBG_ERR(("A: BRI, can't register BAR[1]")) |
| 161 | diva_bri_cleanup_adapter(a); |
| 162 | return (-1); |
| 163 | } |
| 164 | a->resources.pci.addr[1] = (void *) (unsigned long) a->resources.pci.bar[1]; |
| 165 | a->resources.pci.length[1] = bri_bar_length[1]; |
| 166 | |
| 167 | if (diva_os_register_io_port(a, 1, a->resources.pci.bar[2], |
| 168 | bar2_length, &a->port_name[0], 2)) { |
| 169 | DBG_ERR(("A: BRI, can't register BAR[2]")) |
| 170 | diva_bri_cleanup_adapter(a); |
| 171 | return (-1); |
| 172 | } |
| 173 | a->resources.pci.addr[2] = (void *) (unsigned long) a->resources.pci.bar[2]; |
| 174 | a->resources.pci.length[2] = bar2_length; |
| 175 | |
| 176 | /* |
| 177 | Set all memory areas |
| 178 | */ |
| 179 | diva_bri_set_addresses(a); |
| 180 | |
| 181 | /* |
| 182 | Get Serial Number |
| 183 | */ |
| 184 | a->xdi_adapter.serialNo = diva_bri_get_serial_number(a); |
| 185 | |
| 186 | /* |
| 187 | Register I/O ports with correct name now |
| 188 | */ |
| 189 | if (diva_bri_reregister_io(a)) { |
| 190 | diva_bri_cleanup_adapter(a); |
| 191 | return (-1); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | Initialize OS dependent objects |
| 196 | */ |
| 197 | if (diva_os_initialize_spin_lock |
| 198 | (&a->xdi_adapter.isr_spin_lock, "isr")) { |
| 199 | diva_bri_cleanup_adapter(a); |
| 200 | return (-1); |
| 201 | } |
| 202 | if (diva_os_initialize_spin_lock |
| 203 | (&a->xdi_adapter.data_spin_lock, "data")) { |
| 204 | diva_bri_cleanup_adapter(a); |
| 205 | return (-1); |
| 206 | } |
| 207 | |
| 208 | strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasbrid"); |
| 209 | |
| 210 | if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr, |
| 211 | DIDpcRoutine, &a->xdi_adapter)) { |
| 212 | diva_bri_cleanup_adapter(a); |
| 213 | return (-1); |
| 214 | } |
| 215 | /* |
| 216 | Do not initialize second DPC - only one thread will be created |
| 217 | */ |
| 218 | a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object; |
| 219 | |
| 220 | /* |
| 221 | Create entity table |
| 222 | */ |
| 223 | a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels; |
| 224 | a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info; |
| 225 | a->xdi_adapter.e_tbl = diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO)); |
| 226 | if (!a->xdi_adapter.e_tbl) { |
| 227 | diva_bri_cleanup_adapter(a); |
| 228 | return (-1); |
| 229 | } |
| 230 | memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO)); |
| 231 | |
| 232 | /* |
| 233 | Set up interface |
| 234 | */ |
| 235 | a->xdi_adapter.a.io = &a->xdi_adapter; |
| 236 | a->xdi_adapter.DIRequest = request; |
| 237 | a->interface.cleanup_adapter_proc = diva_bri_cleanup_adapter; |
| 238 | a->interface.cmd_proc = diva_bri_cmd_card_proc; |
| 239 | |
| 240 | p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter); |
| 241 | outpp(p, 0x41); |
| 242 | DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p); |
| 243 | |
| 244 | prepare_maestra_functions(&a->xdi_adapter); |
| 245 | |
| 246 | a->dsp_mask = 0x00000003; |
| 247 | |
| 248 | /* |
| 249 | Set IRQ handler |
| 250 | */ |
| 251 | a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq; |
| 252 | sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA BRI %ld", |
| 253 | (long) a->xdi_adapter.serialNo); |
| 254 | if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr, |
| 255 | a->xdi_adapter.irq_info.irq_name)) { |
| 256 | diva_bri_cleanup_adapter(a); |
| 257 | return (-1); |
| 258 | } |
| 259 | a->xdi_adapter.irq_info.registered = 1; |
| 260 | |
| 261 | diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name, |
| 262 | a->resources.pci.irq, a->xdi_adapter.serialNo); |
| 263 | |
| 264 | return (0); |
| 265 | } |
| 266 | |
| 267 | |
| 268 | static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a) |
| 269 | { |
| 270 | int i; |
| 271 | |
| 272 | if (a->xdi_adapter.Initialized) { |
| 273 | diva_bri_stop_adapter(a); |
| 274 | } |
| 275 | |
| 276 | /* |
| 277 | Remove ISR Handler |
| 278 | */ |
| 279 | if (a->xdi_adapter.irq_info.registered) { |
| 280 | diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr); |
| 281 | } |
| 282 | a->xdi_adapter.irq_info.registered = 0; |
| 283 | |
| 284 | if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) { |
| 285 | divasa_unmap_pci_bar(a->resources.pci.addr[0]); |
| 286 | a->resources.pci.addr[0] = NULL; |
| 287 | a->resources.pci.bar[0] = 0; |
| 288 | } |
| 289 | |
| 290 | for (i = 1; i < 3; i++) { |
| 291 | if (a->resources.pci.addr[i] && a->resources.pci.bar[i]) { |
| 292 | diva_os_register_io_port(a, 0, |
| 293 | a->resources.pci.bar[i], |
| 294 | a->resources.pci. |
| 295 | length[i], |
| 296 | &a->port_name[0], i); |
| 297 | a->resources.pci.addr[i] = NULL; |
| 298 | a->resources.pci.bar[i] = 0; |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | /* |
| 303 | Free OS objects |
| 304 | */ |
| 305 | diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr); |
| 306 | diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr); |
| 307 | |
| 308 | diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr); |
| 309 | a->xdi_adapter.isr_soft_isr.object = NULL; |
| 310 | |
| 311 | diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm"); |
| 312 | diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm"); |
| 313 | |
| 314 | /* |
| 315 | Free memory |
| 316 | */ |
| 317 | if (a->xdi_adapter.e_tbl) { |
| 318 | diva_os_free(0, a->xdi_adapter.e_tbl); |
| 319 | a->xdi_adapter.e_tbl = NULL; |
| 320 | } |
| 321 | |
| 322 | return (0); |
| 323 | } |
| 324 | |
| 325 | void diva_os_prepare_maestra_functions(PISDN_ADAPTER IoAdapter) |
| 326 | { |
| 327 | } |
| 328 | |
| 329 | /* |
| 330 | ** Get serial number |
| 331 | */ |
| 332 | static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a) |
| 333 | { |
| 334 | dword serNo = 0; |
| 335 | byte __iomem *confIO; |
| 336 | word serHi, serLo; |
| 337 | word __iomem *confMem; |
| 338 | |
| 339 | confIO = DIVA_OS_MEM_ATTACH_CFG(&a->xdi_adapter); |
| 340 | serHi = (word) (inppw(&confIO[0x22]) & 0x0FFF); |
| 341 | serLo = (word) (inppw(&confIO[0x26]) & 0x0FFF); |
| 342 | serNo = ((dword) serHi << 16) | (dword) serLo; |
| 343 | DIVA_OS_MEM_DETACH_CFG(&a->xdi_adapter, confIO); |
| 344 | |
| 345 | if ((serNo == 0) || (serNo == 0xFFFFFFFF)) { |
| 346 | DBG_FTL(("W: BRI use BAR[0] to get card serial number")) |
| 347 | |
| 348 | confMem = (word __iomem *)DIVA_OS_MEM_ATTACH_RAM(&a->xdi_adapter); |
| 349 | serHi = (word) (READ_WORD(&confMem[0x11]) & 0x0FFF); |
| 350 | serLo = (word) (READ_WORD(&confMem[0x13]) & 0x0FFF); |
| 351 | serNo = (((dword) serHi) << 16) | ((dword) serLo); |
| 352 | DIVA_OS_MEM_DETACH_RAM(&a->xdi_adapter, confMem); |
| 353 | } |
| 354 | |
| 355 | DBG_LOG(("Serial Number=%ld", serNo)) |
| 356 | |
| 357 | return (serNo); |
| 358 | } |
| 359 | |
| 360 | /* |
| 361 | ** Unregister I/O and register it with new name, |
| 362 | ** based on Serial Number |
| 363 | */ |
| 364 | static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a) |
| 365 | { |
| 366 | int i; |
| 367 | |
| 368 | for (i = 1; i < 3; i++) { |
| 369 | diva_os_register_io_port(a, 0, a->resources.pci.bar[i], |
| 370 | a->resources.pci.length[i], |
| 371 | &a->port_name[0], i); |
| 372 | a->resources.pci.addr[i] = NULL; |
| 373 | } |
| 374 | |
| 375 | sprintf(a->port_name, "DIVA BRI %ld", |
| 376 | (long) a->xdi_adapter.serialNo); |
| 377 | |
| 378 | for (i = 1; i < 3; i++) { |
| 379 | if (diva_os_register_io_port(a, 1, a->resources.pci.bar[i], |
| 380 | a->resources.pci.length[i], |
| 381 | &a->port_name[0], i)) { |
| 382 | DBG_ERR(("A: failed to reregister BAR[%d]", i)) |
| 383 | return (-1); |
| 384 | } |
| 385 | a->resources.pci.addr[i] = |
| 386 | (void *) (unsigned long) a->resources.pci.bar[i]; |
| 387 | } |
| 388 | |
| 389 | return (0); |
| 390 | } |
| 391 | |
| 392 | /* |
| 393 | ** Process command from user mode |
| 394 | */ |
| 395 | static int |
| 396 | diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a, |
| 397 | diva_xdi_um_cfg_cmd_t * cmd, int length) |
| 398 | { |
| 399 | int ret = -1; |
| 400 | |
| 401 | if (cmd->adapter != a->controller) { |
| 402 | DBG_ERR(("A: pri_cmd, invalid controller=%d != %d", |
| 403 | cmd->adapter, a->controller)) |
| 404 | return (-1); |
| 405 | } |
| 406 | |
| 407 | switch (cmd->command) { |
| 408 | case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL: |
| 409 | a->xdi_mbox.data_length = sizeof(dword); |
| 410 | a->xdi_mbox.data = |
| 411 | diva_os_malloc(0, a->xdi_mbox.data_length); |
| 412 | if (a->xdi_mbox.data) { |
| 413 | *(dword *) a->xdi_mbox.data = |
| 414 | (dword) a->CardOrdinal; |
| 415 | a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; |
| 416 | ret = 0; |
| 417 | } |
| 418 | break; |
| 419 | |
| 420 | case DIVA_XDI_UM_CMD_GET_SERIAL_NR: |
| 421 | a->xdi_mbox.data_length = sizeof(dword); |
| 422 | a->xdi_mbox.data = |
| 423 | diva_os_malloc(0, a->xdi_mbox.data_length); |
| 424 | if (a->xdi_mbox.data) { |
| 425 | *(dword *) a->xdi_mbox.data = |
| 426 | (dword) a->xdi_adapter.serialNo; |
| 427 | a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; |
| 428 | ret = 0; |
| 429 | } |
| 430 | break; |
| 431 | |
| 432 | case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG: |
| 433 | a->xdi_mbox.data_length = sizeof(dword) * 9; |
| 434 | a->xdi_mbox.data = |
| 435 | diva_os_malloc(0, a->xdi_mbox.data_length); |
| 436 | if (a->xdi_mbox.data) { |
| 437 | int i; |
| 438 | dword *data = (dword *) a->xdi_mbox.data; |
| 439 | |
| 440 | for (i = 0; i < 8; i++) { |
| 441 | *data++ = a->resources.pci.bar[i]; |
| 442 | } |
| 443 | *data++ = (dword) a->resources.pci.irq; |
| 444 | a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; |
| 445 | ret = 0; |
| 446 | } |
| 447 | break; |
| 448 | |
| 449 | case DIVA_XDI_UM_CMD_GET_CARD_STATE: |
| 450 | a->xdi_mbox.data_length = sizeof(dword); |
| 451 | a->xdi_mbox.data = |
| 452 | diva_os_malloc(0, a->xdi_mbox.data_length); |
| 453 | if (a->xdi_mbox.data) { |
| 454 | dword *data = (dword *) a->xdi_mbox.data; |
| 455 | if (!a->xdi_adapter.port) { |
| 456 | *data = 3; |
| 457 | } else if (a->xdi_adapter.trapped) { |
| 458 | *data = 2; |
| 459 | } else if (a->xdi_adapter.Initialized) { |
| 460 | *data = 1; |
| 461 | } else { |
| 462 | *data = 0; |
| 463 | } |
| 464 | a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY; |
| 465 | ret = 0; |
| 466 | } |
| 467 | break; |
| 468 | |
| 469 | case DIVA_XDI_UM_CMD_RESET_ADAPTER: |
| 470 | ret = diva_bri_reset_adapter(&a->xdi_adapter); |
| 471 | break; |
| 472 | |
| 473 | case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK: |
| 474 | ret = diva_bri_write_sdram_block(&a->xdi_adapter, |
| 475 | cmd->command_data. |
| 476 | write_sdram.offset, |
| 477 | (byte *) & cmd[1], |
| 478 | cmd->command_data. |
| 479 | write_sdram.length); |
| 480 | break; |
| 481 | |
| 482 | case DIVA_XDI_UM_CMD_START_ADAPTER: |
| 483 | ret = diva_bri_start_adapter(&a->xdi_adapter, |
| 484 | cmd->command_data.start. |
| 485 | offset, |
| 486 | cmd->command_data.start. |
| 487 | features); |
| 488 | break; |
| 489 | |
| 490 | case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES: |
| 491 | a->xdi_adapter.features = |
| 492 | cmd->command_data.features.features; |
| 493 | a->xdi_adapter.a.protocol_capabilities = |
| 494 | a->xdi_adapter.features; |
| 495 | DBG_TRC( |
| 496 | ("Set raw protocol features (%08x)", |
| 497 | a->xdi_adapter.features)) ret = 0; |
| 498 | break; |
| 499 | |
| 500 | case DIVA_XDI_UM_CMD_STOP_ADAPTER: |
| 501 | ret = diva_bri_stop_adapter(a); |
| 502 | break; |
| 503 | |
| 504 | case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY: |
| 505 | ret = diva_card_read_xlog(a); |
| 506 | break; |
| 507 | |
| 508 | default: |
| 509 | DBG_ERR( |
| 510 | ("A: A(%d) invalid cmd=%d", a->controller, |
| 511 | cmd->command))} |
| 512 | |
| 513 | return (ret); |
| 514 | } |
| 515 | |
| 516 | static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter) |
| 517 | { |
| 518 | byte __iomem *addrHi, *addrLo, *ioaddr; |
| 519 | dword i; |
| 520 | byte __iomem *Port; |
| 521 | |
| 522 | if (!IoAdapter->port) { |
| 523 | return (-1); |
| 524 | } |
| 525 | if (IoAdapter->Initialized) { |
| 526 | DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first", |
| 527 | IoAdapter->ANum)) return (-1); |
| 528 | } |
| 529 | (*(IoAdapter->rstFnc)) (IoAdapter); |
| 530 | diva_os_wait(100); |
| 531 | Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter); |
| 532 | addrHi = Port + |
| 533 | ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH); |
| 534 | addrLo = Port + ADDR; |
| 535 | ioaddr = Port + DATA; |
| 536 | /* |
| 537 | recover |
| 538 | */ |
| 539 | outpp(addrHi, (byte) 0); |
| 540 | outppw(addrLo, (word) 0); |
| 541 | outppw(ioaddr, (word) 0); |
| 542 | /* |
| 543 | clear shared memory |
| 544 | */ |
| 545 | outpp(addrHi, |
| 546 | (byte) ( |
| 547 | (IoAdapter->MemoryBase + IoAdapter->MemorySize - |
| 548 | BRI_SHARED_RAM_SIZE) >> 16)); |
| 549 | outppw(addrLo, 0); |
| 550 | for (i = 0; i < 0x8000; outppw(ioaddr, 0), ++i); |
| 551 | diva_os_wait(100); |
| 552 | |
| 553 | /* |
| 554 | clear signature |
| 555 | */ |
| 556 | outpp(addrHi, |
| 557 | (byte) ( |
| 558 | (IoAdapter->MemoryBase + IoAdapter->MemorySize - |
| 559 | BRI_SHARED_RAM_SIZE) >> 16)); |
| 560 | outppw(addrLo, 0x1e); |
| 561 | outpp(ioaddr, 0); |
| 562 | outpp(ioaddr, 0); |
| 563 | |
| 564 | outpp(addrHi, (byte) 0); |
| 565 | outppw(addrLo, (word) 0); |
| 566 | outppw(ioaddr, (word) 0); |
| 567 | |
| 568 | DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port); |
| 569 | |
| 570 | /* |
| 571 | Forget all outstanding entities |
| 572 | */ |
| 573 | IoAdapter->e_count = 0; |
| 574 | if (IoAdapter->e_tbl) { |
| 575 | memset(IoAdapter->e_tbl, 0x00, |
| 576 | IoAdapter->e_max * sizeof(E_INFO)); |
| 577 | } |
| 578 | IoAdapter->head = 0; |
| 579 | IoAdapter->tail = 0; |
| 580 | IoAdapter->assign = 0; |
| 581 | IoAdapter->trapped = 0; |
| 582 | |
| 583 | memset(&IoAdapter->a.IdTable[0], 0x00, |
| 584 | sizeof(IoAdapter->a.IdTable)); |
| 585 | memset(&IoAdapter->a.IdTypeTable[0], 0x00, |
| 586 | sizeof(IoAdapter->a.IdTypeTable)); |
| 587 | memset(&IoAdapter->a.FlowControlIdTable[0], 0x00, |
| 588 | sizeof(IoAdapter->a.FlowControlIdTable)); |
| 589 | memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00, |
| 590 | sizeof(IoAdapter->a.FlowControlSkipTable)); |
| 591 | memset(&IoAdapter->a.misc_flags_table[0], 0x00, |
| 592 | sizeof(IoAdapter->a.misc_flags_table)); |
| 593 | memset(&IoAdapter->a.rx_stream[0], 0x00, |
| 594 | sizeof(IoAdapter->a.rx_stream)); |
| 595 | memset(&IoAdapter->a.tx_stream[0], 0x00, |
| 596 | sizeof(IoAdapter->a.tx_stream)); |
| 597 | memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos)); |
| 598 | memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos)); |
| 599 | |
| 600 | return (0); |
| 601 | } |
| 602 | |
| 603 | static int |
| 604 | diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter, |
| 605 | dword address, const byte * data, dword length) |
| 606 | { |
| 607 | byte __iomem *addrHi, *addrLo, *ioaddr; |
| 608 | byte __iomem *Port; |
| 609 | |
| 610 | if (!IoAdapter->port) { |
| 611 | return (-1); |
| 612 | } |
| 613 | |
| 614 | Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter); |
| 615 | addrHi = Port + |
| 616 | ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH); |
| 617 | addrLo = Port + ADDR; |
| 618 | ioaddr = Port + DATA; |
| 619 | |
| 620 | while (length--) { |
| 621 | outpp(addrHi, (word) (address >> 16)); |
| 622 | outppw(addrLo, (word) (address & 0x0000ffff)); |
| 623 | outpp(ioaddr, *data++); |
| 624 | address++; |
| 625 | } |
| 626 | |
| 627 | DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port); |
| 628 | return (0); |
| 629 | } |
| 630 | |
| 631 | static int |
| 632 | diva_bri_start_adapter(PISDN_ADAPTER IoAdapter, |
| 633 | dword start_address, dword features) |
| 634 | { |
| 635 | byte __iomem *Port; |
| 636 | dword i, test; |
| 637 | byte __iomem *addrHi, *addrLo, *ioaddr; |
| 638 | int started = 0; |
| 639 | ADAPTER *a = &IoAdapter->a; |
| 640 | |
| 641 | if (IoAdapter->Initialized) { |
| 642 | DBG_ERR( |
| 643 | ("A: A(%d) bri_start_adapter, adapter already running", |
| 644 | IoAdapter->ANum)) return (-1); |
| 645 | } |
| 646 | if (!IoAdapter->port) { |
| 647 | DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped", |
| 648 | IoAdapter->ANum)) return (-1); |
| 649 | } |
| 650 | |
| 651 | sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum); |
| 652 | DBG_LOG(("A(%d) start BRI", IoAdapter->ANum)) |
| 653 | |
| 654 | Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter); |
| 655 | addrHi = Port + |
| 656 | ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH); |
| 657 | addrLo = Port + ADDR; |
| 658 | ioaddr = Port + DATA; |
| 659 | |
| 660 | outpp(addrHi, |
| 661 | (byte) ( |
| 662 | (IoAdapter->MemoryBase + IoAdapter->MemorySize - |
| 663 | BRI_SHARED_RAM_SIZE) >> 16)); |
| 664 | outppw(addrLo, 0x1e); |
| 665 | outppw(ioaddr, 0x00); |
| 666 | DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port); |
| 667 | |
| 668 | /* |
| 669 | start the protocol code |
| 670 | */ |
| 671 | Port = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter); |
| 672 | outpp(Port, 0x08); |
| 673 | DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, Port); |
| 674 | |
| 675 | Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter); |
| 676 | addrHi = Port + |
| 677 | ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH); |
| 678 | addrLo = Port + ADDR; |
| 679 | ioaddr = Port + DATA; |
| 680 | /* |
| 681 | wait for signature (max. 3 seconds) |
| 682 | */ |
| 683 | for (i = 0; i < 300; ++i) { |
| 684 | diva_os_wait(10); |
| 685 | outpp(addrHi, |
| 686 | (byte) ( |
| 687 | (IoAdapter->MemoryBase + |
| 688 | IoAdapter->MemorySize - |
| 689 | BRI_SHARED_RAM_SIZE) >> 16)); |
| 690 | outppw(addrLo, 0x1e); |
| 691 | test = (dword) inppw(ioaddr); |
| 692 | if (test == 0x4447) { |
| 693 | DBG_LOG( |
| 694 | ("Protocol startup time %d.%02d seconds", |
| 695 | (i / 100), (i % 100))) |
| 696 | started = 1; |
| 697 | break; |
| 698 | } |
| 699 | } |
| 700 | DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port); |
| 701 | |
| 702 | if (!started) { |
| 703 | DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X", |
| 704 | IoAdapter->ANum, IoAdapter->Properties.Name, |
| 705 | test)) |
| 706 | (*(IoAdapter->trapFnc)) (IoAdapter); |
| 707 | return (-1); |
| 708 | } |
| 709 | |
| 710 | IoAdapter->Initialized = 1; |
| 711 | |
| 712 | /* |
| 713 | Check Interrupt |
| 714 | */ |
| 715 | IoAdapter->IrqCount = 0; |
| 716 | a->ReadyInt = 1; |
| 717 | |
| 718 | if (IoAdapter->reset) { |
| 719 | Port = DIVA_OS_MEM_ATTACH_RESET(IoAdapter); |
| 720 | outpp(Port, 0x41); |
| 721 | DIVA_OS_MEM_DETACH_RESET(IoAdapter, Port); |
| 722 | } |
| 723 | |
| 724 | a->ram_out(a, &PR_RAM->ReadyInt, 1); |
| 725 | for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) { |
| 726 | diva_os_wait(10); |
| 727 | } |
| 728 | if (!IoAdapter->IrqCount) { |
| 729 | DBG_ERR( |
| 730 | ("A: A(%d) interrupt test failed", |
| 731 | IoAdapter->ANum)) |
| 732 | IoAdapter->Initialized = 0; |
| 733 | IoAdapter->stop(IoAdapter); |
| 734 | return (-1); |
| 735 | } |
| 736 | |
| 737 | IoAdapter->Properties.Features = (word) features; |
| 738 | diva_xdi_display_adapter_features(IoAdapter->ANum); |
| 739 | DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum)) |
| 740 | /* |
| 741 | Register with DIDD |
| 742 | */ |
| 743 | diva_xdi_didd_register_adapter(IoAdapter->ANum); |
| 744 | |
| 745 | return (0); |
| 746 | } |
| 747 | |
| 748 | static void diva_bri_clear_interrupts(diva_os_xdi_adapter_t * a) |
| 749 | { |
| 750 | PISDN_ADAPTER IoAdapter = &a->xdi_adapter; |
| 751 | |
| 752 | /* |
| 753 | clear any pending interrupt |
| 754 | */ |
| 755 | IoAdapter->disIrq(IoAdapter); |
| 756 | |
| 757 | IoAdapter->tst_irq(&IoAdapter->a); |
| 758 | IoAdapter->clr_irq(&IoAdapter->a); |
| 759 | IoAdapter->tst_irq(&IoAdapter->a); |
| 760 | |
| 761 | /* |
| 762 | kill pending dpcs |
| 763 | */ |
| 764 | diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr); |
| 765 | diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr); |
| 766 | } |
| 767 | |
| 768 | /* |
| 769 | ** Stop card |
| 770 | */ |
| 771 | static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a) |
| 772 | { |
| 773 | PISDN_ADAPTER IoAdapter = &a->xdi_adapter; |
| 774 | int i = 100; |
| 775 | |
| 776 | if (!IoAdapter->port) { |
| 777 | return (-1); |
| 778 | } |
| 779 | if (!IoAdapter->Initialized) { |
| 780 | DBG_ERR(("A: A(%d) can't stop BRI adapter - not running", |
| 781 | IoAdapter->ANum)) |
| 782 | return (-1); /* nothing to stop */ |
| 783 | } |
| 784 | IoAdapter->Initialized = 0; |
| 785 | |
| 786 | /* |
| 787 | Disconnect Adapter from DIDD |
| 788 | */ |
| 789 | diva_xdi_didd_remove_adapter(IoAdapter->ANum); |
| 790 | |
| 791 | /* |
| 792 | Stop interrupts |
| 793 | */ |
| 794 | a->clear_interrupts_proc = diva_bri_clear_interrupts; |
| 795 | IoAdapter->a.ReadyInt = 1; |
| 796 | IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt); |
| 797 | do { |
| 798 | diva_os_sleep(10); |
| 799 | } while (i-- && a->clear_interrupts_proc); |
| 800 | if (a->clear_interrupts_proc) { |
| 801 | diva_bri_clear_interrupts(a); |
| 802 | a->clear_interrupts_proc = NULL; |
| 803 | DBG_ERR(("A: A(%d) no final interrupt from BRI adapter", |
| 804 | IoAdapter->ANum)) |
| 805 | } |
| 806 | IoAdapter->a.ReadyInt = 0; |
| 807 | |
| 808 | /* |
| 809 | Stop and reset adapter |
| 810 | */ |
| 811 | IoAdapter->stop(IoAdapter); |
| 812 | |
| 813 | return (0); |
| 814 | } |