162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * hfcpci.c low level driver for CCD's hfc-pci based cards 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author Werner Cornelius (werner@isdn4linux.de) 762306a36Sopenharmony_ci * based on existing driver for CCD hfc ISA cards 862306a36Sopenharmony_ci * type approval valid for HFC-S PCI A based card 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) 1162306a36Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Module options: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * debug: 1662306a36Sopenharmony_ci * NOTE: only one poll value must be given for all cards 1762306a36Sopenharmony_ci * See hfc_pci.h for debug flags. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * poll: 2062306a36Sopenharmony_ci * NOTE: only one poll value must be given for all cards 2162306a36Sopenharmony_ci * Give the number of samples for each fifo process. 2262306a36Sopenharmony_ci * By default 128 is used. Decrease to reduce delay, increase to 2362306a36Sopenharmony_ci * reduce cpu load. If unsure, don't mess with it! 2462306a36Sopenharmony_ci * A value of 128 will use controller's interrupt. Other values will 2562306a36Sopenharmony_ci * use kernel timer, because the controller will not allow lower values 2662306a36Sopenharmony_ci * than 128. 2762306a36Sopenharmony_ci * Also note that the value depends on the kernel timer frequency. 2862306a36Sopenharmony_ci * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. 2962306a36Sopenharmony_ci * If the kernel uses 100 Hz, steps of 80 samples are possible. 3062306a36Sopenharmony_ci * If the kernel uses 300 Hz, steps of about 26 samples are possible. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/interrupt.h> 3462306a36Sopenharmony_ci#include <linux/module.h> 3562306a36Sopenharmony_ci#include <linux/pci.h> 3662306a36Sopenharmony_ci#include <linux/delay.h> 3762306a36Sopenharmony_ci#include <linux/mISDNhw.h> 3862306a36Sopenharmony_ci#include <linux/slab.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include "hfc_pci.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic const char *hfcpci_revision = "2.0"; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int HFC_cnt; 4562306a36Sopenharmony_cistatic uint debug; 4662306a36Sopenharmony_cistatic uint poll, tics; 4762306a36Sopenharmony_cistatic struct timer_list hfc_tl; 4862306a36Sopenharmony_cistatic unsigned long hfc_jiffies; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 5162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5262306a36Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 5362306a36Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cienum { 5662306a36Sopenharmony_ci HFC_CCD_2BD0, 5762306a36Sopenharmony_ci HFC_CCD_B000, 5862306a36Sopenharmony_ci HFC_CCD_B006, 5962306a36Sopenharmony_ci HFC_CCD_B007, 6062306a36Sopenharmony_ci HFC_CCD_B008, 6162306a36Sopenharmony_ci HFC_CCD_B009, 6262306a36Sopenharmony_ci HFC_CCD_B00A, 6362306a36Sopenharmony_ci HFC_CCD_B00B, 6462306a36Sopenharmony_ci HFC_CCD_B00C, 6562306a36Sopenharmony_ci HFC_CCD_B100, 6662306a36Sopenharmony_ci HFC_CCD_B700, 6762306a36Sopenharmony_ci HFC_CCD_B701, 6862306a36Sopenharmony_ci HFC_ASUS_0675, 6962306a36Sopenharmony_ci HFC_BERKOM_A1T, 7062306a36Sopenharmony_ci HFC_BERKOM_TCONCEPT, 7162306a36Sopenharmony_ci HFC_ANIGMA_MC145575, 7262306a36Sopenharmony_ci HFC_ZOLTRIX_2BD0, 7362306a36Sopenharmony_ci HFC_DIGI_DF_M_IOM2_E, 7462306a36Sopenharmony_ci HFC_DIGI_DF_M_E, 7562306a36Sopenharmony_ci HFC_DIGI_DF_M_IOM2_A, 7662306a36Sopenharmony_ci HFC_DIGI_DF_M_A, 7762306a36Sopenharmony_ci HFC_ABOCOM_2BD1, 7862306a36Sopenharmony_ci HFC_SITECOM_DC105V2, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct hfcPCI_hw { 8262306a36Sopenharmony_ci unsigned char cirm; 8362306a36Sopenharmony_ci unsigned char ctmt; 8462306a36Sopenharmony_ci unsigned char clkdel; 8562306a36Sopenharmony_ci unsigned char states; 8662306a36Sopenharmony_ci unsigned char conn; 8762306a36Sopenharmony_ci unsigned char mst_m; 8862306a36Sopenharmony_ci unsigned char int_m1; 8962306a36Sopenharmony_ci unsigned char int_m2; 9062306a36Sopenharmony_ci unsigned char sctrl; 9162306a36Sopenharmony_ci unsigned char sctrl_r; 9262306a36Sopenharmony_ci unsigned char sctrl_e; 9362306a36Sopenharmony_ci unsigned char trm; 9462306a36Sopenharmony_ci unsigned char fifo_en; 9562306a36Sopenharmony_ci unsigned char bswapped; 9662306a36Sopenharmony_ci unsigned char protocol; 9762306a36Sopenharmony_ci int nt_timer; 9862306a36Sopenharmony_ci unsigned char __iomem *pci_io; /* start of PCI IO memory */ 9962306a36Sopenharmony_ci dma_addr_t dmahandle; 10062306a36Sopenharmony_ci void *fifos; /* FIFO memory */ 10162306a36Sopenharmony_ci int last_bfifo_cnt[2]; 10262306a36Sopenharmony_ci /* marker saving last b-fifo frame count */ 10362306a36Sopenharmony_ci struct timer_list timer; 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define HFC_CFG_MASTER 1 10762306a36Sopenharmony_ci#define HFC_CFG_SLAVE 2 10862306a36Sopenharmony_ci#define HFC_CFG_PCM 3 10962306a36Sopenharmony_ci#define HFC_CFG_2HFC 4 11062306a36Sopenharmony_ci#define HFC_CFG_SLAVEHFC 5 11162306a36Sopenharmony_ci#define HFC_CFG_NEG_F0 6 11262306a36Sopenharmony_ci#define HFC_CFG_SW_DD_DU 7 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define FLG_HFC_TIMER_T1 16 11562306a36Sopenharmony_ci#define FLG_HFC_TIMER_T3 17 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ 11862306a36Sopenharmony_ci#define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ 11962306a36Sopenharmony_ci#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ 12062306a36Sopenharmony_ci#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct hfc_pci { 12462306a36Sopenharmony_ci u_char subtype; 12562306a36Sopenharmony_ci u_char chanlimit; 12662306a36Sopenharmony_ci u_char initdone; 12762306a36Sopenharmony_ci u_long cfg; 12862306a36Sopenharmony_ci u_int irq; 12962306a36Sopenharmony_ci u_int irqcnt; 13062306a36Sopenharmony_ci struct pci_dev *pdev; 13162306a36Sopenharmony_ci struct hfcPCI_hw hw; 13262306a36Sopenharmony_ci spinlock_t lock; /* card lock */ 13362306a36Sopenharmony_ci struct dchannel dch; 13462306a36Sopenharmony_ci struct bchannel bch[2]; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* Interface functions */ 13862306a36Sopenharmony_cistatic void 13962306a36Sopenharmony_cienable_hwirq(struct hfc_pci *hc) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; 14262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void 14662306a36Sopenharmony_cidisable_hwirq(struct hfc_pci *hc) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); 14962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * free hardware resources used by driver 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_cistatic void 15662306a36Sopenharmony_cirelease_io_hfcpci(struct hfc_pci *hc) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci /* disable memory mapped ports + busmaster */ 15962306a36Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, 0); 16062306a36Sopenharmony_ci del_timer(&hc->hw.timer); 16162306a36Sopenharmony_ci dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, 16262306a36Sopenharmony_ci hc->hw.dmahandle); 16362306a36Sopenharmony_ci iounmap(hc->hw.pci_io); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * set mode (NT or TE) 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_cistatic void 17062306a36Sopenharmony_cihfcpci_setmode(struct hfc_pci *hc) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 17362306a36Sopenharmony_ci hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ 17462306a36Sopenharmony_ci hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ 17562306a36Sopenharmony_ci hc->hw.states = 1; /* G1 */ 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ 17862306a36Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ 17962306a36Sopenharmony_ci hc->hw.states = 2; /* F2 */ 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); 18262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); 18362306a36Sopenharmony_ci udelay(10); 18462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ 18562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * function called to reset the HFC PCI chip. A complete software reset of chip 19062306a36Sopenharmony_ci * and fifos is done. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistatic void 19362306a36Sopenharmony_cireset_hfcpci(struct hfc_pci *hc) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci u_char val; 19662306a36Sopenharmony_ci int cnt = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci printk(KERN_DEBUG "reset_hfcpci: entered\n"); 19962306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_CHIP_ID); 20062306a36Sopenharmony_ci printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); 20162306a36Sopenharmony_ci /* enable memory mapped ports, disable busmaster */ 20262306a36Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); 20362306a36Sopenharmony_ci disable_hwirq(hc); 20462306a36Sopenharmony_ci /* enable memory ports + busmaster */ 20562306a36Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, 20662306a36Sopenharmony_ci PCI_ENA_MEMIO + PCI_ENA_MASTER); 20762306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 20862306a36Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); 20962306a36Sopenharmony_ci hc->hw.cirm = HFCPCI_RESET; /* Reset On */ 21062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 21162306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 21262306a36Sopenharmony_ci mdelay(10); /* Timeout 10ms */ 21362306a36Sopenharmony_ci hc->hw.cirm = 0; /* Reset Off */ 21462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 21562306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 21662306a36Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); 21762306a36Sopenharmony_ci while (cnt < 50000) { /* max 50000 us */ 21862306a36Sopenharmony_ci udelay(5); 21962306a36Sopenharmony_ci cnt += 5; 22062306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_STATUS); 22162306a36Sopenharmony_ci if (!(val & 2)) 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci hc->hw.fifo_en = 0x30; /* only D fifos enabled */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci hc->hw.bswapped = 0; /* no exchange */ 22962306a36Sopenharmony_ci hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; 23062306a36Sopenharmony_ci hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ 23162306a36Sopenharmony_ci hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ 23262306a36Sopenharmony_ci hc->hw.sctrl_r = 0; 23362306a36Sopenharmony_ci hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ 23462306a36Sopenharmony_ci hc->hw.mst_m = 0; 23562306a36Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 23662306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ 23762306a36Sopenharmony_ci if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) 23862306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_F0_NEGATIV; 23962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 24062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 24162306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); 24262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | 24562306a36Sopenharmony_ci HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; 24662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Clear already pending ints */ 24962306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S1); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* set NT/TE mode */ 25262306a36Sopenharmony_ci hfcpci_setmode(hc); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 25562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * Init GCI/IOM2 in master mode 25962306a36Sopenharmony_ci * Slots 0 and 1 are set for B-chan 1 and 2 26062306a36Sopenharmony_ci * D- and monitor/CI channel are not enabled 26162306a36Sopenharmony_ci * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC 26262306a36Sopenharmony_ci * STIO2 is used as data input, B1+B2 from IOM->ST 26362306a36Sopenharmony_ci * ST B-channel send disabled -> continuous 1s 26462306a36Sopenharmony_ci * The IOM slots are always enabled 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci if (test_bit(HFC_CFG_PCM, &hc->cfg)) { 26762306a36Sopenharmony_ci /* set data flow directions: connect B1,B2: HFC to/from PCM */ 26862306a36Sopenharmony_ci hc->hw.conn = 0x09; 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci hc->hw.conn = 0x36; /* set data flow directions */ 27162306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { 27262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); 27362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); 27462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); 27562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, 0x80); 27862306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, 0x81); 27962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, 0x80); 28062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, 0x81); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 28462306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S2); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * Timer function called when kernel timer expires 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_cistatic void 29162306a36Sopenharmony_cihfcpci_Timer(struct timer_list *t) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct hfc_pci *hc = from_timer(hc, t, hw.timer); 29462306a36Sopenharmony_ci hc->hw.timer.expires = jiffies + 75; 29562306a36Sopenharmony_ci /* WD RESET */ 29662306a36Sopenharmony_ci/* 29762306a36Sopenharmony_ci * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80); 29862306a36Sopenharmony_ci * add_timer(&hc->hw.timer); 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * select a b-channel entry matching and active 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_cistatic struct bchannel * 30762306a36Sopenharmony_ciSel_BCS(struct hfc_pci *hc, int channel) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && 31062306a36Sopenharmony_ci (hc->bch[0].nr & channel)) 31162306a36Sopenharmony_ci return &hc->bch[0]; 31262306a36Sopenharmony_ci else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && 31362306a36Sopenharmony_ci (hc->bch[1].nr & channel)) 31462306a36Sopenharmony_ci return &hc->bch[1]; 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci return NULL; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* 32062306a36Sopenharmony_ci * clear the desired B-channel rx fifo 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_cistatic void 32362306a36Sopenharmony_cihfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci u_char fifo_state; 32662306a36Sopenharmony_ci struct bzfifo *bzr; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (fifo) { 32962306a36Sopenharmony_ci bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; 33062306a36Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX; 33162306a36Sopenharmony_ci } else { 33262306a36Sopenharmony_ci bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; 33362306a36Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci if (fifo_state) 33662306a36Sopenharmony_ci hc->hw.fifo_en ^= fifo_state; 33762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 33862306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[fifo] = 0; 33962306a36Sopenharmony_ci bzr->f1 = MAX_B_FRAMES; 34062306a36Sopenharmony_ci bzr->f2 = bzr->f1; /* init F pointers to remain constant */ 34162306a36Sopenharmony_ci bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); 34262306a36Sopenharmony_ci bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16( 34362306a36Sopenharmony_ci le16_to_cpu(bzr->za[MAX_B_FRAMES].z1)); 34462306a36Sopenharmony_ci if (fifo_state) 34562306a36Sopenharmony_ci hc->hw.fifo_en |= fifo_state; 34662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * clear the desired B-channel tx fifo 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci u_char fifo_state; 35562306a36Sopenharmony_ci struct bzfifo *bzt; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (fifo) { 35862306a36Sopenharmony_ci bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 35962306a36Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX; 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 36262306a36Sopenharmony_ci fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci if (fifo_state) 36562306a36Sopenharmony_ci hc->hw.fifo_en ^= fifo_state; 36662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 36762306a36Sopenharmony_ci if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) 36862306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) " 36962306a36Sopenharmony_ci "z1(%x) z2(%x) state(%x)\n", 37062306a36Sopenharmony_ci fifo, bzt->f1, bzt->f2, 37162306a36Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), 37262306a36Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z2), 37362306a36Sopenharmony_ci fifo_state); 37462306a36Sopenharmony_ci bzt->f2 = MAX_B_FRAMES; 37562306a36Sopenharmony_ci bzt->f1 = bzt->f2; /* init F pointers to remain constant */ 37662306a36Sopenharmony_ci bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); 37762306a36Sopenharmony_ci bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2); 37862306a36Sopenharmony_ci if (fifo_state) 37962306a36Sopenharmony_ci hc->hw.fifo_en |= fifo_state; 38062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 38162306a36Sopenharmony_ci if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) 38262306a36Sopenharmony_ci printk(KERN_DEBUG 38362306a36Sopenharmony_ci "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n", 38462306a36Sopenharmony_ci fifo, bzt->f1, bzt->f2, 38562306a36Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), 38662306a36Sopenharmony_ci le16_to_cpu(bzt->za[MAX_B_FRAMES].z2)); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* 39062306a36Sopenharmony_ci * read a complete B-frame out of the buffer 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_cistatic void 39362306a36Sopenharmony_cihfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, 39462306a36Sopenharmony_ci u_char *bdata, int count) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci u_char *ptr, *ptr1, new_f2; 39762306a36Sopenharmony_ci int maxlen, new_z2; 39862306a36Sopenharmony_ci struct zt *zp; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) 40162306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_empty_fifo\n"); 40262306a36Sopenharmony_ci zp = &bz->za[bz->f2]; /* point to Z-Regs */ 40362306a36Sopenharmony_ci new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ 40462306a36Sopenharmony_ci if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) 40562306a36Sopenharmony_ci new_z2 -= B_FIFO_SIZE; /* buffer wrap */ 40662306a36Sopenharmony_ci new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; 40762306a36Sopenharmony_ci if ((count > MAX_DATA_SIZE + 3) || (count < 4) || 40862306a36Sopenharmony_ci (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { 40962306a36Sopenharmony_ci if (bch->debug & DEBUG_HW) 41062306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet " 41162306a36Sopenharmony_ci "invalid length %d or crc\n", count); 41262306a36Sopenharmony_ci#ifdef ERROR_STATISTIC 41362306a36Sopenharmony_ci bch->err_inv++; 41462306a36Sopenharmony_ci#endif 41562306a36Sopenharmony_ci bz->za[new_f2].z2 = cpu_to_le16(new_z2); 41662306a36Sopenharmony_ci bz->f2 = new_f2; /* next buffer */ 41762306a36Sopenharmony_ci } else { 41862306a36Sopenharmony_ci bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC); 41962306a36Sopenharmony_ci if (!bch->rx_skb) { 42062306a36Sopenharmony_ci printk(KERN_WARNING "HFCPCI: receive out of memory\n"); 42162306a36Sopenharmony_ci return; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci count -= 3; 42462306a36Sopenharmony_ci ptr = skb_put(bch->rx_skb, count); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) 42762306a36Sopenharmony_ci maxlen = count; /* complete transfer */ 42862306a36Sopenharmony_ci else 42962306a36Sopenharmony_ci maxlen = B_FIFO_SIZE + B_SUB_VAL - 43062306a36Sopenharmony_ci le16_to_cpu(zp->z2); /* maximum */ 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); 43362306a36Sopenharmony_ci /* start of data */ 43462306a36Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 43562306a36Sopenharmony_ci count -= maxlen; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (count) { /* rest remaining */ 43862306a36Sopenharmony_ci ptr += maxlen; 43962306a36Sopenharmony_ci ptr1 = bdata; /* start of buffer */ 44062306a36Sopenharmony_ci memcpy(ptr, ptr1, count); /* rest */ 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci bz->za[new_f2].z2 = cpu_to_le16(new_z2); 44362306a36Sopenharmony_ci bz->f2 = new_f2; /* next buffer */ 44462306a36Sopenharmony_ci recv_Bchannel(bch, MISDN_ID_ANY, false); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* 44962306a36Sopenharmony_ci * D-channel receive procedure 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_cistatic int 45262306a36Sopenharmony_cireceive_dmsg(struct hfc_pci *hc) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct dchannel *dch = &hc->dch; 45562306a36Sopenharmony_ci int maxlen; 45662306a36Sopenharmony_ci int rcnt, total; 45762306a36Sopenharmony_ci int count = 5; 45862306a36Sopenharmony_ci u_char *ptr, *ptr1; 45962306a36Sopenharmony_ci struct dfifo *df; 46062306a36Sopenharmony_ci struct zt *zp; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx; 46362306a36Sopenharmony_ci while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { 46462306a36Sopenharmony_ci zp = &df->za[df->f2 & D_FREG_MASK]; 46562306a36Sopenharmony_ci rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); 46662306a36Sopenharmony_ci if (rcnt < 0) 46762306a36Sopenharmony_ci rcnt += D_FIFO_SIZE; 46862306a36Sopenharmony_ci rcnt++; 46962306a36Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 47062306a36Sopenharmony_ci printk(KERN_DEBUG 47162306a36Sopenharmony_ci "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n", 47262306a36Sopenharmony_ci df->f1, df->f2, 47362306a36Sopenharmony_ci le16_to_cpu(zp->z1), 47462306a36Sopenharmony_ci le16_to_cpu(zp->z2), 47562306a36Sopenharmony_ci rcnt); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || 47862306a36Sopenharmony_ci (df->data[le16_to_cpu(zp->z1)])) { 47962306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 48062306a36Sopenharmony_ci printk(KERN_DEBUG 48162306a36Sopenharmony_ci "empty_fifo hfcpci packet inv. len " 48262306a36Sopenharmony_ci "%d or crc %d\n", 48362306a36Sopenharmony_ci rcnt, 48462306a36Sopenharmony_ci df->data[le16_to_cpu(zp->z1)]); 48562306a36Sopenharmony_ci#ifdef ERROR_STATISTIC 48662306a36Sopenharmony_ci cs->err_rx++; 48762306a36Sopenharmony_ci#endif 48862306a36Sopenharmony_ci df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | 48962306a36Sopenharmony_ci (MAX_D_FRAMES + 1); /* next buffer */ 49062306a36Sopenharmony_ci df->za[df->f2 & D_FREG_MASK].z2 = 49162306a36Sopenharmony_ci cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & 49262306a36Sopenharmony_ci (D_FIFO_SIZE - 1)); 49362306a36Sopenharmony_ci } else { 49462306a36Sopenharmony_ci dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); 49562306a36Sopenharmony_ci if (!dch->rx_skb) { 49662306a36Sopenharmony_ci printk(KERN_WARNING 49762306a36Sopenharmony_ci "HFC-PCI: D receive out of memory\n"); 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci total = rcnt; 50162306a36Sopenharmony_ci rcnt -= 3; 50262306a36Sopenharmony_ci ptr = skb_put(dch->rx_skb, rcnt); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) 50562306a36Sopenharmony_ci maxlen = rcnt; /* complete transfer */ 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); 50862306a36Sopenharmony_ci /* maximum */ 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ptr1 = df->data + le16_to_cpu(zp->z2); 51162306a36Sopenharmony_ci /* start of data */ 51262306a36Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 51362306a36Sopenharmony_ci rcnt -= maxlen; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (rcnt) { /* rest remaining */ 51662306a36Sopenharmony_ci ptr += maxlen; 51762306a36Sopenharmony_ci ptr1 = df->data; /* start of buffer */ 51862306a36Sopenharmony_ci memcpy(ptr, ptr1, rcnt); /* rest */ 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | 52162306a36Sopenharmony_ci (MAX_D_FRAMES + 1); /* next buffer */ 52262306a36Sopenharmony_ci df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16(( 52362306a36Sopenharmony_ci le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); 52462306a36Sopenharmony_ci recv_Dchannel(dch); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci return 1; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* 53162306a36Sopenharmony_ci * check for transparent receive data and read max one 'poll' size if avail 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_cistatic void 53462306a36Sopenharmony_cihfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, 53562306a36Sopenharmony_ci struct bzfifo *txbz, u_char *bdata) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci __le16 *z1r, *z2r, *z1t, *z2t; 53862306a36Sopenharmony_ci int new_z2, fcnt_rx, fcnt_tx, maxlen; 53962306a36Sopenharmony_ci u_char *ptr, *ptr1; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ 54262306a36Sopenharmony_ci z2r = z1r + 1; 54362306a36Sopenharmony_ci z1t = &txbz->za[MAX_B_FRAMES].z1; 54462306a36Sopenharmony_ci z2t = z1t + 1; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); 54762306a36Sopenharmony_ci if (!fcnt_rx) 54862306a36Sopenharmony_ci return; /* no data avail */ 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (fcnt_rx <= 0) 55162306a36Sopenharmony_ci fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */ 55262306a36Sopenharmony_ci new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */ 55362306a36Sopenharmony_ci if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) 55462306a36Sopenharmony_ci new_z2 -= B_FIFO_SIZE; /* buffer wrap */ 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); 55762306a36Sopenharmony_ci if (fcnt_tx <= 0) 55862306a36Sopenharmony_ci fcnt_tx += B_FIFO_SIZE; 55962306a36Sopenharmony_ci /* fcnt_tx contains available bytes in tx-fifo */ 56062306a36Sopenharmony_ci fcnt_tx = B_FIFO_SIZE - fcnt_tx; 56162306a36Sopenharmony_ci /* remaining bytes to send (bytes in tx-fifo) */ 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (test_bit(FLG_RX_OFF, &bch->Flags)) { 56462306a36Sopenharmony_ci bch->dropcnt += fcnt_rx; 56562306a36Sopenharmony_ci *z2r = cpu_to_le16(new_z2); 56662306a36Sopenharmony_ci return; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci maxlen = bchannel_get_rxbuf(bch, fcnt_rx); 56962306a36Sopenharmony_ci if (maxlen < 0) { 57062306a36Sopenharmony_ci pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx); 57162306a36Sopenharmony_ci } else { 57262306a36Sopenharmony_ci ptr = skb_put(bch->rx_skb, fcnt_rx); 57362306a36Sopenharmony_ci if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) 57462306a36Sopenharmony_ci maxlen = fcnt_rx; /* complete transfer */ 57562306a36Sopenharmony_ci else 57662306a36Sopenharmony_ci maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); 57762306a36Sopenharmony_ci /* maximum */ 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); 58062306a36Sopenharmony_ci /* start of data */ 58162306a36Sopenharmony_ci memcpy(ptr, ptr1, maxlen); /* copy data */ 58262306a36Sopenharmony_ci fcnt_rx -= maxlen; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (fcnt_rx) { /* rest remaining */ 58562306a36Sopenharmony_ci ptr += maxlen; 58662306a36Sopenharmony_ci ptr1 = bdata; /* start of buffer */ 58762306a36Sopenharmony_ci memcpy(ptr, ptr1, fcnt_rx); /* rest */ 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */ 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci *z2r = cpu_to_le16(new_z2); /* new position */ 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/* 59562306a36Sopenharmony_ci * B-channel main receive routine 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_cistatic void 59862306a36Sopenharmony_cimain_rec_hfcpci(struct bchannel *bch) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 60162306a36Sopenharmony_ci int rcnt, real_fifo; 60262306a36Sopenharmony_ci int receive = 0, count = 5; 60362306a36Sopenharmony_ci struct bzfifo *txbz, *rxbz; 60462306a36Sopenharmony_ci u_char *bdata; 60562306a36Sopenharmony_ci struct zt *zp; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if ((bch->nr & 2) && (!hc->hw.bswapped)) { 60862306a36Sopenharmony_ci rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; 60962306a36Sopenharmony_ci txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 61062306a36Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; 61162306a36Sopenharmony_ci real_fifo = 1; 61262306a36Sopenharmony_ci } else { 61362306a36Sopenharmony_ci rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; 61462306a36Sopenharmony_ci txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 61562306a36Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; 61662306a36Sopenharmony_ci real_fifo = 0; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ciBegin: 61962306a36Sopenharmony_ci count--; 62062306a36Sopenharmony_ci if (rxbz->f1 != rxbz->f2) { 62162306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 62262306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", 62362306a36Sopenharmony_ci bch->nr, rxbz->f1, rxbz->f2); 62462306a36Sopenharmony_ci zp = &rxbz->za[rxbz->f2]; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); 62762306a36Sopenharmony_ci if (rcnt < 0) 62862306a36Sopenharmony_ci rcnt += B_FIFO_SIZE; 62962306a36Sopenharmony_ci rcnt++; 63062306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 63162306a36Sopenharmony_ci printk(KERN_DEBUG 63262306a36Sopenharmony_ci "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", 63362306a36Sopenharmony_ci bch->nr, le16_to_cpu(zp->z1), 63462306a36Sopenharmony_ci le16_to_cpu(zp->z2), rcnt); 63562306a36Sopenharmony_ci hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt); 63662306a36Sopenharmony_ci rcnt = rxbz->f1 - rxbz->f2; 63762306a36Sopenharmony_ci if (rcnt < 0) 63862306a36Sopenharmony_ci rcnt += MAX_B_FRAMES + 1; 63962306a36Sopenharmony_ci if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { 64062306a36Sopenharmony_ci rcnt = 0; 64162306a36Sopenharmony_ci hfcpci_clear_fifo_rx(hc, real_fifo); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[real_fifo] = rcnt; 64462306a36Sopenharmony_ci if (rcnt > 1) 64562306a36Sopenharmony_ci receive = 1; 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci receive = 0; 64862306a36Sopenharmony_ci } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 64962306a36Sopenharmony_ci hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata); 65062306a36Sopenharmony_ci return; 65162306a36Sopenharmony_ci } else 65262306a36Sopenharmony_ci receive = 0; 65362306a36Sopenharmony_ci if (count && receive) 65462306a36Sopenharmony_ci goto Begin; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci/* 65962306a36Sopenharmony_ci * D-channel send routine 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_cistatic void 66262306a36Sopenharmony_cihfcpci_fill_dfifo(struct hfc_pci *hc) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct dchannel *dch = &hc->dch; 66562306a36Sopenharmony_ci int fcnt; 66662306a36Sopenharmony_ci int count, new_z1, maxlen; 66762306a36Sopenharmony_ci struct dfifo *df; 66862306a36Sopenharmony_ci u_char *src, *dst, new_f1; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO)) 67162306a36Sopenharmony_ci printk(KERN_DEBUG "%s\n", __func__); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!dch->tx_skb) 67462306a36Sopenharmony_ci return; 67562306a36Sopenharmony_ci count = dch->tx_skb->len - dch->tx_idx; 67662306a36Sopenharmony_ci if (count <= 0) 67762306a36Sopenharmony_ci return; 67862306a36Sopenharmony_ci df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (dch->debug & DEBUG_HW_DFIFO) 68162306a36Sopenharmony_ci printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__, 68262306a36Sopenharmony_ci df->f1, df->f2, 68362306a36Sopenharmony_ci le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); 68462306a36Sopenharmony_ci fcnt = df->f1 - df->f2; /* frame count actually buffered */ 68562306a36Sopenharmony_ci if (fcnt < 0) 68662306a36Sopenharmony_ci fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ 68762306a36Sopenharmony_ci if (fcnt > (MAX_D_FRAMES - 1)) { 68862306a36Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 68962306a36Sopenharmony_ci printk(KERN_DEBUG 69062306a36Sopenharmony_ci "hfcpci_fill_Dfifo more as 14 frames\n"); 69162306a36Sopenharmony_ci#ifdef ERROR_STATISTIC 69262306a36Sopenharmony_ci cs->err_tx++; 69362306a36Sopenharmony_ci#endif 69462306a36Sopenharmony_ci return; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci /* now determine free bytes in FIFO buffer */ 69762306a36Sopenharmony_ci maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - 69862306a36Sopenharmony_ci le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1; 69962306a36Sopenharmony_ci if (maxlen <= 0) 70062306a36Sopenharmony_ci maxlen += D_FIFO_SIZE; /* count now contains available bytes */ 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 70362306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n", 70462306a36Sopenharmony_ci count, maxlen); 70562306a36Sopenharmony_ci if (count > maxlen) { 70662306a36Sopenharmony_ci if (dch->debug & DEBUG_HW_DCHANNEL) 70762306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n"); 70862306a36Sopenharmony_ci return; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & 71162306a36Sopenharmony_ci (D_FIFO_SIZE - 1); 71262306a36Sopenharmony_ci new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); 71362306a36Sopenharmony_ci src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ 71462306a36Sopenharmony_ci dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); 71562306a36Sopenharmony_ci maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); 71662306a36Sopenharmony_ci /* end fifo */ 71762306a36Sopenharmony_ci if (maxlen > count) 71862306a36Sopenharmony_ci maxlen = count; /* limit size */ 71962306a36Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci count -= maxlen; /* remaining bytes */ 72262306a36Sopenharmony_ci if (count) { 72362306a36Sopenharmony_ci dst = df->data; /* start of buffer */ 72462306a36Sopenharmony_ci src += maxlen; /* new position */ 72562306a36Sopenharmony_ci memcpy(dst, src, count); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); 72862306a36Sopenharmony_ci /* for next buffer */ 72962306a36Sopenharmony_ci df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); 73062306a36Sopenharmony_ci /* new pos actual buffer */ 73162306a36Sopenharmony_ci df->f1 = new_f1; /* next frame */ 73262306a36Sopenharmony_ci dch->tx_idx = dch->tx_skb->len; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci/* 73662306a36Sopenharmony_ci * B-channel send routine 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_cistatic void 73962306a36Sopenharmony_cihfcpci_fill_fifo(struct bchannel *bch) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 74262306a36Sopenharmony_ci int maxlen, fcnt; 74362306a36Sopenharmony_ci int count, new_z1; 74462306a36Sopenharmony_ci struct bzfifo *bz; 74562306a36Sopenharmony_ci u_char *bdata; 74662306a36Sopenharmony_ci u_char new_f1, *src, *dst; 74762306a36Sopenharmony_ci __le16 *z1t, *z2t; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) 75062306a36Sopenharmony_ci printk(KERN_DEBUG "%s\n", __func__); 75162306a36Sopenharmony_ci if ((!bch->tx_skb) || bch->tx_skb->len == 0) { 75262306a36Sopenharmony_ci if (!test_bit(FLG_FILLEMPTY, &bch->Flags) && 75362306a36Sopenharmony_ci !test_bit(FLG_TRANSPARENT, &bch->Flags)) 75462306a36Sopenharmony_ci return; 75562306a36Sopenharmony_ci count = HFCPCI_FILLEMPTY; 75662306a36Sopenharmony_ci } else { 75762306a36Sopenharmony_ci count = bch->tx_skb->len - bch->tx_idx; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci if ((bch->nr & 2) && (!hc->hw.bswapped)) { 76062306a36Sopenharmony_ci bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; 76162306a36Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; 76262306a36Sopenharmony_ci } else { 76362306a36Sopenharmony_ci bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; 76462306a36Sopenharmony_ci bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 76862306a36Sopenharmony_ci z1t = &bz->za[MAX_B_FRAMES].z1; 76962306a36Sopenharmony_ci z2t = z1t + 1; 77062306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 77162306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) " 77262306a36Sopenharmony_ci "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count, 77362306a36Sopenharmony_ci le16_to_cpu(*z1t), le16_to_cpu(*z2t)); 77462306a36Sopenharmony_ci fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); 77562306a36Sopenharmony_ci if (fcnt <= 0) 77662306a36Sopenharmony_ci fcnt += B_FIFO_SIZE; 77762306a36Sopenharmony_ci if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { 77862306a36Sopenharmony_ci /* fcnt contains available bytes in fifo */ 77962306a36Sopenharmony_ci if (count > fcnt) 78062306a36Sopenharmony_ci count = fcnt; 78162306a36Sopenharmony_ci new_z1 = le16_to_cpu(*z1t) + count; 78262306a36Sopenharmony_ci /* new buffer Position */ 78362306a36Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 78462306a36Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 78562306a36Sopenharmony_ci dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); 78662306a36Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); 78762306a36Sopenharmony_ci /* end of fifo */ 78862306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BFIFO) 78962306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_FFt fillempty " 79062306a36Sopenharmony_ci "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", 79162306a36Sopenharmony_ci fcnt, maxlen, new_z1, dst); 79262306a36Sopenharmony_ci if (maxlen > count) 79362306a36Sopenharmony_ci maxlen = count; /* limit size */ 79462306a36Sopenharmony_ci memset(dst, bch->fill[0], maxlen); /* first copy */ 79562306a36Sopenharmony_ci count -= maxlen; /* remaining bytes */ 79662306a36Sopenharmony_ci if (count) { 79762306a36Sopenharmony_ci dst = bdata; /* start of buffer */ 79862306a36Sopenharmony_ci memset(dst, bch->fill[0], count); 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci *z1t = cpu_to_le16(new_z1); /* now send data */ 80162306a36Sopenharmony_ci return; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci /* fcnt contains available bytes in fifo */ 80462306a36Sopenharmony_ci fcnt = B_FIFO_SIZE - fcnt; 80562306a36Sopenharmony_ci /* remaining bytes to send (bytes in fifo) */ 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci next_t_frame: 80862306a36Sopenharmony_ci count = bch->tx_skb->len - bch->tx_idx; 80962306a36Sopenharmony_ci /* maximum fill shall be poll*2 */ 81062306a36Sopenharmony_ci if (count > (poll << 1) - fcnt) 81162306a36Sopenharmony_ci count = (poll << 1) - fcnt; 81262306a36Sopenharmony_ci if (count <= 0) 81362306a36Sopenharmony_ci return; 81462306a36Sopenharmony_ci /* data is suitable for fifo */ 81562306a36Sopenharmony_ci new_z1 = le16_to_cpu(*z1t) + count; 81662306a36Sopenharmony_ci /* new buffer Position */ 81762306a36Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 81862306a36Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 81962306a36Sopenharmony_ci src = bch->tx_skb->data + bch->tx_idx; 82062306a36Sopenharmony_ci /* source pointer */ 82162306a36Sopenharmony_ci dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); 82262306a36Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); 82362306a36Sopenharmony_ci /* end of fifo */ 82462306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BFIFO) 82562306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) " 82662306a36Sopenharmony_ci "maxl(%d) nz1(%x) dst(%p)\n", 82762306a36Sopenharmony_ci fcnt, maxlen, new_z1, dst); 82862306a36Sopenharmony_ci fcnt += count; 82962306a36Sopenharmony_ci bch->tx_idx += count; 83062306a36Sopenharmony_ci if (maxlen > count) 83162306a36Sopenharmony_ci maxlen = count; /* limit size */ 83262306a36Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 83362306a36Sopenharmony_ci count -= maxlen; /* remaining bytes */ 83462306a36Sopenharmony_ci if (count) { 83562306a36Sopenharmony_ci dst = bdata; /* start of buffer */ 83662306a36Sopenharmony_ci src += maxlen; /* new position */ 83762306a36Sopenharmony_ci memcpy(dst, src, count); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci *z1t = cpu_to_le16(new_z1); /* now send data */ 84062306a36Sopenharmony_ci if (bch->tx_idx < bch->tx_skb->len) 84162306a36Sopenharmony_ci return; 84262306a36Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 84362306a36Sopenharmony_ci if (get_next_bframe(bch)) 84462306a36Sopenharmony_ci goto next_t_frame; 84562306a36Sopenharmony_ci return; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 84862306a36Sopenharmony_ci printk(KERN_DEBUG 84962306a36Sopenharmony_ci "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n", 85062306a36Sopenharmony_ci __func__, bch->nr, bz->f1, bz->f2, 85162306a36Sopenharmony_ci bz->za[bz->f1].z1); 85262306a36Sopenharmony_ci fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ 85362306a36Sopenharmony_ci if (fcnt < 0) 85462306a36Sopenharmony_ci fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ 85562306a36Sopenharmony_ci if (fcnt > (MAX_B_FRAMES - 1)) { 85662306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 85762306a36Sopenharmony_ci printk(KERN_DEBUG 85862306a36Sopenharmony_ci "hfcpci_fill_Bfifo more as 14 frames\n"); 85962306a36Sopenharmony_ci return; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci /* now determine free bytes in FIFO buffer */ 86262306a36Sopenharmony_ci maxlen = le16_to_cpu(bz->za[bz->f2].z2) - 86362306a36Sopenharmony_ci le16_to_cpu(bz->za[bz->f1].z1) - 1; 86462306a36Sopenharmony_ci if (maxlen <= 0) 86562306a36Sopenharmony_ci maxlen += B_FIFO_SIZE; /* count now contains available bytes */ 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 86862306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n", 86962306a36Sopenharmony_ci bch->nr, count, maxlen); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (maxlen < count) { 87262306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 87362306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n"); 87462306a36Sopenharmony_ci return; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; 87762306a36Sopenharmony_ci /* new buffer Position */ 87862306a36Sopenharmony_ci if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) 87962306a36Sopenharmony_ci new_z1 -= B_FIFO_SIZE; /* buffer wrap */ 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); 88262306a36Sopenharmony_ci src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ 88362306a36Sopenharmony_ci dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); 88462306a36Sopenharmony_ci maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); 88562306a36Sopenharmony_ci /* end fifo */ 88662306a36Sopenharmony_ci if (maxlen > count) 88762306a36Sopenharmony_ci maxlen = count; /* limit size */ 88862306a36Sopenharmony_ci memcpy(dst, src, maxlen); /* first copy */ 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci count -= maxlen; /* remaining bytes */ 89162306a36Sopenharmony_ci if (count) { 89262306a36Sopenharmony_ci dst = bdata; /* start of buffer */ 89362306a36Sopenharmony_ci src += maxlen; /* new position */ 89462306a36Sopenharmony_ci memcpy(dst, src, count); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ 89762306a36Sopenharmony_ci bz->f1 = new_f1; /* next frame */ 89862306a36Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 89962306a36Sopenharmony_ci get_next_bframe(bch); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/* 90562306a36Sopenharmony_ci * handle L1 state changes TE 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic void 90962306a36Sopenharmony_ciph_state_te(struct dchannel *dch) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci if (dch->debug) 91262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: TE newstate %x\n", 91362306a36Sopenharmony_ci __func__, dch->state); 91462306a36Sopenharmony_ci switch (dch->state) { 91562306a36Sopenharmony_ci case 0: 91662306a36Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci case 3: 91962306a36Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci case 5: 92262306a36Sopenharmony_ci case 8: 92362306a36Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 92462306a36Sopenharmony_ci break; 92562306a36Sopenharmony_ci case 6: 92662306a36Sopenharmony_ci l1_event(dch->l1, INFO2); 92762306a36Sopenharmony_ci break; 92862306a36Sopenharmony_ci case 7: 92962306a36Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci/* 93562306a36Sopenharmony_ci * handle L1 state changes NT 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic void 93962306a36Sopenharmony_cihandle_nt_timer3(struct dchannel *dch) { 94062306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 94362306a36Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 94462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 94562306a36Sopenharmony_ci hc->hw.nt_timer = 0; 94662306a36Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 94762306a36Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 94862306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 94962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 95062306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 95162306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic void 95562306a36Sopenharmony_ciph_state_nt(struct dchannel *dch) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (dch->debug) 96062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: NT newstate %x\n", 96162306a36Sopenharmony_ci __func__, dch->state); 96262306a36Sopenharmony_ci switch (dch->state) { 96362306a36Sopenharmony_ci case 2: 96462306a36Sopenharmony_ci if (hc->hw.nt_timer < 0) { 96562306a36Sopenharmony_ci hc->hw.nt_timer = 0; 96662306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 96762306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 96862306a36Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 96962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 97062306a36Sopenharmony_ci /* Clear already pending ints */ 97162306a36Sopenharmony_ci (void) Read_hfc(hc, HFCPCI_INT_S1); 97262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); 97362306a36Sopenharmony_ci udelay(10); 97462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 4); 97562306a36Sopenharmony_ci dch->state = 4; 97662306a36Sopenharmony_ci } else if (hc->hw.nt_timer == 0) { 97762306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_TIMER; 97862306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 97962306a36Sopenharmony_ci hc->hw.nt_timer = NT_T1_COUNT; 98062306a36Sopenharmony_ci hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; 98162306a36Sopenharmony_ci hc->hw.ctmt |= HFCPCI_TIM3_125; 98262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | 98362306a36Sopenharmony_ci HFCPCI_CLTIMER); 98462306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 98562306a36Sopenharmony_ci test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags); 98662306a36Sopenharmony_ci /* allow G2 -> G3 transition */ 98762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); 98862306a36Sopenharmony_ci } else { 98962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci break; 99262306a36Sopenharmony_ci case 1: 99362306a36Sopenharmony_ci hc->hw.nt_timer = 0; 99462306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 99562306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 99662306a36Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 99762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 99862306a36Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 99962306a36Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 100062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 100162306a36Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 100262306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 100362306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 100462306a36Sopenharmony_ci break; 100562306a36Sopenharmony_ci case 4: 100662306a36Sopenharmony_ci hc->hw.nt_timer = 0; 100762306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); 100862306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 100962306a36Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 101062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci case 3: 101362306a36Sopenharmony_ci if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) { 101462306a36Sopenharmony_ci if (!test_and_clear_bit(FLG_L2_ACTIVATED, 101562306a36Sopenharmony_ci &dch->Flags)) { 101662306a36Sopenharmony_ci handle_nt_timer3(dch); 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); 102062306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_TIMER; 102162306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 102262306a36Sopenharmony_ci hc->hw.nt_timer = NT_T3_COUNT; 102362306a36Sopenharmony_ci hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; 102462306a36Sopenharmony_ci hc->hw.ctmt |= HFCPCI_TIM3_125; 102562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | 102662306a36Sopenharmony_ci HFCPCI_CLTIMER); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic void 103362306a36Sopenharmony_ciph_state(struct dchannel *dch) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 103862306a36Sopenharmony_ci if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) && 103962306a36Sopenharmony_ci hc->hw.nt_timer < 0) 104062306a36Sopenharmony_ci handle_nt_timer3(dch); 104162306a36Sopenharmony_ci else 104262306a36Sopenharmony_ci ph_state_nt(dch); 104362306a36Sopenharmony_ci } else 104462306a36Sopenharmony_ci ph_state_te(dch); 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci/* 104862306a36Sopenharmony_ci * Layer 1 callback function 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_cistatic int 105162306a36Sopenharmony_cihfc_l1callback(struct dchannel *dch, u_int cmd) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci switch (cmd) { 105662306a36Sopenharmony_ci case INFO3_P8: 105762306a36Sopenharmony_ci case INFO3_P10: 105862306a36Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 105962306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 106062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci case HW_RESET_REQ: 106362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); 106462306a36Sopenharmony_ci /* HFC ST 3 */ 106562306a36Sopenharmony_ci udelay(6); 106662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ 106762306a36Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 106862306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 106962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 107062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | 107162306a36Sopenharmony_ci HFCPCI_DO_ACTION); 107262306a36Sopenharmony_ci l1_event(dch->l1, HW_POWERUP_IND); 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci case HW_DEACT_REQ: 107562306a36Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 107662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 107762306a36Sopenharmony_ci skb_queue_purge(&dch->squeue); 107862306a36Sopenharmony_ci if (dch->tx_skb) { 107962306a36Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 108062306a36Sopenharmony_ci dch->tx_skb = NULL; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci dch->tx_idx = 0; 108362306a36Sopenharmony_ci if (dch->rx_skb) { 108462306a36Sopenharmony_ci dev_kfree_skb(dch->rx_skb); 108562306a36Sopenharmony_ci dch->rx_skb = NULL; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 108862306a36Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 108962306a36Sopenharmony_ci del_timer(&dch->timer); 109062306a36Sopenharmony_ci break; 109162306a36Sopenharmony_ci case HW_POWERUP_REQ: 109262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); 109362306a36Sopenharmony_ci break; 109462306a36Sopenharmony_ci case PH_ACTIVATE_IND: 109562306a36Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 109662306a36Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 109762306a36Sopenharmony_ci GFP_ATOMIC); 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci case PH_DEACTIVATE_IND: 110062306a36Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 110162306a36Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 110262306a36Sopenharmony_ci GFP_ATOMIC); 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci default: 110562306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 110662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 110762306a36Sopenharmony_ci __func__, cmd); 110862306a36Sopenharmony_ci return -1; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci/* 111462306a36Sopenharmony_ci * Interrupt handler 111562306a36Sopenharmony_ci */ 111662306a36Sopenharmony_cistatic inline void 111762306a36Sopenharmony_citx_birq(struct bchannel *bch) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) 112062306a36Sopenharmony_ci hfcpci_fill_fifo(bch); 112162306a36Sopenharmony_ci else { 112262306a36Sopenharmony_ci dev_kfree_skb_any(bch->tx_skb); 112362306a36Sopenharmony_ci if (get_next_bframe(bch)) 112462306a36Sopenharmony_ci hfcpci_fill_fifo(bch); 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic inline void 112962306a36Sopenharmony_citx_dirq(struct dchannel *dch) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) 113262306a36Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 113362306a36Sopenharmony_ci else { 113462306a36Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 113562306a36Sopenharmony_ci if (get_next_dframe(dch)) 113662306a36Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic irqreturn_t 114162306a36Sopenharmony_cihfcpci_int(int intno, void *dev_id) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct hfc_pci *hc = dev_id; 114462306a36Sopenharmony_ci u_char exval; 114562306a36Sopenharmony_ci struct bchannel *bch; 114662306a36Sopenharmony_ci u_char val, stat; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci spin_lock(&hc->lock); 114962306a36Sopenharmony_ci if (!(hc->hw.int_m2 & 0x08)) { 115062306a36Sopenharmony_ci spin_unlock(&hc->lock); 115162306a36Sopenharmony_ci return IRQ_NONE; /* not initialised */ 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci stat = Read_hfc(hc, HFCPCI_STATUS); 115462306a36Sopenharmony_ci if (HFCPCI_ANYINT & stat) { 115562306a36Sopenharmony_ci val = Read_hfc(hc, HFCPCI_INT_S1); 115662306a36Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 115762306a36Sopenharmony_ci printk(KERN_DEBUG 115862306a36Sopenharmony_ci "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val); 115962306a36Sopenharmony_ci } else { 116062306a36Sopenharmony_ci /* shared */ 116162306a36Sopenharmony_ci spin_unlock(&hc->lock); 116262306a36Sopenharmony_ci return IRQ_NONE; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci hc->irqcnt++; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 116762306a36Sopenharmony_ci printk(KERN_DEBUG "HFC-PCI irq %x\n", val); 116862306a36Sopenharmony_ci val &= hc->hw.int_m1; 116962306a36Sopenharmony_ci if (val & 0x40) { /* state machine irq */ 117062306a36Sopenharmony_ci exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; 117162306a36Sopenharmony_ci if (hc->dch.debug & DEBUG_HW_DCHANNEL) 117262306a36Sopenharmony_ci printk(KERN_DEBUG "ph_state chg %d->%d\n", 117362306a36Sopenharmony_ci hc->dch.state, exval); 117462306a36Sopenharmony_ci hc->dch.state = exval; 117562306a36Sopenharmony_ci schedule_event(&hc->dch, FLG_PHCHANGE); 117662306a36Sopenharmony_ci val &= ~0x40; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci if (val & 0x80) { /* timer irq */ 117962306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 118062306a36Sopenharmony_ci if ((--hc->hw.nt_timer) < 0) 118162306a36Sopenharmony_ci schedule_event(&hc->dch, FLG_PHCHANGE); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci val &= ~0x80; 118462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci if (val & 0x08) { /* B1 rx */ 118762306a36Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 118862306a36Sopenharmony_ci if (bch) 118962306a36Sopenharmony_ci main_rec_hfcpci(bch); 119062306a36Sopenharmony_ci else if (hc->dch.debug) 119162306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci if (val & 0x10) { /* B2 rx */ 119462306a36Sopenharmony_ci bch = Sel_BCS(hc, 2); 119562306a36Sopenharmony_ci if (bch) 119662306a36Sopenharmony_ci main_rec_hfcpci(bch); 119762306a36Sopenharmony_ci else if (hc->dch.debug) 119862306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci if (val & 0x01) { /* B1 tx */ 120162306a36Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 120262306a36Sopenharmony_ci if (bch) 120362306a36Sopenharmony_ci tx_birq(bch); 120462306a36Sopenharmony_ci else if (hc->dch.debug) 120562306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci if (val & 0x02) { /* B2 tx */ 120862306a36Sopenharmony_ci bch = Sel_BCS(hc, 2); 120962306a36Sopenharmony_ci if (bch) 121062306a36Sopenharmony_ci tx_birq(bch); 121162306a36Sopenharmony_ci else if (hc->dch.debug) 121262306a36Sopenharmony_ci printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci if (val & 0x20) /* D rx */ 121562306a36Sopenharmony_ci receive_dmsg(hc); 121662306a36Sopenharmony_ci if (val & 0x04) { /* D tx */ 121762306a36Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) 121862306a36Sopenharmony_ci del_timer(&hc->dch.timer); 121962306a36Sopenharmony_ci tx_dirq(&hc->dch); 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci spin_unlock(&hc->lock); 122262306a36Sopenharmony_ci return IRQ_HANDLED; 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci/* 122662306a36Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_cistatic void 122962306a36Sopenharmony_cihfcpci_dbusy_timer(struct timer_list *t) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/* 123462306a36Sopenharmony_ci * activate/deactivate hardware for selected channels and mode 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_cistatic int 123762306a36Sopenharmony_cimode_hfcpci(struct bchannel *bch, int bc, int protocol) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 124062306a36Sopenharmony_ci int fifo2; 124162306a36Sopenharmony_ci u_char rx_slot = 0, tx_slot = 0, pcm_mode; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 124462306a36Sopenharmony_ci printk(KERN_DEBUG 124562306a36Sopenharmony_ci "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", 124662306a36Sopenharmony_ci bch->state, protocol, bch->nr, bc); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci fifo2 = bc; 124962306a36Sopenharmony_ci pcm_mode = (bc >> 24) & 0xff; 125062306a36Sopenharmony_ci if (pcm_mode) { /* PCM SLOT USE */ 125162306a36Sopenharmony_ci if (!test_bit(HFC_CFG_PCM, &hc->cfg)) 125262306a36Sopenharmony_ci printk(KERN_WARNING 125362306a36Sopenharmony_ci "%s: pcm channel id without HFC_CFG_PCM\n", 125462306a36Sopenharmony_ci __func__); 125562306a36Sopenharmony_ci rx_slot = (bc >> 8) & 0xff; 125662306a36Sopenharmony_ci tx_slot = (bc >> 16) & 0xff; 125762306a36Sopenharmony_ci bc = bc & 0xff; 125862306a36Sopenharmony_ci } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) 125962306a36Sopenharmony_ci printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", 126062306a36Sopenharmony_ci __func__); 126162306a36Sopenharmony_ci if (hc->chanlimit > 1) { 126262306a36Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 126362306a36Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 126462306a36Sopenharmony_ci } else { 126562306a36Sopenharmony_ci if (bc & 2) { 126662306a36Sopenharmony_ci if (protocol != ISDN_P_NONE) { 126762306a36Sopenharmony_ci hc->hw.bswapped = 1; /* B1 and B2 exchanged */ 126862306a36Sopenharmony_ci hc->hw.sctrl_e |= 0x80; 126962306a36Sopenharmony_ci } else { 127062306a36Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 127162306a36Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci fifo2 = 1; 127462306a36Sopenharmony_ci } else { 127562306a36Sopenharmony_ci hc->hw.bswapped = 0; /* B1 and B2 normal mode */ 127662306a36Sopenharmony_ci hc->hw.sctrl_e &= ~0x80; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci switch (protocol) { 128062306a36Sopenharmony_ci case (-1): /* used for init */ 128162306a36Sopenharmony_ci bch->state = -1; 128262306a36Sopenharmony_ci bch->nr = bc; 128362306a36Sopenharmony_ci fallthrough; 128462306a36Sopenharmony_ci case (ISDN_P_NONE): 128562306a36Sopenharmony_ci if (bch->state == ISDN_P_NONE) 128662306a36Sopenharmony_ci return 0; 128762306a36Sopenharmony_ci if (bc & 2) { 128862306a36Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_B2_ENA; 128962306a36Sopenharmony_ci hc->hw.sctrl_r &= ~SCTRL_B2_ENA; 129062306a36Sopenharmony_ci } else { 129162306a36Sopenharmony_ci hc->hw.sctrl &= ~SCTRL_B1_ENA; 129262306a36Sopenharmony_ci hc->hw.sctrl_r &= ~SCTRL_B1_ENA; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci if (fifo2 & 2) { 129562306a36Sopenharmony_ci hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; 129662306a36Sopenharmony_ci hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS | 129762306a36Sopenharmony_ci HFCPCI_INTS_B2REC); 129862306a36Sopenharmony_ci } else { 129962306a36Sopenharmony_ci hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; 130062306a36Sopenharmony_ci hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS | 130162306a36Sopenharmony_ci HFCPCI_INTS_B1REC); 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 130462306a36Sopenharmony_ci if (bch->nr & 2) 130562306a36Sopenharmony_ci hc->hw.cirm &= 0x7f; 130662306a36Sopenharmony_ci else 130762306a36Sopenharmony_ci hc->hw.cirm &= 0xbf; 130862306a36Sopenharmony_ci#endif 130962306a36Sopenharmony_ci bch->state = ISDN_P_NONE; 131062306a36Sopenharmony_ci bch->nr = bc; 131162306a36Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &bch->Flags); 131262306a36Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci case (ISDN_P_B_RAW): 131562306a36Sopenharmony_ci bch->state = protocol; 131662306a36Sopenharmony_ci bch->nr = bc; 131762306a36Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); 131862306a36Sopenharmony_ci hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); 131962306a36Sopenharmony_ci if (bc & 2) { 132062306a36Sopenharmony_ci hc->hw.sctrl |= SCTRL_B2_ENA; 132162306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 132262306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 132362306a36Sopenharmony_ci hc->hw.cirm |= 0x80; 132462306a36Sopenharmony_ci#endif 132562306a36Sopenharmony_ci } else { 132662306a36Sopenharmony_ci hc->hw.sctrl |= SCTRL_B1_ENA; 132762306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 132862306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 132962306a36Sopenharmony_ci hc->hw.cirm |= 0x40; 133062306a36Sopenharmony_ci#endif 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci if (fifo2 & 2) { 133362306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; 133462306a36Sopenharmony_ci if (!tics) 133562306a36Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | 133662306a36Sopenharmony_ci HFCPCI_INTS_B2REC); 133762306a36Sopenharmony_ci hc->hw.ctmt |= 2; 133862306a36Sopenharmony_ci hc->hw.conn &= ~0x18; 133962306a36Sopenharmony_ci } else { 134062306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; 134162306a36Sopenharmony_ci if (!tics) 134262306a36Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | 134362306a36Sopenharmony_ci HFCPCI_INTS_B1REC); 134462306a36Sopenharmony_ci hc->hw.ctmt |= 1; 134562306a36Sopenharmony_ci hc->hw.conn &= ~0x03; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); 134862306a36Sopenharmony_ci break; 134962306a36Sopenharmony_ci case (ISDN_P_B_HDLC): 135062306a36Sopenharmony_ci bch->state = protocol; 135162306a36Sopenharmony_ci bch->nr = bc; 135262306a36Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); 135362306a36Sopenharmony_ci hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); 135462306a36Sopenharmony_ci if (bc & 2) { 135562306a36Sopenharmony_ci hc->hw.sctrl |= SCTRL_B2_ENA; 135662306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 135762306a36Sopenharmony_ci } else { 135862306a36Sopenharmony_ci hc->hw.sctrl |= SCTRL_B1_ENA; 135962306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci if (fifo2 & 2) { 136262306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[1] = 0; 136362306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; 136462306a36Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | 136562306a36Sopenharmony_ci HFCPCI_INTS_B2REC); 136662306a36Sopenharmony_ci hc->hw.ctmt &= ~2; 136762306a36Sopenharmony_ci hc->hw.conn &= ~0x18; 136862306a36Sopenharmony_ci } else { 136962306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[0] = 0; 137062306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; 137162306a36Sopenharmony_ci hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | 137262306a36Sopenharmony_ci HFCPCI_INTS_B1REC); 137362306a36Sopenharmony_ci hc->hw.ctmt &= ~1; 137462306a36Sopenharmony_ci hc->hw.conn &= ~0x03; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci test_and_set_bit(FLG_HDLC, &bch->Flags); 137762306a36Sopenharmony_ci break; 137862306a36Sopenharmony_ci default: 137962306a36Sopenharmony_ci printk(KERN_DEBUG "prot not known %x\n", protocol); 138062306a36Sopenharmony_ci return -ENOPROTOOPT; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci if (test_bit(HFC_CFG_PCM, &hc->cfg)) { 138362306a36Sopenharmony_ci if ((protocol == ISDN_P_NONE) || 138462306a36Sopenharmony_ci (protocol == -1)) { /* init case */ 138562306a36Sopenharmony_ci rx_slot = 0; 138662306a36Sopenharmony_ci tx_slot = 0; 138762306a36Sopenharmony_ci } else { 138862306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { 138962306a36Sopenharmony_ci rx_slot |= 0xC0; 139062306a36Sopenharmony_ci tx_slot |= 0xC0; 139162306a36Sopenharmony_ci } else { 139262306a36Sopenharmony_ci rx_slot |= 0x80; 139362306a36Sopenharmony_ci tx_slot |= 0x80; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci if (bc & 2) { 139762306a36Sopenharmony_ci hc->hw.conn &= 0xc7; 139862306a36Sopenharmony_ci hc->hw.conn |= 0x08; 139962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", 140062306a36Sopenharmony_ci __func__, tx_slot); 140162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", 140262306a36Sopenharmony_ci __func__, rx_slot); 140362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); 140462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); 140562306a36Sopenharmony_ci } else { 140662306a36Sopenharmony_ci hc->hw.conn &= 0xf8; 140762306a36Sopenharmony_ci hc->hw.conn |= 0x01; 140862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", 140962306a36Sopenharmony_ci __func__, tx_slot); 141062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", 141162306a36Sopenharmony_ci __func__, rx_slot); 141262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); 141362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); 141762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 141862306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 141962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); 142062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 142162306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 142262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 142362306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 142462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 142562306a36Sopenharmony_ci#endif 142662306a36Sopenharmony_ci return 0; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic int 143062306a36Sopenharmony_ciset_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (bch->debug & DEBUG_HW_BCHANNEL) 143562306a36Sopenharmony_ci printk(KERN_DEBUG 143662306a36Sopenharmony_ci "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", 143762306a36Sopenharmony_ci bch->state, protocol, bch->nr, chan); 143862306a36Sopenharmony_ci if (bch->nr != chan) { 143962306a36Sopenharmony_ci printk(KERN_DEBUG 144062306a36Sopenharmony_ci "HFCPCI rxtest wrong channel parameter %x/%x\n", 144162306a36Sopenharmony_ci bch->nr, chan); 144262306a36Sopenharmony_ci return -EINVAL; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci switch (protocol) { 144562306a36Sopenharmony_ci case (ISDN_P_B_RAW): 144662306a36Sopenharmony_ci bch->state = protocol; 144762306a36Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); 144862306a36Sopenharmony_ci if (chan & 2) { 144962306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 145062306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; 145162306a36Sopenharmony_ci if (!tics) 145262306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B2REC; 145362306a36Sopenharmony_ci hc->hw.ctmt |= 2; 145462306a36Sopenharmony_ci hc->hw.conn &= ~0x18; 145562306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 145662306a36Sopenharmony_ci hc->hw.cirm |= 0x80; 145762306a36Sopenharmony_ci#endif 145862306a36Sopenharmony_ci } else { 145962306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 146062306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; 146162306a36Sopenharmony_ci if (!tics) 146262306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B1REC; 146362306a36Sopenharmony_ci hc->hw.ctmt |= 1; 146462306a36Sopenharmony_ci hc->hw.conn &= ~0x03; 146562306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 146662306a36Sopenharmony_ci hc->hw.cirm |= 0x40; 146762306a36Sopenharmony_ci#endif 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci break; 147062306a36Sopenharmony_ci case (ISDN_P_B_HDLC): 147162306a36Sopenharmony_ci bch->state = protocol; 147262306a36Sopenharmony_ci hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); 147362306a36Sopenharmony_ci if (chan & 2) { 147462306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B2_ENA; 147562306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[1] = 0; 147662306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; 147762306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B2REC; 147862306a36Sopenharmony_ci hc->hw.ctmt &= ~2; 147962306a36Sopenharmony_ci hc->hw.conn &= ~0x18; 148062306a36Sopenharmony_ci } else { 148162306a36Sopenharmony_ci hc->hw.sctrl_r |= SCTRL_B1_ENA; 148262306a36Sopenharmony_ci hc->hw.last_bfifo_cnt[0] = 0; 148362306a36Sopenharmony_ci hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; 148462306a36Sopenharmony_ci hc->hw.int_m1 |= HFCPCI_INTS_B1REC; 148562306a36Sopenharmony_ci hc->hw.ctmt &= ~1; 148662306a36Sopenharmony_ci hc->hw.conn &= ~0x03; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci break; 148962306a36Sopenharmony_ci default: 149062306a36Sopenharmony_ci printk(KERN_DEBUG "prot not known %x\n", protocol); 149162306a36Sopenharmony_ci return -ENOPROTOOPT; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 149462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); 149562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); 149662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); 149762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 149862306a36Sopenharmony_ci#ifdef REVERSE_BITORDER 149962306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); 150062306a36Sopenharmony_ci#endif 150162306a36Sopenharmony_ci return 0; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic void 150562306a36Sopenharmony_cideactivate_bchannel(struct bchannel *bch) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 150862306a36Sopenharmony_ci u_long flags; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 151162306a36Sopenharmony_ci mISDN_clear_bchannel(bch); 151262306a36Sopenharmony_ci mode_hfcpci(bch, bch->nr, ISDN_P_NONE); 151362306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci/* 151762306a36Sopenharmony_ci * Layer 1 B-channel hardware access 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_cistatic int 152062306a36Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_cistatic int 152562306a36Sopenharmony_cihfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 152862306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 152962306a36Sopenharmony_ci int ret = -EINVAL; 153062306a36Sopenharmony_ci u_long flags; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (bch->debug & DEBUG_HW) 153362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); 153462306a36Sopenharmony_ci switch (cmd) { 153562306a36Sopenharmony_ci case HW_TESTRX_RAW: 153662306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 153762306a36Sopenharmony_ci ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); 153862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 153962306a36Sopenharmony_ci break; 154062306a36Sopenharmony_ci case HW_TESTRX_HDLC: 154162306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 154262306a36Sopenharmony_ci ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); 154362306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci case HW_TESTRX_OFF: 154662306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 154762306a36Sopenharmony_ci mode_hfcpci(bch, bch->nr, ISDN_P_NONE); 154862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 154962306a36Sopenharmony_ci ret = 0; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci case CLOSE_CHANNEL: 155262306a36Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 155362306a36Sopenharmony_ci deactivate_bchannel(bch); 155462306a36Sopenharmony_ci ch->protocol = ISDN_P_NONE; 155562306a36Sopenharmony_ci ch->peer = NULL; 155662306a36Sopenharmony_ci module_put(THIS_MODULE); 155762306a36Sopenharmony_ci ret = 0; 155862306a36Sopenharmony_ci break; 155962306a36Sopenharmony_ci case CONTROL_CHANNEL: 156062306a36Sopenharmony_ci ret = channel_bctrl(bch, arg); 156162306a36Sopenharmony_ci break; 156262306a36Sopenharmony_ci default: 156362306a36Sopenharmony_ci printk(KERN_WARNING "%s: unknown prim(%x)\n", 156462306a36Sopenharmony_ci __func__, cmd); 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci return ret; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci/* 157062306a36Sopenharmony_ci * Layer2 -> Layer 1 Dchannel data 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_cistatic int 157362306a36Sopenharmony_cihfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 157662306a36Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 157762306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 157862306a36Sopenharmony_ci int ret = -EINVAL; 157962306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 158062306a36Sopenharmony_ci unsigned int id; 158162306a36Sopenharmony_ci u_long flags; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci switch (hh->prim) { 158462306a36Sopenharmony_ci case PH_DATA_REQ: 158562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 158662306a36Sopenharmony_ci ret = dchannel_senddata(dch, skb); 158762306a36Sopenharmony_ci if (ret > 0) { /* direct TX */ 158862306a36Sopenharmony_ci id = hh->id; /* skb can be freed */ 158962306a36Sopenharmony_ci hfcpci_fill_dfifo(dch->hw); 159062306a36Sopenharmony_ci ret = 0; 159162306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 159262306a36Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 159362306a36Sopenharmony_ci } else 159462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 159562306a36Sopenharmony_ci return ret; 159662306a36Sopenharmony_ci case PH_ACTIVATE_REQ: 159762306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 159862306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 159962306a36Sopenharmony_ci ret = 0; 160062306a36Sopenharmony_ci if (test_bit(HFC_CFG_MASTER, &hc->cfg)) 160162306a36Sopenharmony_ci hc->hw.mst_m |= HFCPCI_MASTER; 160262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 160362306a36Sopenharmony_ci if (test_bit(FLG_ACTIVE, &dch->Flags)) { 160462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 160562306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 160662306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 160762306a36Sopenharmony_ci break; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); 161062306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | 161162306a36Sopenharmony_ci HFCPCI_DO_ACTION | 1); 161262306a36Sopenharmony_ci } else 161362306a36Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 161462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 161562306a36Sopenharmony_ci break; 161662306a36Sopenharmony_ci case PH_DEACTIVATE_REQ: 161762306a36Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 161862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 161962306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_NT_S0) { 162062306a36Sopenharmony_ci struct sk_buff_head free_queue; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci __skb_queue_head_init(&free_queue); 162362306a36Sopenharmony_ci /* prepare deactivation */ 162462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_STATES, 0x40); 162562306a36Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 162662306a36Sopenharmony_ci if (dch->tx_skb) { 162762306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 162862306a36Sopenharmony_ci dch->tx_skb = NULL; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci dch->tx_idx = 0; 163162306a36Sopenharmony_ci if (dch->rx_skb) { 163262306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 163362306a36Sopenharmony_ci dch->rx_skb = NULL; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 163662306a36Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 163762306a36Sopenharmony_ci del_timer(&dch->timer); 163862306a36Sopenharmony_ci#ifdef FIXME 163962306a36Sopenharmony_ci if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 164062306a36Sopenharmony_ci dchannel_sched_event(&hc->dch, D_CLEARBUSY); 164162306a36Sopenharmony_ci#endif 164262306a36Sopenharmony_ci hc->hw.mst_m &= ~HFCPCI_MASTER; 164362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 164462306a36Sopenharmony_ci ret = 0; 164562306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 164662306a36Sopenharmony_ci __skb_queue_purge(&free_queue); 164762306a36Sopenharmony_ci } else { 164862306a36Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 164962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci break; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci if (!ret) 165462306a36Sopenharmony_ci dev_kfree_skb(skb); 165562306a36Sopenharmony_ci return ret; 165662306a36Sopenharmony_ci} 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci/* 165962306a36Sopenharmony_ci * Layer2 -> Layer 1 Bchannel data 166062306a36Sopenharmony_ci */ 166162306a36Sopenharmony_cistatic int 166262306a36Sopenharmony_cihfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 166562306a36Sopenharmony_ci struct hfc_pci *hc = bch->hw; 166662306a36Sopenharmony_ci int ret = -EINVAL; 166762306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 166862306a36Sopenharmony_ci unsigned long flags; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci switch (hh->prim) { 167162306a36Sopenharmony_ci case PH_DATA_REQ: 167262306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 167362306a36Sopenharmony_ci ret = bchannel_senddata(bch, skb); 167462306a36Sopenharmony_ci if (ret > 0) { /* direct TX */ 167562306a36Sopenharmony_ci hfcpci_fill_fifo(bch); 167662306a36Sopenharmony_ci ret = 0; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 167962306a36Sopenharmony_ci return ret; 168062306a36Sopenharmony_ci case PH_ACTIVATE_REQ: 168162306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 168262306a36Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 168362306a36Sopenharmony_ci ret = mode_hfcpci(bch, bch->nr, ch->protocol); 168462306a36Sopenharmony_ci else 168562306a36Sopenharmony_ci ret = 0; 168662306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 168762306a36Sopenharmony_ci if (!ret) 168862306a36Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 168962306a36Sopenharmony_ci NULL, GFP_KERNEL); 169062306a36Sopenharmony_ci break; 169162306a36Sopenharmony_ci case PH_DEACTIVATE_REQ: 169262306a36Sopenharmony_ci deactivate_bchannel(bch); 169362306a36Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 169462306a36Sopenharmony_ci NULL, GFP_KERNEL); 169562306a36Sopenharmony_ci ret = 0; 169662306a36Sopenharmony_ci break; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci if (!ret) 169962306a36Sopenharmony_ci dev_kfree_skb(skb); 170062306a36Sopenharmony_ci return ret; 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci/* 170462306a36Sopenharmony_ci * called for card init message 170562306a36Sopenharmony_ci */ 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_cistatic void 170862306a36Sopenharmony_ciinithfcpci(struct hfc_pci *hc) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci printk(KERN_DEBUG "inithfcpci: entered\n"); 171162306a36Sopenharmony_ci timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0); 171262306a36Sopenharmony_ci hc->chanlimit = 2; 171362306a36Sopenharmony_ci mode_hfcpci(&hc->bch[0], 1, -1); 171462306a36Sopenharmony_ci mode_hfcpci(&hc->bch[1], 2, -1); 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_cistatic int 171962306a36Sopenharmony_ciinit_card(struct hfc_pci *hc) 172062306a36Sopenharmony_ci{ 172162306a36Sopenharmony_ci int cnt = 3; 172262306a36Sopenharmony_ci u_long flags; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci printk(KERN_DEBUG "init_card: entered\n"); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 172862306a36Sopenharmony_ci disable_hwirq(hc); 172962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 173062306a36Sopenharmony_ci if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { 173162306a36Sopenharmony_ci printk(KERN_WARNING 173262306a36Sopenharmony_ci "mISDN: couldn't get interrupt %d\n", hc->irq); 173362306a36Sopenharmony_ci return -EIO; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 173662306a36Sopenharmony_ci reset_hfcpci(hc); 173762306a36Sopenharmony_ci while (cnt) { 173862306a36Sopenharmony_ci inithfcpci(hc); 173962306a36Sopenharmony_ci /* 174062306a36Sopenharmony_ci * Finally enable IRQ output 174162306a36Sopenharmony_ci * this is only allowed, if an IRQ routine is already 174262306a36Sopenharmony_ci * established for this HFC, so don't do that earlier 174362306a36Sopenharmony_ci */ 174462306a36Sopenharmony_ci enable_hwirq(hc); 174562306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 174662306a36Sopenharmony_ci /* Timeout 80ms */ 174762306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 174862306a36Sopenharmony_ci schedule_timeout((80 * HZ) / 1000); 174962306a36Sopenharmony_ci printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", 175062306a36Sopenharmony_ci hc->irq, hc->irqcnt); 175162306a36Sopenharmony_ci /* now switch timer interrupt off */ 175262306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 175362306a36Sopenharmony_ci hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; 175462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 175562306a36Sopenharmony_ci /* reinit mode reg */ 175662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); 175762306a36Sopenharmony_ci if (!hc->irqcnt) { 175862306a36Sopenharmony_ci printk(KERN_WARNING 175962306a36Sopenharmony_ci "HFC PCI: IRQ(%d) getting no interrupts " 176062306a36Sopenharmony_ci "during init %d\n", hc->irq, 4 - cnt); 176162306a36Sopenharmony_ci if (cnt == 1) 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci else { 176462306a36Sopenharmony_ci reset_hfcpci(hc); 176562306a36Sopenharmony_ci cnt--; 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci } else { 176862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 176962306a36Sopenharmony_ci hc->initdone = 1; 177062306a36Sopenharmony_ci return 0; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci disable_hwirq(hc); 177462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 177562306a36Sopenharmony_ci free_irq(hc->irq, hc); 177662306a36Sopenharmony_ci return -EIO; 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cistatic int 178062306a36Sopenharmony_cichannel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci int ret = 0; 178362306a36Sopenharmony_ci u_char slot; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci switch (cq->op) { 178662306a36Sopenharmony_ci case MISDN_CTRL_GETOP: 178762306a36Sopenharmony_ci cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | 178862306a36Sopenharmony_ci MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3; 178962306a36Sopenharmony_ci break; 179062306a36Sopenharmony_ci case MISDN_CTRL_LOOP: 179162306a36Sopenharmony_ci /* channel 0 disabled loop */ 179262306a36Sopenharmony_ci if (cq->channel < 0 || cq->channel > 2) { 179362306a36Sopenharmony_ci ret = -EINVAL; 179462306a36Sopenharmony_ci break; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci if (cq->channel & 1) { 179762306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 179862306a36Sopenharmony_ci slot = 0xC0; 179962306a36Sopenharmony_ci else 180062306a36Sopenharmony_ci slot = 0x80; 180162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", 180262306a36Sopenharmony_ci __func__, slot); 180362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, slot); 180462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, slot); 180562306a36Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~7) | 6; 180662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci if (cq->channel & 2) { 180962306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 181062306a36Sopenharmony_ci slot = 0xC1; 181162306a36Sopenharmony_ci else 181262306a36Sopenharmony_ci slot = 0x81; 181362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", 181462306a36Sopenharmony_ci __func__, slot); 181562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, slot); 181662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, slot); 181762306a36Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; 181862306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci if (cq->channel & 3) 182162306a36Sopenharmony_ci hc->hw.trm |= 0x80; /* enable IOM-loop */ 182262306a36Sopenharmony_ci else { 182362306a36Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; 182462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 182562306a36Sopenharmony_ci hc->hw.trm &= 0x7f; /* disable IOM-loop */ 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 182862306a36Sopenharmony_ci break; 182962306a36Sopenharmony_ci case MISDN_CTRL_CONNECT: 183062306a36Sopenharmony_ci if (cq->channel == cq->p1) { 183162306a36Sopenharmony_ci ret = -EINVAL; 183262306a36Sopenharmony_ci break; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci if (cq->channel < 1 || cq->channel > 2 || 183562306a36Sopenharmony_ci cq->p1 < 1 || cq->p1 > 2) { 183662306a36Sopenharmony_ci ret = -EINVAL; 183762306a36Sopenharmony_ci break; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 184062306a36Sopenharmony_ci slot = 0xC0; 184162306a36Sopenharmony_ci else 184262306a36Sopenharmony_ci slot = 0x80; 184362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", 184462306a36Sopenharmony_ci __func__, slot); 184562306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_SSL, slot); 184662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_RSL, slot); 184762306a36Sopenharmony_ci if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) 184862306a36Sopenharmony_ci slot = 0xC1; 184962306a36Sopenharmony_ci else 185062306a36Sopenharmony_ci slot = 0x81; 185162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", 185262306a36Sopenharmony_ci __func__, slot); 185362306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B2_SSL, slot); 185462306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_B1_RSL, slot); 185562306a36Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; 185662306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 185762306a36Sopenharmony_ci hc->hw.trm |= 0x80; 185862306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); 185962306a36Sopenharmony_ci break; 186062306a36Sopenharmony_ci case MISDN_CTRL_DISCONNECT: 186162306a36Sopenharmony_ci hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; 186262306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); 186362306a36Sopenharmony_ci hc->hw.trm &= 0x7f; /* disable IOM-loop */ 186462306a36Sopenharmony_ci break; 186562306a36Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 186662306a36Sopenharmony_ci ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); 186762306a36Sopenharmony_ci break; 186862306a36Sopenharmony_ci default: 186962306a36Sopenharmony_ci printk(KERN_WARNING "%s: unknown Op %x\n", 187062306a36Sopenharmony_ci __func__, cq->op); 187162306a36Sopenharmony_ci ret = -EINVAL; 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci return ret; 187562306a36Sopenharmony_ci} 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic int 187862306a36Sopenharmony_ciopen_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, 187962306a36Sopenharmony_ci struct channel_req *rq) 188062306a36Sopenharmony_ci{ 188162306a36Sopenharmony_ci int err = 0; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 188462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, 188562306a36Sopenharmony_ci hc->dch.dev.id, __builtin_return_address(0)); 188662306a36Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 188762306a36Sopenharmony_ci return -EINVAL; 188862306a36Sopenharmony_ci if (rq->adr.channel == 1) { 188962306a36Sopenharmony_ci /* TODO: E-Channel */ 189062306a36Sopenharmony_ci return -EINVAL; 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci if (!hc->initdone) { 189362306a36Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 189462306a36Sopenharmony_ci err = create_l1(&hc->dch, hfc_l1callback); 189562306a36Sopenharmony_ci if (err) 189662306a36Sopenharmony_ci return err; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci hc->hw.protocol = rq->protocol; 189962306a36Sopenharmony_ci ch->protocol = rq->protocol; 190062306a36Sopenharmony_ci err = init_card(hc); 190162306a36Sopenharmony_ci if (err) 190262306a36Sopenharmony_ci return err; 190362306a36Sopenharmony_ci } else { 190462306a36Sopenharmony_ci if (rq->protocol != ch->protocol) { 190562306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_TE_S0) 190662306a36Sopenharmony_ci l1_event(hc->dch.l1, CLOSE_CHANNEL); 190762306a36Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 190862306a36Sopenharmony_ci err = create_l1(&hc->dch, hfc_l1callback); 190962306a36Sopenharmony_ci if (err) 191062306a36Sopenharmony_ci return err; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci hc->hw.protocol = rq->protocol; 191362306a36Sopenharmony_ci ch->protocol = rq->protocol; 191462306a36Sopenharmony_ci hfcpci_setmode(hc); 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || 191962306a36Sopenharmony_ci ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { 192062306a36Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 192162306a36Sopenharmony_ci 0, NULL, GFP_KERNEL); 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci rq->ch = ch; 192462306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 192562306a36Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 192662306a36Sopenharmony_ci return 0; 192762306a36Sopenharmony_ci} 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_cistatic int 193062306a36Sopenharmony_ciopen_bchannel(struct hfc_pci *hc, struct channel_req *rq) 193162306a36Sopenharmony_ci{ 193262306a36Sopenharmony_ci struct bchannel *bch; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 193562306a36Sopenharmony_ci return -EINVAL; 193662306a36Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 193762306a36Sopenharmony_ci return -EINVAL; 193862306a36Sopenharmony_ci bch = &hc->bch[rq->adr.channel - 1]; 193962306a36Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 194062306a36Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 194162306a36Sopenharmony_ci bch->ch.protocol = rq->protocol; 194262306a36Sopenharmony_ci rq->ch = &bch->ch; /* TODO: E-channel */ 194362306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 194462306a36Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 194562306a36Sopenharmony_ci return 0; 194662306a36Sopenharmony_ci} 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci/* 194962306a36Sopenharmony_ci * device control function 195062306a36Sopenharmony_ci */ 195162306a36Sopenharmony_cistatic int 195262306a36Sopenharmony_cihfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 195362306a36Sopenharmony_ci{ 195462306a36Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 195562306a36Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 195662306a36Sopenharmony_ci struct hfc_pci *hc = dch->hw; 195762306a36Sopenharmony_ci struct channel_req *rq; 195862306a36Sopenharmony_ci int err = 0; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 196162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 196262306a36Sopenharmony_ci __func__, cmd, arg); 196362306a36Sopenharmony_ci switch (cmd) { 196462306a36Sopenharmony_ci case OPEN_CHANNEL: 196562306a36Sopenharmony_ci rq = arg; 196662306a36Sopenharmony_ci if ((rq->protocol == ISDN_P_TE_S0) || 196762306a36Sopenharmony_ci (rq->protocol == ISDN_P_NT_S0)) 196862306a36Sopenharmony_ci err = open_dchannel(hc, ch, rq); 196962306a36Sopenharmony_ci else 197062306a36Sopenharmony_ci err = open_bchannel(hc, rq); 197162306a36Sopenharmony_ci break; 197262306a36Sopenharmony_ci case CLOSE_CHANNEL: 197362306a36Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 197462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) close from %p\n", 197562306a36Sopenharmony_ci __func__, hc->dch.dev.id, 197662306a36Sopenharmony_ci __builtin_return_address(0)); 197762306a36Sopenharmony_ci module_put(THIS_MODULE); 197862306a36Sopenharmony_ci break; 197962306a36Sopenharmony_ci case CONTROL_CHANNEL: 198062306a36Sopenharmony_ci err = channel_ctrl(hc, arg); 198162306a36Sopenharmony_ci break; 198262306a36Sopenharmony_ci default: 198362306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 198462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 198562306a36Sopenharmony_ci __func__, cmd); 198662306a36Sopenharmony_ci return -EINVAL; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci return err; 198962306a36Sopenharmony_ci} 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic int 199262306a36Sopenharmony_cisetup_hw(struct hfc_pci *hc) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci void *buffer; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); 199762306a36Sopenharmony_ci hc->hw.cirm = 0; 199862306a36Sopenharmony_ci hc->dch.state = 0; 199962306a36Sopenharmony_ci pci_set_master(hc->pdev); 200062306a36Sopenharmony_ci if (!hc->irq) { 200162306a36Sopenharmony_ci printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); 200262306a36Sopenharmony_ci return -EINVAL; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci hc->hw.pci_io = 200562306a36Sopenharmony_ci (char __iomem *)(unsigned long)hc->pdev->resource[1].start; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (!hc->hw.pci_io) { 200862306a36Sopenharmony_ci printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); 200962306a36Sopenharmony_ci return -ENOMEM; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci /* Allocate memory for FIFOS */ 201262306a36Sopenharmony_ci /* the memory needs to be on a 32k boundary within the first 4G */ 201362306a36Sopenharmony_ci if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) { 201462306a36Sopenharmony_ci printk(KERN_WARNING 201562306a36Sopenharmony_ci "HFC-PCI: No usable DMA configuration!\n"); 201662306a36Sopenharmony_ci return -EIO; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle, 201962306a36Sopenharmony_ci GFP_KERNEL); 202062306a36Sopenharmony_ci /* We silently assume the address is okay if nonzero */ 202162306a36Sopenharmony_ci if (!buffer) { 202262306a36Sopenharmony_ci printk(KERN_WARNING 202362306a36Sopenharmony_ci "HFC-PCI: Error allocating memory for FIFO!\n"); 202462306a36Sopenharmony_ci return -ENOMEM; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci hc->hw.fifos = buffer; 202762306a36Sopenharmony_ci pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); 202862306a36Sopenharmony_ci hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); 202962306a36Sopenharmony_ci if (unlikely(!hc->hw.pci_io)) { 203062306a36Sopenharmony_ci printk(KERN_WARNING 203162306a36Sopenharmony_ci "HFC-PCI: Error in ioremap for PCI!\n"); 203262306a36Sopenharmony_ci dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos, 203362306a36Sopenharmony_ci hc->hw.dmahandle); 203462306a36Sopenharmony_ci return -ENOMEM; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci printk(KERN_INFO 203862306a36Sopenharmony_ci "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n", 203962306a36Sopenharmony_ci (u_long) hc->hw.pci_io, hc->hw.fifos, 204062306a36Sopenharmony_ci &hc->hw.dmahandle, hc->irq, HZ); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci /* enable memory mapped ports, disable busmaster */ 204362306a36Sopenharmony_ci pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); 204462306a36Sopenharmony_ci hc->hw.int_m2 = 0; 204562306a36Sopenharmony_ci disable_hwirq(hc); 204662306a36Sopenharmony_ci hc->hw.int_m1 = 0; 204762306a36Sopenharmony_ci Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); 204862306a36Sopenharmony_ci /* At this point the needed PCI config is done */ 204962306a36Sopenharmony_ci /* fifos are still not enabled */ 205062306a36Sopenharmony_ci timer_setup(&hc->hw.timer, hfcpci_Timer, 0); 205162306a36Sopenharmony_ci /* default PCM master */ 205262306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); 205362306a36Sopenharmony_ci return 0; 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_cistatic void 205762306a36Sopenharmony_cirelease_card(struct hfc_pci *hc) { 205862306a36Sopenharmony_ci u_long flags; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 206162306a36Sopenharmony_ci hc->hw.int_m2 = 0; /* interrupt output off ! */ 206262306a36Sopenharmony_ci disable_hwirq(hc); 206362306a36Sopenharmony_ci mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); 206462306a36Sopenharmony_ci mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); 206562306a36Sopenharmony_ci if (hc->dch.timer.function != NULL) { 206662306a36Sopenharmony_ci del_timer(&hc->dch.timer); 206762306a36Sopenharmony_ci hc->dch.timer.function = NULL; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 207062306a36Sopenharmony_ci if (hc->hw.protocol == ISDN_P_TE_S0) 207162306a36Sopenharmony_ci l1_event(hc->dch.l1, CLOSE_CHANNEL); 207262306a36Sopenharmony_ci if (hc->initdone) 207362306a36Sopenharmony_ci free_irq(hc->irq, hc); 207462306a36Sopenharmony_ci release_io_hfcpci(hc); /* must release after free_irq! */ 207562306a36Sopenharmony_ci mISDN_unregister_device(&hc->dch.dev); 207662306a36Sopenharmony_ci mISDN_freebchannel(&hc->bch[1]); 207762306a36Sopenharmony_ci mISDN_freebchannel(&hc->bch[0]); 207862306a36Sopenharmony_ci mISDN_freedchannel(&hc->dch); 207962306a36Sopenharmony_ci pci_set_drvdata(hc->pdev, NULL); 208062306a36Sopenharmony_ci kfree(hc); 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_cistatic int 208462306a36Sopenharmony_cisetup_card(struct hfc_pci *card) 208562306a36Sopenharmony_ci{ 208662306a36Sopenharmony_ci int err = -EINVAL; 208762306a36Sopenharmony_ci u_int i; 208862306a36Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci card->dch.debug = debug; 209162306a36Sopenharmony_ci spin_lock_init(&card->lock); 209262306a36Sopenharmony_ci mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); 209362306a36Sopenharmony_ci card->dch.hw = card; 209462306a36Sopenharmony_ci card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); 209562306a36Sopenharmony_ci card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 209662306a36Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 209762306a36Sopenharmony_ci card->dch.dev.D.send = hfcpci_l2l1D; 209862306a36Sopenharmony_ci card->dch.dev.D.ctrl = hfc_dctrl; 209962306a36Sopenharmony_ci card->dch.dev.nrbchan = 2; 210062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 210162306a36Sopenharmony_ci card->bch[i].nr = i + 1; 210262306a36Sopenharmony_ci set_channelmap(i + 1, card->dch.dev.channelmap); 210362306a36Sopenharmony_ci card->bch[i].debug = debug; 210462306a36Sopenharmony_ci mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); 210562306a36Sopenharmony_ci card->bch[i].hw = card; 210662306a36Sopenharmony_ci card->bch[i].ch.send = hfcpci_l2l1B; 210762306a36Sopenharmony_ci card->bch[i].ch.ctrl = hfc_bctrl; 210862306a36Sopenharmony_ci card->bch[i].ch.nr = i + 1; 210962306a36Sopenharmony_ci list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci err = setup_hw(card); 211262306a36Sopenharmony_ci if (err) 211362306a36Sopenharmony_ci goto error; 211462306a36Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); 211562306a36Sopenharmony_ci err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); 211662306a36Sopenharmony_ci if (err) 211762306a36Sopenharmony_ci goto error; 211862306a36Sopenharmony_ci HFC_cnt++; 211962306a36Sopenharmony_ci printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); 212062306a36Sopenharmony_ci return 0; 212162306a36Sopenharmony_cierror: 212262306a36Sopenharmony_ci mISDN_freebchannel(&card->bch[1]); 212362306a36Sopenharmony_ci mISDN_freebchannel(&card->bch[0]); 212462306a36Sopenharmony_ci mISDN_freedchannel(&card->dch); 212562306a36Sopenharmony_ci kfree(card); 212662306a36Sopenharmony_ci return err; 212762306a36Sopenharmony_ci} 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci/* private data in the PCI devices list */ 213062306a36Sopenharmony_cistruct _hfc_map { 213162306a36Sopenharmony_ci u_int subtype; 213262306a36Sopenharmony_ci u_int flag; 213362306a36Sopenharmony_ci char *name; 213462306a36Sopenharmony_ci}; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_cistatic const struct _hfc_map hfc_map[] = 213762306a36Sopenharmony_ci{ 213862306a36Sopenharmony_ci {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, 213962306a36Sopenharmony_ci {HFC_CCD_B000, 0, "Billion B000"}, 214062306a36Sopenharmony_ci {HFC_CCD_B006, 0, "Billion B006"}, 214162306a36Sopenharmony_ci {HFC_CCD_B007, 0, "Billion B007"}, 214262306a36Sopenharmony_ci {HFC_CCD_B008, 0, "Billion B008"}, 214362306a36Sopenharmony_ci {HFC_CCD_B009, 0, "Billion B009"}, 214462306a36Sopenharmony_ci {HFC_CCD_B00A, 0, "Billion B00A"}, 214562306a36Sopenharmony_ci {HFC_CCD_B00B, 0, "Billion B00B"}, 214662306a36Sopenharmony_ci {HFC_CCD_B00C, 0, "Billion B00C"}, 214762306a36Sopenharmony_ci {HFC_CCD_B100, 0, "Seyeon B100"}, 214862306a36Sopenharmony_ci {HFC_CCD_B700, 0, "Primux II S0 B700"}, 214962306a36Sopenharmony_ci {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, 215062306a36Sopenharmony_ci {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, 215162306a36Sopenharmony_ci {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, 215262306a36Sopenharmony_ci {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, 215362306a36Sopenharmony_ci {HFC_BERKOM_A1T, 0, "German telekom A1T"}, 215462306a36Sopenharmony_ci {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, 215562306a36Sopenharmony_ci {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, 215662306a36Sopenharmony_ci {HFC_DIGI_DF_M_IOM2_E, 0, 215762306a36Sopenharmony_ci "Digi International DataFire Micro V IOM2 (Europe)"}, 215862306a36Sopenharmony_ci {HFC_DIGI_DF_M_E, 0, 215962306a36Sopenharmony_ci "Digi International DataFire Micro V (Europe)"}, 216062306a36Sopenharmony_ci {HFC_DIGI_DF_M_IOM2_A, 0, 216162306a36Sopenharmony_ci "Digi International DataFire Micro V IOM2 (North America)"}, 216262306a36Sopenharmony_ci {HFC_DIGI_DF_M_A, 0, 216362306a36Sopenharmony_ci "Digi International DataFire Micro V (North America)"}, 216462306a36Sopenharmony_ci {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, 216562306a36Sopenharmony_ci {}, 216662306a36Sopenharmony_ci}; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_cistatic const struct pci_device_id hfc_ids[] = 216962306a36Sopenharmony_ci{ 217062306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0), 217162306a36Sopenharmony_ci (unsigned long) &hfc_map[0] }, 217262306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000), 217362306a36Sopenharmony_ci (unsigned long) &hfc_map[1] }, 217462306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006), 217562306a36Sopenharmony_ci (unsigned long) &hfc_map[2] }, 217662306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007), 217762306a36Sopenharmony_ci (unsigned long) &hfc_map[3] }, 217862306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008), 217962306a36Sopenharmony_ci (unsigned long) &hfc_map[4] }, 218062306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009), 218162306a36Sopenharmony_ci (unsigned long) &hfc_map[5] }, 218262306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A), 218362306a36Sopenharmony_ci (unsigned long) &hfc_map[6] }, 218462306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B), 218562306a36Sopenharmony_ci (unsigned long) &hfc_map[7] }, 218662306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C), 218762306a36Sopenharmony_ci (unsigned long) &hfc_map[8] }, 218862306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100), 218962306a36Sopenharmony_ci (unsigned long) &hfc_map[9] }, 219062306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700), 219162306a36Sopenharmony_ci (unsigned long) &hfc_map[10] }, 219262306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701), 219362306a36Sopenharmony_ci (unsigned long) &hfc_map[11] }, 219462306a36Sopenharmony_ci { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1), 219562306a36Sopenharmony_ci (unsigned long) &hfc_map[12] }, 219662306a36Sopenharmony_ci { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675), 219762306a36Sopenharmony_ci (unsigned long) &hfc_map[13] }, 219862306a36Sopenharmony_ci { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT), 219962306a36Sopenharmony_ci (unsigned long) &hfc_map[14] }, 220062306a36Sopenharmony_ci { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T), 220162306a36Sopenharmony_ci (unsigned long) &hfc_map[15] }, 220262306a36Sopenharmony_ci { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575), 220362306a36Sopenharmony_ci (unsigned long) &hfc_map[16] }, 220462306a36Sopenharmony_ci { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0), 220562306a36Sopenharmony_ci (unsigned long) &hfc_map[17] }, 220662306a36Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E), 220762306a36Sopenharmony_ci (unsigned long) &hfc_map[18] }, 220862306a36Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E), 220962306a36Sopenharmony_ci (unsigned long) &hfc_map[19] }, 221062306a36Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A), 221162306a36Sopenharmony_ci (unsigned long) &hfc_map[20] }, 221262306a36Sopenharmony_ci { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A), 221362306a36Sopenharmony_ci (unsigned long) &hfc_map[21] }, 221462306a36Sopenharmony_ci { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2), 221562306a36Sopenharmony_ci (unsigned long) &hfc_map[22] }, 221662306a36Sopenharmony_ci {}, 221762306a36Sopenharmony_ci}; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_cistatic int 222062306a36Sopenharmony_cihfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 222162306a36Sopenharmony_ci{ 222262306a36Sopenharmony_ci int err = -ENOMEM; 222362306a36Sopenharmony_ci struct hfc_pci *card; 222462306a36Sopenharmony_ci struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci card = kzalloc(sizeof(struct hfc_pci), GFP_KERNEL); 222762306a36Sopenharmony_ci if (!card) { 222862306a36Sopenharmony_ci printk(KERN_ERR "No kmem for HFC card\n"); 222962306a36Sopenharmony_ci return err; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci card->pdev = pdev; 223262306a36Sopenharmony_ci card->subtype = m->subtype; 223362306a36Sopenharmony_ci err = pci_enable_device(pdev); 223462306a36Sopenharmony_ci if (err) { 223562306a36Sopenharmony_ci kfree(card); 223662306a36Sopenharmony_ci return err; 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", 224062306a36Sopenharmony_ci m->name, pci_name(pdev)); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci card->irq = pdev->irq; 224362306a36Sopenharmony_ci pci_set_drvdata(pdev, card); 224462306a36Sopenharmony_ci err = setup_card(card); 224562306a36Sopenharmony_ci if (err) 224662306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 224762306a36Sopenharmony_ci return err; 224862306a36Sopenharmony_ci} 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_cistatic void 225162306a36Sopenharmony_cihfc_remove_pci(struct pci_dev *pdev) 225262306a36Sopenharmony_ci{ 225362306a36Sopenharmony_ci struct hfc_pci *card = pci_get_drvdata(pdev); 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci if (card) 225662306a36Sopenharmony_ci release_card(card); 225762306a36Sopenharmony_ci else 225862306a36Sopenharmony_ci if (debug) 225962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: drvdata already removed\n", 226062306a36Sopenharmony_ci __func__); 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic struct pci_driver hfc_driver = { 226562306a36Sopenharmony_ci .name = "hfcpci", 226662306a36Sopenharmony_ci .probe = hfc_probe, 226762306a36Sopenharmony_ci .remove = hfc_remove_pci, 226862306a36Sopenharmony_ci .id_table = hfc_ids, 226962306a36Sopenharmony_ci}; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_cistatic int 227262306a36Sopenharmony_ci_hfcpci_softirq(struct device *dev, void *unused) 227362306a36Sopenharmony_ci{ 227462306a36Sopenharmony_ci struct hfc_pci *hc = dev_get_drvdata(dev); 227562306a36Sopenharmony_ci struct bchannel *bch; 227662306a36Sopenharmony_ci if (hc == NULL) 227762306a36Sopenharmony_ci return 0; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { 228062306a36Sopenharmony_ci spin_lock_irq(&hc->lock); 228162306a36Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); 228262306a36Sopenharmony_ci if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ 228362306a36Sopenharmony_ci main_rec_hfcpci(bch); 228462306a36Sopenharmony_ci tx_birq(bch); 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); 228762306a36Sopenharmony_ci if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ 228862306a36Sopenharmony_ci main_rec_hfcpci(bch); 228962306a36Sopenharmony_ci tx_birq(bch); 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci spin_unlock_irq(&hc->lock); 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci return 0; 229462306a36Sopenharmony_ci} 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_cistatic void 229762306a36Sopenharmony_cihfcpci_softirq(struct timer_list *unused) 229862306a36Sopenharmony_ci{ 229962306a36Sopenharmony_ci WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL, 230062306a36Sopenharmony_ci _hfcpci_softirq) != 0); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci /* if next event would be in the past ... */ 230362306a36Sopenharmony_ci if ((s32)(hfc_jiffies + tics - jiffies) <= 0) 230462306a36Sopenharmony_ci hfc_jiffies = jiffies + 1; 230562306a36Sopenharmony_ci else 230662306a36Sopenharmony_ci hfc_jiffies += tics; 230762306a36Sopenharmony_ci hfc_tl.expires = hfc_jiffies; 230862306a36Sopenharmony_ci add_timer(&hfc_tl); 230962306a36Sopenharmony_ci} 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_cistatic int __init 231262306a36Sopenharmony_ciHFC_init(void) 231362306a36Sopenharmony_ci{ 231462306a36Sopenharmony_ci int err; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (!poll) 231762306a36Sopenharmony_ci poll = HFCPCI_BTRANS_THRESHOLD; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci if (poll != HFCPCI_BTRANS_THRESHOLD) { 232062306a36Sopenharmony_ci tics = (poll * HZ) / 8000; 232162306a36Sopenharmony_ci if (tics < 1) 232262306a36Sopenharmony_ci tics = 1; 232362306a36Sopenharmony_ci poll = (tics * 8000) / HZ; 232462306a36Sopenharmony_ci if (poll > 256 || poll < 8) { 232562306a36Sopenharmony_ci printk(KERN_ERR "%s: Wrong poll value %d not in range " 232662306a36Sopenharmony_ci "of 8..256.\n", __func__, poll); 232762306a36Sopenharmony_ci err = -EINVAL; 232862306a36Sopenharmony_ci return err; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci } 233162306a36Sopenharmony_ci if (poll != HFCPCI_BTRANS_THRESHOLD) { 233262306a36Sopenharmony_ci printk(KERN_INFO "%s: Using alternative poll value of %d\n", 233362306a36Sopenharmony_ci __func__, poll); 233462306a36Sopenharmony_ci timer_setup(&hfc_tl, hfcpci_softirq, 0); 233562306a36Sopenharmony_ci hfc_tl.expires = jiffies + tics; 233662306a36Sopenharmony_ci hfc_jiffies = hfc_tl.expires; 233762306a36Sopenharmony_ci add_timer(&hfc_tl); 233862306a36Sopenharmony_ci } else 233962306a36Sopenharmony_ci tics = 0; /* indicate the use of controller's timer */ 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci err = pci_register_driver(&hfc_driver); 234262306a36Sopenharmony_ci if (err) { 234362306a36Sopenharmony_ci if (timer_pending(&hfc_tl)) 234462306a36Sopenharmony_ci del_timer(&hfc_tl); 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci return err; 234862306a36Sopenharmony_ci} 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_cistatic void __exit 235162306a36Sopenharmony_ciHFC_cleanup(void) 235262306a36Sopenharmony_ci{ 235362306a36Sopenharmony_ci del_timer_sync(&hfc_tl); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci pci_unregister_driver(&hfc_driver); 235662306a36Sopenharmony_ci} 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_cimodule_init(HFC_init); 235962306a36Sopenharmony_cimodule_exit(HFC_cleanup); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfc_ids); 2362