18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * hfcpci.c low level driver for CCD's hfc-pci based cards 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author Werner Cornelius (werner@isdn4linux.de) 78c2ecf20Sopenharmony_ci * based on existing driver for CCD hfc ISA cards 88c2ecf20Sopenharmony_ci * type approval valid for HFC-S PCI A based card 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) 118c2ecf20Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Module options: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * debug: 168c2ecf20Sopenharmony_ci * NOTE: only one poll value must be given for all cards 178c2ecf20Sopenharmony_ci * See hfc_pci.h for debug flags. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * poll: 208c2ecf20Sopenharmony_ci * NOTE: only one poll value must be given for all cards 218c2ecf20Sopenharmony_ci * Give the number of samples for each fifo process. 228c2ecf20Sopenharmony_ci * By default 128 is used. Decrease to reduce delay, increase to 238c2ecf20Sopenharmony_ci * reduce cpu load. If unsure, don't mess with it! 248c2ecf20Sopenharmony_ci * A value of 128 will use controller's interrupt. Other values will 258c2ecf20Sopenharmony_ci * use kernel timer, because the controller will not allow lower values 268c2ecf20Sopenharmony_ci * than 128. 278c2ecf20Sopenharmony_ci * Also note that the value depends on the kernel timer frequency. 288c2ecf20Sopenharmony_ci * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. 298c2ecf20Sopenharmony_ci * If the kernel uses 100 Hz, steps of 80 samples are possible. 308c2ecf20Sopenharmony_ci * If the kernel uses 300 Hz, steps of about 26 samples are possible. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <linux/pci.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "hfc_pci.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const char *hfcpci_revision = "2.0"; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int HFC_cnt; 458c2ecf20Sopenharmony_cistatic uint debug; 468c2ecf20Sopenharmony_cistatic uint poll, tics; 478c2ecf20Sopenharmony_cistatic struct timer_list hfc_tl; 488c2ecf20Sopenharmony_cistatic unsigned long hfc_jiffies; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 538c2ecf20Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cienum { 568c2ecf20Sopenharmony_ci HFC_CCD_2BD0, 578c2ecf20Sopenharmony_ci HFC_CCD_B000, 588c2ecf20Sopenharmony_ci HFC_CCD_B006, 598c2ecf20Sopenharmony_ci HFC_CCD_B007, 608c2ecf20Sopenharmony_ci HFC_CCD_B008, 618c2ecf20Sopenharmony_ci HFC_CCD_B009, 628c2ecf20Sopenharmony_ci HFC_CCD_B00A, 638c2ecf20Sopenharmony_ci HFC_CCD_B00B, 648c2ecf20Sopenharmony_ci HFC_CCD_B00C, 658c2ecf20Sopenharmony_ci HFC_CCD_B100, 668c2ecf20Sopenharmony_ci HFC_CCD_B700, 678c2ecf20Sopenharmony_ci HFC_CCD_B701, 688c2ecf20Sopenharmony_ci HFC_ASUS_0675, 698c2ecf20Sopenharmony_ci HFC_BERKOM_A1T, 708c2ecf20Sopenharmony_ci HFC_BERKOM_TCONCEPT, 718c2ecf20Sopenharmony_ci HFC_ANIGMA_MC145575, 728c2ecf20Sopenharmony_ci HFC_ZOLTRIX_2BD0, 738c2ecf20Sopenharmony_ci HFC_DIGI_DF_M_IOM2_E, 748c2ecf20Sopenharmony_ci HFC_DIGI_DF_M_E, 758c2ecf20Sopenharmony_ci HFC_DIGI_DF_M_IOM2_A, 768c2ecf20Sopenharmony_ci HFC_DIGI_DF_M_A, 778c2ecf20Sopenharmony_ci HFC_ABOCOM_2BD1, 788c2ecf20Sopenharmony_ci HFC_SITECOM_DC105V2, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct hfcPCI_hw { 828c2ecf20Sopenharmony_ci unsigned char cirm; 838c2ecf20Sopenharmony_ci unsigned char ctmt; 848c2ecf20Sopenharmony_ci unsigned char clkdel; 858c2ecf20Sopenharmony_ci unsigned char states; 868c2ecf20Sopenharmony_ci unsigned char conn; 878c2ecf20Sopenharmony_ci unsigned char mst_m; 888c2ecf20Sopenharmony_ci unsigned char int_m1; 898c2ecf20Sopenharmony_ci unsigned char int_m2; 908c2ecf20Sopenharmony_ci unsigned char sctrl; 918c2ecf20Sopenharmony_ci unsigned char sctrl_r; 928c2ecf20Sopenharmony_ci unsigned char sctrl_e; 938c2ecf20Sopenharmony_ci unsigned char trm; 948c2ecf20Sopenharmony_ci unsigned char fifo_en; 958c2ecf20Sopenharmony_ci unsigned char bswapped; 968c2ecf20Sopenharmony_ci unsigned char protocol; 978c2ecf20Sopenharmony_ci int nt_timer; 988c2ecf20Sopenharmony_ci unsigned char __iomem *pci_io; /* start of PCI IO memory */ 998c2ecf20Sopenharmony_ci dma_addr_t dmahandle; 1008c2ecf20Sopenharmony_ci void *fifos; /* FIFO memory */ 1018c2ecf20Sopenharmony_ci int last_bfifo_cnt[2]; 1028c2ecf20Sopenharmony_ci /* marker saving last b-fifo frame count */ 1038c2ecf20Sopenharmony_ci struct timer_list timer; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define HFC_CFG_MASTER 1 1078c2ecf20Sopenharmony_ci#define HFC_CFG_SLAVE 2 1088c2ecf20Sopenharmony_ci#define HFC_CFG_PCM 3 1098c2ecf20Sopenharmony_ci#define HFC_CFG_2HFC 4 1108c2ecf20Sopenharmony_ci#define HFC_CFG_SLAVEHFC 5 1118c2ecf20Sopenharmony_ci#define HFC_CFG_NEG_F0 6 1128c2ecf20Sopenharmony_ci#define HFC_CFG_SW_DD_DU 7 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define FLG_HFC_TIMER_T1 16 1158c2ecf20Sopenharmony_ci#define FLG_HFC_TIMER_T3 17 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ 1188c2ecf20Sopenharmony_ci#define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ 1198c2ecf20Sopenharmony_ci#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ 1208c2ecf20Sopenharmony_ci#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistruct hfc_pci { 1248c2ecf20Sopenharmony_ci u_char subtype; 1258c2ecf20Sopenharmony_ci u_char chanlimit; 1268c2ecf20Sopenharmony_ci u_char initdone; 1278c2ecf20Sopenharmony_ci u_long cfg; 1288c2ecf20Sopenharmony_ci u_int irq; 1298c2ecf20Sopenharmony_ci u_int irqcnt; 1308c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1318c2ecf20Sopenharmony_ci struct hfcPCI_hw hw; 1328c2ecf20Sopenharmony_ci spinlock_t lock; /* card lock */ 1338c2ecf20Sopenharmony_ci struct dchannel dch; 1348c2ecf20Sopenharmony_ci struct bchannel bch[2]; 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Interface functions */ 1388c2ecf20Sopenharmony_cistatic void 1398c2ecf20Sopenharmony_cienable_hwirq(struct hfc_pci *hc) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; 1428c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void 1468c2ecf20Sopenharmony_cidisable_hwirq(struct hfc_pci *hc) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); 1498c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * free hardware resources used by driver 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic void 1568c2ecf20Sopenharmony_cirelease_io_hfcpci(struct hfc_pci *hc) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci /* disable memory mapped ports + busmaster */ 1598c2ecf20Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, 0); 1608c2ecf20Sopenharmony_ci del_timer(&hc->hw.timer); 1618c2ecf20Sopenharmony_ci dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, 1628c2ecf20Sopenharmony_ci hc->hw.dmahandle); 1638c2ecf20Sopenharmony_ci iounmap(hc->hw.pci_io); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* 1678c2ecf20Sopenharmony_ci * set mode (NT or TE) 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_cistatic void 1708c2ecf20Sopenharmony_cihfcpci_setmode(struct hfc_pci *hc) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 1738c2ecf20Sopenharmony_ci hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ 1748c2ecf20Sopenharmony_ci hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ 1758c2ecf20Sopenharmony_ci hc->hw.states = 1; /* G1 */ 1768c2ecf20Sopenharmony_ci } else { 1778c2ecf20Sopenharmony_ci hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ 1788c2ecf20Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ 1798c2ecf20Sopenharmony_ci hc->hw.states = 2; /* F2 */ 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); 1828c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); 1838c2ecf20Sopenharmony_ci udelay(10); 1848c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ 1858c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * function called to reset the HFC PCI chip. A complete software reset of chip 1908c2ecf20Sopenharmony_ci * and fifos is done. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_cistatic void 1938c2ecf20Sopenharmony_cireset_hfcpci(struct hfc_pci *hc) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u_char val; 1968c2ecf20Sopenharmony_ci int cnt = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci printk(KERN_DEBUG "reset_hfcpci: entered\n"); 1998c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_CHIP_ID); 2008c2ecf20Sopenharmony_ci printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); 2018c2ecf20Sopenharmony_ci /* enable memory mapped ports, disable busmaster */ 2028c2ecf20Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); 2038c2ecf20Sopenharmony_ci disable_hwirq(hc); 2048c2ecf20Sopenharmony_ci /* enable memory ports + busmaster */ 2058c2ecf20Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, 2068c2ecf20Sopenharmony_ci PCI_ENA_MEMIO + PCI_ENA_MASTER); 2078c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 2088c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); 2098c2ecf20Sopenharmony_ci hc->hw.cirm = HFCPCI_RESET; /* Reset On */ 2108c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 2118c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 2128c2ecf20Sopenharmony_ci mdelay(10); /* Timeout 10ms */ 2138c2ecf20Sopenharmony_ci hc->hw.cirm = 0; /* Reset Off */ 2148c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 2158c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 2168c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); 2178c2ecf20Sopenharmony_ci while (cnt < 50000) { /* max 50000 us */ 2188c2ecf20Sopenharmony_ci udelay(5); 2198c2ecf20Sopenharmony_ci cnt += 5; 2208c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 2218c2ecf20Sopenharmony_ci if (!(val & 2)) 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci hc->hw.fifo_en = 0x30; /* only D fifos enabled */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci hc->hw.bswapped = 0; /* no exchange */ 2298c2ecf20Sopenharmony_ci hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; 2308c2ecf20Sopenharmony_ci hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ 2318c2ecf20Sopenharmony_ci hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ 2328c2ecf20Sopenharmony_ci hc->hw.sctrl_r = 0; 2338c2ecf20Sopenharmony_ci hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ 2348c2ecf20Sopenharmony_ci hc->hw.mst_m = 0; 2358c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 2368c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ 2378c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) 2388c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_F0_NEGATIV; 2398c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 2408c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 2418c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); 2428c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | 2458c2ecf20Sopenharmony_ci HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; 2468c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Clear already pending ints */ 2498c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S1); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* set NT/TE mode */ 2528c2ecf20Sopenharmony_ci hfcpci_setmode(hc); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 2558c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Init GCI/IOM2 in master mode 2598c2ecf20Sopenharmony_ci * Slots 0 and 1 are set for B-chan 1 and 2 2608c2ecf20Sopenharmony_ci * D- and monitor/CI channel are not enabled 2618c2ecf20Sopenharmony_ci * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC 2628c2ecf20Sopenharmony_ci * STIO2 is used as data input, B1+B2 from IOM->ST 2638c2ecf20Sopenharmony_ci * ST B-channel send disabled -> continuous 1s 2648c2ecf20Sopenharmony_ci * The IOM slots are always enabled 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_PCM, &hc->cfg)) { 2678c2ecf20Sopenharmony_ci /* set data flow directions: connect B1,B2: HFC to/from PCM */ 2688c2ecf20Sopenharmony_ci hc->hw.conn = 0x09; 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci hc->hw.conn = 0x36; /* set data flow directions */ 2718c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { 2728c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); 2738c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); 2748c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); 2758c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); 2768c2ecf20Sopenharmony_ci } else { 2778c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, 0x80); 2788c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, 0x81); 2798c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, 0x80); 2808c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, 0x81); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 2848c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S2); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * Timer function called when kernel timer expires 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic void 2918c2ecf20Sopenharmony_cihfcpci_Timer(struct timer_list *t) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct hfc_pci *hc = from_timer(hc, t, hw.timer); 2948c2ecf20Sopenharmony_ci hc->hw.timer.expires = jiffies + 75; 2958c2ecf20Sopenharmony_ci /* WD RESET */ 2968c2ecf20Sopenharmony_ci/* 2978c2ecf20Sopenharmony_ci * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80); 2988c2ecf20Sopenharmony_ci * add_timer(&hc->hw.timer); 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci * select a b-channel entry matching and active 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_cistatic struct bchannel * 3078c2ecf20Sopenharmony_ciSel_BCS(struct hfc_pci *hc, int channel) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && 3108c2ecf20Sopenharmony_ci (hc->bch[0].nr & channel)) 3118c2ecf20Sopenharmony_ci return &hc->bch[0]; 3128c2ecf20Sopenharmony_ci else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && 3138c2ecf20Sopenharmony_ci (hc->bch[1].nr & channel)) 3148c2ecf20Sopenharmony_ci return &hc->bch[1]; 3158c2ecf20Sopenharmony_ci else 3168c2ecf20Sopenharmony_ci return NULL; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* 3208c2ecf20Sopenharmony_ci * clear the desired B-channel rx fifo 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic void 3238c2ecf20Sopenharmony_cihfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci u_char fifo_state; 3268c2ecf20Sopenharmony_ci struct bzfifo *bzr; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (fifo) { 3298c2ecf20Sopenharmony_ci bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; 3308c2ecf20Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX; 3318c2ecf20Sopenharmony_ci } else { 3328c2ecf20Sopenharmony_ci bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; 3338c2ecf20Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci if (fifo_state) 3368c2ecf20Sopenharmony_ci hc->hw.fifo_en ^= fifo_state; 3378c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 3388c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[fifo] = 0; 3398c2ecf20Sopenharmony_ci bzr->f1 = MAX_B_FRAMES; 3408c2ecf20Sopenharmony_ci bzr->f2 = bzr->f1; /* init F pointers to remain constant */ 3418c2ecf20Sopenharmony_ci bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); 3428c2ecf20Sopenharmony_ci bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16( 3438c2ecf20Sopenharmony_ci le16_to_cpu(bzr->za[MAX_B_FRAMES].z1)); 3448c2ecf20Sopenharmony_ci if (fifo_state) 3458c2ecf20Sopenharmony_ci hc->hw.fifo_en |= fifo_state; 3468c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * clear the desired B-channel tx fifo 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci u_char fifo_state; 3558c2ecf20Sopenharmony_ci struct bzfifo *bzt; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (fifo) { 3588c2ecf20Sopenharmony_ci bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 3598c2ecf20Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX; 3608c2ecf20Sopenharmony_ci } else { 3618c2ecf20Sopenharmony_ci bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 3628c2ecf20Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci if (fifo_state) 3658c2ecf20Sopenharmony_ci hc->hw.fifo_en ^= fifo_state; 3668c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 3678c2ecf20Sopenharmony_ci if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) 3688c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) " 3698c2ecf20Sopenharmony_ci "z1(%x) z2(%x) state(%x)\n", 3708c2ecf20Sopenharmony_ci fifo, bzt->f1, bzt->f2, 3718c2ecf20Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), 3728c2ecf20Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z2), 3738c2ecf20Sopenharmony_ci fifo_state); 3748c2ecf20Sopenharmony_ci bzt->f2 = MAX_B_FRAMES; 3758c2ecf20Sopenharmony_ci bzt->f1 = bzt->f2; /* init F pointers to remain constant */ 3768c2ecf20Sopenharmony_ci bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); 3778c2ecf20Sopenharmony_ci bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2); 3788c2ecf20Sopenharmony_ci if (fifo_state) 3798c2ecf20Sopenharmony_ci hc->hw.fifo_en |= fifo_state; 3808c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 3818c2ecf20Sopenharmony_ci if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) 3828c2ecf20Sopenharmony_ci printk(KERN_DEBUG 3838c2ecf20Sopenharmony_ci "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n", 3848c2ecf20Sopenharmony_ci fifo, bzt->f1, bzt->f2, 3858c2ecf20Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), 3868c2ecf20Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z2)); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* 3908c2ecf20Sopenharmony_ci * read a complete B-frame out of the buffer 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic void 3938c2ecf20Sopenharmony_cihfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, 3948c2ecf20Sopenharmony_ci u_char *bdata, int count) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci u_char *ptr, *ptr1, new_f2; 3978c2ecf20Sopenharmony_ci int maxlen, new_z2; 3988c2ecf20Sopenharmony_ci struct zt *zp; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) 4018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_empty_fifo\n"); 4028c2ecf20Sopenharmony_ci zp = &bz->za[bz->f2]; /* point to Z-Regs */ 4038c2ecf20Sopenharmony_ci new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ 4048c2ecf20Sopenharmony_ci if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) 4058c2ecf20Sopenharmony_ci new_z2 -= B_FIFO_SIZE; /* buffer wrap */ 4068c2ecf20Sopenharmony_ci new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; 4078c2ecf20Sopenharmony_ci if ((count > MAX_DATA_SIZE + 3) || (count < 4) || 4088c2ecf20Sopenharmony_ci (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { 4098c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW) 4108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet " 4118c2ecf20Sopenharmony_ci "invalid length %d or crc\n", count); 4128c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 4138c2ecf20Sopenharmony_ci bch->err_inv++; 4148c2ecf20Sopenharmony_ci#endif 4158c2ecf20Sopenharmony_ci bz->za[new_f2].z2 = cpu_to_le16(new_z2); 4168c2ecf20Sopenharmony_ci bz->f2 = new_f2; /* next buffer */ 4178c2ecf20Sopenharmony_ci } else { 4188c2ecf20Sopenharmony_ci bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC); 4198c2ecf20Sopenharmony_ci if (!bch->rx_skb) { 4208c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFCPCI: receive out of memory\n"); 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci count -= 3; 4248c2ecf20Sopenharmony_ci ptr = skb_put(bch->rx_skb, count); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) 4278c2ecf20Sopenharmony_ci maxlen = count; /* complete transfer */ 4288c2ecf20Sopenharmony_ci else 4298c2ecf20Sopenharmony_ci maxlen = B_FIFO_SIZE + B_SUB_VAL - 4308c2ecf20Sopenharmony_ci le16_to_cpu(zp->z2); /* maximum */ 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); 4338c2ecf20Sopenharmony_ci /* start of data */ 4348c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 4358c2ecf20Sopenharmony_ci count -= maxlen; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (count) { /* rest remaining */ 4388c2ecf20Sopenharmony_ci ptr += maxlen; 4398c2ecf20Sopenharmony_ci ptr1 = bdata; /* start of buffer */ 4408c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, count); /* rest */ 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci bz->za[new_f2].z2 = cpu_to_le16(new_z2); 4438c2ecf20Sopenharmony_ci bz->f2 = new_f2; /* next buffer */ 4448c2ecf20Sopenharmony_ci recv_Bchannel(bch, MISDN_ID_ANY, false); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* 4498c2ecf20Sopenharmony_ci * D-channel receive procedure 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_cistatic int 4528c2ecf20Sopenharmony_cireceive_dmsg(struct hfc_pci *hc) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct dchannel *dch = &hc->dch; 4558c2ecf20Sopenharmony_ci int maxlen; 4568c2ecf20Sopenharmony_ci int rcnt, total; 4578c2ecf20Sopenharmony_ci int count = 5; 4588c2ecf20Sopenharmony_ci u_char *ptr, *ptr1; 4598c2ecf20Sopenharmony_ci struct dfifo *df; 4608c2ecf20Sopenharmony_ci struct zt *zp; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx; 4638c2ecf20Sopenharmony_ci while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { 4648c2ecf20Sopenharmony_ci zp = &df->za[df->f2 & D_FREG_MASK]; 4658c2ecf20Sopenharmony_ci rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); 4668c2ecf20Sopenharmony_ci if (rcnt < 0) 4678c2ecf20Sopenharmony_ci rcnt += D_FIFO_SIZE; 4688c2ecf20Sopenharmony_ci rcnt++; 4698c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 4708c2ecf20Sopenharmony_ci printk(KERN_DEBUG 4718c2ecf20Sopenharmony_ci "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n", 4728c2ecf20Sopenharmony_ci df->f1, df->f2, 4738c2ecf20Sopenharmony_ci le16_to_cpu(zp->z1), 4748c2ecf20Sopenharmony_ci le16_to_cpu(zp->z2), 4758c2ecf20Sopenharmony_ci rcnt); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || 4788c2ecf20Sopenharmony_ci (df->data[le16_to_cpu(zp->z1)])) { 4798c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 4808c2ecf20Sopenharmony_ci printk(KERN_DEBUG 4818c2ecf20Sopenharmony_ci "empty_fifo hfcpci packet inv. len " 4828c2ecf20Sopenharmony_ci "%d or crc %d\n", 4838c2ecf20Sopenharmony_ci rcnt, 4848c2ecf20Sopenharmony_ci df->data[le16_to_cpu(zp->z1)]); 4858c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 4868c2ecf20Sopenharmony_ci cs->err_rx++; 4878c2ecf20Sopenharmony_ci#endif 4888c2ecf20Sopenharmony_ci df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | 4898c2ecf20Sopenharmony_ci (MAX_D_FRAMES + 1); /* next buffer */ 4908c2ecf20Sopenharmony_ci df->za[df->f2 & D_FREG_MASK].z2 = 4918c2ecf20Sopenharmony_ci cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & 4928c2ecf20Sopenharmony_ci (D_FIFO_SIZE - 1)); 4938c2ecf20Sopenharmony_ci } else { 4948c2ecf20Sopenharmony_ci dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); 4958c2ecf20Sopenharmony_ci if (!dch->rx_skb) { 4968c2ecf20Sopenharmony_ci printk(KERN_WARNING 4978c2ecf20Sopenharmony_ci "HFC-PCI: D receive out of memory\n"); 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci total = rcnt; 5018c2ecf20Sopenharmony_ci rcnt -= 3; 5028c2ecf20Sopenharmony_ci ptr = skb_put(dch->rx_skb, rcnt); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) 5058c2ecf20Sopenharmony_ci maxlen = rcnt; /* complete transfer */ 5068c2ecf20Sopenharmony_ci else 5078c2ecf20Sopenharmony_ci maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); 5088c2ecf20Sopenharmony_ci /* maximum */ 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci ptr1 = df->data + le16_to_cpu(zp->z2); 5118c2ecf20Sopenharmony_ci /* start of data */ 5128c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 5138c2ecf20Sopenharmony_ci rcnt -= maxlen; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (rcnt) { /* rest remaining */ 5168c2ecf20Sopenharmony_ci ptr += maxlen; 5178c2ecf20Sopenharmony_ci ptr1 = df->data; /* start of buffer */ 5188c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, rcnt); /* rest */ 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | 5218c2ecf20Sopenharmony_ci (MAX_D_FRAMES + 1); /* next buffer */ 5228c2ecf20Sopenharmony_ci df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16(( 5238c2ecf20Sopenharmony_ci le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); 5248c2ecf20Sopenharmony_ci recv_Dchannel(dch); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci return 1; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/* 5318c2ecf20Sopenharmony_ci * check for transparent receive data and read max one 'poll' size if avail 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_cistatic void 5348c2ecf20Sopenharmony_cihfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, 5358c2ecf20Sopenharmony_ci struct bzfifo *txbz, u_char *bdata) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci __le16 *z1r, *z2r, *z1t, *z2t; 5388c2ecf20Sopenharmony_ci int new_z2, fcnt_rx, fcnt_tx, maxlen; 5398c2ecf20Sopenharmony_ci u_char *ptr, *ptr1; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ 5428c2ecf20Sopenharmony_ci z2r = z1r + 1; 5438c2ecf20Sopenharmony_ci z1t = &txbz->za[MAX_B_FRAMES].z1; 5448c2ecf20Sopenharmony_ci z2t = z1t + 1; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); 5478c2ecf20Sopenharmony_ci if (!fcnt_rx) 5488c2ecf20Sopenharmony_ci return; /* no data avail */ 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (fcnt_rx <= 0) 5518c2ecf20Sopenharmony_ci fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */ 5528c2ecf20Sopenharmony_ci new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */ 5538c2ecf20Sopenharmony_ci if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) 5548c2ecf20Sopenharmony_ci new_z2 -= B_FIFO_SIZE; /* buffer wrap */ 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); 5578c2ecf20Sopenharmony_ci if (fcnt_tx <= 0) 5588c2ecf20Sopenharmony_ci fcnt_tx += B_FIFO_SIZE; 5598c2ecf20Sopenharmony_ci /* fcnt_tx contains available bytes in tx-fifo */ 5608c2ecf20Sopenharmony_ci fcnt_tx = B_FIFO_SIZE - fcnt_tx; 5618c2ecf20Sopenharmony_ci /* remaining bytes to send (bytes in tx-fifo) */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (test_bit(FLG_RX_OFF, &bch->Flags)) { 5648c2ecf20Sopenharmony_ci bch->dropcnt += fcnt_rx; 5658c2ecf20Sopenharmony_ci *z2r = cpu_to_le16(new_z2); 5668c2ecf20Sopenharmony_ci return; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(bch, fcnt_rx); 5698c2ecf20Sopenharmony_ci if (maxlen < 0) { 5708c2ecf20Sopenharmony_ci pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx); 5718c2ecf20Sopenharmony_ci } else { 5728c2ecf20Sopenharmony_ci ptr = skb_put(bch->rx_skb, fcnt_rx); 5738c2ecf20Sopenharmony_ci if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) 5748c2ecf20Sopenharmony_ci maxlen = fcnt_rx; /* complete transfer */ 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); 5778c2ecf20Sopenharmony_ci /* maximum */ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); 5808c2ecf20Sopenharmony_ci /* start of data */ 5818c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 5828c2ecf20Sopenharmony_ci fcnt_rx -= maxlen; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (fcnt_rx) { /* rest remaining */ 5858c2ecf20Sopenharmony_ci ptr += maxlen; 5868c2ecf20Sopenharmony_ci ptr1 = bdata; /* start of buffer */ 5878c2ecf20Sopenharmony_ci memcpy(ptr, ptr1, fcnt_rx); /* rest */ 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */ 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci *z2r = cpu_to_le16(new_z2); /* new position */ 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/* 5958c2ecf20Sopenharmony_ci * B-channel main receive routine 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_cistatic void 5988c2ecf20Sopenharmony_cimain_rec_hfcpci(struct bchannel *bch) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 6018c2ecf20Sopenharmony_ci int rcnt, real_fifo; 6028c2ecf20Sopenharmony_ci int receive = 0, count = 5; 6038c2ecf20Sopenharmony_ci struct bzfifo *txbz, *rxbz; 6048c2ecf20Sopenharmony_ci u_char *bdata; 6058c2ecf20Sopenharmony_ci struct zt *zp; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if ((bch->nr & 2) && (!hc->hw.bswapped)) { 6088c2ecf20Sopenharmony_ci rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; 6098c2ecf20Sopenharmony_ci txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 6108c2ecf20Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; 6118c2ecf20Sopenharmony_ci real_fifo = 1; 6128c2ecf20Sopenharmony_ci } else { 6138c2ecf20Sopenharmony_ci rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; 6148c2ecf20Sopenharmony_ci txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 6158c2ecf20Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; 6168c2ecf20Sopenharmony_ci real_fifo = 0; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ciBegin: 6198c2ecf20Sopenharmony_ci count--; 6208c2ecf20Sopenharmony_ci if (rxbz->f1 != rxbz->f2) { 6218c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 6228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", 6238c2ecf20Sopenharmony_ci bch->nr, rxbz->f1, rxbz->f2); 6248c2ecf20Sopenharmony_ci zp = &rxbz->za[rxbz->f2]; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); 6278c2ecf20Sopenharmony_ci if (rcnt < 0) 6288c2ecf20Sopenharmony_ci rcnt += B_FIFO_SIZE; 6298c2ecf20Sopenharmony_ci rcnt++; 6308c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 6318c2ecf20Sopenharmony_ci printk(KERN_DEBUG 6328c2ecf20Sopenharmony_ci "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", 6338c2ecf20Sopenharmony_ci bch->nr, le16_to_cpu(zp->z1), 6348c2ecf20Sopenharmony_ci le16_to_cpu(zp->z2), rcnt); 6358c2ecf20Sopenharmony_ci hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt); 6368c2ecf20Sopenharmony_ci rcnt = rxbz->f1 - rxbz->f2; 6378c2ecf20Sopenharmony_ci if (rcnt < 0) 6388c2ecf20Sopenharmony_ci rcnt += MAX_B_FRAMES + 1; 6398c2ecf20Sopenharmony_ci if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { 6408c2ecf20Sopenharmony_ci rcnt = 0; 6418c2ecf20Sopenharmony_ci hfcpci_clear_fifo_rx(hc, real_fifo); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[real_fifo] = rcnt; 6448c2ecf20Sopenharmony_ci if (rcnt > 1) 6458c2ecf20Sopenharmony_ci receive = 1; 6468c2ecf20Sopenharmony_ci else 6478c2ecf20Sopenharmony_ci receive = 0; 6488c2ecf20Sopenharmony_ci } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 6498c2ecf20Sopenharmony_ci hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata); 6508c2ecf20Sopenharmony_ci return; 6518c2ecf20Sopenharmony_ci } else 6528c2ecf20Sopenharmony_ci receive = 0; 6538c2ecf20Sopenharmony_ci if (count && receive) 6548c2ecf20Sopenharmony_ci goto Begin; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/* 6598c2ecf20Sopenharmony_ci * D-channel send routine 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_cistatic void 6628c2ecf20Sopenharmony_cihfcpci_fill_dfifo(struct hfc_pci *hc) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct dchannel *dch = &hc->dch; 6658c2ecf20Sopenharmony_ci int fcnt; 6668c2ecf20Sopenharmony_ci int count, new_z1, maxlen; 6678c2ecf20Sopenharmony_ci struct dfifo *df; 6688c2ecf20Sopenharmony_ci u_char *src, *dst, new_f1; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO)) 6718c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s\n", __func__); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!dch->tx_skb) 6748c2ecf20Sopenharmony_ci return; 6758c2ecf20Sopenharmony_ci count = dch->tx_skb->len - dch->tx_idx; 6768c2ecf20Sopenharmony_ci if (count <= 0) 6778c2ecf20Sopenharmony_ci return; 6788c2ecf20Sopenharmony_ci df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW_DFIFO) 6818c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__, 6828c2ecf20Sopenharmony_ci df->f1, df->f2, 6838c2ecf20Sopenharmony_ci le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); 6848c2ecf20Sopenharmony_ci fcnt = df->f1 - df->f2; /* frame count actually buffered */ 6858c2ecf20Sopenharmony_ci if (fcnt < 0) 6868c2ecf20Sopenharmony_ci fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ 6878c2ecf20Sopenharmony_ci if (fcnt > (MAX_D_FRAMES - 1)) { 6888c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 6898c2ecf20Sopenharmony_ci printk(KERN_DEBUG 6908c2ecf20Sopenharmony_ci "hfcpci_fill_Dfifo more as 14 frames\n"); 6918c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 6928c2ecf20Sopenharmony_ci cs->err_tx++; 6938c2ecf20Sopenharmony_ci#endif 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci /* now determine free bytes in FIFO buffer */ 6978c2ecf20Sopenharmony_ci maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - 6988c2ecf20Sopenharmony_ci le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1; 6998c2ecf20Sopenharmony_ci if (maxlen <= 0) 7008c2ecf20Sopenharmony_ci maxlen += D_FIFO_SIZE; /* count now contains available bytes */ 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 7038c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n", 7048c2ecf20Sopenharmony_ci count, maxlen); 7058c2ecf20Sopenharmony_ci if (count > maxlen) { 7068c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 7078c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n"); 7088c2ecf20Sopenharmony_ci return; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & 7118c2ecf20Sopenharmony_ci (D_FIFO_SIZE - 1); 7128c2ecf20Sopenharmony_ci new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); 7138c2ecf20Sopenharmony_ci src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ 7148c2ecf20Sopenharmony_ci dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); 7158c2ecf20Sopenharmony_ci maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); 7168c2ecf20Sopenharmony_ci /* end fifo */ 7178c2ecf20Sopenharmony_ci if (maxlen > count) 7188c2ecf20Sopenharmony_ci maxlen = count; /* limit size */ 7198c2ecf20Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci count -= maxlen; /* remaining bytes */ 7228c2ecf20Sopenharmony_ci if (count) { 7238c2ecf20Sopenharmony_ci dst = df->data; /* start of buffer */ 7248c2ecf20Sopenharmony_ci src += maxlen; /* new position */ 7258c2ecf20Sopenharmony_ci memcpy(dst, src, count); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); 7288c2ecf20Sopenharmony_ci /* for next buffer */ 7298c2ecf20Sopenharmony_ci df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); 7308c2ecf20Sopenharmony_ci /* new pos actual buffer */ 7318c2ecf20Sopenharmony_ci df->f1 = new_f1; /* next frame */ 7328c2ecf20Sopenharmony_ci dch->tx_idx = dch->tx_skb->len; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci/* 7368c2ecf20Sopenharmony_ci * B-channel send routine 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_cistatic void 7398c2ecf20Sopenharmony_cihfcpci_fill_fifo(struct bchannel *bch) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 7428c2ecf20Sopenharmony_ci int maxlen, fcnt; 7438c2ecf20Sopenharmony_ci int count, new_z1; 7448c2ecf20Sopenharmony_ci struct bzfifo *bz; 7458c2ecf20Sopenharmony_ci u_char *bdata; 7468c2ecf20Sopenharmony_ci u_char new_f1, *src, *dst; 7478c2ecf20Sopenharmony_ci __le16 *z1t, *z2t; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) 7508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s\n", __func__); 7518c2ecf20Sopenharmony_ci if ((!bch->tx_skb) || bch->tx_skb->len == 0) { 7528c2ecf20Sopenharmony_ci if (!test_bit(FLG_FILLEMPTY, &bch->Flags) && 7538c2ecf20Sopenharmony_ci !test_bit(FLG_TRANSPARENT, &bch->Flags)) 7548c2ecf20Sopenharmony_ci return; 7558c2ecf20Sopenharmony_ci count = HFCPCI_FILLEMPTY; 7568c2ecf20Sopenharmony_ci } else { 7578c2ecf20Sopenharmony_ci count = bch->tx_skb->len - bch->tx_idx; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci if ((bch->nr & 2) && (!hc->hw.bswapped)) { 7608c2ecf20Sopenharmony_ci bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 7618c2ecf20Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; 7628c2ecf20Sopenharmony_ci } else { 7638c2ecf20Sopenharmony_ci bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 7648c2ecf20Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 7688c2ecf20Sopenharmony_ci z1t = &bz->za[MAX_B_FRAMES].z1; 7698c2ecf20Sopenharmony_ci z2t = z1t + 1; 7708c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 7718c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) " 7728c2ecf20Sopenharmony_ci "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count, 7738c2ecf20Sopenharmony_ci le16_to_cpu(*z1t), le16_to_cpu(*z2t)); 7748c2ecf20Sopenharmony_ci fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); 7758c2ecf20Sopenharmony_ci if (fcnt <= 0) 7768c2ecf20Sopenharmony_ci fcnt += B_FIFO_SIZE; 7778c2ecf20Sopenharmony_ci if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { 7788c2ecf20Sopenharmony_ci /* fcnt contains available bytes in fifo */ 7798c2ecf20Sopenharmony_ci if (count > fcnt) 7808c2ecf20Sopenharmony_ci count = fcnt; 7818c2ecf20Sopenharmony_ci new_z1 = le16_to_cpu(*z1t) + count; 7828c2ecf20Sopenharmony_ci /* new buffer Position */ 7838c2ecf20Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 7848c2ecf20Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 7858c2ecf20Sopenharmony_ci dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); 7868c2ecf20Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); 7878c2ecf20Sopenharmony_ci /* end of fifo */ 7888c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BFIFO) 7898c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_FFt fillempty " 7908c2ecf20Sopenharmony_ci "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", 7918c2ecf20Sopenharmony_ci fcnt, maxlen, new_z1, dst); 7928c2ecf20Sopenharmony_ci if (maxlen > count) 7938c2ecf20Sopenharmony_ci maxlen = count; /* limit size */ 7948c2ecf20Sopenharmony_ci memset(dst, bch->fill[0], maxlen); /* first copy */ 7958c2ecf20Sopenharmony_ci count -= maxlen; /* remaining bytes */ 7968c2ecf20Sopenharmony_ci if (count) { 7978c2ecf20Sopenharmony_ci dst = bdata; /* start of buffer */ 7988c2ecf20Sopenharmony_ci memset(dst, bch->fill[0], count); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci *z1t = cpu_to_le16(new_z1); /* now send data */ 8018c2ecf20Sopenharmony_ci return; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci /* fcnt contains available bytes in fifo */ 8048c2ecf20Sopenharmony_ci fcnt = B_FIFO_SIZE - fcnt; 8058c2ecf20Sopenharmony_ci /* remaining bytes to send (bytes in fifo) */ 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci next_t_frame: 8088c2ecf20Sopenharmony_ci count = bch->tx_skb->len - bch->tx_idx; 8098c2ecf20Sopenharmony_ci /* maximum fill shall be poll*2 */ 8108c2ecf20Sopenharmony_ci if (count > (poll << 1) - fcnt) 8118c2ecf20Sopenharmony_ci count = (poll << 1) - fcnt; 8128c2ecf20Sopenharmony_ci if (count <= 0) 8138c2ecf20Sopenharmony_ci return; 8148c2ecf20Sopenharmony_ci /* data is suitable for fifo */ 8158c2ecf20Sopenharmony_ci new_z1 = le16_to_cpu(*z1t) + count; 8168c2ecf20Sopenharmony_ci /* new buffer Position */ 8178c2ecf20Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 8188c2ecf20Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 8198c2ecf20Sopenharmony_ci src = bch->tx_skb->data + bch->tx_idx; 8208c2ecf20Sopenharmony_ci /* source pointer */ 8218c2ecf20Sopenharmony_ci dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); 8228c2ecf20Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); 8238c2ecf20Sopenharmony_ci /* end of fifo */ 8248c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BFIFO) 8258c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) " 8268c2ecf20Sopenharmony_ci "maxl(%d) nz1(%x) dst(%p)\n", 8278c2ecf20Sopenharmony_ci fcnt, maxlen, new_z1, dst); 8288c2ecf20Sopenharmony_ci fcnt += count; 8298c2ecf20Sopenharmony_ci bch->tx_idx += count; 8308c2ecf20Sopenharmony_ci if (maxlen > count) 8318c2ecf20Sopenharmony_ci maxlen = count; /* limit size */ 8328c2ecf20Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 8338c2ecf20Sopenharmony_ci count -= maxlen; /* remaining bytes */ 8348c2ecf20Sopenharmony_ci if (count) { 8358c2ecf20Sopenharmony_ci dst = bdata; /* start of buffer */ 8368c2ecf20Sopenharmony_ci src += maxlen; /* new position */ 8378c2ecf20Sopenharmony_ci memcpy(dst, src, count); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci *z1t = cpu_to_le16(new_z1); /* now send data */ 8408c2ecf20Sopenharmony_ci if (bch->tx_idx < bch->tx_skb->len) 8418c2ecf20Sopenharmony_ci return; 8428c2ecf20Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 8438c2ecf20Sopenharmony_ci if (get_next_bframe(bch)) 8448c2ecf20Sopenharmony_ci goto next_t_frame; 8458c2ecf20Sopenharmony_ci return; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 8488c2ecf20Sopenharmony_ci printk(KERN_DEBUG 8498c2ecf20Sopenharmony_ci "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n", 8508c2ecf20Sopenharmony_ci __func__, bch->nr, bz->f1, bz->f2, 8518c2ecf20Sopenharmony_ci bz->za[bz->f1].z1); 8528c2ecf20Sopenharmony_ci fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ 8538c2ecf20Sopenharmony_ci if (fcnt < 0) 8548c2ecf20Sopenharmony_ci fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ 8558c2ecf20Sopenharmony_ci if (fcnt > (MAX_B_FRAMES - 1)) { 8568c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 8578c2ecf20Sopenharmony_ci printk(KERN_DEBUG 8588c2ecf20Sopenharmony_ci "hfcpci_fill_Bfifo more as 14 frames\n"); 8598c2ecf20Sopenharmony_ci return; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci /* now determine free bytes in FIFO buffer */ 8628c2ecf20Sopenharmony_ci maxlen = le16_to_cpu(bz->za[bz->f2].z2) - 8638c2ecf20Sopenharmony_ci le16_to_cpu(bz->za[bz->f1].z1) - 1; 8648c2ecf20Sopenharmony_ci if (maxlen <= 0) 8658c2ecf20Sopenharmony_ci maxlen += B_FIFO_SIZE; /* count now contains available bytes */ 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 8688c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n", 8698c2ecf20Sopenharmony_ci bch->nr, count, maxlen); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (maxlen < count) { 8728c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 8738c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n"); 8748c2ecf20Sopenharmony_ci return; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; 8778c2ecf20Sopenharmony_ci /* new buffer Position */ 8788c2ecf20Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 8798c2ecf20Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); 8828c2ecf20Sopenharmony_ci src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ 8838c2ecf20Sopenharmony_ci dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); 8848c2ecf20Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); 8858c2ecf20Sopenharmony_ci /* end fifo */ 8868c2ecf20Sopenharmony_ci if (maxlen > count) 8878c2ecf20Sopenharmony_ci maxlen = count; /* limit size */ 8888c2ecf20Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci count -= maxlen; /* remaining bytes */ 8918c2ecf20Sopenharmony_ci if (count) { 8928c2ecf20Sopenharmony_ci dst = bdata; /* start of buffer */ 8938c2ecf20Sopenharmony_ci src += maxlen; /* new position */ 8948c2ecf20Sopenharmony_ci memcpy(dst, src, count); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ 8978c2ecf20Sopenharmony_ci bz->f1 = new_f1; /* next frame */ 8988c2ecf20Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 8998c2ecf20Sopenharmony_ci get_next_bframe(bch); 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci/* 9058c2ecf20Sopenharmony_ci * handle L1 state changes TE 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic void 9098c2ecf20Sopenharmony_ciph_state_te(struct dchannel *dch) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci if (dch->debug) 9128c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: TE newstate %x\n", 9138c2ecf20Sopenharmony_ci __func__, dch->state); 9148c2ecf20Sopenharmony_ci switch (dch->state) { 9158c2ecf20Sopenharmony_ci case 0: 9168c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci case 3: 9198c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci case 5: 9228c2ecf20Sopenharmony_ci case 8: 9238c2ecf20Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci case 6: 9268c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO2); 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case 7: 9298c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci/* 9358c2ecf20Sopenharmony_ci * handle L1 state changes NT 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic void 9398c2ecf20Sopenharmony_cihandle_nt_timer3(struct dchannel *dch) { 9408c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 9438c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 9448c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 9458c2ecf20Sopenharmony_ci hc->hw.nt_timer = 0; 9468c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 9478c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 9488c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 9498c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 9508c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 9518c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic void 9558c2ecf20Sopenharmony_ciph_state_nt(struct dchannel *dch) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (dch->debug) 9608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: NT newstate %x\n", 9618c2ecf20Sopenharmony_ci __func__, dch->state); 9628c2ecf20Sopenharmony_ci switch (dch->state) { 9638c2ecf20Sopenharmony_ci case 2: 9648c2ecf20Sopenharmony_ci if (hc->hw.nt_timer < 0) { 9658c2ecf20Sopenharmony_ci hc->hw.nt_timer = 0; 9668c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 9678c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 9688c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 9698c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 9708c2ecf20Sopenharmony_ci /* Clear already pending ints */ 9718c2ecf20Sopenharmony_ci (void) Read_hfc(hc, HFCPCI_INT_S1); 9728c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); 9738c2ecf20Sopenharmony_ci udelay(10); 9748c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 4); 9758c2ecf20Sopenharmony_ci dch->state = 4; 9768c2ecf20Sopenharmony_ci } else if (hc->hw.nt_timer == 0) { 9778c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_TIMER; 9788c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 9798c2ecf20Sopenharmony_ci hc->hw.nt_timer = NT_T1_COUNT; 9808c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; 9818c2ecf20Sopenharmony_ci hc->hw.ctmt |= HFCPCI_TIM3_125; 9828c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | 9838c2ecf20Sopenharmony_ci HFCPCI_CLTIMER); 9848c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 9858c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags); 9868c2ecf20Sopenharmony_ci /* allow G2 -> G3 transition */ 9878c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); 9888c2ecf20Sopenharmony_ci } else { 9898c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci break; 9928c2ecf20Sopenharmony_ci case 1: 9938c2ecf20Sopenharmony_ci hc->hw.nt_timer = 0; 9948c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 9958c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 9968c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 9978c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 9988c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 9998c2ecf20Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 10008c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 10018c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 10028c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 10038c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci case 4: 10068c2ecf20Sopenharmony_ci hc->hw.nt_timer = 0; 10078c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 10088c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 10098c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 10108c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 10118c2ecf20Sopenharmony_ci break; 10128c2ecf20Sopenharmony_ci case 3: 10138c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) { 10148c2ecf20Sopenharmony_ci if (!test_and_clear_bit(FLG_L2_ACTIVATED, 10158c2ecf20Sopenharmony_ci &dch->Flags)) { 10168c2ecf20Sopenharmony_ci handle_nt_timer3(dch); 10178c2ecf20Sopenharmony_ci break; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 10208c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_TIMER; 10218c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 10228c2ecf20Sopenharmony_ci hc->hw.nt_timer = NT_T3_COUNT; 10238c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; 10248c2ecf20Sopenharmony_ci hc->hw.ctmt |= HFCPCI_TIM3_125; 10258c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | 10268c2ecf20Sopenharmony_ci HFCPCI_CLTIMER); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic void 10338c2ecf20Sopenharmony_ciph_state(struct dchannel *dch) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 10388c2ecf20Sopenharmony_ci if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) && 10398c2ecf20Sopenharmony_ci hc->hw.nt_timer < 0) 10408c2ecf20Sopenharmony_ci handle_nt_timer3(dch); 10418c2ecf20Sopenharmony_ci else 10428c2ecf20Sopenharmony_ci ph_state_nt(dch); 10438c2ecf20Sopenharmony_ci } else 10448c2ecf20Sopenharmony_ci ph_state_te(dch); 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci/* 10488c2ecf20Sopenharmony_ci * Layer 1 callback function 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_cistatic int 10518c2ecf20Sopenharmony_cihfc_l1callback(struct dchannel *dch, u_int cmd) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci switch (cmd) { 10568c2ecf20Sopenharmony_ci case INFO3_P8: 10578c2ecf20Sopenharmony_ci case INFO3_P10: 10588c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 10598c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 10608c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci case HW_RESET_REQ: 10638c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); 10648c2ecf20Sopenharmony_ci /* HFC ST 3 */ 10658c2ecf20Sopenharmony_ci udelay(6); 10668c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ 10678c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 10688c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 10698c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 10708c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | 10718c2ecf20Sopenharmony_ci HFCPCI_DO_ACTION); 10728c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_POWERUP_IND); 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci case HW_DEACT_REQ: 10758c2ecf20Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 10768c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 10778c2ecf20Sopenharmony_ci skb_queue_purge(&dch->squeue); 10788c2ecf20Sopenharmony_ci if (dch->tx_skb) { 10798c2ecf20Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 10808c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci dch->tx_idx = 0; 10838c2ecf20Sopenharmony_ci if (dch->rx_skb) { 10848c2ecf20Sopenharmony_ci dev_kfree_skb(dch->rx_skb); 10858c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 10888c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 10898c2ecf20Sopenharmony_ci del_timer(&dch->timer); 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci case HW_POWERUP_REQ: 10928c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci case PH_ACTIVATE_IND: 10958c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 10968c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 10978c2ecf20Sopenharmony_ci GFP_ATOMIC); 10988c2ecf20Sopenharmony_ci break; 10998c2ecf20Sopenharmony_ci case PH_DEACTIVATE_IND: 11008c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 11018c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 11028c2ecf20Sopenharmony_ci GFP_ATOMIC); 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci default: 11058c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 11068c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 11078c2ecf20Sopenharmony_ci __func__, cmd); 11088c2ecf20Sopenharmony_ci return -1; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci/* 11148c2ecf20Sopenharmony_ci * Interrupt handler 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_cistatic inline void 11178c2ecf20Sopenharmony_citx_birq(struct bchannel *bch) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) 11208c2ecf20Sopenharmony_ci hfcpci_fill_fifo(bch); 11218c2ecf20Sopenharmony_ci else { 11228c2ecf20Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 11238c2ecf20Sopenharmony_ci if (get_next_bframe(bch)) 11248c2ecf20Sopenharmony_ci hfcpci_fill_fifo(bch); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic inline void 11298c2ecf20Sopenharmony_citx_dirq(struct dchannel *dch) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) 11328c2ecf20Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 11338c2ecf20Sopenharmony_ci else { 11348c2ecf20Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 11358c2ecf20Sopenharmony_ci if (get_next_dframe(dch)) 11368c2ecf20Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic irqreturn_t 11418c2ecf20Sopenharmony_cihfcpci_int(int intno, void *dev_id) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct hfc_pci *hc = dev_id; 11448c2ecf20Sopenharmony_ci u_char exval; 11458c2ecf20Sopenharmony_ci struct bchannel *bch; 11468c2ecf20Sopenharmony_ci u_char val, stat; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci spin_lock(&hc->lock); 11498c2ecf20Sopenharmony_ci if (!(hc->hw.int_m2 & 0x08)) { 11508c2ecf20Sopenharmony_ci spin_unlock(&hc->lock); 11518c2ecf20Sopenharmony_ci return IRQ_NONE; /* not initialised */ 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci stat = Read_hfc(hc, HFCPCI_STATUS); 11548c2ecf20Sopenharmony_ci if (HFCPCI_ANYINT & stat) { 11558c2ecf20Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S1); 11568c2ecf20Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 11578c2ecf20Sopenharmony_ci printk(KERN_DEBUG 11588c2ecf20Sopenharmony_ci "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val); 11598c2ecf20Sopenharmony_ci } else { 11608c2ecf20Sopenharmony_ci /* shared */ 11618c2ecf20Sopenharmony_ci spin_unlock(&hc->lock); 11628c2ecf20Sopenharmony_ci return IRQ_NONE; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci hc->irqcnt++; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 11678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI irq %x\n", val); 11688c2ecf20Sopenharmony_ci val &= hc->hw.int_m1; 11698c2ecf20Sopenharmony_ci if (val & 0x40) { /* state machine irq */ 11708c2ecf20Sopenharmony_ci exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; 11718c2ecf20Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 11728c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ph_state chg %d->%d\n", 11738c2ecf20Sopenharmony_ci hc->dch.state, exval); 11748c2ecf20Sopenharmony_ci hc->dch.state = exval; 11758c2ecf20Sopenharmony_ci schedule_event(&hc->dch, FLG_PHCHANGE); 11768c2ecf20Sopenharmony_ci val &= ~0x40; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci if (val & 0x80) { /* timer irq */ 11798c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 11808c2ecf20Sopenharmony_ci if ((--hc->hw.nt_timer) < 0) 11818c2ecf20Sopenharmony_ci schedule_event(&hc->dch, FLG_PHCHANGE); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci val &= ~0x80; 11848c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci if (val & 0x08) { /* B1 rx */ 11878c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 11888c2ecf20Sopenharmony_ci if (bch) 11898c2ecf20Sopenharmony_ci main_rec_hfcpci(bch); 11908c2ecf20Sopenharmony_ci else if (hc->dch.debug) 11918c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci if (val & 0x10) { /* B2 rx */ 11948c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, 2); 11958c2ecf20Sopenharmony_ci if (bch) 11968c2ecf20Sopenharmony_ci main_rec_hfcpci(bch); 11978c2ecf20Sopenharmony_ci else if (hc->dch.debug) 11988c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci if (val & 0x01) { /* B1 tx */ 12018c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 12028c2ecf20Sopenharmony_ci if (bch) 12038c2ecf20Sopenharmony_ci tx_birq(bch); 12048c2ecf20Sopenharmony_ci else if (hc->dch.debug) 12058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci if (val & 0x02) { /* B2 tx */ 12088c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, 2); 12098c2ecf20Sopenharmony_ci if (bch) 12108c2ecf20Sopenharmony_ci tx_birq(bch); 12118c2ecf20Sopenharmony_ci else if (hc->dch.debug) 12128c2ecf20Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci if (val & 0x20) /* D rx */ 12158c2ecf20Sopenharmony_ci receive_dmsg(hc); 12168c2ecf20Sopenharmony_ci if (val & 0x04) { /* D tx */ 12178c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) 12188c2ecf20Sopenharmony_ci del_timer(&hc->dch.timer); 12198c2ecf20Sopenharmony_ci tx_dirq(&hc->dch); 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci spin_unlock(&hc->lock); 12228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci/* 12268c2ecf20Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_cistatic void 12298c2ecf20Sopenharmony_cihfcpci_dbusy_timer(struct timer_list *t) 12308c2ecf20Sopenharmony_ci{ 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci/* 12348c2ecf20Sopenharmony_ci * activate/deactivate hardware for selected channels and mode 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_cistatic int 12378c2ecf20Sopenharmony_cimode_hfcpci(struct bchannel *bch, int bc, int protocol) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 12408c2ecf20Sopenharmony_ci int fifo2; 12418c2ecf20Sopenharmony_ci u_char rx_slot = 0, tx_slot = 0, pcm_mode; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 12448c2ecf20Sopenharmony_ci printk(KERN_DEBUG 12458c2ecf20Sopenharmony_ci "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", 12468c2ecf20Sopenharmony_ci bch->state, protocol, bch->nr, bc); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci fifo2 = bc; 12498c2ecf20Sopenharmony_ci pcm_mode = (bc >> 24) & 0xff; 12508c2ecf20Sopenharmony_ci if (pcm_mode) { /* PCM SLOT USE */ 12518c2ecf20Sopenharmony_ci if (!test_bit(HFC_CFG_PCM, &hc->cfg)) 12528c2ecf20Sopenharmony_ci printk(KERN_WARNING 12538c2ecf20Sopenharmony_ci "%s: pcm channel id without HFC_CFG_PCM\n", 12548c2ecf20Sopenharmony_ci __func__); 12558c2ecf20Sopenharmony_ci rx_slot = (bc >> 8) & 0xff; 12568c2ecf20Sopenharmony_ci tx_slot = (bc >> 16) & 0xff; 12578c2ecf20Sopenharmony_ci bc = bc & 0xff; 12588c2ecf20Sopenharmony_ci } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) 12598c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", 12608c2ecf20Sopenharmony_ci __func__); 12618c2ecf20Sopenharmony_ci if (hc->chanlimit > 1) { 12628c2ecf20Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 12638c2ecf20Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 12648c2ecf20Sopenharmony_ci } else { 12658c2ecf20Sopenharmony_ci if (bc & 2) { 12668c2ecf20Sopenharmony_ci if (protocol != ISDN_P_NONE) { 12678c2ecf20Sopenharmony_ci hc->hw.bswapped = 1; /* B1 and B2 exchanged */ 12688c2ecf20Sopenharmony_ci hc->hw.sctrl_e |= 0x80; 12698c2ecf20Sopenharmony_ci } else { 12708c2ecf20Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 12718c2ecf20Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci fifo2 = 1; 12748c2ecf20Sopenharmony_ci } else { 12758c2ecf20Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 12768c2ecf20Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci switch (protocol) { 12808c2ecf20Sopenharmony_ci case (-1): /* used for init */ 12818c2ecf20Sopenharmony_ci bch->state = -1; 12828c2ecf20Sopenharmony_ci bch->nr = bc; 12838c2ecf20Sopenharmony_ci fallthrough; 12848c2ecf20Sopenharmony_ci case (ISDN_P_NONE): 12858c2ecf20Sopenharmony_ci if (bch->state == ISDN_P_NONE) 12868c2ecf20Sopenharmony_ci return 0; 12878c2ecf20Sopenharmony_ci if (bc & 2) { 12888c2ecf20Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_B2_ENA; 12898c2ecf20Sopenharmony_ci hc->hw.sctrl_r &= ~SCTRL_B2_ENA; 12908c2ecf20Sopenharmony_ci } else { 12918c2ecf20Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_B1_ENA; 12928c2ecf20Sopenharmony_ci hc->hw.sctrl_r &= ~SCTRL_B1_ENA; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci if (fifo2 & 2) { 12958c2ecf20Sopenharmony_ci hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; 12968c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS | 12978c2ecf20Sopenharmony_ci HFCPCI_INTS_B2REC); 12988c2ecf20Sopenharmony_ci } else { 12998c2ecf20Sopenharmony_ci hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; 13008c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS | 13018c2ecf20Sopenharmony_ci HFCPCI_INTS_B1REC); 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 13048c2ecf20Sopenharmony_ci if (bch->nr & 2) 13058c2ecf20Sopenharmony_ci hc->hw.cirm &= 0x7f; 13068c2ecf20Sopenharmony_ci else 13078c2ecf20Sopenharmony_ci hc->hw.cirm &= 0xbf; 13088c2ecf20Sopenharmony_ci#endif 13098c2ecf20Sopenharmony_ci bch->state = ISDN_P_NONE; 13108c2ecf20Sopenharmony_ci bch->nr = bc; 13118c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &bch->Flags); 13128c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci case (ISDN_P_B_RAW): 13158c2ecf20Sopenharmony_ci bch->state = protocol; 13168c2ecf20Sopenharmony_ci bch->nr = bc; 13178c2ecf20Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); 13188c2ecf20Sopenharmony_ci hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); 13198c2ecf20Sopenharmony_ci if (bc & 2) { 13208c2ecf20Sopenharmony_ci hc->hw.sctrl |= SCTRL_B2_ENA; 13218c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 13228c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 13238c2ecf20Sopenharmony_ci hc->hw.cirm |= 0x80; 13248c2ecf20Sopenharmony_ci#endif 13258c2ecf20Sopenharmony_ci } else { 13268c2ecf20Sopenharmony_ci hc->hw.sctrl |= SCTRL_B1_ENA; 13278c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 13288c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 13298c2ecf20Sopenharmony_ci hc->hw.cirm |= 0x40; 13308c2ecf20Sopenharmony_ci#endif 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci if (fifo2 & 2) { 13338c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; 13348c2ecf20Sopenharmony_ci if (!tics) 13358c2ecf20Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | 13368c2ecf20Sopenharmony_ci HFCPCI_INTS_B2REC); 13378c2ecf20Sopenharmony_ci hc->hw.ctmt |= 2; 13388c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x18; 13398c2ecf20Sopenharmony_ci } else { 13408c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; 13418c2ecf20Sopenharmony_ci if (!tics) 13428c2ecf20Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | 13438c2ecf20Sopenharmony_ci HFCPCI_INTS_B1REC); 13448c2ecf20Sopenharmony_ci hc->hw.ctmt |= 1; 13458c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x03; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); 13488c2ecf20Sopenharmony_ci break; 13498c2ecf20Sopenharmony_ci case (ISDN_P_B_HDLC): 13508c2ecf20Sopenharmony_ci bch->state = protocol; 13518c2ecf20Sopenharmony_ci bch->nr = bc; 13528c2ecf20Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); 13538c2ecf20Sopenharmony_ci hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); 13548c2ecf20Sopenharmony_ci if (bc & 2) { 13558c2ecf20Sopenharmony_ci hc->hw.sctrl |= SCTRL_B2_ENA; 13568c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 13578c2ecf20Sopenharmony_ci } else { 13588c2ecf20Sopenharmony_ci hc->hw.sctrl |= SCTRL_B1_ENA; 13598c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci if (fifo2 & 2) { 13628c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[1] = 0; 13638c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; 13648c2ecf20Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | 13658c2ecf20Sopenharmony_ci HFCPCI_INTS_B2REC); 13668c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~2; 13678c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x18; 13688c2ecf20Sopenharmony_ci } else { 13698c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[0] = 0; 13708c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; 13718c2ecf20Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | 13728c2ecf20Sopenharmony_ci HFCPCI_INTS_B1REC); 13738c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~1; 13748c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x03; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &bch->Flags); 13778c2ecf20Sopenharmony_ci break; 13788c2ecf20Sopenharmony_ci default: 13798c2ecf20Sopenharmony_ci printk(KERN_DEBUG "prot not known %x\n", protocol); 13808c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_PCM, &hc->cfg)) { 13838c2ecf20Sopenharmony_ci if ((protocol == ISDN_P_NONE) || 13848c2ecf20Sopenharmony_ci (protocol == -1)) { /* init case */ 13858c2ecf20Sopenharmony_ci rx_slot = 0; 13868c2ecf20Sopenharmony_ci tx_slot = 0; 13878c2ecf20Sopenharmony_ci } else { 13888c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { 13898c2ecf20Sopenharmony_ci rx_slot |= 0xC0; 13908c2ecf20Sopenharmony_ci tx_slot |= 0xC0; 13918c2ecf20Sopenharmony_ci } else { 13928c2ecf20Sopenharmony_ci rx_slot |= 0x80; 13938c2ecf20Sopenharmony_ci tx_slot |= 0x80; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci if (bc & 2) { 13978c2ecf20Sopenharmony_ci hc->hw.conn &= 0xc7; 13988c2ecf20Sopenharmony_ci hc->hw.conn |= 0x08; 13998c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", 14008c2ecf20Sopenharmony_ci __func__, tx_slot); 14018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", 14028c2ecf20Sopenharmony_ci __func__, rx_slot); 14038c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); 14048c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); 14058c2ecf20Sopenharmony_ci } else { 14068c2ecf20Sopenharmony_ci hc->hw.conn &= 0xf8; 14078c2ecf20Sopenharmony_ci hc->hw.conn |= 0x01; 14088c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", 14098c2ecf20Sopenharmony_ci __func__, tx_slot); 14108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", 14118c2ecf20Sopenharmony_ci __func__, rx_slot); 14128c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); 14138c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); 14178c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 14188c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 14198c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); 14208c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 14218c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 14228c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 14238c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 14248c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 14258c2ecf20Sopenharmony_ci#endif 14268c2ecf20Sopenharmony_ci return 0; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic int 14308c2ecf20Sopenharmony_ciset_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 14358c2ecf20Sopenharmony_ci printk(KERN_DEBUG 14368c2ecf20Sopenharmony_ci "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", 14378c2ecf20Sopenharmony_ci bch->state, protocol, bch->nr, chan); 14388c2ecf20Sopenharmony_ci if (bch->nr != chan) { 14398c2ecf20Sopenharmony_ci printk(KERN_DEBUG 14408c2ecf20Sopenharmony_ci "HFCPCI rxtest wrong channel parameter %x/%x\n", 14418c2ecf20Sopenharmony_ci bch->nr, chan); 14428c2ecf20Sopenharmony_ci return -EINVAL; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci switch (protocol) { 14458c2ecf20Sopenharmony_ci case (ISDN_P_B_RAW): 14468c2ecf20Sopenharmony_ci bch->state = protocol; 14478c2ecf20Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); 14488c2ecf20Sopenharmony_ci if (chan & 2) { 14498c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 14508c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; 14518c2ecf20Sopenharmony_ci if (!tics) 14528c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B2REC; 14538c2ecf20Sopenharmony_ci hc->hw.ctmt |= 2; 14548c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x18; 14558c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 14568c2ecf20Sopenharmony_ci hc->hw.cirm |= 0x80; 14578c2ecf20Sopenharmony_ci#endif 14588c2ecf20Sopenharmony_ci } else { 14598c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 14608c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; 14618c2ecf20Sopenharmony_ci if (!tics) 14628c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B1REC; 14638c2ecf20Sopenharmony_ci hc->hw.ctmt |= 1; 14648c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x03; 14658c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 14668c2ecf20Sopenharmony_ci hc->hw.cirm |= 0x40; 14678c2ecf20Sopenharmony_ci#endif 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci break; 14708c2ecf20Sopenharmony_ci case (ISDN_P_B_HDLC): 14718c2ecf20Sopenharmony_ci bch->state = protocol; 14728c2ecf20Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); 14738c2ecf20Sopenharmony_ci if (chan & 2) { 14748c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 14758c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[1] = 0; 14768c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; 14778c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B2REC; 14788c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~2; 14798c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x18; 14808c2ecf20Sopenharmony_ci } else { 14818c2ecf20Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 14828c2ecf20Sopenharmony_ci hc->hw.last_bfifo_cnt[0] = 0; 14838c2ecf20Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; 14848c2ecf20Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B1REC; 14858c2ecf20Sopenharmony_ci hc->hw.ctmt &= ~1; 14868c2ecf20Sopenharmony_ci hc->hw.conn &= ~0x03; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci break; 14898c2ecf20Sopenharmony_ci default: 14908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "prot not known %x\n", protocol); 14918c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 14948c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 14958c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 14968c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 14978c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 14988c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER 14998c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 15008c2ecf20Sopenharmony_ci#endif 15018c2ecf20Sopenharmony_ci return 0; 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic void 15058c2ecf20Sopenharmony_cideactivate_bchannel(struct bchannel *bch) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 15088c2ecf20Sopenharmony_ci u_long flags; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15118c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 15128c2ecf20Sopenharmony_ci mode_hfcpci(bch, bch->nr, ISDN_P_NONE); 15138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci/* 15178c2ecf20Sopenharmony_ci * Layer 1 B-channel hardware access 15188c2ecf20Sopenharmony_ci */ 15198c2ecf20Sopenharmony_cistatic int 15208c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_cistatic int 15258c2ecf20Sopenharmony_cihfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 15288c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 15298c2ecf20Sopenharmony_ci int ret = -EINVAL; 15308c2ecf20Sopenharmony_ci u_long flags; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW) 15338c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); 15348c2ecf20Sopenharmony_ci switch (cmd) { 15358c2ecf20Sopenharmony_ci case HW_TESTRX_RAW: 15368c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15378c2ecf20Sopenharmony_ci ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); 15388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15398c2ecf20Sopenharmony_ci break; 15408c2ecf20Sopenharmony_ci case HW_TESTRX_HDLC: 15418c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15428c2ecf20Sopenharmony_ci ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); 15438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15448c2ecf20Sopenharmony_ci break; 15458c2ecf20Sopenharmony_ci case HW_TESTRX_OFF: 15468c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15478c2ecf20Sopenharmony_ci mode_hfcpci(bch, bch->nr, ISDN_P_NONE); 15488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15498c2ecf20Sopenharmony_ci ret = 0; 15508c2ecf20Sopenharmony_ci break; 15518c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 15528c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 15538c2ecf20Sopenharmony_ci deactivate_bchannel(bch); 15548c2ecf20Sopenharmony_ci ch->protocol = ISDN_P_NONE; 15558c2ecf20Sopenharmony_ci ch->peer = NULL; 15568c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 15578c2ecf20Sopenharmony_ci ret = 0; 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 15608c2ecf20Sopenharmony_ci ret = channel_bctrl(bch, arg); 15618c2ecf20Sopenharmony_ci break; 15628c2ecf20Sopenharmony_ci default: 15638c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unknown prim(%x)\n", 15648c2ecf20Sopenharmony_ci __func__, cmd); 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci return ret; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci/* 15708c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Dchannel data 15718c2ecf20Sopenharmony_ci */ 15728c2ecf20Sopenharmony_cistatic int 15738c2ecf20Sopenharmony_cihfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 15768c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 15778c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 15788c2ecf20Sopenharmony_ci int ret = -EINVAL; 15798c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 15808c2ecf20Sopenharmony_ci unsigned int id; 15818c2ecf20Sopenharmony_ci u_long flags; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci switch (hh->prim) { 15848c2ecf20Sopenharmony_ci case PH_DATA_REQ: 15858c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15868c2ecf20Sopenharmony_ci ret = dchannel_senddata(dch, skb); 15878c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 15888c2ecf20Sopenharmony_ci id = hh->id; /* skb can be freed */ 15898c2ecf20Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 15908c2ecf20Sopenharmony_ci ret = 0; 15918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15928c2ecf20Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 15938c2ecf20Sopenharmony_ci } else 15948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15958c2ecf20Sopenharmony_ci return ret; 15968c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 15978c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 15988c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 15998c2ecf20Sopenharmony_ci ret = 0; 16008c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 16018c2ecf20Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 16028c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 16038c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &dch->Flags)) { 16048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16058c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 16068c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 16078c2ecf20Sopenharmony_ci break; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); 16108c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | 16118c2ecf20Sopenharmony_ci HFCPCI_DO_ACTION | 1); 16128c2ecf20Sopenharmony_ci } else 16138c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 16148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16158c2ecf20Sopenharmony_ci break; 16168c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 16178c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 16188c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 16198c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 16208c2ecf20Sopenharmony_ci struct sk_buff_head free_queue; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci __skb_queue_head_init(&free_queue); 16238c2ecf20Sopenharmony_ci /* prepare deactivation */ 16248c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 0x40); 16258c2ecf20Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 16268c2ecf20Sopenharmony_ci if (dch->tx_skb) { 16278c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 16288c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci dch->tx_idx = 0; 16318c2ecf20Sopenharmony_ci if (dch->rx_skb) { 16328c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 16338c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 16368c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 16378c2ecf20Sopenharmony_ci del_timer(&dch->timer); 16388c2ecf20Sopenharmony_ci#ifdef FIXME 16398c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 16408c2ecf20Sopenharmony_ci dchannel_sched_event(&hc->dch, D_CLEARBUSY); 16418c2ecf20Sopenharmony_ci#endif 16428c2ecf20Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 16438c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 16448c2ecf20Sopenharmony_ci ret = 0; 16458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16468c2ecf20Sopenharmony_ci __skb_queue_purge(&free_queue); 16478c2ecf20Sopenharmony_ci } else { 16488c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 16498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci break; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci if (!ret) 16548c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 16558c2ecf20Sopenharmony_ci return ret; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci/* 16598c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Bchannel data 16608c2ecf20Sopenharmony_ci */ 16618c2ecf20Sopenharmony_cistatic int 16628c2ecf20Sopenharmony_cihfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 16658c2ecf20Sopenharmony_ci struct hfc_pci *hc = bch->hw; 16668c2ecf20Sopenharmony_ci int ret = -EINVAL; 16678c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 16688c2ecf20Sopenharmony_ci unsigned long flags; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci switch (hh->prim) { 16718c2ecf20Sopenharmony_ci case PH_DATA_REQ: 16728c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 16738c2ecf20Sopenharmony_ci ret = bchannel_senddata(bch, skb); 16748c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 16758c2ecf20Sopenharmony_ci hfcpci_fill_fifo(bch); 16768c2ecf20Sopenharmony_ci ret = 0; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16798c2ecf20Sopenharmony_ci return ret; 16808c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 16818c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 16828c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 16838c2ecf20Sopenharmony_ci ret = mode_hfcpci(bch, bch->nr, ch->protocol); 16848c2ecf20Sopenharmony_ci else 16858c2ecf20Sopenharmony_ci ret = 0; 16868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 16878c2ecf20Sopenharmony_ci if (!ret) 16888c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 16898c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 16928c2ecf20Sopenharmony_ci deactivate_bchannel(bch); 16938c2ecf20Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 16948c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 16958c2ecf20Sopenharmony_ci ret = 0; 16968c2ecf20Sopenharmony_ci break; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci if (!ret) 16998c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 17008c2ecf20Sopenharmony_ci return ret; 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci/* 17048c2ecf20Sopenharmony_ci * called for card init message 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cistatic void 17088c2ecf20Sopenharmony_ciinithfcpci(struct hfc_pci *hc) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "inithfcpci: entered\n"); 17118c2ecf20Sopenharmony_ci timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0); 17128c2ecf20Sopenharmony_ci hc->chanlimit = 2; 17138c2ecf20Sopenharmony_ci mode_hfcpci(&hc->bch[0], 1, -1); 17148c2ecf20Sopenharmony_ci mode_hfcpci(&hc->bch[1], 2, -1); 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic int 17198c2ecf20Sopenharmony_ciinit_card(struct hfc_pci *hc) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci int cnt = 3; 17228c2ecf20Sopenharmony_ci u_long flags; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "init_card: entered\n"); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 17288c2ecf20Sopenharmony_ci disable_hwirq(hc); 17298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 17308c2ecf20Sopenharmony_ci if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { 17318c2ecf20Sopenharmony_ci printk(KERN_WARNING 17328c2ecf20Sopenharmony_ci "mISDN: couldn't get interrupt %d\n", hc->irq); 17338c2ecf20Sopenharmony_ci return -EIO; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 17368c2ecf20Sopenharmony_ci reset_hfcpci(hc); 17378c2ecf20Sopenharmony_ci while (cnt) { 17388c2ecf20Sopenharmony_ci inithfcpci(hc); 17398c2ecf20Sopenharmony_ci /* 17408c2ecf20Sopenharmony_ci * Finally enable IRQ output 17418c2ecf20Sopenharmony_ci * this is only allowed, if an IRQ routine is already 17428c2ecf20Sopenharmony_ci * established for this HFC, so don't do that earlier 17438c2ecf20Sopenharmony_ci */ 17448c2ecf20Sopenharmony_ci enable_hwirq(hc); 17458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 17468c2ecf20Sopenharmony_ci /* Timeout 80ms */ 17478c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 17488c2ecf20Sopenharmony_ci schedule_timeout((80 * HZ) / 1000); 17498c2ecf20Sopenharmony_ci printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", 17508c2ecf20Sopenharmony_ci hc->irq, hc->irqcnt); 17518c2ecf20Sopenharmony_ci /* now switch timer interrupt off */ 17528c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 17538c2ecf20Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 17548c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 17558c2ecf20Sopenharmony_ci /* reinit mode reg */ 17568c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 17578c2ecf20Sopenharmony_ci if (!hc->irqcnt) { 17588c2ecf20Sopenharmony_ci printk(KERN_WARNING 17598c2ecf20Sopenharmony_ci "HFC PCI: IRQ(%d) getting no interrupts " 17608c2ecf20Sopenharmony_ci "during init %d\n", hc->irq, 4 - cnt); 17618c2ecf20Sopenharmony_ci if (cnt == 1) 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci else { 17648c2ecf20Sopenharmony_ci reset_hfcpci(hc); 17658c2ecf20Sopenharmony_ci cnt--; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci } else { 17688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 17698c2ecf20Sopenharmony_ci hc->initdone = 1; 17708c2ecf20Sopenharmony_ci return 0; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci disable_hwirq(hc); 17748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 17758c2ecf20Sopenharmony_ci free_irq(hc->irq, hc); 17768c2ecf20Sopenharmony_ci return -EIO; 17778c2ecf20Sopenharmony_ci} 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_cistatic int 17808c2ecf20Sopenharmony_cichannel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci int ret = 0; 17838c2ecf20Sopenharmony_ci u_char slot; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci switch (cq->op) { 17868c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 17878c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | 17888c2ecf20Sopenharmony_ci MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3; 17898c2ecf20Sopenharmony_ci break; 17908c2ecf20Sopenharmony_ci case MISDN_CTRL_LOOP: 17918c2ecf20Sopenharmony_ci /* channel 0 disabled loop */ 17928c2ecf20Sopenharmony_ci if (cq->channel < 0 || cq->channel > 2) { 17938c2ecf20Sopenharmony_ci ret = -EINVAL; 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci if (cq->channel & 1) { 17978c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 17988c2ecf20Sopenharmony_ci slot = 0xC0; 17998c2ecf20Sopenharmony_ci else 18008c2ecf20Sopenharmony_ci slot = 0x80; 18018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", 18028c2ecf20Sopenharmony_ci __func__, slot); 18038c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, slot); 18048c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, slot); 18058c2ecf20Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~7) | 6; 18068c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci if (cq->channel & 2) { 18098c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 18108c2ecf20Sopenharmony_ci slot = 0xC1; 18118c2ecf20Sopenharmony_ci else 18128c2ecf20Sopenharmony_ci slot = 0x81; 18138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", 18148c2ecf20Sopenharmony_ci __func__, slot); 18158c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, slot); 18168c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, slot); 18178c2ecf20Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; 18188c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci if (cq->channel & 3) 18218c2ecf20Sopenharmony_ci hc->hw.trm |= 0x80; /* enable IOM-loop */ 18228c2ecf20Sopenharmony_ci else { 18238c2ecf20Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; 18248c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 18258c2ecf20Sopenharmony_ci hc->hw.trm &= 0x7f; /* disable IOM-loop */ 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci case MISDN_CTRL_CONNECT: 18308c2ecf20Sopenharmony_ci if (cq->channel == cq->p1) { 18318c2ecf20Sopenharmony_ci ret = -EINVAL; 18328c2ecf20Sopenharmony_ci break; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci if (cq->channel < 1 || cq->channel > 2 || 18358c2ecf20Sopenharmony_ci cq->p1 < 1 || cq->p1 > 2) { 18368c2ecf20Sopenharmony_ci ret = -EINVAL; 18378c2ecf20Sopenharmony_ci break; 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 18408c2ecf20Sopenharmony_ci slot = 0xC0; 18418c2ecf20Sopenharmony_ci else 18428c2ecf20Sopenharmony_ci slot = 0x80; 18438c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", 18448c2ecf20Sopenharmony_ci __func__, slot); 18458c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, slot); 18468c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, slot); 18478c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 18488c2ecf20Sopenharmony_ci slot = 0xC1; 18498c2ecf20Sopenharmony_ci else 18508c2ecf20Sopenharmony_ci slot = 0x81; 18518c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", 18528c2ecf20Sopenharmony_ci __func__, slot); 18538c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, slot); 18548c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, slot); 18558c2ecf20Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; 18568c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 18578c2ecf20Sopenharmony_ci hc->hw.trm |= 0x80; 18588c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci case MISDN_CTRL_DISCONNECT: 18618c2ecf20Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; 18628c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 18638c2ecf20Sopenharmony_ci hc->hw.trm &= 0x7f; /* disable IOM-loop */ 18648c2ecf20Sopenharmony_ci break; 18658c2ecf20Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 18668c2ecf20Sopenharmony_ci ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); 18678c2ecf20Sopenharmony_ci break; 18688c2ecf20Sopenharmony_ci default: 18698c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unknown Op %x\n", 18708c2ecf20Sopenharmony_ci __func__, cq->op); 18718c2ecf20Sopenharmony_ci ret = -EINVAL; 18728c2ecf20Sopenharmony_ci break; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci return ret; 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic int 18788c2ecf20Sopenharmony_ciopen_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, 18798c2ecf20Sopenharmony_ci struct channel_req *rq) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci int err = 0; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 18848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, 18858c2ecf20Sopenharmony_ci hc->dch.dev.id, __builtin_return_address(0)); 18868c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 18878c2ecf20Sopenharmony_ci return -EINVAL; 18888c2ecf20Sopenharmony_ci if (rq->adr.channel == 1) { 18898c2ecf20Sopenharmony_ci /* TODO: E-Channel */ 18908c2ecf20Sopenharmony_ci return -EINVAL; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci if (!hc->initdone) { 18938c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 18948c2ecf20Sopenharmony_ci err = create_l1(&hc->dch, hfc_l1callback); 18958c2ecf20Sopenharmony_ci if (err) 18968c2ecf20Sopenharmony_ci return err; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci hc->hw.protocol = rq->protocol; 18998c2ecf20Sopenharmony_ci ch->protocol = rq->protocol; 19008c2ecf20Sopenharmony_ci err = init_card(hc); 19018c2ecf20Sopenharmony_ci if (err) 19028c2ecf20Sopenharmony_ci return err; 19038c2ecf20Sopenharmony_ci } else { 19048c2ecf20Sopenharmony_ci if (rq->protocol != ch->protocol) { 19058c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_TE_S0) 19068c2ecf20Sopenharmony_ci l1_event(hc->dch.l1, CLOSE_CHANNEL); 19078c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 19088c2ecf20Sopenharmony_ci err = create_l1(&hc->dch, hfc_l1callback); 19098c2ecf20Sopenharmony_ci if (err) 19108c2ecf20Sopenharmony_ci return err; 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci hc->hw.protocol = rq->protocol; 19138c2ecf20Sopenharmony_ci ch->protocol = rq->protocol; 19148c2ecf20Sopenharmony_ci hfcpci_setmode(hc); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || 19198c2ecf20Sopenharmony_ci ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { 19208c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 19218c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci rq->ch = ch; 19248c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 19258c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 19268c2ecf20Sopenharmony_ci return 0; 19278c2ecf20Sopenharmony_ci} 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_cistatic int 19308c2ecf20Sopenharmony_ciopen_bchannel(struct hfc_pci *hc, struct channel_req *rq) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci struct bchannel *bch; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 19358c2ecf20Sopenharmony_ci return -EINVAL; 19368c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 19378c2ecf20Sopenharmony_ci return -EINVAL; 19388c2ecf20Sopenharmony_ci bch = &hc->bch[rq->adr.channel - 1]; 19398c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 19408c2ecf20Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 19418c2ecf20Sopenharmony_ci bch->ch.protocol = rq->protocol; 19428c2ecf20Sopenharmony_ci rq->ch = &bch->ch; /* TODO: E-channel */ 19438c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 19448c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 19458c2ecf20Sopenharmony_ci return 0; 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci/* 19498c2ecf20Sopenharmony_ci * device control function 19508c2ecf20Sopenharmony_ci */ 19518c2ecf20Sopenharmony_cistatic int 19528c2ecf20Sopenharmony_cihfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 19558c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 19568c2ecf20Sopenharmony_ci struct hfc_pci *hc = dch->hw; 19578c2ecf20Sopenharmony_ci struct channel_req *rq; 19588c2ecf20Sopenharmony_ci int err = 0; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 19618c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 19628c2ecf20Sopenharmony_ci __func__, cmd, arg); 19638c2ecf20Sopenharmony_ci switch (cmd) { 19648c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 19658c2ecf20Sopenharmony_ci rq = arg; 19668c2ecf20Sopenharmony_ci if ((rq->protocol == ISDN_P_TE_S0) || 19678c2ecf20Sopenharmony_ci (rq->protocol == ISDN_P_NT_S0)) 19688c2ecf20Sopenharmony_ci err = open_dchannel(hc, ch, rq); 19698c2ecf20Sopenharmony_ci else 19708c2ecf20Sopenharmony_ci err = open_bchannel(hc, rq); 19718c2ecf20Sopenharmony_ci break; 19728c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 19738c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 19748c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) close from %p\n", 19758c2ecf20Sopenharmony_ci __func__, hc->dch.dev.id, 19768c2ecf20Sopenharmony_ci __builtin_return_address(0)); 19778c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 19788c2ecf20Sopenharmony_ci break; 19798c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 19808c2ecf20Sopenharmony_ci err = channel_ctrl(hc, arg); 19818c2ecf20Sopenharmony_ci break; 19828c2ecf20Sopenharmony_ci default: 19838c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 19848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 19858c2ecf20Sopenharmony_ci __func__, cmd); 19868c2ecf20Sopenharmony_ci return -EINVAL; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci return err; 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_cistatic int 19928c2ecf20Sopenharmony_cisetup_hw(struct hfc_pci *hc) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci void *buffer; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); 19978c2ecf20Sopenharmony_ci hc->hw.cirm = 0; 19988c2ecf20Sopenharmony_ci hc->dch.state = 0; 19998c2ecf20Sopenharmony_ci pci_set_master(hc->pdev); 20008c2ecf20Sopenharmony_ci if (!hc->irq) { 20018c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); 20028c2ecf20Sopenharmony_ci return -EINVAL; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci hc->hw.pci_io = 20058c2ecf20Sopenharmony_ci (char __iomem *)(unsigned long)hc->pdev->resource[1].start; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (!hc->hw.pci_io) { 20088c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); 20098c2ecf20Sopenharmony_ci return -ENOMEM; 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci /* Allocate memory for FIFOS */ 20128c2ecf20Sopenharmony_ci /* the memory needs to be on a 32k boundary within the first 4G */ 20138c2ecf20Sopenharmony_ci if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) { 20148c2ecf20Sopenharmony_ci printk(KERN_WARNING 20158c2ecf20Sopenharmony_ci "HFC-PCI: No usable DMA configuration!\n"); 20168c2ecf20Sopenharmony_ci return -EIO; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle, 20198c2ecf20Sopenharmony_ci GFP_KERNEL); 20208c2ecf20Sopenharmony_ci /* We silently assume the address is okay if nonzero */ 20218c2ecf20Sopenharmony_ci if (!buffer) { 20228c2ecf20Sopenharmony_ci printk(KERN_WARNING 20238c2ecf20Sopenharmony_ci "HFC-PCI: Error allocating memory for FIFO!\n"); 20248c2ecf20Sopenharmony_ci return -ENOMEM; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci hc->hw.fifos = buffer; 20278c2ecf20Sopenharmony_ci pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); 20288c2ecf20Sopenharmony_ci hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); 20298c2ecf20Sopenharmony_ci if (unlikely(!hc->hw.pci_io)) { 20308c2ecf20Sopenharmony_ci printk(KERN_WARNING 20318c2ecf20Sopenharmony_ci "HFC-PCI: Error in ioremap for PCI!\n"); 20328c2ecf20Sopenharmony_ci dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, 20338c2ecf20Sopenharmony_ci hc->hw.dmahandle); 20348c2ecf20Sopenharmony_ci return -ENOMEM; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci printk(KERN_INFO 20388c2ecf20Sopenharmony_ci "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n", 20398c2ecf20Sopenharmony_ci (u_long) hc->hw.pci_io, hc->hw.fifos, 20408c2ecf20Sopenharmony_ci &hc->hw.dmahandle, hc->irq, HZ); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* enable memory mapped ports, disable busmaster */ 20438c2ecf20Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); 20448c2ecf20Sopenharmony_ci hc->hw.int_m2 = 0; 20458c2ecf20Sopenharmony_ci disable_hwirq(hc); 20468c2ecf20Sopenharmony_ci hc->hw.int_m1 = 0; 20478c2ecf20Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 20488c2ecf20Sopenharmony_ci /* At this point the needed PCI config is done */ 20498c2ecf20Sopenharmony_ci /* fifos are still not enabled */ 20508c2ecf20Sopenharmony_ci timer_setup(&hc->hw.timer, hfcpci_Timer, 0); 20518c2ecf20Sopenharmony_ci /* default PCM master */ 20528c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); 20538c2ecf20Sopenharmony_ci return 0; 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic void 20578c2ecf20Sopenharmony_cirelease_card(struct hfc_pci *hc) { 20588c2ecf20Sopenharmony_ci u_long flags; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 20618c2ecf20Sopenharmony_ci hc->hw.int_m2 = 0; /* interrupt output off ! */ 20628c2ecf20Sopenharmony_ci disable_hwirq(hc); 20638c2ecf20Sopenharmony_ci mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); 20648c2ecf20Sopenharmony_ci mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); 20658c2ecf20Sopenharmony_ci if (hc->dch.timer.function != NULL) { 20668c2ecf20Sopenharmony_ci del_timer(&hc->dch.timer); 20678c2ecf20Sopenharmony_ci hc->dch.timer.function = NULL; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 20708c2ecf20Sopenharmony_ci if (hc->hw.protocol == ISDN_P_TE_S0) 20718c2ecf20Sopenharmony_ci l1_event(hc->dch.l1, CLOSE_CHANNEL); 20728c2ecf20Sopenharmony_ci if (hc->initdone) 20738c2ecf20Sopenharmony_ci free_irq(hc->irq, hc); 20748c2ecf20Sopenharmony_ci release_io_hfcpci(hc); /* must release after free_irq! */ 20758c2ecf20Sopenharmony_ci mISDN_unregister_device(&hc->dch.dev); 20768c2ecf20Sopenharmony_ci mISDN_freebchannel(&hc->bch[1]); 20778c2ecf20Sopenharmony_ci mISDN_freebchannel(&hc->bch[0]); 20788c2ecf20Sopenharmony_ci mISDN_freedchannel(&hc->dch); 20798c2ecf20Sopenharmony_ci pci_set_drvdata(hc->pdev, NULL); 20808c2ecf20Sopenharmony_ci kfree(hc); 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic int 20848c2ecf20Sopenharmony_cisetup_card(struct hfc_pci *card) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci int err = -EINVAL; 20878c2ecf20Sopenharmony_ci u_int i; 20888c2ecf20Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci card->dch.debug = debug; 20918c2ecf20Sopenharmony_ci spin_lock_init(&card->lock); 20928c2ecf20Sopenharmony_ci mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); 20938c2ecf20Sopenharmony_ci card->dch.hw = card; 20948c2ecf20Sopenharmony_ci card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); 20958c2ecf20Sopenharmony_ci card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 20968c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 20978c2ecf20Sopenharmony_ci card->dch.dev.D.send = hfcpci_l2l1D; 20988c2ecf20Sopenharmony_ci card->dch.dev.D.ctrl = hfc_dctrl; 20998c2ecf20Sopenharmony_ci card->dch.dev.nrbchan = 2; 21008c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 21018c2ecf20Sopenharmony_ci card->bch[i].nr = i + 1; 21028c2ecf20Sopenharmony_ci set_channelmap(i + 1, card->dch.dev.channelmap); 21038c2ecf20Sopenharmony_ci card->bch[i].debug = debug; 21048c2ecf20Sopenharmony_ci mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); 21058c2ecf20Sopenharmony_ci card->bch[i].hw = card; 21068c2ecf20Sopenharmony_ci card->bch[i].ch.send = hfcpci_l2l1B; 21078c2ecf20Sopenharmony_ci card->bch[i].ch.ctrl = hfc_bctrl; 21088c2ecf20Sopenharmony_ci card->bch[i].ch.nr = i + 1; 21098c2ecf20Sopenharmony_ci list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci err = setup_hw(card); 21128c2ecf20Sopenharmony_ci if (err) 21138c2ecf20Sopenharmony_ci goto error; 21148c2ecf20Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); 21158c2ecf20Sopenharmony_ci err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); 21168c2ecf20Sopenharmony_ci if (err) 21178c2ecf20Sopenharmony_ci goto error; 21188c2ecf20Sopenharmony_ci HFC_cnt++; 21198c2ecf20Sopenharmony_ci printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); 21208c2ecf20Sopenharmony_ci return 0; 21218c2ecf20Sopenharmony_cierror: 21228c2ecf20Sopenharmony_ci mISDN_freebchannel(&card->bch[1]); 21238c2ecf20Sopenharmony_ci mISDN_freebchannel(&card->bch[0]); 21248c2ecf20Sopenharmony_ci mISDN_freedchannel(&card->dch); 21258c2ecf20Sopenharmony_ci kfree(card); 21268c2ecf20Sopenharmony_ci return err; 21278c2ecf20Sopenharmony_ci} 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci/* private data in the PCI devices list */ 21308c2ecf20Sopenharmony_cistruct _hfc_map { 21318c2ecf20Sopenharmony_ci u_int subtype; 21328c2ecf20Sopenharmony_ci u_int flag; 21338c2ecf20Sopenharmony_ci char *name; 21348c2ecf20Sopenharmony_ci}; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_cistatic const struct _hfc_map hfc_map[] = 21378c2ecf20Sopenharmony_ci{ 21388c2ecf20Sopenharmony_ci {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, 21398c2ecf20Sopenharmony_ci {HFC_CCD_B000, 0, "Billion B000"}, 21408c2ecf20Sopenharmony_ci {HFC_CCD_B006, 0, "Billion B006"}, 21418c2ecf20Sopenharmony_ci {HFC_CCD_B007, 0, "Billion B007"}, 21428c2ecf20Sopenharmony_ci {HFC_CCD_B008, 0, "Billion B008"}, 21438c2ecf20Sopenharmony_ci {HFC_CCD_B009, 0, "Billion B009"}, 21448c2ecf20Sopenharmony_ci {HFC_CCD_B00A, 0, "Billion B00A"}, 21458c2ecf20Sopenharmony_ci {HFC_CCD_B00B, 0, "Billion B00B"}, 21468c2ecf20Sopenharmony_ci {HFC_CCD_B00C, 0, "Billion B00C"}, 21478c2ecf20Sopenharmony_ci {HFC_CCD_B100, 0, "Seyeon B100"}, 21488c2ecf20Sopenharmony_ci {HFC_CCD_B700, 0, "Primux II S0 B700"}, 21498c2ecf20Sopenharmony_ci {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, 21508c2ecf20Sopenharmony_ci {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, 21518c2ecf20Sopenharmony_ci {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, 21528c2ecf20Sopenharmony_ci {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, 21538c2ecf20Sopenharmony_ci {HFC_BERKOM_A1T, 0, "German telekom A1T"}, 21548c2ecf20Sopenharmony_ci {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, 21558c2ecf20Sopenharmony_ci {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, 21568c2ecf20Sopenharmony_ci {HFC_DIGI_DF_M_IOM2_E, 0, 21578c2ecf20Sopenharmony_ci "Digi International DataFire Micro V IOM2 (Europe)"}, 21588c2ecf20Sopenharmony_ci {HFC_DIGI_DF_M_E, 0, 21598c2ecf20Sopenharmony_ci "Digi International DataFire Micro V (Europe)"}, 21608c2ecf20Sopenharmony_ci {HFC_DIGI_DF_M_IOM2_A, 0, 21618c2ecf20Sopenharmony_ci "Digi International DataFire Micro V IOM2 (North America)"}, 21628c2ecf20Sopenharmony_ci {HFC_DIGI_DF_M_A, 0, 21638c2ecf20Sopenharmony_ci "Digi International DataFire Micro V (North America)"}, 21648c2ecf20Sopenharmony_ci {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, 21658c2ecf20Sopenharmony_ci {}, 21668c2ecf20Sopenharmony_ci}; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic const struct pci_device_id hfc_ids[] = 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0), 21718c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[0] }, 21728c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000), 21738c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[1] }, 21748c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006), 21758c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[2] }, 21768c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007), 21778c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[3] }, 21788c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008), 21798c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[4] }, 21808c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009), 21818c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[5] }, 21828c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A), 21838c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[6] }, 21848c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B), 21858c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[7] }, 21868c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C), 21878c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[8] }, 21888c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100), 21898c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[9] }, 21908c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700), 21918c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[10] }, 21928c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701), 21938c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[11] }, 21948c2ecf20Sopenharmony_ci { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1), 21958c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[12] }, 21968c2ecf20Sopenharmony_ci { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675), 21978c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[13] }, 21988c2ecf20Sopenharmony_ci { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT), 21998c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[14] }, 22008c2ecf20Sopenharmony_ci { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T), 22018c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[15] }, 22028c2ecf20Sopenharmony_ci { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575), 22038c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[16] }, 22048c2ecf20Sopenharmony_ci { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0), 22058c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[17] }, 22068c2ecf20Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E), 22078c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[18] }, 22088c2ecf20Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E), 22098c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[19] }, 22108c2ecf20Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A), 22118c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[20] }, 22128c2ecf20Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A), 22138c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[21] }, 22148c2ecf20Sopenharmony_ci { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2), 22158c2ecf20Sopenharmony_ci (unsigned long) &hfc_map[22] }, 22168c2ecf20Sopenharmony_ci {}, 22178c2ecf20Sopenharmony_ci}; 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_cistatic int 22208c2ecf20Sopenharmony_cihfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci int err = -ENOMEM; 22238c2ecf20Sopenharmony_ci struct hfc_pci *card; 22248c2ecf20Sopenharmony_ci struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci card = kzalloc(sizeof(struct hfc_pci), GFP_KERNEL); 22278c2ecf20Sopenharmony_ci if (!card) { 22288c2ecf20Sopenharmony_ci printk(KERN_ERR "No kmem for HFC card\n"); 22298c2ecf20Sopenharmony_ci return err; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci card->pdev = pdev; 22328c2ecf20Sopenharmony_ci card->subtype = m->subtype; 22338c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 22348c2ecf20Sopenharmony_ci if (err) { 22358c2ecf20Sopenharmony_ci kfree(card); 22368c2ecf20Sopenharmony_ci return err; 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", 22408c2ecf20Sopenharmony_ci m->name, pci_name(pdev)); 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci card->irq = pdev->irq; 22438c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, card); 22448c2ecf20Sopenharmony_ci err = setup_card(card); 22458c2ecf20Sopenharmony_ci if (err) 22468c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 22478c2ecf20Sopenharmony_ci return err; 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_cistatic void 22518c2ecf20Sopenharmony_cihfc_remove_pci(struct pci_dev *pdev) 22528c2ecf20Sopenharmony_ci{ 22538c2ecf20Sopenharmony_ci struct hfc_pci *card = pci_get_drvdata(pdev); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (card) 22568c2ecf20Sopenharmony_ci release_card(card); 22578c2ecf20Sopenharmony_ci else 22588c2ecf20Sopenharmony_ci if (debug) 22598c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: drvdata already removed\n", 22608c2ecf20Sopenharmony_ci __func__); 22618c2ecf20Sopenharmony_ci} 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_cistatic struct pci_driver hfc_driver = { 22658c2ecf20Sopenharmony_ci .name = "hfcpci", 22668c2ecf20Sopenharmony_ci .probe = hfc_probe, 22678c2ecf20Sopenharmony_ci .remove = hfc_remove_pci, 22688c2ecf20Sopenharmony_ci .id_table = hfc_ids, 22698c2ecf20Sopenharmony_ci}; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_cistatic int 22728c2ecf20Sopenharmony_ci_hfcpci_softirq(struct device *dev, void *unused) 22738c2ecf20Sopenharmony_ci{ 22748c2ecf20Sopenharmony_ci struct hfc_pci *hc = dev_get_drvdata(dev); 22758c2ecf20Sopenharmony_ci struct bchannel *bch; 22768c2ecf20Sopenharmony_ci if (hc == NULL) 22778c2ecf20Sopenharmony_ci return 0; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { 22808c2ecf20Sopenharmony_ci spin_lock_irq(&hc->lock); 22818c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 22828c2ecf20Sopenharmony_ci if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ 22838c2ecf20Sopenharmony_ci main_rec_hfcpci(bch); 22848c2ecf20Sopenharmony_ci tx_birq(bch); 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); 22878c2ecf20Sopenharmony_ci if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ 22888c2ecf20Sopenharmony_ci main_rec_hfcpci(bch); 22898c2ecf20Sopenharmony_ci tx_birq(bch); 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci spin_unlock_irq(&hc->lock); 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci return 0; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic void 22978c2ecf20Sopenharmony_cihfcpci_softirq(struct timer_list *unused) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL, 23008c2ecf20Sopenharmony_ci _hfcpci_softirq) != 0); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* if next event would be in the past ... */ 23038c2ecf20Sopenharmony_ci if ((s32)(hfc_jiffies + tics - jiffies) <= 0) 23048c2ecf20Sopenharmony_ci hfc_jiffies = jiffies + 1; 23058c2ecf20Sopenharmony_ci else 23068c2ecf20Sopenharmony_ci hfc_jiffies += tics; 23078c2ecf20Sopenharmony_ci hfc_tl.expires = hfc_jiffies; 23088c2ecf20Sopenharmony_ci add_timer(&hfc_tl); 23098c2ecf20Sopenharmony_ci} 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_cistatic int __init 23128c2ecf20Sopenharmony_ciHFC_init(void) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci int err; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci if (!poll) 23178c2ecf20Sopenharmony_ci poll = HFCPCI_BTRANS_THRESHOLD; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (poll != HFCPCI_BTRANS_THRESHOLD) { 23208c2ecf20Sopenharmony_ci tics = (poll * HZ) / 8000; 23218c2ecf20Sopenharmony_ci if (tics < 1) 23228c2ecf20Sopenharmony_ci tics = 1; 23238c2ecf20Sopenharmony_ci poll = (tics * 8000) / HZ; 23248c2ecf20Sopenharmony_ci if (poll > 256 || poll < 8) { 23258c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Wrong poll value %d not in range " 23268c2ecf20Sopenharmony_ci "of 8..256.\n", __func__, poll); 23278c2ecf20Sopenharmony_ci err = -EINVAL; 23288c2ecf20Sopenharmony_ci return err; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci if (poll != HFCPCI_BTRANS_THRESHOLD) { 23328c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Using alternative poll value of %d\n", 23338c2ecf20Sopenharmony_ci __func__, poll); 23348c2ecf20Sopenharmony_ci timer_setup(&hfc_tl, hfcpci_softirq, 0); 23358c2ecf20Sopenharmony_ci hfc_tl.expires = jiffies + tics; 23368c2ecf20Sopenharmony_ci hfc_jiffies = hfc_tl.expires; 23378c2ecf20Sopenharmony_ci add_timer(&hfc_tl); 23388c2ecf20Sopenharmony_ci } else 23398c2ecf20Sopenharmony_ci tics = 0; /* indicate the use of controller's timer */ 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci err = pci_register_driver(&hfc_driver); 23428c2ecf20Sopenharmony_ci if (err) { 23438c2ecf20Sopenharmony_ci if (timer_pending(&hfc_tl)) 23448c2ecf20Sopenharmony_ci del_timer(&hfc_tl); 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci return err; 23488c2ecf20Sopenharmony_ci} 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_cistatic void __exit 23518c2ecf20Sopenharmony_ciHFC_cleanup(void) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci if (timer_pending(&hfc_tl)) 23548c2ecf20Sopenharmony_ci del_timer_sync(&hfc_tl); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci pci_unregister_driver(&hfc_driver); 23578c2ecf20Sopenharmony_ci} 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cimodule_init(HFC_init); 23608c2ecf20Sopenharmony_cimodule_exit(HFC_cleanup); 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfc_ids); 2363