18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * isac.c ISAC specific routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author Karsten Keil <keil@isdn4linux.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/irqreturn.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 148c2ecf20Sopenharmony_ci#include "ipac.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DBUSY_TIMER_VALUE 80 188c2ecf20Sopenharmony_ci#define ARCOFI_USE 1 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define ISAC_REV "2.0" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 238c2ecf20Sopenharmony_ciMODULE_VERSION(ISAC_REV); 248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off)) 278c2ecf20Sopenharmony_ci#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v)) 288c2ecf20Sopenharmony_ci#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o)) 298c2ecf20Sopenharmony_ci#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v)) 308c2ecf20Sopenharmony_ci#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o)) 318c2ecf20Sopenharmony_ci#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v)) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic inline void 348c2ecf20Sopenharmony_ciph_command(struct isac_hw *isac, u8 command) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci pr_debug("%s: ph_command %x\n", isac->name, command); 378c2ecf20Sopenharmony_ci if (isac->type & IPAC_TYPE_ISACX) 388c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE); 398c2ecf20Sopenharmony_ci else 408c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CIX0, (command << 2) | 3); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void 448c2ecf20Sopenharmony_ciisac_ph_state_change(struct isac_hw *isac) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci switch (isac->state) { 478c2ecf20Sopenharmony_ci case (ISAC_IND_RS): 488c2ecf20Sopenharmony_ci case (ISAC_IND_EI): 498c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_DUI); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci schedule_event(&isac->dch, FLG_PHCHANGE); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void 558c2ecf20Sopenharmony_ciisac_ph_state_bh(struct dchannel *dch) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct isac_hw *isac = container_of(dch, struct isac_hw, dch); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci switch (isac->state) { 608c2ecf20Sopenharmony_ci case ISAC_IND_RS: 618c2ecf20Sopenharmony_ci case ISAC_IND_EI: 628c2ecf20Sopenharmony_ci dch->state = 0; 638c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case ISAC_IND_DID: 668c2ecf20Sopenharmony_ci dch->state = 3; 678c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_DEACT_CNF); 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci case ISAC_IND_DR: 708c2ecf20Sopenharmony_ci case ISAC_IND_DR6: 718c2ecf20Sopenharmony_ci dch->state = 3; 728c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci case ISAC_IND_PU: 758c2ecf20Sopenharmony_ci dch->state = 4; 768c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_POWERUP_IND); 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case ISAC_IND_RSY: 798c2ecf20Sopenharmony_ci if (dch->state <= 5) { 808c2ecf20Sopenharmony_ci dch->state = 5; 818c2ecf20Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci dch->state = 8; 848c2ecf20Sopenharmony_ci l1_event(dch->l1, LOSTFRAMING); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci case ISAC_IND_ARD: 888c2ecf20Sopenharmony_ci dch->state = 6; 898c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO2); 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case ISAC_IND_AI8: 928c2ecf20Sopenharmony_ci dch->state = 7; 938c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci case ISAC_IND_AI10: 968c2ecf20Sopenharmony_ci dch->state = 7; 978c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO4_P10); 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci pr_debug("%s: TE newstate %x\n", isac->name, dch->state); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void 1048c2ecf20Sopenharmony_ciisac_empty_fifo(struct isac_hw *isac, int count) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u8 *ptr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci pr_debug("%s: %s %d\n", isac->name, __func__, count); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!isac->dch.rx_skb) { 1118c2ecf20Sopenharmony_ci isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC); 1128c2ecf20Sopenharmony_ci if (!isac->dch.rx_skb) { 1138c2ecf20Sopenharmony_ci pr_info("%s: D receive out of memory\n", isac->name); 1148c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, 0x80); 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) { 1198c2ecf20Sopenharmony_ci pr_debug("%s: %s overrun %d\n", isac->name, __func__, 1208c2ecf20Sopenharmony_ci isac->dch.rx_skb->len + count); 1218c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, 0x80); 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci ptr = skb_put(isac->dch.rx_skb, count); 1258c2ecf20Sopenharmony_ci isac->read_fifo(isac->dch.hw, isac->off, ptr, count); 1268c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, 0x80); 1278c2ecf20Sopenharmony_ci if (isac->dch.debug & DEBUG_HW_DFIFO) { 1288c2ecf20Sopenharmony_ci char pfx[MISDN_MAX_IDLEN + 16]; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ", 1318c2ecf20Sopenharmony_ci isac->name, count); 1328c2ecf20Sopenharmony_ci print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void 1378c2ecf20Sopenharmony_ciisac_fill_fifo(struct isac_hw *isac) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci int count, more; 1408c2ecf20Sopenharmony_ci u8 *ptr; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (!isac->dch.tx_skb) 1438c2ecf20Sopenharmony_ci return; 1448c2ecf20Sopenharmony_ci count = isac->dch.tx_skb->len - isac->dch.tx_idx; 1458c2ecf20Sopenharmony_ci if (count <= 0) 1468c2ecf20Sopenharmony_ci return; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci more = 0; 1498c2ecf20Sopenharmony_ci if (count > 32) { 1508c2ecf20Sopenharmony_ci more = !0; 1518c2ecf20Sopenharmony_ci count = 32; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci pr_debug("%s: %s %d\n", isac->name, __func__, count); 1548c2ecf20Sopenharmony_ci ptr = isac->dch.tx_skb->data + isac->dch.tx_idx; 1558c2ecf20Sopenharmony_ci isac->dch.tx_idx += count; 1568c2ecf20Sopenharmony_ci isac->write_fifo(isac->dch.hw, isac->off, ptr, count); 1578c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa); 1588c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { 1598c2ecf20Sopenharmony_ci pr_debug("%s: %s dbusytimer running\n", isac->name, __func__); 1608c2ecf20Sopenharmony_ci del_timer(&isac->dch.timer); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); 1638c2ecf20Sopenharmony_ci add_timer(&isac->dch.timer); 1648c2ecf20Sopenharmony_ci if (isac->dch.debug & DEBUG_HW_DFIFO) { 1658c2ecf20Sopenharmony_ci char pfx[MISDN_MAX_IDLEN + 16]; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ", 1688c2ecf20Sopenharmony_ci isac->name, count); 1698c2ecf20Sopenharmony_ci print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void 1748c2ecf20Sopenharmony_ciisac_rme_irq(struct isac_hw *isac) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci u8 val, count; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_RSTA); 1798c2ecf20Sopenharmony_ci if ((val & 0x70) != 0x20) { 1808c2ecf20Sopenharmony_ci if (val & 0x40) { 1818c2ecf20Sopenharmony_ci pr_debug("%s: ISAC RDO\n", isac->name); 1828c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 1838c2ecf20Sopenharmony_ci isac->dch.err_rx++; 1848c2ecf20Sopenharmony_ci#endif 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci if (!(val & 0x20)) { 1878c2ecf20Sopenharmony_ci pr_debug("%s: ISAC CRC error\n", isac->name); 1888c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 1898c2ecf20Sopenharmony_ci isac->dch.err_crc++; 1908c2ecf20Sopenharmony_ci#endif 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, 0x80); 1938c2ecf20Sopenharmony_ci dev_kfree_skb(isac->dch.rx_skb); 1948c2ecf20Sopenharmony_ci isac->dch.rx_skb = NULL; 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci count = ReadISAC(isac, ISAC_RBCL) & 0x1f; 1978c2ecf20Sopenharmony_ci if (count == 0) 1988c2ecf20Sopenharmony_ci count = 32; 1998c2ecf20Sopenharmony_ci isac_empty_fifo(isac, count); 2008c2ecf20Sopenharmony_ci recv_Dchannel(&isac->dch); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void 2058c2ecf20Sopenharmony_ciisac_xpr_irq(struct isac_hw *isac) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) 2088c2ecf20Sopenharmony_ci del_timer(&isac->dch.timer); 2098c2ecf20Sopenharmony_ci if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { 2108c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 2118c2ecf20Sopenharmony_ci } else { 2128c2ecf20Sopenharmony_ci dev_kfree_skb(isac->dch.tx_skb); 2138c2ecf20Sopenharmony_ci if (get_next_dframe(&isac->dch)) 2148c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void 2198c2ecf20Sopenharmony_ciisac_retransmit(struct isac_hw *isac) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) 2228c2ecf20Sopenharmony_ci del_timer(&isac->dch.timer); 2238c2ecf20Sopenharmony_ci if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) { 2248c2ecf20Sopenharmony_ci /* Restart frame */ 2258c2ecf20Sopenharmony_ci isac->dch.tx_idx = 0; 2268c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 2278c2ecf20Sopenharmony_ci } else if (isac->dch.tx_skb) { /* should not happen */ 2288c2ecf20Sopenharmony_ci pr_info("%s: tx_skb exist but not busy\n", isac->name); 2298c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags); 2308c2ecf20Sopenharmony_ci isac->dch.tx_idx = 0; 2318c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 2328c2ecf20Sopenharmony_ci } else { 2338c2ecf20Sopenharmony_ci pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name); 2348c2ecf20Sopenharmony_ci if (get_next_dframe(&isac->dch)) 2358c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void 2408c2ecf20Sopenharmony_ciisac_mos_irq(struct isac_hw *isac) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci u8 val; 2438c2ecf20Sopenharmony_ci int ret; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_MOSR); 2468c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MOSR %02x\n", isac->name, val); 2478c2ecf20Sopenharmony_ci#if ARCOFI_USE 2488c2ecf20Sopenharmony_ci if (val & 0x08) { 2498c2ecf20Sopenharmony_ci if (!isac->mon_rx) { 2508c2ecf20Sopenharmony_ci isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); 2518c2ecf20Sopenharmony_ci if (!isac->mon_rx) { 2528c2ecf20Sopenharmony_ci pr_info("%s: ISAC MON RX out of memory!\n", 2538c2ecf20Sopenharmony_ci isac->name); 2548c2ecf20Sopenharmony_ci isac->mocr &= 0xf0; 2558c2ecf20Sopenharmony_ci isac->mocr |= 0x0a; 2568c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 2578c2ecf20Sopenharmony_ci goto afterMONR0; 2588c2ecf20Sopenharmony_ci } else 2598c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci if (isac->mon_rxp >= MAX_MON_FRAME) { 2628c2ecf20Sopenharmony_ci isac->mocr &= 0xf0; 2638c2ecf20Sopenharmony_ci isac->mocr |= 0x0a; 2648c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 2658c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 2668c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MON RX overflow!\n", isac->name); 2678c2ecf20Sopenharmony_ci goto afterMONR0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0); 2708c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MOR0 %02x\n", isac->name, 2718c2ecf20Sopenharmony_ci isac->mon_rx[isac->mon_rxp - 1]); 2728c2ecf20Sopenharmony_ci if (isac->mon_rxp == 1) { 2738c2ecf20Sopenharmony_ci isac->mocr |= 0x04; 2748c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ciafterMONR0: 2788c2ecf20Sopenharmony_ci if (val & 0x80) { 2798c2ecf20Sopenharmony_ci if (!isac->mon_rx) { 2808c2ecf20Sopenharmony_ci isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); 2818c2ecf20Sopenharmony_ci if (!isac->mon_rx) { 2828c2ecf20Sopenharmony_ci pr_info("%s: ISAC MON RX out of memory!\n", 2838c2ecf20Sopenharmony_ci isac->name); 2848c2ecf20Sopenharmony_ci isac->mocr &= 0x0f; 2858c2ecf20Sopenharmony_ci isac->mocr |= 0xa0; 2868c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 2878c2ecf20Sopenharmony_ci goto afterMONR1; 2888c2ecf20Sopenharmony_ci } else 2898c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci if (isac->mon_rxp >= MAX_MON_FRAME) { 2928c2ecf20Sopenharmony_ci isac->mocr &= 0x0f; 2938c2ecf20Sopenharmony_ci isac->mocr |= 0xa0; 2948c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 2958c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 2968c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MON RX overflow!\n", isac->name); 2978c2ecf20Sopenharmony_ci goto afterMONR1; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1); 3008c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MOR1 %02x\n", isac->name, 3018c2ecf20Sopenharmony_ci isac->mon_rx[isac->mon_rxp - 1]); 3028c2ecf20Sopenharmony_ci isac->mocr |= 0x40; 3038c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ciafterMONR1: 3068c2ecf20Sopenharmony_ci if (val & 0x04) { 3078c2ecf20Sopenharmony_ci isac->mocr &= 0xf0; 3088c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3098c2ecf20Sopenharmony_ci isac->mocr |= 0x0a; 3108c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3118c2ecf20Sopenharmony_ci if (isac->monitor) { 3128c2ecf20Sopenharmony_ci ret = isac->monitor(isac->dch.hw, MONITOR_RX_0, 3138c2ecf20Sopenharmony_ci isac->mon_rx, isac->mon_rxp); 3148c2ecf20Sopenharmony_ci if (ret) 3158c2ecf20Sopenharmony_ci kfree(isac->mon_rx); 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci pr_info("%s: MONITOR 0 received %d but no user\n", 3188c2ecf20Sopenharmony_ci isac->name, isac->mon_rxp); 3198c2ecf20Sopenharmony_ci kfree(isac->mon_rx); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci isac->mon_rx = NULL; 3228c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci if (val & 0x40) { 3258c2ecf20Sopenharmony_ci isac->mocr &= 0x0f; 3268c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3278c2ecf20Sopenharmony_ci isac->mocr |= 0xa0; 3288c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3298c2ecf20Sopenharmony_ci if (isac->monitor) { 3308c2ecf20Sopenharmony_ci ret = isac->monitor(isac->dch.hw, MONITOR_RX_1, 3318c2ecf20Sopenharmony_ci isac->mon_rx, isac->mon_rxp); 3328c2ecf20Sopenharmony_ci if (ret) 3338c2ecf20Sopenharmony_ci kfree(isac->mon_rx); 3348c2ecf20Sopenharmony_ci } else { 3358c2ecf20Sopenharmony_ci pr_info("%s: MONITOR 1 received %d but no user\n", 3368c2ecf20Sopenharmony_ci isac->name, isac->mon_rxp); 3378c2ecf20Sopenharmony_ci kfree(isac->mon_rx); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci isac->mon_rx = NULL; 3408c2ecf20Sopenharmony_ci isac->mon_rxp = 0; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci if (val & 0x02) { 3438c2ecf20Sopenharmony_ci if ((!isac->mon_tx) || (isac->mon_txc && 3448c2ecf20Sopenharmony_ci (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) { 3458c2ecf20Sopenharmony_ci isac->mocr &= 0xf0; 3468c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3478c2ecf20Sopenharmony_ci isac->mocr |= 0x0a; 3488c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3498c2ecf20Sopenharmony_ci if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { 3508c2ecf20Sopenharmony_ci if (isac->monitor) 3518c2ecf20Sopenharmony_ci isac->monitor(isac->dch.hw, 3528c2ecf20Sopenharmony_ci MONITOR_TX_0, NULL, 0); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci kfree(isac->mon_tx); 3558c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 3568c2ecf20Sopenharmony_ci isac->mon_txc = 0; 3578c2ecf20Sopenharmony_ci isac->mon_txp = 0; 3588c2ecf20Sopenharmony_ci goto AfterMOX0; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { 3618c2ecf20Sopenharmony_ci if (isac->monitor) 3628c2ecf20Sopenharmony_ci isac->monitor(isac->dch.hw, 3638c2ecf20Sopenharmony_ci MONITOR_TX_0, NULL, 0); 3648c2ecf20Sopenharmony_ci kfree(isac->mon_tx); 3658c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 3668c2ecf20Sopenharmony_ci isac->mon_txc = 0; 3678c2ecf20Sopenharmony_ci isac->mon_txp = 0; 3688c2ecf20Sopenharmony_ci goto AfterMOX0; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]); 3718c2ecf20Sopenharmony_ci pr_debug("%s: ISAC %02x -> MOX0\n", isac->name, 3728c2ecf20Sopenharmony_ci isac->mon_tx[isac->mon_txp - 1]); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ciAfterMOX0: 3758c2ecf20Sopenharmony_ci if (val & 0x20) { 3768c2ecf20Sopenharmony_ci if ((!isac->mon_tx) || (isac->mon_txc && 3778c2ecf20Sopenharmony_ci (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) { 3788c2ecf20Sopenharmony_ci isac->mocr &= 0x0f; 3798c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3808c2ecf20Sopenharmony_ci isac->mocr |= 0xa0; 3818c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOCR, isac->mocr); 3828c2ecf20Sopenharmony_ci if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { 3838c2ecf20Sopenharmony_ci if (isac->monitor) 3848c2ecf20Sopenharmony_ci isac->monitor(isac->dch.hw, 3858c2ecf20Sopenharmony_ci MONITOR_TX_1, NULL, 0); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci kfree(isac->mon_tx); 3888c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 3898c2ecf20Sopenharmony_ci isac->mon_txc = 0; 3908c2ecf20Sopenharmony_ci isac->mon_txp = 0; 3918c2ecf20Sopenharmony_ci goto AfterMOX1; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { 3948c2ecf20Sopenharmony_ci if (isac->monitor) 3958c2ecf20Sopenharmony_ci isac->monitor(isac->dch.hw, 3968c2ecf20Sopenharmony_ci MONITOR_TX_1, NULL, 0); 3978c2ecf20Sopenharmony_ci kfree(isac->mon_tx); 3988c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 3998c2ecf20Sopenharmony_ci isac->mon_txc = 0; 4008c2ecf20Sopenharmony_ci isac->mon_txp = 0; 4018c2ecf20Sopenharmony_ci goto AfterMOX1; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]); 4048c2ecf20Sopenharmony_ci pr_debug("%s: ISAC %02x -> MOX1\n", isac->name, 4058c2ecf20Sopenharmony_ci isac->mon_tx[isac->mon_txp - 1]); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ciAfterMOX1: 4088c2ecf20Sopenharmony_ci val = 0; /* dummy to avoid warning */ 4098c2ecf20Sopenharmony_ci#endif 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic void 4138c2ecf20Sopenharmony_ciisac_cisq_irq(struct isac_hw *isac) { 4148c2ecf20Sopenharmony_ci u8 val; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_CIR0); 4178c2ecf20Sopenharmony_ci pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val); 4188c2ecf20Sopenharmony_ci if (val & 2) { 4198c2ecf20Sopenharmony_ci pr_debug("%s: ph_state change %x->%x\n", isac->name, 4208c2ecf20Sopenharmony_ci isac->state, (val >> 2) & 0xf); 4218c2ecf20Sopenharmony_ci isac->state = (val >> 2) & 0xf; 4228c2ecf20Sopenharmony_ci isac_ph_state_change(isac); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci if (val & 1) { 4258c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_CIR1); 4268c2ecf20Sopenharmony_ci pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void 4318c2ecf20Sopenharmony_ciisacsx_cic_irq(struct isac_hw *isac) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci u8 val; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_CIR0); 4368c2ecf20Sopenharmony_ci pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); 4378c2ecf20Sopenharmony_ci if (val & ISACX_CIR0_CIC0) { 4388c2ecf20Sopenharmony_ci pr_debug("%s: ph_state change %x->%x\n", isac->name, 4398c2ecf20Sopenharmony_ci isac->state, val >> 4); 4408c2ecf20Sopenharmony_ci isac->state = val >> 4; 4418c2ecf20Sopenharmony_ci isac_ph_state_change(isac); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void 4468c2ecf20Sopenharmony_ciisacsx_rme_irq(struct isac_hw *isac) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int count; 4498c2ecf20Sopenharmony_ci u8 val; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_RSTAD); 4528c2ecf20Sopenharmony_ci if ((val & (ISACX_RSTAD_VFR | 4538c2ecf20Sopenharmony_ci ISACX_RSTAD_RDO | 4548c2ecf20Sopenharmony_ci ISACX_RSTAD_CRC | 4558c2ecf20Sopenharmony_ci ISACX_RSTAD_RAB)) 4568c2ecf20Sopenharmony_ci != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) { 4578c2ecf20Sopenharmony_ci pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val); 4588c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 4598c2ecf20Sopenharmony_ci if (val & ISACX_RSTAD_CRC) 4608c2ecf20Sopenharmony_ci isac->dch.err_rx++; 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci isac->dch.err_crc++; 4638c2ecf20Sopenharmony_ci#endif 4648c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); 4658c2ecf20Sopenharmony_ci dev_kfree_skb(isac->dch.rx_skb); 4668c2ecf20Sopenharmony_ci isac->dch.rx_skb = NULL; 4678c2ecf20Sopenharmony_ci } else { 4688c2ecf20Sopenharmony_ci count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; 4698c2ecf20Sopenharmony_ci if (count == 0) 4708c2ecf20Sopenharmony_ci count = 32; 4718c2ecf20Sopenharmony_ci isac_empty_fifo(isac, count); 4728c2ecf20Sopenharmony_ci if (isac->dch.rx_skb) { 4738c2ecf20Sopenharmony_ci skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1); 4748c2ecf20Sopenharmony_ci pr_debug("%s: dchannel received %d\n", isac->name, 4758c2ecf20Sopenharmony_ci isac->dch.rx_skb->len); 4768c2ecf20Sopenharmony_ci recv_Dchannel(&isac->dch); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ciirqreturn_t 4828c2ecf20Sopenharmony_cimISDNisac_irq(struct isac_hw *isac, u8 val) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci if (unlikely(!val)) 4858c2ecf20Sopenharmony_ci return IRQ_NONE; 4868c2ecf20Sopenharmony_ci pr_debug("%s: ISAC interrupt %02x\n", isac->name, val); 4878c2ecf20Sopenharmony_ci if (isac->type & IPAC_TYPE_ISACX) { 4888c2ecf20Sopenharmony_ci if (val & ISACX__CIC) 4898c2ecf20Sopenharmony_ci isacsx_cic_irq(isac); 4908c2ecf20Sopenharmony_ci if (val & ISACX__ICD) { 4918c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_ISTAD); 4928c2ecf20Sopenharmony_ci pr_debug("%s: ISTAD %02x\n", isac->name, val); 4938c2ecf20Sopenharmony_ci if (val & ISACX_D_XDU) { 4948c2ecf20Sopenharmony_ci pr_debug("%s: ISAC XDU\n", isac->name); 4958c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 4968c2ecf20Sopenharmony_ci isac->dch.err_tx++; 4978c2ecf20Sopenharmony_ci#endif 4988c2ecf20Sopenharmony_ci isac_retransmit(isac); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci if (val & ISACX_D_XMR) { 5018c2ecf20Sopenharmony_ci pr_debug("%s: ISAC XMR\n", isac->name); 5028c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 5038c2ecf20Sopenharmony_ci isac->dch.err_tx++; 5048c2ecf20Sopenharmony_ci#endif 5058c2ecf20Sopenharmony_ci isac_retransmit(isac); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci if (val & ISACX_D_XPR) 5088c2ecf20Sopenharmony_ci isac_xpr_irq(isac); 5098c2ecf20Sopenharmony_ci if (val & ISACX_D_RFO) { 5108c2ecf20Sopenharmony_ci pr_debug("%s: ISAC RFO\n", isac->name); 5118c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci if (val & ISACX_D_RME) 5148c2ecf20Sopenharmony_ci isacsx_rme_irq(isac); 5158c2ecf20Sopenharmony_ci if (val & ISACX_D_RPF) 5168c2ecf20Sopenharmony_ci isac_empty_fifo(isac, 0x20); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci } else { 5198c2ecf20Sopenharmony_ci if (val & 0x80) /* RME */ 5208c2ecf20Sopenharmony_ci isac_rme_irq(isac); 5218c2ecf20Sopenharmony_ci if (val & 0x40) /* RPF */ 5228c2ecf20Sopenharmony_ci isac_empty_fifo(isac, 32); 5238c2ecf20Sopenharmony_ci if (val & 0x10) /* XPR */ 5248c2ecf20Sopenharmony_ci isac_xpr_irq(isac); 5258c2ecf20Sopenharmony_ci if (val & 0x04) /* CISQ */ 5268c2ecf20Sopenharmony_ci isac_cisq_irq(isac); 5278c2ecf20Sopenharmony_ci if (val & 0x20) /* RSC - never */ 5288c2ecf20Sopenharmony_ci pr_debug("%s: ISAC RSC interrupt\n", isac->name); 5298c2ecf20Sopenharmony_ci if (val & 0x02) /* SIN - never */ 5308c2ecf20Sopenharmony_ci pr_debug("%s: ISAC SIN interrupt\n", isac->name); 5318c2ecf20Sopenharmony_ci if (val & 0x01) { /* EXI */ 5328c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_EXIR); 5338c2ecf20Sopenharmony_ci pr_debug("%s: ISAC EXIR %02x\n", isac->name, val); 5348c2ecf20Sopenharmony_ci if (val & 0x80) /* XMR */ 5358c2ecf20Sopenharmony_ci pr_debug("%s: ISAC XMR\n", isac->name); 5368c2ecf20Sopenharmony_ci if (val & 0x40) { /* XDU */ 5378c2ecf20Sopenharmony_ci pr_debug("%s: ISAC XDU\n", isac->name); 5388c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 5398c2ecf20Sopenharmony_ci isac->dch.err_tx++; 5408c2ecf20Sopenharmony_ci#endif 5418c2ecf20Sopenharmony_ci isac_retransmit(isac); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci if (val & 0x04) /* MOS */ 5448c2ecf20Sopenharmony_ci isac_mos_irq(isac); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNisac_irq); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int 5528c2ecf20Sopenharmony_ciisac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 5558c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 5568c2ecf20Sopenharmony_ci struct isac_hw *isac = container_of(dch, struct isac_hw, dch); 5578c2ecf20Sopenharmony_ci int ret = -EINVAL; 5588c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 5598c2ecf20Sopenharmony_ci u32 id; 5608c2ecf20Sopenharmony_ci u_long flags; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci switch (hh->prim) { 5638c2ecf20Sopenharmony_ci case PH_DATA_REQ: 5648c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 5658c2ecf20Sopenharmony_ci ret = dchannel_senddata(dch, skb); 5668c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 5678c2ecf20Sopenharmony_ci id = hh->id; /* skb can be freed */ 5688c2ecf20Sopenharmony_ci isac_fill_fifo(isac); 5698c2ecf20Sopenharmony_ci ret = 0; 5708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 5718c2ecf20Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 5728c2ecf20Sopenharmony_ci } else 5738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 5748c2ecf20Sopenharmony_ci return ret; 5758c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 5768c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 5798c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 5808c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!ret) 5858c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int 5908c2ecf20Sopenharmony_ciisac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci u8 tl = 0; 5938c2ecf20Sopenharmony_ci unsigned long flags; 5948c2ecf20Sopenharmony_ci int ret = 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci switch (cmd) { 5978c2ecf20Sopenharmony_ci case HW_TESTLOOP: 5988c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 5998c2ecf20Sopenharmony_ci if (!(isac->type & IPAC_TYPE_ISACX)) { 6008c2ecf20Sopenharmony_ci /* TODO: implement for IPAC_TYPE_ISACX */ 6018c2ecf20Sopenharmony_ci if (para & 1) /* B1 */ 6028c2ecf20Sopenharmony_ci tl |= 0x0c; 6038c2ecf20Sopenharmony_ci else if (para & 2) /* B2 */ 6048c2ecf20Sopenharmony_ci tl |= 0x3; 6058c2ecf20Sopenharmony_ci /* we only support IOM2 mode */ 6068c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_SPCR, tl); 6078c2ecf20Sopenharmony_ci if (tl) 6088c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_ADF1, 0x8); 6098c2ecf20Sopenharmony_ci else 6108c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_ADF1, 0x0); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci case HW_TIMER3_VALUE: 6158c2ecf20Sopenharmony_ci ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff)); 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci default: 6188c2ecf20Sopenharmony_ci pr_debug("%s: %s unknown command %x %lx\n", isac->name, 6198c2ecf20Sopenharmony_ci __func__, cmd, para); 6208c2ecf20Sopenharmony_ci ret = -1; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci return ret; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int 6268c2ecf20Sopenharmony_ciisac_l1cmd(struct dchannel *dch, u32 cmd) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct isac_hw *isac = container_of(dch, struct isac_hw, dch); 6298c2ecf20Sopenharmony_ci u_long flags; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state); 6328c2ecf20Sopenharmony_ci switch (cmd) { 6338c2ecf20Sopenharmony_ci case INFO3_P8: 6348c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 6358c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_AR8); 6368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci case INFO3_P10: 6398c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 6408c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_AR10); 6418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case HW_RESET_REQ: 6448c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 6458c2ecf20Sopenharmony_ci if ((isac->state == ISAC_IND_EI) || 6468c2ecf20Sopenharmony_ci (isac->state == ISAC_IND_DR) || 6478c2ecf20Sopenharmony_ci (isac->state == ISAC_IND_DR6) || 6488c2ecf20Sopenharmony_ci (isac->state == ISAC_IND_RS)) 6498c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_TIM); 6508c2ecf20Sopenharmony_ci else 6518c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_RS); 6528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 6538c2ecf20Sopenharmony_ci break; 6548c2ecf20Sopenharmony_ci case HW_DEACT_REQ: 6558c2ecf20Sopenharmony_ci skb_queue_purge(&dch->squeue); 6568c2ecf20Sopenharmony_ci if (dch->tx_skb) { 6578c2ecf20Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 6588c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci dch->tx_idx = 0; 6618c2ecf20Sopenharmony_ci if (dch->rx_skb) { 6628c2ecf20Sopenharmony_ci dev_kfree_skb(dch->rx_skb); 6638c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 6668c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 6678c2ecf20Sopenharmony_ci del_timer(&dch->timer); 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case HW_POWERUP_REQ: 6708c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 6718c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_TIM); 6728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci case PH_ACTIVATE_IND: 6758c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 6768c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 6778c2ecf20Sopenharmony_ci GFP_ATOMIC); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case PH_DEACTIVATE_IND: 6808c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 6818c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 6828c2ecf20Sopenharmony_ci GFP_ATOMIC); 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci default: 6858c2ecf20Sopenharmony_ci pr_debug("%s: %s unknown command %x\n", isac->name, 6868c2ecf20Sopenharmony_ci __func__, cmd); 6878c2ecf20Sopenharmony_ci return -1; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void 6938c2ecf20Sopenharmony_ciisac_release(struct isac_hw *isac) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci if (isac->type & IPAC_TYPE_ISACX) 6968c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_MASK, 0xff); 6978c2ecf20Sopenharmony_ci else if (isac->type != 0) 6988c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MASK, 0xff); 6998c2ecf20Sopenharmony_ci if (isac->dch.timer.function != NULL) { 7008c2ecf20Sopenharmony_ci del_timer(&isac->dch.timer); 7018c2ecf20Sopenharmony_ci isac->dch.timer.function = NULL; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci kfree(isac->mon_rx); 7048c2ecf20Sopenharmony_ci isac->mon_rx = NULL; 7058c2ecf20Sopenharmony_ci kfree(isac->mon_tx); 7068c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 7078c2ecf20Sopenharmony_ci if (isac->dch.l1) 7088c2ecf20Sopenharmony_ci l1_event(isac->dch.l1, CLOSE_CHANNEL); 7098c2ecf20Sopenharmony_ci mISDN_freedchannel(&isac->dch); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic void 7138c2ecf20Sopenharmony_cidbusy_timer_handler(struct timer_list *t) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct isac_hw *isac = from_timer(isac, t, dch.timer); 7168c2ecf20Sopenharmony_ci int rbch, star; 7178c2ecf20Sopenharmony_ci u_long flags; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { 7208c2ecf20Sopenharmony_ci spin_lock_irqsave(isac->hwlock, flags); 7218c2ecf20Sopenharmony_ci rbch = ReadISAC(isac, ISAC_RBCH); 7228c2ecf20Sopenharmony_ci star = ReadISAC(isac, ISAC_STAR); 7238c2ecf20Sopenharmony_ci pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", 7248c2ecf20Sopenharmony_ci isac->name, rbch, star); 7258c2ecf20Sopenharmony_ci if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */ 7268c2ecf20Sopenharmony_ci test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags); 7278c2ecf20Sopenharmony_ci else { 7288c2ecf20Sopenharmony_ci /* discard frame; reset transceiver */ 7298c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags); 7308c2ecf20Sopenharmony_ci if (isac->dch.tx_idx) 7318c2ecf20Sopenharmony_ci isac->dch.tx_idx = 0; 7328c2ecf20Sopenharmony_ci else 7338c2ecf20Sopenharmony_ci pr_info("%s: ISAC D-Channel Busy no tx_idx\n", 7348c2ecf20Sopenharmony_ci isac->name); 7358c2ecf20Sopenharmony_ci /* Transmitter reset */ 7368c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_CMDR, 0x01); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isac->hwlock, flags); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int 7438c2ecf20Sopenharmony_ciopen_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, 7468c2ecf20Sopenharmony_ci isac->dch.dev.id, caller); 7478c2ecf20Sopenharmony_ci if (rq->protocol != ISDN_P_TE_S0) 7488c2ecf20Sopenharmony_ci return -EINVAL; 7498c2ecf20Sopenharmony_ci if (rq->adr.channel == 1) 7508c2ecf20Sopenharmony_ci /* E-Channel not supported */ 7518c2ecf20Sopenharmony_ci return -EINVAL; 7528c2ecf20Sopenharmony_ci rq->ch = &isac->dch.dev.D; 7538c2ecf20Sopenharmony_ci rq->ch->protocol = rq->protocol; 7548c2ecf20Sopenharmony_ci if (isac->dch.state == 7) 7558c2ecf20Sopenharmony_ci _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 7568c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int 7618c2ecf20Sopenharmony_ciopen_dchannel(struct isac_hw *isac, struct channel_req *rq) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci return open_dchannel_caller(isac, rq, __builtin_return_address(0)); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic const char *ISACVer[] = 7678c2ecf20Sopenharmony_ci{"2086/2186 V1.1", "2085 B1", "2085 B2", 7688c2ecf20Sopenharmony_ci "2085 V2.3"}; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int 7718c2ecf20Sopenharmony_ciisac_init(struct isac_hw *isac) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci u8 val; 7748c2ecf20Sopenharmony_ci int err = 0; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!isac->dch.l1) { 7778c2ecf20Sopenharmony_ci err = create_l1(&isac->dch, isac_l1cmd); 7788c2ecf20Sopenharmony_ci if (err) 7798c2ecf20Sopenharmony_ci return err; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci isac->mon_tx = NULL; 7828c2ecf20Sopenharmony_ci isac->mon_rx = NULL; 7838c2ecf20Sopenharmony_ci timer_setup(&isac->dch.timer, dbusy_timer_handler, 0); 7848c2ecf20Sopenharmony_ci isac->mocr = 0xaa; 7858c2ecf20Sopenharmony_ci if (isac->type & IPAC_TYPE_ISACX) { 7868c2ecf20Sopenharmony_ci /* Disable all IRQ */ 7878c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_MASK, 0xff); 7888c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_STARD); 7898c2ecf20Sopenharmony_ci pr_debug("%s: ISACX STARD %x\n", isac->name, val); 7908c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_ISTAD); 7918c2ecf20Sopenharmony_ci pr_debug("%s: ISACX ISTAD %x\n", isac->name, val); 7928c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_ISTA); 7938c2ecf20Sopenharmony_ci pr_debug("%s: ISACX ISTA %x\n", isac->name, val); 7948c2ecf20Sopenharmony_ci /* clear LDD */ 7958c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_TR_CONF0, 0x00); 7968c2ecf20Sopenharmony_ci /* enable transmitter */ 7978c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_TR_CONF2, 0x00); 7988c2ecf20Sopenharmony_ci /* transparent mode 0, RAC, stop/go */ 7998c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_MODED, 0xc9); 8008c2ecf20Sopenharmony_ci /* all HDLC IRQ unmasked */ 8018c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_ID); 8028c2ecf20Sopenharmony_ci if (isac->dch.debug & DEBUG_HW) 8038c2ecf20Sopenharmony_ci pr_notice("%s: ISACX Design ID %x\n", 8048c2ecf20Sopenharmony_ci isac->name, val & 0x3f); 8058c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISACX_CIR0); 8068c2ecf20Sopenharmony_ci pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); 8078c2ecf20Sopenharmony_ci isac->state = val >> 4; 8088c2ecf20Sopenharmony_ci isac_ph_state_change(isac); 8098c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_RS); 8108c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_MASK, IPACX__ON); 8118c2ecf20Sopenharmony_ci WriteISAC(isac, ISACX_MASKD, 0x00); 8128c2ecf20Sopenharmony_ci } else { /* old isac */ 8138c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MASK, 0xff); 8148c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_STAR); 8158c2ecf20Sopenharmony_ci pr_debug("%s: ISAC STAR %x\n", isac->name, val); 8168c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_MODE); 8178c2ecf20Sopenharmony_ci pr_debug("%s: ISAC MODE %x\n", isac->name, val); 8188c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_ADF2); 8198c2ecf20Sopenharmony_ci pr_debug("%s: ISAC ADF2 %x\n", isac->name, val); 8208c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_ISTA); 8218c2ecf20Sopenharmony_ci pr_debug("%s: ISAC ISTA %x\n", isac->name, val); 8228c2ecf20Sopenharmony_ci if (val & 0x01) { 8238c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_EXIR); 8248c2ecf20Sopenharmony_ci pr_debug("%s: ISAC EXIR %x\n", isac->name, val); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_RBCH); 8278c2ecf20Sopenharmony_ci if (isac->dch.debug & DEBUG_HW) 8288c2ecf20Sopenharmony_ci pr_notice("%s: ISAC version (%x): %s\n", isac->name, 8298c2ecf20Sopenharmony_ci val, ISACVer[(val >> 5) & 3]); 8308c2ecf20Sopenharmony_ci isac->type |= ((val >> 5) & 3); 8318c2ecf20Sopenharmony_ci if (!isac->adf2) 8328c2ecf20Sopenharmony_ci isac->adf2 = 0x80; 8338c2ecf20Sopenharmony_ci if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */ 8348c2ecf20Sopenharmony_ci pr_info("%s: only support IOM2 mode but adf2=%02x\n", 8358c2ecf20Sopenharmony_ci isac->name, isac->adf2); 8368c2ecf20Sopenharmony_ci isac_release(isac); 8378c2ecf20Sopenharmony_ci return -EINVAL; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_ADF2, isac->adf2); 8408c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_SQXR, 0x2f); 8418c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_SPCR, 0x00); 8428c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_STCR, 0x70); 8438c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MODE, 0xc9); 8448c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_TIMR, 0x00); 8458c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_ADF1, 0x00); 8468c2ecf20Sopenharmony_ci val = ReadISAC(isac, ISAC_CIR0); 8478c2ecf20Sopenharmony_ci pr_debug("%s: ISAC CIR0 %x\n", isac->name, val); 8488c2ecf20Sopenharmony_ci isac->state = (val >> 2) & 0xf; 8498c2ecf20Sopenharmony_ci isac_ph_state_change(isac); 8508c2ecf20Sopenharmony_ci ph_command(isac, ISAC_CMD_RS); 8518c2ecf20Sopenharmony_ci WriteISAC(isac, ISAC_MASK, 0); 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci return err; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ciint 8578c2ecf20Sopenharmony_cimISDNisac_init(struct isac_hw *isac, void *hw) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh); 8608c2ecf20Sopenharmony_ci isac->dch.hw = hw; 8618c2ecf20Sopenharmony_ci isac->dch.dev.D.send = isac_l1hw; 8628c2ecf20Sopenharmony_ci isac->init = isac_init; 8638c2ecf20Sopenharmony_ci isac->release = isac_release; 8648c2ecf20Sopenharmony_ci isac->ctrl = isac_ctrl; 8658c2ecf20Sopenharmony_ci isac->open = open_dchannel; 8668c2ecf20Sopenharmony_ci isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); 8678c2ecf20Sopenharmony_ci isac->dch.dev.nrbchan = 2; 8688c2ecf20Sopenharmony_ci return 0; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNisac_init); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic void 8738c2ecf20Sopenharmony_ciwaitforCEC(struct hscx_hw *hx) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci u8 starb, to = 50; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci while (to) { 8788c2ecf20Sopenharmony_ci starb = ReadHSCX(hx, IPAC_STARB); 8798c2ecf20Sopenharmony_ci if (!(starb & 0x04)) 8808c2ecf20Sopenharmony_ci break; 8818c2ecf20Sopenharmony_ci udelay(1); 8828c2ecf20Sopenharmony_ci to--; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci if (to < 50) 8858c2ecf20Sopenharmony_ci pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr, 8868c2ecf20Sopenharmony_ci 50 - to); 8878c2ecf20Sopenharmony_ci if (!to) 8888c2ecf20Sopenharmony_ci pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void 8938c2ecf20Sopenharmony_ciwaitforXFW(struct hscx_hw *hx) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci u8 starb, to = 50; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci while (to) { 8988c2ecf20Sopenharmony_ci starb = ReadHSCX(hx, IPAC_STARB); 8998c2ecf20Sopenharmony_ci if ((starb & 0x44) == 0x40) 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci udelay(1); 9028c2ecf20Sopenharmony_ci to--; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci if (to < 50) 9058c2ecf20Sopenharmony_ci pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr, 9068c2ecf20Sopenharmony_ci 50 - to); 9078c2ecf20Sopenharmony_ci if (!to) 9088c2ecf20Sopenharmony_ci pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void 9128c2ecf20Sopenharmony_cihscx_cmdr(struct hscx_hw *hx, u8 cmd) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci if (hx->ip->type & IPAC_TYPE_IPACX) 9158c2ecf20Sopenharmony_ci WriteHSCX(hx, IPACX_CMDRB, cmd); 9168c2ecf20Sopenharmony_ci else { 9178c2ecf20Sopenharmony_ci waitforCEC(hx); 9188c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_CMDRB, cmd); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic void 9238c2ecf20Sopenharmony_cihscx_empty_fifo(struct hscx_hw *hscx, u8 count) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci u8 *p; 9268c2ecf20Sopenharmony_ci int maxlen; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); 9298c2ecf20Sopenharmony_ci if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) { 9308c2ecf20Sopenharmony_ci hscx->bch.dropcnt += count; 9318c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x80); /* RMC */ 9328c2ecf20Sopenharmony_ci return; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(&hscx->bch, count); 9358c2ecf20Sopenharmony_ci if (maxlen < 0) { 9368c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x80); /* RMC */ 9378c2ecf20Sopenharmony_ci if (hscx->bch.rx_skb) 9388c2ecf20Sopenharmony_ci skb_trim(hscx->bch.rx_skb, 0); 9398c2ecf20Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 9408c2ecf20Sopenharmony_ci hscx->ip->name, hscx->bch.nr, count); 9418c2ecf20Sopenharmony_ci return; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci p = skb_put(hscx->bch.rx_skb, count); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (hscx->ip->type & IPAC_TYPE_IPACX) 9468c2ecf20Sopenharmony_ci hscx->ip->read_fifo(hscx->ip->hw, 9478c2ecf20Sopenharmony_ci hscx->off + IPACX_RFIFOB, p, count); 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci hscx->ip->read_fifo(hscx->ip->hw, 9508c2ecf20Sopenharmony_ci hscx->off, p, count); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x80); /* RMC */ 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (hscx->bch.debug & DEBUG_HW_BFIFO) { 9558c2ecf20Sopenharmony_ci snprintf(hscx->log, 64, "B%1d-recv %s %d ", 9568c2ecf20Sopenharmony_ci hscx->bch.nr, hscx->ip->name, count); 9578c2ecf20Sopenharmony_ci print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic void 9628c2ecf20Sopenharmony_cihscx_fill_fifo(struct hscx_hw *hscx) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci int count, more; 9658c2ecf20Sopenharmony_ci u8 *p; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!hscx->bch.tx_skb) { 9688c2ecf20Sopenharmony_ci if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags)) 9698c2ecf20Sopenharmony_ci return; 9708c2ecf20Sopenharmony_ci count = hscx->fifo_size; 9718c2ecf20Sopenharmony_ci more = 1; 9728c2ecf20Sopenharmony_ci p = hscx->log; 9738c2ecf20Sopenharmony_ci memset(p, hscx->bch.fill[0], count); 9748c2ecf20Sopenharmony_ci } else { 9758c2ecf20Sopenharmony_ci count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; 9768c2ecf20Sopenharmony_ci if (count <= 0) 9778c2ecf20Sopenharmony_ci return; 9788c2ecf20Sopenharmony_ci p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; 9818c2ecf20Sopenharmony_ci if (count > hscx->fifo_size) { 9828c2ecf20Sopenharmony_ci count = hscx->fifo_size; 9838c2ecf20Sopenharmony_ci more = 1; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, 9868c2ecf20Sopenharmony_ci count, hscx->bch.tx_idx, hscx->bch.tx_skb->len); 9878c2ecf20Sopenharmony_ci hscx->bch.tx_idx += count; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci if (hscx->ip->type & IPAC_TYPE_IPACX) 9908c2ecf20Sopenharmony_ci hscx->ip->write_fifo(hscx->ip->hw, 9918c2ecf20Sopenharmony_ci hscx->off + IPACX_XFIFOB, p, count); 9928c2ecf20Sopenharmony_ci else { 9938c2ecf20Sopenharmony_ci waitforXFW(hscx); 9948c2ecf20Sopenharmony_ci hscx->ip->write_fifo(hscx->ip->hw, 9958c2ecf20Sopenharmony_ci hscx->off, p, count); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci hscx_cmdr(hscx, more ? 0x08 : 0x0a); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) { 10008c2ecf20Sopenharmony_ci snprintf(hscx->log, 64, "B%1d-send %s %d ", 10018c2ecf20Sopenharmony_ci hscx->bch.nr, hscx->ip->name, count); 10028c2ecf20Sopenharmony_ci print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic void 10078c2ecf20Sopenharmony_cihscx_xpr(struct hscx_hw *hx) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) { 10108c2ecf20Sopenharmony_ci hscx_fill_fifo(hx); 10118c2ecf20Sopenharmony_ci } else { 10128c2ecf20Sopenharmony_ci dev_kfree_skb(hx->bch.tx_skb); 10138c2ecf20Sopenharmony_ci if (get_next_bframe(&hx->bch)) { 10148c2ecf20Sopenharmony_ci hscx_fill_fifo(hx); 10158c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags); 10168c2ecf20Sopenharmony_ci } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) { 10178c2ecf20Sopenharmony_ci hscx_fill_fifo(hx); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void 10238c2ecf20Sopenharmony_ciipac_rme(struct hscx_hw *hx) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci int count; 10268c2ecf20Sopenharmony_ci u8 rstab; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (hx->ip->type & IPAC_TYPE_IPACX) 10298c2ecf20Sopenharmony_ci rstab = ReadHSCX(hx, IPACX_RSTAB); 10308c2ecf20Sopenharmony_ci else 10318c2ecf20Sopenharmony_ci rstab = ReadHSCX(hx, IPAC_RSTAB); 10328c2ecf20Sopenharmony_ci pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab); 10338c2ecf20Sopenharmony_ci if ((rstab & 0xf0) != 0xa0) { 10348c2ecf20Sopenharmony_ci /* !(VFR && !RDO && CRC && !RAB) */ 10358c2ecf20Sopenharmony_ci if (!(rstab & 0x80)) { 10368c2ecf20Sopenharmony_ci if (hx->bch.debug & DEBUG_HW_BCHANNEL) 10378c2ecf20Sopenharmony_ci pr_notice("%s: B%1d invalid frame\n", 10388c2ecf20Sopenharmony_ci hx->ip->name, hx->bch.nr); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci if (rstab & 0x40) { 10418c2ecf20Sopenharmony_ci if (hx->bch.debug & DEBUG_HW_BCHANNEL) 10428c2ecf20Sopenharmony_ci pr_notice("%s: B%1d RDO proto=%x\n", 10438c2ecf20Sopenharmony_ci hx->ip->name, hx->bch.nr, 10448c2ecf20Sopenharmony_ci hx->bch.state); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci if (!(rstab & 0x20)) { 10478c2ecf20Sopenharmony_ci if (hx->bch.debug & DEBUG_HW_BCHANNEL) 10488c2ecf20Sopenharmony_ci pr_notice("%s: B%1d CRC error\n", 10498c2ecf20Sopenharmony_ci hx->ip->name, hx->bch.nr); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci hscx_cmdr(hx, 0x80); /* Do RMC */ 10528c2ecf20Sopenharmony_ci return; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci if (hx->ip->type & IPAC_TYPE_IPACX) 10558c2ecf20Sopenharmony_ci count = ReadHSCX(hx, IPACX_RBCLB); 10568c2ecf20Sopenharmony_ci else 10578c2ecf20Sopenharmony_ci count = ReadHSCX(hx, IPAC_RBCLB); 10588c2ecf20Sopenharmony_ci count &= (hx->fifo_size - 1); 10598c2ecf20Sopenharmony_ci if (count == 0) 10608c2ecf20Sopenharmony_ci count = hx->fifo_size; 10618c2ecf20Sopenharmony_ci hscx_empty_fifo(hx, count); 10628c2ecf20Sopenharmony_ci if (!hx->bch.rx_skb) 10638c2ecf20Sopenharmony_ci return; 10648c2ecf20Sopenharmony_ci if (hx->bch.rx_skb->len < 2) { 10658c2ecf20Sopenharmony_ci pr_debug("%s: B%1d frame to short %d\n", 10668c2ecf20Sopenharmony_ci hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len); 10678c2ecf20Sopenharmony_ci skb_trim(hx->bch.rx_skb, 0); 10688c2ecf20Sopenharmony_ci } else { 10698c2ecf20Sopenharmony_ci skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); 10708c2ecf20Sopenharmony_ci recv_Bchannel(&hx->bch, 0, false); 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic void 10758c2ecf20Sopenharmony_ciipac_irq(struct hscx_hw *hx, u8 ista) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci u8 istab, m, exirb = 0; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (hx->ip->type & IPAC_TYPE_IPACX) 10808c2ecf20Sopenharmony_ci istab = ReadHSCX(hx, IPACX_ISTAB); 10818c2ecf20Sopenharmony_ci else if (hx->ip->type & IPAC_TYPE_IPAC) { 10828c2ecf20Sopenharmony_ci istab = ReadHSCX(hx, IPAC_ISTAB); 10838c2ecf20Sopenharmony_ci m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB; 10848c2ecf20Sopenharmony_ci if (m & ista) { 10858c2ecf20Sopenharmony_ci exirb = ReadHSCX(hx, IPAC_EXIRB); 10868c2ecf20Sopenharmony_ci pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, 10878c2ecf20Sopenharmony_ci hx->bch.nr, exirb); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci } else if (hx->bch.nr & 2) { /* HSCX B */ 10908c2ecf20Sopenharmony_ci if (ista & (HSCX__EXA | HSCX__ICA)) 10918c2ecf20Sopenharmony_ci ipac_irq(&hx->ip->hscx[0], ista); 10928c2ecf20Sopenharmony_ci if (ista & HSCX__EXB) { 10938c2ecf20Sopenharmony_ci exirb = ReadHSCX(hx, IPAC_EXIRB); 10948c2ecf20Sopenharmony_ci pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, 10958c2ecf20Sopenharmony_ci hx->bch.nr, exirb); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci istab = ista & 0xF8; 10988c2ecf20Sopenharmony_ci } else { /* HSCX A */ 10998c2ecf20Sopenharmony_ci istab = ReadHSCX(hx, IPAC_ISTAB); 11008c2ecf20Sopenharmony_ci if (ista & HSCX__EXA) { 11018c2ecf20Sopenharmony_ci exirb = ReadHSCX(hx, IPAC_EXIRB); 11028c2ecf20Sopenharmony_ci pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, 11038c2ecf20Sopenharmony_ci hx->bch.nr, exirb); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci istab = istab & 0xF8; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci if (exirb & IPAC_B_XDU) 11088c2ecf20Sopenharmony_ci istab |= IPACX_B_XDU; 11098c2ecf20Sopenharmony_ci if (exirb & IPAC_B_RFO) 11108c2ecf20Sopenharmony_ci istab |= IPACX_B_RFO; 11118c2ecf20Sopenharmony_ci pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &hx->bch.Flags)) 11148c2ecf20Sopenharmony_ci return; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (istab & IPACX_B_RME) 11178c2ecf20Sopenharmony_ci ipac_rme(hx); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (istab & IPACX_B_RPF) { 11208c2ecf20Sopenharmony_ci hscx_empty_fifo(hx, hx->fifo_size); 11218c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) 11228c2ecf20Sopenharmony_ci recv_Bchannel(&hx->bch, 0, false); 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (istab & IPACX_B_RFO) { 11268c2ecf20Sopenharmony_ci pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr); 11278c2ecf20Sopenharmony_ci hscx_cmdr(hx, 0x40); /* RRES */ 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (istab & IPACX_B_XPR) 11318c2ecf20Sopenharmony_ci hscx_xpr(hx); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (istab & IPACX_B_XDU) { 11348c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { 11358c2ecf20Sopenharmony_ci if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags)) 11368c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags); 11378c2ecf20Sopenharmony_ci hscx_xpr(hx); 11388c2ecf20Sopenharmony_ci return; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, 11418c2ecf20Sopenharmony_ci hx->bch.nr, hx->bch.tx_idx); 11428c2ecf20Sopenharmony_ci hx->bch.tx_idx = 0; 11438c2ecf20Sopenharmony_ci hscx_cmdr(hx, 0x01); /* XRES */ 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ciirqreturn_t 11488c2ecf20Sopenharmony_cimISDNipac_irq(struct ipac_hw *ipac, int maxloop) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci int cnt = maxloop + 1; 11518c2ecf20Sopenharmony_ci u8 ista, istad; 11528c2ecf20Sopenharmony_ci struct isac_hw *isac = &ipac->isac; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (ipac->type & IPAC_TYPE_IPACX) { 11558c2ecf20Sopenharmony_ci ista = ReadIPAC(ipac, ISACX_ISTA); 11568c2ecf20Sopenharmony_ci while (ista && --cnt) { 11578c2ecf20Sopenharmony_ci pr_debug("%s: ISTA %02x\n", ipac->name, ista); 11588c2ecf20Sopenharmony_ci if (ista & IPACX__ICA) 11598c2ecf20Sopenharmony_ci ipac_irq(&ipac->hscx[0], ista); 11608c2ecf20Sopenharmony_ci if (ista & IPACX__ICB) 11618c2ecf20Sopenharmony_ci ipac_irq(&ipac->hscx[1], ista); 11628c2ecf20Sopenharmony_ci if (ista & (ISACX__ICD | ISACX__CIC)) 11638c2ecf20Sopenharmony_ci mISDNisac_irq(&ipac->isac, ista); 11648c2ecf20Sopenharmony_ci ista = ReadIPAC(ipac, ISACX_ISTA); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci } else if (ipac->type & IPAC_TYPE_IPAC) { 11678c2ecf20Sopenharmony_ci ista = ReadIPAC(ipac, IPAC_ISTA); 11688c2ecf20Sopenharmony_ci while (ista && --cnt) { 11698c2ecf20Sopenharmony_ci pr_debug("%s: ISTA %02x\n", ipac->name, ista); 11708c2ecf20Sopenharmony_ci if (ista & (IPAC__ICD | IPAC__EXD)) { 11718c2ecf20Sopenharmony_ci istad = ReadISAC(isac, ISAC_ISTA); 11728c2ecf20Sopenharmony_ci pr_debug("%s: ISTAD %02x\n", ipac->name, istad); 11738c2ecf20Sopenharmony_ci if (istad & IPAC_D_TIN2) 11748c2ecf20Sopenharmony_ci pr_debug("%s TIN2 irq\n", ipac->name); 11758c2ecf20Sopenharmony_ci if (ista & IPAC__EXD) 11768c2ecf20Sopenharmony_ci istad |= 1; /* ISAC EXI */ 11778c2ecf20Sopenharmony_ci mISDNisac_irq(isac, istad); 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci if (ista & (IPAC__ICA | IPAC__EXA)) 11808c2ecf20Sopenharmony_ci ipac_irq(&ipac->hscx[0], ista); 11818c2ecf20Sopenharmony_ci if (ista & (IPAC__ICB | IPAC__EXB)) 11828c2ecf20Sopenharmony_ci ipac_irq(&ipac->hscx[1], ista); 11838c2ecf20Sopenharmony_ci ista = ReadIPAC(ipac, IPAC_ISTA); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci } else if (ipac->type & IPAC_TYPE_HSCX) { 11868c2ecf20Sopenharmony_ci while (--cnt) { 11878c2ecf20Sopenharmony_ci ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off); 11888c2ecf20Sopenharmony_ci pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista); 11898c2ecf20Sopenharmony_ci if (ista) 11908c2ecf20Sopenharmony_ci ipac_irq(&ipac->hscx[1], ista); 11918c2ecf20Sopenharmony_ci istad = ReadISAC(isac, ISAC_ISTA); 11928c2ecf20Sopenharmony_ci pr_debug("%s: ISTAD %02x\n", ipac->name, istad); 11938c2ecf20Sopenharmony_ci if (istad) 11948c2ecf20Sopenharmony_ci mISDNisac_irq(isac, istad); 11958c2ecf20Sopenharmony_ci if (0 == (ista | istad)) 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */ 12008c2ecf20Sopenharmony_ci return IRQ_NONE; 12018c2ecf20Sopenharmony_ci if (cnt < maxloop) 12028c2ecf20Sopenharmony_ci pr_debug("%s: %d irqloops cpu%d\n", ipac->name, 12038c2ecf20Sopenharmony_ci maxloop - cnt, smp_processor_id()); 12048c2ecf20Sopenharmony_ci if (maxloop && !cnt) 12058c2ecf20Sopenharmony_ci pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name, 12068c2ecf20Sopenharmony_ci maxloop, smp_processor_id()); 12078c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNipac_irq); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic int 12128c2ecf20Sopenharmony_cihscx_mode(struct hscx_hw *hscx, u32 bprotocol) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name, 12158c2ecf20Sopenharmony_ci '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr); 12168c2ecf20Sopenharmony_ci if (hscx->ip->type & IPAC_TYPE_IPACX) { 12178c2ecf20Sopenharmony_ci if (hscx->bch.nr & 1) { /* B1 and ICA */ 12188c2ecf20Sopenharmony_ci WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80); 12198c2ecf20Sopenharmony_ci WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88); 12208c2ecf20Sopenharmony_ci } else { /* B2 and ICB */ 12218c2ecf20Sopenharmony_ci WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81); 12228c2ecf20Sopenharmony_ci WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci switch (bprotocol) { 12258c2ecf20Sopenharmony_ci case ISDN_P_NONE: /* init */ 12268c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */ 12278c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */ 12288c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */ 12298c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 12308c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); 12318c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 12328c2ecf20Sopenharmony_ci break; 12338c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 12348c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */ 12358c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */ 12368c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 12378c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); 12388c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 12418c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */ 12428c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */ 12438c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 12448c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); 12458c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); 12468c2ecf20Sopenharmony_ci break; 12478c2ecf20Sopenharmony_ci default: 12488c2ecf20Sopenharmony_ci pr_info("%s: protocol not known %x\n", hscx->ip->name, 12498c2ecf20Sopenharmony_ci bprotocol); 12508c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */ 12538c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x82); 12548c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR2, 0x30); 12558c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_XCCR, 0x07); 12568c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_RCCR, 0x07); 12578c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAX, hscx->slot); 12588c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAR, hscx->slot); 12598c2ecf20Sopenharmony_ci switch (bprotocol) { 12608c2ecf20Sopenharmony_ci case ISDN_P_NONE: 12618c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAX, 0x1F); 12628c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAR, 0x1F); 12638c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0x84); 12648c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x82); 12658c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ 12668c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); 12678c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 12708c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ 12718c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x82); 12728c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 12738c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0); 12748c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 12758c2ecf20Sopenharmony_ci break; 12768c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 12778c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0x8c); 12788c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x8a); 12798c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 12808c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0); 12818c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); 12828c2ecf20Sopenharmony_ci break; 12838c2ecf20Sopenharmony_ci default: 12848c2ecf20Sopenharmony_ci pr_info("%s: protocol not known %x\n", hscx->ip->name, 12858c2ecf20Sopenharmony_ci bprotocol); 12868c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */ 12898c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x85); 12908c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR2, 0x30); 12918c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_XCCR, 0x07); 12928c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_RCCR, 0x07); 12938c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAX, hscx->slot); 12948c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAR, hscx->slot); 12958c2ecf20Sopenharmony_ci switch (bprotocol) { 12968c2ecf20Sopenharmony_ci case ISDN_P_NONE: 12978c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAX, 0x1F); 12988c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_TSAR, 0x1F); 12998c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0x84); 13008c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x85); 13018c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ 13028c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); 13038c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 13068c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ 13078c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x85); 13088c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 13098c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0); 13108c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 13138c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MODEB, 0x8c); 13148c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_CCR1, 0x8d); 13158c2ecf20Sopenharmony_ci hscx_cmdr(hscx, 0x41); 13168c2ecf20Sopenharmony_ci WriteHSCX(hscx, IPAC_MASKB, 0); 13178c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci default: 13208c2ecf20Sopenharmony_ci pr_info("%s: protocol not known %x\n", hscx->ip->name, 13218c2ecf20Sopenharmony_ci bprotocol); 13228c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci } else 13258c2ecf20Sopenharmony_ci return -EINVAL; 13268c2ecf20Sopenharmony_ci hscx->bch.state = bprotocol; 13278c2ecf20Sopenharmony_ci return 0; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic int 13318c2ecf20Sopenharmony_cihscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 13348c2ecf20Sopenharmony_ci struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); 13358c2ecf20Sopenharmony_ci int ret = -EINVAL; 13368c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 13378c2ecf20Sopenharmony_ci unsigned long flags; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci switch (hh->prim) { 13408c2ecf20Sopenharmony_ci case PH_DATA_REQ: 13418c2ecf20Sopenharmony_ci spin_lock_irqsave(hx->ip->hwlock, flags); 13428c2ecf20Sopenharmony_ci ret = bchannel_senddata(bch, skb); 13438c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 13448c2ecf20Sopenharmony_ci ret = 0; 13458c2ecf20Sopenharmony_ci hscx_fill_fifo(hx); 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hx->ip->hwlock, flags); 13488c2ecf20Sopenharmony_ci return ret; 13498c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 13508c2ecf20Sopenharmony_ci spin_lock_irqsave(hx->ip->hwlock, flags); 13518c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 13528c2ecf20Sopenharmony_ci ret = hscx_mode(hx, ch->protocol); 13538c2ecf20Sopenharmony_ci else 13548c2ecf20Sopenharmony_ci ret = 0; 13558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hx->ip->hwlock, flags); 13568c2ecf20Sopenharmony_ci if (!ret) 13578c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 13588c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 13618c2ecf20Sopenharmony_ci spin_lock_irqsave(hx->ip->hwlock, flags); 13628c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 13638c2ecf20Sopenharmony_ci hscx_mode(hx, ISDN_P_NONE); 13648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hx->ip->hwlock, flags); 13658c2ecf20Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 13668c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 13678c2ecf20Sopenharmony_ci ret = 0; 13688c2ecf20Sopenharmony_ci break; 13698c2ecf20Sopenharmony_ci default: 13708c2ecf20Sopenharmony_ci pr_info("%s: %s unknown prim(%x,%x)\n", 13718c2ecf20Sopenharmony_ci hx->ip->name, __func__, hh->prim, hh->id); 13728c2ecf20Sopenharmony_ci ret = -EINVAL; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci if (!ret) 13758c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13768c2ecf20Sopenharmony_ci return ret; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_cistatic int 13808c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic int 13868c2ecf20Sopenharmony_cihscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 13898c2ecf20Sopenharmony_ci struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); 13908c2ecf20Sopenharmony_ci int ret = -EINVAL; 13918c2ecf20Sopenharmony_ci u_long flags; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg); 13948c2ecf20Sopenharmony_ci switch (cmd) { 13958c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 13968c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 13978c2ecf20Sopenharmony_ci cancel_work_sync(&bch->workq); 13988c2ecf20Sopenharmony_ci spin_lock_irqsave(hx->ip->hwlock, flags); 13998c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 14008c2ecf20Sopenharmony_ci hscx_mode(hx, ISDN_P_NONE); 14018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hx->ip->hwlock, flags); 14028c2ecf20Sopenharmony_ci ch->protocol = ISDN_P_NONE; 14038c2ecf20Sopenharmony_ci ch->peer = NULL; 14048c2ecf20Sopenharmony_ci module_put(hx->ip->owner); 14058c2ecf20Sopenharmony_ci ret = 0; 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 14088c2ecf20Sopenharmony_ci ret = channel_bctrl(bch, arg); 14098c2ecf20Sopenharmony_ci break; 14108c2ecf20Sopenharmony_ci default: 14118c2ecf20Sopenharmony_ci pr_info("%s: %s unknown prim(%x)\n", 14128c2ecf20Sopenharmony_ci hx->ip->name, __func__, cmd); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci return ret; 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic void 14188c2ecf20Sopenharmony_cifree_ipac(struct ipac_hw *ipac) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci isac_release(&ipac->isac); 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cistatic const char *HSCXVer[] = 14248c2ecf20Sopenharmony_ci{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", 14258c2ecf20Sopenharmony_ci "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic void 14308c2ecf20Sopenharmony_cihscx_init(struct hscx_hw *hx) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci u8 val; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_RAH2, 0xFF); 14358c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_XBCH, 0x00); 14368c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_RLCR, 0x00); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci if (hx->ip->type & IPAC_TYPE_HSCX) { 14398c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_CCR1, 0x85); 14408c2ecf20Sopenharmony_ci val = ReadHSCX(hx, HSCX_VSTR); 14418c2ecf20Sopenharmony_ci pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val); 14428c2ecf20Sopenharmony_ci if (hx->bch.debug & DEBUG_HW) 14438c2ecf20Sopenharmony_ci pr_notice("%s: HSCX version %s\n", hx->ip->name, 14448c2ecf20Sopenharmony_ci HSCXVer[val & 0x0f]); 14458c2ecf20Sopenharmony_ci } else 14468c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_CCR1, 0x82); 14478c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_CCR2, 0x30); 14488c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_XCCR, 0x07); 14498c2ecf20Sopenharmony_ci WriteHSCX(hx, IPAC_RCCR, 0x07); 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic int 14538c2ecf20Sopenharmony_ciipac_init(struct ipac_hw *ipac) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci u8 val; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (ipac->type & IPAC_TYPE_HSCX) { 14588c2ecf20Sopenharmony_ci hscx_init(&ipac->hscx[0]); 14598c2ecf20Sopenharmony_ci hscx_init(&ipac->hscx[1]); 14608c2ecf20Sopenharmony_ci val = ReadIPAC(ipac, IPAC_ID); 14618c2ecf20Sopenharmony_ci } else if (ipac->type & IPAC_TYPE_IPAC) { 14628c2ecf20Sopenharmony_ci hscx_init(&ipac->hscx[0]); 14638c2ecf20Sopenharmony_ci hscx_init(&ipac->hscx[1]); 14648c2ecf20Sopenharmony_ci WriteIPAC(ipac, IPAC_MASK, IPAC__ON); 14658c2ecf20Sopenharmony_ci val = ReadIPAC(ipac, IPAC_CONF); 14668c2ecf20Sopenharmony_ci /* conf is default 0, but can be overwritten by card setup */ 14678c2ecf20Sopenharmony_ci pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name, 14688c2ecf20Sopenharmony_ci val, ipac->conf); 14698c2ecf20Sopenharmony_ci WriteIPAC(ipac, IPAC_CONF, ipac->conf); 14708c2ecf20Sopenharmony_ci val = ReadIPAC(ipac, IPAC_ID); 14718c2ecf20Sopenharmony_ci if (ipac->hscx[0].bch.debug & DEBUG_HW) 14728c2ecf20Sopenharmony_ci pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val); 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci /* nothing special for IPACX to do here */ 14758c2ecf20Sopenharmony_ci return isac_init(&ipac->isac); 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_cistatic int 14798c2ecf20Sopenharmony_ciopen_bchannel(struct ipac_hw *ipac, struct channel_req *rq) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci struct bchannel *bch; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 14848c2ecf20Sopenharmony_ci return -EINVAL; 14858c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 14868c2ecf20Sopenharmony_ci return -EINVAL; 14878c2ecf20Sopenharmony_ci bch = &ipac->hscx[rq->adr.channel - 1].bch; 14888c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 14898c2ecf20Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 14908c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); 14918c2ecf20Sopenharmony_ci bch->ch.protocol = rq->protocol; 14928c2ecf20Sopenharmony_ci rq->ch = &bch->ch; 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic int 14978c2ecf20Sopenharmony_cichannel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci int ret = 0; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci switch (cq->op) { 15028c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 15038c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci case MISDN_CTRL_LOOP: 15068c2ecf20Sopenharmony_ci /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ 15078c2ecf20Sopenharmony_ci if (cq->channel < 0 || cq->channel > 3) { 15088c2ecf20Sopenharmony_ci ret = -EINVAL; 15098c2ecf20Sopenharmony_ci break; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 15148c2ecf20Sopenharmony_ci ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1); 15158c2ecf20Sopenharmony_ci break; 15168c2ecf20Sopenharmony_ci default: 15178c2ecf20Sopenharmony_ci pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); 15188c2ecf20Sopenharmony_ci ret = -EINVAL; 15198c2ecf20Sopenharmony_ci break; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci return ret; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic int 15258c2ecf20Sopenharmony_ciipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 15288c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 15298c2ecf20Sopenharmony_ci struct isac_hw *isac = container_of(dch, struct isac_hw, dch); 15308c2ecf20Sopenharmony_ci struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac); 15318c2ecf20Sopenharmony_ci struct channel_req *rq; 15328c2ecf20Sopenharmony_ci int err = 0; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg); 15358c2ecf20Sopenharmony_ci switch (cmd) { 15368c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 15378c2ecf20Sopenharmony_ci rq = arg; 15388c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) 15398c2ecf20Sopenharmony_ci err = open_dchannel_caller(isac, rq, __builtin_return_address(0)); 15408c2ecf20Sopenharmony_ci else 15418c2ecf20Sopenharmony_ci err = open_bchannel(ipac, rq); 15428c2ecf20Sopenharmony_ci if (err) 15438c2ecf20Sopenharmony_ci break; 15448c2ecf20Sopenharmony_ci if (!try_module_get(ipac->owner)) 15458c2ecf20Sopenharmony_ci pr_info("%s: cannot get module\n", ipac->name); 15468c2ecf20Sopenharmony_ci break; 15478c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 15488c2ecf20Sopenharmony_ci pr_debug("%s: dev(%d) close from %p\n", ipac->name, 15498c2ecf20Sopenharmony_ci dch->dev.id, __builtin_return_address(0)); 15508c2ecf20Sopenharmony_ci module_put(ipac->owner); 15518c2ecf20Sopenharmony_ci break; 15528c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 15538c2ecf20Sopenharmony_ci err = channel_ctrl(ipac, arg); 15548c2ecf20Sopenharmony_ci break; 15558c2ecf20Sopenharmony_ci default: 15568c2ecf20Sopenharmony_ci pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd); 15578c2ecf20Sopenharmony_ci return -EINVAL; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci return err; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ciu32 15638c2ecf20Sopenharmony_cimISDNipac_init(struct ipac_hw *ipac, void *hw) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci u32 ret; 15668c2ecf20Sopenharmony_ci u8 i; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci ipac->hw = hw; 15698c2ecf20Sopenharmony_ci if (ipac->isac.dch.debug & DEBUG_HW) 15708c2ecf20Sopenharmony_ci pr_notice("%s: ipac type %x\n", ipac->name, ipac->type); 15718c2ecf20Sopenharmony_ci if (ipac->type & IPAC_TYPE_HSCX) { 15728c2ecf20Sopenharmony_ci ipac->isac.type = IPAC_TYPE_ISAC; 15738c2ecf20Sopenharmony_ci ipac->hscx[0].off = 0; 15748c2ecf20Sopenharmony_ci ipac->hscx[1].off = 0x40; 15758c2ecf20Sopenharmony_ci ipac->hscx[0].fifo_size = 32; 15768c2ecf20Sopenharmony_ci ipac->hscx[1].fifo_size = 32; 15778c2ecf20Sopenharmony_ci } else if (ipac->type & IPAC_TYPE_IPAC) { 15788c2ecf20Sopenharmony_ci ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC; 15798c2ecf20Sopenharmony_ci ipac->hscx[0].off = 0; 15808c2ecf20Sopenharmony_ci ipac->hscx[1].off = 0x40; 15818c2ecf20Sopenharmony_ci ipac->hscx[0].fifo_size = 64; 15828c2ecf20Sopenharmony_ci ipac->hscx[1].fifo_size = 64; 15838c2ecf20Sopenharmony_ci } else if (ipac->type & IPAC_TYPE_IPACX) { 15848c2ecf20Sopenharmony_ci ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX; 15858c2ecf20Sopenharmony_ci ipac->hscx[0].off = IPACX_OFF_ICA; 15868c2ecf20Sopenharmony_ci ipac->hscx[1].off = IPACX_OFF_ICB; 15878c2ecf20Sopenharmony_ci ipac->hscx[0].fifo_size = 64; 15888c2ecf20Sopenharmony_ci ipac->hscx[1].fifo_size = 64; 15898c2ecf20Sopenharmony_ci } else 15908c2ecf20Sopenharmony_ci return 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci mISDNisac_init(&ipac->isac, hw); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci ipac->isac.dch.dev.D.ctrl = ipac_dctrl; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 15978c2ecf20Sopenharmony_ci ipac->hscx[i].bch.nr = i + 1; 15988c2ecf20Sopenharmony_ci set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); 15998c2ecf20Sopenharmony_ci list_add(&ipac->hscx[i].bch.ch.list, 16008c2ecf20Sopenharmony_ci &ipac->isac.dch.dev.bchannels); 16018c2ecf20Sopenharmony_ci mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM, 16028c2ecf20Sopenharmony_ci ipac->hscx[i].fifo_size); 16038c2ecf20Sopenharmony_ci ipac->hscx[i].bch.ch.nr = i + 1; 16048c2ecf20Sopenharmony_ci ipac->hscx[i].bch.ch.send = &hscx_l2l1; 16058c2ecf20Sopenharmony_ci ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; 16068c2ecf20Sopenharmony_ci ipac->hscx[i].bch.hw = hw; 16078c2ecf20Sopenharmony_ci ipac->hscx[i].ip = ipac; 16088c2ecf20Sopenharmony_ci /* default values for IOM time slots 16098c2ecf20Sopenharmony_ci * can be overwritten by card */ 16108c2ecf20Sopenharmony_ci ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci ipac->init = ipac_init; 16148c2ecf20Sopenharmony_ci ipac->release = free_ipac; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 16178c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 16188c2ecf20Sopenharmony_ci return ret; 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNipac_init); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int __init 16238c2ecf20Sopenharmony_ciisac_mod_init(void) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci pr_notice("mISDNipac module version %s\n", ISAC_REV); 16268c2ecf20Sopenharmony_ci return 0; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic void __exit 16308c2ecf20Sopenharmony_ciisac_mod_cleanup(void) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci pr_notice("mISDNipac module unloaded\n"); 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_cimodule_init(isac_mod_init); 16358c2ecf20Sopenharmony_cimodule_exit(isac_mod_cleanup); 1636