162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author Andreas Eversberg (jolly@eversberg.eu) 662306a36Sopenharmony_ci * ported to mqueue mechanism: 762306a36Sopenharmony_ci * Peter Sprenger (sprengermoving-bytes.de) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * inspired by existing hfc-pci driver: 1062306a36Sopenharmony_ci * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) 1162306a36Sopenharmony_ci * Copyright 2008 by Karsten Keil (kkeil@suse.de) 1262306a36Sopenharmony_ci * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu) 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Thanks to Cologne Chip AG for this great controller! 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * module parameters: 1962306a36Sopenharmony_ci * type: 2062306a36Sopenharmony_ci * By default (0), the card is automatically detected. 2162306a36Sopenharmony_ci * Or use the following combinations: 2262306a36Sopenharmony_ci * Bit 0-7 = 0x00001 = HFC-E1 (1 port) 2362306a36Sopenharmony_ci * or Bit 0-7 = 0x00004 = HFC-4S (4 ports) 2462306a36Sopenharmony_ci * or Bit 0-7 = 0x00008 = HFC-8S (8 ports) 2562306a36Sopenharmony_ci * Bit 8 = 0x00100 = uLaw (instead of aLaw) 2662306a36Sopenharmony_ci * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware 2762306a36Sopenharmony_ci * Bit 10 = spare 2862306a36Sopenharmony_ci * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) 2962306a36Sopenharmony_ci * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto) 3062306a36Sopenharmony_ci * Bit 13 = spare 3162306a36Sopenharmony_ci * Bit 14 = 0x04000 = Use external ram (128K) 3262306a36Sopenharmony_ci * Bit 15 = 0x08000 = Use external ram (512K) 3362306a36Sopenharmony_ci * Bit 16 = 0x10000 = Use 64 timeslots instead of 32 3462306a36Sopenharmony_ci * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else 3562306a36Sopenharmony_ci * Bit 18 = spare 3662306a36Sopenharmony_ci * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) 3762306a36Sopenharmony_ci * (all other bits are reserved and shall be 0) 3862306a36Sopenharmony_ci * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM 3962306a36Sopenharmony_ci * bus (PCM master) 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * port: (optional or required for all ports on all installed cards) 4262306a36Sopenharmony_ci * HFC-4S/HFC-8S only bits: 4362306a36Sopenharmony_ci * Bit 0 = 0x001 = Use master clock for this S/T interface 4462306a36Sopenharmony_ci * (ony once per chip). 4562306a36Sopenharmony_ci * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) 4662306a36Sopenharmony_ci * Don't use this unless you know what you are doing! 4762306a36Sopenharmony_ci * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) 4862306a36Sopenharmony_ci * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock 4962306a36Sopenharmony_ci * received from port 1 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * HFC-E1 only bits: 5262306a36Sopenharmony_ci * Bit 0 = 0x0001 = interface: 0=copper, 1=optical 5362306a36Sopenharmony_ci * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode) 5462306a36Sopenharmony_ci * Bit 2 = 0x0004 = Report LOS 5562306a36Sopenharmony_ci * Bit 3 = 0x0008 = Report AIS 5662306a36Sopenharmony_ci * Bit 4 = 0x0010 = Report SLIP 5762306a36Sopenharmony_ci * Bit 5 = 0x0020 = Report RDI 5862306a36Sopenharmony_ci * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame 5962306a36Sopenharmony_ci * mode instead. 6062306a36Sopenharmony_ci * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode. 6162306a36Sopenharmony_ci * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode. 6262306a36Sopenharmony_ci * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL. 6362306a36Sopenharmony_ci * (E1 only) 6462306a36Sopenharmony_ci * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 6562306a36Sopenharmony_ci * for default. 6662306a36Sopenharmony_ci * (all other bits are reserved and shall be 0) 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * debug: 6962306a36Sopenharmony_ci * NOTE: only one debug value must be given for all cards 7062306a36Sopenharmony_ci * enable debugging (see hfc_multi.h for debug options) 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * poll: 7362306a36Sopenharmony_ci * NOTE: only one poll value must be given for all cards 7462306a36Sopenharmony_ci * Give the number of samples for each fifo process. 7562306a36Sopenharmony_ci * By default 128 is used. Decrease to reduce delay, increase to 7662306a36Sopenharmony_ci * reduce cpu load. If unsure, don't mess with it! 7762306a36Sopenharmony_ci * Valid is 8, 16, 32, 64, 128, 256. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * pcm: 8062306a36Sopenharmony_ci * NOTE: only one pcm value must be given for every card. 8162306a36Sopenharmony_ci * The PCM bus id tells the mISDNdsp module about the connected PCM bus. 8262306a36Sopenharmony_ci * By default (0), the PCM bus id is 100 for the card that is PCM master. 8362306a36Sopenharmony_ci * If multiple cards are PCM master (because they are not interconnected), 8462306a36Sopenharmony_ci * each card with PCM master will have increasing PCM id. 8562306a36Sopenharmony_ci * All PCM busses with the same ID are expected to be connected and have 8662306a36Sopenharmony_ci * common time slots slots. 8762306a36Sopenharmony_ci * Only one chip of the PCM bus must be master, the others slave. 8862306a36Sopenharmony_ci * -1 means no support of PCM bus not even. 8962306a36Sopenharmony_ci * Omit this value, if all cards are interconnected or none is connected. 9062306a36Sopenharmony_ci * If unsure, don't give this parameter. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * dmask and bmask: 9362306a36Sopenharmony_ci * NOTE: One dmask value must be given for every HFC-E1 card. 9462306a36Sopenharmony_ci * If omitted, the E1 card has D-channel on time slot 16, which is default. 9562306a36Sopenharmony_ci * dmask is a 32 bit mask. The bit must be set for an alternate time slot. 9662306a36Sopenharmony_ci * If multiple bits are set, multiple virtual card fragments are created. 9762306a36Sopenharmony_ci * For each bit set, a bmask value must be given. Each bit on the bmask 9862306a36Sopenharmony_ci * value stands for a B-channel. The bmask may not overlap with dmask or 9962306a36Sopenharmony_ci * with other bmask values for that card. 10062306a36Sopenharmony_ci * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000 10162306a36Sopenharmony_ci * This will create one fragment with D-channel on slot 1 with 10262306a36Sopenharmony_ci * B-channels on slots 2..15, and a second fragment with D-channel 10362306a36Sopenharmony_ci * on slot 17 with B-channels on slot 18..31. Slot 16 is unused. 10462306a36Sopenharmony_ci * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will 10562306a36Sopenharmony_ci * not function. 10662306a36Sopenharmony_ci * Example: dmask=0x00000001 bmask=0xfffffffe 10762306a36Sopenharmony_ci * This will create a port with all 31 usable timeslots as 10862306a36Sopenharmony_ci * B-channels. 10962306a36Sopenharmony_ci * If no bits are set on bmask, no B-channel is created for that fragment. 11062306a36Sopenharmony_ci * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask) 11162306a36Sopenharmony_ci * This will create 31 ports with one D-channel only. 11262306a36Sopenharmony_ci * If you don't know how to use it, you don't need it! 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * iomode: 11562306a36Sopenharmony_ci * NOTE: only one mode value must be given for every card. 11662306a36Sopenharmony_ci * -> See hfc_multi.h for HFC_IO_MODE_* values 11762306a36Sopenharmony_ci * By default, the IO mode is pci memory IO (MEMIO). 11862306a36Sopenharmony_ci * Some cards require specific IO mode, so it cannot be changed. 11962306a36Sopenharmony_ci * It may be useful to set IO mode to register io (REGIO) to solve 12062306a36Sopenharmony_ci * PCI bridge problems. 12162306a36Sopenharmony_ci * If unsure, don't give this parameter. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * clockdelay_nt: 12462306a36Sopenharmony_ci * NOTE: only one clockdelay_nt value must be given once for all cards. 12562306a36Sopenharmony_ci * Give the value of the clock control register (A_ST_CLK_DLY) 12662306a36Sopenharmony_ci * of the S/T interfaces in NT mode. 12762306a36Sopenharmony_ci * This register is needed for the TBR3 certification, so don't change it. 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * clockdelay_te: 13062306a36Sopenharmony_ci * NOTE: only one clockdelay_te value must be given once 13162306a36Sopenharmony_ci * Give the value of the clock control register (A_ST_CLK_DLY) 13262306a36Sopenharmony_ci * of the S/T interfaces in TE mode. 13362306a36Sopenharmony_ci * This register is needed for the TBR3 certification, so don't change it. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * clock: 13662306a36Sopenharmony_ci * NOTE: only one clock value must be given once 13762306a36Sopenharmony_ci * Selects interface with clock source for mISDN and applications. 13862306a36Sopenharmony_ci * Set to card number starting with 1. Set to -1 to disable. 13962306a36Sopenharmony_ci * By default, the first card is used as clock source. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * hwid: 14262306a36Sopenharmony_ci * NOTE: only one hwid value must be given once 14362306a36Sopenharmony_ci * Enable special embedded devices with XHFC controllers. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * debug register access (never use this, it will flood your system log) 14862306a36Sopenharmony_ci * #define HFC_REGISTER_DEBUG 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define HFC_MULTI_VERSION "2.03" 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#include <linux/interrupt.h> 15462306a36Sopenharmony_ci#include <linux/module.h> 15562306a36Sopenharmony_ci#include <linux/slab.h> 15662306a36Sopenharmony_ci#include <linux/pci.h> 15762306a36Sopenharmony_ci#include <linux/delay.h> 15862306a36Sopenharmony_ci#include <linux/mISDNhw.h> 15962306a36Sopenharmony_ci#include <linux/mISDNdsp.h> 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci #define IRQCOUNT_DEBUG 16362306a36Sopenharmony_ci #define IRQ_DEBUG 16462306a36Sopenharmony_ci*/ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#include "hfc_multi.h" 16762306a36Sopenharmony_ci#ifdef ECHOPREP 16862306a36Sopenharmony_ci#include "gaintab.h" 16962306a36Sopenharmony_ci#endif 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define MAX_CARDS 8 17262306a36Sopenharmony_ci#define MAX_PORTS (8 * MAX_CARDS) 17362306a36Sopenharmony_ci#define MAX_FRAGS (32 * MAX_CARDS) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic LIST_HEAD(HFClist); 17662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(HFClock); /* global hfc list lock */ 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void ph_state_change(struct dchannel *); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic struct hfc_multi *syncmaster; 18162306a36Sopenharmony_cistatic int plxsd_master; /* if we have a master card (yet) */ 18262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define TYP_E1 1 18562306a36Sopenharmony_ci#define TYP_4S 4 18662306a36Sopenharmony_ci#define TYP_8S 8 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int poll_timer = 6; /* default = 128 samples = 16ms */ 18962306a36Sopenharmony_ci/* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ 19062306a36Sopenharmony_cistatic int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; 19162306a36Sopenharmony_ci#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ 19262306a36Sopenharmony_ci#define CLKDEL_NT 0x6c /* CLKDEL in NT mode 19362306a36Sopenharmony_ci (0x60 MUST be included!) */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ 19662306a36Sopenharmony_ci#define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ 19762306a36Sopenharmony_ci#define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * module stuff 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic uint type[MAX_CARDS]; 20462306a36Sopenharmony_cistatic int pcm[MAX_CARDS]; 20562306a36Sopenharmony_cistatic uint dmask[MAX_CARDS]; 20662306a36Sopenharmony_cistatic uint bmask[MAX_FRAGS]; 20762306a36Sopenharmony_cistatic uint iomode[MAX_CARDS]; 20862306a36Sopenharmony_cistatic uint port[MAX_PORTS]; 20962306a36Sopenharmony_cistatic uint debug; 21062306a36Sopenharmony_cistatic uint poll; 21162306a36Sopenharmony_cistatic int clock; 21262306a36Sopenharmony_cistatic uint timer; 21362306a36Sopenharmony_cistatic uint clockdelay_te = CLKDEL_TE; 21462306a36Sopenharmony_cistatic uint clockdelay_nt = CLKDEL_NT; 21562306a36Sopenharmony_ci#define HWID_NONE 0 21662306a36Sopenharmony_ci#define HWID_MINIP4 1 21762306a36Sopenharmony_ci#define HWID_MINIP8 2 21862306a36Sopenharmony_ci#define HWID_MINIP16 3 21962306a36Sopenharmony_cistatic uint hwid = HWID_NONE; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Eversberg"); 22462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 22562306a36Sopenharmony_ciMODULE_VERSION(HFC_MULTI_VERSION); 22662306a36Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 22762306a36Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR); 22862306a36Sopenharmony_cimodule_param(clock, int, S_IRUGO | S_IWUSR); 22962306a36Sopenharmony_cimodule_param(timer, uint, S_IRUGO | S_IWUSR); 23062306a36Sopenharmony_cimodule_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); 23162306a36Sopenharmony_cimodule_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); 23262306a36Sopenharmony_cimodule_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); 23362306a36Sopenharmony_cimodule_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); 23462306a36Sopenharmony_cimodule_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR); 23562306a36Sopenharmony_cimodule_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR); 23662306a36Sopenharmony_cimodule_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); 23762306a36Sopenharmony_cimodule_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); 23862306a36Sopenharmony_cimodule_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 24162306a36Sopenharmony_ci#define HFC_outb(hc, reg, val) \ 24262306a36Sopenharmony_ci (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) 24362306a36Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val) \ 24462306a36Sopenharmony_ci (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) 24562306a36Sopenharmony_ci#define HFC_inb(hc, reg) \ 24662306a36Sopenharmony_ci (hc->HFC_inb(hc, reg, __func__, __LINE__)) 24762306a36Sopenharmony_ci#define HFC_inb_nodebug(hc, reg) \ 24862306a36Sopenharmony_ci (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) 24962306a36Sopenharmony_ci#define HFC_inw(hc, reg) \ 25062306a36Sopenharmony_ci (hc->HFC_inw(hc, reg, __func__, __LINE__)) 25162306a36Sopenharmony_ci#define HFC_inw_nodebug(hc, reg) \ 25262306a36Sopenharmony_ci (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) 25362306a36Sopenharmony_ci#define HFC_wait(hc) \ 25462306a36Sopenharmony_ci (hc->HFC_wait(hc, __func__, __LINE__)) 25562306a36Sopenharmony_ci#define HFC_wait_nodebug(hc) \ 25662306a36Sopenharmony_ci (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) 25762306a36Sopenharmony_ci#else 25862306a36Sopenharmony_ci#define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val)) 25962306a36Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val)) 26062306a36Sopenharmony_ci#define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg)) 26162306a36Sopenharmony_ci#define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg)) 26262306a36Sopenharmony_ci#define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg)) 26362306a36Sopenharmony_ci#define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg)) 26462306a36Sopenharmony_ci#define HFC_wait(hc) (hc->HFC_wait(hc)) 26562306a36Sopenharmony_ci#define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) 26662306a36Sopenharmony_ci#endif 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 26962306a36Sopenharmony_ci#include "hfc_multi_8xx.h" 27062306a36Sopenharmony_ci#endif 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* HFC_IO_MODE_PCIMEM */ 27362306a36Sopenharmony_cistatic void 27462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 27562306a36Sopenharmony_ciHFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, 27662306a36Sopenharmony_ci const char *function, int line) 27762306a36Sopenharmony_ci#else 27862306a36Sopenharmony_ci HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) 27962306a36Sopenharmony_ci#endif 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci writeb(val, hc->pci_membase + reg); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_cistatic u_char 28462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 28562306a36Sopenharmony_ciHFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) 28662306a36Sopenharmony_ci#else 28762306a36Sopenharmony_ci HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) 28862306a36Sopenharmony_ci#endif 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return readb(hc->pci_membase + reg); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_cistatic u_short 29362306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 29462306a36Sopenharmony_ciHFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) 29562306a36Sopenharmony_ci#else 29662306a36Sopenharmony_ci HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) 29762306a36Sopenharmony_ci#endif 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci return readw(hc->pci_membase + reg); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_cistatic void 30262306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 30362306a36Sopenharmony_ciHFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) 30462306a36Sopenharmony_ci#else 30562306a36Sopenharmony_ci HFC_wait_pcimem(struct hfc_multi *hc) 30662306a36Sopenharmony_ci#endif 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci while (readb(hc->pci_membase + R_STATUS) & V_BUSY) 30962306a36Sopenharmony_ci cpu_relax(); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* HFC_IO_MODE_REGIO */ 31362306a36Sopenharmony_cistatic void 31462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 31562306a36Sopenharmony_ciHFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, 31662306a36Sopenharmony_ci const char *function, int line) 31762306a36Sopenharmony_ci#else 31862306a36Sopenharmony_ci HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) 31962306a36Sopenharmony_ci#endif 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 32262306a36Sopenharmony_ci outb(val, hc->pci_iobase); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_cistatic u_char 32562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 32662306a36Sopenharmony_ciHFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) 32762306a36Sopenharmony_ci#else 32862306a36Sopenharmony_ci HFC_inb_regio(struct hfc_multi *hc, u_char reg) 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 33262306a36Sopenharmony_ci return inb(hc->pci_iobase); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_cistatic u_short 33562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 33662306a36Sopenharmony_ciHFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) 33762306a36Sopenharmony_ci#else 33862306a36Sopenharmony_ci HFC_inw_regio(struct hfc_multi *hc, u_char reg) 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 34262306a36Sopenharmony_ci return inw(hc->pci_iobase); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_cistatic void 34562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 34662306a36Sopenharmony_ciHFC_wait_regio(struct hfc_multi *hc, const char *function, int line) 34762306a36Sopenharmony_ci#else 34862306a36Sopenharmony_ci HFC_wait_regio(struct hfc_multi *hc) 34962306a36Sopenharmony_ci#endif 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci outb(R_STATUS, hc->pci_iobase + 4); 35262306a36Sopenharmony_ci while (inb(hc->pci_iobase) & V_BUSY) 35362306a36Sopenharmony_ci cpu_relax(); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 35762306a36Sopenharmony_cistatic void 35862306a36Sopenharmony_ciHFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, 35962306a36Sopenharmony_ci const char *function, int line) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci char regname[256] = "", bits[9] = "xxxxxxxx"; 36262306a36Sopenharmony_ci int i; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci i = -1; 36562306a36Sopenharmony_ci while (hfc_register_names[++i].name) { 36662306a36Sopenharmony_ci if (hfc_register_names[i].reg == reg) 36762306a36Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci if (regname[0] == '\0') 37062306a36Sopenharmony_ci strcpy(regname, "register"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci bits[7] = '0' + (!!(val & 1)); 37362306a36Sopenharmony_ci bits[6] = '0' + (!!(val & 2)); 37462306a36Sopenharmony_ci bits[5] = '0' + (!!(val & 4)); 37562306a36Sopenharmony_ci bits[4] = '0' + (!!(val & 8)); 37662306a36Sopenharmony_ci bits[3] = '0' + (!!(val & 16)); 37762306a36Sopenharmony_ci bits[2] = '0' + (!!(val & 32)); 37862306a36Sopenharmony_ci bits[1] = '0' + (!!(val & 64)); 37962306a36Sopenharmony_ci bits[0] = '0' + (!!(val & 128)); 38062306a36Sopenharmony_ci printk(KERN_DEBUG 38162306a36Sopenharmony_ci "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", 38262306a36Sopenharmony_ci hc->id, reg, regname, val, bits, function, line); 38362306a36Sopenharmony_ci HFC_outb_nodebug(hc, reg, val); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_cistatic u_char 38662306a36Sopenharmony_ciHFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci char regname[256] = "", bits[9] = "xxxxxxxx"; 38962306a36Sopenharmony_ci u_char val = HFC_inb_nodebug(hc, reg); 39062306a36Sopenharmony_ci int i; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci i = 0; 39362306a36Sopenharmony_ci while (hfc_register_names[i++].name) 39462306a36Sopenharmony_ci ; 39562306a36Sopenharmony_ci while (hfc_register_names[++i].name) { 39662306a36Sopenharmony_ci if (hfc_register_names[i].reg == reg) 39762306a36Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci if (regname[0] == '\0') 40062306a36Sopenharmony_ci strcpy(regname, "register"); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci bits[7] = '0' + (!!(val & 1)); 40362306a36Sopenharmony_ci bits[6] = '0' + (!!(val & 2)); 40462306a36Sopenharmony_ci bits[5] = '0' + (!!(val & 4)); 40562306a36Sopenharmony_ci bits[4] = '0' + (!!(val & 8)); 40662306a36Sopenharmony_ci bits[3] = '0' + (!!(val & 16)); 40762306a36Sopenharmony_ci bits[2] = '0' + (!!(val & 32)); 40862306a36Sopenharmony_ci bits[1] = '0' + (!!(val & 64)); 40962306a36Sopenharmony_ci bits[0] = '0' + (!!(val & 128)); 41062306a36Sopenharmony_ci printk(KERN_DEBUG 41162306a36Sopenharmony_ci "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", 41262306a36Sopenharmony_ci hc->id, reg, regname, val, bits, function, line); 41362306a36Sopenharmony_ci return val; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_cistatic u_short 41662306a36Sopenharmony_ciHFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci char regname[256] = ""; 41962306a36Sopenharmony_ci u_short val = HFC_inw_nodebug(hc, reg); 42062306a36Sopenharmony_ci int i; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci i = 0; 42362306a36Sopenharmony_ci while (hfc_register_names[i++].name) 42462306a36Sopenharmony_ci ; 42562306a36Sopenharmony_ci while (hfc_register_names[++i].name) { 42662306a36Sopenharmony_ci if (hfc_register_names[i].reg == reg) 42762306a36Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci if (regname[0] == '\0') 43062306a36Sopenharmony_ci strcpy(regname, "register"); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci printk(KERN_DEBUG 43362306a36Sopenharmony_ci "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", 43462306a36Sopenharmony_ci hc->id, reg, regname, val, function, line); 43562306a36Sopenharmony_ci return val; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_cistatic void 43862306a36Sopenharmony_ciHFC_wait_debug(struct hfc_multi *hc, const char *function, int line) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", 44162306a36Sopenharmony_ci hc->id, function, line); 44262306a36Sopenharmony_ci HFC_wait_nodebug(hc); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci#endif 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* write fifo data (REGIO) */ 44762306a36Sopenharmony_cistatic void 44862306a36Sopenharmony_ciwrite_fifo_regio(struct hfc_multi *hc, u_char *data, int len) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); 45162306a36Sopenharmony_ci while (len >> 2) { 45262306a36Sopenharmony_ci outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase); 45362306a36Sopenharmony_ci data += 4; 45462306a36Sopenharmony_ci len -= 4; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci while (len >> 1) { 45762306a36Sopenharmony_ci outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase); 45862306a36Sopenharmony_ci data += 2; 45962306a36Sopenharmony_ci len -= 2; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci while (len) { 46262306a36Sopenharmony_ci outb(*data, hc->pci_iobase); 46362306a36Sopenharmony_ci data++; 46462306a36Sopenharmony_ci len--; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci/* write fifo data (PCIMEM) */ 46862306a36Sopenharmony_cistatic void 46962306a36Sopenharmony_ciwrite_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci while (len >> 2) { 47262306a36Sopenharmony_ci writel(cpu_to_le32(*(u32 *)data), 47362306a36Sopenharmony_ci hc->pci_membase + A_FIFO_DATA0); 47462306a36Sopenharmony_ci data += 4; 47562306a36Sopenharmony_ci len -= 4; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci while (len >> 1) { 47862306a36Sopenharmony_ci writew(cpu_to_le16(*(u16 *)data), 47962306a36Sopenharmony_ci hc->pci_membase + A_FIFO_DATA0); 48062306a36Sopenharmony_ci data += 2; 48162306a36Sopenharmony_ci len -= 2; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci while (len) { 48462306a36Sopenharmony_ci writeb(*data, hc->pci_membase + A_FIFO_DATA0); 48562306a36Sopenharmony_ci data++; 48662306a36Sopenharmony_ci len--; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* read fifo data (REGIO) */ 49162306a36Sopenharmony_cistatic void 49262306a36Sopenharmony_ciread_fifo_regio(struct hfc_multi *hc, u_char *data, int len) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); 49562306a36Sopenharmony_ci while (len >> 2) { 49662306a36Sopenharmony_ci *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase)); 49762306a36Sopenharmony_ci data += 4; 49862306a36Sopenharmony_ci len -= 4; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci while (len >> 1) { 50162306a36Sopenharmony_ci *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase)); 50262306a36Sopenharmony_ci data += 2; 50362306a36Sopenharmony_ci len -= 2; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci while (len) { 50662306a36Sopenharmony_ci *data = inb(hc->pci_iobase); 50762306a36Sopenharmony_ci data++; 50862306a36Sopenharmony_ci len--; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* read fifo data (PCIMEM) */ 51362306a36Sopenharmony_cistatic void 51462306a36Sopenharmony_ciread_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci while (len >> 2) { 51762306a36Sopenharmony_ci *(u32 *)data = 51862306a36Sopenharmony_ci le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0)); 51962306a36Sopenharmony_ci data += 4; 52062306a36Sopenharmony_ci len -= 4; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci while (len >> 1) { 52362306a36Sopenharmony_ci *(u16 *)data = 52462306a36Sopenharmony_ci le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0)); 52562306a36Sopenharmony_ci data += 2; 52662306a36Sopenharmony_ci len -= 2; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci while (len) { 52962306a36Sopenharmony_ci *data = readb(hc->pci_membase + A_FIFO_DATA0); 53062306a36Sopenharmony_ci data++; 53162306a36Sopenharmony_ci len--; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void 53662306a36Sopenharmony_cienable_hwirq(struct hfc_multi *hc) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; 53962306a36Sopenharmony_ci HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic void 54362306a36Sopenharmony_cidisable_hwirq(struct hfc_multi *hc) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); 54662306a36Sopenharmony_ci HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci#define NUM_EC 2 55062306a36Sopenharmony_ci#define MAX_TDM_CHAN 32 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic inline void 55462306a36Sopenharmony_cienablepcibridge(struct hfc_multi *c) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic inline void 56062306a36Sopenharmony_cidisablepcibridge(struct hfc_multi *c) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic inline unsigned char 56662306a36Sopenharmony_cireadpcibridge(struct hfc_multi *hc, unsigned char address) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci unsigned short cipv; 56962306a36Sopenharmony_ci unsigned char data; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (!hc->pci_iobase) 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* slow down a PCI read access by 1 PCI clock cycle */ 57562306a36Sopenharmony_ci HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (address == 0) 57862306a36Sopenharmony_ci cipv = 0x4000; 57962306a36Sopenharmony_ci else 58062306a36Sopenharmony_ci cipv = 0x5800; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* select local bridge port address by writing to CIP port */ 58362306a36Sopenharmony_ci /* data = HFC_inb(c, cipv); * was _io before */ 58462306a36Sopenharmony_ci outw(cipv, hc->pci_iobase + 4); 58562306a36Sopenharmony_ci data = inb(hc->pci_iobase); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* restore R_CTRL for normal PCI read cycle speed */ 58862306a36Sopenharmony_ci HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return data; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic inline void 59462306a36Sopenharmony_ciwritepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci unsigned short cipv; 59762306a36Sopenharmony_ci unsigned int datav; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (!hc->pci_iobase) 60062306a36Sopenharmony_ci return; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (address == 0) 60362306a36Sopenharmony_ci cipv = 0x4000; 60462306a36Sopenharmony_ci else 60562306a36Sopenharmony_ci cipv = 0x5800; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* select local bridge port address by writing to CIP port */ 60862306a36Sopenharmony_ci outw(cipv, hc->pci_iobase + 4); 60962306a36Sopenharmony_ci /* define a 32 bit dword with 4 identical bytes for write sequence */ 61062306a36Sopenharmony_ci datav = data | ((__u32) data << 8) | ((__u32) data << 16) | 61162306a36Sopenharmony_ci ((__u32) data << 24); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * write this 32 bit dword to the bridge data port 61562306a36Sopenharmony_ci * this will initiate a write sequence of up to 4 writes to the same 61662306a36Sopenharmony_ci * address on the local bus interface the number of write accesses 61762306a36Sopenharmony_ci * is undefined but >=1 and depends on the next PCI transaction 61862306a36Sopenharmony_ci * during write sequence on the local bus 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci outl(datav, hc->pci_iobase); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic inline void 62462306a36Sopenharmony_cicpld_set_reg(struct hfc_multi *hc, unsigned char reg) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci /* Do data pin read low byte */ 62762306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, reg); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic inline void 63162306a36Sopenharmony_cicpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci cpld_set_reg(hc, reg); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci enablepcibridge(hc); 63662306a36Sopenharmony_ci writepcibridge(hc, 1, val); 63762306a36Sopenharmony_ci disablepcibridge(hc); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic inline void 64362306a36Sopenharmony_civpm_write_address(struct hfc_multi *hc, unsigned short addr) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci cpld_write_reg(hc, 0, 0xff & addr); 64662306a36Sopenharmony_ci cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic inline unsigned char 65062306a36Sopenharmony_civpm_in(struct hfc_multi *c, int which, unsigned short addr) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci unsigned char res; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci vpm_write_address(c, addr); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (!which) 65762306a36Sopenharmony_ci cpld_set_reg(c, 2); 65862306a36Sopenharmony_ci else 65962306a36Sopenharmony_ci cpld_set_reg(c, 3); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci enablepcibridge(c); 66262306a36Sopenharmony_ci res = readpcibridge(c, 1); 66362306a36Sopenharmony_ci disablepcibridge(c); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci cpld_set_reg(c, 0); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return res; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic inline void 67162306a36Sopenharmony_civpm_out(struct hfc_multi *c, int which, unsigned short addr, 67262306a36Sopenharmony_ci unsigned char data) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci vpm_write_address(c, addr); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci enablepcibridge(c); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (!which) 67962306a36Sopenharmony_ci cpld_set_reg(c, 2); 68062306a36Sopenharmony_ci else 68162306a36Sopenharmony_ci cpld_set_reg(c, 3); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci writepcibridge(c, 1, data); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci cpld_set_reg(c, 0); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci disablepcibridge(c); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci { 69062306a36Sopenharmony_ci unsigned char regin; 69162306a36Sopenharmony_ci regin = vpm_in(c, which, addr); 69262306a36Sopenharmony_ci if (regin != data) 69362306a36Sopenharmony_ci printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " 69462306a36Sopenharmony_ci "0x%x\n", data, addr, regin); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic void 70162306a36Sopenharmony_civpm_init(struct hfc_multi *wc) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci unsigned char reg; 70462306a36Sopenharmony_ci unsigned int mask; 70562306a36Sopenharmony_ci unsigned int i, x, y; 70662306a36Sopenharmony_ci unsigned int ver; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci for (x = 0; x < NUM_EC; x++) { 70962306a36Sopenharmony_ci /* Setup GPIO's */ 71062306a36Sopenharmony_ci if (!x) { 71162306a36Sopenharmony_ci ver = vpm_in(wc, x, 0x1a0); 71262306a36Sopenharmony_ci printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci for (y = 0; y < 4; y++) { 71662306a36Sopenharmony_ci vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ 71762306a36Sopenharmony_ci vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ 71862306a36Sopenharmony_ci vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Setup TDM path - sets fsync and tdm_clk as inputs */ 72262306a36Sopenharmony_ci reg = vpm_in(wc, x, 0x1a3); /* misc_con */ 72362306a36Sopenharmony_ci vpm_out(wc, x, 0x1a3, reg & ~2); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Setup Echo length (256 taps) */ 72662306a36Sopenharmony_ci vpm_out(wc, x, 0x022, 1); 72762306a36Sopenharmony_ci vpm_out(wc, x, 0x023, 0xff); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* Setup timeslots */ 73062306a36Sopenharmony_ci vpm_out(wc, x, 0x02f, 0x00); 73162306a36Sopenharmony_ci mask = 0x02020202 << (x * 4); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Setup the tdm channel masks for all chips */ 73462306a36Sopenharmony_ci for (i = 0; i < 4; i++) 73562306a36Sopenharmony_ci vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Setup convergence rate */ 73862306a36Sopenharmony_ci printk(KERN_DEBUG "VPM: A-law mode\n"); 73962306a36Sopenharmony_ci reg = 0x00 | 0x10 | 0x01; 74062306a36Sopenharmony_ci vpm_out(wc, x, 0x20, reg); 74162306a36Sopenharmony_ci printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); 74262306a36Sopenharmony_ci /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci vpm_out(wc, x, 0x24, 0x02); 74562306a36Sopenharmony_ci reg = vpm_in(wc, x, 0x24); 74662306a36Sopenharmony_ci printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Initialize echo cans */ 74962306a36Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 75062306a36Sopenharmony_ci if (mask & (0x00000001 << i)) 75162306a36Sopenharmony_ci vpm_out(wc, x, i, 0x00); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * ARM arch at least disallows a udelay of 75662306a36Sopenharmony_ci * more than 2ms... it gives a fake "__bad_udelay" 75762306a36Sopenharmony_ci * reference at link-time. 75862306a36Sopenharmony_ci * long delays in kernel code are pretty sucky anyway 75962306a36Sopenharmony_ci * for now work around it using 5 x 2ms instead of 1 x 10ms 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci udelay(2000); 76362306a36Sopenharmony_ci udelay(2000); 76462306a36Sopenharmony_ci udelay(2000); 76562306a36Sopenharmony_ci udelay(2000); 76662306a36Sopenharmony_ci udelay(2000); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Put in bypass mode */ 76962306a36Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 77062306a36Sopenharmony_ci if (mask & (0x00000001 << i)) 77162306a36Sopenharmony_ci vpm_out(wc, x, i, 0x01); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* Enable bypass */ 77562306a36Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 77662306a36Sopenharmony_ci if (mask & (0x00000001 << i)) 77762306a36Sopenharmony_ci vpm_out(wc, x, 0x78 + i, 0x01); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci#ifdef UNUSED 78462306a36Sopenharmony_cistatic void 78562306a36Sopenharmony_civpm_check(struct hfc_multi *hctmp) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci unsigned char gpi2; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci gpi2 = HFC_inb(hctmp, R_GPI_IN2); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if ((gpi2 & 0x3) != 0x3) 79262306a36Sopenharmony_ci printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci#endif /* UNUSED */ 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* 79862306a36Sopenharmony_ci * Interface to enable/disable the HW Echocan 79962306a36Sopenharmony_ci * 80062306a36Sopenharmony_ci * these functions are called within a spin_lock_irqsave on 80162306a36Sopenharmony_ci * the channel instance lock, so we are not disturbed by irqs 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * we can later easily change the interface to make other 80462306a36Sopenharmony_ci * things configurable, for now we configure the taps 80562306a36Sopenharmony_ci * 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic void 80962306a36Sopenharmony_civpm_echocan_on(struct hfc_multi *hc, int ch, int taps) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci unsigned int timeslot; 81262306a36Sopenharmony_ci unsigned int unit; 81362306a36Sopenharmony_ci struct bchannel *bch = hc->chan[ch].bch; 81462306a36Sopenharmony_ci#ifdef TXADJ 81562306a36Sopenharmony_ci int txadj = -4; 81662306a36Sopenharmony_ci struct sk_buff *skb; 81762306a36Sopenharmony_ci#endif 81862306a36Sopenharmony_ci if (hc->chan[ch].protocol != ISDN_P_B_RAW) 81962306a36Sopenharmony_ci return; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (!bch) 82262306a36Sopenharmony_ci return; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci#ifdef TXADJ 82562306a36Sopenharmony_ci skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, 82662306a36Sopenharmony_ci sizeof(int), &txadj, GFP_ATOMIC); 82762306a36Sopenharmony_ci if (skb) 82862306a36Sopenharmony_ci recv_Bchannel_skb(bch, skb); 82962306a36Sopenharmony_ci#endif 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; 83262306a36Sopenharmony_ci unit = ch % 4; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", 83562306a36Sopenharmony_ci taps, timeslot); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci vpm_out(hc, unit, timeslot, 0x7e); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic void 84162306a36Sopenharmony_civpm_echocan_off(struct hfc_multi *hc, int ch) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci unsigned int timeslot; 84462306a36Sopenharmony_ci unsigned int unit; 84562306a36Sopenharmony_ci struct bchannel *bch = hc->chan[ch].bch; 84662306a36Sopenharmony_ci#ifdef TXADJ 84762306a36Sopenharmony_ci int txadj = 0; 84862306a36Sopenharmony_ci struct sk_buff *skb; 84962306a36Sopenharmony_ci#endif 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (hc->chan[ch].protocol != ISDN_P_B_RAW) 85262306a36Sopenharmony_ci return; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (!bch) 85562306a36Sopenharmony_ci return; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci#ifdef TXADJ 85862306a36Sopenharmony_ci skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, 85962306a36Sopenharmony_ci sizeof(int), &txadj, GFP_ATOMIC); 86062306a36Sopenharmony_ci if (skb) 86162306a36Sopenharmony_ci recv_Bchannel_skb(bch, skb); 86262306a36Sopenharmony_ci#endif 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; 86562306a36Sopenharmony_ci unit = ch % 4; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", 86862306a36Sopenharmony_ci timeslot); 86962306a36Sopenharmony_ci /* FILLME */ 87062306a36Sopenharmony_ci vpm_out(hc, unit, timeslot, 0x01); 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/* 87562306a36Sopenharmony_ci * Speech Design resync feature 87662306a36Sopenharmony_ci * NOTE: This is called sometimes outside interrupt handler. 87762306a36Sopenharmony_ci * We must lock irqsave, so no other interrupt (other card) will occur! 87862306a36Sopenharmony_ci * Also multiple interrupts may nest, so must lock each access (lists, card)! 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_cistatic inline void 88162306a36Sopenharmony_cihfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct hfc_multi *hc, *next, *pcmmaster = NULL; 88462306a36Sopenharmony_ci void __iomem *plx_acc_32; 88562306a36Sopenharmony_ci u_int pv; 88662306a36Sopenharmony_ci u_long flags; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 88962306a36Sopenharmony_ci spin_lock(&plx_lock); /* must be locked inside other locks */ 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 89262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", 89362306a36Sopenharmony_ci __func__, syncmaster); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* select new master */ 89662306a36Sopenharmony_ci if (newmaster) { 89762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 89862306a36Sopenharmony_ci printk(KERN_DEBUG "using provided controller\n"); 89962306a36Sopenharmony_ci } else { 90062306a36Sopenharmony_ci list_for_each_entry_safe(hc, next, &HFClist, list) { 90162306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 90262306a36Sopenharmony_ci if (hc->syncronized) { 90362306a36Sopenharmony_ci newmaster = hc; 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* Disable sync of all cards */ 91162306a36Sopenharmony_ci list_for_each_entry_safe(hc, next, &HFClist, list) { 91262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 91362306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 91462306a36Sopenharmony_ci pv = readl(plx_acc_32); 91562306a36Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 91662306a36Sopenharmony_ci writel(pv, plx_acc_32); 91762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { 91862306a36Sopenharmony_ci pcmmaster = hc; 91962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 92062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 92162306a36Sopenharmony_ci printk(KERN_DEBUG 92262306a36Sopenharmony_ci "Schedule SYNC_I\n"); 92362306a36Sopenharmony_ci hc->e1_resync |= 1; /* get SYNC_I */ 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (newmaster) { 93062306a36Sopenharmony_ci hc = newmaster; 93162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 93262306a36Sopenharmony_ci printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " 93362306a36Sopenharmony_ci "interface.\n", hc->id, hc); 93462306a36Sopenharmony_ci /* Enable new sync master */ 93562306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 93662306a36Sopenharmony_ci pv = readl(plx_acc_32); 93762306a36Sopenharmony_ci pv |= PLX_SYNC_O_EN; 93862306a36Sopenharmony_ci writel(pv, plx_acc_32); 93962306a36Sopenharmony_ci /* switch to jatt PLL, if not disabled by RX_SYNC */ 94062306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 94162306a36Sopenharmony_ci && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { 94262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 94362306a36Sopenharmony_ci printk(KERN_DEBUG "Schedule jatt PLL\n"); 94462306a36Sopenharmony_ci hc->e1_resync |= 2; /* switch to jatt */ 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci } else { 94762306a36Sopenharmony_ci if (pcmmaster) { 94862306a36Sopenharmony_ci hc = pcmmaster; 94962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 95062306a36Sopenharmony_ci printk(KERN_DEBUG 95162306a36Sopenharmony_ci "id=%d (0x%p) = PCM master syncronized " 95262306a36Sopenharmony_ci "with QUARTZ\n", hc->id, hc); 95362306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 95462306a36Sopenharmony_ci /* Use the crystal clock for the PCM 95562306a36Sopenharmony_ci master card */ 95662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 95762306a36Sopenharmony_ci printk(KERN_DEBUG 95862306a36Sopenharmony_ci "Schedule QUARTZ for HFC-E1\n"); 95962306a36Sopenharmony_ci hc->e1_resync |= 4; /* switch quartz */ 96062306a36Sopenharmony_ci } else { 96162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 96262306a36Sopenharmony_ci printk(KERN_DEBUG 96362306a36Sopenharmony_ci "QUARTZ is automatically " 96462306a36Sopenharmony_ci "enabled by HFC-%dS\n", hc->ctype); 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 96762306a36Sopenharmony_ci pv = readl(plx_acc_32); 96862306a36Sopenharmony_ci pv |= PLX_SYNC_O_EN; 96962306a36Sopenharmony_ci writel(pv, plx_acc_32); 97062306a36Sopenharmony_ci } else 97162306a36Sopenharmony_ci if (!rm) 97262306a36Sopenharmony_ci printk(KERN_ERR "%s no pcm master, this MUST " 97362306a36Sopenharmony_ci "not happen!\n", __func__); 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci syncmaster = newmaster; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci spin_unlock(&plx_lock); 97862306a36Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci/* This must be called AND hc must be locked irqsave!!! */ 98262306a36Sopenharmony_cistatic inline void 98362306a36Sopenharmony_ciplxsd_checksync(struct hfc_multi *hc, int rm) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci if (hc->syncronized) { 98662306a36Sopenharmony_ci if (syncmaster == NULL) { 98762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 98862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: GOT sync on card %d" 98962306a36Sopenharmony_ci " (id=%d)\n", __func__, hc->id + 1, 99062306a36Sopenharmony_ci hc->id); 99162306a36Sopenharmony_ci hfcmulti_resync(hc, hc, rm); 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci } else { 99462306a36Sopenharmony_ci if (syncmaster == hc) { 99562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 99662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: LOST sync on card %d" 99762306a36Sopenharmony_ci " (id=%d)\n", __func__, hc->id + 1, 99862306a36Sopenharmony_ci hc->id); 99962306a36Sopenharmony_ci hfcmulti_resync(hc, NULL, rm); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci/* 100662306a36Sopenharmony_ci * free hardware resources used by driver 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_cistatic void 100962306a36Sopenharmony_cirelease_io_hfcmulti(struct hfc_multi *hc) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci void __iomem *plx_acc_32; 101262306a36Sopenharmony_ci u_int pv; 101362306a36Sopenharmony_ci u_long plx_flags; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 101662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* soft reset also masks all interrupts */ 101962306a36Sopenharmony_ci hc->hw.r_cirm |= V_SRES; 102062306a36Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 102162306a36Sopenharmony_ci udelay(1000); 102262306a36Sopenharmony_ci hc->hw.r_cirm &= ~V_SRES; 102362306a36Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 102462306a36Sopenharmony_ci udelay(1000); /* instead of 'wait' that may cause locking */ 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* release Speech Design card, if PLX was initialized */ 102762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { 102862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 102962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: release PLXSD card %d\n", 103062306a36Sopenharmony_ci __func__, hc->id + 1); 103162306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 103262306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 103362306a36Sopenharmony_ci writel(PLX_GPIOC_INIT, plx_acc_32); 103462306a36Sopenharmony_ci pv = readl(plx_acc_32); 103562306a36Sopenharmony_ci /* Termination off */ 103662306a36Sopenharmony_ci pv &= ~PLX_TERM_ON; 103762306a36Sopenharmony_ci /* Disconnect the PCM */ 103862306a36Sopenharmony_ci pv |= PLX_SLAVE_EN_N; 103962306a36Sopenharmony_ci pv &= ~PLX_MASTER_EN; 104062306a36Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 104162306a36Sopenharmony_ci /* Put the DSP in Reset */ 104262306a36Sopenharmony_ci pv &= ~PLX_DSP_RES_N; 104362306a36Sopenharmony_ci writel(pv, plx_acc_32); 104462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 104562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", 104662306a36Sopenharmony_ci __func__, pv); 104762306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* disable memory mapped ports / io ports */ 105162306a36Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ 105262306a36Sopenharmony_ci if (hc->pci_dev) 105362306a36Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); 105462306a36Sopenharmony_ci if (hc->pci_membase) 105562306a36Sopenharmony_ci iounmap(hc->pci_membase); 105662306a36Sopenharmony_ci if (hc->plx_membase) 105762306a36Sopenharmony_ci iounmap(hc->plx_membase); 105862306a36Sopenharmony_ci if (hc->pci_iobase) 105962306a36Sopenharmony_ci release_region(hc->pci_iobase, 8); 106062306a36Sopenharmony_ci if (hc->xhfc_membase) 106162306a36Sopenharmony_ci iounmap((void *)hc->xhfc_membase); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (hc->pci_dev) { 106462306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 106562306a36Sopenharmony_ci pci_set_drvdata(hc->pci_dev, NULL); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 106862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci/* 107262306a36Sopenharmony_ci * function called to reset the HFC chip. A complete software reset of chip 107362306a36Sopenharmony_ci * and fifos is done. All configuration of the chip is done. 107462306a36Sopenharmony_ci */ 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic int 107762306a36Sopenharmony_ciinit_chip(struct hfc_multi *hc) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci u_long flags, val, val2 = 0, rev; 108062306a36Sopenharmony_ci int i, err = 0; 108162306a36Sopenharmony_ci u_char r_conf_en, rval; 108262306a36Sopenharmony_ci void __iomem *plx_acc_32; 108362306a36Sopenharmony_ci u_int pv; 108462306a36Sopenharmony_ci u_long plx_flags, hfc_flags; 108562306a36Sopenharmony_ci int plx_count; 108662306a36Sopenharmony_ci struct hfc_multi *pos, *next, *plx_last_hc; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 108962306a36Sopenharmony_ci /* reset all registers */ 109062306a36Sopenharmony_ci memset(&hc->hw, 0, sizeof(struct hfcm_hw)); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* revision check */ 109362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 109462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 109562306a36Sopenharmony_ci val = HFC_inb(hc, R_CHIP_ID); 109662306a36Sopenharmony_ci if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && 109762306a36Sopenharmony_ci (val >> 1) != 0x31) { 109862306a36Sopenharmony_ci printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); 109962306a36Sopenharmony_ci err = -EIO; 110062306a36Sopenharmony_ci goto out; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci rev = HFC_inb(hc, R_CHIP_RV); 110362306a36Sopenharmony_ci printk(KERN_INFO 110462306a36Sopenharmony_ci "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", 110562306a36Sopenharmony_ci val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? 110662306a36Sopenharmony_ci " (old FIFO handling)" : ""); 110762306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { 110862306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); 110962306a36Sopenharmony_ci printk(KERN_WARNING 111062306a36Sopenharmony_ci "HFC_multi: NOTE: Your chip is revision 0, " 111162306a36Sopenharmony_ci "ask Cologne Chip for update. Newer chips " 111262306a36Sopenharmony_ci "have a better FIFO handling. Old chips " 111362306a36Sopenharmony_ci "still work but may have slightly lower " 111462306a36Sopenharmony_ci "HDLC transmit performance.\n"); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci if (rev > 1) { 111762306a36Sopenharmony_ci printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " 111862306a36Sopenharmony_ci "consider chip revision = %ld. The chip / " 111962306a36Sopenharmony_ci "bridge may not work.\n", rev); 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* set s-ram size */ 112362306a36Sopenharmony_ci hc->Flen = 0x10; 112462306a36Sopenharmony_ci hc->Zmin = 0x80; 112562306a36Sopenharmony_ci hc->Zlen = 384; 112662306a36Sopenharmony_ci hc->DTMFbase = 0x1000; 112762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { 112862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 112962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: changing to 128K external RAM\n", 113062306a36Sopenharmony_ci __func__); 113162306a36Sopenharmony_ci hc->hw.r_ctrl |= V_EXT_RAM; 113262306a36Sopenharmony_ci hc->hw.r_ram_sz = 1; 113362306a36Sopenharmony_ci hc->Flen = 0x20; 113462306a36Sopenharmony_ci hc->Zmin = 0xc0; 113562306a36Sopenharmony_ci hc->Zlen = 1856; 113662306a36Sopenharmony_ci hc->DTMFbase = 0x2000; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { 113962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 114062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: changing to 512K external RAM\n", 114162306a36Sopenharmony_ci __func__); 114262306a36Sopenharmony_ci hc->hw.r_ctrl |= V_EXT_RAM; 114362306a36Sopenharmony_ci hc->hw.r_ram_sz = 2; 114462306a36Sopenharmony_ci hc->Flen = 0x20; 114562306a36Sopenharmony_ci hc->Zmin = 0xc0; 114662306a36Sopenharmony_ci hc->Zlen = 8000; 114762306a36Sopenharmony_ci hc->DTMFbase = 0x2000; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 115062306a36Sopenharmony_ci hc->Flen = 0x8; 115162306a36Sopenharmony_ci hc->Zmin = 0x0; 115262306a36Sopenharmony_ci hc->Zlen = 64; 115362306a36Sopenharmony_ci hc->DTMFbase = 0x0; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci hc->max_trans = poll << 1; 115662306a36Sopenharmony_ci if (hc->max_trans > hc->Zlen) 115762306a36Sopenharmony_ci hc->max_trans = hc->Zlen; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Speech Design PLX bridge */ 116062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 116162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 116262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", 116362306a36Sopenharmony_ci __func__, hc->id + 1); 116462306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 116562306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 116662306a36Sopenharmony_ci writel(PLX_GPIOC_INIT, plx_acc_32); 116762306a36Sopenharmony_ci pv = readl(plx_acc_32); 116862306a36Sopenharmony_ci /* The first and the last cards are terminating the PCM bus */ 116962306a36Sopenharmony_ci pv |= PLX_TERM_ON; /* hc is currently the last */ 117062306a36Sopenharmony_ci /* Disconnect the PCM */ 117162306a36Sopenharmony_ci pv |= PLX_SLAVE_EN_N; 117262306a36Sopenharmony_ci pv &= ~PLX_MASTER_EN; 117362306a36Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 117462306a36Sopenharmony_ci /* Put the DSP in Reset */ 117562306a36Sopenharmony_ci pv &= ~PLX_DSP_RES_N; 117662306a36Sopenharmony_ci writel(pv, plx_acc_32); 117762306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 117862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 117962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", 118062306a36Sopenharmony_ci __func__, pv); 118162306a36Sopenharmony_ci /* 118262306a36Sopenharmony_ci * If we are the 3rd PLXSD card or higher, we must turn 118362306a36Sopenharmony_ci * termination of last PLXSD card off. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci spin_lock_irqsave(&HFClock, hfc_flags); 118662306a36Sopenharmony_ci plx_count = 0; 118762306a36Sopenharmony_ci plx_last_hc = NULL; 118862306a36Sopenharmony_ci list_for_each_entry_safe(pos, next, &HFClist, list) { 118962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { 119062306a36Sopenharmony_ci plx_count++; 119162306a36Sopenharmony_ci if (pos != hc) 119262306a36Sopenharmony_ci plx_last_hc = pos; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci if (plx_count >= 3) { 119662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 119762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: card %d is between, so " 119862306a36Sopenharmony_ci "we disable termination\n", 119962306a36Sopenharmony_ci __func__, plx_last_hc->id + 1); 120062306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 120162306a36Sopenharmony_ci plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; 120262306a36Sopenharmony_ci pv = readl(plx_acc_32); 120362306a36Sopenharmony_ci pv &= ~PLX_TERM_ON; 120462306a36Sopenharmony_ci writel(pv, plx_acc_32); 120562306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 120662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 120762306a36Sopenharmony_ci printk(KERN_DEBUG 120862306a36Sopenharmony_ci "%s: term off: PLX_GPIO=%x\n", 120962306a36Sopenharmony_ci __func__, pv); 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci spin_unlock_irqrestore(&HFClock, hfc_flags); 121262306a36Sopenharmony_ci hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 121662306a36Sopenharmony_ci hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* we only want the real Z2 read-pointer for revision > 0 */ 121962306a36Sopenharmony_ci if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) 122062306a36Sopenharmony_ci hc->hw.r_ram_sz |= V_FZ_MD; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* select pcm mode */ 122362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 122462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 122562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: setting PCM into slave mode\n", 122662306a36Sopenharmony_ci __func__); 122762306a36Sopenharmony_ci } else 122862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { 122962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 123062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: setting PCM into master mode\n", 123162306a36Sopenharmony_ci __func__); 123262306a36Sopenharmony_ci hc->hw.r_pcm_md0 |= V_PCM_MD; 123362306a36Sopenharmony_ci } else { 123462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 123562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: performing PCM auto detect\n", 123662306a36Sopenharmony_ci __func__); 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* soft reset */ 124062306a36Sopenharmony_ci HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); 124162306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 124262306a36Sopenharmony_ci HFC_outb(hc, 0x0C /* R_FIFO_THRES */, 124362306a36Sopenharmony_ci 0x11 /* 16 Bytes TX/RX */); 124462306a36Sopenharmony_ci else 124562306a36Sopenharmony_ci HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); 124662306a36Sopenharmony_ci HFC_outb(hc, R_FIFO_MD, 0); 124762306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 124862306a36Sopenharmony_ci hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; 124962306a36Sopenharmony_ci else 125062306a36Sopenharmony_ci hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES 125162306a36Sopenharmony_ci | V_RLD_EPR; 125262306a36Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 125362306a36Sopenharmony_ci udelay(100); 125462306a36Sopenharmony_ci hc->hw.r_cirm = 0; 125562306a36Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 125662306a36Sopenharmony_ci udelay(100); 125762306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 125862306a36Sopenharmony_ci HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci /* Speech Design PLX bridge pcm and sync mode */ 126162306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 126262306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 126362306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 126462306a36Sopenharmony_ci pv = readl(plx_acc_32); 126562306a36Sopenharmony_ci /* Connect PCM */ 126662306a36Sopenharmony_ci if (hc->hw.r_pcm_md0 & V_PCM_MD) { 126762306a36Sopenharmony_ci pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; 126862306a36Sopenharmony_ci pv |= PLX_SYNC_O_EN; 126962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 127062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", 127162306a36Sopenharmony_ci __func__, pv); 127262306a36Sopenharmony_ci } else { 127362306a36Sopenharmony_ci pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); 127462306a36Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 127562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 127662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", 127762306a36Sopenharmony_ci __func__, pv); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci writel(pv, plx_acc_32); 128062306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* PCM setup */ 128462306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); 128562306a36Sopenharmony_ci if (hc->slots == 32) 128662306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x00); 128762306a36Sopenharmony_ci if (hc->slots == 64) 128862306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x10); 128962306a36Sopenharmony_ci if (hc->slots == 128) 129062306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x20); 129162306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); 129262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 129362306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ 129462306a36Sopenharmony_ci else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 129562306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ 129662306a36Sopenharmony_ci else 129762306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ 129862306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); 129962306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 130062306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_SLOT, i); 130162306a36Sopenharmony_ci HFC_outb_nodebug(hc, A_SL_CFG, 0); 130262306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 130362306a36Sopenharmony_ci HFC_outb_nodebug(hc, A_CONF, 0); 130462306a36Sopenharmony_ci hc->slot_owner[i] = -1; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* set clock speed */ 130862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { 130962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 131062306a36Sopenharmony_ci printk(KERN_DEBUG 131162306a36Sopenharmony_ci "%s: setting double clock\n", __func__); 131262306a36Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 131662306a36Sopenharmony_ci HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci /* B410P GPIO */ 131962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 132062306a36Sopenharmony_ci printk(KERN_NOTICE "Setting GPIOs\n"); 132162306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x30); 132262306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0x3); 132362306a36Sopenharmony_ci udelay(1000); 132462306a36Sopenharmony_ci printk(KERN_NOTICE "calling vpm_init\n"); 132562306a36Sopenharmony_ci vpm_init(hc); 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* check if R_F0_CNT counts (8 kHz frame count) */ 132962306a36Sopenharmony_ci val = HFC_inb(hc, R_F0_CNTL); 133062306a36Sopenharmony_ci val += HFC_inb(hc, R_F0_CNTH) << 8; 133162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 133262306a36Sopenharmony_ci printk(KERN_DEBUG 133362306a36Sopenharmony_ci "HFC_multi F0_CNT %ld after reset\n", val); 133462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 133562306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 133662306a36Sopenharmony_ci schedule_timeout((HZ / 100) ? : 1); /* Timeout minimum 10ms */ 133762306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 133862306a36Sopenharmony_ci val2 = HFC_inb(hc, R_F0_CNTL); 133962306a36Sopenharmony_ci val2 += HFC_inb(hc, R_F0_CNTH) << 8; 134062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 134162306a36Sopenharmony_ci printk(KERN_DEBUG 134262306a36Sopenharmony_ci "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", 134362306a36Sopenharmony_ci val2); 134462306a36Sopenharmony_ci if (val2 >= val + 8) { /* 1 ms */ 134562306a36Sopenharmony_ci /* it counts, so we keep the pcm mode */ 134662306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) 134762306a36Sopenharmony_ci printk(KERN_INFO "controller is PCM bus MASTER\n"); 134862306a36Sopenharmony_ci else 134962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) 135062306a36Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE\n"); 135162306a36Sopenharmony_ci else { 135262306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 135362306a36Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE " 135462306a36Sopenharmony_ci "(auto detected)\n"); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci } else { 135762306a36Sopenharmony_ci /* does not count */ 135862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { 135962306a36Sopenharmony_ci controller_fail: 136062306a36Sopenharmony_ci printk(KERN_ERR "HFC_multi ERROR, getting no 125us " 136162306a36Sopenharmony_ci "pulse. Seems that controller fails.\n"); 136262306a36Sopenharmony_ci err = -EIO; 136362306a36Sopenharmony_ci goto out; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 136662306a36Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE " 136762306a36Sopenharmony_ci "(ignoring missing PCM clock)\n"); 136862306a36Sopenharmony_ci } else { 136962306a36Sopenharmony_ci /* only one pcm master */ 137062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) 137162306a36Sopenharmony_ci && plxsd_master) { 137262306a36Sopenharmony_ci printk(KERN_ERR "HFC_multi ERROR, no clock " 137362306a36Sopenharmony_ci "on another Speech Design card found. " 137462306a36Sopenharmony_ci "Please be sure to connect PCM cable.\n"); 137562306a36Sopenharmony_ci err = -EIO; 137662306a36Sopenharmony_ci goto out; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci /* retry with master clock */ 137962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 138062306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 138162306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 138262306a36Sopenharmony_ci pv = readl(plx_acc_32); 138362306a36Sopenharmony_ci pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; 138462306a36Sopenharmony_ci pv |= PLX_SYNC_O_EN; 138562306a36Sopenharmony_ci writel(pv, plx_acc_32); 138662306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 138762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 138862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: master: " 138962306a36Sopenharmony_ci "PLX_GPIO=%x\n", __func__, pv); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci hc->hw.r_pcm_md0 |= V_PCM_MD; 139262306a36Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); 139362306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 139462306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 139562306a36Sopenharmony_ci schedule_timeout((HZ / 100) ?: 1); /* Timeout min. 10ms */ 139662306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 139762306a36Sopenharmony_ci val2 = HFC_inb(hc, R_F0_CNTL); 139862306a36Sopenharmony_ci val2 += HFC_inb(hc, R_F0_CNTH) << 8; 139962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 140062306a36Sopenharmony_ci printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " 140162306a36Sopenharmony_ci "10 ms (2nd try)\n", val2); 140262306a36Sopenharmony_ci if (val2 >= val + 8) { /* 1 ms */ 140362306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, 140462306a36Sopenharmony_ci &hc->chip); 140562306a36Sopenharmony_ci printk(KERN_INFO "controller is PCM bus MASTER " 140662306a36Sopenharmony_ci "(auto detected)\n"); 140762306a36Sopenharmony_ci } else 140862306a36Sopenharmony_ci goto controller_fail; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Release the DSP Reset */ 141362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 141462306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) 141562306a36Sopenharmony_ci plxsd_master = 1; 141662306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 141762306a36Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 141862306a36Sopenharmony_ci pv = readl(plx_acc_32); 141962306a36Sopenharmony_ci pv |= PLX_DSP_RES_N; 142062306a36Sopenharmony_ci writel(pv, plx_acc_32); 142162306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 142262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 142362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", 142462306a36Sopenharmony_ci __func__, pv); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci /* pcm id */ 142862306a36Sopenharmony_ci if (hc->pcm) 142962306a36Sopenharmony_ci printk(KERN_INFO "controller has given PCM BUS ID %d\n", 143062306a36Sopenharmony_ci hc->pcm); 143162306a36Sopenharmony_ci else { 143262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) 143362306a36Sopenharmony_ci || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 143462306a36Sopenharmony_ci PCM_cnt++; /* SD has proprietary bridging */ 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci hc->pcm = PCM_cnt; 143762306a36Sopenharmony_ci printk(KERN_INFO "controller has PCM BUS ID %d " 143862306a36Sopenharmony_ci "(auto selected)\n", hc->pcm); 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* set up timer */ 144262306a36Sopenharmony_ci HFC_outb(hc, R_TI_WD, poll_timer); 144362306a36Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* set E1 state machine IRQ */ 144662306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 144762306a36Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* set DTMF detection */ 145062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { 145162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 145262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: enabling DTMF detection " 145362306a36Sopenharmony_ci "for all B-channel\n", __func__); 145462306a36Sopenharmony_ci hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; 145562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_ULAW, &hc->chip)) 145662306a36Sopenharmony_ci hc->hw.r_dtmf |= V_ULAW_SEL; 145762306a36Sopenharmony_ci HFC_outb(hc, R_DTMF_N, 102 - 1); 145862306a36Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* conference engine */ 146262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_ULAW, &hc->chip)) 146362306a36Sopenharmony_ci r_conf_en = V_CONF_EN | V_ULAW; 146462306a36Sopenharmony_ci else 146562306a36Sopenharmony_ci r_conf_en = V_CONF_EN; 146662306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 146762306a36Sopenharmony_ci HFC_outb(hc, R_CONF_EN, r_conf_en); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* setting leds */ 147062306a36Sopenharmony_ci switch (hc->leds) { 147162306a36Sopenharmony_ci case 1: /* HFC-E1 OEM */ 147262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 147362306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x32); 147462306a36Sopenharmony_ci else 147562306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x30); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0x0f); 147862306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0x00); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); 148162306a36Sopenharmony_ci break; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci case 2: /* HFC-4S OEM */ 148462306a36Sopenharmony_ci case 3: 148562306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0xf0); 148662306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0xff); 148762306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0x00); 148862306a36Sopenharmony_ci break; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { 149262306a36Sopenharmony_ci hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ 149362306a36Sopenharmony_ci HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* set master clock */ 149762306a36Sopenharmony_ci if (hc->masterclk >= 0) { 149862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 149962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: setting ST master clock " 150062306a36Sopenharmony_ci "to port %d (0..%d)\n", 150162306a36Sopenharmony_ci __func__, hc->masterclk, hc->ports - 1); 150262306a36Sopenharmony_ci hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); 150362306a36Sopenharmony_ci HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* setting misc irq */ 150962306a36Sopenharmony_ci HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); 151062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 151162306a36Sopenharmony_ci printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", 151262306a36Sopenharmony_ci hc->hw.r_irqmsk_misc); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* RAM access test */ 151562306a36Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR0, 0); 151662306a36Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR1, 0); 151762306a36Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR2, 0); 151862306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 151962306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, i); 152062306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_DATA, ((i * 3) & 0xff)); 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 152362306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, i); 152462306a36Sopenharmony_ci HFC_inb_nodebug(hc, R_RAM_DATA); 152562306a36Sopenharmony_ci rval = HFC_inb_nodebug(hc, R_INT_DATA); 152662306a36Sopenharmony_ci if (rval != ((i * 3) & 0xff)) { 152762306a36Sopenharmony_ci printk(KERN_DEBUG 152862306a36Sopenharmony_ci "addr:%x val:%x should:%x\n", i, rval, 152962306a36Sopenharmony_ci (i * 3) & 0xff); 153062306a36Sopenharmony_ci err++; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci if (err) { 153462306a36Sopenharmony_ci printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); 153562306a36Sopenharmony_ci err = -EIO; 153662306a36Sopenharmony_ci goto out; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 154062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 154162306a36Sopenharmony_ciout: 154262306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 154362306a36Sopenharmony_ci return err; 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci/* 154862306a36Sopenharmony_ci * control the watchdog 154962306a36Sopenharmony_ci */ 155062306a36Sopenharmony_cistatic void 155162306a36Sopenharmony_cihfcmulti_watchdog(struct hfc_multi *hc) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci hc->wdcount++; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (hc->wdcount > 10) { 155662306a36Sopenharmony_ci hc->wdcount = 0; 155762306a36Sopenharmony_ci hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? 155862306a36Sopenharmony_ci V_GPIO_OUT3 : V_GPIO_OUT2; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ 156162306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); 156262306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci/* 156962306a36Sopenharmony_ci * output leds 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_cistatic void 157262306a36Sopenharmony_cihfcmulti_leds(struct hfc_multi *hc) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci unsigned long lled; 157562306a36Sopenharmony_ci unsigned long leddw; 157662306a36Sopenharmony_ci int i, state, active, leds; 157762306a36Sopenharmony_ci struct dchannel *dch; 157862306a36Sopenharmony_ci int led[4]; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci switch (hc->leds) { 158162306a36Sopenharmony_ci case 1: /* HFC-E1 OEM */ 158262306a36Sopenharmony_ci /* 2 red steady: LOS 158362306a36Sopenharmony_ci * 1 red steady: L1 not active 158462306a36Sopenharmony_ci * 2 green steady: L1 active 158562306a36Sopenharmony_ci * 1st green flashing: activity on TX 158662306a36Sopenharmony_ci * 2nd green flashing: activity on RX 158762306a36Sopenharmony_ci */ 158862306a36Sopenharmony_ci led[0] = 0; 158962306a36Sopenharmony_ci led[1] = 0; 159062306a36Sopenharmony_ci led[2] = 0; 159162306a36Sopenharmony_ci led[3] = 0; 159262306a36Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 159362306a36Sopenharmony_ci if (dch) { 159462306a36Sopenharmony_ci if (hc->chan[hc->dnum[0]].los) 159562306a36Sopenharmony_ci led[1] = 1; 159662306a36Sopenharmony_ci if (hc->e1_state != 1) { 159762306a36Sopenharmony_ci led[0] = 1; 159862306a36Sopenharmony_ci hc->flash[2] = 0; 159962306a36Sopenharmony_ci hc->flash[3] = 0; 160062306a36Sopenharmony_ci } else { 160162306a36Sopenharmony_ci led[2] = 1; 160262306a36Sopenharmony_ci led[3] = 1; 160362306a36Sopenharmony_ci if (!hc->flash[2] && hc->activity_tx) 160462306a36Sopenharmony_ci hc->flash[2] = poll; 160562306a36Sopenharmony_ci if (!hc->flash[3] && hc->activity_rx) 160662306a36Sopenharmony_ci hc->flash[3] = poll; 160762306a36Sopenharmony_ci if (hc->flash[2] && hc->flash[2] < 1024) 160862306a36Sopenharmony_ci led[2] = 0; 160962306a36Sopenharmony_ci if (hc->flash[3] && hc->flash[3] < 1024) 161062306a36Sopenharmony_ci led[3] = 0; 161162306a36Sopenharmony_ci if (hc->flash[2] >= 2048) 161262306a36Sopenharmony_ci hc->flash[2] = 0; 161362306a36Sopenharmony_ci if (hc->flash[3] >= 2048) 161462306a36Sopenharmony_ci hc->flash[3] = 0; 161562306a36Sopenharmony_ci if (hc->flash[2]) 161662306a36Sopenharmony_ci hc->flash[2] += poll; 161762306a36Sopenharmony_ci if (hc->flash[3]) 161862306a36Sopenharmony_ci hc->flash[3] += poll; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; 162262306a36Sopenharmony_ci /* leds are inverted */ 162362306a36Sopenharmony_ci if (leds != (int)hc->ledstate) { 162462306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); 162562306a36Sopenharmony_ci hc->ledstate = leds; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci break; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci case 2: /* HFC-4S OEM */ 163062306a36Sopenharmony_ci /* red steady: PH_DEACTIVATE 163162306a36Sopenharmony_ci * green steady: PH_ACTIVATE 163262306a36Sopenharmony_ci * green flashing: activity on TX 163362306a36Sopenharmony_ci */ 163462306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 163562306a36Sopenharmony_ci state = 0; 163662306a36Sopenharmony_ci active = -1; 163762306a36Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 163862306a36Sopenharmony_ci if (dch) { 163962306a36Sopenharmony_ci state = dch->state; 164062306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 164162306a36Sopenharmony_ci active = 3; 164262306a36Sopenharmony_ci else 164362306a36Sopenharmony_ci active = 7; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci if (state) { 164662306a36Sopenharmony_ci if (state == active) { 164762306a36Sopenharmony_ci led[i] = 1; /* led green */ 164862306a36Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 164962306a36Sopenharmony_ci if (!hc->flash[i] && 165062306a36Sopenharmony_ci (hc->activity_tx & (1 << i))) 165162306a36Sopenharmony_ci hc->flash[i] = poll; 165262306a36Sopenharmony_ci if (hc->flash[i] && hc->flash[i] < 1024) 165362306a36Sopenharmony_ci led[i] = 0; /* led off */ 165462306a36Sopenharmony_ci if (hc->flash[i] >= 2048) 165562306a36Sopenharmony_ci hc->flash[i] = 0; 165662306a36Sopenharmony_ci if (hc->flash[i]) 165762306a36Sopenharmony_ci hc->flash[i] += poll; 165862306a36Sopenharmony_ci } else { 165962306a36Sopenharmony_ci led[i] = 2; /* led red */ 166062306a36Sopenharmony_ci hc->flash[i] = 0; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci } else 166362306a36Sopenharmony_ci led[i] = 0; /* led off */ 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 166662306a36Sopenharmony_ci leds = 0; 166762306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 166862306a36Sopenharmony_ci if (led[i] == 1) { 166962306a36Sopenharmony_ci /*green*/ 167062306a36Sopenharmony_ci leds |= (0x2 << (i * 2)); 167162306a36Sopenharmony_ci } else if (led[i] == 2) { 167262306a36Sopenharmony_ci /*red*/ 167362306a36Sopenharmony_ci leds |= (0x1 << (i * 2)); 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci if (leds != (int)hc->ledstate) { 167762306a36Sopenharmony_ci vpm_out(hc, 0, 0x1a8 + 3, leds); 167862306a36Sopenharmony_ci hc->ledstate = leds; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci } else { 168162306a36Sopenharmony_ci leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | 168262306a36Sopenharmony_ci ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | 168362306a36Sopenharmony_ci ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | 168462306a36Sopenharmony_ci ((led[0] & 1) << 6) | ((led[2] & 1) << 7); 168562306a36Sopenharmony_ci if (leds != (int)hc->ledstate) { 168662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); 168762306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); 168862306a36Sopenharmony_ci hc->ledstate = leds; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci break; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci case 3: /* HFC 1S/2S Beronet */ 169462306a36Sopenharmony_ci /* red steady: PH_DEACTIVATE 169562306a36Sopenharmony_ci * green steady: PH_ACTIVATE 169662306a36Sopenharmony_ci * green flashing: activity on TX 169762306a36Sopenharmony_ci */ 169862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 169962306a36Sopenharmony_ci state = 0; 170062306a36Sopenharmony_ci active = -1; 170162306a36Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 170262306a36Sopenharmony_ci if (dch) { 170362306a36Sopenharmony_ci state = dch->state; 170462306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 170562306a36Sopenharmony_ci active = 3; 170662306a36Sopenharmony_ci else 170762306a36Sopenharmony_ci active = 7; 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci if (state) { 171062306a36Sopenharmony_ci if (state == active) { 171162306a36Sopenharmony_ci led[i] = 1; /* led green */ 171262306a36Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 171362306a36Sopenharmony_ci if (!hc->flash[i] && 171462306a36Sopenharmony_ci (hc->activity_tx & (1 << i))) 171562306a36Sopenharmony_ci hc->flash[i] = poll; 171662306a36Sopenharmony_ci if (hc->flash[i] < 1024) 171762306a36Sopenharmony_ci led[i] = 0; /* led off */ 171862306a36Sopenharmony_ci if (hc->flash[i] >= 2048) 171962306a36Sopenharmony_ci hc->flash[i] = 0; 172062306a36Sopenharmony_ci if (hc->flash[i]) 172162306a36Sopenharmony_ci hc->flash[i] += poll; 172262306a36Sopenharmony_ci } else { 172362306a36Sopenharmony_ci led[i] = 2; /* led red */ 172462306a36Sopenharmony_ci hc->flash[i] = 0; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci } else 172762306a36Sopenharmony_ci led[i] = 0; /* led off */ 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2) 173062306a36Sopenharmony_ci | ((led[1]&1) << 3); 173162306a36Sopenharmony_ci if (leds != (int)hc->ledstate) { 173262306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_EN1, 173362306a36Sopenharmony_ci ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); 173462306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, 173562306a36Sopenharmony_ci ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); 173662306a36Sopenharmony_ci hc->ledstate = leds; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci break; 173962306a36Sopenharmony_ci case 8: /* HFC 8S+ Beronet */ 174062306a36Sopenharmony_ci /* off: PH_DEACTIVATE 174162306a36Sopenharmony_ci * steady: PH_ACTIVATE 174262306a36Sopenharmony_ci * flashing: activity on TX 174362306a36Sopenharmony_ci */ 174462306a36Sopenharmony_ci lled = 0xff; /* leds off */ 174562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 174662306a36Sopenharmony_ci state = 0; 174762306a36Sopenharmony_ci active = -1; 174862306a36Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 174962306a36Sopenharmony_ci if (dch) { 175062306a36Sopenharmony_ci state = dch->state; 175162306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 175262306a36Sopenharmony_ci active = 3; 175362306a36Sopenharmony_ci else 175462306a36Sopenharmony_ci active = 7; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci if (state) { 175762306a36Sopenharmony_ci if (state == active) { 175862306a36Sopenharmony_ci lled &= ~(1 << i); /* led on */ 175962306a36Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 176062306a36Sopenharmony_ci if (!hc->flash[i] && 176162306a36Sopenharmony_ci (hc->activity_tx & (1 << i))) 176262306a36Sopenharmony_ci hc->flash[i] = poll; 176362306a36Sopenharmony_ci if (hc->flash[i] < 1024) 176462306a36Sopenharmony_ci lled |= 1 << i; /* led off */ 176562306a36Sopenharmony_ci if (hc->flash[i] >= 2048) 176662306a36Sopenharmony_ci hc->flash[i] = 0; 176762306a36Sopenharmony_ci if (hc->flash[i]) 176862306a36Sopenharmony_ci hc->flash[i] += poll; 176962306a36Sopenharmony_ci } else 177062306a36Sopenharmony_ci hc->flash[i] = 0; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci leddw = lled << 24 | lled << 16 | lled << 8 | lled; 177462306a36Sopenharmony_ci if (leddw != hc->ledstate) { 177562306a36Sopenharmony_ci /* HFC_outb(hc, R_BRG_PCM_CFG, 1); 177662306a36Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ 177762306a36Sopenharmony_ci /* was _io before */ 177862306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); 177962306a36Sopenharmony_ci outw(0x4000, hc->pci_iobase + 4); 178062306a36Sopenharmony_ci outl(leddw, hc->pci_iobase); 178162306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); 178262306a36Sopenharmony_ci hc->ledstate = leddw; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci break; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci hc->activity_tx = 0; 178762306a36Sopenharmony_ci hc->activity_rx = 0; 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci/* 179062306a36Sopenharmony_ci * read dtmf coefficients 179162306a36Sopenharmony_ci */ 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_cistatic void 179462306a36Sopenharmony_cihfcmulti_dtmf(struct hfc_multi *hc) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci s32 *coeff; 179762306a36Sopenharmony_ci u_int mantissa; 179862306a36Sopenharmony_ci int co, ch; 179962306a36Sopenharmony_ci struct bchannel *bch = NULL; 180062306a36Sopenharmony_ci u8 exponent; 180162306a36Sopenharmony_ci int dtmf = 0; 180262306a36Sopenharmony_ci int addr; 180362306a36Sopenharmony_ci u16 w_float; 180462306a36Sopenharmony_ci struct sk_buff *skb; 180562306a36Sopenharmony_ci struct mISDNhead *hh; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 180862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); 180962306a36Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 181062306a36Sopenharmony_ci /* only process enabled B-channels */ 181162306a36Sopenharmony_ci bch = hc->chan[ch].bch; 181262306a36Sopenharmony_ci if (!bch) 181362306a36Sopenharmony_ci continue; 181462306a36Sopenharmony_ci if (!hc->created[hc->chan[ch].port]) 181562306a36Sopenharmony_ci continue; 181662306a36Sopenharmony_ci if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) 181762306a36Sopenharmony_ci continue; 181862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 181962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dtmf channel %d:", 182062306a36Sopenharmony_ci __func__, ch); 182162306a36Sopenharmony_ci coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); 182262306a36Sopenharmony_ci dtmf = 1; 182362306a36Sopenharmony_ci for (co = 0; co < 8; co++) { 182462306a36Sopenharmony_ci /* read W(n-1) coefficient */ 182562306a36Sopenharmony_ci addr = hc->DTMFbase + ((co << 7) | (ch << 2)); 182662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); 182762306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR1, addr >> 8); 182862306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr >> 16) 182962306a36Sopenharmony_ci | V_ADDR_INC); 183062306a36Sopenharmony_ci w_float = HFC_inb_nodebug(hc, R_RAM_DATA); 183162306a36Sopenharmony_ci w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); 183262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 183362306a36Sopenharmony_ci printk(" %04x", w_float); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci /* decode float (see chip doc) */ 183662306a36Sopenharmony_ci mantissa = w_float & 0x0fff; 183762306a36Sopenharmony_ci if (w_float & 0x8000) 183862306a36Sopenharmony_ci mantissa |= 0xfffff000; 183962306a36Sopenharmony_ci exponent = (w_float >> 12) & 0x7; 184062306a36Sopenharmony_ci if (exponent) { 184162306a36Sopenharmony_ci mantissa ^= 0x1000; 184262306a36Sopenharmony_ci mantissa <<= (exponent - 1); 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci /* store coefficient */ 184662306a36Sopenharmony_ci coeff[co << 1] = mantissa; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* read W(n) coefficient */ 184962306a36Sopenharmony_ci w_float = HFC_inb_nodebug(hc, R_RAM_DATA); 185062306a36Sopenharmony_ci w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); 185162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 185262306a36Sopenharmony_ci printk(" %04x", w_float); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci /* decode float (see chip doc) */ 185562306a36Sopenharmony_ci mantissa = w_float & 0x0fff; 185662306a36Sopenharmony_ci if (w_float & 0x8000) 185762306a36Sopenharmony_ci mantissa |= 0xfffff000; 185862306a36Sopenharmony_ci exponent = (w_float >> 12) & 0x7; 185962306a36Sopenharmony_ci if (exponent) { 186062306a36Sopenharmony_ci mantissa ^= 0x1000; 186162306a36Sopenharmony_ci mantissa <<= (exponent - 1); 186262306a36Sopenharmony_ci } 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* store coefficient */ 186562306a36Sopenharmony_ci coeff[(co << 1) | 1] = mantissa; 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 186862306a36Sopenharmony_ci printk(" DTMF ready %08x %08x %08x %08x " 186962306a36Sopenharmony_ci "%08x %08x %08x %08x\n", 187062306a36Sopenharmony_ci coeff[0], coeff[1], coeff[2], coeff[3], 187162306a36Sopenharmony_ci coeff[4], coeff[5], coeff[6], coeff[7]); 187262306a36Sopenharmony_ci hc->chan[ch].coeff_count++; 187362306a36Sopenharmony_ci if (hc->chan[ch].coeff_count == 8) { 187462306a36Sopenharmony_ci hc->chan[ch].coeff_count = 0; 187562306a36Sopenharmony_ci skb = mI_alloc_skb(512, GFP_ATOMIC); 187662306a36Sopenharmony_ci if (!skb) { 187762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: No memory for skb\n", 187862306a36Sopenharmony_ci __func__); 187962306a36Sopenharmony_ci continue; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci hh = mISDN_HEAD_P(skb); 188262306a36Sopenharmony_ci hh->prim = PH_CONTROL_IND; 188362306a36Sopenharmony_ci hh->id = DTMF_HFC_COEF; 188462306a36Sopenharmony_ci skb_put_data(skb, hc->chan[ch].coeff, 512); 188562306a36Sopenharmony_ci recv_Bchannel_skb(bch, skb); 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci /* restart DTMF processing */ 189062306a36Sopenharmony_ci hc->dtmf = dtmf; 189162306a36Sopenharmony_ci if (dtmf) 189262306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci/* 189762306a36Sopenharmony_ci * fill fifo as much as possible 189862306a36Sopenharmony_ci */ 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_cistatic void 190162306a36Sopenharmony_cihfcmulti_tx(struct hfc_multi *hc, int ch) 190262306a36Sopenharmony_ci{ 190362306a36Sopenharmony_ci int i, ii, temp, len = 0; 190462306a36Sopenharmony_ci int Zspace, z1, z2; /* must be int for calculation */ 190562306a36Sopenharmony_ci int Fspace, f1, f2; 190662306a36Sopenharmony_ci u_char *d; 190762306a36Sopenharmony_ci int *txpending, slot_tx; 190862306a36Sopenharmony_ci struct bchannel *bch; 190962306a36Sopenharmony_ci struct dchannel *dch; 191062306a36Sopenharmony_ci struct sk_buff **sp = NULL; 191162306a36Sopenharmony_ci int *idxp; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci bch = hc->chan[ch].bch; 191462306a36Sopenharmony_ci dch = hc->chan[ch].dch; 191562306a36Sopenharmony_ci if ((!dch) && (!bch)) 191662306a36Sopenharmony_ci return; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci txpending = &hc->chan[ch].txpending; 191962306a36Sopenharmony_ci slot_tx = hc->chan[ch].slot_tx; 192062306a36Sopenharmony_ci if (dch) { 192162306a36Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &dch->Flags)) 192262306a36Sopenharmony_ci return; 192362306a36Sopenharmony_ci sp = &dch->tx_skb; 192462306a36Sopenharmony_ci idxp = &dch->tx_idx; 192562306a36Sopenharmony_ci } else { 192662306a36Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &bch->Flags)) 192762306a36Sopenharmony_ci return; 192862306a36Sopenharmony_ci sp = &bch->tx_skb; 192962306a36Sopenharmony_ci idxp = &bch->tx_idx; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci if (*sp) 193262306a36Sopenharmony_ci len = (*sp)->len; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if ((!len) && *txpending != 1) 193562306a36Sopenharmony_ci return; /* no data */ 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 193862306a36Sopenharmony_ci (hc->chan[ch].protocol == ISDN_P_B_RAW) && 193962306a36Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 194062306a36Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) 194162306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); 194262306a36Sopenharmony_ci else 194362306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 194462306a36Sopenharmony_ci HFC_wait_nodebug(hc); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (*txpending == 2) { 194762306a36Sopenharmony_ci /* reset fifo */ 194862306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 194962306a36Sopenharmony_ci HFC_wait_nodebug(hc); 195062306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 195162306a36Sopenharmony_ci *txpending = 1; 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_cinext_frame: 195462306a36Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 195562306a36Sopenharmony_ci f1 = HFC_inb_nodebug(hc, A_F1); 195662306a36Sopenharmony_ci f2 = HFC_inb_nodebug(hc, A_F2); 195762306a36Sopenharmony_ci while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { 195862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 195962306a36Sopenharmony_ci printk(KERN_DEBUG 196062306a36Sopenharmony_ci "%s(card %d): reread f2 because %d!=%d\n", 196162306a36Sopenharmony_ci __func__, hc->id + 1, temp, f2); 196262306a36Sopenharmony_ci f2 = temp; /* repeat until F2 is equal */ 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci Fspace = f2 - f1 - 1; 196562306a36Sopenharmony_ci if (Fspace < 0) 196662306a36Sopenharmony_ci Fspace += hc->Flen; 196762306a36Sopenharmony_ci /* 196862306a36Sopenharmony_ci * Old FIFO handling doesn't give us the current Z2 read 196962306a36Sopenharmony_ci * pointer, so we cannot send the next frame before the fifo 197062306a36Sopenharmony_ci * is empty. It makes no difference except for a slightly 197162306a36Sopenharmony_ci * lower performance. 197262306a36Sopenharmony_ci */ 197362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { 197462306a36Sopenharmony_ci if (f1 != f2) 197562306a36Sopenharmony_ci Fspace = 0; 197662306a36Sopenharmony_ci else 197762306a36Sopenharmony_ci Fspace = 1; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci /* one frame only for ST D-channels, to allow resending */ 198062306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1 && dch) { 198162306a36Sopenharmony_ci if (f1 != f2) 198262306a36Sopenharmony_ci Fspace = 0; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci /* F-counter full condition */ 198562306a36Sopenharmony_ci if (Fspace == 0) 198662306a36Sopenharmony_ci return; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; 198962306a36Sopenharmony_ci z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; 199062306a36Sopenharmony_ci while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { 199162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 199262306a36Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): reread z2 because " 199362306a36Sopenharmony_ci "%d!=%d\n", __func__, hc->id + 1, temp, z2); 199462306a36Sopenharmony_ci z2 = temp; /* repeat unti Z2 is equal */ 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci hc->chan[ch].Zfill = z1 - z2; 199762306a36Sopenharmony_ci if (hc->chan[ch].Zfill < 0) 199862306a36Sopenharmony_ci hc->chan[ch].Zfill += hc->Zlen; 199962306a36Sopenharmony_ci Zspace = z2 - z1; 200062306a36Sopenharmony_ci if (Zspace <= 0) 200162306a36Sopenharmony_ci Zspace += hc->Zlen; 200262306a36Sopenharmony_ci Zspace -= 4; /* keep not too full, so pointers will not overrun */ 200362306a36Sopenharmony_ci /* fill transparent data only to maxinum transparent load (minus 4) */ 200462306a36Sopenharmony_ci if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) 200562306a36Sopenharmony_ci Zspace = Zspace - hc->Zlen + hc->max_trans; 200662306a36Sopenharmony_ci if (Zspace <= 0) /* no space of 4 bytes */ 200762306a36Sopenharmony_ci return; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci /* if no data */ 201062306a36Sopenharmony_ci if (!len) { 201162306a36Sopenharmony_ci if (z1 == z2) { /* empty */ 201262306a36Sopenharmony_ci /* if done with FIFO audio data during PCM connection */ 201362306a36Sopenharmony_ci if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && 201462306a36Sopenharmony_ci *txpending && slot_tx >= 0) { 201562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 201662306a36Sopenharmony_ci printk(KERN_DEBUG 201762306a36Sopenharmony_ci "%s: reconnecting PCM due to no " 201862306a36Sopenharmony_ci "more FIFO data: channel %d " 201962306a36Sopenharmony_ci "slot_tx %d\n", 202062306a36Sopenharmony_ci __func__, ch, slot_tx); 202162306a36Sopenharmony_ci /* connect slot */ 202262306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 202362306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 202462306a36Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 202562306a36Sopenharmony_ci /* Enable FIFO, no interrupt */ 202662306a36Sopenharmony_ci else 202762306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | 202862306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 202962306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); 203062306a36Sopenharmony_ci HFC_wait_nodebug(hc); 203162306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 203262306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 203362306a36Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 203462306a36Sopenharmony_ci /* Enable FIFO, no interrupt */ 203562306a36Sopenharmony_ci else 203662306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | 203762306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 203862306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 203962306a36Sopenharmony_ci HFC_wait_nodebug(hc); 204062306a36Sopenharmony_ci } 204162306a36Sopenharmony_ci *txpending = 0; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci return; /* no data */ 204462306a36Sopenharmony_ci } 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* "fill fifo if empty" feature */ 204762306a36Sopenharmony_ci if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) 204862306a36Sopenharmony_ci && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { 204962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FILL) 205062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: buffer empty, so we have " 205162306a36Sopenharmony_ci "underrun\n", __func__); 205262306a36Sopenharmony_ci /* fill buffer, to prevent future underrun */ 205362306a36Sopenharmony_ci hc->write_fifo(hc, hc->silence_data, poll >> 1); 205462306a36Sopenharmony_ci Zspace -= (poll >> 1); 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* if audio data and connected slot */ 205862306a36Sopenharmony_ci if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) 205962306a36Sopenharmony_ci && slot_tx >= 0) { 206062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 206162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: disconnecting PCM due to " 206262306a36Sopenharmony_ci "FIFO data: channel %d slot_tx %d\n", 206362306a36Sopenharmony_ci __func__, ch, slot_tx); 206462306a36Sopenharmony_ci /* disconnect slot */ 206562306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 206662306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 206762306a36Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 206862306a36Sopenharmony_ci /* Enable FIFO, no interrupt */ 206962306a36Sopenharmony_ci else 207062306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | 207162306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 207262306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); 207362306a36Sopenharmony_ci HFC_wait_nodebug(hc); 207462306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 207562306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 207662306a36Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 207762306a36Sopenharmony_ci /* Enable FIFO, no interrupt */ 207862306a36Sopenharmony_ci else 207962306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | 208062306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 208162306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 208262306a36Sopenharmony_ci HFC_wait_nodebug(hc); 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci *txpending = 1; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* show activity */ 208762306a36Sopenharmony_ci if (dch) 208862306a36Sopenharmony_ci hc->activity_tx |= 1 << hc->chan[ch].port; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci /* fill fifo to what we have left */ 209162306a36Sopenharmony_ci ii = len; 209262306a36Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) 209362306a36Sopenharmony_ci temp = 1; 209462306a36Sopenharmony_ci else 209562306a36Sopenharmony_ci temp = 0; 209662306a36Sopenharmony_ci i = *idxp; 209762306a36Sopenharmony_ci d = (*sp)->data + i; 209862306a36Sopenharmony_ci if (ii - i > Zspace) 209962306a36Sopenharmony_ci ii = Zspace + i; 210062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 210162306a36Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " 210262306a36Sopenharmony_ci "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", 210362306a36Sopenharmony_ci __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, 210462306a36Sopenharmony_ci temp ? "HDLC" : "TRANS"); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* Have to prep the audio data */ 210762306a36Sopenharmony_ci hc->write_fifo(hc, d, ii - i); 210862306a36Sopenharmony_ci hc->chan[ch].Zfill += ii - i; 210962306a36Sopenharmony_ci *idxp = ii; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci /* if not all data has been written */ 211262306a36Sopenharmony_ci if (ii != len) { 211362306a36Sopenharmony_ci /* NOTE: fifo is started by the calling function */ 211462306a36Sopenharmony_ci return; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci /* if all data has been written, terminate frame */ 211862306a36Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 211962306a36Sopenharmony_ci /* increment f-counter */ 212062306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); 212162306a36Sopenharmony_ci HFC_wait_nodebug(hc); 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci dev_kfree_skb(*sp); 212562306a36Sopenharmony_ci /* check for next frame */ 212662306a36Sopenharmony_ci if (bch && get_next_bframe(bch)) { 212762306a36Sopenharmony_ci len = (*sp)->len; 212862306a36Sopenharmony_ci goto next_frame; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci if (dch && get_next_dframe(dch)) { 213162306a36Sopenharmony_ci len = (*sp)->len; 213262306a36Sopenharmony_ci goto next_frame; 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci /* 213662306a36Sopenharmony_ci * now we have no more data, so in case of transparent, 213762306a36Sopenharmony_ci * we set the last byte in fifo to 'silence' in case we will get 213862306a36Sopenharmony_ci * no more data at all. this prevents sending an undefined value. 213962306a36Sopenharmony_ci */ 214062306a36Sopenharmony_ci if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) 214162306a36Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci/* NOTE: only called if E1 card is in active state */ 214662306a36Sopenharmony_cistatic void 214762306a36Sopenharmony_cihfcmulti_rx(struct hfc_multi *hc, int ch) 214862306a36Sopenharmony_ci{ 214962306a36Sopenharmony_ci int temp; 215062306a36Sopenharmony_ci int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ 215162306a36Sopenharmony_ci int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ 215262306a36Sopenharmony_ci int again = 0; 215362306a36Sopenharmony_ci struct bchannel *bch; 215462306a36Sopenharmony_ci struct dchannel *dch = NULL; 215562306a36Sopenharmony_ci struct sk_buff *skb, **sp = NULL; 215662306a36Sopenharmony_ci int maxlen; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci bch = hc->chan[ch].bch; 215962306a36Sopenharmony_ci if (bch) { 216062306a36Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &bch->Flags)) 216162306a36Sopenharmony_ci return; 216262306a36Sopenharmony_ci } else if (hc->chan[ch].dch) { 216362306a36Sopenharmony_ci dch = hc->chan[ch].dch; 216462306a36Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &dch->Flags)) 216562306a36Sopenharmony_ci return; 216662306a36Sopenharmony_ci } else { 216762306a36Sopenharmony_ci return; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_cinext_frame: 217062306a36Sopenharmony_ci /* on first AND before getting next valid frame, R_FIFO must be written 217162306a36Sopenharmony_ci to. */ 217262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 217362306a36Sopenharmony_ci (hc->chan[ch].protocol == ISDN_P_B_RAW) && 217462306a36Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 217562306a36Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) 217662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1); 217762306a36Sopenharmony_ci else 217862306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1); 217962306a36Sopenharmony_ci HFC_wait_nodebug(hc); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci /* ignore if rx is off BUT change fifo (above) to start pending TX */ 218262306a36Sopenharmony_ci if (hc->chan[ch].rx_off) { 218362306a36Sopenharmony_ci if (bch) 218462306a36Sopenharmony_ci bch->dropcnt += poll; /* not exact but fair enough */ 218562306a36Sopenharmony_ci return; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 218962306a36Sopenharmony_ci f1 = HFC_inb_nodebug(hc, A_F1); 219062306a36Sopenharmony_ci while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { 219162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 219262306a36Sopenharmony_ci printk(KERN_DEBUG 219362306a36Sopenharmony_ci "%s(card %d): reread f1 because %d!=%d\n", 219462306a36Sopenharmony_ci __func__, hc->id + 1, temp, f1); 219562306a36Sopenharmony_ci f1 = temp; /* repeat until F1 is equal */ 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci f2 = HFC_inb_nodebug(hc, A_F2); 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; 220062306a36Sopenharmony_ci while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { 220162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 220262306a36Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): reread z2 because " 220362306a36Sopenharmony_ci "%d!=%d\n", __func__, hc->id + 1, temp, z2); 220462306a36Sopenharmony_ci z1 = temp; /* repeat until Z1 is equal */ 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; 220762306a36Sopenharmony_ci Zsize = z1 - z2; 220862306a36Sopenharmony_ci if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) 220962306a36Sopenharmony_ci /* complete hdlc frame */ 221062306a36Sopenharmony_ci Zsize++; 221162306a36Sopenharmony_ci if (Zsize < 0) 221262306a36Sopenharmony_ci Zsize += hc->Zlen; 221362306a36Sopenharmony_ci /* if buffer is empty */ 221462306a36Sopenharmony_ci if (Zsize <= 0) 221562306a36Sopenharmony_ci return; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if (bch) { 221862306a36Sopenharmony_ci maxlen = bchannel_get_rxbuf(bch, Zsize); 221962306a36Sopenharmony_ci if (maxlen < 0) { 222062306a36Sopenharmony_ci pr_warn("card%d.B%d: No bufferspace for %d bytes\n", 222162306a36Sopenharmony_ci hc->id + 1, bch->nr, Zsize); 222262306a36Sopenharmony_ci return; 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci sp = &bch->rx_skb; 222562306a36Sopenharmony_ci maxlen = bch->maxlen; 222662306a36Sopenharmony_ci } else { /* Dchannel */ 222762306a36Sopenharmony_ci sp = &dch->rx_skb; 222862306a36Sopenharmony_ci maxlen = dch->maxlen + 3; 222962306a36Sopenharmony_ci if (*sp == NULL) { 223062306a36Sopenharmony_ci *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); 223162306a36Sopenharmony_ci if (*sp == NULL) { 223262306a36Sopenharmony_ci pr_warn("card%d: No mem for dch rx_skb\n", 223362306a36Sopenharmony_ci hc->id + 1); 223462306a36Sopenharmony_ci return; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci /* show activity */ 223962306a36Sopenharmony_ci if (dch) 224062306a36Sopenharmony_ci hc->activity_rx |= 1 << hc->chan[ch].port; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci /* empty fifo with what we have */ 224362306a36Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 224462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 224562306a36Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " 224662306a36Sopenharmony_ci "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " 224762306a36Sopenharmony_ci "got=%d (again %d)\n", __func__, hc->id + 1, ch, 224862306a36Sopenharmony_ci Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", 224962306a36Sopenharmony_ci f1, f2, Zsize + (*sp)->len, again); 225062306a36Sopenharmony_ci /* HDLC */ 225162306a36Sopenharmony_ci if ((Zsize + (*sp)->len) > maxlen) { 225262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 225362306a36Sopenharmony_ci printk(KERN_DEBUG 225462306a36Sopenharmony_ci "%s(card %d): hdlc-frame too large.\n", 225562306a36Sopenharmony_ci __func__, hc->id + 1); 225662306a36Sopenharmony_ci skb_trim(*sp, 0); 225762306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 225862306a36Sopenharmony_ci HFC_wait_nodebug(hc); 225962306a36Sopenharmony_ci return; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci if (f1 != f2) { 226562306a36Sopenharmony_ci /* increment Z2,F2-counter */ 226662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); 226762306a36Sopenharmony_ci HFC_wait_nodebug(hc); 226862306a36Sopenharmony_ci /* check size */ 226962306a36Sopenharmony_ci if ((*sp)->len < 4) { 227062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 227162306a36Sopenharmony_ci printk(KERN_DEBUG 227262306a36Sopenharmony_ci "%s(card %d): Frame below minimum " 227362306a36Sopenharmony_ci "size\n", __func__, hc->id + 1); 227462306a36Sopenharmony_ci skb_trim(*sp, 0); 227562306a36Sopenharmony_ci goto next_frame; 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci /* there is at least one complete frame, check crc */ 227862306a36Sopenharmony_ci if ((*sp)->data[(*sp)->len - 1]) { 227962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_CRC) 228062306a36Sopenharmony_ci printk(KERN_DEBUG 228162306a36Sopenharmony_ci "%s: CRC-error\n", __func__); 228262306a36Sopenharmony_ci skb_trim(*sp, 0); 228362306a36Sopenharmony_ci goto next_frame; 228462306a36Sopenharmony_ci } 228562306a36Sopenharmony_ci skb_trim(*sp, (*sp)->len - 3); 228662306a36Sopenharmony_ci if ((*sp)->len < MISDN_COPY_SIZE) { 228762306a36Sopenharmony_ci skb = *sp; 228862306a36Sopenharmony_ci *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); 228962306a36Sopenharmony_ci if (*sp) { 229062306a36Sopenharmony_ci skb_put_data(*sp, skb->data, skb->len); 229162306a36Sopenharmony_ci skb_trim(skb, 0); 229262306a36Sopenharmony_ci } else { 229362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: No mem\n", 229462306a36Sopenharmony_ci __func__); 229562306a36Sopenharmony_ci *sp = skb; 229662306a36Sopenharmony_ci skb = NULL; 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci } else { 229962306a36Sopenharmony_ci skb = NULL; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) { 230262306a36Sopenharmony_ci printk(KERN_DEBUG "%s(card %d):", 230362306a36Sopenharmony_ci __func__, hc->id + 1); 230462306a36Sopenharmony_ci temp = 0; 230562306a36Sopenharmony_ci while (temp < (*sp)->len) 230662306a36Sopenharmony_ci printk(" %02x", (*sp)->data[temp++]); 230762306a36Sopenharmony_ci printk("\n"); 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci if (dch) 231062306a36Sopenharmony_ci recv_Dchannel(dch); 231162306a36Sopenharmony_ci else 231262306a36Sopenharmony_ci recv_Bchannel(bch, MISDN_ID_ANY, false); 231362306a36Sopenharmony_ci *sp = skb; 231462306a36Sopenharmony_ci again++; 231562306a36Sopenharmony_ci goto next_frame; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci /* there is an incomplete frame */ 231862306a36Sopenharmony_ci } else { 231962306a36Sopenharmony_ci /* transparent */ 232062306a36Sopenharmony_ci hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); 232162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 232262306a36Sopenharmony_ci printk(KERN_DEBUG 232362306a36Sopenharmony_ci "%s(card %d): fifo(%d) reading %d bytes " 232462306a36Sopenharmony_ci "(z1=%04x, z2=%04x) TRANS\n", 232562306a36Sopenharmony_ci __func__, hc->id + 1, ch, Zsize, z1, z2); 232662306a36Sopenharmony_ci /* only bch is transparent */ 232762306a36Sopenharmony_ci recv_Bchannel(bch, hc->chan[ch].Zfill, false); 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci} 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci/* 233362306a36Sopenharmony_ci * Interrupt handler 233462306a36Sopenharmony_ci */ 233562306a36Sopenharmony_cistatic void 233662306a36Sopenharmony_cisignal_state_up(struct dchannel *dch, int info, char *msg) 233762306a36Sopenharmony_ci{ 233862306a36Sopenharmony_ci struct sk_buff *skb; 233962306a36Sopenharmony_ci int id, data = info; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 234262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", __func__, msg); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, 234762306a36Sopenharmony_ci GFP_ATOMIC); 234862306a36Sopenharmony_ci if (!skb) 234962306a36Sopenharmony_ci return; 235062306a36Sopenharmony_ci recv_Dchannel_skb(dch, skb); 235162306a36Sopenharmony_ci} 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_cistatic inline void 235462306a36Sopenharmony_cihandle_timer_irq(struct hfc_multi *hc) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci int ch, temp; 235762306a36Sopenharmony_ci struct dchannel *dch; 235862306a36Sopenharmony_ci u_long flags; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci /* process queued resync jobs */ 236162306a36Sopenharmony_ci if (hc->e1_resync) { 236262306a36Sopenharmony_ci /* lock, so e1_resync gets not changed */ 236362306a36Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 236462306a36Sopenharmony_ci if (hc->e1_resync & 1) { 236562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 236662306a36Sopenharmony_ci printk(KERN_DEBUG "Enable SYNC_I\n"); 236762306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); 236862306a36Sopenharmony_ci /* disable JATT, if RX_SYNC is set */ 236962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) 237062306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci if (hc->e1_resync & 2) { 237362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 237462306a36Sopenharmony_ci printk(KERN_DEBUG "Enable jatt PLL\n"); 237562306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci if (hc->e1_resync & 4) { 237862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 237962306a36Sopenharmony_ci printk(KERN_DEBUG 238062306a36Sopenharmony_ci "Enable QUARTZ for HFC-E1\n"); 238162306a36Sopenharmony_ci /* set jatt to quartz */ 238262306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC 238362306a36Sopenharmony_ci | V_JATT_OFF); 238462306a36Sopenharmony_ci /* switch to JATT, in case it is not already */ 238562306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci hc->e1_resync = 0; 238862306a36Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) 239262306a36Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 239362306a36Sopenharmony_ci if (hc->created[hc->chan[ch].port]) { 239462306a36Sopenharmony_ci hfcmulti_tx(hc, ch); 239562306a36Sopenharmony_ci /* fifo is started when switching to rx-fifo */ 239662306a36Sopenharmony_ci hfcmulti_rx(hc, ch); 239762306a36Sopenharmony_ci if (hc->chan[ch].dch && 239862306a36Sopenharmony_ci hc->chan[ch].nt_timer > -1) { 239962306a36Sopenharmony_ci dch = hc->chan[ch].dch; 240062306a36Sopenharmony_ci if (!(--hc->chan[ch].nt_timer)) { 240162306a36Sopenharmony_ci schedule_event(dch, 240262306a36Sopenharmony_ci FLG_PHCHANGE); 240362306a36Sopenharmony_ci if (debug & 240462306a36Sopenharmony_ci DEBUG_HFCMULTI_STATE) 240562306a36Sopenharmony_ci printk(KERN_DEBUG 240662306a36Sopenharmony_ci "%s: nt_timer at " 240762306a36Sopenharmony_ci "state %x\n", 240862306a36Sopenharmony_ci __func__, 240962306a36Sopenharmony_ci dch->state); 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci } 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { 241562306a36Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 241662306a36Sopenharmony_ci /* LOS */ 241762306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; 241862306a36Sopenharmony_ci hc->chan[hc->dnum[0]].los = temp; 241962306a36Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { 242062306a36Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].los) 242162306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_LOS_ON, 242262306a36Sopenharmony_ci "LOS detected"); 242362306a36Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].los) 242462306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_LOS_OFF, 242562306a36Sopenharmony_ci "LOS gone"); 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { 242862306a36Sopenharmony_ci /* AIS */ 242962306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; 243062306a36Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].ais) 243162306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_AIS_ON, 243262306a36Sopenharmony_ci "AIS detected"); 243362306a36Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].ais) 243462306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_AIS_OFF, 243562306a36Sopenharmony_ci "AIS gone"); 243662306a36Sopenharmony_ci hc->chan[hc->dnum[0]].ais = temp; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { 243962306a36Sopenharmony_ci /* SLIP */ 244062306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; 244162306a36Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].slip_rx) 244262306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_SLIP_RX, 244362306a36Sopenharmony_ci " bit SLIP detected RX"); 244462306a36Sopenharmony_ci hc->chan[hc->dnum[0]].slip_rx = temp; 244562306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; 244662306a36Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].slip_tx) 244762306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_SLIP_TX, 244862306a36Sopenharmony_ci " bit SLIP detected TX"); 244962306a36Sopenharmony_ci hc->chan[hc->dnum[0]].slip_tx = temp; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { 245262306a36Sopenharmony_ci /* RDI */ 245362306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; 245462306a36Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].rdi) 245562306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_RDI_ON, 245662306a36Sopenharmony_ci "RDI detected"); 245762306a36Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].rdi) 245862306a36Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_RDI_OFF, 245962306a36Sopenharmony_ci "RDI gone"); 246062306a36Sopenharmony_ci hc->chan[hc->dnum[0]].rdi = temp; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_JATT_DIR); 246362306a36Sopenharmony_ci switch (hc->chan[hc->dnum[0]].sync) { 246462306a36Sopenharmony_ci case 0: 246562306a36Sopenharmony_ci if ((temp & 0x60) == 0x60) { 246662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 246762306a36Sopenharmony_ci printk(KERN_DEBUG 246862306a36Sopenharmony_ci "%s: (id=%d) E1 now " 246962306a36Sopenharmony_ci "in clock sync\n", 247062306a36Sopenharmony_ci __func__, hc->id); 247162306a36Sopenharmony_ci HFC_outb(hc, R_RX_OFF, 247262306a36Sopenharmony_ci hc->chan[hc->dnum[0]].jitter | V_RX_INIT); 247362306a36Sopenharmony_ci HFC_outb(hc, R_TX_OFF, 247462306a36Sopenharmony_ci hc->chan[hc->dnum[0]].jitter | V_RX_INIT); 247562306a36Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 1; 247662306a36Sopenharmony_ci goto check_framesync; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci break; 247962306a36Sopenharmony_ci case 1: 248062306a36Sopenharmony_ci if ((temp & 0x60) != 0x60) { 248162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 248262306a36Sopenharmony_ci printk(KERN_DEBUG 248362306a36Sopenharmony_ci "%s: (id=%d) E1 " 248462306a36Sopenharmony_ci "lost clock sync\n", 248562306a36Sopenharmony_ci __func__, hc->id); 248662306a36Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 0; 248762306a36Sopenharmony_ci break; 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci check_framesync: 249062306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA); 249162306a36Sopenharmony_ci if (temp == 0x27) { 249262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 249362306a36Sopenharmony_ci printk(KERN_DEBUG 249462306a36Sopenharmony_ci "%s: (id=%d) E1 " 249562306a36Sopenharmony_ci "now in frame sync\n", 249662306a36Sopenharmony_ci __func__, hc->id); 249762306a36Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 2; 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci break; 250062306a36Sopenharmony_ci case 2: 250162306a36Sopenharmony_ci if ((temp & 0x60) != 0x60) { 250262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 250362306a36Sopenharmony_ci printk(KERN_DEBUG 250462306a36Sopenharmony_ci "%s: (id=%d) E1 lost " 250562306a36Sopenharmony_ci "clock & frame sync\n", 250662306a36Sopenharmony_ci __func__, hc->id); 250762306a36Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 0; 250862306a36Sopenharmony_ci break; 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA); 251162306a36Sopenharmony_ci if (temp != 0x27) { 251262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 251362306a36Sopenharmony_ci printk(KERN_DEBUG 251462306a36Sopenharmony_ci "%s: (id=%d) E1 " 251562306a36Sopenharmony_ci "lost frame sync\n", 251662306a36Sopenharmony_ci __func__, hc->id); 251762306a36Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 1; 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci break; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 252462306a36Sopenharmony_ci hfcmulti_watchdog(hc); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (hc->leds) 252762306a36Sopenharmony_ci hfcmulti_leds(hc); 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic void 253162306a36Sopenharmony_ciph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) 253262306a36Sopenharmony_ci{ 253362306a36Sopenharmony_ci struct dchannel *dch; 253462306a36Sopenharmony_ci int ch; 253562306a36Sopenharmony_ci int active; 253662306a36Sopenharmony_ci u_char st_status, temp; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci /* state machine */ 253962306a36Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 254062306a36Sopenharmony_ci if (hc->chan[ch].dch) { 254162306a36Sopenharmony_ci dch = hc->chan[ch].dch; 254262306a36Sopenharmony_ci if (r_irq_statech & 1) { 254362306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_ST_SEL, 254462306a36Sopenharmony_ci hc->chan[ch].port); 254562306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 254662306a36Sopenharmony_ci udelay(1); 254762306a36Sopenharmony_ci /* undocumented: status changes during read */ 254862306a36Sopenharmony_ci st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); 254962306a36Sopenharmony_ci while (st_status != (temp = 255062306a36Sopenharmony_ci HFC_inb_nodebug(hc, A_ST_RD_STATE))) { 255162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 255262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: reread " 255362306a36Sopenharmony_ci "STATE because %d!=%d\n", 255462306a36Sopenharmony_ci __func__, temp, 255562306a36Sopenharmony_ci st_status); 255662306a36Sopenharmony_ci st_status = temp; /* repeat */ 255762306a36Sopenharmony_ci } 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci /* Speech Design TE-sync indication */ 256062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && 256162306a36Sopenharmony_ci dch->dev.D.protocol == ISDN_P_TE_S0) { 256262306a36Sopenharmony_ci if (st_status & V_FR_SYNC_ST) 256362306a36Sopenharmony_ci hc->syncronized |= 256462306a36Sopenharmony_ci (1 << hc->chan[ch].port); 256562306a36Sopenharmony_ci else 256662306a36Sopenharmony_ci hc->syncronized &= 256762306a36Sopenharmony_ci ~(1 << hc->chan[ch].port); 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci dch->state = st_status & 0x0f; 257062306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 257162306a36Sopenharmony_ci active = 3; 257262306a36Sopenharmony_ci else 257362306a36Sopenharmony_ci active = 7; 257462306a36Sopenharmony_ci if (dch->state == active) { 257562306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 257662306a36Sopenharmony_ci (ch << 1) | 1); 257762306a36Sopenharmony_ci HFC_wait_nodebug(hc); 257862306a36Sopenharmony_ci HFC_outb_nodebug(hc, 257962306a36Sopenharmony_ci R_INC_RES_FIFO, V_RES_F); 258062306a36Sopenharmony_ci HFC_wait_nodebug(hc); 258162306a36Sopenharmony_ci dch->tx_idx = 0; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci schedule_event(dch, FLG_PHCHANGE); 258462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 258562306a36Sopenharmony_ci printk(KERN_DEBUG 258662306a36Sopenharmony_ci "%s: S/T newstate %x port %d\n", 258762306a36Sopenharmony_ci __func__, dch->state, 258862306a36Sopenharmony_ci hc->chan[ch].port); 258962306a36Sopenharmony_ci } 259062306a36Sopenharmony_ci r_irq_statech >>= 1; 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 259462306a36Sopenharmony_ci plxsd_checksync(hc, 0); 259562306a36Sopenharmony_ci} 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_cistatic void 259862306a36Sopenharmony_cififo_irq(struct hfc_multi *hc, int block) 259962306a36Sopenharmony_ci{ 260062306a36Sopenharmony_ci int ch, j; 260162306a36Sopenharmony_ci struct dchannel *dch; 260262306a36Sopenharmony_ci struct bchannel *bch; 260362306a36Sopenharmony_ci u_char r_irq_fifo_bl; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); 260662306a36Sopenharmony_ci j = 0; 260762306a36Sopenharmony_ci while (j < 8) { 260862306a36Sopenharmony_ci ch = (block << 2) + (j >> 1); 260962306a36Sopenharmony_ci dch = hc->chan[ch].dch; 261062306a36Sopenharmony_ci bch = hc->chan[ch].bch; 261162306a36Sopenharmony_ci if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { 261262306a36Sopenharmony_ci j += 2; 261362306a36Sopenharmony_ci continue; 261462306a36Sopenharmony_ci } 261562306a36Sopenharmony_ci if (dch && (r_irq_fifo_bl & (1 << j)) && 261662306a36Sopenharmony_ci test_bit(FLG_ACTIVE, &dch->Flags)) { 261762306a36Sopenharmony_ci hfcmulti_tx(hc, ch); 261862306a36Sopenharmony_ci /* start fifo */ 261962306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 262062306a36Sopenharmony_ci HFC_wait_nodebug(hc); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci if (bch && (r_irq_fifo_bl & (1 << j)) && 262362306a36Sopenharmony_ci test_bit(FLG_ACTIVE, &bch->Flags)) { 262462306a36Sopenharmony_ci hfcmulti_tx(hc, ch); 262562306a36Sopenharmony_ci /* start fifo */ 262662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 262762306a36Sopenharmony_ci HFC_wait_nodebug(hc); 262862306a36Sopenharmony_ci } 262962306a36Sopenharmony_ci j++; 263062306a36Sopenharmony_ci if (dch && (r_irq_fifo_bl & (1 << j)) && 263162306a36Sopenharmony_ci test_bit(FLG_ACTIVE, &dch->Flags)) { 263262306a36Sopenharmony_ci hfcmulti_rx(hc, ch); 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci if (bch && (r_irq_fifo_bl & (1 << j)) && 263562306a36Sopenharmony_ci test_bit(FLG_ACTIVE, &bch->Flags)) { 263662306a36Sopenharmony_ci hfcmulti_rx(hc, ch); 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci j++; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci} 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci#ifdef IRQ_DEBUG 264362306a36Sopenharmony_ciint irqsem; 264462306a36Sopenharmony_ci#endif 264562306a36Sopenharmony_cistatic irqreturn_t 264662306a36Sopenharmony_cihfcmulti_interrupt(int intno, void *dev_id) 264762306a36Sopenharmony_ci{ 264862306a36Sopenharmony_ci#ifdef IRQCOUNT_DEBUG 264962306a36Sopenharmony_ci static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, 265062306a36Sopenharmony_ci iq5 = 0, iq6 = 0, iqcnt = 0; 265162306a36Sopenharmony_ci#endif 265262306a36Sopenharmony_ci struct hfc_multi *hc = dev_id; 265362306a36Sopenharmony_ci struct dchannel *dch; 265462306a36Sopenharmony_ci u_char r_irq_statech, status, r_irq_misc, r_irq_oview; 265562306a36Sopenharmony_ci int i; 265662306a36Sopenharmony_ci void __iomem *plx_acc; 265762306a36Sopenharmony_ci u_short wval; 265862306a36Sopenharmony_ci u_char e1_syncsta, temp, temp2; 265962306a36Sopenharmony_ci u_long flags; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci if (!hc) { 266262306a36Sopenharmony_ci printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); 266362306a36Sopenharmony_ci return IRQ_NONE; 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci spin_lock(&hc->lock); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci#ifdef IRQ_DEBUG 266962306a36Sopenharmony_ci if (irqsem) 267062306a36Sopenharmony_ci printk(KERN_ERR "irq for card %d during irq from " 267162306a36Sopenharmony_ci "card %d, this is no bug.\n", hc->id + 1, irqsem); 267262306a36Sopenharmony_ci irqsem = hc->id + 1; 267362306a36Sopenharmony_ci#endif 267462306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 267562306a36Sopenharmony_ci if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) 267662306a36Sopenharmony_ci goto irq_notforus; 267762306a36Sopenharmony_ci#endif 267862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 267962306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, flags); 268062306a36Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 268162306a36Sopenharmony_ci wval = readw(plx_acc); 268262306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, flags); 268362306a36Sopenharmony_ci if (!(wval & PLX_INTCSR_LINTI1_STATUS)) 268462306a36Sopenharmony_ci goto irq_notforus; 268562306a36Sopenharmony_ci } 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci status = HFC_inb_nodebug(hc, R_STATUS); 268862306a36Sopenharmony_ci r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); 268962306a36Sopenharmony_ci#ifdef IRQCOUNT_DEBUG 269062306a36Sopenharmony_ci if (r_irq_statech) 269162306a36Sopenharmony_ci iq1++; 269262306a36Sopenharmony_ci if (status & V_DTMF_STA) 269362306a36Sopenharmony_ci iq2++; 269462306a36Sopenharmony_ci if (status & V_LOST_STA) 269562306a36Sopenharmony_ci iq3++; 269662306a36Sopenharmony_ci if (status & V_EXT_IRQSTA) 269762306a36Sopenharmony_ci iq4++; 269862306a36Sopenharmony_ci if (status & V_MISC_IRQSTA) 269962306a36Sopenharmony_ci iq5++; 270062306a36Sopenharmony_ci if (status & V_FR_IRQSTA) 270162306a36Sopenharmony_ci iq6++; 270262306a36Sopenharmony_ci if (iqcnt++ > 5000) { 270362306a36Sopenharmony_ci printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", 270462306a36Sopenharmony_ci iq1, iq2, iq3, iq4, iq5, iq6); 270562306a36Sopenharmony_ci iqcnt = 0; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci#endif 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci if (!r_irq_statech && 271062306a36Sopenharmony_ci !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | 271162306a36Sopenharmony_ci V_MISC_IRQSTA | V_FR_IRQSTA))) { 271262306a36Sopenharmony_ci /* irq is not for us */ 271362306a36Sopenharmony_ci goto irq_notforus; 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci hc->irqcnt++; 271662306a36Sopenharmony_ci if (r_irq_statech) { 271762306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) 271862306a36Sopenharmony_ci ph_state_irq(hc, r_irq_statech); 271962306a36Sopenharmony_ci } 272062306a36Sopenharmony_ci if (status & V_LOST_STA) { 272162306a36Sopenharmony_ci /* LOST IRQ */ 272262306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci if (status & V_MISC_IRQSTA) { 272562306a36Sopenharmony_ci /* misc IRQ */ 272662306a36Sopenharmony_ci r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); 272762306a36Sopenharmony_ci r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ 272862306a36Sopenharmony_ci if (r_irq_misc & V_STA_IRQ) { 272962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 273062306a36Sopenharmony_ci /* state machine */ 273162306a36Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 273262306a36Sopenharmony_ci e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); 273362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) 273462306a36Sopenharmony_ci && hc->e1_getclock) { 273562306a36Sopenharmony_ci if (e1_syncsta & V_FR_SYNC_E1) 273662306a36Sopenharmony_ci hc->syncronized = 1; 273762306a36Sopenharmony_ci else 273862306a36Sopenharmony_ci hc->syncronized = 0; 273962306a36Sopenharmony_ci } 274062306a36Sopenharmony_ci /* undocumented: status changes during read */ 274162306a36Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_E1_RD_STA); 274262306a36Sopenharmony_ci while (temp != (temp2 = 274362306a36Sopenharmony_ci HFC_inb_nodebug(hc, R_E1_RD_STA))) { 274462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 274562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: reread " 274662306a36Sopenharmony_ci "STATE because %d!=%d\n", 274762306a36Sopenharmony_ci __func__, temp, temp2); 274862306a36Sopenharmony_ci temp = temp2; /* repeat */ 274962306a36Sopenharmony_ci } 275062306a36Sopenharmony_ci /* broadcast state change to all fragments */ 275162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 275262306a36Sopenharmony_ci printk(KERN_DEBUG 275362306a36Sopenharmony_ci "%s: E1 (id=%d) newstate %x\n", 275462306a36Sopenharmony_ci __func__, hc->id, temp & 0x7); 275562306a36Sopenharmony_ci for (i = 0; i < hc->ports; i++) { 275662306a36Sopenharmony_ci dch = hc->chan[hc->dnum[i]].dch; 275762306a36Sopenharmony_ci dch->state = temp & 0x7; 275862306a36Sopenharmony_ci schedule_event(dch, FLG_PHCHANGE); 275962306a36Sopenharmony_ci } 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 276262306a36Sopenharmony_ci plxsd_checksync(hc, 0); 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci } 276562306a36Sopenharmony_ci if (r_irq_misc & V_TI_IRQ) { 276662306a36Sopenharmony_ci if (hc->iclock_on) 276762306a36Sopenharmony_ci mISDN_clock_update(hc->iclock, poll, NULL); 276862306a36Sopenharmony_ci handle_timer_irq(hc); 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci if (r_irq_misc & V_DTMF_IRQ) 277262306a36Sopenharmony_ci hfcmulti_dtmf(hc); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci if (r_irq_misc & V_IRQ_PROC) { 277562306a36Sopenharmony_ci static int irq_proc_cnt; 277662306a36Sopenharmony_ci if (!irq_proc_cnt++) 277762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: got V_IRQ_PROC -" 277862306a36Sopenharmony_ci " this should not happen\n", __func__); 277962306a36Sopenharmony_ci } 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci } 278262306a36Sopenharmony_ci if (status & V_FR_IRQSTA) { 278362306a36Sopenharmony_ci /* FIFO IRQ */ 278462306a36Sopenharmony_ci r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); 278562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 278662306a36Sopenharmony_ci if (r_irq_oview & (1 << i)) 278762306a36Sopenharmony_ci fifo_irq(hc, i); 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci } 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci#ifdef IRQ_DEBUG 279262306a36Sopenharmony_ci irqsem = 0; 279362306a36Sopenharmony_ci#endif 279462306a36Sopenharmony_ci spin_unlock(&hc->lock); 279562306a36Sopenharmony_ci return IRQ_HANDLED; 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ciirq_notforus: 279862306a36Sopenharmony_ci#ifdef IRQ_DEBUG 279962306a36Sopenharmony_ci irqsem = 0; 280062306a36Sopenharmony_ci#endif 280162306a36Sopenharmony_ci spin_unlock(&hc->lock); 280262306a36Sopenharmony_ci return IRQ_NONE; 280362306a36Sopenharmony_ci} 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci/* 280762306a36Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function 280862306a36Sopenharmony_ci */ 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_cistatic void 281162306a36Sopenharmony_cihfcmulti_dbusy_timer(struct timer_list *t) 281262306a36Sopenharmony_ci{ 281362306a36Sopenharmony_ci} 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci/* 281762306a36Sopenharmony_ci * activate/deactivate hardware for selected channels and mode 281862306a36Sopenharmony_ci * 281962306a36Sopenharmony_ci * configure B-channel with the given protocol 282062306a36Sopenharmony_ci * ch eqals to the HFC-channel (0-31) 282162306a36Sopenharmony_ci * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 282262306a36Sopenharmony_ci * for S/T, 1-31 for E1) 282362306a36Sopenharmony_ci * the hdlc interrupts will be set/unset 282462306a36Sopenharmony_ci */ 282562306a36Sopenharmony_cistatic int 282662306a36Sopenharmony_cimode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, 282762306a36Sopenharmony_ci int bank_tx, int slot_rx, int bank_rx) 282862306a36Sopenharmony_ci{ 282962306a36Sopenharmony_ci int flow_tx = 0, flow_rx = 0, routing = 0; 283062306a36Sopenharmony_ci int oslot_tx, oslot_rx; 283162306a36Sopenharmony_ci int conf; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci if (ch < 0 || ch > 31) 283462306a36Sopenharmony_ci return -EINVAL; 283562306a36Sopenharmony_ci oslot_tx = hc->chan[ch].slot_tx; 283662306a36Sopenharmony_ci oslot_rx = hc->chan[ch].slot_rx; 283762306a36Sopenharmony_ci conf = hc->chan[ch].conf; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 284062306a36Sopenharmony_ci printk(KERN_DEBUG 284162306a36Sopenharmony_ci "%s: card %d channel %d protocol %x slot old=%d new=%d " 284262306a36Sopenharmony_ci "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", 284362306a36Sopenharmony_ci __func__, hc->id, ch, protocol, oslot_tx, slot_tx, 284462306a36Sopenharmony_ci bank_tx, oslot_rx, slot_rx, bank_rx); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci if (oslot_tx >= 0 && slot_tx != oslot_tx) { 284762306a36Sopenharmony_ci /* remove from slot */ 284862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 284962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", 285062306a36Sopenharmony_ci __func__, oslot_tx); 285162306a36Sopenharmony_ci if (hc->slot_owner[oslot_tx << 1] == ch) { 285262306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, oslot_tx << 1); 285362306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0); 285462306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 285562306a36Sopenharmony_ci HFC_outb(hc, A_CONF, 0); 285662306a36Sopenharmony_ci hc->slot_owner[oslot_tx << 1] = -1; 285762306a36Sopenharmony_ci } else { 285862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 285962306a36Sopenharmony_ci printk(KERN_DEBUG 286062306a36Sopenharmony_ci "%s: we are not owner of this tx slot " 286162306a36Sopenharmony_ci "anymore, channel %d is.\n", 286262306a36Sopenharmony_ci __func__, hc->slot_owner[oslot_tx << 1]); 286362306a36Sopenharmony_ci } 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci if (oslot_rx >= 0 && slot_rx != oslot_rx) { 286762306a36Sopenharmony_ci /* remove from slot */ 286862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 286962306a36Sopenharmony_ci printk(KERN_DEBUG 287062306a36Sopenharmony_ci "%s: remove from slot %d (RX)\n", 287162306a36Sopenharmony_ci __func__, oslot_rx); 287262306a36Sopenharmony_ci if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { 287362306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); 287462306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0); 287562306a36Sopenharmony_ci hc->slot_owner[(oslot_rx << 1) | 1] = -1; 287662306a36Sopenharmony_ci } else { 287762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 287862306a36Sopenharmony_ci printk(KERN_DEBUG 287962306a36Sopenharmony_ci "%s: we are not owner of this rx slot " 288062306a36Sopenharmony_ci "anymore, channel %d is.\n", 288162306a36Sopenharmony_ci __func__, 288262306a36Sopenharmony_ci hc->slot_owner[(oslot_rx << 1) | 1]); 288362306a36Sopenharmony_ci } 288462306a36Sopenharmony_ci } 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci if (slot_tx < 0) { 288762306a36Sopenharmony_ci flow_tx = 0x80; /* FIFO->ST */ 288862306a36Sopenharmony_ci /* disable pcm slot */ 288962306a36Sopenharmony_ci hc->chan[ch].slot_tx = -1; 289062306a36Sopenharmony_ci hc->chan[ch].bank_tx = 0; 289162306a36Sopenharmony_ci } else { 289262306a36Sopenharmony_ci /* set pcm slot */ 289362306a36Sopenharmony_ci if (hc->chan[ch].txpending) 289462306a36Sopenharmony_ci flow_tx = 0x80; /* FIFO->ST */ 289562306a36Sopenharmony_ci else 289662306a36Sopenharmony_ci flow_tx = 0xc0; /* PCM->ST */ 289762306a36Sopenharmony_ci /* put on slot */ 289862306a36Sopenharmony_ci routing = bank_tx ? 0xc0 : 0x80; 289962306a36Sopenharmony_ci if (conf >= 0 || bank_tx > 1) 290062306a36Sopenharmony_ci routing = 0x40; /* loop */ 290162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 290262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: put channel %d to slot %d bank" 290362306a36Sopenharmony_ci " %d flow %02x routing %02x conf %d (TX)\n", 290462306a36Sopenharmony_ci __func__, ch, slot_tx, bank_tx, 290562306a36Sopenharmony_ci flow_tx, routing, conf); 290662306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, slot_tx << 1); 290762306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, (ch << 1) | routing); 290862306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 290962306a36Sopenharmony_ci HFC_outb(hc, A_CONF, 291062306a36Sopenharmony_ci (conf < 0) ? 0 : (conf | V_CONF_SL)); 291162306a36Sopenharmony_ci hc->slot_owner[slot_tx << 1] = ch; 291262306a36Sopenharmony_ci hc->chan[ch].slot_tx = slot_tx; 291362306a36Sopenharmony_ci hc->chan[ch].bank_tx = bank_tx; 291462306a36Sopenharmony_ci } 291562306a36Sopenharmony_ci if (slot_rx < 0) { 291662306a36Sopenharmony_ci /* disable pcm slot */ 291762306a36Sopenharmony_ci flow_rx = 0x80; /* ST->FIFO */ 291862306a36Sopenharmony_ci hc->chan[ch].slot_rx = -1; 291962306a36Sopenharmony_ci hc->chan[ch].bank_rx = 0; 292062306a36Sopenharmony_ci } else { 292162306a36Sopenharmony_ci /* set pcm slot */ 292262306a36Sopenharmony_ci if (hc->chan[ch].txpending) 292362306a36Sopenharmony_ci flow_rx = 0x80; /* ST->FIFO */ 292462306a36Sopenharmony_ci else 292562306a36Sopenharmony_ci flow_rx = 0xc0; /* ST->(FIFO,PCM) */ 292662306a36Sopenharmony_ci /* put on slot */ 292762306a36Sopenharmony_ci routing = bank_rx ? 0x80 : 0xc0; /* reversed */ 292862306a36Sopenharmony_ci if (conf >= 0 || bank_rx > 1) 292962306a36Sopenharmony_ci routing = 0x40; /* loop */ 293062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 293162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: put channel %d to slot %d bank" 293262306a36Sopenharmony_ci " %d flow %02x routing %02x conf %d (RX)\n", 293362306a36Sopenharmony_ci __func__, ch, slot_rx, bank_rx, 293462306a36Sopenharmony_ci flow_rx, routing, conf); 293562306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, (slot_rx << 1) | V_SL_DIR); 293662306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, (ch << 1) | V_CH_DIR | routing); 293762306a36Sopenharmony_ci hc->slot_owner[(slot_rx << 1) | 1] = ch; 293862306a36Sopenharmony_ci hc->chan[ch].slot_rx = slot_rx; 293962306a36Sopenharmony_ci hc->chan[ch].bank_rx = bank_rx; 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci switch (protocol) { 294362306a36Sopenharmony_ci case (ISDN_P_NONE): 294462306a36Sopenharmony_ci /* disable TX fifo */ 294562306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 294662306a36Sopenharmony_ci HFC_wait(hc); 294762306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); 294862306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 294962306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 295062306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 295162306a36Sopenharmony_ci HFC_wait(hc); 295262306a36Sopenharmony_ci /* disable RX fifo */ 295362306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 295462306a36Sopenharmony_ci HFC_wait(hc); 295562306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); 295662306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 295762306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 295862306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 295962306a36Sopenharmony_ci HFC_wait(hc); 296062306a36Sopenharmony_ci if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { 296162306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] &= 296262306a36Sopenharmony_ci ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; 296362306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 296462306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 296562306a36Sopenharmony_ci udelay(1); 296662306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 296762306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 296862306a36Sopenharmony_ci } 296962306a36Sopenharmony_ci if (hc->chan[ch].bch) { 297062306a36Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); 297162306a36Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, 297262306a36Sopenharmony_ci &hc->chan[ch].bch->Flags); 297362306a36Sopenharmony_ci } 297462306a36Sopenharmony_ci break; 297562306a36Sopenharmony_ci case (ISDN_P_B_RAW): /* B-channel */ 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 297862306a36Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 297962306a36Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) { 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci printk(KERN_DEBUG 298262306a36Sopenharmony_ci "Setting B-channel %d to echo cancelable " 298362306a36Sopenharmony_ci "state on PCM slot %d\n", ch, 298462306a36Sopenharmony_ci ((ch / 4) * 8) + ((ch % 4) * 4) + 1); 298562306a36Sopenharmony_ci printk(KERN_DEBUG 298662306a36Sopenharmony_ci "Enabling pass through for channel\n"); 298762306a36Sopenharmony_ci vpm_out(hc, ch, ((ch / 4) * 8) + 298862306a36Sopenharmony_ci ((ch % 4) * 4) + 1, 0x01); 298962306a36Sopenharmony_ci /* rx path */ 299062306a36Sopenharmony_ci /* S/T -> PCM */ 299162306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1)); 299262306a36Sopenharmony_ci HFC_wait(hc); 299362306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); 299462306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + 299562306a36Sopenharmony_ci ((ch % 4) * 4) + 1) << 1); 299662306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci /* PCM -> FIFO */ 299962306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); 300062306a36Sopenharmony_ci HFC_wait(hc); 300162306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); 300262306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 300362306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 300462306a36Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 300562306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 300662306a36Sopenharmony_ci HFC_wait(hc); 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + 300962306a36Sopenharmony_ci ((ch % 4) * 4) + 1) << 1) | 1); 301062306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci /* tx path */ 301362306a36Sopenharmony_ci /* PCM -> S/T */ 301462306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 301562306a36Sopenharmony_ci HFC_wait(hc); 301662306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); 301762306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + 301862306a36Sopenharmony_ci ((ch % 4) * 4)) << 1) | 1); 301962306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci /* FIFO -> PCM */ 302262306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); 302362306a36Sopenharmony_ci HFC_wait(hc); 302462306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); 302562306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 302662306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 302762306a36Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 302862306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 302962306a36Sopenharmony_ci HFC_wait(hc); 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci /* tx silence */ 303262306a36Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 303362306a36Sopenharmony_ci HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + 303462306a36Sopenharmony_ci ((ch % 4) * 4)) << 1); 303562306a36Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); 303662306a36Sopenharmony_ci } else { 303762306a36Sopenharmony_ci /* enable TX fifo */ 303862306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 303962306a36Sopenharmony_ci HFC_wait(hc); 304062306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 304162306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | 304262306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 304362306a36Sopenharmony_ci /* Enable FIFO, no interrupt */ 304462306a36Sopenharmony_ci else 304562306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | 304662306a36Sopenharmony_ci V_HDLC_TRP | V_IFF); 304762306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 304862306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 304962306a36Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 305062306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 305162306a36Sopenharmony_ci HFC_wait(hc); 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci /* tx silence */ 305462306a36Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 305562306a36Sopenharmony_ci /* enable RX fifo */ 305662306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 305762306a36Sopenharmony_ci HFC_wait(hc); 305862306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 305962306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | 306062306a36Sopenharmony_ci V_HDLC_TRP); 306162306a36Sopenharmony_ci /* Enable FIFO, no interrupt*/ 306262306a36Sopenharmony_ci else 306362306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | 306462306a36Sopenharmony_ci V_HDLC_TRP); 306562306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 306662306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 306762306a36Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 306862306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 306962306a36Sopenharmony_ci HFC_wait(hc); 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci } 307262306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 307362306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] |= 307462306a36Sopenharmony_ci ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; 307562306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 307662306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 307762306a36Sopenharmony_ci udelay(1); 307862306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 307962306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 308062306a36Sopenharmony_ci } 308162306a36Sopenharmony_ci if (hc->chan[ch].bch) 308262306a36Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, 308362306a36Sopenharmony_ci &hc->chan[ch].bch->Flags); 308462306a36Sopenharmony_ci break; 308562306a36Sopenharmony_ci case (ISDN_P_B_HDLC): /* B-channel */ 308662306a36Sopenharmony_ci case (ISDN_P_TE_S0): /* D-channel */ 308762306a36Sopenharmony_ci case (ISDN_P_NT_S0): 308862306a36Sopenharmony_ci case (ISDN_P_TE_E1): 308962306a36Sopenharmony_ci case (ISDN_P_NT_E1): 309062306a36Sopenharmony_ci /* enable TX fifo */ 309162306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 309262306a36Sopenharmony_ci HFC_wait(hc); 309362306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { 309462306a36Sopenharmony_ci /* E1 or B-channel */ 309562306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); 309662306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 309762306a36Sopenharmony_ci } else { 309862306a36Sopenharmony_ci /* D-Channel without HDLC fill flags */ 309962306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); 310062306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 2); 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, V_IRQ); 310362306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 310462306a36Sopenharmony_ci HFC_wait(hc); 310562306a36Sopenharmony_ci /* enable RX fifo */ 310662306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 310762306a36Sopenharmony_ci HFC_wait(hc); 310862306a36Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); 310962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) 311062306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ 311162306a36Sopenharmony_ci else 311262306a36Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ 311362306a36Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, V_IRQ); 311462306a36Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 311562306a36Sopenharmony_ci HFC_wait(hc); 311662306a36Sopenharmony_ci if (hc->chan[ch].bch) { 311762306a36Sopenharmony_ci test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); 311862306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 311962306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] |= 312062306a36Sopenharmony_ci ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; 312162306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 312262306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 312362306a36Sopenharmony_ci udelay(1); 312462306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 312562306a36Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 312662306a36Sopenharmony_ci } 312762306a36Sopenharmony_ci } 312862306a36Sopenharmony_ci break; 312962306a36Sopenharmony_ci default: 313062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: protocol not known %x\n", 313162306a36Sopenharmony_ci __func__, protocol); 313262306a36Sopenharmony_ci hc->chan[ch].protocol = ISDN_P_NONE; 313362306a36Sopenharmony_ci return -ENOPROTOOPT; 313462306a36Sopenharmony_ci } 313562306a36Sopenharmony_ci hc->chan[ch].protocol = protocol; 313662306a36Sopenharmony_ci return 0; 313762306a36Sopenharmony_ci} 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci/* 314162306a36Sopenharmony_ci * connect/disconnect PCM 314262306a36Sopenharmony_ci */ 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_cistatic void 314562306a36Sopenharmony_cihfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, 314662306a36Sopenharmony_ci int slot_rx, int bank_rx) 314762306a36Sopenharmony_ci{ 314862306a36Sopenharmony_ci if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { 314962306a36Sopenharmony_ci /* disable PCM */ 315062306a36Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); 315162306a36Sopenharmony_ci return; 315262306a36Sopenharmony_ci } 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci /* enable pcm */ 315562306a36Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, 315662306a36Sopenharmony_ci slot_rx, bank_rx); 315762306a36Sopenharmony_ci} 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci/* 316062306a36Sopenharmony_ci * set/disable conference 316162306a36Sopenharmony_ci */ 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_cistatic void 316462306a36Sopenharmony_cihfcmulti_conf(struct hfc_multi *hc, int ch, int num) 316562306a36Sopenharmony_ci{ 316662306a36Sopenharmony_ci if (num >= 0 && num <= 7) 316762306a36Sopenharmony_ci hc->chan[ch].conf = num; 316862306a36Sopenharmony_ci else 316962306a36Sopenharmony_ci hc->chan[ch].conf = -1; 317062306a36Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, 317162306a36Sopenharmony_ci hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, 317262306a36Sopenharmony_ci hc->chan[ch].bank_rx); 317362306a36Sopenharmony_ci} 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci/* 317762306a36Sopenharmony_ci * set/disable sample loop 317862306a36Sopenharmony_ci */ 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci/* NOTE: this function is experimental and therefore disabled */ 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci/* 318362306a36Sopenharmony_ci * Layer 1 callback function 318462306a36Sopenharmony_ci */ 318562306a36Sopenharmony_cistatic int 318662306a36Sopenharmony_cihfcm_l1callback(struct dchannel *dch, u_int cmd) 318762306a36Sopenharmony_ci{ 318862306a36Sopenharmony_ci struct hfc_multi *hc = dch->hw; 318962306a36Sopenharmony_ci struct sk_buff_head free_queue; 319062306a36Sopenharmony_ci u_long flags; 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci switch (cmd) { 319362306a36Sopenharmony_ci case INFO3_P8: 319462306a36Sopenharmony_ci case INFO3_P10: 319562306a36Sopenharmony_ci break; 319662306a36Sopenharmony_ci case HW_RESET_REQ: 319762306a36Sopenharmony_ci /* start activation */ 319862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 319962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 320062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 320162306a36Sopenharmony_ci printk(KERN_DEBUG 320262306a36Sopenharmony_ci "%s: HW_RESET_REQ no BRI\n", 320362306a36Sopenharmony_ci __func__); 320462306a36Sopenharmony_ci } else { 320562306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 320662306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 320762306a36Sopenharmony_ci udelay(1); 320862306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ 320962306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 321062306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3); 321162306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT * 3)); 321262306a36Sopenharmony_ci /* activate */ 321362306a36Sopenharmony_ci } 321462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 321562306a36Sopenharmony_ci l1_event(dch->l1, HW_POWERUP_IND); 321662306a36Sopenharmony_ci break; 321762306a36Sopenharmony_ci case HW_DEACT_REQ: 321862306a36Sopenharmony_ci __skb_queue_head_init(&free_queue); 321962306a36Sopenharmony_ci /* start deactivation */ 322062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 322162306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 322262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 322362306a36Sopenharmony_ci printk(KERN_DEBUG 322462306a36Sopenharmony_ci "%s: HW_DEACT_REQ no BRI\n", 322562306a36Sopenharmony_ci __func__); 322662306a36Sopenharmony_ci } else { 322762306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 322862306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 322962306a36Sopenharmony_ci udelay(1); 323062306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); 323162306a36Sopenharmony_ci /* deactivate */ 323262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 323362306a36Sopenharmony_ci hc->syncronized &= 323462306a36Sopenharmony_ci ~(1 << hc->chan[dch->slot].port); 323562306a36Sopenharmony_ci plxsd_checksync(hc, 0); 323662306a36Sopenharmony_ci } 323762306a36Sopenharmony_ci } 323862306a36Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 323962306a36Sopenharmony_ci if (dch->tx_skb) { 324062306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 324162306a36Sopenharmony_ci dch->tx_skb = NULL; 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci dch->tx_idx = 0; 324462306a36Sopenharmony_ci if (dch->rx_skb) { 324562306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 324662306a36Sopenharmony_ci dch->rx_skb = NULL; 324762306a36Sopenharmony_ci } 324862306a36Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 324962306a36Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 325062306a36Sopenharmony_ci del_timer(&dch->timer); 325162306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 325262306a36Sopenharmony_ci __skb_queue_purge(&free_queue); 325362306a36Sopenharmony_ci break; 325462306a36Sopenharmony_ci case HW_POWERUP_REQ: 325562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 325662306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 325762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 325862306a36Sopenharmony_ci printk(KERN_DEBUG 325962306a36Sopenharmony_ci "%s: HW_POWERUP_REQ no BRI\n", 326062306a36Sopenharmony_ci __func__); 326162306a36Sopenharmony_ci } else { 326262306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 326362306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 326462306a36Sopenharmony_ci udelay(1); 326562306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ 326662306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 326762306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ 326862306a36Sopenharmony_ci } 326962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 327062306a36Sopenharmony_ci break; 327162306a36Sopenharmony_ci case PH_ACTIVATE_IND: 327262306a36Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 327362306a36Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 327462306a36Sopenharmony_ci GFP_ATOMIC); 327562306a36Sopenharmony_ci break; 327662306a36Sopenharmony_ci case PH_DEACTIVATE_IND: 327762306a36Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 327862306a36Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 327962306a36Sopenharmony_ci GFP_ATOMIC); 328062306a36Sopenharmony_ci break; 328162306a36Sopenharmony_ci default: 328262306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 328362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 328462306a36Sopenharmony_ci __func__, cmd); 328562306a36Sopenharmony_ci return -1; 328662306a36Sopenharmony_ci } 328762306a36Sopenharmony_ci return 0; 328862306a36Sopenharmony_ci} 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci/* 329162306a36Sopenharmony_ci * Layer2 -> Layer 1 Transfer 329262306a36Sopenharmony_ci */ 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_cistatic int 329562306a36Sopenharmony_cihandle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) 329662306a36Sopenharmony_ci{ 329762306a36Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 329862306a36Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 329962306a36Sopenharmony_ci struct hfc_multi *hc = dch->hw; 330062306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 330162306a36Sopenharmony_ci int ret = -EINVAL; 330262306a36Sopenharmony_ci unsigned int id; 330362306a36Sopenharmony_ci u_long flags; 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci switch (hh->prim) { 330662306a36Sopenharmony_ci case PH_DATA_REQ: 330762306a36Sopenharmony_ci if (skb->len < 1) 330862306a36Sopenharmony_ci break; 330962306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 331062306a36Sopenharmony_ci ret = dchannel_senddata(dch, skb); 331162306a36Sopenharmony_ci if (ret > 0) { /* direct TX */ 331262306a36Sopenharmony_ci id = hh->id; /* skb can be freed */ 331362306a36Sopenharmony_ci hfcmulti_tx(hc, dch->slot); 331462306a36Sopenharmony_ci ret = 0; 331562306a36Sopenharmony_ci /* start fifo */ 331662306a36Sopenharmony_ci HFC_outb(hc, R_FIFO, 0); 331762306a36Sopenharmony_ci HFC_wait(hc); 331862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 331962306a36Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 332062306a36Sopenharmony_ci } else 332162306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 332262306a36Sopenharmony_ci return ret; 332362306a36Sopenharmony_ci case PH_ACTIVATE_REQ: 332462306a36Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 332562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 332662306a36Sopenharmony_ci ret = 0; 332762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 332862306a36Sopenharmony_ci printk(KERN_DEBUG 332962306a36Sopenharmony_ci "%s: PH_ACTIVATE port %d (0..%d)\n", 333062306a36Sopenharmony_ci __func__, hc->chan[dch->slot].port, 333162306a36Sopenharmony_ci hc->ports - 1); 333262306a36Sopenharmony_ci /* start activation */ 333362306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 333462306a36Sopenharmony_ci ph_state_change(dch); 333562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 333662306a36Sopenharmony_ci printk(KERN_DEBUG 333762306a36Sopenharmony_ci "%s: E1 report state %x \n", 333862306a36Sopenharmony_ci __func__, dch->state); 333962306a36Sopenharmony_ci } else { 334062306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 334162306a36Sopenharmony_ci hc->chan[dch->slot].port); 334262306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 334362306a36Sopenharmony_ci udelay(1); 334462306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); 334562306a36Sopenharmony_ci /* G1 */ 334662306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 334762306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 1); 334862306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 1 | 334962306a36Sopenharmony_ci (V_ST_ACT * 3)); /* activate */ 335062306a36Sopenharmony_ci dch->state = 1; 335162306a36Sopenharmony_ci } 335262306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 335362306a36Sopenharmony_ci } else 335462306a36Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 335562306a36Sopenharmony_ci break; 335662306a36Sopenharmony_ci case PH_DEACTIVATE_REQ: 335762306a36Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 335862306a36Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 335962306a36Sopenharmony_ci struct sk_buff_head free_queue; 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci __skb_queue_head_init(&free_queue); 336262306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 336362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 336462306a36Sopenharmony_ci printk(KERN_DEBUG 336562306a36Sopenharmony_ci "%s: PH_DEACTIVATE port %d (0..%d)\n", 336662306a36Sopenharmony_ci __func__, hc->chan[dch->slot].port, 336762306a36Sopenharmony_ci hc->ports - 1); 336862306a36Sopenharmony_ci /* start deactivation */ 336962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 337062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 337162306a36Sopenharmony_ci printk(KERN_DEBUG 337262306a36Sopenharmony_ci "%s: PH_DEACTIVATE no BRI\n", 337362306a36Sopenharmony_ci __func__); 337462306a36Sopenharmony_ci } else { 337562306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 337662306a36Sopenharmony_ci hc->chan[dch->slot].port); 337762306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 337862306a36Sopenharmony_ci udelay(1); 337962306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); 338062306a36Sopenharmony_ci /* deactivate */ 338162306a36Sopenharmony_ci dch->state = 1; 338262306a36Sopenharmony_ci } 338362306a36Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 338462306a36Sopenharmony_ci if (dch->tx_skb) { 338562306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 338662306a36Sopenharmony_ci dch->tx_skb = NULL; 338762306a36Sopenharmony_ci } 338862306a36Sopenharmony_ci dch->tx_idx = 0; 338962306a36Sopenharmony_ci if (dch->rx_skb) { 339062306a36Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 339162306a36Sopenharmony_ci dch->rx_skb = NULL; 339262306a36Sopenharmony_ci } 339362306a36Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 339462306a36Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 339562306a36Sopenharmony_ci del_timer(&dch->timer); 339662306a36Sopenharmony_ci#ifdef FIXME 339762306a36Sopenharmony_ci if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 339862306a36Sopenharmony_ci dchannel_sched_event(&hc->dch, D_CLEARBUSY); 339962306a36Sopenharmony_ci#endif 340062306a36Sopenharmony_ci ret = 0; 340162306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 340262306a36Sopenharmony_ci __skb_queue_purge(&free_queue); 340362306a36Sopenharmony_ci } else 340462306a36Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 340562306a36Sopenharmony_ci break; 340662306a36Sopenharmony_ci } 340762306a36Sopenharmony_ci if (!ret) 340862306a36Sopenharmony_ci dev_kfree_skb(skb); 340962306a36Sopenharmony_ci return ret; 341062306a36Sopenharmony_ci} 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_cistatic void 341362306a36Sopenharmony_cideactivate_bchannel(struct bchannel *bch) 341462306a36Sopenharmony_ci{ 341562306a36Sopenharmony_ci struct hfc_multi *hc = bch->hw; 341662306a36Sopenharmony_ci u_long flags; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 341962306a36Sopenharmony_ci mISDN_clear_bchannel(bch); 342062306a36Sopenharmony_ci hc->chan[bch->slot].coeff_count = 0; 342162306a36Sopenharmony_ci hc->chan[bch->slot].rx_off = 0; 342262306a36Sopenharmony_ci hc->chan[bch->slot].conf = -1; 342362306a36Sopenharmony_ci mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); 342462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 342562306a36Sopenharmony_ci} 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_cistatic int 342862306a36Sopenharmony_cihandle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) 342962306a36Sopenharmony_ci{ 343062306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 343162306a36Sopenharmony_ci struct hfc_multi *hc = bch->hw; 343262306a36Sopenharmony_ci int ret = -EINVAL; 343362306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 343462306a36Sopenharmony_ci unsigned long flags; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci switch (hh->prim) { 343762306a36Sopenharmony_ci case PH_DATA_REQ: 343862306a36Sopenharmony_ci if (!skb->len) 343962306a36Sopenharmony_ci break; 344062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 344162306a36Sopenharmony_ci ret = bchannel_senddata(bch, skb); 344262306a36Sopenharmony_ci if (ret > 0) { /* direct TX */ 344362306a36Sopenharmony_ci hfcmulti_tx(hc, bch->slot); 344462306a36Sopenharmony_ci ret = 0; 344562306a36Sopenharmony_ci /* start fifo */ 344662306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 344762306a36Sopenharmony_ci HFC_wait_nodebug(hc); 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 345062306a36Sopenharmony_ci return ret; 345162306a36Sopenharmony_ci case PH_ACTIVATE_REQ: 345262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 345362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", 345462306a36Sopenharmony_ci __func__, bch->slot); 345562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 345662306a36Sopenharmony_ci /* activate B-channel if not already activated */ 345762306a36Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { 345862306a36Sopenharmony_ci hc->chan[bch->slot].txpending = 0; 345962306a36Sopenharmony_ci ret = mode_hfcmulti(hc, bch->slot, 346062306a36Sopenharmony_ci ch->protocol, 346162306a36Sopenharmony_ci hc->chan[bch->slot].slot_tx, 346262306a36Sopenharmony_ci hc->chan[bch->slot].bank_tx, 346362306a36Sopenharmony_ci hc->chan[bch->slot].slot_rx, 346462306a36Sopenharmony_ci hc->chan[bch->slot].bank_rx); 346562306a36Sopenharmony_ci if (!ret) { 346662306a36Sopenharmony_ci if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf 346762306a36Sopenharmony_ci && test_bit(HFC_CHIP_DTMF, &hc->chip)) { 346862306a36Sopenharmony_ci /* start decoder */ 346962306a36Sopenharmony_ci hc->dtmf = 1; 347062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 347162306a36Sopenharmony_ci printk(KERN_DEBUG 347262306a36Sopenharmony_ci "%s: start dtmf decoder\n", 347362306a36Sopenharmony_ci __func__); 347462306a36Sopenharmony_ci HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | 347562306a36Sopenharmony_ci V_RST_DTMF); 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci } 347862306a36Sopenharmony_ci } else 347962306a36Sopenharmony_ci ret = 0; 348062306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 348162306a36Sopenharmony_ci if (!ret) 348262306a36Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, 348362306a36Sopenharmony_ci GFP_KERNEL); 348462306a36Sopenharmony_ci break; 348562306a36Sopenharmony_ci case PH_CONTROL_REQ: 348662306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 348762306a36Sopenharmony_ci switch (hh->id) { 348862306a36Sopenharmony_ci case HFC_SPL_LOOP_ON: /* set sample loop */ 348962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 349062306a36Sopenharmony_ci printk(KERN_DEBUG 349162306a36Sopenharmony_ci "%s: HFC_SPL_LOOP_ON (len = %d)\n", 349262306a36Sopenharmony_ci __func__, skb->len); 349362306a36Sopenharmony_ci ret = 0; 349462306a36Sopenharmony_ci break; 349562306a36Sopenharmony_ci case HFC_SPL_LOOP_OFF: /* set silence */ 349662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 349762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", 349862306a36Sopenharmony_ci __func__); 349962306a36Sopenharmony_ci ret = 0; 350062306a36Sopenharmony_ci break; 350162306a36Sopenharmony_ci default: 350262306a36Sopenharmony_ci printk(KERN_ERR 350362306a36Sopenharmony_ci "%s: unknown PH_CONTROL_REQ info %x\n", 350462306a36Sopenharmony_ci __func__, hh->id); 350562306a36Sopenharmony_ci ret = -EINVAL; 350662306a36Sopenharmony_ci } 350762306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 350862306a36Sopenharmony_ci break; 350962306a36Sopenharmony_ci case PH_DEACTIVATE_REQ: 351062306a36Sopenharmony_ci deactivate_bchannel(bch); /* locked there */ 351162306a36Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, 351262306a36Sopenharmony_ci GFP_KERNEL); 351362306a36Sopenharmony_ci ret = 0; 351462306a36Sopenharmony_ci break; 351562306a36Sopenharmony_ci } 351662306a36Sopenharmony_ci if (!ret) 351762306a36Sopenharmony_ci dev_kfree_skb(skb); 351862306a36Sopenharmony_ci return ret; 351962306a36Sopenharmony_ci} 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci/* 352262306a36Sopenharmony_ci * bchannel control function 352362306a36Sopenharmony_ci */ 352462306a36Sopenharmony_cistatic int 352562306a36Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 352662306a36Sopenharmony_ci{ 352762306a36Sopenharmony_ci int ret = 0; 352862306a36Sopenharmony_ci struct dsp_features *features = 352962306a36Sopenharmony_ci (struct dsp_features *)(*((u_long *)&cq->p1)); 353062306a36Sopenharmony_ci struct hfc_multi *hc = bch->hw; 353162306a36Sopenharmony_ci int slot_tx; 353262306a36Sopenharmony_ci int bank_tx; 353362306a36Sopenharmony_ci int slot_rx; 353462306a36Sopenharmony_ci int bank_rx; 353562306a36Sopenharmony_ci int num; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci switch (cq->op) { 353862306a36Sopenharmony_ci case MISDN_CTRL_GETOP: 353962306a36Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 354062306a36Sopenharmony_ci cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; 354162306a36Sopenharmony_ci break; 354262306a36Sopenharmony_ci case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ 354362306a36Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 354462306a36Sopenharmony_ci hc->chan[bch->slot].rx_off = !!cq->p1; 354562306a36Sopenharmony_ci if (!hc->chan[bch->slot].rx_off) { 354662306a36Sopenharmony_ci /* reset fifo on rx on */ 354762306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); 354862306a36Sopenharmony_ci HFC_wait_nodebug(hc); 354962306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 355062306a36Sopenharmony_ci HFC_wait_nodebug(hc); 355162306a36Sopenharmony_ci } 355262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 355362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", 355462306a36Sopenharmony_ci __func__, bch->nr, hc->chan[bch->slot].rx_off); 355562306a36Sopenharmony_ci break; 355662306a36Sopenharmony_ci case MISDN_CTRL_FILL_EMPTY: 355762306a36Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 355862306a36Sopenharmony_ci hc->silence = bch->fill[0]; 355962306a36Sopenharmony_ci memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); 356062306a36Sopenharmony_ci break; 356162306a36Sopenharmony_ci case MISDN_CTRL_HW_FEATURES: /* fill features structure */ 356262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 356362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HW_FEATURE request\n", 356462306a36Sopenharmony_ci __func__); 356562306a36Sopenharmony_ci /* create confirm */ 356662306a36Sopenharmony_ci features->hfc_id = hc->id; 356762306a36Sopenharmony_ci if (test_bit(HFC_CHIP_DTMF, &hc->chip)) 356862306a36Sopenharmony_ci features->hfc_dtmf = 1; 356962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_CONF, &hc->chip)) 357062306a36Sopenharmony_ci features->hfc_conf = 1; 357162306a36Sopenharmony_ci features->hfc_loops = 0; 357262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 357362306a36Sopenharmony_ci features->hfc_echocanhw = 1; 357462306a36Sopenharmony_ci } else { 357562306a36Sopenharmony_ci features->pcm_id = hc->pcm; 357662306a36Sopenharmony_ci features->pcm_slots = hc->slots; 357762306a36Sopenharmony_ci features->pcm_banks = 2; 357862306a36Sopenharmony_ci } 357962306a36Sopenharmony_ci break; 358062306a36Sopenharmony_ci case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ 358162306a36Sopenharmony_ci slot_tx = cq->p1 & 0xff; 358262306a36Sopenharmony_ci bank_tx = cq->p1 >> 8; 358362306a36Sopenharmony_ci slot_rx = cq->p2 & 0xff; 358462306a36Sopenharmony_ci bank_rx = cq->p2 >> 8; 358562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 358662306a36Sopenharmony_ci printk(KERN_DEBUG 358762306a36Sopenharmony_ci "%s: HFC_PCM_CONN slot %d bank %d (TX) " 358862306a36Sopenharmony_ci "slot %d bank %d (RX)\n", 358962306a36Sopenharmony_ci __func__, slot_tx, bank_tx, 359062306a36Sopenharmony_ci slot_rx, bank_rx); 359162306a36Sopenharmony_ci if (slot_tx < hc->slots && bank_tx <= 2 && 359262306a36Sopenharmony_ci slot_rx < hc->slots && bank_rx <= 2) 359362306a36Sopenharmony_ci hfcmulti_pcm(hc, bch->slot, 359462306a36Sopenharmony_ci slot_tx, bank_tx, slot_rx, bank_rx); 359562306a36Sopenharmony_ci else { 359662306a36Sopenharmony_ci printk(KERN_WARNING 359762306a36Sopenharmony_ci "%s: HFC_PCM_CONN slot %d bank %d (TX) " 359862306a36Sopenharmony_ci "slot %d bank %d (RX) out of range\n", 359962306a36Sopenharmony_ci __func__, slot_tx, bank_tx, 360062306a36Sopenharmony_ci slot_rx, bank_rx); 360162306a36Sopenharmony_ci ret = -EINVAL; 360262306a36Sopenharmony_ci } 360362306a36Sopenharmony_ci break; 360462306a36Sopenharmony_ci case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ 360562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 360662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", 360762306a36Sopenharmony_ci __func__); 360862306a36Sopenharmony_ci hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); 360962306a36Sopenharmony_ci break; 361062306a36Sopenharmony_ci case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ 361162306a36Sopenharmony_ci num = cq->p1 & 0xff; 361262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 361362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", 361462306a36Sopenharmony_ci __func__, num); 361562306a36Sopenharmony_ci if (num <= 7) 361662306a36Sopenharmony_ci hfcmulti_conf(hc, bch->slot, num); 361762306a36Sopenharmony_ci else { 361862306a36Sopenharmony_ci printk(KERN_WARNING 361962306a36Sopenharmony_ci "%s: HW_CONF_JOIN conf %d out of range\n", 362062306a36Sopenharmony_ci __func__, num); 362162306a36Sopenharmony_ci ret = -EINVAL; 362262306a36Sopenharmony_ci } 362362306a36Sopenharmony_ci break; 362462306a36Sopenharmony_ci case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ 362562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 362662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); 362762306a36Sopenharmony_ci hfcmulti_conf(hc, bch->slot, -1); 362862306a36Sopenharmony_ci break; 362962306a36Sopenharmony_ci case MISDN_CTRL_HFC_ECHOCAN_ON: 363062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 363162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); 363262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 363362306a36Sopenharmony_ci vpm_echocan_on(hc, bch->slot, cq->p1); 363462306a36Sopenharmony_ci else 363562306a36Sopenharmony_ci ret = -EINVAL; 363662306a36Sopenharmony_ci break; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci case MISDN_CTRL_HFC_ECHOCAN_OFF: 363962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 364062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", 364162306a36Sopenharmony_ci __func__); 364262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 364362306a36Sopenharmony_ci vpm_echocan_off(hc, bch->slot); 364462306a36Sopenharmony_ci else 364562306a36Sopenharmony_ci ret = -EINVAL; 364662306a36Sopenharmony_ci break; 364762306a36Sopenharmony_ci default: 364862306a36Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 364962306a36Sopenharmony_ci break; 365062306a36Sopenharmony_ci } 365162306a36Sopenharmony_ci return ret; 365262306a36Sopenharmony_ci} 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_cistatic int 365562306a36Sopenharmony_cihfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 365662306a36Sopenharmony_ci{ 365762306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 365862306a36Sopenharmony_ci struct hfc_multi *hc = bch->hw; 365962306a36Sopenharmony_ci int err = -EINVAL; 366062306a36Sopenharmony_ci u_long flags; 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci if (bch->debug & DEBUG_HW) 366362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 366462306a36Sopenharmony_ci __func__, cmd, arg); 366562306a36Sopenharmony_ci switch (cmd) { 366662306a36Sopenharmony_ci case CLOSE_CHANNEL: 366762306a36Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 366862306a36Sopenharmony_ci deactivate_bchannel(bch); /* locked there */ 366962306a36Sopenharmony_ci ch->protocol = ISDN_P_NONE; 367062306a36Sopenharmony_ci ch->peer = NULL; 367162306a36Sopenharmony_ci module_put(THIS_MODULE); 367262306a36Sopenharmony_ci err = 0; 367362306a36Sopenharmony_ci break; 367462306a36Sopenharmony_ci case CONTROL_CHANNEL: 367562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 367662306a36Sopenharmony_ci err = channel_bctrl(bch, arg); 367762306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 367862306a36Sopenharmony_ci break; 367962306a36Sopenharmony_ci default: 368062306a36Sopenharmony_ci printk(KERN_WARNING "%s: unknown prim(%x)\n", 368162306a36Sopenharmony_ci __func__, cmd); 368262306a36Sopenharmony_ci } 368362306a36Sopenharmony_ci return err; 368462306a36Sopenharmony_ci} 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci/* 368762306a36Sopenharmony_ci * handle D-channel events 368862306a36Sopenharmony_ci * 368962306a36Sopenharmony_ci * handle state change event 369062306a36Sopenharmony_ci */ 369162306a36Sopenharmony_cistatic void 369262306a36Sopenharmony_ciph_state_change(struct dchannel *dch) 369362306a36Sopenharmony_ci{ 369462306a36Sopenharmony_ci struct hfc_multi *hc; 369562306a36Sopenharmony_ci int ch, i; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci if (!dch) { 369862306a36Sopenharmony_ci printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); 369962306a36Sopenharmony_ci return; 370062306a36Sopenharmony_ci } 370162306a36Sopenharmony_ci hc = dch->hw; 370262306a36Sopenharmony_ci ch = dch->slot; 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 370562306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_E1) { 370662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 370762306a36Sopenharmony_ci printk(KERN_DEBUG 370862306a36Sopenharmony_ci "%s: E1 TE (id=%d) newstate %x\n", 370962306a36Sopenharmony_ci __func__, hc->id, dch->state); 371062306a36Sopenharmony_ci } else { 371162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 371262306a36Sopenharmony_ci printk(KERN_DEBUG 371362306a36Sopenharmony_ci "%s: E1 NT (id=%d) newstate %x\n", 371462306a36Sopenharmony_ci __func__, hc->id, dch->state); 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci switch (dch->state) { 371762306a36Sopenharmony_ci case (1): 371862306a36Sopenharmony_ci if (hc->e1_state != 1) { 371962306a36Sopenharmony_ci for (i = 1; i <= 31; i++) { 372062306a36Sopenharmony_ci /* reset fifos on e1 activation */ 372162306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 372262306a36Sopenharmony_ci (i << 1) | 1); 372362306a36Sopenharmony_ci HFC_wait_nodebug(hc); 372462306a36Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, 372562306a36Sopenharmony_ci V_RES_F); 372662306a36Sopenharmony_ci HFC_wait_nodebug(hc); 372762306a36Sopenharmony_ci } 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 373062306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 373162306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 373262306a36Sopenharmony_ci break; 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci default: 373562306a36Sopenharmony_ci if (hc->e1_state != 1) 373662306a36Sopenharmony_ci return; 373762306a36Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 373862306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 373962306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 374062306a36Sopenharmony_ci } 374162306a36Sopenharmony_ci hc->e1_state = dch->state; 374262306a36Sopenharmony_ci } else { 374362306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_S0) { 374462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 374562306a36Sopenharmony_ci printk(KERN_DEBUG 374662306a36Sopenharmony_ci "%s: S/T TE newstate %x\n", 374762306a36Sopenharmony_ci __func__, dch->state); 374862306a36Sopenharmony_ci switch (dch->state) { 374962306a36Sopenharmony_ci case (0): 375062306a36Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 375162306a36Sopenharmony_ci break; 375262306a36Sopenharmony_ci case (3): 375362306a36Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 375462306a36Sopenharmony_ci break; 375562306a36Sopenharmony_ci case (5): 375662306a36Sopenharmony_ci case (8): 375762306a36Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 375862306a36Sopenharmony_ci break; 375962306a36Sopenharmony_ci case (6): 376062306a36Sopenharmony_ci l1_event(dch->l1, INFO2); 376162306a36Sopenharmony_ci break; 376262306a36Sopenharmony_ci case (7): 376362306a36Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 376462306a36Sopenharmony_ci break; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci } else { 376762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 376862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: S/T NT newstate %x\n", 376962306a36Sopenharmony_ci __func__, dch->state); 377062306a36Sopenharmony_ci switch (dch->state) { 377162306a36Sopenharmony_ci case (2): 377262306a36Sopenharmony_ci if (hc->chan[ch].nt_timer == 0) { 377362306a36Sopenharmony_ci hc->chan[ch].nt_timer = -1; 377462306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 377562306a36Sopenharmony_ci hc->chan[ch].port); 377662306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 377762306a36Sopenharmony_ci udelay(1); 377862306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 4 | 377962306a36Sopenharmony_ci V_ST_LD_STA); /* G4 */ 378062306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 378162306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 4); 378262306a36Sopenharmony_ci dch->state = 4; 378362306a36Sopenharmony_ci } else { 378462306a36Sopenharmony_ci /* one extra count for the next event */ 378562306a36Sopenharmony_ci hc->chan[ch].nt_timer = 378662306a36Sopenharmony_ci nt_t1_count[poll_timer] + 1; 378762306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 378862306a36Sopenharmony_ci hc->chan[ch].port); 378962306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 379062306a36Sopenharmony_ci udelay(1); 379162306a36Sopenharmony_ci /* allow G2 -> G3 transition */ 379262306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 2 | 379362306a36Sopenharmony_ci V_SET_G2_G3); 379462306a36Sopenharmony_ci } 379562306a36Sopenharmony_ci break; 379662306a36Sopenharmony_ci case (1): 379762306a36Sopenharmony_ci hc->chan[ch].nt_timer = -1; 379862306a36Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 379962306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 380062306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 380162306a36Sopenharmony_ci break; 380262306a36Sopenharmony_ci case (4): 380362306a36Sopenharmony_ci hc->chan[ch].nt_timer = -1; 380462306a36Sopenharmony_ci break; 380562306a36Sopenharmony_ci case (3): 380662306a36Sopenharmony_ci hc->chan[ch].nt_timer = -1; 380762306a36Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 380862306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 380962306a36Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 381062306a36Sopenharmony_ci break; 381162306a36Sopenharmony_ci } 381262306a36Sopenharmony_ci } 381362306a36Sopenharmony_ci } 381462306a36Sopenharmony_ci} 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci/* 381762306a36Sopenharmony_ci * called for card mode init message 381862306a36Sopenharmony_ci */ 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_cistatic void 382162306a36Sopenharmony_cihfcmulti_initmode(struct dchannel *dch) 382262306a36Sopenharmony_ci{ 382362306a36Sopenharmony_ci struct hfc_multi *hc = dch->hw; 382462306a36Sopenharmony_ci u_char a_st_wr_state, r_e1_wr_sta; 382562306a36Sopenharmony_ci int i, pt; 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 382862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci i = dch->slot; 383162306a36Sopenharmony_ci pt = hc->chan[i].port; 383262306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 383362306a36Sopenharmony_ci /* E1 */ 383462306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].slot_tx = -1; 383562306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].slot_rx = -1; 383662306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].conf = -1; 383762306a36Sopenharmony_ci if (hc->dnum[pt]) { 383862306a36Sopenharmony_ci mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol, 383962306a36Sopenharmony_ci -1, 0, -1, 0); 384062306a36Sopenharmony_ci timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); 384162306a36Sopenharmony_ci } 384262306a36Sopenharmony_ci for (i = 1; i <= 31; i++) { 384362306a36Sopenharmony_ci if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ 384462306a36Sopenharmony_ci continue; 384562306a36Sopenharmony_ci hc->chan[i].slot_tx = -1; 384662306a36Sopenharmony_ci hc->chan[i].slot_rx = -1; 384762306a36Sopenharmony_ci hc->chan[i].conf = -1; 384862306a36Sopenharmony_ci mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); 384962306a36Sopenharmony_ci } 385062306a36Sopenharmony_ci } 385162306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && pt == 0) { 385262306a36Sopenharmony_ci /* E1, port 0 */ 385362306a36Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 385462306a36Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { 385562306a36Sopenharmony_ci HFC_outb(hc, R_LOS0, 255); /* 2 ms */ 385662306a36Sopenharmony_ci HFC_outb(hc, R_LOS1, 255); /* 512 ms */ 385762306a36Sopenharmony_ci } 385862306a36Sopenharmony_ci if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) { 385962306a36Sopenharmony_ci HFC_outb(hc, R_RX0, 0); 386062306a36Sopenharmony_ci hc->hw.r_tx0 = 0 | V_OUT_EN; 386162306a36Sopenharmony_ci } else { 386262306a36Sopenharmony_ci HFC_outb(hc, R_RX0, 1); 386362306a36Sopenharmony_ci hc->hw.r_tx0 = 1 | V_OUT_EN; 386462306a36Sopenharmony_ci } 386562306a36Sopenharmony_ci hc->hw.r_tx1 = V_ATX | V_NTRI; 386662306a36Sopenharmony_ci HFC_outb(hc, R_TX0, hc->hw.r_tx0); 386762306a36Sopenharmony_ci HFC_outb(hc, R_TX1, hc->hw.r_tx1); 386862306a36Sopenharmony_ci HFC_outb(hc, R_TX_FR0, 0x00); 386962306a36Sopenharmony_ci HFC_outb(hc, R_TX_FR1, 0xf8); 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) 387262306a36Sopenharmony_ci HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) 387762306a36Sopenharmony_ci HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_E1) { 388062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 388162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is NT-mode\n", 388262306a36Sopenharmony_ci __func__); 388362306a36Sopenharmony_ci r_e1_wr_sta = 0; /* G0 */ 388462306a36Sopenharmony_ci hc->e1_getclock = 0; 388562306a36Sopenharmony_ci } else { 388662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 388762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is TE-mode\n", 388862306a36Sopenharmony_ci __func__); 388962306a36Sopenharmony_ci r_e1_wr_sta = 0; /* F0 */ 389062306a36Sopenharmony_ci hc->e1_getclock = 1; 389162306a36Sopenharmony_ci } 389262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) 389362306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); 389462306a36Sopenharmony_ci else 389562306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 389662306a36Sopenharmony_ci if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) 389762306a36Sopenharmony_ci hc->e1_getclock = 1; 389862306a36Sopenharmony_ci if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) 389962306a36Sopenharmony_ci hc->e1_getclock = 0; 390062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 390162306a36Sopenharmony_ci /* SLAVE (clock master) */ 390262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 390362306a36Sopenharmony_ci printk(KERN_DEBUG 390462306a36Sopenharmony_ci "%s: E1 port is clock master " 390562306a36Sopenharmony_ci "(clock from PCM)\n", __func__); 390662306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); 390762306a36Sopenharmony_ci } else { 390862306a36Sopenharmony_ci if (hc->e1_getclock) { 390962306a36Sopenharmony_ci /* MASTER (clock slave) */ 391062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 391162306a36Sopenharmony_ci printk(KERN_DEBUG 391262306a36Sopenharmony_ci "%s: E1 port is clock slave " 391362306a36Sopenharmony_ci "(clock to PCM)\n", __func__); 391462306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); 391562306a36Sopenharmony_ci } else { 391662306a36Sopenharmony_ci /* MASTER (clock master) */ 391762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 391862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is " 391962306a36Sopenharmony_ci "clock master " 392062306a36Sopenharmony_ci "(clock from QUARTZ)\n", 392162306a36Sopenharmony_ci __func__); 392262306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | 392362306a36Sopenharmony_ci V_PCM_SYNC | V_JATT_OFF); 392462306a36Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 392562306a36Sopenharmony_ci } 392662306a36Sopenharmony_ci } 392762306a36Sopenharmony_ci HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ 392862306a36Sopenharmony_ci HFC_outb(hc, R_PWM_MD, V_PWM0_MD); 392962306a36Sopenharmony_ci HFC_outb(hc, R_PWM0, 0x50); 393062306a36Sopenharmony_ci HFC_outb(hc, R_PWM1, 0xff); 393162306a36Sopenharmony_ci /* state machine setup */ 393262306a36Sopenharmony_ci HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); 393362306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 393462306a36Sopenharmony_ci HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); 393562306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 393662306a36Sopenharmony_ci hc->syncronized = 0; 393762306a36Sopenharmony_ci plxsd_checksync(hc, 0); 393862306a36Sopenharmony_ci } 393962306a36Sopenharmony_ci } 394062306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 394162306a36Sopenharmony_ci /* ST */ 394262306a36Sopenharmony_ci hc->chan[i].slot_tx = -1; 394362306a36Sopenharmony_ci hc->chan[i].slot_rx = -1; 394462306a36Sopenharmony_ci hc->chan[i].conf = -1; 394562306a36Sopenharmony_ci mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); 394662306a36Sopenharmony_ci timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); 394762306a36Sopenharmony_ci hc->chan[i - 2].slot_tx = -1; 394862306a36Sopenharmony_ci hc->chan[i - 2].slot_rx = -1; 394962306a36Sopenharmony_ci hc->chan[i - 2].conf = -1; 395062306a36Sopenharmony_ci mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); 395162306a36Sopenharmony_ci hc->chan[i - 1].slot_tx = -1; 395262306a36Sopenharmony_ci hc->chan[i - 1].slot_rx = -1; 395362306a36Sopenharmony_ci hc->chan[i - 1].conf = -1; 395462306a36Sopenharmony_ci mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); 395562306a36Sopenharmony_ci /* select interface */ 395662306a36Sopenharmony_ci HFC_outb(hc, R_ST_SEL, pt); 395762306a36Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 395862306a36Sopenharmony_ci udelay(1); 395962306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) { 396062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 396162306a36Sopenharmony_ci printk(KERN_DEBUG 396262306a36Sopenharmony_ci "%s: ST port %d is NT-mode\n", 396362306a36Sopenharmony_ci __func__, pt); 396462306a36Sopenharmony_ci /* clock delay */ 396562306a36Sopenharmony_ci HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); 396662306a36Sopenharmony_ci a_st_wr_state = 1; /* G1 */ 396762306a36Sopenharmony_ci hc->hw.a_st_ctrl0[pt] = V_ST_MD; 396862306a36Sopenharmony_ci } else { 396962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 397062306a36Sopenharmony_ci printk(KERN_DEBUG 397162306a36Sopenharmony_ci "%s: ST port %d is TE-mode\n", 397262306a36Sopenharmony_ci __func__, pt); 397362306a36Sopenharmony_ci /* clock delay */ 397462306a36Sopenharmony_ci HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); 397562306a36Sopenharmony_ci a_st_wr_state = 2; /* F2 */ 397662306a36Sopenharmony_ci hc->hw.a_st_ctrl0[pt] = 0; 397762306a36Sopenharmony_ci } 397862306a36Sopenharmony_ci if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) 397962306a36Sopenharmony_ci hc->hw.a_st_ctrl0[pt] |= V_TX_LI; 398062306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 398162306a36Sopenharmony_ci hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; 398262306a36Sopenharmony_ci HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, 398362306a36Sopenharmony_ci 0x7c << 1 /* V_ST_PULSE */); 398462306a36Sopenharmony_ci } 398562306a36Sopenharmony_ci /* line setup */ 398662306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); 398762306a36Sopenharmony_ci /* disable E-channel */ 398862306a36Sopenharmony_ci if ((dch->dev.D.protocol == ISDN_P_NT_S0) || 398962306a36Sopenharmony_ci test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) 399062306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); 399162306a36Sopenharmony_ci else 399262306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL1, 0); 399362306a36Sopenharmony_ci /* enable B-channel receive */ 399462306a36Sopenharmony_ci HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); 399562306a36Sopenharmony_ci /* state machine setup */ 399662306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); 399762306a36Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 399862306a36Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); 399962306a36Sopenharmony_ci hc->hw.r_sci_msk |= 1 << pt; 400062306a36Sopenharmony_ci /* state machine interrupts */ 400162306a36Sopenharmony_ci HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); 400262306a36Sopenharmony_ci /* unset sync on port */ 400362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 400462306a36Sopenharmony_ci hc->syncronized &= 400562306a36Sopenharmony_ci ~(1 << hc->chan[dch->slot].port); 400662306a36Sopenharmony_ci plxsd_checksync(hc, 0); 400762306a36Sopenharmony_ci } 400862306a36Sopenharmony_ci } 400962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 401062306a36Sopenharmony_ci printk("%s: done\n", __func__); 401162306a36Sopenharmony_ci} 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_cistatic int 401562306a36Sopenharmony_ciopen_dchannel(struct hfc_multi *hc, struct dchannel *dch, 401662306a36Sopenharmony_ci struct channel_req *rq) 401762306a36Sopenharmony_ci{ 401862306a36Sopenharmony_ci int err = 0; 401962306a36Sopenharmony_ci u_long flags; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 402262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, 402362306a36Sopenharmony_ci dch->dev.id, __builtin_return_address(0)); 402462306a36Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 402562306a36Sopenharmony_ci return -EINVAL; 402662306a36Sopenharmony_ci if ((dch->dev.D.protocol != ISDN_P_NONE) && 402762306a36Sopenharmony_ci (dch->dev.D.protocol != rq->protocol)) { 402862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 402962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: change protocol %x to %x\n", 403062306a36Sopenharmony_ci __func__, dch->dev.D.protocol, rq->protocol); 403162306a36Sopenharmony_ci } 403262306a36Sopenharmony_ci if ((dch->dev.D.protocol == ISDN_P_TE_S0) && 403362306a36Sopenharmony_ci (rq->protocol != ISDN_P_TE_S0)) 403462306a36Sopenharmony_ci l1_event(dch->l1, CLOSE_CHANNEL); 403562306a36Sopenharmony_ci if (dch->dev.D.protocol != rq->protocol) { 403662306a36Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 403762306a36Sopenharmony_ci err = create_l1(dch, hfcm_l1callback); 403862306a36Sopenharmony_ci if (err) 403962306a36Sopenharmony_ci return err; 404062306a36Sopenharmony_ci } 404162306a36Sopenharmony_ci dch->dev.D.protocol = rq->protocol; 404262306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 404362306a36Sopenharmony_ci hfcmulti_initmode(dch); 404462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 404562306a36Sopenharmony_ci } 404662306a36Sopenharmony_ci if (test_bit(FLG_ACTIVE, &dch->Flags)) 404762306a36Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 404862306a36Sopenharmony_ci 0, NULL, GFP_KERNEL); 404962306a36Sopenharmony_ci rq->ch = &dch->dev.D; 405062306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 405162306a36Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 405262306a36Sopenharmony_ci return 0; 405362306a36Sopenharmony_ci} 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_cistatic int 405662306a36Sopenharmony_ciopen_bchannel(struct hfc_multi *hc, struct dchannel *dch, 405762306a36Sopenharmony_ci struct channel_req *rq) 405862306a36Sopenharmony_ci{ 405962306a36Sopenharmony_ci struct bchannel *bch; 406062306a36Sopenharmony_ci int ch; 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) 406362306a36Sopenharmony_ci return -EINVAL; 406462306a36Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 406562306a36Sopenharmony_ci return -EINVAL; 406662306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 406762306a36Sopenharmony_ci ch = rq->adr.channel; 406862306a36Sopenharmony_ci else 406962306a36Sopenharmony_ci ch = (rq->adr.channel - 1) + (dch->slot - 2); 407062306a36Sopenharmony_ci bch = hc->chan[ch].bch; 407162306a36Sopenharmony_ci if (!bch) { 407262306a36Sopenharmony_ci printk(KERN_ERR "%s:internal error ch %d has no bch\n", 407362306a36Sopenharmony_ci __func__, ch); 407462306a36Sopenharmony_ci return -EINVAL; 407562306a36Sopenharmony_ci } 407662306a36Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 407762306a36Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 407862306a36Sopenharmony_ci bch->ch.protocol = rq->protocol; 407962306a36Sopenharmony_ci hc->chan[ch].rx_off = 0; 408062306a36Sopenharmony_ci rq->ch = &bch->ch; 408162306a36Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 408262306a36Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 408362306a36Sopenharmony_ci return 0; 408462306a36Sopenharmony_ci} 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_ci/* 408762306a36Sopenharmony_ci * device control function 408862306a36Sopenharmony_ci */ 408962306a36Sopenharmony_cistatic int 409062306a36Sopenharmony_cichannel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) 409162306a36Sopenharmony_ci{ 409262306a36Sopenharmony_ci struct hfc_multi *hc = dch->hw; 409362306a36Sopenharmony_ci int ret = 0; 409462306a36Sopenharmony_ci int wd_mode, wd_cnt; 409562306a36Sopenharmony_ci 409662306a36Sopenharmony_ci switch (cq->op) { 409762306a36Sopenharmony_ci case MISDN_CTRL_GETOP: 409862306a36Sopenharmony_ci cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3; 409962306a36Sopenharmony_ci break; 410062306a36Sopenharmony_ci case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ 410162306a36Sopenharmony_ci wd_cnt = cq->p1 & 0xf; 410262306a36Sopenharmony_ci wd_mode = !!(cq->p1 >> 4); 410362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 410462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" 410562306a36Sopenharmony_ci ", counter 0x%x\n", __func__, 410662306a36Sopenharmony_ci wd_mode ? "AUTO" : "MANUAL", wd_cnt); 410762306a36Sopenharmony_ci /* set the watchdog timer */ 410862306a36Sopenharmony_ci HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); 410962306a36Sopenharmony_ci hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); 411062306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 411162306a36Sopenharmony_ci hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; 411262306a36Sopenharmony_ci /* init the watchdog register and reset the counter */ 411362306a36Sopenharmony_ci HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); 411462306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 411562306a36Sopenharmony_ci /* enable the watchdog output for Speech-Design */ 411662306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); 411762306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); 411862306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0); 411962306a36Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); 412062306a36Sopenharmony_ci } 412162306a36Sopenharmony_ci break; 412262306a36Sopenharmony_ci case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ 412362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 412462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", 412562306a36Sopenharmony_ci __func__); 412662306a36Sopenharmony_ci HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); 412762306a36Sopenharmony_ci break; 412862306a36Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 412962306a36Sopenharmony_ci ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); 413062306a36Sopenharmony_ci break; 413162306a36Sopenharmony_ci default: 413262306a36Sopenharmony_ci printk(KERN_WARNING "%s: unknown Op %x\n", 413362306a36Sopenharmony_ci __func__, cq->op); 413462306a36Sopenharmony_ci ret = -EINVAL; 413562306a36Sopenharmony_ci break; 413662306a36Sopenharmony_ci } 413762306a36Sopenharmony_ci return ret; 413862306a36Sopenharmony_ci} 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_cistatic int 414162306a36Sopenharmony_cihfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 414262306a36Sopenharmony_ci{ 414362306a36Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 414462306a36Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 414562306a36Sopenharmony_ci struct hfc_multi *hc = dch->hw; 414662306a36Sopenharmony_ci struct channel_req *rq; 414762306a36Sopenharmony_ci int err = 0; 414862306a36Sopenharmony_ci u_long flags; 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 415162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 415262306a36Sopenharmony_ci __func__, cmd, arg); 415362306a36Sopenharmony_ci switch (cmd) { 415462306a36Sopenharmony_ci case OPEN_CHANNEL: 415562306a36Sopenharmony_ci rq = arg; 415662306a36Sopenharmony_ci switch (rq->protocol) { 415762306a36Sopenharmony_ci case ISDN_P_TE_S0: 415862306a36Sopenharmony_ci case ISDN_P_NT_S0: 415962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 416062306a36Sopenharmony_ci err = -EINVAL; 416162306a36Sopenharmony_ci break; 416262306a36Sopenharmony_ci } 416362306a36Sopenharmony_ci err = open_dchannel(hc, dch, rq); /* locked there */ 416462306a36Sopenharmony_ci break; 416562306a36Sopenharmony_ci case ISDN_P_TE_E1: 416662306a36Sopenharmony_ci case ISDN_P_NT_E1: 416762306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 416862306a36Sopenharmony_ci err = -EINVAL; 416962306a36Sopenharmony_ci break; 417062306a36Sopenharmony_ci } 417162306a36Sopenharmony_ci err = open_dchannel(hc, dch, rq); /* locked there */ 417262306a36Sopenharmony_ci break; 417362306a36Sopenharmony_ci default: 417462306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 417562306a36Sopenharmony_ci err = open_bchannel(hc, dch, rq); 417662306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 417762306a36Sopenharmony_ci } 417862306a36Sopenharmony_ci break; 417962306a36Sopenharmony_ci case CLOSE_CHANNEL: 418062306a36Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 418162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) close from %p\n", 418262306a36Sopenharmony_ci __func__, dch->dev.id, 418362306a36Sopenharmony_ci __builtin_return_address(0)); 418462306a36Sopenharmony_ci module_put(THIS_MODULE); 418562306a36Sopenharmony_ci break; 418662306a36Sopenharmony_ci case CONTROL_CHANNEL: 418762306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 418862306a36Sopenharmony_ci err = channel_dctrl(dch, arg); 418962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 419062306a36Sopenharmony_ci break; 419162306a36Sopenharmony_ci default: 419262306a36Sopenharmony_ci if (dch->debug & DEBUG_HW) 419362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 419462306a36Sopenharmony_ci __func__, cmd); 419562306a36Sopenharmony_ci err = -EINVAL; 419662306a36Sopenharmony_ci } 419762306a36Sopenharmony_ci return err; 419862306a36Sopenharmony_ci} 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_cistatic int 420162306a36Sopenharmony_ciclockctl(void *priv, int enable) 420262306a36Sopenharmony_ci{ 420362306a36Sopenharmony_ci struct hfc_multi *hc = priv; 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_ci hc->iclock_on = enable; 420662306a36Sopenharmony_ci return 0; 420762306a36Sopenharmony_ci} 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci/* 421062306a36Sopenharmony_ci * initialize the card 421162306a36Sopenharmony_ci */ 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci/* 421462306a36Sopenharmony_ci * start timer irq, wait some time and check if we have interrupts. 421562306a36Sopenharmony_ci * if not, reset chip and try again. 421662306a36Sopenharmony_ci */ 421762306a36Sopenharmony_cistatic int 421862306a36Sopenharmony_ciinit_card(struct hfc_multi *hc) 421962306a36Sopenharmony_ci{ 422062306a36Sopenharmony_ci int err = -EIO; 422162306a36Sopenharmony_ci u_long flags; 422262306a36Sopenharmony_ci void __iomem *plx_acc; 422362306a36Sopenharmony_ci u_long plx_flags; 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 422662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 422962306a36Sopenharmony_ci /* set interrupts but leave global interrupt disabled */ 423062306a36Sopenharmony_ci hc->hw.r_irq_ctrl = V_FIFO_IRQ; 423162306a36Sopenharmony_ci disable_hwirq(hc); 423262306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, 423562306a36Sopenharmony_ci "HFC-multi", hc)) { 423662306a36Sopenharmony_ci printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", 423762306a36Sopenharmony_ci hc->irq); 423862306a36Sopenharmony_ci hc->irq = 0; 423962306a36Sopenharmony_ci return -EIO; 424062306a36Sopenharmony_ci } 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 424362306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 424462306a36Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 424562306a36Sopenharmony_ci writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), 424662306a36Sopenharmony_ci plx_acc); /* enable PCI & LINT1 irq */ 424762306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 424862306a36Sopenharmony_ci } 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 425162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ %d count %d\n", 425262306a36Sopenharmony_ci __func__, hc->irq, hc->irqcnt); 425362306a36Sopenharmony_ci err = init_chip(hc); 425462306a36Sopenharmony_ci if (err) 425562306a36Sopenharmony_ci goto error; 425662306a36Sopenharmony_ci /* 425762306a36Sopenharmony_ci * Finally enable IRQ output 425862306a36Sopenharmony_ci * this is only allowed, if an IRQ routine is already 425962306a36Sopenharmony_ci * established for this HFC, so don't do that earlier 426062306a36Sopenharmony_ci */ 426162306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 426262306a36Sopenharmony_ci enable_hwirq(hc); 426362306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 426462306a36Sopenharmony_ci /* printk(KERN_DEBUG "no master irq set!!!\n"); */ 426562306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 426662306a36Sopenharmony_ci schedule_timeout((100 * HZ) / 1000); /* Timeout 100ms */ 426762306a36Sopenharmony_ci /* turn IRQ off until chip is completely initialized */ 426862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 426962306a36Sopenharmony_ci disable_hwirq(hc); 427062306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 427162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 427262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ %d count %d\n", 427362306a36Sopenharmony_ci __func__, hc->irq, hc->irqcnt); 427462306a36Sopenharmony_ci if (hc->irqcnt) { 427562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 427662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci return 0; 427962306a36Sopenharmony_ci } 428062306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 428162306a36Sopenharmony_ci printk(KERN_INFO "ignoring missing interrupts\n"); 428262306a36Sopenharmony_ci return 0; 428362306a36Sopenharmony_ci } 428462306a36Sopenharmony_ci 428562306a36Sopenharmony_ci printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", 428662306a36Sopenharmony_ci hc->irq); 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci err = -EIO; 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_cierror: 429162306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 429262306a36Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 429362306a36Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 429462306a36Sopenharmony_ci writew(0x00, plx_acc); /*disable IRQs*/ 429562306a36Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 429662306a36Sopenharmony_ci } 429762306a36Sopenharmony_ci 429862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 429962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); 430062306a36Sopenharmony_ci if (hc->irq) { 430162306a36Sopenharmony_ci free_irq(hc->irq, hc); 430262306a36Sopenharmony_ci hc->irq = 0; 430362306a36Sopenharmony_ci } 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 430662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); 430762306a36Sopenharmony_ci return err; 430862306a36Sopenharmony_ci} 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci/* 431162306a36Sopenharmony_ci * find pci device and set it up 431262306a36Sopenharmony_ci */ 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_cistatic int 431562306a36Sopenharmony_cisetup_pci(struct hfc_multi *hc, struct pci_dev *pdev, 431662306a36Sopenharmony_ci const struct pci_device_id *ent) 431762306a36Sopenharmony_ci{ 431862306a36Sopenharmony_ci struct hm_map *m = (struct hm_map *)ent->driver_data; 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci printk(KERN_INFO 432162306a36Sopenharmony_ci "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", 432262306a36Sopenharmony_ci m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci hc->pci_dev = pdev; 432562306a36Sopenharmony_ci if (m->clock2) 432662306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); 432762306a36Sopenharmony_ci 432862306a36Sopenharmony_ci if (ent->vendor == PCI_VENDOR_ID_DIGIUM && 432962306a36Sopenharmony_ci ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) { 433062306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_B410P, &hc->chip); 433162306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); 433262306a36Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 433362306a36Sopenharmony_ci hc->slots = 32; 433462306a36Sopenharmony_ci } 433562306a36Sopenharmony_ci 433662306a36Sopenharmony_ci if (hc->pci_dev->irq <= 0) { 433762306a36Sopenharmony_ci printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); 433862306a36Sopenharmony_ci return -EIO; 433962306a36Sopenharmony_ci } 434062306a36Sopenharmony_ci if (pci_enable_device(hc->pci_dev)) { 434162306a36Sopenharmony_ci printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); 434262306a36Sopenharmony_ci return -EIO; 434362306a36Sopenharmony_ci } 434462306a36Sopenharmony_ci hc->leds = m->leds; 434562306a36Sopenharmony_ci hc->ledstate = 0xAFFEAFFE; 434662306a36Sopenharmony_ci hc->opticalsupport = m->opticalsupport; 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci hc->pci_iobase = 0; 434962306a36Sopenharmony_ci hc->pci_membase = NULL; 435062306a36Sopenharmony_ci hc->plx_membase = NULL; 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci /* set memory access methods */ 435362306a36Sopenharmony_ci if (m->io_mode) /* use mode from card config */ 435462306a36Sopenharmony_ci hc->io_mode = m->io_mode; 435562306a36Sopenharmony_ci switch (hc->io_mode) { 435662306a36Sopenharmony_ci case HFC_IO_MODE_PLXSD: 435762306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); 435862306a36Sopenharmony_ci hc->slots = 128; /* required */ 435962306a36Sopenharmony_ci hc->HFC_outb = HFC_outb_pcimem; 436062306a36Sopenharmony_ci hc->HFC_inb = HFC_inb_pcimem; 436162306a36Sopenharmony_ci hc->HFC_inw = HFC_inw_pcimem; 436262306a36Sopenharmony_ci hc->HFC_wait = HFC_wait_pcimem; 436362306a36Sopenharmony_ci hc->read_fifo = read_fifo_pcimem; 436462306a36Sopenharmony_ci hc->write_fifo = write_fifo_pcimem; 436562306a36Sopenharmony_ci hc->plx_origmembase = hc->pci_dev->resource[0].start; 436662306a36Sopenharmony_ci /* MEMBASE 1 is PLX PCI Bridge */ 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci if (!hc->plx_origmembase) { 436962306a36Sopenharmony_ci printk(KERN_WARNING 437062306a36Sopenharmony_ci "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); 437162306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 437262306a36Sopenharmony_ci return -EIO; 437362306a36Sopenharmony_ci } 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ci hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); 437662306a36Sopenharmony_ci if (!hc->plx_membase) { 437762306a36Sopenharmony_ci printk(KERN_WARNING 437862306a36Sopenharmony_ci "HFC-multi: failed to remap plx address space. " 437962306a36Sopenharmony_ci "(internal error)\n"); 438062306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 438162306a36Sopenharmony_ci return -EIO; 438262306a36Sopenharmony_ci } 438362306a36Sopenharmony_ci printk(KERN_INFO 438462306a36Sopenharmony_ci "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", 438562306a36Sopenharmony_ci (u_long)hc->plx_membase, hc->plx_origmembase); 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci hc->pci_origmembase = hc->pci_dev->resource[2].start; 438862306a36Sopenharmony_ci /* MEMBASE 1 is PLX PCI Bridge */ 438962306a36Sopenharmony_ci if (!hc->pci_origmembase) { 439062306a36Sopenharmony_ci printk(KERN_WARNING 439162306a36Sopenharmony_ci "HFC-multi: No IO-Memory for PCI card found\n"); 439262306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 439362306a36Sopenharmony_ci return -EIO; 439462306a36Sopenharmony_ci } 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); 439762306a36Sopenharmony_ci if (!hc->pci_membase) { 439862306a36Sopenharmony_ci printk(KERN_WARNING "HFC-multi: failed to remap io " 439962306a36Sopenharmony_ci "address space. (internal error)\n"); 440062306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 440162306a36Sopenharmony_ci return -EIO; 440262306a36Sopenharmony_ci } 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci printk(KERN_INFO 440562306a36Sopenharmony_ci "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " 440662306a36Sopenharmony_ci "leds-type %d\n", 440762306a36Sopenharmony_ci hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, 440862306a36Sopenharmony_ci hc->pci_dev->irq, HZ, hc->leds); 440962306a36Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); 441062306a36Sopenharmony_ci break; 441162306a36Sopenharmony_ci case HFC_IO_MODE_PCIMEM: 441262306a36Sopenharmony_ci hc->HFC_outb = HFC_outb_pcimem; 441362306a36Sopenharmony_ci hc->HFC_inb = HFC_inb_pcimem; 441462306a36Sopenharmony_ci hc->HFC_inw = HFC_inw_pcimem; 441562306a36Sopenharmony_ci hc->HFC_wait = HFC_wait_pcimem; 441662306a36Sopenharmony_ci hc->read_fifo = read_fifo_pcimem; 441762306a36Sopenharmony_ci hc->write_fifo = write_fifo_pcimem; 441862306a36Sopenharmony_ci hc->pci_origmembase = hc->pci_dev->resource[1].start; 441962306a36Sopenharmony_ci if (!hc->pci_origmembase) { 442062306a36Sopenharmony_ci printk(KERN_WARNING 442162306a36Sopenharmony_ci "HFC-multi: No IO-Memory for PCI card found\n"); 442262306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 442362306a36Sopenharmony_ci return -EIO; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci 442662306a36Sopenharmony_ci hc->pci_membase = ioremap(hc->pci_origmembase, 256); 442762306a36Sopenharmony_ci if (!hc->pci_membase) { 442862306a36Sopenharmony_ci printk(KERN_WARNING 442962306a36Sopenharmony_ci "HFC-multi: failed to remap io address space. " 443062306a36Sopenharmony_ci "(internal error)\n"); 443162306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 443262306a36Sopenharmony_ci return -EIO; 443362306a36Sopenharmony_ci } 443462306a36Sopenharmony_ci printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " 443562306a36Sopenharmony_ci "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, 443662306a36Sopenharmony_ci hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); 443762306a36Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); 443862306a36Sopenharmony_ci break; 443962306a36Sopenharmony_ci case HFC_IO_MODE_REGIO: 444062306a36Sopenharmony_ci hc->HFC_outb = HFC_outb_regio; 444162306a36Sopenharmony_ci hc->HFC_inb = HFC_inb_regio; 444262306a36Sopenharmony_ci hc->HFC_inw = HFC_inw_regio; 444362306a36Sopenharmony_ci hc->HFC_wait = HFC_wait_regio; 444462306a36Sopenharmony_ci hc->read_fifo = read_fifo_regio; 444562306a36Sopenharmony_ci hc->write_fifo = write_fifo_regio; 444662306a36Sopenharmony_ci hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; 444762306a36Sopenharmony_ci if (!hc->pci_iobase) { 444862306a36Sopenharmony_ci printk(KERN_WARNING 444962306a36Sopenharmony_ci "HFC-multi: No IO for PCI card found\n"); 445062306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 445162306a36Sopenharmony_ci return -EIO; 445262306a36Sopenharmony_ci } 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { 445562306a36Sopenharmony_ci printk(KERN_WARNING "HFC-multi: failed to request " 445662306a36Sopenharmony_ci "address space at 0x%08lx (internal error)\n", 445762306a36Sopenharmony_ci hc->pci_iobase); 445862306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 445962306a36Sopenharmony_ci return -EIO; 446062306a36Sopenharmony_ci } 446162306a36Sopenharmony_ci 446262306a36Sopenharmony_ci printk(KERN_INFO 446362306a36Sopenharmony_ci "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", 446462306a36Sopenharmony_ci m->vendor_name, m->card_name, (u_int) hc->pci_iobase, 446562306a36Sopenharmony_ci hc->pci_dev->irq, HZ, hc->leds); 446662306a36Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); 446762306a36Sopenharmony_ci break; 446862306a36Sopenharmony_ci default: 446962306a36Sopenharmony_ci printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); 447062306a36Sopenharmony_ci pci_disable_device(hc->pci_dev); 447162306a36Sopenharmony_ci return -EIO; 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci pci_set_drvdata(hc->pci_dev, hc); 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_ci /* At this point the needed PCI config is done */ 447762306a36Sopenharmony_ci /* fifos are still not enabled */ 447862306a36Sopenharmony_ci return 0; 447962306a36Sopenharmony_ci} 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_ci 448262306a36Sopenharmony_ci/* 448362306a36Sopenharmony_ci * remove port 448462306a36Sopenharmony_ci */ 448562306a36Sopenharmony_ci 448662306a36Sopenharmony_cistatic void 448762306a36Sopenharmony_cirelease_port(struct hfc_multi *hc, struct dchannel *dch) 448862306a36Sopenharmony_ci{ 448962306a36Sopenharmony_ci int pt, ci, i = 0; 449062306a36Sopenharmony_ci u_long flags; 449162306a36Sopenharmony_ci struct bchannel *pb; 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci ci = dch->slot; 449462306a36Sopenharmony_ci pt = hc->chan[ci].port; 449562306a36Sopenharmony_ci 449662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 449762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: entered for port %d\n", 449862306a36Sopenharmony_ci __func__, pt + 1); 449962306a36Sopenharmony_ci 450062306a36Sopenharmony_ci if (pt >= hc->ports) { 450162306a36Sopenharmony_ci printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", 450262306a36Sopenharmony_ci __func__, pt + 1); 450362306a36Sopenharmony_ci return; 450462306a36Sopenharmony_ci } 450562306a36Sopenharmony_ci 450662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 450762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: releasing port=%d\n", 450862306a36Sopenharmony_ci __func__, pt + 1); 450962306a36Sopenharmony_ci 451062306a36Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_S0) 451162306a36Sopenharmony_ci l1_event(dch->l1, CLOSE_CHANNEL); 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci hc->chan[ci].dch = NULL; 451462306a36Sopenharmony_ci 451562306a36Sopenharmony_ci if (hc->created[pt]) { 451662306a36Sopenharmony_ci hc->created[pt] = 0; 451762306a36Sopenharmony_ci mISDN_unregister_device(&dch->dev); 451862306a36Sopenharmony_ci } 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 452162306a36Sopenharmony_ci 452262306a36Sopenharmony_ci if (dch->timer.function) { 452362306a36Sopenharmony_ci del_timer(&dch->timer); 452462306a36Sopenharmony_ci dch->timer.function = NULL; 452562306a36Sopenharmony_ci } 452662306a36Sopenharmony_ci 452762306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { /* E1 */ 452862306a36Sopenharmony_ci /* remove sync */ 452962306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 453062306a36Sopenharmony_ci hc->syncronized = 0; 453162306a36Sopenharmony_ci plxsd_checksync(hc, 1); 453262306a36Sopenharmony_ci } 453362306a36Sopenharmony_ci /* free channels */ 453462306a36Sopenharmony_ci for (i = 0; i <= 31; i++) { 453562306a36Sopenharmony_ci if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ 453662306a36Sopenharmony_ci continue; 453762306a36Sopenharmony_ci if (hc->chan[i].bch) { 453862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 453962306a36Sopenharmony_ci printk(KERN_DEBUG 454062306a36Sopenharmony_ci "%s: free port %d channel %d\n", 454162306a36Sopenharmony_ci __func__, hc->chan[i].port + 1, i); 454262306a36Sopenharmony_ci pb = hc->chan[i].bch; 454362306a36Sopenharmony_ci hc->chan[i].bch = NULL; 454462306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 454562306a36Sopenharmony_ci mISDN_freebchannel(pb); 454662306a36Sopenharmony_ci kfree(pb); 454762306a36Sopenharmony_ci kfree(hc->chan[i].coeff); 454862306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 454962306a36Sopenharmony_ci } 455062306a36Sopenharmony_ci } 455162306a36Sopenharmony_ci } else { 455262306a36Sopenharmony_ci /* remove sync */ 455362306a36Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 455462306a36Sopenharmony_ci hc->syncronized &= 455562306a36Sopenharmony_ci ~(1 << hc->chan[ci].port); 455662306a36Sopenharmony_ci plxsd_checksync(hc, 1); 455762306a36Sopenharmony_ci } 455862306a36Sopenharmony_ci /* free channels */ 455962306a36Sopenharmony_ci if (hc->chan[ci - 2].bch) { 456062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 456162306a36Sopenharmony_ci printk(KERN_DEBUG 456262306a36Sopenharmony_ci "%s: free port %d channel %d\n", 456362306a36Sopenharmony_ci __func__, hc->chan[ci - 2].port + 1, 456462306a36Sopenharmony_ci ci - 2); 456562306a36Sopenharmony_ci pb = hc->chan[ci - 2].bch; 456662306a36Sopenharmony_ci hc->chan[ci - 2].bch = NULL; 456762306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 456862306a36Sopenharmony_ci mISDN_freebchannel(pb); 456962306a36Sopenharmony_ci kfree(pb); 457062306a36Sopenharmony_ci kfree(hc->chan[ci - 2].coeff); 457162306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 457262306a36Sopenharmony_ci } 457362306a36Sopenharmony_ci if (hc->chan[ci - 1].bch) { 457462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 457562306a36Sopenharmony_ci printk(KERN_DEBUG 457662306a36Sopenharmony_ci "%s: free port %d channel %d\n", 457762306a36Sopenharmony_ci __func__, hc->chan[ci - 1].port + 1, 457862306a36Sopenharmony_ci ci - 1); 457962306a36Sopenharmony_ci pb = hc->chan[ci - 1].bch; 458062306a36Sopenharmony_ci hc->chan[ci - 1].bch = NULL; 458162306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 458262306a36Sopenharmony_ci mISDN_freebchannel(pb); 458362306a36Sopenharmony_ci kfree(pb); 458462306a36Sopenharmony_ci kfree(hc->chan[ci - 1].coeff); 458562306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 458662306a36Sopenharmony_ci } 458762306a36Sopenharmony_ci } 458862306a36Sopenharmony_ci 458962306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 459062306a36Sopenharmony_ci 459162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 459262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__, 459362306a36Sopenharmony_ci pt+1, ci); 459462306a36Sopenharmony_ci mISDN_freedchannel(dch); 459562306a36Sopenharmony_ci kfree(dch); 459662306a36Sopenharmony_ci 459762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 459862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: done!\n", __func__); 459962306a36Sopenharmony_ci} 460062306a36Sopenharmony_ci 460162306a36Sopenharmony_cistatic void 460262306a36Sopenharmony_cirelease_card(struct hfc_multi *hc) 460362306a36Sopenharmony_ci{ 460462306a36Sopenharmony_ci u_long flags; 460562306a36Sopenharmony_ci int ch; 460662306a36Sopenharmony_ci 460762306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 460862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: release card (%d) entered\n", 460962306a36Sopenharmony_ci __func__, hc->id); 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_ci /* unregister clock source */ 461262306a36Sopenharmony_ci if (hc->iclock) 461362306a36Sopenharmony_ci mISDN_unregister_clock(hc->iclock); 461462306a36Sopenharmony_ci 461562306a36Sopenharmony_ci /* disable and free irq */ 461662306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 461762306a36Sopenharmony_ci disable_hwirq(hc); 461862306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 461962306a36Sopenharmony_ci udelay(1000); 462062306a36Sopenharmony_ci if (hc->irq) { 462162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 462262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n", 462362306a36Sopenharmony_ci __func__, hc->irq, hc); 462462306a36Sopenharmony_ci free_irq(hc->irq, hc); 462562306a36Sopenharmony_ci hc->irq = 0; 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci } 462862306a36Sopenharmony_ci 462962306a36Sopenharmony_ci /* disable D-channels & B-channels */ 463062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 463162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: disable all channels (d and b)\n", 463262306a36Sopenharmony_ci __func__); 463362306a36Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 463462306a36Sopenharmony_ci if (hc->chan[ch].dch) 463562306a36Sopenharmony_ci release_port(hc, hc->chan[ch].dch); 463662306a36Sopenharmony_ci } 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci /* dimm leds */ 463962306a36Sopenharmony_ci if (hc->leds) 464062306a36Sopenharmony_ci hfcmulti_leds(hc); 464162306a36Sopenharmony_ci 464262306a36Sopenharmony_ci /* release hardware */ 464362306a36Sopenharmony_ci release_io_hfcmulti(hc); 464462306a36Sopenharmony_ci 464562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 464662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: remove instance from list\n", 464762306a36Sopenharmony_ci __func__); 464862306a36Sopenharmony_ci list_del(&hc->list); 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 465162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: delete instance\n", __func__); 465262306a36Sopenharmony_ci if (hc == syncmaster) 465362306a36Sopenharmony_ci syncmaster = NULL; 465462306a36Sopenharmony_ci kfree(hc); 465562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 465662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: card successfully removed\n", 465762306a36Sopenharmony_ci __func__); 465862306a36Sopenharmony_ci} 465962306a36Sopenharmony_ci 466062306a36Sopenharmony_cistatic void 466162306a36Sopenharmony_ciinit_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) 466262306a36Sopenharmony_ci{ 466362306a36Sopenharmony_ci /* set optical line type */ 466462306a36Sopenharmony_ci if (port[Port_cnt] & 0x001) { 466562306a36Sopenharmony_ci if (!m->opticalsupport) { 466662306a36Sopenharmony_ci printk(KERN_INFO 466762306a36Sopenharmony_ci "This board has no optical " 466862306a36Sopenharmony_ci "support\n"); 466962306a36Sopenharmony_ci } else { 467062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 467162306a36Sopenharmony_ci printk(KERN_DEBUG 467262306a36Sopenharmony_ci "%s: PORT set optical " 467362306a36Sopenharmony_ci "interfacs: card(%d) " 467462306a36Sopenharmony_ci "port(%d)\n", 467562306a36Sopenharmony_ci __func__, 467662306a36Sopenharmony_ci HFC_cnt + 1, 1); 467762306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_OPTICAL, 467862306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 467962306a36Sopenharmony_ci } 468062306a36Sopenharmony_ci } 468162306a36Sopenharmony_ci /* set LOS report */ 468262306a36Sopenharmony_ci if (port[Port_cnt] & 0x004) { 468362306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 468462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT set " 468562306a36Sopenharmony_ci "LOS report: card(%d) port(%d)\n", 468662306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 468762306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_LOS, 468862306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 468962306a36Sopenharmony_ci } 469062306a36Sopenharmony_ci /* set AIS report */ 469162306a36Sopenharmony_ci if (port[Port_cnt] & 0x008) { 469262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 469362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT set " 469462306a36Sopenharmony_ci "AIS report: card(%d) port(%d)\n", 469562306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 469662306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_AIS, 469762306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 469862306a36Sopenharmony_ci } 469962306a36Sopenharmony_ci /* set SLIP report */ 470062306a36Sopenharmony_ci if (port[Port_cnt] & 0x010) { 470162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 470262306a36Sopenharmony_ci printk(KERN_DEBUG 470362306a36Sopenharmony_ci "%s: PORT set SLIP report: " 470462306a36Sopenharmony_ci "card(%d) port(%d)\n", 470562306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 470662306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_SLIP, 470762306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 470862306a36Sopenharmony_ci } 470962306a36Sopenharmony_ci /* set RDI report */ 471062306a36Sopenharmony_ci if (port[Port_cnt] & 0x020) { 471162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 471262306a36Sopenharmony_ci printk(KERN_DEBUG 471362306a36Sopenharmony_ci "%s: PORT set RDI report: " 471462306a36Sopenharmony_ci "card(%d) port(%d)\n", 471562306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 471662306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_RDI, 471762306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 471862306a36Sopenharmony_ci } 471962306a36Sopenharmony_ci /* set CRC-4 Mode */ 472062306a36Sopenharmony_ci if (!(port[Port_cnt] & 0x100)) { 472162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 472262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" 472362306a36Sopenharmony_ci " card(%d) port(%d)\n", 472462306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 472562306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_CRC4, 472662306a36Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 472762306a36Sopenharmony_ci } else { 472862306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 472962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT turn off CRC4" 473062306a36Sopenharmony_ci " report: card(%d) port(%d)\n", 473162306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 473262306a36Sopenharmony_ci } 473362306a36Sopenharmony_ci /* set forced clock */ 473462306a36Sopenharmony_ci if (port[Port_cnt] & 0x0200) { 473562306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 473662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT force getting clock from " 473762306a36Sopenharmony_ci "E1: card(%d) port(%d)\n", 473862306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 473962306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); 474062306a36Sopenharmony_ci } else 474162306a36Sopenharmony_ci if (port[Port_cnt] & 0x0400) { 474262306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 474362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT force putting clock to " 474462306a36Sopenharmony_ci "E1: card(%d) port(%d)\n", 474562306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 474662306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); 474762306a36Sopenharmony_ci } 474862306a36Sopenharmony_ci /* set JATT PLL */ 474962306a36Sopenharmony_ci if (port[Port_cnt] & 0x0800) { 475062306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 475162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PORT disable JATT PLL on " 475262306a36Sopenharmony_ci "E1: card(%d) port(%d)\n", 475362306a36Sopenharmony_ci __func__, HFC_cnt + 1, 1); 475462306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); 475562306a36Sopenharmony_ci } 475662306a36Sopenharmony_ci /* set elastic jitter buffer */ 475762306a36Sopenharmony_ci if (port[Port_cnt] & 0x3000) { 475862306a36Sopenharmony_ci hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3; 475962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 476062306a36Sopenharmony_ci printk(KERN_DEBUG 476162306a36Sopenharmony_ci "%s: PORT set elastic " 476262306a36Sopenharmony_ci "buffer to %d: card(%d) port(%d)\n", 476362306a36Sopenharmony_ci __func__, hc->chan[hc->dnum[0]].jitter, 476462306a36Sopenharmony_ci HFC_cnt + 1, 1); 476562306a36Sopenharmony_ci } else 476662306a36Sopenharmony_ci hc->chan[hc->dnum[0]].jitter = 2; /* default */ 476762306a36Sopenharmony_ci} 476862306a36Sopenharmony_ci 476962306a36Sopenharmony_cistatic int 477062306a36Sopenharmony_ciinit_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) 477162306a36Sopenharmony_ci{ 477262306a36Sopenharmony_ci struct dchannel *dch; 477362306a36Sopenharmony_ci struct bchannel *bch; 477462306a36Sopenharmony_ci int ch, ret = 0; 477562306a36Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 477662306a36Sopenharmony_ci int bcount = 0; 477762306a36Sopenharmony_ci 477862306a36Sopenharmony_ci dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); 477962306a36Sopenharmony_ci if (!dch) 478062306a36Sopenharmony_ci return -ENOMEM; 478162306a36Sopenharmony_ci dch->debug = debug; 478262306a36Sopenharmony_ci mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); 478362306a36Sopenharmony_ci dch->hw = hc; 478462306a36Sopenharmony_ci dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); 478562306a36Sopenharmony_ci dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 478662306a36Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 478762306a36Sopenharmony_ci dch->dev.D.send = handle_dmsg; 478862306a36Sopenharmony_ci dch->dev.D.ctrl = hfcm_dctrl; 478962306a36Sopenharmony_ci dch->slot = hc->dnum[pt]; 479062306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].dch = dch; 479162306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].port = pt; 479262306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].nt_timer = -1; 479362306a36Sopenharmony_ci for (ch = 1; ch <= 31; ch++) { 479462306a36Sopenharmony_ci if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ 479562306a36Sopenharmony_ci continue; 479662306a36Sopenharmony_ci bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); 479762306a36Sopenharmony_ci if (!bch) { 479862306a36Sopenharmony_ci printk(KERN_ERR "%s: no memory for bchannel\n", 479962306a36Sopenharmony_ci __func__); 480062306a36Sopenharmony_ci ret = -ENOMEM; 480162306a36Sopenharmony_ci goto free_chan; 480262306a36Sopenharmony_ci } 480362306a36Sopenharmony_ci hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); 480462306a36Sopenharmony_ci if (!hc->chan[ch].coeff) { 480562306a36Sopenharmony_ci printk(KERN_ERR "%s: no memory for coeffs\n", 480662306a36Sopenharmony_ci __func__); 480762306a36Sopenharmony_ci ret = -ENOMEM; 480862306a36Sopenharmony_ci kfree(bch); 480962306a36Sopenharmony_ci goto free_chan; 481062306a36Sopenharmony_ci } 481162306a36Sopenharmony_ci bch->nr = ch; 481262306a36Sopenharmony_ci bch->slot = ch; 481362306a36Sopenharmony_ci bch->debug = debug; 481462306a36Sopenharmony_ci mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); 481562306a36Sopenharmony_ci bch->hw = hc; 481662306a36Sopenharmony_ci bch->ch.send = handle_bmsg; 481762306a36Sopenharmony_ci bch->ch.ctrl = hfcm_bctrl; 481862306a36Sopenharmony_ci bch->ch.nr = ch; 481962306a36Sopenharmony_ci list_add(&bch->ch.list, &dch->dev.bchannels); 482062306a36Sopenharmony_ci hc->chan[ch].bch = bch; 482162306a36Sopenharmony_ci hc->chan[ch].port = pt; 482262306a36Sopenharmony_ci set_channelmap(bch->nr, dch->dev.channelmap); 482362306a36Sopenharmony_ci bcount++; 482462306a36Sopenharmony_ci } 482562306a36Sopenharmony_ci dch->dev.nrbchan = bcount; 482662306a36Sopenharmony_ci if (pt == 0) 482762306a36Sopenharmony_ci init_e1_port_hw(hc, m); 482862306a36Sopenharmony_ci if (hc->ports > 1) 482962306a36Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d", 483062306a36Sopenharmony_ci HFC_cnt + 1, pt+1); 483162306a36Sopenharmony_ci else 483262306a36Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); 483362306a36Sopenharmony_ci ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); 483462306a36Sopenharmony_ci if (ret) 483562306a36Sopenharmony_ci goto free_chan; 483662306a36Sopenharmony_ci hc->created[pt] = 1; 483762306a36Sopenharmony_ci return ret; 483862306a36Sopenharmony_cifree_chan: 483962306a36Sopenharmony_ci release_port(hc, dch); 484062306a36Sopenharmony_ci return ret; 484162306a36Sopenharmony_ci} 484262306a36Sopenharmony_ci 484362306a36Sopenharmony_cistatic int 484462306a36Sopenharmony_ciinit_multi_port(struct hfc_multi *hc, int pt) 484562306a36Sopenharmony_ci{ 484662306a36Sopenharmony_ci struct dchannel *dch; 484762306a36Sopenharmony_ci struct bchannel *bch; 484862306a36Sopenharmony_ci int ch, i, ret = 0; 484962306a36Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 485062306a36Sopenharmony_ci 485162306a36Sopenharmony_ci dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); 485262306a36Sopenharmony_ci if (!dch) 485362306a36Sopenharmony_ci return -ENOMEM; 485462306a36Sopenharmony_ci dch->debug = debug; 485562306a36Sopenharmony_ci mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); 485662306a36Sopenharmony_ci dch->hw = hc; 485762306a36Sopenharmony_ci dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); 485862306a36Sopenharmony_ci dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 485962306a36Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 486062306a36Sopenharmony_ci dch->dev.D.send = handle_dmsg; 486162306a36Sopenharmony_ci dch->dev.D.ctrl = hfcm_dctrl; 486262306a36Sopenharmony_ci dch->dev.nrbchan = 2; 486362306a36Sopenharmony_ci i = pt << 2; 486462306a36Sopenharmony_ci dch->slot = i + 2; 486562306a36Sopenharmony_ci hc->chan[i + 2].dch = dch; 486662306a36Sopenharmony_ci hc->chan[i + 2].port = pt; 486762306a36Sopenharmony_ci hc->chan[i + 2].nt_timer = -1; 486862306a36Sopenharmony_ci for (ch = 0; ch < dch->dev.nrbchan; ch++) { 486962306a36Sopenharmony_ci bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); 487062306a36Sopenharmony_ci if (!bch) { 487162306a36Sopenharmony_ci printk(KERN_ERR "%s: no memory for bchannel\n", 487262306a36Sopenharmony_ci __func__); 487362306a36Sopenharmony_ci ret = -ENOMEM; 487462306a36Sopenharmony_ci goto free_chan; 487562306a36Sopenharmony_ci } 487662306a36Sopenharmony_ci hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); 487762306a36Sopenharmony_ci if (!hc->chan[i + ch].coeff) { 487862306a36Sopenharmony_ci printk(KERN_ERR "%s: no memory for coeffs\n", 487962306a36Sopenharmony_ci __func__); 488062306a36Sopenharmony_ci ret = -ENOMEM; 488162306a36Sopenharmony_ci kfree(bch); 488262306a36Sopenharmony_ci goto free_chan; 488362306a36Sopenharmony_ci } 488462306a36Sopenharmony_ci bch->nr = ch + 1; 488562306a36Sopenharmony_ci bch->slot = i + ch; 488662306a36Sopenharmony_ci bch->debug = debug; 488762306a36Sopenharmony_ci mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); 488862306a36Sopenharmony_ci bch->hw = hc; 488962306a36Sopenharmony_ci bch->ch.send = handle_bmsg; 489062306a36Sopenharmony_ci bch->ch.ctrl = hfcm_bctrl; 489162306a36Sopenharmony_ci bch->ch.nr = ch + 1; 489262306a36Sopenharmony_ci list_add(&bch->ch.list, &dch->dev.bchannels); 489362306a36Sopenharmony_ci hc->chan[i + ch].bch = bch; 489462306a36Sopenharmony_ci hc->chan[i + ch].port = pt; 489562306a36Sopenharmony_ci set_channelmap(bch->nr, dch->dev.channelmap); 489662306a36Sopenharmony_ci } 489762306a36Sopenharmony_ci /* set master clock */ 489862306a36Sopenharmony_ci if (port[Port_cnt] & 0x001) { 489962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 490062306a36Sopenharmony_ci printk(KERN_DEBUG 490162306a36Sopenharmony_ci "%s: PROTOCOL set master clock: " 490262306a36Sopenharmony_ci "card(%d) port(%d)\n", 490362306a36Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 490462306a36Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 490562306a36Sopenharmony_ci printk(KERN_ERR "Error: Master clock " 490662306a36Sopenharmony_ci "for port(%d) of card(%d) is only" 490762306a36Sopenharmony_ci " possible with TE-mode\n", 490862306a36Sopenharmony_ci pt + 1, HFC_cnt + 1); 490962306a36Sopenharmony_ci ret = -EINVAL; 491062306a36Sopenharmony_ci goto free_chan; 491162306a36Sopenharmony_ci } 491262306a36Sopenharmony_ci if (hc->masterclk >= 0) { 491362306a36Sopenharmony_ci printk(KERN_ERR "Error: Master clock " 491462306a36Sopenharmony_ci "for port(%d) of card(%d) already " 491562306a36Sopenharmony_ci "defined for port(%d)\n", 491662306a36Sopenharmony_ci pt + 1, HFC_cnt + 1, hc->masterclk + 1); 491762306a36Sopenharmony_ci ret = -EINVAL; 491862306a36Sopenharmony_ci goto free_chan; 491962306a36Sopenharmony_ci } 492062306a36Sopenharmony_ci hc->masterclk = pt; 492162306a36Sopenharmony_ci } 492262306a36Sopenharmony_ci /* set transmitter line to non capacitive */ 492362306a36Sopenharmony_ci if (port[Port_cnt] & 0x002) { 492462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 492562306a36Sopenharmony_ci printk(KERN_DEBUG 492662306a36Sopenharmony_ci "%s: PROTOCOL set non capacitive " 492762306a36Sopenharmony_ci "transmitter: card(%d) port(%d)\n", 492862306a36Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 492962306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_NONCAP_TX, 493062306a36Sopenharmony_ci &hc->chan[i + 2].cfg); 493162306a36Sopenharmony_ci } 493262306a36Sopenharmony_ci /* disable E-channel */ 493362306a36Sopenharmony_ci if (port[Port_cnt] & 0x004) { 493462306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 493562306a36Sopenharmony_ci printk(KERN_DEBUG 493662306a36Sopenharmony_ci "%s: PROTOCOL disable E-channel: " 493762306a36Sopenharmony_ci "card(%d) port(%d)\n", 493862306a36Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 493962306a36Sopenharmony_ci test_and_set_bit(HFC_CFG_DIS_ECHANNEL, 494062306a36Sopenharmony_ci &hc->chan[i + 2].cfg); 494162306a36Sopenharmony_ci } 494262306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 494362306a36Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", 494462306a36Sopenharmony_ci HFC_cnt + 1, pt + 1); 494562306a36Sopenharmony_ci ret = mISDN_register_device(&dch->dev, NULL, name); 494662306a36Sopenharmony_ci } else { 494762306a36Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", 494862306a36Sopenharmony_ci hc->ctype, HFC_cnt + 1, pt + 1); 494962306a36Sopenharmony_ci ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); 495062306a36Sopenharmony_ci } 495162306a36Sopenharmony_ci if (ret) 495262306a36Sopenharmony_ci goto free_chan; 495362306a36Sopenharmony_ci hc->created[pt] = 1; 495462306a36Sopenharmony_ci return ret; 495562306a36Sopenharmony_cifree_chan: 495662306a36Sopenharmony_ci release_port(hc, dch); 495762306a36Sopenharmony_ci return ret; 495862306a36Sopenharmony_ci} 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_cistatic int 496162306a36Sopenharmony_cihfcmulti_init(struct hm_map *m, struct pci_dev *pdev, 496262306a36Sopenharmony_ci const struct pci_device_id *ent) 496362306a36Sopenharmony_ci{ 496462306a36Sopenharmony_ci int ret_err = 0; 496562306a36Sopenharmony_ci int pt; 496662306a36Sopenharmony_ci struct hfc_multi *hc; 496762306a36Sopenharmony_ci u_long flags; 496862306a36Sopenharmony_ci u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ 496962306a36Sopenharmony_ci int i, ch; 497062306a36Sopenharmony_ci u_int maskcheck; 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci if (HFC_cnt >= MAX_CARDS) { 497362306a36Sopenharmony_ci printk(KERN_ERR "too many cards (max=%d).\n", 497462306a36Sopenharmony_ci MAX_CARDS); 497562306a36Sopenharmony_ci return -EINVAL; 497662306a36Sopenharmony_ci } 497762306a36Sopenharmony_ci if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { 497862306a36Sopenharmony_ci printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " 497962306a36Sopenharmony_ci "type[%d] %d was supplied as module parameter\n", 498062306a36Sopenharmony_ci m->vendor_name, m->card_name, m->type, HFC_cnt, 498162306a36Sopenharmony_ci type[HFC_cnt] & 0xff); 498262306a36Sopenharmony_ci printk(KERN_WARNING "HFC-MULTI: Load module without parameters " 498362306a36Sopenharmony_ci "first, to see cards and their types."); 498462306a36Sopenharmony_ci return -EINVAL; 498562306a36Sopenharmony_ci } 498662306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 498762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", 498862306a36Sopenharmony_ci __func__, m->vendor_name, m->card_name, m->type, 498962306a36Sopenharmony_ci type[HFC_cnt]); 499062306a36Sopenharmony_ci 499162306a36Sopenharmony_ci /* allocate card+fifo structure */ 499262306a36Sopenharmony_ci hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL); 499362306a36Sopenharmony_ci if (!hc) { 499462306a36Sopenharmony_ci printk(KERN_ERR "No kmem for HFC-Multi card\n"); 499562306a36Sopenharmony_ci return -ENOMEM; 499662306a36Sopenharmony_ci } 499762306a36Sopenharmony_ci spin_lock_init(&hc->lock); 499862306a36Sopenharmony_ci hc->mtyp = m; 499962306a36Sopenharmony_ci hc->ctype = m->type; 500062306a36Sopenharmony_ci hc->ports = m->ports; 500162306a36Sopenharmony_ci hc->id = HFC_cnt; 500262306a36Sopenharmony_ci hc->pcm = pcm[HFC_cnt]; 500362306a36Sopenharmony_ci hc->io_mode = iomode[HFC_cnt]; 500462306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) { 500562306a36Sopenharmony_ci /* fragment card */ 500662306a36Sopenharmony_ci pt = 0; 500762306a36Sopenharmony_ci maskcheck = 0; 500862306a36Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 500962306a36Sopenharmony_ci if (!((1 << ch) & dmask[E1_cnt])) 501062306a36Sopenharmony_ci continue; 501162306a36Sopenharmony_ci hc->dnum[pt] = ch; 501262306a36Sopenharmony_ci hc->bmask[pt] = bmask[bmask_cnt++]; 501362306a36Sopenharmony_ci if ((maskcheck & hc->bmask[pt]) 501462306a36Sopenharmony_ci || (dmask[E1_cnt] & hc->bmask[pt])) { 501562306a36Sopenharmony_ci printk(KERN_INFO 501662306a36Sopenharmony_ci "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", 501762306a36Sopenharmony_ci E1_cnt + 1, pt); 501862306a36Sopenharmony_ci kfree(hc); 501962306a36Sopenharmony_ci return -EINVAL; 502062306a36Sopenharmony_ci } 502162306a36Sopenharmony_ci maskcheck |= hc->bmask[pt]; 502262306a36Sopenharmony_ci printk(KERN_INFO 502362306a36Sopenharmony_ci "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n", 502462306a36Sopenharmony_ci E1_cnt + 1, ch, hc->bmask[pt]); 502562306a36Sopenharmony_ci pt++; 502662306a36Sopenharmony_ci } 502762306a36Sopenharmony_ci hc->ports = pt; 502862306a36Sopenharmony_ci } 502962306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) { 503062306a36Sopenharmony_ci /* default card layout */ 503162306a36Sopenharmony_ci hc->dnum[0] = 16; 503262306a36Sopenharmony_ci hc->bmask[0] = 0xfffefffe; 503362306a36Sopenharmony_ci hc->ports = 1; 503462306a36Sopenharmony_ci } 503562306a36Sopenharmony_ci 503662306a36Sopenharmony_ci /* set chip specific features */ 503762306a36Sopenharmony_ci hc->masterclk = -1; 503862306a36Sopenharmony_ci if (type[HFC_cnt] & 0x100) { 503962306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); 504062306a36Sopenharmony_ci hc->silence = 0xff; /* ulaw silence */ 504162306a36Sopenharmony_ci } else 504262306a36Sopenharmony_ci hc->silence = 0x2a; /* alaw silence */ 504362306a36Sopenharmony_ci if ((poll >> 1) > sizeof(hc->silence_data)) { 504462306a36Sopenharmony_ci printk(KERN_ERR "HFCMULTI error: silence_data too small, " 504562306a36Sopenharmony_ci "please fix\n"); 504662306a36Sopenharmony_ci kfree(hc); 504762306a36Sopenharmony_ci return -EINVAL; 504862306a36Sopenharmony_ci } 504962306a36Sopenharmony_ci for (i = 0; i < (poll >> 1); i++) 505062306a36Sopenharmony_ci hc->silence_data[i] = hc->silence; 505162306a36Sopenharmony_ci 505262306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) { 505362306a36Sopenharmony_ci if (!(type[HFC_cnt] & 0x200)) 505462306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); 505562306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_CONF, &hc->chip); 505662306a36Sopenharmony_ci } 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci if (type[HFC_cnt] & 0x800) 505962306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 506062306a36Sopenharmony_ci if (type[HFC_cnt] & 0x1000) { 506162306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); 506262306a36Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 506362306a36Sopenharmony_ci } 506462306a36Sopenharmony_ci if (type[HFC_cnt] & 0x4000) 506562306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); 506662306a36Sopenharmony_ci if (type[HFC_cnt] & 0x8000) 506762306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); 506862306a36Sopenharmony_ci hc->slots = 32; 506962306a36Sopenharmony_ci if (type[HFC_cnt] & 0x10000) 507062306a36Sopenharmony_ci hc->slots = 64; 507162306a36Sopenharmony_ci if (type[HFC_cnt] & 0x20000) 507262306a36Sopenharmony_ci hc->slots = 128; 507362306a36Sopenharmony_ci if (type[HFC_cnt] & 0x80000) { 507462306a36Sopenharmony_ci test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); 507562306a36Sopenharmony_ci hc->wdcount = 0; 507662306a36Sopenharmony_ci hc->wdbyte = V_GPIO_OUT2; 507762306a36Sopenharmony_ci printk(KERN_NOTICE "Watchdog enabled\n"); 507862306a36Sopenharmony_ci } 507962306a36Sopenharmony_ci 508062306a36Sopenharmony_ci if (pdev && ent) 508162306a36Sopenharmony_ci /* setup pci, hc->slots may change due to PLXSD */ 508262306a36Sopenharmony_ci ret_err = setup_pci(hc, pdev, ent); 508362306a36Sopenharmony_ci else 508462306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 508562306a36Sopenharmony_ci ret_err = setup_embedded(hc, m); 508662306a36Sopenharmony_ci#else 508762306a36Sopenharmony_ci { 508862306a36Sopenharmony_ci printk(KERN_WARNING "Embedded IO Mode not selected\n"); 508962306a36Sopenharmony_ci ret_err = -EIO; 509062306a36Sopenharmony_ci } 509162306a36Sopenharmony_ci#endif 509262306a36Sopenharmony_ci if (ret_err) { 509362306a36Sopenharmony_ci if (hc == syncmaster) 509462306a36Sopenharmony_ci syncmaster = NULL; 509562306a36Sopenharmony_ci kfree(hc); 509662306a36Sopenharmony_ci return ret_err; 509762306a36Sopenharmony_ci } 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci hc->HFC_outb_nodebug = hc->HFC_outb; 510062306a36Sopenharmony_ci hc->HFC_inb_nodebug = hc->HFC_inb; 510162306a36Sopenharmony_ci hc->HFC_inw_nodebug = hc->HFC_inw; 510262306a36Sopenharmony_ci hc->HFC_wait_nodebug = hc->HFC_wait; 510362306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 510462306a36Sopenharmony_ci hc->HFC_outb = HFC_outb_debug; 510562306a36Sopenharmony_ci hc->HFC_inb = HFC_inb_debug; 510662306a36Sopenharmony_ci hc->HFC_inw = HFC_inw_debug; 510762306a36Sopenharmony_ci hc->HFC_wait = HFC_wait_debug; 510862306a36Sopenharmony_ci#endif 510962306a36Sopenharmony_ci /* create channels */ 511062306a36Sopenharmony_ci for (pt = 0; pt < hc->ports; pt++) { 511162306a36Sopenharmony_ci if (Port_cnt >= MAX_PORTS) { 511262306a36Sopenharmony_ci printk(KERN_ERR "too many ports (max=%d).\n", 511362306a36Sopenharmony_ci MAX_PORTS); 511462306a36Sopenharmony_ci ret_err = -EINVAL; 511562306a36Sopenharmony_ci goto free_card; 511662306a36Sopenharmony_ci } 511762306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 511862306a36Sopenharmony_ci ret_err = init_e1_port(hc, m, pt); 511962306a36Sopenharmony_ci else 512062306a36Sopenharmony_ci ret_err = init_multi_port(hc, pt); 512162306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 512262306a36Sopenharmony_ci printk(KERN_DEBUG 512362306a36Sopenharmony_ci "%s: Registering D-channel, card(%d) port(%d) " 512462306a36Sopenharmony_ci "result %d\n", 512562306a36Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1, ret_err); 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci if (ret_err) { 512862306a36Sopenharmony_ci while (pt) { /* release already registered ports */ 512962306a36Sopenharmony_ci pt--; 513062306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 513162306a36Sopenharmony_ci release_port(hc, 513262306a36Sopenharmony_ci hc->chan[hc->dnum[pt]].dch); 513362306a36Sopenharmony_ci else 513462306a36Sopenharmony_ci release_port(hc, 513562306a36Sopenharmony_ci hc->chan[(pt << 2) + 2].dch); 513662306a36Sopenharmony_ci } 513762306a36Sopenharmony_ci goto free_card; 513862306a36Sopenharmony_ci } 513962306a36Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) 514062306a36Sopenharmony_ci Port_cnt++; /* for each S0 port */ 514162306a36Sopenharmony_ci } 514262306a36Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 514362306a36Sopenharmony_ci Port_cnt++; /* for each E1 port */ 514462306a36Sopenharmony_ci E1_cnt++; 514562306a36Sopenharmony_ci } 514662306a36Sopenharmony_ci 514762306a36Sopenharmony_ci /* disp switches */ 514862306a36Sopenharmony_ci switch (m->dip_type) { 514962306a36Sopenharmony_ci case DIP_4S: 515062306a36Sopenharmony_ci /* 515162306a36Sopenharmony_ci * Get DIP setting for beroNet 1S/2S/4S cards 515262306a36Sopenharmony_ci * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + 515362306a36Sopenharmony_ci * GPI 19/23 (R_GPI_IN2)) 515462306a36Sopenharmony_ci */ 515562306a36Sopenharmony_ci dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | 515662306a36Sopenharmony_ci ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | 515762306a36Sopenharmony_ci (~HFC_inb(hc, R_GPI_IN2) & 0x08); 515862306a36Sopenharmony_ci 515962306a36Sopenharmony_ci /* Port mode (TE/NT) jumpers */ 516062306a36Sopenharmony_ci pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf); 516162306a36Sopenharmony_ci 516262306a36Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 516362306a36Sopenharmony_ci pmj = ~pmj & 0xf; 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", 516662306a36Sopenharmony_ci m->vendor_name, m->card_name, dips, pmj); 516762306a36Sopenharmony_ci break; 516862306a36Sopenharmony_ci case DIP_8S: 516962306a36Sopenharmony_ci /* 517062306a36Sopenharmony_ci * Get DIP Setting for beroNet 8S0+ cards 517162306a36Sopenharmony_ci * Enable PCI auxbridge function 517262306a36Sopenharmony_ci */ 517362306a36Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); 517462306a36Sopenharmony_ci /* prepare access to auxport */ 517562306a36Sopenharmony_ci outw(0x4000, hc->pci_iobase + 4); 517662306a36Sopenharmony_ci /* 517762306a36Sopenharmony_ci * some dummy reads are required to 517862306a36Sopenharmony_ci * read valid DIP switch data 517962306a36Sopenharmony_ci */ 518062306a36Sopenharmony_ci dips = inb(hc->pci_iobase); 518162306a36Sopenharmony_ci dips = inb(hc->pci_iobase); 518262306a36Sopenharmony_ci dips = inb(hc->pci_iobase); 518362306a36Sopenharmony_ci dips = ~inb(hc->pci_iobase) & 0x3F; 518462306a36Sopenharmony_ci outw(0x0, hc->pci_iobase + 4); 518562306a36Sopenharmony_ci /* disable PCI auxbridge function */ 518662306a36Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); 518762306a36Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x)\n", 518862306a36Sopenharmony_ci m->vendor_name, m->card_name, dips); 518962306a36Sopenharmony_ci break; 519062306a36Sopenharmony_ci case DIP_E1: 519162306a36Sopenharmony_ci /* 519262306a36Sopenharmony_ci * get DIP Setting for beroNet E1 cards 519362306a36Sopenharmony_ci * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) 519462306a36Sopenharmony_ci */ 519562306a36Sopenharmony_ci dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0) >> 4; 519662306a36Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x)\n", 519762306a36Sopenharmony_ci m->vendor_name, m->card_name, dips); 519862306a36Sopenharmony_ci break; 519962306a36Sopenharmony_ci } 520062306a36Sopenharmony_ci 520162306a36Sopenharmony_ci /* add to list */ 520262306a36Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 520362306a36Sopenharmony_ci list_add_tail(&hc->list, &HFClist); 520462306a36Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 520562306a36Sopenharmony_ci 520662306a36Sopenharmony_ci /* use as clock source */ 520762306a36Sopenharmony_ci if (clock == HFC_cnt + 1) 520862306a36Sopenharmony_ci hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); 520962306a36Sopenharmony_ci 521062306a36Sopenharmony_ci /* initialize hardware */ 521162306a36Sopenharmony_ci hc->irq = (m->irq) ? : hc->pci_dev->irq; 521262306a36Sopenharmony_ci ret_err = init_card(hc); 521362306a36Sopenharmony_ci if (ret_err) { 521462306a36Sopenharmony_ci printk(KERN_ERR "init card returns %d\n", ret_err); 521562306a36Sopenharmony_ci release_card(hc); 521662306a36Sopenharmony_ci return ret_err; 521762306a36Sopenharmony_ci } 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_ci /* start IRQ and return */ 522062306a36Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 522162306a36Sopenharmony_ci enable_hwirq(hc); 522262306a36Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 522362306a36Sopenharmony_ci return 0; 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_cifree_card: 522662306a36Sopenharmony_ci release_io_hfcmulti(hc); 522762306a36Sopenharmony_ci if (hc == syncmaster) 522862306a36Sopenharmony_ci syncmaster = NULL; 522962306a36Sopenharmony_ci kfree(hc); 523062306a36Sopenharmony_ci return ret_err; 523162306a36Sopenharmony_ci} 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_cistatic void hfc_remove_pci(struct pci_dev *pdev) 523462306a36Sopenharmony_ci{ 523562306a36Sopenharmony_ci struct hfc_multi *card = pci_get_drvdata(pdev); 523662306a36Sopenharmony_ci u_long flags; 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci if (debug) 523962306a36Sopenharmony_ci printk(KERN_INFO "removing hfc_multi card vendor:%x " 524062306a36Sopenharmony_ci "device:%x subvendor:%x subdevice:%x\n", 524162306a36Sopenharmony_ci pdev->vendor, pdev->device, 524262306a36Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device); 524362306a36Sopenharmony_ci 524462306a36Sopenharmony_ci if (card) { 524562306a36Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 524662306a36Sopenharmony_ci release_card(card); 524762306a36Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 524862306a36Sopenharmony_ci } else { 524962306a36Sopenharmony_ci if (debug) 525062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: drvdata already removed\n", 525162306a36Sopenharmony_ci __func__); 525262306a36Sopenharmony_ci } 525362306a36Sopenharmony_ci} 525462306a36Sopenharmony_ci 525562306a36Sopenharmony_ci#define VENDOR_CCD "Cologne Chip AG" 525662306a36Sopenharmony_ci#define VENDOR_BN "beroNet GmbH" 525762306a36Sopenharmony_ci#define VENDOR_DIG "Digium Inc." 525862306a36Sopenharmony_ci#define VENDOR_JH "Junghanns.NET GmbH" 525962306a36Sopenharmony_ci#define VENDOR_PRIM "PrimuX" 526062306a36Sopenharmony_ci 526162306a36Sopenharmony_cistatic const struct hm_map hfcm_map[] = { 526262306a36Sopenharmony_ci /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, 526362306a36Sopenharmony_ci /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 526462306a36Sopenharmony_ci /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 526562306a36Sopenharmony_ci /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 526662306a36Sopenharmony_ci /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, 526762306a36Sopenharmony_ci /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, 526862306a36Sopenharmony_ci /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 526962306a36Sopenharmony_ci /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, 527062306a36Sopenharmony_ci /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, 527162306a36Sopenharmony_ci /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, 527262306a36Sopenharmony_ci /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, 527362306a36Sopenharmony_ci /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, 527462306a36Sopenharmony_ci 527562306a36Sopenharmony_ci /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, 527662306a36Sopenharmony_ci /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, 527762306a36Sopenharmony_ci HFC_IO_MODE_REGIO, 0}, 527862306a36Sopenharmony_ci /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, 527962306a36Sopenharmony_ci /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, 528062306a36Sopenharmony_ci 528162306a36Sopenharmony_ci /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, 528262306a36Sopenharmony_ci /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, 528362306a36Sopenharmony_ci /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, 528462306a36Sopenharmony_ci 528562306a36Sopenharmony_ci /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 528662306a36Sopenharmony_ci /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, 528762306a36Sopenharmony_ci /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 528862306a36Sopenharmony_ci /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 528962306a36Sopenharmony_ci 529062306a36Sopenharmony_ci /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, 529162306a36Sopenharmony_ci /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, 529262306a36Sopenharmony_ci /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, 529562306a36Sopenharmony_ci HFC_IO_MODE_PLXSD, 0}, 529662306a36Sopenharmony_ci /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, 529762306a36Sopenharmony_ci HFC_IO_MODE_PLXSD, 0}, 529862306a36Sopenharmony_ci /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, 529962306a36Sopenharmony_ci /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, 530062306a36Sopenharmony_ci /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, 530162306a36Sopenharmony_ci /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, 530262306a36Sopenharmony_ci HFC_IO_MODE_EMBSD, XHFC_IRQ}, 530362306a36Sopenharmony_ci /*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, 530462306a36Sopenharmony_ci /*33*/ {VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 530562306a36Sopenharmony_ci /*34*/ {VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 530662306a36Sopenharmony_ci}; 530762306a36Sopenharmony_ci 530862306a36Sopenharmony_ci#undef H 530962306a36Sopenharmony_ci#define H(x) ((unsigned long)&hfcm_map[x]) 531062306a36Sopenharmony_cistatic const struct pci_device_id hfmultipci_ids[] = { 531162306a36Sopenharmony_ci 531262306a36Sopenharmony_ci /* Cards with HFC-4S Chip */ 531362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 531462306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ 531562306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 531662306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ 531762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 531862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ 531962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 532062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ 532162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 532262306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ 532362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 532462306a36Sopenharmony_ci PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ 532562306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 532662306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ 532762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 532862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ 532962306a36Sopenharmony_ci { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 533062306a36Sopenharmony_ci PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, 533162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 533262306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ 533362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 533462306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, 533562306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 533662306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ 533762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 533862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ 533962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 534062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ 534162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 534262306a36Sopenharmony_ci 0xb761, 0, 0, H(33)}, /* BN2S PCIe */ 534362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 534462306a36Sopenharmony_ci 0xb762, 0, 0, H(34)}, /* BN4S PCIe */ 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci /* Cards with HFC-8S Chip */ 534762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 534862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ 534962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 535062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ 535162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 535262306a36Sopenharmony_ci PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ 535362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 535462306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ 535562306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 535662306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ 535762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 535862306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */ 535962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 536062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ 536162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 536262306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ 536362306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 536462306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */ 536562306a36Sopenharmony_ci 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci /* Cards with HFC-E1 Chip */ 536862306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 536962306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ 537062306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 537162306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ 537262306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 537362306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ 537462306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 537562306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ 537662306a36Sopenharmony_ci 537762306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 537862306a36Sopenharmony_ci PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ 537962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 538062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ 538162306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 538262306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ 538362306a36Sopenharmony_ci 538462306a36Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, 538562306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ 538662306a36Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, 538762306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 539062306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ 539162306a36Sopenharmony_ci 539262306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 }, 539362306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 }, 539462306a36Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 }, 539562306a36Sopenharmony_ci {0, } 539662306a36Sopenharmony_ci}; 539762306a36Sopenharmony_ci#undef H 539862306a36Sopenharmony_ci 539962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfmultipci_ids); 540062306a36Sopenharmony_ci 540162306a36Sopenharmony_cistatic int 540262306a36Sopenharmony_cihfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 540362306a36Sopenharmony_ci{ 540462306a36Sopenharmony_ci struct hm_map *m = (struct hm_map *)ent->driver_data; 540562306a36Sopenharmony_ci int ret; 540662306a36Sopenharmony_ci 540762306a36Sopenharmony_ci if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( 540862306a36Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFC4S || 540962306a36Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFC8S || 541062306a36Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { 541162306a36Sopenharmony_ci printk(KERN_ERR 541262306a36Sopenharmony_ci "Unknown HFC multiport controller (vendor:%04x device:%04x " 541362306a36Sopenharmony_ci "subvendor:%04x subdevice:%04x)\n", pdev->vendor, 541462306a36Sopenharmony_ci pdev->device, pdev->subsystem_vendor, 541562306a36Sopenharmony_ci pdev->subsystem_device); 541662306a36Sopenharmony_ci printk(KERN_ERR 541762306a36Sopenharmony_ci "Please contact the driver maintainer for support.\n"); 541862306a36Sopenharmony_ci return -ENODEV; 541962306a36Sopenharmony_ci } 542062306a36Sopenharmony_ci ret = hfcmulti_init(m, pdev, ent); 542162306a36Sopenharmony_ci if (ret) 542262306a36Sopenharmony_ci return ret; 542362306a36Sopenharmony_ci HFC_cnt++; 542462306a36Sopenharmony_ci printk(KERN_INFO "%d devices registered\n", HFC_cnt); 542562306a36Sopenharmony_ci return 0; 542662306a36Sopenharmony_ci} 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_cistatic struct pci_driver hfcmultipci_driver = { 542962306a36Sopenharmony_ci .name = "hfc_multi", 543062306a36Sopenharmony_ci .probe = hfcmulti_probe, 543162306a36Sopenharmony_ci .remove = hfc_remove_pci, 543262306a36Sopenharmony_ci .id_table = hfmultipci_ids, 543362306a36Sopenharmony_ci}; 543462306a36Sopenharmony_ci 543562306a36Sopenharmony_cistatic void __exit 543662306a36Sopenharmony_ciHFCmulti_cleanup(void) 543762306a36Sopenharmony_ci{ 543862306a36Sopenharmony_ci struct hfc_multi *card, *next; 543962306a36Sopenharmony_ci 544062306a36Sopenharmony_ci /* get rid of all devices of this driver */ 544162306a36Sopenharmony_ci list_for_each_entry_safe(card, next, &HFClist, list) 544262306a36Sopenharmony_ci release_card(card); 544362306a36Sopenharmony_ci pci_unregister_driver(&hfcmultipci_driver); 544462306a36Sopenharmony_ci} 544562306a36Sopenharmony_ci 544662306a36Sopenharmony_cistatic int __init 544762306a36Sopenharmony_ciHFCmulti_init(void) 544862306a36Sopenharmony_ci{ 544962306a36Sopenharmony_ci int err; 545062306a36Sopenharmony_ci int i, xhfc = 0; 545162306a36Sopenharmony_ci struct hm_map m; 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_ci printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); 545462306a36Sopenharmony_ci 545562306a36Sopenharmony_ci#ifdef IRQ_DEBUG 545662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); 545762306a36Sopenharmony_ci#endif 545862306a36Sopenharmony_ci 545962306a36Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 546062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: init entered\n", __func__); 546162306a36Sopenharmony_ci 546262306a36Sopenharmony_ci switch (poll) { 546362306a36Sopenharmony_ci case 0: 546462306a36Sopenharmony_ci poll_timer = 6; 546562306a36Sopenharmony_ci poll = 128; 546662306a36Sopenharmony_ci break; 546762306a36Sopenharmony_ci case 8: 546862306a36Sopenharmony_ci poll_timer = 2; 546962306a36Sopenharmony_ci break; 547062306a36Sopenharmony_ci case 16: 547162306a36Sopenharmony_ci poll_timer = 3; 547262306a36Sopenharmony_ci break; 547362306a36Sopenharmony_ci case 32: 547462306a36Sopenharmony_ci poll_timer = 4; 547562306a36Sopenharmony_ci break; 547662306a36Sopenharmony_ci case 64: 547762306a36Sopenharmony_ci poll_timer = 5; 547862306a36Sopenharmony_ci break; 547962306a36Sopenharmony_ci case 128: 548062306a36Sopenharmony_ci poll_timer = 6; 548162306a36Sopenharmony_ci break; 548262306a36Sopenharmony_ci case 256: 548362306a36Sopenharmony_ci poll_timer = 7; 548462306a36Sopenharmony_ci break; 548562306a36Sopenharmony_ci default: 548662306a36Sopenharmony_ci printk(KERN_ERR 548762306a36Sopenharmony_ci "%s: Wrong poll value (%d).\n", __func__, poll); 548862306a36Sopenharmony_ci err = -EINVAL; 548962306a36Sopenharmony_ci return err; 549062306a36Sopenharmony_ci 549162306a36Sopenharmony_ci } 549262306a36Sopenharmony_ci 549362306a36Sopenharmony_ci if (!clock) 549462306a36Sopenharmony_ci clock = 1; 549562306a36Sopenharmony_ci 549662306a36Sopenharmony_ci /* Register the embedded devices. 549762306a36Sopenharmony_ci * This should be done before the PCI cards registration */ 549862306a36Sopenharmony_ci switch (hwid) { 549962306a36Sopenharmony_ci case HWID_MINIP4: 550062306a36Sopenharmony_ci xhfc = 1; 550162306a36Sopenharmony_ci m = hfcm_map[31]; 550262306a36Sopenharmony_ci break; 550362306a36Sopenharmony_ci case HWID_MINIP8: 550462306a36Sopenharmony_ci xhfc = 2; 550562306a36Sopenharmony_ci m = hfcm_map[31]; 550662306a36Sopenharmony_ci break; 550762306a36Sopenharmony_ci case HWID_MINIP16: 550862306a36Sopenharmony_ci xhfc = 4; 550962306a36Sopenharmony_ci m = hfcm_map[31]; 551062306a36Sopenharmony_ci break; 551162306a36Sopenharmony_ci default: 551262306a36Sopenharmony_ci xhfc = 0; 551362306a36Sopenharmony_ci } 551462306a36Sopenharmony_ci 551562306a36Sopenharmony_ci for (i = 0; i < xhfc; ++i) { 551662306a36Sopenharmony_ci err = hfcmulti_init(&m, NULL, NULL); 551762306a36Sopenharmony_ci if (err) { 551862306a36Sopenharmony_ci printk(KERN_ERR "error registering embedded driver: " 551962306a36Sopenharmony_ci "%x\n", err); 552062306a36Sopenharmony_ci return err; 552162306a36Sopenharmony_ci } 552262306a36Sopenharmony_ci HFC_cnt++; 552362306a36Sopenharmony_ci printk(KERN_INFO "%d devices registered\n", HFC_cnt); 552462306a36Sopenharmony_ci } 552562306a36Sopenharmony_ci 552662306a36Sopenharmony_ci /* Register the PCI cards */ 552762306a36Sopenharmony_ci err = pci_register_driver(&hfcmultipci_driver); 552862306a36Sopenharmony_ci if (err < 0) { 552962306a36Sopenharmony_ci printk(KERN_ERR "error registering pci driver: %x\n", err); 553062306a36Sopenharmony_ci return err; 553162306a36Sopenharmony_ci } 553262306a36Sopenharmony_ci 553362306a36Sopenharmony_ci return 0; 553462306a36Sopenharmony_ci} 553562306a36Sopenharmony_ci 553662306a36Sopenharmony_ci 553762306a36Sopenharmony_cimodule_init(HFCmulti_init); 553862306a36Sopenharmony_cimodule_exit(HFCmulti_cleanup); 5539