1/* 2 * Driver for ISAC-S and ISAC-SX 3 * ISDN Subscriber Access Controller for Terminals 4 * 5 * Author Kai Germaschewski 6 * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> 7 * 2001 by Karsten Keil <keil@isdn4linux.de> 8 * 9 * based upon Karsten Keil's original isac.c driver 10 * 11 * This software may be used and distributed according to the terms 12 * of the GNU General Public License, incorporated herein by reference. 13 * 14 * Thanks to Wizard Computersysteme GmbH, Bremervoerde and 15 * SoHaNet Technology GmbH, Berlin 16 * for supporting the development of this driver 17 */ 18 19/* TODO: 20 * specifically handle level vs edge triggered? 21 */ 22 23#include <linux/module.h> 24#include <linux/gfp.h> 25#include <linux/init.h> 26#include <linux/netdevice.h> 27#include "hisax_isac.h" 28 29// debugging cruft 30 31#define __debug_variable debug 32#include "hisax_debug.h" 33 34#ifdef CONFIG_HISAX_DEBUG 35static int debug = 1; 36module_param(debug, int, 0); 37 38static char *ISACVer[] = { 39 "2086/2186 V1.1", 40 "2085 B1", 41 "2085 B2", 42 "2085 V2.3" 43}; 44#endif 45 46MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>"); 47MODULE_DESCRIPTION("ISAC/ISAC-SX driver"); 48MODULE_LICENSE("GPL"); 49 50#define DBG_WARN 0x0001 51#define DBG_IRQ 0x0002 52#define DBG_L1M 0x0004 53#define DBG_PR 0x0008 54#define DBG_RFIFO 0x0100 55#define DBG_RPACKET 0x0200 56#define DBG_XFIFO 0x1000 57#define DBG_XPACKET 0x2000 58 59// we need to distinguish ISAC-S and ISAC-SX 60#define TYPE_ISAC 0x00 61#define TYPE_ISACSX 0x01 62 63// registers etc. 64#define ISAC_MASK 0x20 65#define ISAC_ISTA 0x20 66#define ISAC_ISTA_EXI 0x01 67#define ISAC_ISTA_SIN 0x02 68#define ISAC_ISTA_CISQ 0x04 69#define ISAC_ISTA_XPR 0x10 70#define ISAC_ISTA_RSC 0x20 71#define ISAC_ISTA_RPF 0x40 72#define ISAC_ISTA_RME 0x80 73 74#define ISAC_STAR 0x21 75#define ISAC_CMDR 0x21 76#define ISAC_CMDR_XRES 0x01 77#define ISAC_CMDR_XME 0x02 78#define ISAC_CMDR_XTF 0x08 79#define ISAC_CMDR_RRES 0x40 80#define ISAC_CMDR_RMC 0x80 81 82#define ISAC_EXIR 0x24 83#define ISAC_EXIR_MOS 0x04 84#define ISAC_EXIR_XDU 0x40 85#define ISAC_EXIR_XMR 0x80 86 87#define ISAC_ADF2 0x39 88#define ISAC_SPCR 0x30 89#define ISAC_ADF1 0x38 90 91#define ISAC_CIR0 0x31 92#define ISAC_CIX0 0x31 93#define ISAC_CIR0_CIC0 0x02 94#define ISAC_CIR0_CIC1 0x01 95 96#define ISAC_CIR1 0x33 97#define ISAC_CIX1 0x33 98#define ISAC_STCR 0x37 99#define ISAC_MODE 0x22 100 101#define ISAC_RSTA 0x27 102#define ISAC_RSTA_RDO 0x40 103#define ISAC_RSTA_CRC 0x20 104#define ISAC_RSTA_RAB 0x10 105 106#define ISAC_RBCL 0x25 107#define ISAC_RBCH 0x2A 108#define ISAC_TIMR 0x23 109#define ISAC_SQXR 0x3b 110#define ISAC_MOSR 0x3a 111#define ISAC_MOCR 0x3a 112#define ISAC_MOR0 0x32 113#define ISAC_MOX0 0x32 114#define ISAC_MOR1 0x34 115#define ISAC_MOX1 0x34 116 117#define ISAC_RBCH_XAC 0x80 118 119#define ISAC_CMD_TIM 0x0 120#define ISAC_CMD_RES 0x1 121#define ISAC_CMD_SSP 0x2 122#define ISAC_CMD_SCP 0x3 123#define ISAC_CMD_AR8 0x8 124#define ISAC_CMD_AR10 0x9 125#define ISAC_CMD_ARL 0xa 126#define ISAC_CMD_DI 0xf 127 128#define ISACSX_MASK 0x60 129#define ISACSX_ISTA 0x60 130#define ISACSX_ISTA_ICD 0x01 131#define ISACSX_ISTA_CIC 0x10 132 133#define ISACSX_MASKD 0x20 134#define ISACSX_ISTAD 0x20 135#define ISACSX_ISTAD_XDU 0x04 136#define ISACSX_ISTAD_XMR 0x08 137#define ISACSX_ISTAD_XPR 0x10 138#define ISACSX_ISTAD_RFO 0x20 139#define ISACSX_ISTAD_RPF 0x40 140#define ISACSX_ISTAD_RME 0x80 141 142#define ISACSX_CMDRD 0x21 143#define ISACSX_CMDRD_XRES 0x01 144#define ISACSX_CMDRD_XME 0x02 145#define ISACSX_CMDRD_XTF 0x08 146#define ISACSX_CMDRD_RRES 0x40 147#define ISACSX_CMDRD_RMC 0x80 148 149#define ISACSX_MODED 0x22 150 151#define ISACSX_RBCLD 0x26 152 153#define ISACSX_RSTAD 0x28 154#define ISACSX_RSTAD_RAB 0x10 155#define ISACSX_RSTAD_CRC 0x20 156#define ISACSX_RSTAD_RDO 0x40 157#define ISACSX_RSTAD_VFR 0x80 158 159#define ISACSX_CIR0 0x2e 160#define ISACSX_CIR0_CIC0 0x08 161#define ISACSX_CIX0 0x2e 162 163#define ISACSX_TR_CONF0 0x30 164 165#define ISACSX_TR_CONF2 0x32 166 167static struct Fsm l1fsm; 168 169enum { 170 ST_L1_RESET, 171 ST_L1_F3_PDOWN, 172 ST_L1_F3_PUP, 173 ST_L1_F3_PEND_DEACT, 174 ST_L1_F4, 175 ST_L1_F5, 176 ST_L1_F6, 177 ST_L1_F7, 178 ST_L1_F8, 179}; 180 181#define L1_STATE_COUNT (ST_L1_F8 + 1) 182 183static char *strL1State[] = 184{ 185 "ST_L1_RESET", 186 "ST_L1_F3_PDOWN", 187 "ST_L1_F3_PUP", 188 "ST_L1_F3_PEND_DEACT", 189 "ST_L1_F4", 190 "ST_L1_F5", 191 "ST_L1_F6", 192 "ST_L1_F7", 193 "ST_L1_F8", 194}; 195 196enum { 197 EV_PH_DR, // 0000 198 EV_PH_RES, // 0001 199 EV_PH_TMA, // 0010 200 EV_PH_SLD, // 0011 201 EV_PH_RSY, // 0100 202 EV_PH_DR6, // 0101 203 EV_PH_EI, // 0110 204 EV_PH_PU, // 0111 205 EV_PH_AR, // 1000 206 EV_PH_9, // 1001 207 EV_PH_ARL, // 1010 208 EV_PH_CVR, // 1011 209 EV_PH_AI8, // 1100 210 EV_PH_AI10, // 1101 211 EV_PH_AIL, // 1110 212 EV_PH_DC, // 1111 213 EV_PH_ACTIVATE_REQ, 214 EV_PH_DEACTIVATE_REQ, 215 EV_TIMER3, 216}; 217 218#define L1_EVENT_COUNT (EV_TIMER3 + 1) 219 220static char *strL1Event[] = 221{ 222 "EV_PH_DR", // 0000 223 "EV_PH_RES", // 0001 224 "EV_PH_TMA", // 0010 225 "EV_PH_SLD", // 0011 226 "EV_PH_RSY", // 0100 227 "EV_PH_DR6", // 0101 228 "EV_PH_EI", // 0110 229 "EV_PH_PU", // 0111 230 "EV_PH_AR", // 1000 231 "EV_PH_9", // 1001 232 "EV_PH_ARL", // 1010 233 "EV_PH_CVR", // 1011 234 "EV_PH_AI8", // 1100 235 "EV_PH_AI10", // 1101 236 "EV_PH_AIL", // 1110 237 "EV_PH_DC", // 1111 238 "EV_PH_ACTIVATE_REQ", 239 "EV_PH_DEACTIVATE_REQ", 240 "EV_TIMER3", 241}; 242 243static inline void D_L1L2(struct isac *isac, int pr, void *arg) 244{ 245 struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if; 246 247 DBG(DBG_PR, "pr %#x", pr); 248 ifc->l1l2(ifc, pr, arg); 249} 250 251static void ph_command(struct isac *isac, unsigned int command) 252{ 253 DBG(DBG_L1M, "ph_command %#x", command); 254 switch (isac->type) { 255 case TYPE_ISAC: 256 isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3); 257 break; 258 case TYPE_ISACSX: 259 isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1)); 260 break; 261 } 262} 263 264// ---------------------------------------------------------------------- 265 266static void l1_di(struct FsmInst *fi, int event, void *arg) 267{ 268 struct isac *isac = fi->userdata; 269 270 FsmChangeState(fi, ST_L1_RESET); 271 ph_command(isac, ISAC_CMD_DI); 272} 273 274static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg) 275{ 276 struct isac *isac = fi->userdata; 277 278 FsmChangeState(fi, ST_L1_RESET); 279 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); 280 ph_command(isac, ISAC_CMD_DI); 281} 282 283static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg) 284{ 285 FsmChangeState(fi, ST_L1_F3_PDOWN); 286} 287 288static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg) 289{ 290 struct isac *isac = fi->userdata; 291 292 FsmChangeState(fi, ST_L1_F3_PEND_DEACT); 293 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); 294 ph_command(isac, ISAC_CMD_DI); 295} 296 297static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg) 298{ 299 struct isac *isac = fi->userdata; 300 301 FsmChangeState(fi, ST_L1_F3_PEND_DEACT); 302 ph_command(isac, ISAC_CMD_DI); 303} 304 305static void l1_go_f4(struct FsmInst *fi, int event, void *arg) 306{ 307 FsmChangeState(fi, ST_L1_F4); 308} 309 310static void l1_go_f5(struct FsmInst *fi, int event, void *arg) 311{ 312 FsmChangeState(fi, ST_L1_F5); 313} 314 315static void l1_go_f6(struct FsmInst *fi, int event, void *arg) 316{ 317 FsmChangeState(fi, ST_L1_F6); 318} 319 320static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) 321{ 322 struct isac *isac = fi->userdata; 323 324 FsmChangeState(fi, ST_L1_F6); 325 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); 326} 327 328static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) 329{ 330 struct isac *isac = fi->userdata; 331 332 FsmDelTimer(&isac->timer, 0); 333 FsmChangeState(fi, ST_L1_F7); 334 ph_command(isac, ISAC_CMD_AR8); 335 D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL); 336} 337 338static void l1_go_f8(struct FsmInst *fi, int event, void *arg) 339{ 340 FsmChangeState(fi, ST_L1_F8); 341} 342 343static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) 344{ 345 struct isac *isac = fi->userdata; 346 347 FsmChangeState(fi, ST_L1_F8); 348 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); 349} 350 351static void l1_ar8(struct FsmInst *fi, int event, void *arg) 352{ 353 struct isac *isac = fi->userdata; 354 355 FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); 356 ph_command(isac, ISAC_CMD_AR8); 357} 358 359static void l1_timer3(struct FsmInst *fi, int event, void *arg) 360{ 361 struct isac *isac = fi->userdata; 362 363 ph_command(isac, ISAC_CMD_DI); 364 D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); 365} 366 367// state machines according to data sheet PSB 2186 / 3186 368 369static struct FsmNode L1FnList[] __initdata = 370{ 371 {ST_L1_RESET, EV_PH_RES, l1_di}, 372 {ST_L1_RESET, EV_PH_EI, l1_di}, 373 {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown}, 374 {ST_L1_RESET, EV_PH_AR, l1_go_f6}, 375 {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind}, 376 377 {ST_L1_F3_PDOWN, EV_PH_RES, l1_di}, 378 {ST_L1_F3_PDOWN, EV_PH_EI, l1_di}, 379 {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6}, 380 {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5}, 381 {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4}, 382 {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind}, 383 {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8}, 384 {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3}, 385 386 {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di}, 387 {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di}, 388 {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown}, 389 {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5}, 390 {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6}, 391 {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind}, 392 393 {ST_L1_F4, EV_PH_RES, l1_di}, 394 {ST_L1_F4, EV_PH_EI, l1_di}, 395 {ST_L1_F4, EV_PH_RSY, l1_go_f5}, 396 {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind}, 397 {ST_L1_F4, EV_TIMER3, l1_timer3}, 398 {ST_L1_F4, EV_PH_DC, l1_go_f3pdown}, 399 400 {ST_L1_F5, EV_PH_RES, l1_di}, 401 {ST_L1_F5, EV_PH_EI, l1_di}, 402 {ST_L1_F5, EV_PH_AR, l1_go_f6}, 403 {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind}, 404 {ST_L1_F5, EV_TIMER3, l1_timer3}, 405 {ST_L1_F5, EV_PH_DR, l1_go_f3pend}, 406 {ST_L1_F5, EV_PH_DC, l1_go_f3pdown}, 407 408 {ST_L1_F6, EV_PH_RES, l1_di}, 409 {ST_L1_F6, EV_PH_EI, l1_di}, 410 {ST_L1_F6, EV_PH_RSY, l1_go_f8}, 411 {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind}, 412 {ST_L1_F6, EV_PH_DR6, l1_go_f3pend}, 413 {ST_L1_F6, EV_TIMER3, l1_timer3}, 414 {ST_L1_F6, EV_PH_DC, l1_go_f3pdown}, 415 416 {ST_L1_F7, EV_PH_RES, l1_di_deact_ind}, 417 {ST_L1_F7, EV_PH_EI, l1_di_deact_ind}, 418 {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind}, 419 {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind}, 420 {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind}, 421 422 {ST_L1_F8, EV_PH_RES, l1_di}, 423 {ST_L1_F8, EV_PH_EI, l1_di}, 424 {ST_L1_F8, EV_PH_AR, l1_go_f6}, 425 {ST_L1_F8, EV_PH_DR, l1_go_f3pend}, 426 {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind}, 427 {ST_L1_F8, EV_TIMER3, l1_timer3}, 428 {ST_L1_F8, EV_PH_DC, l1_go_f3pdown}, 429}; 430 431static void l1m_debug(struct FsmInst *fi, char *fmt, ...) 432{ 433 va_list args; 434 char buf[256]; 435 436 va_start(args, fmt); 437 vsnprintf(buf, sizeof(buf), fmt, args); 438 DBG(DBG_L1M, "%s", buf); 439 va_end(args); 440} 441 442static void isac_version(struct isac *cs) 443{ 444 int val; 445 446 val = cs->read_isac(cs, ISAC_RBCH); 447 DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]); 448} 449 450static void isac_empty_fifo(struct isac *isac, int count) 451{ 452 // this also works for isacsx, since 453 // CMDR(D) register works the same 454 u_char *ptr; 455 456 DBG(DBG_IRQ, "count %d", count); 457 458 if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) { 459 DBG(DBG_WARN, "overrun %d", isac->rcvidx + count); 460 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); 461 isac->rcvidx = 0; 462 return; 463 } 464 ptr = isac->rcvbuf + isac->rcvidx; 465 isac->rcvidx += count; 466 isac->read_isac_fifo(isac, ptr, count); 467 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); 468 DBG_PACKET(DBG_RFIFO, ptr, count); 469} 470 471static void isac_fill_fifo(struct isac *isac) 472{ 473 // this also works for isacsx, since 474 // CMDR(D) register works the same 475 476 int count; 477 unsigned char cmd; 478 u_char *ptr; 479 480 BUG_ON(!isac->tx_skb); 481 482 count = isac->tx_skb->len; 483 BUG_ON(count <= 0); 484 485 DBG(DBG_IRQ, "count %d", count); 486 487 if (count > 0x20) { 488 count = 0x20; 489 cmd = ISAC_CMDR_XTF; 490 } else { 491 cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; 492 } 493 494 ptr = isac->tx_skb->data; 495 skb_pull(isac->tx_skb, count); 496 isac->tx_cnt += count; 497 DBG_PACKET(DBG_XFIFO, ptr, count); 498 isac->write_isac_fifo(isac, ptr, count); 499 isac->write_isac(isac, ISAC_CMDR, cmd); 500} 501 502static void isac_retransmit(struct isac *isac) 503{ 504 if (!isac->tx_skb) { 505 DBG(DBG_WARN, "no skb"); 506 return; 507 } 508 skb_push(isac->tx_skb, isac->tx_cnt); 509 isac->tx_cnt = 0; 510} 511 512 513static inline void isac_cisq_interrupt(struct isac *isac) 514{ 515 unsigned char val; 516 517 val = isac->read_isac(isac, ISAC_CIR0); 518 DBG(DBG_IRQ, "CIR0 %#x", val); 519 if (val & ISAC_CIR0_CIC0) { 520 DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf); 521 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); 522 } 523 if (val & ISAC_CIR0_CIC1) { 524 val = isac->read_isac(isac, ISAC_CIR1); 525 DBG(DBG_WARN, "ISAC CIR1 %#x", val); 526 } 527} 528 529static inline void isac_rme_interrupt(struct isac *isac) 530{ 531 unsigned char val; 532 int count; 533 struct sk_buff *skb; 534 535 val = isac->read_isac(isac, ISAC_RSTA); 536 if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB)) 537 != ISAC_RSTA_CRC) { 538 DBG(DBG_WARN, "RSTA %#x, dropped", val); 539 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); 540 goto out; 541 } 542 543 count = isac->read_isac(isac, ISAC_RBCL) & 0x1f; 544 DBG(DBG_IRQ, "RBCL %#x", count); 545 if (count == 0) 546 count = 0x20; 547 548 isac_empty_fifo(isac, count); 549 count = isac->rcvidx; 550 if (count < 1) { 551 DBG(DBG_WARN, "count %d < 1", count); 552 goto out; 553 } 554 555 skb = alloc_skb(count, GFP_ATOMIC); 556 if (!skb) { 557 DBG(DBG_WARN, "no memory, dropping\n"); 558 goto out; 559 } 560 memcpy(skb_put(skb, count), isac->rcvbuf, count); 561 DBG_SKB(DBG_RPACKET, skb); 562 D_L1L2(isac, PH_DATA | INDICATION, skb); 563out: 564 isac->rcvidx = 0; 565} 566 567static inline void isac_xpr_interrupt(struct isac *isac) 568{ 569 if (!isac->tx_skb) 570 return; 571 572 if (isac->tx_skb->len > 0) { 573 isac_fill_fifo(isac); 574 return; 575 } 576 dev_kfree_skb_irq(isac->tx_skb); 577 isac->tx_cnt = 0; 578 isac->tx_skb = NULL; 579 D_L1L2(isac, PH_DATA | CONFIRM, NULL); 580} 581 582static inline void isac_exi_interrupt(struct isac *isac) 583{ 584 unsigned char val; 585 586 val = isac->read_isac(isac, ISAC_EXIR); 587 DBG(2, "EXIR %#x", val); 588 589 if (val & ISAC_EXIR_XMR) { 590 DBG(DBG_WARN, "ISAC XMR"); 591 isac_retransmit(isac); 592 } 593 if (val & ISAC_EXIR_XDU) { 594 DBG(DBG_WARN, "ISAC XDU"); 595 isac_retransmit(isac); 596 } 597 if (val & ISAC_EXIR_MOS) { /* MOS */ 598 DBG(DBG_WARN, "MOS"); 599 val = isac->read_isac(isac, ISAC_MOSR); 600 DBG(2, "ISAC MOSR %#x", val); 601 } 602} 603 604void isac_irq(struct isac *isac) 605{ 606 unsigned char val; 607 608 val = isac->read_isac(isac, ISAC_ISTA); 609 DBG(DBG_IRQ, "ISTA %#x", val); 610 611 if (val & ISAC_ISTA_EXI) { 612 DBG(DBG_IRQ, "EXI"); 613 isac_exi_interrupt(isac); 614 } 615 if (val & ISAC_ISTA_XPR) { 616 DBG(DBG_IRQ, "XPR"); 617 isac_xpr_interrupt(isac); 618 } 619 if (val & ISAC_ISTA_RME) { 620 DBG(DBG_IRQ, "RME"); 621 isac_rme_interrupt(isac); 622 } 623 if (val & ISAC_ISTA_RPF) { 624 DBG(DBG_IRQ, "RPF"); 625 isac_empty_fifo(isac, 0x20); 626 } 627 if (val & ISAC_ISTA_CISQ) { 628 DBG(DBG_IRQ, "CISQ"); 629 isac_cisq_interrupt(isac); 630 } 631 if (val & ISAC_ISTA_RSC) { 632 DBG(DBG_WARN, "RSC"); 633 } 634 if (val & ISAC_ISTA_SIN) { 635 DBG(DBG_WARN, "SIN"); 636 } 637 isac->write_isac(isac, ISAC_MASK, 0xff); 638 isac->write_isac(isac, ISAC_MASK, 0x00); 639} 640 641// ====================================================================== 642 643static inline void isacsx_cic_interrupt(struct isac *isac) 644{ 645 unsigned char val; 646 647 val = isac->read_isac(isac, ISACSX_CIR0); 648 DBG(DBG_IRQ, "CIR0 %#x", val); 649 if (val & ISACSX_CIR0_CIC0) { 650 DBG(DBG_IRQ, "CODR0 %#x", val >> 4); 651 FsmEvent(&isac->l1m, val >> 4, NULL); 652 } 653} 654 655static inline void isacsx_rme_interrupt(struct isac *isac) 656{ 657 int count; 658 struct sk_buff *skb; 659 unsigned char val; 660 661 val = isac->read_isac(isac, ISACSX_RSTAD); 662 if ((val & (ISACSX_RSTAD_VFR | 663 ISACSX_RSTAD_RDO | 664 ISACSX_RSTAD_CRC | 665 ISACSX_RSTAD_RAB)) 666 != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) { 667 DBG(DBG_WARN, "RSTAD %#x, dropped", val); 668 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); 669 goto out; 670 } 671 672 count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f; 673 DBG(DBG_IRQ, "RBCLD %#x", count); 674 if (count == 0) 675 count = 0x20; 676 677 isac_empty_fifo(isac, count); 678 // strip trailing status byte 679 count = isac->rcvidx - 1; 680 if (count < 1) { 681 DBG(DBG_WARN, "count %d < 1", count); 682 goto out; 683 } 684 685 skb = dev_alloc_skb(count); 686 if (!skb) { 687 DBG(DBG_WARN, "no memory, dropping"); 688 goto out; 689 } 690 memcpy(skb_put(skb, count), isac->rcvbuf, count); 691 DBG_SKB(DBG_RPACKET, skb); 692 D_L1L2(isac, PH_DATA | INDICATION, skb); 693out: 694 isac->rcvidx = 0; 695} 696 697static inline void isacsx_xpr_interrupt(struct isac *isac) 698{ 699 if (!isac->tx_skb) 700 return; 701 702 if (isac->tx_skb->len > 0) { 703 isac_fill_fifo(isac); 704 return; 705 } 706 dev_kfree_skb_irq(isac->tx_skb); 707 isac->tx_skb = NULL; 708 isac->tx_cnt = 0; 709 D_L1L2(isac, PH_DATA | CONFIRM, NULL); 710} 711 712static inline void isacsx_icd_interrupt(struct isac *isac) 713{ 714 unsigned char val; 715 716 val = isac->read_isac(isac, ISACSX_ISTAD); 717 DBG(DBG_IRQ, "ISTAD %#x", val); 718 if (val & ISACSX_ISTAD_XDU) { 719 DBG(DBG_WARN, "ISTAD XDU"); 720 isac_retransmit(isac); 721 } 722 if (val & ISACSX_ISTAD_XMR) { 723 DBG(DBG_WARN, "ISTAD XMR"); 724 isac_retransmit(isac); 725 } 726 if (val & ISACSX_ISTAD_XPR) { 727 DBG(DBG_IRQ, "ISTAD XPR"); 728 isacsx_xpr_interrupt(isac); 729 } 730 if (val & ISACSX_ISTAD_RFO) { 731 DBG(DBG_WARN, "ISTAD RFO"); 732 isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); 733 } 734 if (val & ISACSX_ISTAD_RME) { 735 DBG(DBG_IRQ, "ISTAD RME"); 736 isacsx_rme_interrupt(isac); 737 } 738 if (val & ISACSX_ISTAD_RPF) { 739 DBG(DBG_IRQ, "ISTAD RPF"); 740 isac_empty_fifo(isac, 0x20); 741 } 742} 743 744void isacsx_irq(struct isac *isac) 745{ 746 unsigned char val; 747 748 val = isac->read_isac(isac, ISACSX_ISTA); 749 DBG(DBG_IRQ, "ISTA %#x", val); 750 751 if (val & ISACSX_ISTA_ICD) 752 isacsx_icd_interrupt(isac); 753 if (val & ISACSX_ISTA_CIC) 754 isacsx_cic_interrupt(isac); 755} 756 757void isac_init(struct isac *isac) 758{ 759 isac->tx_skb = NULL; 760 isac->l1m.fsm = &l1fsm; 761 isac->l1m.state = ST_L1_RESET; 762#ifdef CONFIG_HISAX_DEBUG 763 isac->l1m.debug = 1; 764#else 765 isac->l1m.debug = 0; 766#endif 767 isac->l1m.userdata = isac; 768 isac->l1m.printdebug = l1m_debug; 769 FsmInitTimer(&isac->l1m, &isac->timer); 770} 771 772void isac_setup(struct isac *isac) 773{ 774 int val, eval; 775 776 isac->type = TYPE_ISAC; 777 isac_version(isac); 778 779 ph_command(isac, ISAC_CMD_RES); 780 781 isac->write_isac(isac, ISAC_MASK, 0xff); 782 isac->mocr = 0xaa; 783 if (test_bit(ISAC_IOM1, &isac->flags)) { 784 /* IOM 1 Mode */ 785 isac->write_isac(isac, ISAC_ADF2, 0x0); 786 isac->write_isac(isac, ISAC_SPCR, 0xa); 787 isac->write_isac(isac, ISAC_ADF1, 0x2); 788 isac->write_isac(isac, ISAC_STCR, 0x70); 789 isac->write_isac(isac, ISAC_MODE, 0xc9); 790 } else { 791 /* IOM 2 Mode */ 792 if (!isac->adf2) 793 isac->adf2 = 0x80; 794 isac->write_isac(isac, ISAC_ADF2, isac->adf2); 795 isac->write_isac(isac, ISAC_SQXR, 0x2f); 796 isac->write_isac(isac, ISAC_SPCR, 0x00); 797 isac->write_isac(isac, ISAC_STCR, 0x70); 798 isac->write_isac(isac, ISAC_MODE, 0xc9); 799 isac->write_isac(isac, ISAC_TIMR, 0x00); 800 isac->write_isac(isac, ISAC_ADF1, 0x00); 801 } 802 val = isac->read_isac(isac, ISAC_STAR); 803 DBG(2, "ISAC STAR %x", val); 804 val = isac->read_isac(isac, ISAC_MODE); 805 DBG(2, "ISAC MODE %x", val); 806 val = isac->read_isac(isac, ISAC_ADF2); 807 DBG(2, "ISAC ADF2 %x", val); 808 val = isac->read_isac(isac, ISAC_ISTA); 809 DBG(2, "ISAC ISTA %x", val); 810 if (val & 0x01) { 811 eval = isac->read_isac(isac, ISAC_EXIR); 812 DBG(2, "ISAC EXIR %x", eval); 813 } 814 val = isac->read_isac(isac, ISAC_CIR0); 815 DBG(2, "ISAC CIR0 %x", val); 816 FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); 817 818 isac->write_isac(isac, ISAC_MASK, 0x0); 819 // RESET Receiver and Transmitter 820 isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES); 821} 822 823void isacsx_setup(struct isac *isac) 824{ 825 isac->type = TYPE_ISACSX; 826 // clear LDD 827 isac->write_isac(isac, ISACSX_TR_CONF0, 0x00); 828 // enable transmitter 829 isac->write_isac(isac, ISACSX_TR_CONF2, 0x00); 830 // transparent mode 0, RAC, stop/go 831 isac->write_isac(isac, ISACSX_MODED, 0xc9); 832 // all HDLC IRQ unmasked 833 isac->write_isac(isac, ISACSX_MASKD, 0x03); 834 // unmask ICD, CID IRQs 835 isac->write_isac(isac, ISACSX_MASK, 836 ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC)); 837} 838 839void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) 840{ 841 struct isac *isac = hisax_d_if->priv; 842 struct sk_buff *skb = arg; 843 844 DBG(DBG_PR, "pr %#x", pr); 845 846 switch (pr) { 847 case PH_ACTIVATE | REQUEST: 848 FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL); 849 break; 850 case PH_DEACTIVATE | REQUEST: 851 FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL); 852 break; 853 case PH_DATA | REQUEST: 854 DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); 855 DBG_SKB(DBG_XPACKET, skb); 856 if (isac->l1m.state != ST_L1_F7) { 857 DBG(1, "L1 wrong state %d\n", isac->l1m.state); 858 dev_kfree_skb(skb); 859 break; 860 } 861 BUG_ON(isac->tx_skb); 862 863 isac->tx_skb = skb; 864 isac_fill_fifo(isac); 865 break; 866 } 867} 868 869static int __init hisax_isac_init(void) 870{ 871 printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n"); 872 873 l1fsm.state_count = L1_STATE_COUNT; 874 l1fsm.event_count = L1_EVENT_COUNT; 875 l1fsm.strState = strL1State; 876 l1fsm.strEvent = strL1Event; 877 return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); 878} 879 880static void __exit hisax_isac_exit(void) 881{ 882 FsmFree(&l1fsm); 883} 884 885EXPORT_SYMBOL(isac_init); 886EXPORT_SYMBOL(isac_d_l2l1); 887 888EXPORT_SYMBOL(isacsx_setup); 889EXPORT_SYMBOL(isacsx_irq); 890 891EXPORT_SYMBOL(isac_setup); 892EXPORT_SYMBOL(isac_irq); 893 894module_init(hisax_isac_init); 895module_exit(hisax_isac_exit); 896