18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author Andreas Eversberg (jolly@eversberg.eu) 68c2ecf20Sopenharmony_ci * ported to mqueue mechanism: 78c2ecf20Sopenharmony_ci * Peter Sprenger (sprengermoving-bytes.de) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * inspired by existing hfc-pci driver: 108c2ecf20Sopenharmony_ci * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) 118c2ecf20Sopenharmony_ci * Copyright 2008 by Karsten Keil (kkeil@suse.de) 128c2ecf20Sopenharmony_ci * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu) 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Thanks to Cologne Chip AG for this great controller! 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * module parameters: 198c2ecf20Sopenharmony_ci * type: 208c2ecf20Sopenharmony_ci * By default (0), the card is automatically detected. 218c2ecf20Sopenharmony_ci * Or use the following combinations: 228c2ecf20Sopenharmony_ci * Bit 0-7 = 0x00001 = HFC-E1 (1 port) 238c2ecf20Sopenharmony_ci * or Bit 0-7 = 0x00004 = HFC-4S (4 ports) 248c2ecf20Sopenharmony_ci * or Bit 0-7 = 0x00008 = HFC-8S (8 ports) 258c2ecf20Sopenharmony_ci * Bit 8 = 0x00100 = uLaw (instead of aLaw) 268c2ecf20Sopenharmony_ci * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware 278c2ecf20Sopenharmony_ci * Bit 10 = spare 288c2ecf20Sopenharmony_ci * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) 298c2ecf20Sopenharmony_ci * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto) 308c2ecf20Sopenharmony_ci * Bit 13 = spare 318c2ecf20Sopenharmony_ci * Bit 14 = 0x04000 = Use external ram (128K) 328c2ecf20Sopenharmony_ci * Bit 15 = 0x08000 = Use external ram (512K) 338c2ecf20Sopenharmony_ci * Bit 16 = 0x10000 = Use 64 timeslots instead of 32 348c2ecf20Sopenharmony_ci * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else 358c2ecf20Sopenharmony_ci * Bit 18 = spare 368c2ecf20Sopenharmony_ci * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) 378c2ecf20Sopenharmony_ci * (all other bits are reserved and shall be 0) 388c2ecf20Sopenharmony_ci * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM 398c2ecf20Sopenharmony_ci * bus (PCM master) 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * port: (optional or required for all ports on all installed cards) 428c2ecf20Sopenharmony_ci * HFC-4S/HFC-8S only bits: 438c2ecf20Sopenharmony_ci * Bit 0 = 0x001 = Use master clock for this S/T interface 448c2ecf20Sopenharmony_ci * (ony once per chip). 458c2ecf20Sopenharmony_ci * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) 468c2ecf20Sopenharmony_ci * Don't use this unless you know what you are doing! 478c2ecf20Sopenharmony_ci * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) 488c2ecf20Sopenharmony_ci * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock 498c2ecf20Sopenharmony_ci * received from port 1 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * HFC-E1 only bits: 528c2ecf20Sopenharmony_ci * Bit 0 = 0x0001 = interface: 0=copper, 1=optical 538c2ecf20Sopenharmony_ci * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode) 548c2ecf20Sopenharmony_ci * Bit 2 = 0x0004 = Report LOS 558c2ecf20Sopenharmony_ci * Bit 3 = 0x0008 = Report AIS 568c2ecf20Sopenharmony_ci * Bit 4 = 0x0010 = Report SLIP 578c2ecf20Sopenharmony_ci * Bit 5 = 0x0020 = Report RDI 588c2ecf20Sopenharmony_ci * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame 598c2ecf20Sopenharmony_ci * mode instead. 608c2ecf20Sopenharmony_ci * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode. 618c2ecf20Sopenharmony_ci * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode. 628c2ecf20Sopenharmony_ci * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL. 638c2ecf20Sopenharmony_ci * (E1 only) 648c2ecf20Sopenharmony_ci * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 658c2ecf20Sopenharmony_ci * for default. 668c2ecf20Sopenharmony_ci * (all other bits are reserved and shall be 0) 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * debug: 698c2ecf20Sopenharmony_ci * NOTE: only one debug value must be given for all cards 708c2ecf20Sopenharmony_ci * enable debugging (see hfc_multi.h for debug options) 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * poll: 738c2ecf20Sopenharmony_ci * NOTE: only one poll value must be given for all cards 748c2ecf20Sopenharmony_ci * Give the number of samples for each fifo process. 758c2ecf20Sopenharmony_ci * By default 128 is used. Decrease to reduce delay, increase to 768c2ecf20Sopenharmony_ci * reduce cpu load. If unsure, don't mess with it! 778c2ecf20Sopenharmony_ci * Valid is 8, 16, 32, 64, 128, 256. 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * pcm: 808c2ecf20Sopenharmony_ci * NOTE: only one pcm value must be given for every card. 818c2ecf20Sopenharmony_ci * The PCM bus id tells the mISDNdsp module about the connected PCM bus. 828c2ecf20Sopenharmony_ci * By default (0), the PCM bus id is 100 for the card that is PCM master. 838c2ecf20Sopenharmony_ci * If multiple cards are PCM master (because they are not interconnected), 848c2ecf20Sopenharmony_ci * each card with PCM master will have increasing PCM id. 858c2ecf20Sopenharmony_ci * All PCM busses with the same ID are expected to be connected and have 868c2ecf20Sopenharmony_ci * common time slots slots. 878c2ecf20Sopenharmony_ci * Only one chip of the PCM bus must be master, the others slave. 888c2ecf20Sopenharmony_ci * -1 means no support of PCM bus not even. 898c2ecf20Sopenharmony_ci * Omit this value, if all cards are interconnected or none is connected. 908c2ecf20Sopenharmony_ci * If unsure, don't give this parameter. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * dmask and bmask: 938c2ecf20Sopenharmony_ci * NOTE: One dmask value must be given for every HFC-E1 card. 948c2ecf20Sopenharmony_ci * If omitted, the E1 card has D-channel on time slot 16, which is default. 958c2ecf20Sopenharmony_ci * dmask is a 32 bit mask. The bit must be set for an alternate time slot. 968c2ecf20Sopenharmony_ci * If multiple bits are set, multiple virtual card fragments are created. 978c2ecf20Sopenharmony_ci * For each bit set, a bmask value must be given. Each bit on the bmask 988c2ecf20Sopenharmony_ci * value stands for a B-channel. The bmask may not overlap with dmask or 998c2ecf20Sopenharmony_ci * with other bmask values for that card. 1008c2ecf20Sopenharmony_ci * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000 1018c2ecf20Sopenharmony_ci * This will create one fragment with D-channel on slot 1 with 1028c2ecf20Sopenharmony_ci * B-channels on slots 2..15, and a second fragment with D-channel 1038c2ecf20Sopenharmony_ci * on slot 17 with B-channels on slot 18..31. Slot 16 is unused. 1048c2ecf20Sopenharmony_ci * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will 1058c2ecf20Sopenharmony_ci * not function. 1068c2ecf20Sopenharmony_ci * Example: dmask=0x00000001 bmask=0xfffffffe 1078c2ecf20Sopenharmony_ci * This will create a port with all 31 usable timeslots as 1088c2ecf20Sopenharmony_ci * B-channels. 1098c2ecf20Sopenharmony_ci * If no bits are set on bmask, no B-channel is created for that fragment. 1108c2ecf20Sopenharmony_ci * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask) 1118c2ecf20Sopenharmony_ci * This will create 31 ports with one D-channel only. 1128c2ecf20Sopenharmony_ci * If you don't know how to use it, you don't need it! 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * iomode: 1158c2ecf20Sopenharmony_ci * NOTE: only one mode value must be given for every card. 1168c2ecf20Sopenharmony_ci * -> See hfc_multi.h for HFC_IO_MODE_* values 1178c2ecf20Sopenharmony_ci * By default, the IO mode is pci memory IO (MEMIO). 1188c2ecf20Sopenharmony_ci * Some cards require specific IO mode, so it cannot be changed. 1198c2ecf20Sopenharmony_ci * It may be useful to set IO mode to register io (REGIO) to solve 1208c2ecf20Sopenharmony_ci * PCI bridge problems. 1218c2ecf20Sopenharmony_ci * If unsure, don't give this parameter. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * clockdelay_nt: 1248c2ecf20Sopenharmony_ci * NOTE: only one clockdelay_nt value must be given once for all cards. 1258c2ecf20Sopenharmony_ci * Give the value of the clock control register (A_ST_CLK_DLY) 1268c2ecf20Sopenharmony_ci * of the S/T interfaces in NT mode. 1278c2ecf20Sopenharmony_ci * This register is needed for the TBR3 certification, so don't change it. 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * clockdelay_te: 1308c2ecf20Sopenharmony_ci * NOTE: only one clockdelay_te value must be given once 1318c2ecf20Sopenharmony_ci * Give the value of the clock control register (A_ST_CLK_DLY) 1328c2ecf20Sopenharmony_ci * of the S/T interfaces in TE mode. 1338c2ecf20Sopenharmony_ci * This register is needed for the TBR3 certification, so don't change it. 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * clock: 1368c2ecf20Sopenharmony_ci * NOTE: only one clock value must be given once 1378c2ecf20Sopenharmony_ci * Selects interface with clock source for mISDN and applications. 1388c2ecf20Sopenharmony_ci * Set to card number starting with 1. Set to -1 to disable. 1398c2ecf20Sopenharmony_ci * By default, the first card is used as clock source. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * hwid: 1428c2ecf20Sopenharmony_ci * NOTE: only one hwid value must be given once 1438c2ecf20Sopenharmony_ci * Enable special embedded devices with XHFC controllers. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * debug register access (never use this, it will flood your system log) 1488c2ecf20Sopenharmony_ci * #define HFC_REGISTER_DEBUG 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define HFC_MULTI_VERSION "2.03" 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1548c2ecf20Sopenharmony_ci#include <linux/module.h> 1558c2ecf20Sopenharmony_ci#include <linux/slab.h> 1568c2ecf20Sopenharmony_ci#include <linux/pci.h> 1578c2ecf20Sopenharmony_ci#include <linux/delay.h> 1588c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 1598c2ecf20Sopenharmony_ci#include <linux/mISDNdsp.h> 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci #define IRQCOUNT_DEBUG 1638c2ecf20Sopenharmony_ci #define IRQ_DEBUG 1648c2ecf20Sopenharmony_ci*/ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#include "hfc_multi.h" 1678c2ecf20Sopenharmony_ci#ifdef ECHOPREP 1688c2ecf20Sopenharmony_ci#include "gaintab.h" 1698c2ecf20Sopenharmony_ci#endif 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define MAX_CARDS 8 1728c2ecf20Sopenharmony_ci#define MAX_PORTS (8 * MAX_CARDS) 1738c2ecf20Sopenharmony_ci#define MAX_FRAGS (32 * MAX_CARDS) 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic LIST_HEAD(HFClist); 1768c2ecf20Sopenharmony_cistatic spinlock_t HFClock; /* global hfc list lock */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void ph_state_change(struct dchannel *); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic struct hfc_multi *syncmaster; 1818c2ecf20Sopenharmony_cistatic int plxsd_master; /* if we have a master card (yet) */ 1828c2ecf20Sopenharmony_cistatic spinlock_t plx_lock; /* may not acquire other lock inside */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define TYP_E1 1 1858c2ecf20Sopenharmony_ci#define TYP_4S 4 1868c2ecf20Sopenharmony_ci#define TYP_8S 8 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int poll_timer = 6; /* default = 128 samples = 16ms */ 1898c2ecf20Sopenharmony_ci/* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ 1908c2ecf20Sopenharmony_cistatic int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; 1918c2ecf20Sopenharmony_ci#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ 1928c2ecf20Sopenharmony_ci#define CLKDEL_NT 0x6c /* CLKDEL in NT mode 1938c2ecf20Sopenharmony_ci (0x60 MUST be included!) */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ 1968c2ecf20Sopenharmony_ci#define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ 1978c2ecf20Sopenharmony_ci#define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * module stuff 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic uint type[MAX_CARDS]; 2048c2ecf20Sopenharmony_cistatic int pcm[MAX_CARDS]; 2058c2ecf20Sopenharmony_cistatic uint dmask[MAX_CARDS]; 2068c2ecf20Sopenharmony_cistatic uint bmask[MAX_FRAGS]; 2078c2ecf20Sopenharmony_cistatic uint iomode[MAX_CARDS]; 2088c2ecf20Sopenharmony_cistatic uint port[MAX_PORTS]; 2098c2ecf20Sopenharmony_cistatic uint debug; 2108c2ecf20Sopenharmony_cistatic uint poll; 2118c2ecf20Sopenharmony_cistatic int clock; 2128c2ecf20Sopenharmony_cistatic uint timer; 2138c2ecf20Sopenharmony_cistatic uint clockdelay_te = CLKDEL_TE; 2148c2ecf20Sopenharmony_cistatic uint clockdelay_nt = CLKDEL_NT; 2158c2ecf20Sopenharmony_ci#define HWID_NONE 0 2168c2ecf20Sopenharmony_ci#define HWID_MINIP4 1 2178c2ecf20Sopenharmony_ci#define HWID_MINIP8 2 2188c2ecf20Sopenharmony_ci#define HWID_MINIP16 3 2198c2ecf20Sopenharmony_cistatic uint hwid = HWID_NONE; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andreas Eversberg"); 2248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2258c2ecf20Sopenharmony_ciMODULE_VERSION(HFC_MULTI_VERSION); 2268c2ecf20Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 2278c2ecf20Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR); 2288c2ecf20Sopenharmony_cimodule_param(clock, int, S_IRUGO | S_IWUSR); 2298c2ecf20Sopenharmony_cimodule_param(timer, uint, S_IRUGO | S_IWUSR); 2308c2ecf20Sopenharmony_cimodule_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); 2318c2ecf20Sopenharmony_cimodule_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); 2328c2ecf20Sopenharmony_cimodule_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); 2338c2ecf20Sopenharmony_cimodule_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); 2348c2ecf20Sopenharmony_cimodule_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR); 2358c2ecf20Sopenharmony_cimodule_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR); 2368c2ecf20Sopenharmony_cimodule_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); 2378c2ecf20Sopenharmony_cimodule_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); 2388c2ecf20Sopenharmony_cimodule_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 2418c2ecf20Sopenharmony_ci#define HFC_outb(hc, reg, val) \ 2428c2ecf20Sopenharmony_ci (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) 2438c2ecf20Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val) \ 2448c2ecf20Sopenharmony_ci (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) 2458c2ecf20Sopenharmony_ci#define HFC_inb(hc, reg) \ 2468c2ecf20Sopenharmony_ci (hc->HFC_inb(hc, reg, __func__, __LINE__)) 2478c2ecf20Sopenharmony_ci#define HFC_inb_nodebug(hc, reg) \ 2488c2ecf20Sopenharmony_ci (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) 2498c2ecf20Sopenharmony_ci#define HFC_inw(hc, reg) \ 2508c2ecf20Sopenharmony_ci (hc->HFC_inw(hc, reg, __func__, __LINE__)) 2518c2ecf20Sopenharmony_ci#define HFC_inw_nodebug(hc, reg) \ 2528c2ecf20Sopenharmony_ci (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) 2538c2ecf20Sopenharmony_ci#define HFC_wait(hc) \ 2548c2ecf20Sopenharmony_ci (hc->HFC_wait(hc, __func__, __LINE__)) 2558c2ecf20Sopenharmony_ci#define HFC_wait_nodebug(hc) \ 2568c2ecf20Sopenharmony_ci (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) 2578c2ecf20Sopenharmony_ci#else 2588c2ecf20Sopenharmony_ci#define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val)) 2598c2ecf20Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val)) 2608c2ecf20Sopenharmony_ci#define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg)) 2618c2ecf20Sopenharmony_ci#define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg)) 2628c2ecf20Sopenharmony_ci#define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg)) 2638c2ecf20Sopenharmony_ci#define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg)) 2648c2ecf20Sopenharmony_ci#define HFC_wait(hc) (hc->HFC_wait(hc)) 2658c2ecf20Sopenharmony_ci#define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) 2668c2ecf20Sopenharmony_ci#endif 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 2698c2ecf20Sopenharmony_ci#include "hfc_multi_8xx.h" 2708c2ecf20Sopenharmony_ci#endif 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* HFC_IO_MODE_PCIMEM */ 2738c2ecf20Sopenharmony_cistatic void 2748c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 2758c2ecf20Sopenharmony_ciHFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, 2768c2ecf20Sopenharmony_ci const char *function, int line) 2778c2ecf20Sopenharmony_ci#else 2788c2ecf20Sopenharmony_ci HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) 2798c2ecf20Sopenharmony_ci#endif 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci writeb(val, hc->pci_membase + reg); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_cistatic u_char 2848c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 2858c2ecf20Sopenharmony_ciHFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) 2868c2ecf20Sopenharmony_ci#else 2878c2ecf20Sopenharmony_ci HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) 2888c2ecf20Sopenharmony_ci#endif 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci return readb(hc->pci_membase + reg); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_cistatic u_short 2938c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 2948c2ecf20Sopenharmony_ciHFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) 2958c2ecf20Sopenharmony_ci#else 2968c2ecf20Sopenharmony_ci HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) 2978c2ecf20Sopenharmony_ci#endif 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci return readw(hc->pci_membase + reg); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_cistatic void 3028c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3038c2ecf20Sopenharmony_ciHFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) 3048c2ecf20Sopenharmony_ci#else 3058c2ecf20Sopenharmony_ci HFC_wait_pcimem(struct hfc_multi *hc) 3068c2ecf20Sopenharmony_ci#endif 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci while (readb(hc->pci_membase + R_STATUS) & V_BUSY) 3098c2ecf20Sopenharmony_ci cpu_relax(); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* HFC_IO_MODE_REGIO */ 3138c2ecf20Sopenharmony_cistatic void 3148c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3158c2ecf20Sopenharmony_ciHFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, 3168c2ecf20Sopenharmony_ci const char *function, int line) 3178c2ecf20Sopenharmony_ci#else 3188c2ecf20Sopenharmony_ci HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) 3198c2ecf20Sopenharmony_ci#endif 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 3228c2ecf20Sopenharmony_ci outb(val, hc->pci_iobase); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_cistatic u_char 3258c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3268c2ecf20Sopenharmony_ciHFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) 3278c2ecf20Sopenharmony_ci#else 3288c2ecf20Sopenharmony_ci HFC_inb_regio(struct hfc_multi *hc, u_char reg) 3298c2ecf20Sopenharmony_ci#endif 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 3328c2ecf20Sopenharmony_ci return inb(hc->pci_iobase); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_cistatic u_short 3358c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3368c2ecf20Sopenharmony_ciHFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) 3378c2ecf20Sopenharmony_ci#else 3388c2ecf20Sopenharmony_ci HFC_inw_regio(struct hfc_multi *hc, u_char reg) 3398c2ecf20Sopenharmony_ci#endif 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci outb(reg, hc->pci_iobase + 4); 3428c2ecf20Sopenharmony_ci return inw(hc->pci_iobase); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_cistatic void 3458c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3468c2ecf20Sopenharmony_ciHFC_wait_regio(struct hfc_multi *hc, const char *function, int line) 3478c2ecf20Sopenharmony_ci#else 3488c2ecf20Sopenharmony_ci HFC_wait_regio(struct hfc_multi *hc) 3498c2ecf20Sopenharmony_ci#endif 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci outb(R_STATUS, hc->pci_iobase + 4); 3528c2ecf20Sopenharmony_ci while (inb(hc->pci_iobase) & V_BUSY) 3538c2ecf20Sopenharmony_ci cpu_relax(); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 3578c2ecf20Sopenharmony_cistatic void 3588c2ecf20Sopenharmony_ciHFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, 3598c2ecf20Sopenharmony_ci const char *function, int line) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci char regname[256] = "", bits[9] = "xxxxxxxx"; 3628c2ecf20Sopenharmony_ci int i; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci i = -1; 3658c2ecf20Sopenharmony_ci while (hfc_register_names[++i].name) { 3668c2ecf20Sopenharmony_ci if (hfc_register_names[i].reg == reg) 3678c2ecf20Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci if (regname[0] == '\0') 3708c2ecf20Sopenharmony_ci strcpy(regname, "register"); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci bits[7] = '0' + (!!(val & 1)); 3738c2ecf20Sopenharmony_ci bits[6] = '0' + (!!(val & 2)); 3748c2ecf20Sopenharmony_ci bits[5] = '0' + (!!(val & 4)); 3758c2ecf20Sopenharmony_ci bits[4] = '0' + (!!(val & 8)); 3768c2ecf20Sopenharmony_ci bits[3] = '0' + (!!(val & 16)); 3778c2ecf20Sopenharmony_ci bits[2] = '0' + (!!(val & 32)); 3788c2ecf20Sopenharmony_ci bits[1] = '0' + (!!(val & 64)); 3798c2ecf20Sopenharmony_ci bits[0] = '0' + (!!(val & 128)); 3808c2ecf20Sopenharmony_ci printk(KERN_DEBUG 3818c2ecf20Sopenharmony_ci "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", 3828c2ecf20Sopenharmony_ci hc->id, reg, regname, val, bits, function, line); 3838c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, reg, val); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_cistatic u_char 3868c2ecf20Sopenharmony_ciHFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci char regname[256] = "", bits[9] = "xxxxxxxx"; 3898c2ecf20Sopenharmony_ci u_char val = HFC_inb_nodebug(hc, reg); 3908c2ecf20Sopenharmony_ci int i; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci i = 0; 3938c2ecf20Sopenharmony_ci while (hfc_register_names[i++].name) 3948c2ecf20Sopenharmony_ci ; 3958c2ecf20Sopenharmony_ci while (hfc_register_names[++i].name) { 3968c2ecf20Sopenharmony_ci if (hfc_register_names[i].reg == reg) 3978c2ecf20Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci if (regname[0] == '\0') 4008c2ecf20Sopenharmony_ci strcpy(regname, "register"); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci bits[7] = '0' + (!!(val & 1)); 4038c2ecf20Sopenharmony_ci bits[6] = '0' + (!!(val & 2)); 4048c2ecf20Sopenharmony_ci bits[5] = '0' + (!!(val & 4)); 4058c2ecf20Sopenharmony_ci bits[4] = '0' + (!!(val & 8)); 4068c2ecf20Sopenharmony_ci bits[3] = '0' + (!!(val & 16)); 4078c2ecf20Sopenharmony_ci bits[2] = '0' + (!!(val & 32)); 4088c2ecf20Sopenharmony_ci bits[1] = '0' + (!!(val & 64)); 4098c2ecf20Sopenharmony_ci bits[0] = '0' + (!!(val & 128)); 4108c2ecf20Sopenharmony_ci printk(KERN_DEBUG 4118c2ecf20Sopenharmony_ci "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", 4128c2ecf20Sopenharmony_ci hc->id, reg, regname, val, bits, function, line); 4138c2ecf20Sopenharmony_ci return val; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_cistatic u_short 4168c2ecf20Sopenharmony_ciHFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci char regname[256] = ""; 4198c2ecf20Sopenharmony_ci u_short val = HFC_inw_nodebug(hc, reg); 4208c2ecf20Sopenharmony_ci int i; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci i = 0; 4238c2ecf20Sopenharmony_ci while (hfc_register_names[i++].name) 4248c2ecf20Sopenharmony_ci ; 4258c2ecf20Sopenharmony_ci while (hfc_register_names[++i].name) { 4268c2ecf20Sopenharmony_ci if (hfc_register_names[i].reg == reg) 4278c2ecf20Sopenharmony_ci strcat(regname, hfc_register_names[i].name); 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci if (regname[0] == '\0') 4308c2ecf20Sopenharmony_ci strcpy(regname, "register"); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci printk(KERN_DEBUG 4338c2ecf20Sopenharmony_ci "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", 4348c2ecf20Sopenharmony_ci hc->id, reg, regname, val, function, line); 4358c2ecf20Sopenharmony_ci return val; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_cistatic void 4388c2ecf20Sopenharmony_ciHFC_wait_debug(struct hfc_multi *hc, const char *function, int line) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", 4418c2ecf20Sopenharmony_ci hc->id, function, line); 4428c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci#endif 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* write fifo data (REGIO) */ 4478c2ecf20Sopenharmony_cistatic void 4488c2ecf20Sopenharmony_ciwrite_fifo_regio(struct hfc_multi *hc, u_char *data, int len) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); 4518c2ecf20Sopenharmony_ci while (len >> 2) { 4528c2ecf20Sopenharmony_ci outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase); 4538c2ecf20Sopenharmony_ci data += 4; 4548c2ecf20Sopenharmony_ci len -= 4; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci while (len >> 1) { 4578c2ecf20Sopenharmony_ci outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase); 4588c2ecf20Sopenharmony_ci data += 2; 4598c2ecf20Sopenharmony_ci len -= 2; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci while (len) { 4628c2ecf20Sopenharmony_ci outb(*data, hc->pci_iobase); 4638c2ecf20Sopenharmony_ci data++; 4648c2ecf20Sopenharmony_ci len--; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci/* write fifo data (PCIMEM) */ 4688c2ecf20Sopenharmony_cistatic void 4698c2ecf20Sopenharmony_ciwrite_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci while (len >> 2) { 4728c2ecf20Sopenharmony_ci writel(cpu_to_le32(*(u32 *)data), 4738c2ecf20Sopenharmony_ci hc->pci_membase + A_FIFO_DATA0); 4748c2ecf20Sopenharmony_ci data += 4; 4758c2ecf20Sopenharmony_ci len -= 4; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci while (len >> 1) { 4788c2ecf20Sopenharmony_ci writew(cpu_to_le16(*(u16 *)data), 4798c2ecf20Sopenharmony_ci hc->pci_membase + A_FIFO_DATA0); 4808c2ecf20Sopenharmony_ci data += 2; 4818c2ecf20Sopenharmony_ci len -= 2; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci while (len) { 4848c2ecf20Sopenharmony_ci writeb(*data, hc->pci_membase + A_FIFO_DATA0); 4858c2ecf20Sopenharmony_ci data++; 4868c2ecf20Sopenharmony_ci len--; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* read fifo data (REGIO) */ 4918c2ecf20Sopenharmony_cistatic void 4928c2ecf20Sopenharmony_ciread_fifo_regio(struct hfc_multi *hc, u_char *data, int len) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); 4958c2ecf20Sopenharmony_ci while (len >> 2) { 4968c2ecf20Sopenharmony_ci *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase)); 4978c2ecf20Sopenharmony_ci data += 4; 4988c2ecf20Sopenharmony_ci len -= 4; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci while (len >> 1) { 5018c2ecf20Sopenharmony_ci *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase)); 5028c2ecf20Sopenharmony_ci data += 2; 5038c2ecf20Sopenharmony_ci len -= 2; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci while (len) { 5068c2ecf20Sopenharmony_ci *data = inb(hc->pci_iobase); 5078c2ecf20Sopenharmony_ci data++; 5088c2ecf20Sopenharmony_ci len--; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* read fifo data (PCIMEM) */ 5138c2ecf20Sopenharmony_cistatic void 5148c2ecf20Sopenharmony_ciread_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci while (len >> 2) { 5178c2ecf20Sopenharmony_ci *(u32 *)data = 5188c2ecf20Sopenharmony_ci le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0)); 5198c2ecf20Sopenharmony_ci data += 4; 5208c2ecf20Sopenharmony_ci len -= 4; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci while (len >> 1) { 5238c2ecf20Sopenharmony_ci *(u16 *)data = 5248c2ecf20Sopenharmony_ci le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0)); 5258c2ecf20Sopenharmony_ci data += 2; 5268c2ecf20Sopenharmony_ci len -= 2; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci while (len) { 5298c2ecf20Sopenharmony_ci *data = readb(hc->pci_membase + A_FIFO_DATA0); 5308c2ecf20Sopenharmony_ci data++; 5318c2ecf20Sopenharmony_ci len--; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void 5368c2ecf20Sopenharmony_cienable_hwirq(struct hfc_multi *hc) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; 5398c2ecf20Sopenharmony_ci HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic void 5438c2ecf20Sopenharmony_cidisable_hwirq(struct hfc_multi *hc) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); 5468c2ecf20Sopenharmony_ci HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci#define NUM_EC 2 5508c2ecf20Sopenharmony_ci#define MAX_TDM_CHAN 32 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic inline void 5548c2ecf20Sopenharmony_cienablepcibridge(struct hfc_multi *c) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic inline void 5608c2ecf20Sopenharmony_cidisablepcibridge(struct hfc_multi *c) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic inline unsigned char 5668c2ecf20Sopenharmony_cireadpcibridge(struct hfc_multi *hc, unsigned char address) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci unsigned short cipv; 5698c2ecf20Sopenharmony_ci unsigned char data; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!hc->pci_iobase) 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* slow down a PCI read access by 1 PCI clock cycle */ 5758c2ecf20Sopenharmony_ci HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (address == 0) 5788c2ecf20Sopenharmony_ci cipv = 0x4000; 5798c2ecf20Sopenharmony_ci else 5808c2ecf20Sopenharmony_ci cipv = 0x5800; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* select local bridge port address by writing to CIP port */ 5838c2ecf20Sopenharmony_ci /* data = HFC_inb(c, cipv); * was _io before */ 5848c2ecf20Sopenharmony_ci outw(cipv, hc->pci_iobase + 4); 5858c2ecf20Sopenharmony_ci data = inb(hc->pci_iobase); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* restore R_CTRL for normal PCI read cycle speed */ 5888c2ecf20Sopenharmony_ci HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return data; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic inline void 5948c2ecf20Sopenharmony_ciwritepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci unsigned short cipv; 5978c2ecf20Sopenharmony_ci unsigned int datav; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!hc->pci_iobase) 6008c2ecf20Sopenharmony_ci return; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (address == 0) 6038c2ecf20Sopenharmony_ci cipv = 0x4000; 6048c2ecf20Sopenharmony_ci else 6058c2ecf20Sopenharmony_ci cipv = 0x5800; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* select local bridge port address by writing to CIP port */ 6088c2ecf20Sopenharmony_ci outw(cipv, hc->pci_iobase + 4); 6098c2ecf20Sopenharmony_ci /* define a 32 bit dword with 4 identical bytes for write sequence */ 6108c2ecf20Sopenharmony_ci datav = data | ((__u32) data << 8) | ((__u32) data << 16) | 6118c2ecf20Sopenharmony_ci ((__u32) data << 24); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* 6148c2ecf20Sopenharmony_ci * write this 32 bit dword to the bridge data port 6158c2ecf20Sopenharmony_ci * this will initiate a write sequence of up to 4 writes to the same 6168c2ecf20Sopenharmony_ci * address on the local bus interface the number of write accesses 6178c2ecf20Sopenharmony_ci * is undefined but >=1 and depends on the next PCI transaction 6188c2ecf20Sopenharmony_ci * during write sequence on the local bus 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci outl(datav, hc->pci_iobase); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic inline void 6248c2ecf20Sopenharmony_cicpld_set_reg(struct hfc_multi *hc, unsigned char reg) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci /* Do data pin read low byte */ 6278c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, reg); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic inline void 6318c2ecf20Sopenharmony_cicpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci cpld_set_reg(hc, reg); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci enablepcibridge(hc); 6368c2ecf20Sopenharmony_ci writepcibridge(hc, 1, val); 6378c2ecf20Sopenharmony_ci disablepcibridge(hc); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic inline unsigned char 6438c2ecf20Sopenharmony_cicpld_read_reg(struct hfc_multi *hc, unsigned char reg) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci unsigned char bytein; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci cpld_set_reg(hc, reg); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Do data pin read low byte */ 6508c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, reg); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci enablepcibridge(hc); 6538c2ecf20Sopenharmony_ci bytein = readpcibridge(hc, 1); 6548c2ecf20Sopenharmony_ci disablepcibridge(hc); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return bytein; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic inline void 6608c2ecf20Sopenharmony_civpm_write_address(struct hfc_multi *hc, unsigned short addr) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci cpld_write_reg(hc, 0, 0xff & addr); 6638c2ecf20Sopenharmony_ci cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic inline unsigned short 6678c2ecf20Sopenharmony_civpm_read_address(struct hfc_multi *c) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci unsigned short addr; 6708c2ecf20Sopenharmony_ci unsigned short highbit; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci addr = cpld_read_reg(c, 0); 6738c2ecf20Sopenharmony_ci highbit = cpld_read_reg(c, 1); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci addr = addr | (highbit << 8); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return addr & 0x1ff; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic inline unsigned char 6818c2ecf20Sopenharmony_civpm_in(struct hfc_multi *c, int which, unsigned short addr) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci unsigned char res; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci vpm_write_address(c, addr); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!which) 6888c2ecf20Sopenharmony_ci cpld_set_reg(c, 2); 6898c2ecf20Sopenharmony_ci else 6908c2ecf20Sopenharmony_ci cpld_set_reg(c, 3); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci enablepcibridge(c); 6938c2ecf20Sopenharmony_ci res = readpcibridge(c, 1); 6948c2ecf20Sopenharmony_ci disablepcibridge(c); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci cpld_set_reg(c, 0); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return res; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic inline void 7028c2ecf20Sopenharmony_civpm_out(struct hfc_multi *c, int which, unsigned short addr, 7038c2ecf20Sopenharmony_ci unsigned char data) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci vpm_write_address(c, addr); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci enablepcibridge(c); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (!which) 7108c2ecf20Sopenharmony_ci cpld_set_reg(c, 2); 7118c2ecf20Sopenharmony_ci else 7128c2ecf20Sopenharmony_ci cpld_set_reg(c, 3); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci writepcibridge(c, 1, data); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci cpld_set_reg(c, 0); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci disablepcibridge(c); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci { 7218c2ecf20Sopenharmony_ci unsigned char regin; 7228c2ecf20Sopenharmony_ci regin = vpm_in(c, which, addr); 7238c2ecf20Sopenharmony_ci if (regin != data) 7248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " 7258c2ecf20Sopenharmony_ci "0x%x\n", data, addr, regin); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void 7328c2ecf20Sopenharmony_civpm_init(struct hfc_multi *wc) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci unsigned char reg; 7358c2ecf20Sopenharmony_ci unsigned int mask; 7368c2ecf20Sopenharmony_ci unsigned int i, x, y; 7378c2ecf20Sopenharmony_ci unsigned int ver; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci for (x = 0; x < NUM_EC; x++) { 7408c2ecf20Sopenharmony_ci /* Setup GPIO's */ 7418c2ecf20Sopenharmony_ci if (!x) { 7428c2ecf20Sopenharmony_ci ver = vpm_in(wc, x, 0x1a0); 7438c2ecf20Sopenharmony_ci printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci for (y = 0; y < 4; y++) { 7478c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ 7488c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ 7498c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Setup TDM path - sets fsync and tdm_clk as inputs */ 7538c2ecf20Sopenharmony_ci reg = vpm_in(wc, x, 0x1a3); /* misc_con */ 7548c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x1a3, reg & ~2); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Setup Echo length (256 taps) */ 7578c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x022, 1); 7588c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x023, 0xff); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Setup timeslots */ 7618c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x02f, 0x00); 7628c2ecf20Sopenharmony_ci mask = 0x02020202 << (x * 4); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Setup the tdm channel masks for all chips */ 7658c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 7668c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* Setup convergence rate */ 7698c2ecf20Sopenharmony_ci printk(KERN_DEBUG "VPM: A-law mode\n"); 7708c2ecf20Sopenharmony_ci reg = 0x00 | 0x10 | 0x01; 7718c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x20, reg); 7728c2ecf20Sopenharmony_ci printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); 7738c2ecf20Sopenharmony_ci /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x24, 0x02); 7768c2ecf20Sopenharmony_ci reg = vpm_in(wc, x, 0x24); 7778c2ecf20Sopenharmony_ci printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Initialize echo cans */ 7808c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 7818c2ecf20Sopenharmony_ci if (mask & (0x00000001 << i)) 7828c2ecf20Sopenharmony_ci vpm_out(wc, x, i, 0x00); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * ARM arch at least disallows a udelay of 7878c2ecf20Sopenharmony_ci * more than 2ms... it gives a fake "__bad_udelay" 7888c2ecf20Sopenharmony_ci * reference at link-time. 7898c2ecf20Sopenharmony_ci * long delays in kernel code are pretty sucky anyway 7908c2ecf20Sopenharmony_ci * for now work around it using 5 x 2ms instead of 1 x 10ms 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci udelay(2000); 7948c2ecf20Sopenharmony_ci udelay(2000); 7958c2ecf20Sopenharmony_ci udelay(2000); 7968c2ecf20Sopenharmony_ci udelay(2000); 7978c2ecf20Sopenharmony_ci udelay(2000); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Put in bypass mode */ 8008c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 8018c2ecf20Sopenharmony_ci if (mask & (0x00000001 << i)) 8028c2ecf20Sopenharmony_ci vpm_out(wc, x, i, 0x01); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Enable bypass */ 8068c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TDM_CHAN; i++) { 8078c2ecf20Sopenharmony_ci if (mask & (0x00000001 << i)) 8088c2ecf20Sopenharmony_ci vpm_out(wc, x, 0x78 + i, 0x01); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci#ifdef UNUSED 8158c2ecf20Sopenharmony_cistatic void 8168c2ecf20Sopenharmony_civpm_check(struct hfc_multi *hctmp) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci unsigned char gpi2; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci gpi2 = HFC_inb(hctmp, R_GPI_IN2); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if ((gpi2 & 0x3) != 0x3) 8238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci#endif /* UNUSED */ 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci/* 8298c2ecf20Sopenharmony_ci * Interface to enable/disable the HW Echocan 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * these functions are called within a spin_lock_irqsave on 8328c2ecf20Sopenharmony_ci * the channel instance lock, so we are not disturbed by irqs 8338c2ecf20Sopenharmony_ci * 8348c2ecf20Sopenharmony_ci * we can later easily change the interface to make other 8358c2ecf20Sopenharmony_ci * things configurable, for now we configure the taps 8368c2ecf20Sopenharmony_ci * 8378c2ecf20Sopenharmony_ci */ 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic void 8408c2ecf20Sopenharmony_civpm_echocan_on(struct hfc_multi *hc, int ch, int taps) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci unsigned int timeslot; 8438c2ecf20Sopenharmony_ci unsigned int unit; 8448c2ecf20Sopenharmony_ci struct bchannel *bch = hc->chan[ch].bch; 8458c2ecf20Sopenharmony_ci#ifdef TXADJ 8468c2ecf20Sopenharmony_ci int txadj = -4; 8478c2ecf20Sopenharmony_ci struct sk_buff *skb; 8488c2ecf20Sopenharmony_ci#endif 8498c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != ISDN_P_B_RAW) 8508c2ecf20Sopenharmony_ci return; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (!bch) 8538c2ecf20Sopenharmony_ci return; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci#ifdef TXADJ 8568c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, 8578c2ecf20Sopenharmony_ci sizeof(int), &txadj, GFP_ATOMIC); 8588c2ecf20Sopenharmony_ci if (skb) 8598c2ecf20Sopenharmony_ci recv_Bchannel_skb(bch, skb); 8608c2ecf20Sopenharmony_ci#endif 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; 8638c2ecf20Sopenharmony_ci unit = ch % 4; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", 8668c2ecf20Sopenharmony_ci taps, timeslot); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci vpm_out(hc, unit, timeslot, 0x7e); 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic void 8728c2ecf20Sopenharmony_civpm_echocan_off(struct hfc_multi *hc, int ch) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci unsigned int timeslot; 8758c2ecf20Sopenharmony_ci unsigned int unit; 8768c2ecf20Sopenharmony_ci struct bchannel *bch = hc->chan[ch].bch; 8778c2ecf20Sopenharmony_ci#ifdef TXADJ 8788c2ecf20Sopenharmony_ci int txadj = 0; 8798c2ecf20Sopenharmony_ci struct sk_buff *skb; 8808c2ecf20Sopenharmony_ci#endif 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != ISDN_P_B_RAW) 8838c2ecf20Sopenharmony_ci return; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!bch) 8868c2ecf20Sopenharmony_ci return; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci#ifdef TXADJ 8898c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, 8908c2ecf20Sopenharmony_ci sizeof(int), &txadj, GFP_ATOMIC); 8918c2ecf20Sopenharmony_ci if (skb) 8928c2ecf20Sopenharmony_ci recv_Bchannel_skb(bch, skb); 8938c2ecf20Sopenharmony_ci#endif 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1; 8968c2ecf20Sopenharmony_ci unit = ch % 4; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", 8998c2ecf20Sopenharmony_ci timeslot); 9008c2ecf20Sopenharmony_ci /* FILLME */ 9018c2ecf20Sopenharmony_ci vpm_out(hc, unit, timeslot, 0x01); 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/* 9068c2ecf20Sopenharmony_ci * Speech Design resync feature 9078c2ecf20Sopenharmony_ci * NOTE: This is called sometimes outside interrupt handler. 9088c2ecf20Sopenharmony_ci * We must lock irqsave, so no other interrupt (other card) will occur! 9098c2ecf20Sopenharmony_ci * Also multiple interrupts may nest, so must lock each access (lists, card)! 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic inline void 9128c2ecf20Sopenharmony_cihfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct hfc_multi *hc, *next, *pcmmaster = NULL; 9158c2ecf20Sopenharmony_ci void __iomem *plx_acc_32; 9168c2ecf20Sopenharmony_ci u_int pv; 9178c2ecf20Sopenharmony_ci u_long flags; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 9208c2ecf20Sopenharmony_ci spin_lock(&plx_lock); /* must be locked inside other locks */ 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", 9248c2ecf20Sopenharmony_ci __func__, syncmaster); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* select new master */ 9278c2ecf20Sopenharmony_ci if (newmaster) { 9288c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9298c2ecf20Sopenharmony_ci printk(KERN_DEBUG "using provided controller\n"); 9308c2ecf20Sopenharmony_ci } else { 9318c2ecf20Sopenharmony_ci list_for_each_entry_safe(hc, next, &HFClist, list) { 9328c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 9338c2ecf20Sopenharmony_ci if (hc->syncronized) { 9348c2ecf20Sopenharmony_ci newmaster = hc; 9358c2ecf20Sopenharmony_ci break; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Disable sync of all cards */ 9428c2ecf20Sopenharmony_ci list_for_each_entry_safe(hc, next, &HFClist, list) { 9438c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 9448c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 9458c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 9468c2ecf20Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 9478c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 9488c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { 9498c2ecf20Sopenharmony_ci pcmmaster = hc; 9508c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 9518c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9528c2ecf20Sopenharmony_ci printk(KERN_DEBUG 9538c2ecf20Sopenharmony_ci "Schedule SYNC_I\n"); 9548c2ecf20Sopenharmony_ci hc->e1_resync |= 1; /* get SYNC_I */ 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (newmaster) { 9618c2ecf20Sopenharmony_ci hc = newmaster; 9628c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9638c2ecf20Sopenharmony_ci printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " 9648c2ecf20Sopenharmony_ci "interface.\n", hc->id, hc); 9658c2ecf20Sopenharmony_ci /* Enable new sync master */ 9668c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 9678c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 9688c2ecf20Sopenharmony_ci pv |= PLX_SYNC_O_EN; 9698c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 9708c2ecf20Sopenharmony_ci /* switch to jatt PLL, if not disabled by RX_SYNC */ 9718c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 9728c2ecf20Sopenharmony_ci && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { 9738c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9748c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Schedule jatt PLL\n"); 9758c2ecf20Sopenharmony_ci hc->e1_resync |= 2; /* switch to jatt */ 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci } else { 9788c2ecf20Sopenharmony_ci if (pcmmaster) { 9798c2ecf20Sopenharmony_ci hc = pcmmaster; 9808c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9818c2ecf20Sopenharmony_ci printk(KERN_DEBUG 9828c2ecf20Sopenharmony_ci "id=%d (0x%p) = PCM master syncronized " 9838c2ecf20Sopenharmony_ci "with QUARTZ\n", hc->id, hc); 9848c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 9858c2ecf20Sopenharmony_ci /* Use the crystal clock for the PCM 9868c2ecf20Sopenharmony_ci master card */ 9878c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9888c2ecf20Sopenharmony_ci printk(KERN_DEBUG 9898c2ecf20Sopenharmony_ci "Schedule QUARTZ for HFC-E1\n"); 9908c2ecf20Sopenharmony_ci hc->e1_resync |= 4; /* switch quartz */ 9918c2ecf20Sopenharmony_ci } else { 9928c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 9938c2ecf20Sopenharmony_ci printk(KERN_DEBUG 9948c2ecf20Sopenharmony_ci "QUARTZ is automatically " 9958c2ecf20Sopenharmony_ci "enabled by HFC-%dS\n", hc->ctype); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 9988c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 9998c2ecf20Sopenharmony_ci pv |= PLX_SYNC_O_EN; 10008c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 10018c2ecf20Sopenharmony_ci } else 10028c2ecf20Sopenharmony_ci if (!rm) 10038c2ecf20Sopenharmony_ci printk(KERN_ERR "%s no pcm master, this MUST " 10048c2ecf20Sopenharmony_ci "not happen!\n", __func__); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci syncmaster = newmaster; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci spin_unlock(&plx_lock); 10098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* This must be called AND hc must be locked irqsave!!! */ 10138c2ecf20Sopenharmony_cistatic inline void 10148c2ecf20Sopenharmony_ciplxsd_checksync(struct hfc_multi *hc, int rm) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci if (hc->syncronized) { 10178c2ecf20Sopenharmony_ci if (syncmaster == NULL) { 10188c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 10198c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: GOT sync on card %d" 10208c2ecf20Sopenharmony_ci " (id=%d)\n", __func__, hc->id + 1, 10218c2ecf20Sopenharmony_ci hc->id); 10228c2ecf20Sopenharmony_ci hfcmulti_resync(hc, hc, rm); 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci } else { 10258c2ecf20Sopenharmony_ci if (syncmaster == hc) { 10268c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 10278c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: LOST sync on card %d" 10288c2ecf20Sopenharmony_ci " (id=%d)\n", __func__, hc->id + 1, 10298c2ecf20Sopenharmony_ci hc->id); 10308c2ecf20Sopenharmony_ci hfcmulti_resync(hc, NULL, rm); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci/* 10378c2ecf20Sopenharmony_ci * free hardware resources used by driver 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistatic void 10408c2ecf20Sopenharmony_cirelease_io_hfcmulti(struct hfc_multi *hc) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci void __iomem *plx_acc_32; 10438c2ecf20Sopenharmony_ci u_int pv; 10448c2ecf20Sopenharmony_ci u_long plx_flags; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 10478c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* soft reset also masks all interrupts */ 10508c2ecf20Sopenharmony_ci hc->hw.r_cirm |= V_SRES; 10518c2ecf20Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 10528c2ecf20Sopenharmony_ci udelay(1000); 10538c2ecf20Sopenharmony_ci hc->hw.r_cirm &= ~V_SRES; 10548c2ecf20Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 10558c2ecf20Sopenharmony_ci udelay(1000); /* instead of 'wait' that may cause locking */ 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* release Speech Design card, if PLX was initialized */ 10588c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { 10598c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 10608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: release PLXSD card %d\n", 10618c2ecf20Sopenharmony_ci __func__, hc->id + 1); 10628c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 10638c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 10648c2ecf20Sopenharmony_ci writel(PLX_GPIOC_INIT, plx_acc_32); 10658c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 10668c2ecf20Sopenharmony_ci /* Termination off */ 10678c2ecf20Sopenharmony_ci pv &= ~PLX_TERM_ON; 10688c2ecf20Sopenharmony_ci /* Disconnect the PCM */ 10698c2ecf20Sopenharmony_ci pv |= PLX_SLAVE_EN_N; 10708c2ecf20Sopenharmony_ci pv &= ~PLX_MASTER_EN; 10718c2ecf20Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 10728c2ecf20Sopenharmony_ci /* Put the DSP in Reset */ 10738c2ecf20Sopenharmony_ci pv &= ~PLX_DSP_RES_N; 10748c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 10758c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 10768c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", 10778c2ecf20Sopenharmony_ci __func__, pv); 10788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* disable memory mapped ports / io ports */ 10828c2ecf20Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ 10838c2ecf20Sopenharmony_ci if (hc->pci_dev) 10848c2ecf20Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); 10858c2ecf20Sopenharmony_ci if (hc->pci_membase) 10868c2ecf20Sopenharmony_ci iounmap(hc->pci_membase); 10878c2ecf20Sopenharmony_ci if (hc->plx_membase) 10888c2ecf20Sopenharmony_ci iounmap(hc->plx_membase); 10898c2ecf20Sopenharmony_ci if (hc->pci_iobase) 10908c2ecf20Sopenharmony_ci release_region(hc->pci_iobase, 8); 10918c2ecf20Sopenharmony_ci if (hc->xhfc_membase) 10928c2ecf20Sopenharmony_ci iounmap((void *)hc->xhfc_membase); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (hc->pci_dev) { 10958c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 10968c2ecf20Sopenharmony_ci pci_set_drvdata(hc->pci_dev, NULL); 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 10998c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci/* 11038c2ecf20Sopenharmony_ci * function called to reset the HFC chip. A complete software reset of chip 11048c2ecf20Sopenharmony_ci * and fifos is done. All configuration of the chip is done. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic int 11088c2ecf20Sopenharmony_ciinit_chip(struct hfc_multi *hc) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci u_long flags, val, val2 = 0, rev; 11118c2ecf20Sopenharmony_ci int i, err = 0; 11128c2ecf20Sopenharmony_ci u_char r_conf_en, rval; 11138c2ecf20Sopenharmony_ci void __iomem *plx_acc_32; 11148c2ecf20Sopenharmony_ci u_int pv; 11158c2ecf20Sopenharmony_ci u_long plx_flags, hfc_flags; 11168c2ecf20Sopenharmony_ci int plx_count; 11178c2ecf20Sopenharmony_ci struct hfc_multi *pos, *next, *plx_last_hc; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 11208c2ecf20Sopenharmony_ci /* reset all registers */ 11218c2ecf20Sopenharmony_ci memset(&hc->hw, 0, sizeof(struct hfcm_hw)); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* revision check */ 11248c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 11258c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 11268c2ecf20Sopenharmony_ci val = HFC_inb(hc, R_CHIP_ID); 11278c2ecf20Sopenharmony_ci if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && 11288c2ecf20Sopenharmony_ci (val >> 1) != 0x31) { 11298c2ecf20Sopenharmony_ci printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); 11308c2ecf20Sopenharmony_ci err = -EIO; 11318c2ecf20Sopenharmony_ci goto out; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci rev = HFC_inb(hc, R_CHIP_RV); 11348c2ecf20Sopenharmony_ci printk(KERN_INFO 11358c2ecf20Sopenharmony_ci "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", 11368c2ecf20Sopenharmony_ci val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? 11378c2ecf20Sopenharmony_ci " (old FIFO handling)" : ""); 11388c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { 11398c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); 11408c2ecf20Sopenharmony_ci printk(KERN_WARNING 11418c2ecf20Sopenharmony_ci "HFC_multi: NOTE: Your chip is revision 0, " 11428c2ecf20Sopenharmony_ci "ask Cologne Chip for update. Newer chips " 11438c2ecf20Sopenharmony_ci "have a better FIFO handling. Old chips " 11448c2ecf20Sopenharmony_ci "still work but may have slightly lower " 11458c2ecf20Sopenharmony_ci "HDLC transmit performance.\n"); 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci if (rev > 1) { 11488c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " 11498c2ecf20Sopenharmony_ci "consider chip revision = %ld. The chip / " 11508c2ecf20Sopenharmony_ci "bridge may not work.\n", rev); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* set s-ram size */ 11548c2ecf20Sopenharmony_ci hc->Flen = 0x10; 11558c2ecf20Sopenharmony_ci hc->Zmin = 0x80; 11568c2ecf20Sopenharmony_ci hc->Zlen = 384; 11578c2ecf20Sopenharmony_ci hc->DTMFbase = 0x1000; 11588c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { 11598c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 11608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: changing to 128K external RAM\n", 11618c2ecf20Sopenharmony_ci __func__); 11628c2ecf20Sopenharmony_ci hc->hw.r_ctrl |= V_EXT_RAM; 11638c2ecf20Sopenharmony_ci hc->hw.r_ram_sz = 1; 11648c2ecf20Sopenharmony_ci hc->Flen = 0x20; 11658c2ecf20Sopenharmony_ci hc->Zmin = 0xc0; 11668c2ecf20Sopenharmony_ci hc->Zlen = 1856; 11678c2ecf20Sopenharmony_ci hc->DTMFbase = 0x2000; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { 11708c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 11718c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: changing to 512K external RAM\n", 11728c2ecf20Sopenharmony_ci __func__); 11738c2ecf20Sopenharmony_ci hc->hw.r_ctrl |= V_EXT_RAM; 11748c2ecf20Sopenharmony_ci hc->hw.r_ram_sz = 2; 11758c2ecf20Sopenharmony_ci hc->Flen = 0x20; 11768c2ecf20Sopenharmony_ci hc->Zmin = 0xc0; 11778c2ecf20Sopenharmony_ci hc->Zlen = 8000; 11788c2ecf20Sopenharmony_ci hc->DTMFbase = 0x2000; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 11818c2ecf20Sopenharmony_ci hc->Flen = 0x8; 11828c2ecf20Sopenharmony_ci hc->Zmin = 0x0; 11838c2ecf20Sopenharmony_ci hc->Zlen = 64; 11848c2ecf20Sopenharmony_ci hc->DTMFbase = 0x0; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci hc->max_trans = poll << 1; 11878c2ecf20Sopenharmony_ci if (hc->max_trans > hc->Zlen) 11888c2ecf20Sopenharmony_ci hc->max_trans = hc->Zlen; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* Speech Design PLX bridge */ 11918c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 11928c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 11938c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", 11948c2ecf20Sopenharmony_ci __func__, hc->id + 1); 11958c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 11968c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 11978c2ecf20Sopenharmony_ci writel(PLX_GPIOC_INIT, plx_acc_32); 11988c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 11998c2ecf20Sopenharmony_ci /* The first and the last cards are terminating the PCM bus */ 12008c2ecf20Sopenharmony_ci pv |= PLX_TERM_ON; /* hc is currently the last */ 12018c2ecf20Sopenharmony_ci /* Disconnect the PCM */ 12028c2ecf20Sopenharmony_ci pv |= PLX_SLAVE_EN_N; 12038c2ecf20Sopenharmony_ci pv &= ~PLX_MASTER_EN; 12048c2ecf20Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 12058c2ecf20Sopenharmony_ci /* Put the DSP in Reset */ 12068c2ecf20Sopenharmony_ci pv &= ~PLX_DSP_RES_N; 12078c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 12088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 12098c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 12108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", 12118c2ecf20Sopenharmony_ci __func__, pv); 12128c2ecf20Sopenharmony_ci /* 12138c2ecf20Sopenharmony_ci * If we are the 3rd PLXSD card or higher, we must turn 12148c2ecf20Sopenharmony_ci * termination of last PLXSD card off. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_ci spin_lock_irqsave(&HFClock, hfc_flags); 12178c2ecf20Sopenharmony_ci plx_count = 0; 12188c2ecf20Sopenharmony_ci plx_last_hc = NULL; 12198c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, next, &HFClist, list) { 12208c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { 12218c2ecf20Sopenharmony_ci plx_count++; 12228c2ecf20Sopenharmony_ci if (pos != hc) 12238c2ecf20Sopenharmony_ci plx_last_hc = pos; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci if (plx_count >= 3) { 12278c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 12288c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: card %d is between, so " 12298c2ecf20Sopenharmony_ci "we disable termination\n", 12308c2ecf20Sopenharmony_ci __func__, plx_last_hc->id + 1); 12318c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 12328c2ecf20Sopenharmony_ci plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; 12338c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 12348c2ecf20Sopenharmony_ci pv &= ~PLX_TERM_ON; 12358c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 12368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 12378c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 12388c2ecf20Sopenharmony_ci printk(KERN_DEBUG 12398c2ecf20Sopenharmony_ci "%s: term off: PLX_GPIO=%x\n", 12408c2ecf20Sopenharmony_ci __func__, pv); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&HFClock, hfc_flags); 12438c2ecf20Sopenharmony_ci hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 12478c2ecf20Sopenharmony_ci hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* we only want the real Z2 read-pointer for revision > 0 */ 12508c2ecf20Sopenharmony_ci if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) 12518c2ecf20Sopenharmony_ci hc->hw.r_ram_sz |= V_FZ_MD; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* select pcm mode */ 12548c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 12558c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 12568c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: setting PCM into slave mode\n", 12578c2ecf20Sopenharmony_ci __func__); 12588c2ecf20Sopenharmony_ci } else 12598c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { 12608c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 12618c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: setting PCM into master mode\n", 12628c2ecf20Sopenharmony_ci __func__); 12638c2ecf20Sopenharmony_ci hc->hw.r_pcm_md0 |= V_PCM_MD; 12648c2ecf20Sopenharmony_ci } else { 12658c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 12668c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: performing PCM auto detect\n", 12678c2ecf20Sopenharmony_ci __func__); 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* soft reset */ 12718c2ecf20Sopenharmony_ci HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); 12728c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 12738c2ecf20Sopenharmony_ci HFC_outb(hc, 0x0C /* R_FIFO_THRES */, 12748c2ecf20Sopenharmony_ci 0x11 /* 16 Bytes TX/RX */); 12758c2ecf20Sopenharmony_ci else 12768c2ecf20Sopenharmony_ci HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); 12778c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO_MD, 0); 12788c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 12798c2ecf20Sopenharmony_ci hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; 12808c2ecf20Sopenharmony_ci else 12818c2ecf20Sopenharmony_ci hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES 12828c2ecf20Sopenharmony_ci | V_RLD_EPR; 12838c2ecf20Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 12848c2ecf20Sopenharmony_ci udelay(100); 12858c2ecf20Sopenharmony_ci hc->hw.r_cirm = 0; 12868c2ecf20Sopenharmony_ci HFC_outb(hc, R_CIRM, hc->hw.r_cirm); 12878c2ecf20Sopenharmony_ci udelay(100); 12888c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 12898c2ecf20Sopenharmony_ci HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* Speech Design PLX bridge pcm and sync mode */ 12928c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 12938c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 12948c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 12958c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 12968c2ecf20Sopenharmony_ci /* Connect PCM */ 12978c2ecf20Sopenharmony_ci if (hc->hw.r_pcm_md0 & V_PCM_MD) { 12988c2ecf20Sopenharmony_ci pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; 12998c2ecf20Sopenharmony_ci pv |= PLX_SYNC_O_EN; 13008c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 13018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", 13028c2ecf20Sopenharmony_ci __func__, pv); 13038c2ecf20Sopenharmony_ci } else { 13048c2ecf20Sopenharmony_ci pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); 13058c2ecf20Sopenharmony_ci pv &= ~PLX_SYNC_O_EN; 13068c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 13078c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", 13088c2ecf20Sopenharmony_ci __func__, pv); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 13118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* PCM setup */ 13158c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); 13168c2ecf20Sopenharmony_ci if (hc->slots == 32) 13178c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x00); 13188c2ecf20Sopenharmony_ci if (hc->slots == 64) 13198c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x10); 13208c2ecf20Sopenharmony_ci if (hc->slots == 128) 13218c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD1, 0x20); 13228c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); 13238c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 13248c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ 13258c2ecf20Sopenharmony_ci else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 13268c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ 13278c2ecf20Sopenharmony_ci else 13288c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ 13298c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); 13308c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 13318c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_SLOT, i); 13328c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, A_SL_CFG, 0); 13338c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 13348c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, A_CONF, 0); 13358c2ecf20Sopenharmony_ci hc->slot_owner[i] = -1; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* set clock speed */ 13398c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { 13408c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 13418c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13428c2ecf20Sopenharmony_ci "%s: setting double clock\n", __func__); 13438c2ecf20Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) 13478c2ecf20Sopenharmony_ci HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* B410P GPIO */ 13508c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 13518c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Setting GPIOs\n"); 13528c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x30); 13538c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0x3); 13548c2ecf20Sopenharmony_ci udelay(1000); 13558c2ecf20Sopenharmony_ci printk(KERN_NOTICE "calling vpm_init\n"); 13568c2ecf20Sopenharmony_ci vpm_init(hc); 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* check if R_F0_CNT counts (8 kHz frame count) */ 13608c2ecf20Sopenharmony_ci val = HFC_inb(hc, R_F0_CNTL); 13618c2ecf20Sopenharmony_ci val += HFC_inb(hc, R_F0_CNTH) << 8; 13628c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 13638c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13648c2ecf20Sopenharmony_ci "HFC_multi F0_CNT %ld after reset\n", val); 13658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 13668c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 13678c2ecf20Sopenharmony_ci schedule_timeout((HZ / 100) ? : 1); /* Timeout minimum 10ms */ 13688c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 13698c2ecf20Sopenharmony_ci val2 = HFC_inb(hc, R_F0_CNTL); 13708c2ecf20Sopenharmony_ci val2 += HFC_inb(hc, R_F0_CNTH) << 8; 13718c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 13728c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13738c2ecf20Sopenharmony_ci "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", 13748c2ecf20Sopenharmony_ci val2); 13758c2ecf20Sopenharmony_ci if (val2 >= val + 8) { /* 1 ms */ 13768c2ecf20Sopenharmony_ci /* it counts, so we keep the pcm mode */ 13778c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) 13788c2ecf20Sopenharmony_ci printk(KERN_INFO "controller is PCM bus MASTER\n"); 13798c2ecf20Sopenharmony_ci else 13808c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) 13818c2ecf20Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE\n"); 13828c2ecf20Sopenharmony_ci else { 13838c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 13848c2ecf20Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE " 13858c2ecf20Sopenharmony_ci "(auto detected)\n"); 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci } else { 13888c2ecf20Sopenharmony_ci /* does not count */ 13898c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { 13908c2ecf20Sopenharmony_ci controller_fail: 13918c2ecf20Sopenharmony_ci printk(KERN_ERR "HFC_multi ERROR, getting no 125us " 13928c2ecf20Sopenharmony_ci "pulse. Seems that controller fails.\n"); 13938c2ecf20Sopenharmony_ci err = -EIO; 13948c2ecf20Sopenharmony_ci goto out; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 13978c2ecf20Sopenharmony_ci printk(KERN_INFO "controller is PCM bus SLAVE " 13988c2ecf20Sopenharmony_ci "(ignoring missing PCM clock)\n"); 13998c2ecf20Sopenharmony_ci } else { 14008c2ecf20Sopenharmony_ci /* only one pcm master */ 14018c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) 14028c2ecf20Sopenharmony_ci && plxsd_master) { 14038c2ecf20Sopenharmony_ci printk(KERN_ERR "HFC_multi ERROR, no clock " 14048c2ecf20Sopenharmony_ci "on another Speech Design card found. " 14058c2ecf20Sopenharmony_ci "Please be sure to connect PCM cable.\n"); 14068c2ecf20Sopenharmony_ci err = -EIO; 14078c2ecf20Sopenharmony_ci goto out; 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci /* retry with master clock */ 14108c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 14118c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 14128c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 14138c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 14148c2ecf20Sopenharmony_ci pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; 14158c2ecf20Sopenharmony_ci pv |= PLX_SYNC_O_EN; 14168c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 14178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 14188c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 14198c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: master: " 14208c2ecf20Sopenharmony_ci "PLX_GPIO=%x\n", __func__, pv); 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci hc->hw.r_pcm_md0 |= V_PCM_MD; 14238c2ecf20Sopenharmony_ci HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); 14248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 14258c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 14268c2ecf20Sopenharmony_ci schedule_timeout((HZ / 100) ?: 1); /* Timeout min. 10ms */ 14278c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 14288c2ecf20Sopenharmony_ci val2 = HFC_inb(hc, R_F0_CNTL); 14298c2ecf20Sopenharmony_ci val2 += HFC_inb(hc, R_F0_CNTH) << 8; 14308c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 14318c2ecf20Sopenharmony_ci printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " 14328c2ecf20Sopenharmony_ci "10 ms (2nd try)\n", val2); 14338c2ecf20Sopenharmony_ci if (val2 >= val + 8) { /* 1 ms */ 14348c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, 14358c2ecf20Sopenharmony_ci &hc->chip); 14368c2ecf20Sopenharmony_ci printk(KERN_INFO "controller is PCM bus MASTER " 14378c2ecf20Sopenharmony_ci "(auto detected)\n"); 14388c2ecf20Sopenharmony_ci } else 14398c2ecf20Sopenharmony_ci goto controller_fail; 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci /* Release the DSP Reset */ 14448c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 14458c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) 14468c2ecf20Sopenharmony_ci plxsd_master = 1; 14478c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 14488c2ecf20Sopenharmony_ci plx_acc_32 = hc->plx_membase + PLX_GPIOC; 14498c2ecf20Sopenharmony_ci pv = readl(plx_acc_32); 14508c2ecf20Sopenharmony_ci pv |= PLX_DSP_RES_N; 14518c2ecf20Sopenharmony_ci writel(pv, plx_acc_32); 14528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 14538c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 14548c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", 14558c2ecf20Sopenharmony_ci __func__, pv); 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* pcm id */ 14598c2ecf20Sopenharmony_ci if (hc->pcm) 14608c2ecf20Sopenharmony_ci printk(KERN_INFO "controller has given PCM BUS ID %d\n", 14618c2ecf20Sopenharmony_ci hc->pcm); 14628c2ecf20Sopenharmony_ci else { 14638c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) 14648c2ecf20Sopenharmony_ci || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 14658c2ecf20Sopenharmony_ci PCM_cnt++; /* SD has proprietary bridging */ 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci hc->pcm = PCM_cnt; 14688c2ecf20Sopenharmony_ci printk(KERN_INFO "controller has PCM BUS ID %d " 14698c2ecf20Sopenharmony_ci "(auto selected)\n", hc->pcm); 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* set up timer */ 14738c2ecf20Sopenharmony_ci HFC_outb(hc, R_TI_WD, poll_timer); 14748c2ecf20Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* set E1 state machine IRQ */ 14778c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 14788c2ecf20Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* set DTMF detection */ 14818c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { 14828c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 14838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: enabling DTMF detection " 14848c2ecf20Sopenharmony_ci "for all B-channel\n", __func__); 14858c2ecf20Sopenharmony_ci hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; 14868c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_ULAW, &hc->chip)) 14878c2ecf20Sopenharmony_ci hc->hw.r_dtmf |= V_ULAW_SEL; 14888c2ecf20Sopenharmony_ci HFC_outb(hc, R_DTMF_N, 102 - 1); 14898c2ecf20Sopenharmony_ci hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* conference engine */ 14938c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_ULAW, &hc->chip)) 14948c2ecf20Sopenharmony_ci r_conf_en = V_CONF_EN | V_ULAW; 14958c2ecf20Sopenharmony_ci else 14968c2ecf20Sopenharmony_ci r_conf_en = V_CONF_EN; 14978c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 14988c2ecf20Sopenharmony_ci HFC_outb(hc, R_CONF_EN, r_conf_en); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* setting leds */ 15018c2ecf20Sopenharmony_ci switch (hc->leds) { 15028c2ecf20Sopenharmony_ci case 1: /* HFC-E1 OEM */ 15038c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 15048c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x32); 15058c2ecf20Sopenharmony_ci else 15068c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0x30); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0x0f); 15098c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0x00); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci case 2: /* HFC-4S OEM */ 15158c2ecf20Sopenharmony_ci case 3: 15168c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, 0xf0); 15178c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, 0xff); 15188c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0x00); 15198c2ecf20Sopenharmony_ci break; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { 15238c2ecf20Sopenharmony_ci hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ 15248c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* set master clock */ 15288c2ecf20Sopenharmony_ci if (hc->masterclk >= 0) { 15298c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 15308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: setting ST master clock " 15318c2ecf20Sopenharmony_ci "to port %d (0..%d)\n", 15328c2ecf20Sopenharmony_ci __func__, hc->masterclk, hc->ports - 1); 15338c2ecf20Sopenharmony_ci hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); 15348c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* setting misc irq */ 15408c2ecf20Sopenharmony_ci HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); 15418c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 15428c2ecf20Sopenharmony_ci printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", 15438c2ecf20Sopenharmony_ci hc->hw.r_irqmsk_misc); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* RAM access test */ 15468c2ecf20Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR0, 0); 15478c2ecf20Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR1, 0); 15488c2ecf20Sopenharmony_ci HFC_outb(hc, R_RAM_ADDR2, 0); 15498c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 15508c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, i); 15518c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_DATA, ((i * 3) & 0xff)); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 15548c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, i); 15558c2ecf20Sopenharmony_ci HFC_inb_nodebug(hc, R_RAM_DATA); 15568c2ecf20Sopenharmony_ci rval = HFC_inb_nodebug(hc, R_INT_DATA); 15578c2ecf20Sopenharmony_ci if (rval != ((i * 3) & 0xff)) { 15588c2ecf20Sopenharmony_ci printk(KERN_DEBUG 15598c2ecf20Sopenharmony_ci "addr:%x val:%x should:%x\n", i, rval, 15608c2ecf20Sopenharmony_ci (i * 3) & 0xff); 15618c2ecf20Sopenharmony_ci err++; 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci if (err) { 15658c2ecf20Sopenharmony_ci printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); 15668c2ecf20Sopenharmony_ci err = -EIO; 15678c2ecf20Sopenharmony_ci goto out; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 15718c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 15728c2ecf20Sopenharmony_ciout: 15738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 15748c2ecf20Sopenharmony_ci return err; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci/* 15798c2ecf20Sopenharmony_ci * control the watchdog 15808c2ecf20Sopenharmony_ci */ 15818c2ecf20Sopenharmony_cistatic void 15828c2ecf20Sopenharmony_cihfcmulti_watchdog(struct hfc_multi *hc) 15838c2ecf20Sopenharmony_ci{ 15848c2ecf20Sopenharmony_ci hc->wdcount++; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if (hc->wdcount > 10) { 15878c2ecf20Sopenharmony_ci hc->wdcount = 0; 15888c2ecf20Sopenharmony_ci hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? 15898c2ecf20Sopenharmony_ci V_GPIO_OUT3 : V_GPIO_OUT2; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ 15928c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); 15938c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci/* 16008c2ecf20Sopenharmony_ci * output leds 16018c2ecf20Sopenharmony_ci */ 16028c2ecf20Sopenharmony_cistatic void 16038c2ecf20Sopenharmony_cihfcmulti_leds(struct hfc_multi *hc) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci unsigned long lled; 16068c2ecf20Sopenharmony_ci unsigned long leddw; 16078c2ecf20Sopenharmony_ci int i, state, active, leds; 16088c2ecf20Sopenharmony_ci struct dchannel *dch; 16098c2ecf20Sopenharmony_ci int led[4]; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci switch (hc->leds) { 16128c2ecf20Sopenharmony_ci case 1: /* HFC-E1 OEM */ 16138c2ecf20Sopenharmony_ci /* 2 red steady: LOS 16148c2ecf20Sopenharmony_ci * 1 red steady: L1 not active 16158c2ecf20Sopenharmony_ci * 2 green steady: L1 active 16168c2ecf20Sopenharmony_ci * 1st green flashing: activity on TX 16178c2ecf20Sopenharmony_ci * 2nd green flashing: activity on RX 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci led[0] = 0; 16208c2ecf20Sopenharmony_ci led[1] = 0; 16218c2ecf20Sopenharmony_ci led[2] = 0; 16228c2ecf20Sopenharmony_ci led[3] = 0; 16238c2ecf20Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 16248c2ecf20Sopenharmony_ci if (dch) { 16258c2ecf20Sopenharmony_ci if (hc->chan[hc->dnum[0]].los) 16268c2ecf20Sopenharmony_ci led[1] = 1; 16278c2ecf20Sopenharmony_ci if (hc->e1_state != 1) { 16288c2ecf20Sopenharmony_ci led[0] = 1; 16298c2ecf20Sopenharmony_ci hc->flash[2] = 0; 16308c2ecf20Sopenharmony_ci hc->flash[3] = 0; 16318c2ecf20Sopenharmony_ci } else { 16328c2ecf20Sopenharmony_ci led[2] = 1; 16338c2ecf20Sopenharmony_ci led[3] = 1; 16348c2ecf20Sopenharmony_ci if (!hc->flash[2] && hc->activity_tx) 16358c2ecf20Sopenharmony_ci hc->flash[2] = poll; 16368c2ecf20Sopenharmony_ci if (!hc->flash[3] && hc->activity_rx) 16378c2ecf20Sopenharmony_ci hc->flash[3] = poll; 16388c2ecf20Sopenharmony_ci if (hc->flash[2] && hc->flash[2] < 1024) 16398c2ecf20Sopenharmony_ci led[2] = 0; 16408c2ecf20Sopenharmony_ci if (hc->flash[3] && hc->flash[3] < 1024) 16418c2ecf20Sopenharmony_ci led[3] = 0; 16428c2ecf20Sopenharmony_ci if (hc->flash[2] >= 2048) 16438c2ecf20Sopenharmony_ci hc->flash[2] = 0; 16448c2ecf20Sopenharmony_ci if (hc->flash[3] >= 2048) 16458c2ecf20Sopenharmony_ci hc->flash[3] = 0; 16468c2ecf20Sopenharmony_ci if (hc->flash[2]) 16478c2ecf20Sopenharmony_ci hc->flash[2] += poll; 16488c2ecf20Sopenharmony_ci if (hc->flash[3]) 16498c2ecf20Sopenharmony_ci hc->flash[3] += poll; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; 16538c2ecf20Sopenharmony_ci /* leds are inverted */ 16548c2ecf20Sopenharmony_ci if (leds != (int)hc->ledstate) { 16558c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); 16568c2ecf20Sopenharmony_ci hc->ledstate = leds; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci break; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci case 2: /* HFC-4S OEM */ 16618c2ecf20Sopenharmony_ci /* red steady: PH_DEACTIVATE 16628c2ecf20Sopenharmony_ci * green steady: PH_ACTIVATE 16638c2ecf20Sopenharmony_ci * green flashing: activity on TX 16648c2ecf20Sopenharmony_ci */ 16658c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 16668c2ecf20Sopenharmony_ci state = 0; 16678c2ecf20Sopenharmony_ci active = -1; 16688c2ecf20Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 16698c2ecf20Sopenharmony_ci if (dch) { 16708c2ecf20Sopenharmony_ci state = dch->state; 16718c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 16728c2ecf20Sopenharmony_ci active = 3; 16738c2ecf20Sopenharmony_ci else 16748c2ecf20Sopenharmony_ci active = 7; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci if (state) { 16778c2ecf20Sopenharmony_ci if (state == active) { 16788c2ecf20Sopenharmony_ci led[i] = 1; /* led green */ 16798c2ecf20Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 16808c2ecf20Sopenharmony_ci if (!hc->flash[i] && 16818c2ecf20Sopenharmony_ci (hc->activity_tx & (1 << i))) 16828c2ecf20Sopenharmony_ci hc->flash[i] = poll; 16838c2ecf20Sopenharmony_ci if (hc->flash[i] && hc->flash[i] < 1024) 16848c2ecf20Sopenharmony_ci led[i] = 0; /* led off */ 16858c2ecf20Sopenharmony_ci if (hc->flash[i] >= 2048) 16868c2ecf20Sopenharmony_ci hc->flash[i] = 0; 16878c2ecf20Sopenharmony_ci if (hc->flash[i]) 16888c2ecf20Sopenharmony_ci hc->flash[i] += poll; 16898c2ecf20Sopenharmony_ci } else { 16908c2ecf20Sopenharmony_ci led[i] = 2; /* led red */ 16918c2ecf20Sopenharmony_ci hc->flash[i] = 0; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci } else 16948c2ecf20Sopenharmony_ci led[i] = 0; /* led off */ 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 16978c2ecf20Sopenharmony_ci leds = 0; 16988c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 16998c2ecf20Sopenharmony_ci if (led[i] == 1) { 17008c2ecf20Sopenharmony_ci /*green*/ 17018c2ecf20Sopenharmony_ci leds |= (0x2 << (i * 2)); 17028c2ecf20Sopenharmony_ci } else if (led[i] == 2) { 17038c2ecf20Sopenharmony_ci /*red*/ 17048c2ecf20Sopenharmony_ci leds |= (0x1 << (i * 2)); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci if (leds != (int)hc->ledstate) { 17088c2ecf20Sopenharmony_ci vpm_out(hc, 0, 0x1a8 + 3, leds); 17098c2ecf20Sopenharmony_ci hc->ledstate = leds; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci } else { 17128c2ecf20Sopenharmony_ci leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | 17138c2ecf20Sopenharmony_ci ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | 17148c2ecf20Sopenharmony_ci ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | 17158c2ecf20Sopenharmony_ci ((led[0] & 1) << 6) | ((led[2] & 1) << 7); 17168c2ecf20Sopenharmony_ci if (leds != (int)hc->ledstate) { 17178c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); 17188c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); 17198c2ecf20Sopenharmony_ci hc->ledstate = leds; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci case 3: /* HFC 1S/2S Beronet */ 17258c2ecf20Sopenharmony_ci /* red steady: PH_DEACTIVATE 17268c2ecf20Sopenharmony_ci * green steady: PH_ACTIVATE 17278c2ecf20Sopenharmony_ci * green flashing: activity on TX 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 17308c2ecf20Sopenharmony_ci state = 0; 17318c2ecf20Sopenharmony_ci active = -1; 17328c2ecf20Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 17338c2ecf20Sopenharmony_ci if (dch) { 17348c2ecf20Sopenharmony_ci state = dch->state; 17358c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 17368c2ecf20Sopenharmony_ci active = 3; 17378c2ecf20Sopenharmony_ci else 17388c2ecf20Sopenharmony_ci active = 7; 17398c2ecf20Sopenharmony_ci } 17408c2ecf20Sopenharmony_ci if (state) { 17418c2ecf20Sopenharmony_ci if (state == active) { 17428c2ecf20Sopenharmony_ci led[i] = 1; /* led green */ 17438c2ecf20Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 17448c2ecf20Sopenharmony_ci if (!hc->flash[i] && 17458c2ecf20Sopenharmony_ci (hc->activity_tx & (1 << i))) 17468c2ecf20Sopenharmony_ci hc->flash[i] = poll; 17478c2ecf20Sopenharmony_ci if (hc->flash[i] < 1024) 17488c2ecf20Sopenharmony_ci led[i] = 0; /* led off */ 17498c2ecf20Sopenharmony_ci if (hc->flash[i] >= 2048) 17508c2ecf20Sopenharmony_ci hc->flash[i] = 0; 17518c2ecf20Sopenharmony_ci if (hc->flash[i]) 17528c2ecf20Sopenharmony_ci hc->flash[i] += poll; 17538c2ecf20Sopenharmony_ci } else { 17548c2ecf20Sopenharmony_ci led[i] = 2; /* led red */ 17558c2ecf20Sopenharmony_ci hc->flash[i] = 0; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci } else 17588c2ecf20Sopenharmony_ci led[i] = 0; /* led off */ 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2) 17618c2ecf20Sopenharmony_ci | ((led[1]&1) << 3); 17628c2ecf20Sopenharmony_ci if (leds != (int)hc->ledstate) { 17638c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_EN1, 17648c2ecf20Sopenharmony_ci ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); 17658c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_GPIO_OUT1, 17668c2ecf20Sopenharmony_ci ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); 17678c2ecf20Sopenharmony_ci hc->ledstate = leds; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci case 8: /* HFC 8S+ Beronet */ 17718c2ecf20Sopenharmony_ci /* off: PH_DEACTIVATE 17728c2ecf20Sopenharmony_ci * steady: PH_ACTIVATE 17738c2ecf20Sopenharmony_ci * flashing: activity on TX 17748c2ecf20Sopenharmony_ci */ 17758c2ecf20Sopenharmony_ci lled = 0xff; /* leds off */ 17768c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 17778c2ecf20Sopenharmony_ci state = 0; 17788c2ecf20Sopenharmony_ci active = -1; 17798c2ecf20Sopenharmony_ci dch = hc->chan[(i << 2) | 2].dch; 17808c2ecf20Sopenharmony_ci if (dch) { 17818c2ecf20Sopenharmony_ci state = dch->state; 17828c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 17838c2ecf20Sopenharmony_ci active = 3; 17848c2ecf20Sopenharmony_ci else 17858c2ecf20Sopenharmony_ci active = 7; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci if (state) { 17888c2ecf20Sopenharmony_ci if (state == active) { 17898c2ecf20Sopenharmony_ci lled &= ~(1 << i); /* led on */ 17908c2ecf20Sopenharmony_ci hc->activity_tx |= hc->activity_rx; 17918c2ecf20Sopenharmony_ci if (!hc->flash[i] && 17928c2ecf20Sopenharmony_ci (hc->activity_tx & (1 << i))) 17938c2ecf20Sopenharmony_ci hc->flash[i] = poll; 17948c2ecf20Sopenharmony_ci if (hc->flash[i] < 1024) 17958c2ecf20Sopenharmony_ci lled |= 1 << i; /* led off */ 17968c2ecf20Sopenharmony_ci if (hc->flash[i] >= 2048) 17978c2ecf20Sopenharmony_ci hc->flash[i] = 0; 17988c2ecf20Sopenharmony_ci if (hc->flash[i]) 17998c2ecf20Sopenharmony_ci hc->flash[i] += poll; 18008c2ecf20Sopenharmony_ci } else 18018c2ecf20Sopenharmony_ci hc->flash[i] = 0; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci leddw = lled << 24 | lled << 16 | lled << 8 | lled; 18058c2ecf20Sopenharmony_ci if (leddw != hc->ledstate) { 18068c2ecf20Sopenharmony_ci /* HFC_outb(hc, R_BRG_PCM_CFG, 1); 18078c2ecf20Sopenharmony_ci HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ 18088c2ecf20Sopenharmony_ci /* was _io before */ 18098c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); 18108c2ecf20Sopenharmony_ci outw(0x4000, hc->pci_iobase + 4); 18118c2ecf20Sopenharmony_ci outl(leddw, hc->pci_iobase); 18128c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); 18138c2ecf20Sopenharmony_ci hc->ledstate = leddw; 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci break; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci hc->activity_tx = 0; 18188c2ecf20Sopenharmony_ci hc->activity_rx = 0; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci/* 18218c2ecf20Sopenharmony_ci * read dtmf coefficients 18228c2ecf20Sopenharmony_ci */ 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic void 18258c2ecf20Sopenharmony_cihfcmulti_dtmf(struct hfc_multi *hc) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci s32 *coeff; 18288c2ecf20Sopenharmony_ci u_int mantissa; 18298c2ecf20Sopenharmony_ci int co, ch; 18308c2ecf20Sopenharmony_ci struct bchannel *bch = NULL; 18318c2ecf20Sopenharmony_ci u8 exponent; 18328c2ecf20Sopenharmony_ci int dtmf = 0; 18338c2ecf20Sopenharmony_ci int addr; 18348c2ecf20Sopenharmony_ci u16 w_float; 18358c2ecf20Sopenharmony_ci struct sk_buff *skb; 18368c2ecf20Sopenharmony_ci struct mISDNhead *hh; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 18398c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); 18408c2ecf20Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 18418c2ecf20Sopenharmony_ci /* only process enabled B-channels */ 18428c2ecf20Sopenharmony_ci bch = hc->chan[ch].bch; 18438c2ecf20Sopenharmony_ci if (!bch) 18448c2ecf20Sopenharmony_ci continue; 18458c2ecf20Sopenharmony_ci if (!hc->created[hc->chan[ch].port]) 18468c2ecf20Sopenharmony_ci continue; 18478c2ecf20Sopenharmony_ci if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) 18488c2ecf20Sopenharmony_ci continue; 18498c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 18508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dtmf channel %d:", 18518c2ecf20Sopenharmony_ci __func__, ch); 18528c2ecf20Sopenharmony_ci coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); 18538c2ecf20Sopenharmony_ci dtmf = 1; 18548c2ecf20Sopenharmony_ci for (co = 0; co < 8; co++) { 18558c2ecf20Sopenharmony_ci /* read W(n-1) coefficient */ 18568c2ecf20Sopenharmony_ci addr = hc->DTMFbase + ((co << 7) | (ch << 2)); 18578c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); 18588c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR1, addr >> 8); 18598c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr >> 16) 18608c2ecf20Sopenharmony_ci | V_ADDR_INC); 18618c2ecf20Sopenharmony_ci w_float = HFC_inb_nodebug(hc, R_RAM_DATA); 18628c2ecf20Sopenharmony_ci w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); 18638c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 18648c2ecf20Sopenharmony_ci printk(" %04x", w_float); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* decode float (see chip doc) */ 18678c2ecf20Sopenharmony_ci mantissa = w_float & 0x0fff; 18688c2ecf20Sopenharmony_ci if (w_float & 0x8000) 18698c2ecf20Sopenharmony_ci mantissa |= 0xfffff000; 18708c2ecf20Sopenharmony_ci exponent = (w_float >> 12) & 0x7; 18718c2ecf20Sopenharmony_ci if (exponent) { 18728c2ecf20Sopenharmony_ci mantissa ^= 0x1000; 18738c2ecf20Sopenharmony_ci mantissa <<= (exponent - 1); 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci /* store coefficient */ 18778c2ecf20Sopenharmony_ci coeff[co << 1] = mantissa; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* read W(n) coefficient */ 18808c2ecf20Sopenharmony_ci w_float = HFC_inb_nodebug(hc, R_RAM_DATA); 18818c2ecf20Sopenharmony_ci w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); 18828c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 18838c2ecf20Sopenharmony_ci printk(" %04x", w_float); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci /* decode float (see chip doc) */ 18868c2ecf20Sopenharmony_ci mantissa = w_float & 0x0fff; 18878c2ecf20Sopenharmony_ci if (w_float & 0x8000) 18888c2ecf20Sopenharmony_ci mantissa |= 0xfffff000; 18898c2ecf20Sopenharmony_ci exponent = (w_float >> 12) & 0x7; 18908c2ecf20Sopenharmony_ci if (exponent) { 18918c2ecf20Sopenharmony_ci mantissa ^= 0x1000; 18928c2ecf20Sopenharmony_ci mantissa <<= (exponent - 1); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* store coefficient */ 18968c2ecf20Sopenharmony_ci coeff[(co << 1) | 1] = mantissa; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 18998c2ecf20Sopenharmony_ci printk(" DTMF ready %08x %08x %08x %08x " 19008c2ecf20Sopenharmony_ci "%08x %08x %08x %08x\n", 19018c2ecf20Sopenharmony_ci coeff[0], coeff[1], coeff[2], coeff[3], 19028c2ecf20Sopenharmony_ci coeff[4], coeff[5], coeff[6], coeff[7]); 19038c2ecf20Sopenharmony_ci hc->chan[ch].coeff_count++; 19048c2ecf20Sopenharmony_ci if (hc->chan[ch].coeff_count == 8) { 19058c2ecf20Sopenharmony_ci hc->chan[ch].coeff_count = 0; 19068c2ecf20Sopenharmony_ci skb = mI_alloc_skb(512, GFP_ATOMIC); 19078c2ecf20Sopenharmony_ci if (!skb) { 19088c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: No memory for skb\n", 19098c2ecf20Sopenharmony_ci __func__); 19108c2ecf20Sopenharmony_ci continue; 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(skb); 19138c2ecf20Sopenharmony_ci hh->prim = PH_CONTROL_IND; 19148c2ecf20Sopenharmony_ci hh->id = DTMF_HFC_COEF; 19158c2ecf20Sopenharmony_ci skb_put_data(skb, hc->chan[ch].coeff, 512); 19168c2ecf20Sopenharmony_ci recv_Bchannel_skb(bch, skb); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci /* restart DTMF processing */ 19218c2ecf20Sopenharmony_ci hc->dtmf = dtmf; 19228c2ecf20Sopenharmony_ci if (dtmf) 19238c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci/* 19288c2ecf20Sopenharmony_ci * fill fifo as much as possible 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_cistatic void 19328c2ecf20Sopenharmony_cihfcmulti_tx(struct hfc_multi *hc, int ch) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci int i, ii, temp, len = 0; 19358c2ecf20Sopenharmony_ci int Zspace, z1, z2; /* must be int for calculation */ 19368c2ecf20Sopenharmony_ci int Fspace, f1, f2; 19378c2ecf20Sopenharmony_ci u_char *d; 19388c2ecf20Sopenharmony_ci int *txpending, slot_tx; 19398c2ecf20Sopenharmony_ci struct bchannel *bch; 19408c2ecf20Sopenharmony_ci struct dchannel *dch; 19418c2ecf20Sopenharmony_ci struct sk_buff **sp = NULL; 19428c2ecf20Sopenharmony_ci int *idxp; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci bch = hc->chan[ch].bch; 19458c2ecf20Sopenharmony_ci dch = hc->chan[ch].dch; 19468c2ecf20Sopenharmony_ci if ((!dch) && (!bch)) 19478c2ecf20Sopenharmony_ci return; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci txpending = &hc->chan[ch].txpending; 19508c2ecf20Sopenharmony_ci slot_tx = hc->chan[ch].slot_tx; 19518c2ecf20Sopenharmony_ci if (dch) { 19528c2ecf20Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &dch->Flags)) 19538c2ecf20Sopenharmony_ci return; 19548c2ecf20Sopenharmony_ci sp = &dch->tx_skb; 19558c2ecf20Sopenharmony_ci idxp = &dch->tx_idx; 19568c2ecf20Sopenharmony_ci } else { 19578c2ecf20Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &bch->Flags)) 19588c2ecf20Sopenharmony_ci return; 19598c2ecf20Sopenharmony_ci sp = &bch->tx_skb; 19608c2ecf20Sopenharmony_ci idxp = &bch->tx_idx; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci if (*sp) 19638c2ecf20Sopenharmony_ci len = (*sp)->len; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci if ((!len) && *txpending != 1) 19668c2ecf20Sopenharmony_ci return; /* no data */ 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 19698c2ecf20Sopenharmony_ci (hc->chan[ch].protocol == ISDN_P_B_RAW) && 19708c2ecf20Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 19718c2ecf20Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) 19728c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); 19738c2ecf20Sopenharmony_ci else 19748c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 19758c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci if (*txpending == 2) { 19788c2ecf20Sopenharmony_ci /* reset fifo */ 19798c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 19808c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 19818c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 19828c2ecf20Sopenharmony_ci *txpending = 1; 19838c2ecf20Sopenharmony_ci } 19848c2ecf20Sopenharmony_cinext_frame: 19858c2ecf20Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 19868c2ecf20Sopenharmony_ci f1 = HFC_inb_nodebug(hc, A_F1); 19878c2ecf20Sopenharmony_ci f2 = HFC_inb_nodebug(hc, A_F2); 19888c2ecf20Sopenharmony_ci while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { 19898c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 19908c2ecf20Sopenharmony_ci printk(KERN_DEBUG 19918c2ecf20Sopenharmony_ci "%s(card %d): reread f2 because %d!=%d\n", 19928c2ecf20Sopenharmony_ci __func__, hc->id + 1, temp, f2); 19938c2ecf20Sopenharmony_ci f2 = temp; /* repeat until F2 is equal */ 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci Fspace = f2 - f1 - 1; 19968c2ecf20Sopenharmony_ci if (Fspace < 0) 19978c2ecf20Sopenharmony_ci Fspace += hc->Flen; 19988c2ecf20Sopenharmony_ci /* 19998c2ecf20Sopenharmony_ci * Old FIFO handling doesn't give us the current Z2 read 20008c2ecf20Sopenharmony_ci * pointer, so we cannot send the next frame before the fifo 20018c2ecf20Sopenharmony_ci * is empty. It makes no difference except for a slightly 20028c2ecf20Sopenharmony_ci * lower performance. 20038c2ecf20Sopenharmony_ci */ 20048c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { 20058c2ecf20Sopenharmony_ci if (f1 != f2) 20068c2ecf20Sopenharmony_ci Fspace = 0; 20078c2ecf20Sopenharmony_ci else 20088c2ecf20Sopenharmony_ci Fspace = 1; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci /* one frame only for ST D-channels, to allow resending */ 20118c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1 && dch) { 20128c2ecf20Sopenharmony_ci if (f1 != f2) 20138c2ecf20Sopenharmony_ci Fspace = 0; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci /* F-counter full condition */ 20168c2ecf20Sopenharmony_ci if (Fspace == 0) 20178c2ecf20Sopenharmony_ci return; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; 20208c2ecf20Sopenharmony_ci z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; 20218c2ecf20Sopenharmony_ci while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { 20228c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 20238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): reread z2 because " 20248c2ecf20Sopenharmony_ci "%d!=%d\n", __func__, hc->id + 1, temp, z2); 20258c2ecf20Sopenharmony_ci z2 = temp; /* repeat unti Z2 is equal */ 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci hc->chan[ch].Zfill = z1 - z2; 20288c2ecf20Sopenharmony_ci if (hc->chan[ch].Zfill < 0) 20298c2ecf20Sopenharmony_ci hc->chan[ch].Zfill += hc->Zlen; 20308c2ecf20Sopenharmony_ci Zspace = z2 - z1; 20318c2ecf20Sopenharmony_ci if (Zspace <= 0) 20328c2ecf20Sopenharmony_ci Zspace += hc->Zlen; 20338c2ecf20Sopenharmony_ci Zspace -= 4; /* keep not too full, so pointers will not overrun */ 20348c2ecf20Sopenharmony_ci /* fill transparent data only to maxinum transparent load (minus 4) */ 20358c2ecf20Sopenharmony_ci if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) 20368c2ecf20Sopenharmony_ci Zspace = Zspace - hc->Zlen + hc->max_trans; 20378c2ecf20Sopenharmony_ci if (Zspace <= 0) /* no space of 4 bytes */ 20388c2ecf20Sopenharmony_ci return; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci /* if no data */ 20418c2ecf20Sopenharmony_ci if (!len) { 20428c2ecf20Sopenharmony_ci if (z1 == z2) { /* empty */ 20438c2ecf20Sopenharmony_ci /* if done with FIFO audio data during PCM connection */ 20448c2ecf20Sopenharmony_ci if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && 20458c2ecf20Sopenharmony_ci *txpending && slot_tx >= 0) { 20468c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 20478c2ecf20Sopenharmony_ci printk(KERN_DEBUG 20488c2ecf20Sopenharmony_ci "%s: reconnecting PCM due to no " 20498c2ecf20Sopenharmony_ci "more FIFO data: channel %d " 20508c2ecf20Sopenharmony_ci "slot_tx %d\n", 20518c2ecf20Sopenharmony_ci __func__, ch, slot_tx); 20528c2ecf20Sopenharmony_ci /* connect slot */ 20538c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 20548c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 20558c2ecf20Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 20568c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt */ 20578c2ecf20Sopenharmony_ci else 20588c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | 20598c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 20608c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); 20618c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 20628c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 20638c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 20648c2ecf20Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 20658c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt */ 20668c2ecf20Sopenharmony_ci else 20678c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | 20688c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 20698c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 20708c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci *txpending = 0; 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci return; /* no data */ 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* "fill fifo if empty" feature */ 20788c2ecf20Sopenharmony_ci if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) 20798c2ecf20Sopenharmony_ci && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { 20808c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FILL) 20818c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: buffer empty, so we have " 20828c2ecf20Sopenharmony_ci "underrun\n", __func__); 20838c2ecf20Sopenharmony_ci /* fill buffer, to prevent future underrun */ 20848c2ecf20Sopenharmony_ci hc->write_fifo(hc, hc->silence_data, poll >> 1); 20858c2ecf20Sopenharmony_ci Zspace -= (poll >> 1); 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* if audio data and connected slot */ 20898c2ecf20Sopenharmony_ci if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) 20908c2ecf20Sopenharmony_ci && slot_tx >= 0) { 20918c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 20928c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: disconnecting PCM due to " 20938c2ecf20Sopenharmony_ci "FIFO data: channel %d slot_tx %d\n", 20948c2ecf20Sopenharmony_ci __func__, ch, slot_tx); 20958c2ecf20Sopenharmony_ci /* disconnect slot */ 20968c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 20978c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 20988c2ecf20Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 20998c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt */ 21008c2ecf20Sopenharmony_ci else 21018c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | 21028c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 21038c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1); 21048c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 21058c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 21068c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 21078c2ecf20Sopenharmony_ci | 0x07 << 2 | V_HDLC_TRP | V_IFF); 21088c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt */ 21098c2ecf20Sopenharmony_ci else 21108c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | 21118c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 21128c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, ch << 1); 21138c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci *txpending = 1; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci /* show activity */ 21188c2ecf20Sopenharmony_ci if (dch) 21198c2ecf20Sopenharmony_ci hc->activity_tx |= 1 << hc->chan[ch].port; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci /* fill fifo to what we have left */ 21228c2ecf20Sopenharmony_ci ii = len; 21238c2ecf20Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) 21248c2ecf20Sopenharmony_ci temp = 1; 21258c2ecf20Sopenharmony_ci else 21268c2ecf20Sopenharmony_ci temp = 0; 21278c2ecf20Sopenharmony_ci i = *idxp; 21288c2ecf20Sopenharmony_ci d = (*sp)->data + i; 21298c2ecf20Sopenharmony_ci if (ii - i > Zspace) 21308c2ecf20Sopenharmony_ci ii = Zspace + i; 21318c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 21328c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " 21338c2ecf20Sopenharmony_ci "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", 21348c2ecf20Sopenharmony_ci __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, 21358c2ecf20Sopenharmony_ci temp ? "HDLC" : "TRANS"); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* Have to prep the audio data */ 21388c2ecf20Sopenharmony_ci hc->write_fifo(hc, d, ii - i); 21398c2ecf20Sopenharmony_ci hc->chan[ch].Zfill += ii - i; 21408c2ecf20Sopenharmony_ci *idxp = ii; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci /* if not all data has been written */ 21438c2ecf20Sopenharmony_ci if (ii != len) { 21448c2ecf20Sopenharmony_ci /* NOTE: fifo is started by the calling function */ 21458c2ecf20Sopenharmony_ci return; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci /* if all data has been written, terminate frame */ 21498c2ecf20Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 21508c2ecf20Sopenharmony_ci /* increment f-counter */ 21518c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); 21528c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci dev_kfree_skb(*sp); 21568c2ecf20Sopenharmony_ci /* check for next frame */ 21578c2ecf20Sopenharmony_ci if (bch && get_next_bframe(bch)) { 21588c2ecf20Sopenharmony_ci len = (*sp)->len; 21598c2ecf20Sopenharmony_ci goto next_frame; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci if (dch && get_next_dframe(dch)) { 21628c2ecf20Sopenharmony_ci len = (*sp)->len; 21638c2ecf20Sopenharmony_ci goto next_frame; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* 21678c2ecf20Sopenharmony_ci * now we have no more data, so in case of transparent, 21688c2ecf20Sopenharmony_ci * we set the last byte in fifo to 'silence' in case we will get 21698c2ecf20Sopenharmony_ci * no more data at all. this prevents sending an undefined value. 21708c2ecf20Sopenharmony_ci */ 21718c2ecf20Sopenharmony_ci if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) 21728c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci/* NOTE: only called if E1 card is in active state */ 21778c2ecf20Sopenharmony_cistatic void 21788c2ecf20Sopenharmony_cihfcmulti_rx(struct hfc_multi *hc, int ch) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci int temp; 21818c2ecf20Sopenharmony_ci int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ 21828c2ecf20Sopenharmony_ci int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ 21838c2ecf20Sopenharmony_ci int again = 0; 21848c2ecf20Sopenharmony_ci struct bchannel *bch; 21858c2ecf20Sopenharmony_ci struct dchannel *dch = NULL; 21868c2ecf20Sopenharmony_ci struct sk_buff *skb, **sp = NULL; 21878c2ecf20Sopenharmony_ci int maxlen; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci bch = hc->chan[ch].bch; 21908c2ecf20Sopenharmony_ci if (bch) { 21918c2ecf20Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &bch->Flags)) 21928c2ecf20Sopenharmony_ci return; 21938c2ecf20Sopenharmony_ci } else if (hc->chan[ch].dch) { 21948c2ecf20Sopenharmony_ci dch = hc->chan[ch].dch; 21958c2ecf20Sopenharmony_ci if (!test_bit(FLG_ACTIVE, &dch->Flags)) 21968c2ecf20Sopenharmony_ci return; 21978c2ecf20Sopenharmony_ci } else { 21988c2ecf20Sopenharmony_ci return; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_cinext_frame: 22018c2ecf20Sopenharmony_ci /* on first AND before getting next valid frame, R_FIFO must be written 22028c2ecf20Sopenharmony_ci to. */ 22038c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 22048c2ecf20Sopenharmony_ci (hc->chan[ch].protocol == ISDN_P_B_RAW) && 22058c2ecf20Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 22068c2ecf20Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) 22078c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1); 22088c2ecf20Sopenharmony_ci else 22098c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1); 22108c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci /* ignore if rx is off BUT change fifo (above) to start pending TX */ 22138c2ecf20Sopenharmony_ci if (hc->chan[ch].rx_off) { 22148c2ecf20Sopenharmony_ci if (bch) 22158c2ecf20Sopenharmony_ci bch->dropcnt += poll; /* not exact but fair enough */ 22168c2ecf20Sopenharmony_ci return; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 22208c2ecf20Sopenharmony_ci f1 = HFC_inb_nodebug(hc, A_F1); 22218c2ecf20Sopenharmony_ci while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { 22228c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 22238c2ecf20Sopenharmony_ci printk(KERN_DEBUG 22248c2ecf20Sopenharmony_ci "%s(card %d): reread f1 because %d!=%d\n", 22258c2ecf20Sopenharmony_ci __func__, hc->id + 1, temp, f1); 22268c2ecf20Sopenharmony_ci f1 = temp; /* repeat until F1 is equal */ 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci f2 = HFC_inb_nodebug(hc, A_F2); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; 22318c2ecf20Sopenharmony_ci while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { 22328c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 22338c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): reread z2 because " 22348c2ecf20Sopenharmony_ci "%d!=%d\n", __func__, hc->id + 1, temp, z2); 22358c2ecf20Sopenharmony_ci z1 = temp; /* repeat until Z1 is equal */ 22368c2ecf20Sopenharmony_ci } 22378c2ecf20Sopenharmony_ci z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; 22388c2ecf20Sopenharmony_ci Zsize = z1 - z2; 22398c2ecf20Sopenharmony_ci if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) 22408c2ecf20Sopenharmony_ci /* complete hdlc frame */ 22418c2ecf20Sopenharmony_ci Zsize++; 22428c2ecf20Sopenharmony_ci if (Zsize < 0) 22438c2ecf20Sopenharmony_ci Zsize += hc->Zlen; 22448c2ecf20Sopenharmony_ci /* if buffer is empty */ 22458c2ecf20Sopenharmony_ci if (Zsize <= 0) 22468c2ecf20Sopenharmony_ci return; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci if (bch) { 22498c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(bch, Zsize); 22508c2ecf20Sopenharmony_ci if (maxlen < 0) { 22518c2ecf20Sopenharmony_ci pr_warn("card%d.B%d: No bufferspace for %d bytes\n", 22528c2ecf20Sopenharmony_ci hc->id + 1, bch->nr, Zsize); 22538c2ecf20Sopenharmony_ci return; 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci sp = &bch->rx_skb; 22568c2ecf20Sopenharmony_ci maxlen = bch->maxlen; 22578c2ecf20Sopenharmony_ci } else { /* Dchannel */ 22588c2ecf20Sopenharmony_ci sp = &dch->rx_skb; 22598c2ecf20Sopenharmony_ci maxlen = dch->maxlen + 3; 22608c2ecf20Sopenharmony_ci if (*sp == NULL) { 22618c2ecf20Sopenharmony_ci *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); 22628c2ecf20Sopenharmony_ci if (*sp == NULL) { 22638c2ecf20Sopenharmony_ci pr_warn("card%d: No mem for dch rx_skb\n", 22648c2ecf20Sopenharmony_ci hc->id + 1); 22658c2ecf20Sopenharmony_ci return; 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci /* show activity */ 22708c2ecf20Sopenharmony_ci if (dch) 22718c2ecf20Sopenharmony_ci hc->activity_rx |= 1 << hc->chan[ch].port; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci /* empty fifo with what we have */ 22748c2ecf20Sopenharmony_ci if (dch || test_bit(FLG_HDLC, &bch->Flags)) { 22758c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 22768c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " 22778c2ecf20Sopenharmony_ci "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " 22788c2ecf20Sopenharmony_ci "got=%d (again %d)\n", __func__, hc->id + 1, ch, 22798c2ecf20Sopenharmony_ci Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", 22808c2ecf20Sopenharmony_ci f1, f2, Zsize + (*sp)->len, again); 22818c2ecf20Sopenharmony_ci /* HDLC */ 22828c2ecf20Sopenharmony_ci if ((Zsize + (*sp)->len) > maxlen) { 22838c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 22848c2ecf20Sopenharmony_ci printk(KERN_DEBUG 22858c2ecf20Sopenharmony_ci "%s(card %d): hdlc-frame too large.\n", 22868c2ecf20Sopenharmony_ci __func__, hc->id + 1); 22878c2ecf20Sopenharmony_ci skb_trim(*sp, 0); 22888c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 22898c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 22908c2ecf20Sopenharmony_ci return; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (f1 != f2) { 22968c2ecf20Sopenharmony_ci /* increment Z2,F2-counter */ 22978c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); 22988c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 22998c2ecf20Sopenharmony_ci /* check size */ 23008c2ecf20Sopenharmony_ci if ((*sp)->len < 4) { 23018c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 23028c2ecf20Sopenharmony_ci printk(KERN_DEBUG 23038c2ecf20Sopenharmony_ci "%s(card %d): Frame below minimum " 23048c2ecf20Sopenharmony_ci "size\n", __func__, hc->id + 1); 23058c2ecf20Sopenharmony_ci skb_trim(*sp, 0); 23068c2ecf20Sopenharmony_ci goto next_frame; 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci /* there is at least one complete frame, check crc */ 23098c2ecf20Sopenharmony_ci if ((*sp)->data[(*sp)->len - 1]) { 23108c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_CRC) 23118c2ecf20Sopenharmony_ci printk(KERN_DEBUG 23128c2ecf20Sopenharmony_ci "%s: CRC-error\n", __func__); 23138c2ecf20Sopenharmony_ci skb_trim(*sp, 0); 23148c2ecf20Sopenharmony_ci goto next_frame; 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci skb_trim(*sp, (*sp)->len - 3); 23178c2ecf20Sopenharmony_ci if ((*sp)->len < MISDN_COPY_SIZE) { 23188c2ecf20Sopenharmony_ci skb = *sp; 23198c2ecf20Sopenharmony_ci *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); 23208c2ecf20Sopenharmony_ci if (*sp) { 23218c2ecf20Sopenharmony_ci skb_put_data(*sp, skb->data, skb->len); 23228c2ecf20Sopenharmony_ci skb_trim(skb, 0); 23238c2ecf20Sopenharmony_ci } else { 23248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: No mem\n", 23258c2ecf20Sopenharmony_ci __func__); 23268c2ecf20Sopenharmony_ci *sp = skb; 23278c2ecf20Sopenharmony_ci skb = NULL; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci } else { 23308c2ecf20Sopenharmony_ci skb = NULL; 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) { 23338c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(card %d):", 23348c2ecf20Sopenharmony_ci __func__, hc->id + 1); 23358c2ecf20Sopenharmony_ci temp = 0; 23368c2ecf20Sopenharmony_ci while (temp < (*sp)->len) 23378c2ecf20Sopenharmony_ci printk(" %02x", (*sp)->data[temp++]); 23388c2ecf20Sopenharmony_ci printk("\n"); 23398c2ecf20Sopenharmony_ci } 23408c2ecf20Sopenharmony_ci if (dch) 23418c2ecf20Sopenharmony_ci recv_Dchannel(dch); 23428c2ecf20Sopenharmony_ci else 23438c2ecf20Sopenharmony_ci recv_Bchannel(bch, MISDN_ID_ANY, false); 23448c2ecf20Sopenharmony_ci *sp = skb; 23458c2ecf20Sopenharmony_ci again++; 23468c2ecf20Sopenharmony_ci goto next_frame; 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci /* there is an incomplete frame */ 23498c2ecf20Sopenharmony_ci } else { 23508c2ecf20Sopenharmony_ci /* transparent */ 23518c2ecf20Sopenharmony_ci hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); 23528c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_FIFO) 23538c2ecf20Sopenharmony_ci printk(KERN_DEBUG 23548c2ecf20Sopenharmony_ci "%s(card %d): fifo(%d) reading %d bytes " 23558c2ecf20Sopenharmony_ci "(z1=%04x, z2=%04x) TRANS\n", 23568c2ecf20Sopenharmony_ci __func__, hc->id + 1, ch, Zsize, z1, z2); 23578c2ecf20Sopenharmony_ci /* only bch is transparent */ 23588c2ecf20Sopenharmony_ci recv_Bchannel(bch, hc->chan[ch].Zfill, false); 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci} 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci/* 23648c2ecf20Sopenharmony_ci * Interrupt handler 23658c2ecf20Sopenharmony_ci */ 23668c2ecf20Sopenharmony_cistatic void 23678c2ecf20Sopenharmony_cisignal_state_up(struct dchannel *dch, int info, char *msg) 23688c2ecf20Sopenharmony_ci{ 23698c2ecf20Sopenharmony_ci struct sk_buff *skb; 23708c2ecf20Sopenharmony_ci int id, data = info; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 23738c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", __func__, msg); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, 23788c2ecf20Sopenharmony_ci GFP_ATOMIC); 23798c2ecf20Sopenharmony_ci if (!skb) 23808c2ecf20Sopenharmony_ci return; 23818c2ecf20Sopenharmony_ci recv_Dchannel_skb(dch, skb); 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cistatic inline void 23858c2ecf20Sopenharmony_cihandle_timer_irq(struct hfc_multi *hc) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci int ch, temp; 23888c2ecf20Sopenharmony_ci struct dchannel *dch; 23898c2ecf20Sopenharmony_ci u_long flags; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* process queued resync jobs */ 23928c2ecf20Sopenharmony_ci if (hc->e1_resync) { 23938c2ecf20Sopenharmony_ci /* lock, so e1_resync gets not changed */ 23948c2ecf20Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 23958c2ecf20Sopenharmony_ci if (hc->e1_resync & 1) { 23968c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 23978c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Enable SYNC_I\n"); 23988c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); 23998c2ecf20Sopenharmony_ci /* disable JATT, if RX_SYNC is set */ 24008c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) 24018c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); 24028c2ecf20Sopenharmony_ci } 24038c2ecf20Sopenharmony_ci if (hc->e1_resync & 2) { 24048c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 24058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Enable jatt PLL\n"); 24068c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci if (hc->e1_resync & 4) { 24098c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_PLXSD) 24108c2ecf20Sopenharmony_ci printk(KERN_DEBUG 24118c2ecf20Sopenharmony_ci "Enable QUARTZ for HFC-E1\n"); 24128c2ecf20Sopenharmony_ci /* set jatt to quartz */ 24138c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC 24148c2ecf20Sopenharmony_ci | V_JATT_OFF); 24158c2ecf20Sopenharmony_ci /* switch to JATT, in case it is not already */ 24168c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci hc->e1_resync = 0; 24198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 24208c2ecf20Sopenharmony_ci } 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) 24238c2ecf20Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 24248c2ecf20Sopenharmony_ci if (hc->created[hc->chan[ch].port]) { 24258c2ecf20Sopenharmony_ci hfcmulti_tx(hc, ch); 24268c2ecf20Sopenharmony_ci /* fifo is started when switching to rx-fifo */ 24278c2ecf20Sopenharmony_ci hfcmulti_rx(hc, ch); 24288c2ecf20Sopenharmony_ci if (hc->chan[ch].dch && 24298c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer > -1) { 24308c2ecf20Sopenharmony_ci dch = hc->chan[ch].dch; 24318c2ecf20Sopenharmony_ci if (!(--hc->chan[ch].nt_timer)) { 24328c2ecf20Sopenharmony_ci schedule_event(dch, 24338c2ecf20Sopenharmony_ci FLG_PHCHANGE); 24348c2ecf20Sopenharmony_ci if (debug & 24358c2ecf20Sopenharmony_ci DEBUG_HFCMULTI_STATE) 24368c2ecf20Sopenharmony_ci printk(KERN_DEBUG 24378c2ecf20Sopenharmony_ci "%s: nt_timer at " 24388c2ecf20Sopenharmony_ci "state %x\n", 24398c2ecf20Sopenharmony_ci __func__, 24408c2ecf20Sopenharmony_ci dch->state); 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { 24468c2ecf20Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 24478c2ecf20Sopenharmony_ci /* LOS */ 24488c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; 24498c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].los = temp; 24508c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { 24518c2ecf20Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].los) 24528c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_LOS_ON, 24538c2ecf20Sopenharmony_ci "LOS detected"); 24548c2ecf20Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].los) 24558c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_LOS_OFF, 24568c2ecf20Sopenharmony_ci "LOS gone"); 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { 24598c2ecf20Sopenharmony_ci /* AIS */ 24608c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; 24618c2ecf20Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].ais) 24628c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_AIS_ON, 24638c2ecf20Sopenharmony_ci "AIS detected"); 24648c2ecf20Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].ais) 24658c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_AIS_OFF, 24668c2ecf20Sopenharmony_ci "AIS gone"); 24678c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].ais = temp; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { 24708c2ecf20Sopenharmony_ci /* SLIP */ 24718c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; 24728c2ecf20Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].slip_rx) 24738c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_SLIP_RX, 24748c2ecf20Sopenharmony_ci " bit SLIP detected RX"); 24758c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].slip_rx = temp; 24768c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; 24778c2ecf20Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].slip_tx) 24788c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_SLIP_TX, 24798c2ecf20Sopenharmony_ci " bit SLIP detected TX"); 24808c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].slip_tx = temp; 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { 24838c2ecf20Sopenharmony_ci /* RDI */ 24848c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; 24858c2ecf20Sopenharmony_ci if (!temp && hc->chan[hc->dnum[0]].rdi) 24868c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_RDI_ON, 24878c2ecf20Sopenharmony_ci "RDI detected"); 24888c2ecf20Sopenharmony_ci if (temp && !hc->chan[hc->dnum[0]].rdi) 24898c2ecf20Sopenharmony_ci signal_state_up(dch, L1_SIGNAL_RDI_OFF, 24908c2ecf20Sopenharmony_ci "RDI gone"); 24918c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].rdi = temp; 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_JATT_DIR); 24948c2ecf20Sopenharmony_ci switch (hc->chan[hc->dnum[0]].sync) { 24958c2ecf20Sopenharmony_ci case 0: 24968c2ecf20Sopenharmony_ci if ((temp & 0x60) == 0x60) { 24978c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 24988c2ecf20Sopenharmony_ci printk(KERN_DEBUG 24998c2ecf20Sopenharmony_ci "%s: (id=%d) E1 now " 25008c2ecf20Sopenharmony_ci "in clock sync\n", 25018c2ecf20Sopenharmony_ci __func__, hc->id); 25028c2ecf20Sopenharmony_ci HFC_outb(hc, R_RX_OFF, 25038c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].jitter | V_RX_INIT); 25048c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX_OFF, 25058c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].jitter | V_RX_INIT); 25068c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 1; 25078c2ecf20Sopenharmony_ci goto check_framesync; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci break; 25108c2ecf20Sopenharmony_ci case 1: 25118c2ecf20Sopenharmony_ci if ((temp & 0x60) != 0x60) { 25128c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 25138c2ecf20Sopenharmony_ci printk(KERN_DEBUG 25148c2ecf20Sopenharmony_ci "%s: (id=%d) E1 " 25158c2ecf20Sopenharmony_ci "lost clock sync\n", 25168c2ecf20Sopenharmony_ci __func__, hc->id); 25178c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 0; 25188c2ecf20Sopenharmony_ci break; 25198c2ecf20Sopenharmony_ci } 25208c2ecf20Sopenharmony_ci check_framesync: 25218c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA); 25228c2ecf20Sopenharmony_ci if (temp == 0x27) { 25238c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 25248c2ecf20Sopenharmony_ci printk(KERN_DEBUG 25258c2ecf20Sopenharmony_ci "%s: (id=%d) E1 " 25268c2ecf20Sopenharmony_ci "now in frame sync\n", 25278c2ecf20Sopenharmony_ci __func__, hc->id); 25288c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 2; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci case 2: 25328c2ecf20Sopenharmony_ci if ((temp & 0x60) != 0x60) { 25338c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 25348c2ecf20Sopenharmony_ci printk(KERN_DEBUG 25358c2ecf20Sopenharmony_ci "%s: (id=%d) E1 lost " 25368c2ecf20Sopenharmony_ci "clock & frame sync\n", 25378c2ecf20Sopenharmony_ci __func__, hc->id); 25388c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 0; 25398c2ecf20Sopenharmony_ci break; 25408c2ecf20Sopenharmony_ci } 25418c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_SYNC_STA); 25428c2ecf20Sopenharmony_ci if (temp != 0x27) { 25438c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_SYNC) 25448c2ecf20Sopenharmony_ci printk(KERN_DEBUG 25458c2ecf20Sopenharmony_ci "%s: (id=%d) E1 " 25468c2ecf20Sopenharmony_ci "lost frame sync\n", 25478c2ecf20Sopenharmony_ci __func__, hc->id); 25488c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].sync = 1; 25498c2ecf20Sopenharmony_ci } 25508c2ecf20Sopenharmony_ci break; 25518c2ecf20Sopenharmony_ci } 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 25558c2ecf20Sopenharmony_ci hfcmulti_watchdog(hc); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci if (hc->leds) 25588c2ecf20Sopenharmony_ci hfcmulti_leds(hc); 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic void 25628c2ecf20Sopenharmony_ciph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) 25638c2ecf20Sopenharmony_ci{ 25648c2ecf20Sopenharmony_ci struct dchannel *dch; 25658c2ecf20Sopenharmony_ci int ch; 25668c2ecf20Sopenharmony_ci int active; 25678c2ecf20Sopenharmony_ci u_char st_status, temp; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci /* state machine */ 25708c2ecf20Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 25718c2ecf20Sopenharmony_ci if (hc->chan[ch].dch) { 25728c2ecf20Sopenharmony_ci dch = hc->chan[ch].dch; 25738c2ecf20Sopenharmony_ci if (r_irq_statech & 1) { 25748c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_ST_SEL, 25758c2ecf20Sopenharmony_ci hc->chan[ch].port); 25768c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 25778c2ecf20Sopenharmony_ci udelay(1); 25788c2ecf20Sopenharmony_ci /* undocumented: status changes during read */ 25798c2ecf20Sopenharmony_ci st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); 25808c2ecf20Sopenharmony_ci while (st_status != (temp = 25818c2ecf20Sopenharmony_ci HFC_inb_nodebug(hc, A_ST_RD_STATE))) { 25828c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 25838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: reread " 25848c2ecf20Sopenharmony_ci "STATE because %d!=%d\n", 25858c2ecf20Sopenharmony_ci __func__, temp, 25868c2ecf20Sopenharmony_ci st_status); 25878c2ecf20Sopenharmony_ci st_status = temp; /* repeat */ 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci /* Speech Design TE-sync indication */ 25918c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && 25928c2ecf20Sopenharmony_ci dch->dev.D.protocol == ISDN_P_TE_S0) { 25938c2ecf20Sopenharmony_ci if (st_status & V_FR_SYNC_ST) 25948c2ecf20Sopenharmony_ci hc->syncronized |= 25958c2ecf20Sopenharmony_ci (1 << hc->chan[ch].port); 25968c2ecf20Sopenharmony_ci else 25978c2ecf20Sopenharmony_ci hc->syncronized &= 25988c2ecf20Sopenharmony_ci ~(1 << hc->chan[ch].port); 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci dch->state = st_status & 0x0f; 26018c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) 26028c2ecf20Sopenharmony_ci active = 3; 26038c2ecf20Sopenharmony_ci else 26048c2ecf20Sopenharmony_ci active = 7; 26058c2ecf20Sopenharmony_ci if (dch->state == active) { 26068c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 26078c2ecf20Sopenharmony_ci (ch << 1) | 1); 26088c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 26098c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, 26108c2ecf20Sopenharmony_ci R_INC_RES_FIFO, V_RES_F); 26118c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 26128c2ecf20Sopenharmony_ci dch->tx_idx = 0; 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci schedule_event(dch, FLG_PHCHANGE); 26158c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 26168c2ecf20Sopenharmony_ci printk(KERN_DEBUG 26178c2ecf20Sopenharmony_ci "%s: S/T newstate %x port %d\n", 26188c2ecf20Sopenharmony_ci __func__, dch->state, 26198c2ecf20Sopenharmony_ci hc->chan[ch].port); 26208c2ecf20Sopenharmony_ci } 26218c2ecf20Sopenharmony_ci r_irq_statech >>= 1; 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 26258c2ecf20Sopenharmony_ci plxsd_checksync(hc, 0); 26268c2ecf20Sopenharmony_ci} 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_cistatic void 26298c2ecf20Sopenharmony_cififo_irq(struct hfc_multi *hc, int block) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci int ch, j; 26328c2ecf20Sopenharmony_ci struct dchannel *dch; 26338c2ecf20Sopenharmony_ci struct bchannel *bch; 26348c2ecf20Sopenharmony_ci u_char r_irq_fifo_bl; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); 26378c2ecf20Sopenharmony_ci j = 0; 26388c2ecf20Sopenharmony_ci while (j < 8) { 26398c2ecf20Sopenharmony_ci ch = (block << 2) + (j >> 1); 26408c2ecf20Sopenharmony_ci dch = hc->chan[ch].dch; 26418c2ecf20Sopenharmony_ci bch = hc->chan[ch].bch; 26428c2ecf20Sopenharmony_ci if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { 26438c2ecf20Sopenharmony_ci j += 2; 26448c2ecf20Sopenharmony_ci continue; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci if (dch && (r_irq_fifo_bl & (1 << j)) && 26478c2ecf20Sopenharmony_ci test_bit(FLG_ACTIVE, &dch->Flags)) { 26488c2ecf20Sopenharmony_ci hfcmulti_tx(hc, ch); 26498c2ecf20Sopenharmony_ci /* start fifo */ 26508c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 26518c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci if (bch && (r_irq_fifo_bl & (1 << j)) && 26548c2ecf20Sopenharmony_ci test_bit(FLG_ACTIVE, &bch->Flags)) { 26558c2ecf20Sopenharmony_ci hfcmulti_tx(hc, ch); 26568c2ecf20Sopenharmony_ci /* start fifo */ 26578c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 26588c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 26598c2ecf20Sopenharmony_ci } 26608c2ecf20Sopenharmony_ci j++; 26618c2ecf20Sopenharmony_ci if (dch && (r_irq_fifo_bl & (1 << j)) && 26628c2ecf20Sopenharmony_ci test_bit(FLG_ACTIVE, &dch->Flags)) { 26638c2ecf20Sopenharmony_ci hfcmulti_rx(hc, ch); 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci if (bch && (r_irq_fifo_bl & (1 << j)) && 26668c2ecf20Sopenharmony_ci test_bit(FLG_ACTIVE, &bch->Flags)) { 26678c2ecf20Sopenharmony_ci hfcmulti_rx(hc, ch); 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci j++; 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci} 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci#ifdef IRQ_DEBUG 26748c2ecf20Sopenharmony_ciint irqsem; 26758c2ecf20Sopenharmony_ci#endif 26768c2ecf20Sopenharmony_cistatic irqreturn_t 26778c2ecf20Sopenharmony_cihfcmulti_interrupt(int intno, void *dev_id) 26788c2ecf20Sopenharmony_ci{ 26798c2ecf20Sopenharmony_ci#ifdef IRQCOUNT_DEBUG 26808c2ecf20Sopenharmony_ci static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, 26818c2ecf20Sopenharmony_ci iq5 = 0, iq6 = 0, iqcnt = 0; 26828c2ecf20Sopenharmony_ci#endif 26838c2ecf20Sopenharmony_ci struct hfc_multi *hc = dev_id; 26848c2ecf20Sopenharmony_ci struct dchannel *dch; 26858c2ecf20Sopenharmony_ci u_char r_irq_statech, status, r_irq_misc, r_irq_oview; 26868c2ecf20Sopenharmony_ci int i; 26878c2ecf20Sopenharmony_ci void __iomem *plx_acc; 26888c2ecf20Sopenharmony_ci u_short wval; 26898c2ecf20Sopenharmony_ci u_char e1_syncsta, temp, temp2; 26908c2ecf20Sopenharmony_ci u_long flags; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci if (!hc) { 26938c2ecf20Sopenharmony_ci printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); 26948c2ecf20Sopenharmony_ci return IRQ_NONE; 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci spin_lock(&hc->lock); 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci#ifdef IRQ_DEBUG 27008c2ecf20Sopenharmony_ci if (irqsem) 27018c2ecf20Sopenharmony_ci printk(KERN_ERR "irq for card %d during irq from " 27028c2ecf20Sopenharmony_ci "card %d, this is no bug.\n", hc->id + 1, irqsem); 27038c2ecf20Sopenharmony_ci irqsem = hc->id + 1; 27048c2ecf20Sopenharmony_ci#endif 27058c2ecf20Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 27068c2ecf20Sopenharmony_ci if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) 27078c2ecf20Sopenharmony_ci goto irq_notforus; 27088c2ecf20Sopenharmony_ci#endif 27098c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 27108c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, flags); 27118c2ecf20Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 27128c2ecf20Sopenharmony_ci wval = readw(plx_acc); 27138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, flags); 27148c2ecf20Sopenharmony_ci if (!(wval & PLX_INTCSR_LINTI1_STATUS)) 27158c2ecf20Sopenharmony_ci goto irq_notforus; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci status = HFC_inb_nodebug(hc, R_STATUS); 27198c2ecf20Sopenharmony_ci r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); 27208c2ecf20Sopenharmony_ci#ifdef IRQCOUNT_DEBUG 27218c2ecf20Sopenharmony_ci if (r_irq_statech) 27228c2ecf20Sopenharmony_ci iq1++; 27238c2ecf20Sopenharmony_ci if (status & V_DTMF_STA) 27248c2ecf20Sopenharmony_ci iq2++; 27258c2ecf20Sopenharmony_ci if (status & V_LOST_STA) 27268c2ecf20Sopenharmony_ci iq3++; 27278c2ecf20Sopenharmony_ci if (status & V_EXT_IRQSTA) 27288c2ecf20Sopenharmony_ci iq4++; 27298c2ecf20Sopenharmony_ci if (status & V_MISC_IRQSTA) 27308c2ecf20Sopenharmony_ci iq5++; 27318c2ecf20Sopenharmony_ci if (status & V_FR_IRQSTA) 27328c2ecf20Sopenharmony_ci iq6++; 27338c2ecf20Sopenharmony_ci if (iqcnt++ > 5000) { 27348c2ecf20Sopenharmony_ci printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", 27358c2ecf20Sopenharmony_ci iq1, iq2, iq3, iq4, iq5, iq6); 27368c2ecf20Sopenharmony_ci iqcnt = 0; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci#endif 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (!r_irq_statech && 27418c2ecf20Sopenharmony_ci !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | 27428c2ecf20Sopenharmony_ci V_MISC_IRQSTA | V_FR_IRQSTA))) { 27438c2ecf20Sopenharmony_ci /* irq is not for us */ 27448c2ecf20Sopenharmony_ci goto irq_notforus; 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci hc->irqcnt++; 27478c2ecf20Sopenharmony_ci if (r_irq_statech) { 27488c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) 27498c2ecf20Sopenharmony_ci ph_state_irq(hc, r_irq_statech); 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci if (status & V_EXT_IRQSTA) 27528c2ecf20Sopenharmony_ci ; /* external IRQ */ 27538c2ecf20Sopenharmony_ci if (status & V_LOST_STA) { 27548c2ecf20Sopenharmony_ci /* LOST IRQ */ 27558c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci if (status & V_MISC_IRQSTA) { 27588c2ecf20Sopenharmony_ci /* misc IRQ */ 27598c2ecf20Sopenharmony_ci r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); 27608c2ecf20Sopenharmony_ci r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ 27618c2ecf20Sopenharmony_ci if (r_irq_misc & V_STA_IRQ) { 27628c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 27638c2ecf20Sopenharmony_ci /* state machine */ 27648c2ecf20Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 27658c2ecf20Sopenharmony_ci e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); 27668c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip) 27678c2ecf20Sopenharmony_ci && hc->e1_getclock) { 27688c2ecf20Sopenharmony_ci if (e1_syncsta & V_FR_SYNC_E1) 27698c2ecf20Sopenharmony_ci hc->syncronized = 1; 27708c2ecf20Sopenharmony_ci else 27718c2ecf20Sopenharmony_ci hc->syncronized = 0; 27728c2ecf20Sopenharmony_ci } 27738c2ecf20Sopenharmony_ci /* undocumented: status changes during read */ 27748c2ecf20Sopenharmony_ci temp = HFC_inb_nodebug(hc, R_E1_RD_STA); 27758c2ecf20Sopenharmony_ci while (temp != (temp2 = 27768c2ecf20Sopenharmony_ci HFC_inb_nodebug(hc, R_E1_RD_STA))) { 27778c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 27788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: reread " 27798c2ecf20Sopenharmony_ci "STATE because %d!=%d\n", 27808c2ecf20Sopenharmony_ci __func__, temp, temp2); 27818c2ecf20Sopenharmony_ci temp = temp2; /* repeat */ 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci /* broadcast state change to all fragments */ 27848c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 27858c2ecf20Sopenharmony_ci printk(KERN_DEBUG 27868c2ecf20Sopenharmony_ci "%s: E1 (id=%d) newstate %x\n", 27878c2ecf20Sopenharmony_ci __func__, hc->id, temp & 0x7); 27888c2ecf20Sopenharmony_ci for (i = 0; i < hc->ports; i++) { 27898c2ecf20Sopenharmony_ci dch = hc->chan[hc->dnum[i]].dch; 27908c2ecf20Sopenharmony_ci dch->state = temp & 0x7; 27918c2ecf20Sopenharmony_ci schedule_event(dch, FLG_PHCHANGE); 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) 27958c2ecf20Sopenharmony_ci plxsd_checksync(hc, 0); 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci if (r_irq_misc & V_TI_IRQ) { 27998c2ecf20Sopenharmony_ci if (hc->iclock_on) 28008c2ecf20Sopenharmony_ci mISDN_clock_update(hc->iclock, poll, NULL); 28018c2ecf20Sopenharmony_ci handle_timer_irq(hc); 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (r_irq_misc & V_DTMF_IRQ) 28058c2ecf20Sopenharmony_ci hfcmulti_dtmf(hc); 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci if (r_irq_misc & V_IRQ_PROC) { 28088c2ecf20Sopenharmony_ci static int irq_proc_cnt; 28098c2ecf20Sopenharmony_ci if (!irq_proc_cnt++) 28108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: got V_IRQ_PROC -" 28118c2ecf20Sopenharmony_ci " this should not happen\n", __func__); 28128c2ecf20Sopenharmony_ci } 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci if (status & V_FR_IRQSTA) { 28168c2ecf20Sopenharmony_ci /* FIFO IRQ */ 28178c2ecf20Sopenharmony_ci r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); 28188c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 28198c2ecf20Sopenharmony_ci if (r_irq_oview & (1 << i)) 28208c2ecf20Sopenharmony_ci fifo_irq(hc, i); 28218c2ecf20Sopenharmony_ci } 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci#ifdef IRQ_DEBUG 28258c2ecf20Sopenharmony_ci irqsem = 0; 28268c2ecf20Sopenharmony_ci#endif 28278c2ecf20Sopenharmony_ci spin_unlock(&hc->lock); 28288c2ecf20Sopenharmony_ci return IRQ_HANDLED; 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ciirq_notforus: 28318c2ecf20Sopenharmony_ci#ifdef IRQ_DEBUG 28328c2ecf20Sopenharmony_ci irqsem = 0; 28338c2ecf20Sopenharmony_ci#endif 28348c2ecf20Sopenharmony_ci spin_unlock(&hc->lock); 28358c2ecf20Sopenharmony_ci return IRQ_NONE; 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci/* 28408c2ecf20Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function 28418c2ecf20Sopenharmony_ci */ 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_cistatic void 28448c2ecf20Sopenharmony_cihfcmulti_dbusy_timer(struct timer_list *t) 28458c2ecf20Sopenharmony_ci{ 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci/* 28508c2ecf20Sopenharmony_ci * activate/deactivate hardware for selected channels and mode 28518c2ecf20Sopenharmony_ci * 28528c2ecf20Sopenharmony_ci * configure B-channel with the given protocol 28538c2ecf20Sopenharmony_ci * ch eqals to the HFC-channel (0-31) 28548c2ecf20Sopenharmony_ci * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 28558c2ecf20Sopenharmony_ci * for S/T, 1-31 for E1) 28568c2ecf20Sopenharmony_ci * the hdlc interrupts will be set/unset 28578c2ecf20Sopenharmony_ci */ 28588c2ecf20Sopenharmony_cistatic int 28598c2ecf20Sopenharmony_cimode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, 28608c2ecf20Sopenharmony_ci int bank_tx, int slot_rx, int bank_rx) 28618c2ecf20Sopenharmony_ci{ 28628c2ecf20Sopenharmony_ci int flow_tx = 0, flow_rx = 0, routing = 0; 28638c2ecf20Sopenharmony_ci int oslot_tx, oslot_rx; 28648c2ecf20Sopenharmony_ci int conf; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci if (ch < 0 || ch > 31) 28678c2ecf20Sopenharmony_ci return -EINVAL; 28688c2ecf20Sopenharmony_ci oslot_tx = hc->chan[ch].slot_tx; 28698c2ecf20Sopenharmony_ci oslot_rx = hc->chan[ch].slot_rx; 28708c2ecf20Sopenharmony_ci conf = hc->chan[ch].conf; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 28738c2ecf20Sopenharmony_ci printk(KERN_DEBUG 28748c2ecf20Sopenharmony_ci "%s: card %d channel %d protocol %x slot old=%d new=%d " 28758c2ecf20Sopenharmony_ci "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", 28768c2ecf20Sopenharmony_ci __func__, hc->id, ch, protocol, oslot_tx, slot_tx, 28778c2ecf20Sopenharmony_ci bank_tx, oslot_rx, slot_rx, bank_rx); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (oslot_tx >= 0 && slot_tx != oslot_tx) { 28808c2ecf20Sopenharmony_ci /* remove from slot */ 28818c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 28828c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", 28838c2ecf20Sopenharmony_ci __func__, oslot_tx); 28848c2ecf20Sopenharmony_ci if (hc->slot_owner[oslot_tx << 1] == ch) { 28858c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, oslot_tx << 1); 28868c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0); 28878c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 28888c2ecf20Sopenharmony_ci HFC_outb(hc, A_CONF, 0); 28898c2ecf20Sopenharmony_ci hc->slot_owner[oslot_tx << 1] = -1; 28908c2ecf20Sopenharmony_ci } else { 28918c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 28928c2ecf20Sopenharmony_ci printk(KERN_DEBUG 28938c2ecf20Sopenharmony_ci "%s: we are not owner of this tx slot " 28948c2ecf20Sopenharmony_ci "anymore, channel %d is.\n", 28958c2ecf20Sopenharmony_ci __func__, hc->slot_owner[oslot_tx << 1]); 28968c2ecf20Sopenharmony_ci } 28978c2ecf20Sopenharmony_ci } 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci if (oslot_rx >= 0 && slot_rx != oslot_rx) { 29008c2ecf20Sopenharmony_ci /* remove from slot */ 29018c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 29028c2ecf20Sopenharmony_ci printk(KERN_DEBUG 29038c2ecf20Sopenharmony_ci "%s: remove from slot %d (RX)\n", 29048c2ecf20Sopenharmony_ci __func__, oslot_rx); 29058c2ecf20Sopenharmony_ci if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { 29068c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); 29078c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0); 29088c2ecf20Sopenharmony_ci hc->slot_owner[(oslot_rx << 1) | 1] = -1; 29098c2ecf20Sopenharmony_ci } else { 29108c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 29118c2ecf20Sopenharmony_ci printk(KERN_DEBUG 29128c2ecf20Sopenharmony_ci "%s: we are not owner of this rx slot " 29138c2ecf20Sopenharmony_ci "anymore, channel %d is.\n", 29148c2ecf20Sopenharmony_ci __func__, 29158c2ecf20Sopenharmony_ci hc->slot_owner[(oslot_rx << 1) | 1]); 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci } 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if (slot_tx < 0) { 29208c2ecf20Sopenharmony_ci flow_tx = 0x80; /* FIFO->ST */ 29218c2ecf20Sopenharmony_ci /* disable pcm slot */ 29228c2ecf20Sopenharmony_ci hc->chan[ch].slot_tx = -1; 29238c2ecf20Sopenharmony_ci hc->chan[ch].bank_tx = 0; 29248c2ecf20Sopenharmony_ci } else { 29258c2ecf20Sopenharmony_ci /* set pcm slot */ 29268c2ecf20Sopenharmony_ci if (hc->chan[ch].txpending) 29278c2ecf20Sopenharmony_ci flow_tx = 0x80; /* FIFO->ST */ 29288c2ecf20Sopenharmony_ci else 29298c2ecf20Sopenharmony_ci flow_tx = 0xc0; /* PCM->ST */ 29308c2ecf20Sopenharmony_ci /* put on slot */ 29318c2ecf20Sopenharmony_ci routing = bank_tx ? 0xc0 : 0x80; 29328c2ecf20Sopenharmony_ci if (conf >= 0 || bank_tx > 1) 29338c2ecf20Sopenharmony_ci routing = 0x40; /* loop */ 29348c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 29358c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: put channel %d to slot %d bank" 29368c2ecf20Sopenharmony_ci " %d flow %02x routing %02x conf %d (TX)\n", 29378c2ecf20Sopenharmony_ci __func__, ch, slot_tx, bank_tx, 29388c2ecf20Sopenharmony_ci flow_tx, routing, conf); 29398c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, slot_tx << 1); 29408c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, (ch << 1) | routing); 29418c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) 29428c2ecf20Sopenharmony_ci HFC_outb(hc, A_CONF, 29438c2ecf20Sopenharmony_ci (conf < 0) ? 0 : (conf | V_CONF_SL)); 29448c2ecf20Sopenharmony_ci hc->slot_owner[slot_tx << 1] = ch; 29458c2ecf20Sopenharmony_ci hc->chan[ch].slot_tx = slot_tx; 29468c2ecf20Sopenharmony_ci hc->chan[ch].bank_tx = bank_tx; 29478c2ecf20Sopenharmony_ci } 29488c2ecf20Sopenharmony_ci if (slot_rx < 0) { 29498c2ecf20Sopenharmony_ci /* disable pcm slot */ 29508c2ecf20Sopenharmony_ci flow_rx = 0x80; /* ST->FIFO */ 29518c2ecf20Sopenharmony_ci hc->chan[ch].slot_rx = -1; 29528c2ecf20Sopenharmony_ci hc->chan[ch].bank_rx = 0; 29538c2ecf20Sopenharmony_ci } else { 29548c2ecf20Sopenharmony_ci /* set pcm slot */ 29558c2ecf20Sopenharmony_ci if (hc->chan[ch].txpending) 29568c2ecf20Sopenharmony_ci flow_rx = 0x80; /* ST->FIFO */ 29578c2ecf20Sopenharmony_ci else 29588c2ecf20Sopenharmony_ci flow_rx = 0xc0; /* ST->(FIFO,PCM) */ 29598c2ecf20Sopenharmony_ci /* put on slot */ 29608c2ecf20Sopenharmony_ci routing = bank_rx ? 0x80 : 0xc0; /* reversed */ 29618c2ecf20Sopenharmony_ci if (conf >= 0 || bank_rx > 1) 29628c2ecf20Sopenharmony_ci routing = 0x40; /* loop */ 29638c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 29648c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: put channel %d to slot %d bank" 29658c2ecf20Sopenharmony_ci " %d flow %02x routing %02x conf %d (RX)\n", 29668c2ecf20Sopenharmony_ci __func__, ch, slot_rx, bank_rx, 29678c2ecf20Sopenharmony_ci flow_rx, routing, conf); 29688c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, (slot_rx << 1) | V_SL_DIR); 29698c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, (ch << 1) | V_CH_DIR | routing); 29708c2ecf20Sopenharmony_ci hc->slot_owner[(slot_rx << 1) | 1] = ch; 29718c2ecf20Sopenharmony_ci hc->chan[ch].slot_rx = slot_rx; 29728c2ecf20Sopenharmony_ci hc->chan[ch].bank_rx = bank_rx; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci switch (protocol) { 29768c2ecf20Sopenharmony_ci case (ISDN_P_NONE): 29778c2ecf20Sopenharmony_ci /* disable TX fifo */ 29788c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 29798c2ecf20Sopenharmony_ci HFC_wait(hc); 29808c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); 29818c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 29828c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 29838c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 29848c2ecf20Sopenharmony_ci HFC_wait(hc); 29858c2ecf20Sopenharmony_ci /* disable RX fifo */ 29868c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 29878c2ecf20Sopenharmony_ci HFC_wait(hc); 29888c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); 29898c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 29908c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 29918c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 29928c2ecf20Sopenharmony_ci HFC_wait(hc); 29938c2ecf20Sopenharmony_ci if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { 29948c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] &= 29958c2ecf20Sopenharmony_ci ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; 29968c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 29978c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 29988c2ecf20Sopenharmony_ci udelay(1); 29998c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 30008c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 30018c2ecf20Sopenharmony_ci } 30028c2ecf20Sopenharmony_ci if (hc->chan[ch].bch) { 30038c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); 30048c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, 30058c2ecf20Sopenharmony_ci &hc->chan[ch].bch->Flags); 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci break; 30088c2ecf20Sopenharmony_ci case (ISDN_P_B_RAW): /* B-channel */ 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip) && 30118c2ecf20Sopenharmony_ci (hc->chan[ch].slot_rx < 0) && 30128c2ecf20Sopenharmony_ci (hc->chan[ch].slot_tx < 0)) { 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci printk(KERN_DEBUG 30158c2ecf20Sopenharmony_ci "Setting B-channel %d to echo cancelable " 30168c2ecf20Sopenharmony_ci "state on PCM slot %d\n", ch, 30178c2ecf20Sopenharmony_ci ((ch / 4) * 8) + ((ch % 4) * 4) + 1); 30188c2ecf20Sopenharmony_ci printk(KERN_DEBUG 30198c2ecf20Sopenharmony_ci "Enabling pass through for channel\n"); 30208c2ecf20Sopenharmony_ci vpm_out(hc, ch, ((ch / 4) * 8) + 30218c2ecf20Sopenharmony_ci ((ch % 4) * 4) + 1, 0x01); 30228c2ecf20Sopenharmony_ci /* rx path */ 30238c2ecf20Sopenharmony_ci /* S/T -> PCM */ 30248c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1)); 30258c2ecf20Sopenharmony_ci HFC_wait(hc); 30268c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); 30278c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + 30288c2ecf20Sopenharmony_ci ((ch % 4) * 4) + 1) << 1); 30298c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci /* PCM -> FIFO */ 30328c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); 30338c2ecf20Sopenharmony_ci HFC_wait(hc); 30348c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); 30358c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 30368c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 30378c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 30388c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 30398c2ecf20Sopenharmony_ci HFC_wait(hc); 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + 30428c2ecf20Sopenharmony_ci ((ch % 4) * 4) + 1) << 1) | 1); 30438c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci /* tx path */ 30468c2ecf20Sopenharmony_ci /* PCM -> S/T */ 30478c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 30488c2ecf20Sopenharmony_ci HFC_wait(hc); 30498c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); 30508c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + 30518c2ecf20Sopenharmony_ci ((ch % 4) * 4)) << 1) | 1); 30528c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* FIFO -> PCM */ 30558c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); 30568c2ecf20Sopenharmony_ci HFC_wait(hc); 30578c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); 30588c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 30598c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 30608c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 30618c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 30628c2ecf20Sopenharmony_ci HFC_wait(hc); 30638c2ecf20Sopenharmony_ci } 30648c2ecf20Sopenharmony_ci /* tx silence */ 30658c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 30668c2ecf20Sopenharmony_ci HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + 30678c2ecf20Sopenharmony_ci ((ch % 4) * 4)) << 1); 30688c2ecf20Sopenharmony_ci HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); 30698c2ecf20Sopenharmony_ci } else { 30708c2ecf20Sopenharmony_ci /* enable TX fifo */ 30718c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 30728c2ecf20Sopenharmony_ci HFC_wait(hc); 30738c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 30748c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | 30758c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 30768c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt */ 30778c2ecf20Sopenharmony_ci else 30788c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | 30798c2ecf20Sopenharmony_ci V_HDLC_TRP | V_IFF); 30808c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 30818c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 30828c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 30838c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 30848c2ecf20Sopenharmony_ci HFC_wait(hc); 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci /* tx silence */ 30878c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); 30888c2ecf20Sopenharmony_ci /* enable RX fifo */ 30898c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 30908c2ecf20Sopenharmony_ci HFC_wait(hc); 30918c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 30928c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | 30938c2ecf20Sopenharmony_ci V_HDLC_TRP); 30948c2ecf20Sopenharmony_ci /* Enable FIFO, no interrupt*/ 30958c2ecf20Sopenharmony_ci else 30968c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | 30978c2ecf20Sopenharmony_ci V_HDLC_TRP); 30988c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 30998c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, 0); 31008c2ecf20Sopenharmony_ci if (hc->chan[ch].protocol != protocol) { 31018c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 31028c2ecf20Sopenharmony_ci HFC_wait(hc); 31038c2ecf20Sopenharmony_ci } 31048c2ecf20Sopenharmony_ci } 31058c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 31068c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] |= 31078c2ecf20Sopenharmony_ci ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; 31088c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 31098c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 31108c2ecf20Sopenharmony_ci udelay(1); 31118c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 31128c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 31138c2ecf20Sopenharmony_ci } 31148c2ecf20Sopenharmony_ci if (hc->chan[ch].bch) 31158c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, 31168c2ecf20Sopenharmony_ci &hc->chan[ch].bch->Flags); 31178c2ecf20Sopenharmony_ci break; 31188c2ecf20Sopenharmony_ci case (ISDN_P_B_HDLC): /* B-channel */ 31198c2ecf20Sopenharmony_ci case (ISDN_P_TE_S0): /* D-channel */ 31208c2ecf20Sopenharmony_ci case (ISDN_P_NT_S0): 31218c2ecf20Sopenharmony_ci case (ISDN_P_TE_E1): 31228c2ecf20Sopenharmony_ci case (ISDN_P_NT_E1): 31238c2ecf20Sopenharmony_ci /* enable TX fifo */ 31248c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, ch << 1); 31258c2ecf20Sopenharmony_ci HFC_wait(hc); 31268c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { 31278c2ecf20Sopenharmony_ci /* E1 or B-channel */ 31288c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); 31298c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); 31308c2ecf20Sopenharmony_ci } else { 31318c2ecf20Sopenharmony_ci /* D-Channel without HDLC fill flags */ 31328c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); 31338c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 2); 31348c2ecf20Sopenharmony_ci } 31358c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, V_IRQ); 31368c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 31378c2ecf20Sopenharmony_ci HFC_wait(hc); 31388c2ecf20Sopenharmony_ci /* enable RX fifo */ 31398c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, (ch << 1) | 1); 31408c2ecf20Sopenharmony_ci HFC_wait(hc); 31418c2ecf20Sopenharmony_ci HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); 31428c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) 31438c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ 31448c2ecf20Sopenharmony_ci else 31458c2ecf20Sopenharmony_ci HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ 31468c2ecf20Sopenharmony_ci HFC_outb(hc, A_IRQ_MSK, V_IRQ); 31478c2ecf20Sopenharmony_ci HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); 31488c2ecf20Sopenharmony_ci HFC_wait(hc); 31498c2ecf20Sopenharmony_ci if (hc->chan[ch].bch) { 31508c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); 31518c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 31528c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port] |= 31538c2ecf20Sopenharmony_ci ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; 31548c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); 31558c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 31568c2ecf20Sopenharmony_ci udelay(1); 31578c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, 31588c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[hc->chan[ch].port]); 31598c2ecf20Sopenharmony_ci } 31608c2ecf20Sopenharmony_ci } 31618c2ecf20Sopenharmony_ci break; 31628c2ecf20Sopenharmony_ci default: 31638c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: protocol not known %x\n", 31648c2ecf20Sopenharmony_ci __func__, protocol); 31658c2ecf20Sopenharmony_ci hc->chan[ch].protocol = ISDN_P_NONE; 31668c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 31678c2ecf20Sopenharmony_ci } 31688c2ecf20Sopenharmony_ci hc->chan[ch].protocol = protocol; 31698c2ecf20Sopenharmony_ci return 0; 31708c2ecf20Sopenharmony_ci} 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci/* 31748c2ecf20Sopenharmony_ci * connect/disconnect PCM 31758c2ecf20Sopenharmony_ci */ 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_cistatic void 31788c2ecf20Sopenharmony_cihfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, 31798c2ecf20Sopenharmony_ci int slot_rx, int bank_rx) 31808c2ecf20Sopenharmony_ci{ 31818c2ecf20Sopenharmony_ci if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { 31828c2ecf20Sopenharmony_ci /* disable PCM */ 31838c2ecf20Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); 31848c2ecf20Sopenharmony_ci return; 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci /* enable pcm */ 31888c2ecf20Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, 31898c2ecf20Sopenharmony_ci slot_rx, bank_rx); 31908c2ecf20Sopenharmony_ci} 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci/* 31938c2ecf20Sopenharmony_ci * set/disable conference 31948c2ecf20Sopenharmony_ci */ 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_cistatic void 31978c2ecf20Sopenharmony_cihfcmulti_conf(struct hfc_multi *hc, int ch, int num) 31988c2ecf20Sopenharmony_ci{ 31998c2ecf20Sopenharmony_ci if (num >= 0 && num <= 7) 32008c2ecf20Sopenharmony_ci hc->chan[ch].conf = num; 32018c2ecf20Sopenharmony_ci else 32028c2ecf20Sopenharmony_ci hc->chan[ch].conf = -1; 32038c2ecf20Sopenharmony_ci mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, 32048c2ecf20Sopenharmony_ci hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, 32058c2ecf20Sopenharmony_ci hc->chan[ch].bank_rx); 32068c2ecf20Sopenharmony_ci} 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci/* 32108c2ecf20Sopenharmony_ci * set/disable sample loop 32118c2ecf20Sopenharmony_ci */ 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci/* NOTE: this function is experimental and therefore disabled */ 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci/* 32168c2ecf20Sopenharmony_ci * Layer 1 callback function 32178c2ecf20Sopenharmony_ci */ 32188c2ecf20Sopenharmony_cistatic int 32198c2ecf20Sopenharmony_cihfcm_l1callback(struct dchannel *dch, u_int cmd) 32208c2ecf20Sopenharmony_ci{ 32218c2ecf20Sopenharmony_ci struct hfc_multi *hc = dch->hw; 32228c2ecf20Sopenharmony_ci struct sk_buff_head free_queue; 32238c2ecf20Sopenharmony_ci u_long flags; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci switch (cmd) { 32268c2ecf20Sopenharmony_ci case INFO3_P8: 32278c2ecf20Sopenharmony_ci case INFO3_P10: 32288c2ecf20Sopenharmony_ci break; 32298c2ecf20Sopenharmony_ci case HW_RESET_REQ: 32308c2ecf20Sopenharmony_ci /* start activation */ 32318c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 32328c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 32338c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 32348c2ecf20Sopenharmony_ci printk(KERN_DEBUG 32358c2ecf20Sopenharmony_ci "%s: HW_RESET_REQ no BRI\n", 32368c2ecf20Sopenharmony_ci __func__); 32378c2ecf20Sopenharmony_ci } else { 32388c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 32398c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 32408c2ecf20Sopenharmony_ci udelay(1); 32418c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ 32428c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 32438c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3); 32448c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT * 3)); 32458c2ecf20Sopenharmony_ci /* activate */ 32468c2ecf20Sopenharmony_ci } 32478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 32488c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_POWERUP_IND); 32498c2ecf20Sopenharmony_ci break; 32508c2ecf20Sopenharmony_ci case HW_DEACT_REQ: 32518c2ecf20Sopenharmony_ci __skb_queue_head_init(&free_queue); 32528c2ecf20Sopenharmony_ci /* start deactivation */ 32538c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 32548c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 32558c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 32568c2ecf20Sopenharmony_ci printk(KERN_DEBUG 32578c2ecf20Sopenharmony_ci "%s: HW_DEACT_REQ no BRI\n", 32588c2ecf20Sopenharmony_ci __func__); 32598c2ecf20Sopenharmony_ci } else { 32608c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 32618c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 32628c2ecf20Sopenharmony_ci udelay(1); 32638c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); 32648c2ecf20Sopenharmony_ci /* deactivate */ 32658c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 32668c2ecf20Sopenharmony_ci hc->syncronized &= 32678c2ecf20Sopenharmony_ci ~(1 << hc->chan[dch->slot].port); 32688c2ecf20Sopenharmony_ci plxsd_checksync(hc, 0); 32698c2ecf20Sopenharmony_ci } 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 32728c2ecf20Sopenharmony_ci if (dch->tx_skb) { 32738c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 32748c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci dch->tx_idx = 0; 32778c2ecf20Sopenharmony_ci if (dch->rx_skb) { 32788c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 32798c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 32808c2ecf20Sopenharmony_ci } 32818c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 32828c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 32838c2ecf20Sopenharmony_ci del_timer(&dch->timer); 32848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 32858c2ecf20Sopenharmony_ci __skb_queue_purge(&free_queue); 32868c2ecf20Sopenharmony_ci break; 32878c2ecf20Sopenharmony_ci case HW_POWERUP_REQ: 32888c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 32898c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 32908c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 32918c2ecf20Sopenharmony_ci printk(KERN_DEBUG 32928c2ecf20Sopenharmony_ci "%s: HW_POWERUP_REQ no BRI\n", 32938c2ecf20Sopenharmony_ci __func__); 32948c2ecf20Sopenharmony_ci } else { 32958c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); 32968c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 32978c2ecf20Sopenharmony_ci udelay(1); 32988c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ 32998c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 33008c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ 33018c2ecf20Sopenharmony_ci } 33028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 33038c2ecf20Sopenharmony_ci break; 33048c2ecf20Sopenharmony_ci case PH_ACTIVATE_IND: 33058c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 33068c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 33078c2ecf20Sopenharmony_ci GFP_ATOMIC); 33088c2ecf20Sopenharmony_ci break; 33098c2ecf20Sopenharmony_ci case PH_DEACTIVATE_IND: 33108c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 33118c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 33128c2ecf20Sopenharmony_ci GFP_ATOMIC); 33138c2ecf20Sopenharmony_ci break; 33148c2ecf20Sopenharmony_ci default: 33158c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 33168c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 33178c2ecf20Sopenharmony_ci __func__, cmd); 33188c2ecf20Sopenharmony_ci return -1; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci return 0; 33218c2ecf20Sopenharmony_ci} 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci/* 33248c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Transfer 33258c2ecf20Sopenharmony_ci */ 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_cistatic int 33288c2ecf20Sopenharmony_cihandle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) 33298c2ecf20Sopenharmony_ci{ 33308c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 33318c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 33328c2ecf20Sopenharmony_ci struct hfc_multi *hc = dch->hw; 33338c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 33348c2ecf20Sopenharmony_ci int ret = -EINVAL; 33358c2ecf20Sopenharmony_ci unsigned int id; 33368c2ecf20Sopenharmony_ci u_long flags; 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci switch (hh->prim) { 33398c2ecf20Sopenharmony_ci case PH_DATA_REQ: 33408c2ecf20Sopenharmony_ci if (skb->len < 1) 33418c2ecf20Sopenharmony_ci break; 33428c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 33438c2ecf20Sopenharmony_ci ret = dchannel_senddata(dch, skb); 33448c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 33458c2ecf20Sopenharmony_ci id = hh->id; /* skb can be freed */ 33468c2ecf20Sopenharmony_ci hfcmulti_tx(hc, dch->slot); 33478c2ecf20Sopenharmony_ci ret = 0; 33488c2ecf20Sopenharmony_ci /* start fifo */ 33498c2ecf20Sopenharmony_ci HFC_outb(hc, R_FIFO, 0); 33508c2ecf20Sopenharmony_ci HFC_wait(hc); 33518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 33528c2ecf20Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 33538c2ecf20Sopenharmony_ci } else 33548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 33558c2ecf20Sopenharmony_ci return ret; 33568c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 33578c2ecf20Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 33588c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 33598c2ecf20Sopenharmony_ci ret = 0; 33608c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 33618c2ecf20Sopenharmony_ci printk(KERN_DEBUG 33628c2ecf20Sopenharmony_ci "%s: PH_ACTIVATE port %d (0..%d)\n", 33638c2ecf20Sopenharmony_ci __func__, hc->chan[dch->slot].port, 33648c2ecf20Sopenharmony_ci hc->ports - 1); 33658c2ecf20Sopenharmony_ci /* start activation */ 33668c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 33678c2ecf20Sopenharmony_ci ph_state_change(dch); 33688c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 33698c2ecf20Sopenharmony_ci printk(KERN_DEBUG 33708c2ecf20Sopenharmony_ci "%s: E1 report state %x \n", 33718c2ecf20Sopenharmony_ci __func__, dch->state); 33728c2ecf20Sopenharmony_ci } else { 33738c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 33748c2ecf20Sopenharmony_ci hc->chan[dch->slot].port); 33758c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 33768c2ecf20Sopenharmony_ci udelay(1); 33778c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); 33788c2ecf20Sopenharmony_ci /* G1 */ 33798c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 33808c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 1); 33818c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 1 | 33828c2ecf20Sopenharmony_ci (V_ST_ACT * 3)); /* activate */ 33838c2ecf20Sopenharmony_ci dch->state = 1; 33848c2ecf20Sopenharmony_ci } 33858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 33868c2ecf20Sopenharmony_ci } else 33878c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 33888c2ecf20Sopenharmony_ci break; 33898c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 33908c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 33918c2ecf20Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 33928c2ecf20Sopenharmony_ci struct sk_buff_head free_queue; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci __skb_queue_head_init(&free_queue); 33958c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 33968c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 33978c2ecf20Sopenharmony_ci printk(KERN_DEBUG 33988c2ecf20Sopenharmony_ci "%s: PH_DEACTIVATE port %d (0..%d)\n", 33998c2ecf20Sopenharmony_ci __func__, hc->chan[dch->slot].port, 34008c2ecf20Sopenharmony_ci hc->ports - 1); 34018c2ecf20Sopenharmony_ci /* start deactivation */ 34028c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 34038c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 34048c2ecf20Sopenharmony_ci printk(KERN_DEBUG 34058c2ecf20Sopenharmony_ci "%s: PH_DEACTIVATE no BRI\n", 34068c2ecf20Sopenharmony_ci __func__); 34078c2ecf20Sopenharmony_ci } else { 34088c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 34098c2ecf20Sopenharmony_ci hc->chan[dch->slot].port); 34108c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 34118c2ecf20Sopenharmony_ci udelay(1); 34128c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); 34138c2ecf20Sopenharmony_ci /* deactivate */ 34148c2ecf20Sopenharmony_ci dch->state = 1; 34158c2ecf20Sopenharmony_ci } 34168c2ecf20Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 34178c2ecf20Sopenharmony_ci if (dch->tx_skb) { 34188c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 34198c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci dch->tx_idx = 0; 34228c2ecf20Sopenharmony_ci if (dch->rx_skb) { 34238c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 34248c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 34258c2ecf20Sopenharmony_ci } 34268c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 34278c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 34288c2ecf20Sopenharmony_ci del_timer(&dch->timer); 34298c2ecf20Sopenharmony_ci#ifdef FIXME 34308c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 34318c2ecf20Sopenharmony_ci dchannel_sched_event(&hc->dch, D_CLEARBUSY); 34328c2ecf20Sopenharmony_ci#endif 34338c2ecf20Sopenharmony_ci ret = 0; 34348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 34358c2ecf20Sopenharmony_ci __skb_queue_purge(&free_queue); 34368c2ecf20Sopenharmony_ci } else 34378c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 34388c2ecf20Sopenharmony_ci break; 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci if (!ret) 34418c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 34428c2ecf20Sopenharmony_ci return ret; 34438c2ecf20Sopenharmony_ci} 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_cistatic void 34468c2ecf20Sopenharmony_cideactivate_bchannel(struct bchannel *bch) 34478c2ecf20Sopenharmony_ci{ 34488c2ecf20Sopenharmony_ci struct hfc_multi *hc = bch->hw; 34498c2ecf20Sopenharmony_ci u_long flags; 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 34528c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 34538c2ecf20Sopenharmony_ci hc->chan[bch->slot].coeff_count = 0; 34548c2ecf20Sopenharmony_ci hc->chan[bch->slot].rx_off = 0; 34558c2ecf20Sopenharmony_ci hc->chan[bch->slot].conf = -1; 34568c2ecf20Sopenharmony_ci mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); 34578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 34588c2ecf20Sopenharmony_ci} 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_cistatic int 34618c2ecf20Sopenharmony_cihandle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) 34628c2ecf20Sopenharmony_ci{ 34638c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 34648c2ecf20Sopenharmony_ci struct hfc_multi *hc = bch->hw; 34658c2ecf20Sopenharmony_ci int ret = -EINVAL; 34668c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 34678c2ecf20Sopenharmony_ci unsigned long flags; 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci switch (hh->prim) { 34708c2ecf20Sopenharmony_ci case PH_DATA_REQ: 34718c2ecf20Sopenharmony_ci if (!skb->len) 34728c2ecf20Sopenharmony_ci break; 34738c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 34748c2ecf20Sopenharmony_ci ret = bchannel_senddata(bch, skb); 34758c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 34768c2ecf20Sopenharmony_ci hfcmulti_tx(hc, bch->slot); 34778c2ecf20Sopenharmony_ci ret = 0; 34788c2ecf20Sopenharmony_ci /* start fifo */ 34798c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 0); 34808c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 34818c2ecf20Sopenharmony_ci } 34828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 34838c2ecf20Sopenharmony_ci return ret; 34848c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 34858c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 34868c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", 34878c2ecf20Sopenharmony_ci __func__, bch->slot); 34888c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 34898c2ecf20Sopenharmony_ci /* activate B-channel if not already activated */ 34908c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { 34918c2ecf20Sopenharmony_ci hc->chan[bch->slot].txpending = 0; 34928c2ecf20Sopenharmony_ci ret = mode_hfcmulti(hc, bch->slot, 34938c2ecf20Sopenharmony_ci ch->protocol, 34948c2ecf20Sopenharmony_ci hc->chan[bch->slot].slot_tx, 34958c2ecf20Sopenharmony_ci hc->chan[bch->slot].bank_tx, 34968c2ecf20Sopenharmony_ci hc->chan[bch->slot].slot_rx, 34978c2ecf20Sopenharmony_ci hc->chan[bch->slot].bank_rx); 34988c2ecf20Sopenharmony_ci if (!ret) { 34998c2ecf20Sopenharmony_ci if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf 35008c2ecf20Sopenharmony_ci && test_bit(HFC_CHIP_DTMF, &hc->chip)) { 35018c2ecf20Sopenharmony_ci /* start decoder */ 35028c2ecf20Sopenharmony_ci hc->dtmf = 1; 35038c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_DTMF) 35048c2ecf20Sopenharmony_ci printk(KERN_DEBUG 35058c2ecf20Sopenharmony_ci "%s: start dtmf decoder\n", 35068c2ecf20Sopenharmony_ci __func__); 35078c2ecf20Sopenharmony_ci HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | 35088c2ecf20Sopenharmony_ci V_RST_DTMF); 35098c2ecf20Sopenharmony_ci } 35108c2ecf20Sopenharmony_ci } 35118c2ecf20Sopenharmony_ci } else 35128c2ecf20Sopenharmony_ci ret = 0; 35138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 35148c2ecf20Sopenharmony_ci if (!ret) 35158c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, 35168c2ecf20Sopenharmony_ci GFP_KERNEL); 35178c2ecf20Sopenharmony_ci break; 35188c2ecf20Sopenharmony_ci case PH_CONTROL_REQ: 35198c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 35208c2ecf20Sopenharmony_ci switch (hh->id) { 35218c2ecf20Sopenharmony_ci case HFC_SPL_LOOP_ON: /* set sample loop */ 35228c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 35238c2ecf20Sopenharmony_ci printk(KERN_DEBUG 35248c2ecf20Sopenharmony_ci "%s: HFC_SPL_LOOP_ON (len = %d)\n", 35258c2ecf20Sopenharmony_ci __func__, skb->len); 35268c2ecf20Sopenharmony_ci ret = 0; 35278c2ecf20Sopenharmony_ci break; 35288c2ecf20Sopenharmony_ci case HFC_SPL_LOOP_OFF: /* set silence */ 35298c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 35308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", 35318c2ecf20Sopenharmony_ci __func__); 35328c2ecf20Sopenharmony_ci ret = 0; 35338c2ecf20Sopenharmony_ci break; 35348c2ecf20Sopenharmony_ci default: 35358c2ecf20Sopenharmony_ci printk(KERN_ERR 35368c2ecf20Sopenharmony_ci "%s: unknown PH_CONTROL_REQ info %x\n", 35378c2ecf20Sopenharmony_ci __func__, hh->id); 35388c2ecf20Sopenharmony_ci ret = -EINVAL; 35398c2ecf20Sopenharmony_ci } 35408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 35418c2ecf20Sopenharmony_ci break; 35428c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 35438c2ecf20Sopenharmony_ci deactivate_bchannel(bch); /* locked there */ 35448c2ecf20Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, 35458c2ecf20Sopenharmony_ci GFP_KERNEL); 35468c2ecf20Sopenharmony_ci ret = 0; 35478c2ecf20Sopenharmony_ci break; 35488c2ecf20Sopenharmony_ci } 35498c2ecf20Sopenharmony_ci if (!ret) 35508c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 35518c2ecf20Sopenharmony_ci return ret; 35528c2ecf20Sopenharmony_ci} 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci/* 35558c2ecf20Sopenharmony_ci * bchannel control function 35568c2ecf20Sopenharmony_ci */ 35578c2ecf20Sopenharmony_cistatic int 35588c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 35598c2ecf20Sopenharmony_ci{ 35608c2ecf20Sopenharmony_ci int ret = 0; 35618c2ecf20Sopenharmony_ci struct dsp_features *features = 35628c2ecf20Sopenharmony_ci (struct dsp_features *)(*((u_long *)&cq->p1)); 35638c2ecf20Sopenharmony_ci struct hfc_multi *hc = bch->hw; 35648c2ecf20Sopenharmony_ci int slot_tx; 35658c2ecf20Sopenharmony_ci int bank_tx; 35668c2ecf20Sopenharmony_ci int slot_rx; 35678c2ecf20Sopenharmony_ci int bank_rx; 35688c2ecf20Sopenharmony_ci int num; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci switch (cq->op) { 35718c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 35728c2ecf20Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 35738c2ecf20Sopenharmony_ci cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; 35748c2ecf20Sopenharmony_ci break; 35758c2ecf20Sopenharmony_ci case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ 35768c2ecf20Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 35778c2ecf20Sopenharmony_ci hc->chan[bch->slot].rx_off = !!cq->p1; 35788c2ecf20Sopenharmony_ci if (!hc->chan[bch->slot].rx_off) { 35798c2ecf20Sopenharmony_ci /* reset fifo on rx on */ 35808c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); 35818c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 35828c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); 35838c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 35868c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", 35878c2ecf20Sopenharmony_ci __func__, bch->nr, hc->chan[bch->slot].rx_off); 35888c2ecf20Sopenharmony_ci break; 35898c2ecf20Sopenharmony_ci case MISDN_CTRL_FILL_EMPTY: 35908c2ecf20Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 35918c2ecf20Sopenharmony_ci hc->silence = bch->fill[0]; 35928c2ecf20Sopenharmony_ci memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); 35938c2ecf20Sopenharmony_ci break; 35948c2ecf20Sopenharmony_ci case MISDN_CTRL_HW_FEATURES: /* fill features structure */ 35958c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 35968c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HW_FEATURE request\n", 35978c2ecf20Sopenharmony_ci __func__); 35988c2ecf20Sopenharmony_ci /* create confirm */ 35998c2ecf20Sopenharmony_ci features->hfc_id = hc->id; 36008c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_DTMF, &hc->chip)) 36018c2ecf20Sopenharmony_ci features->hfc_dtmf = 1; 36028c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_CONF, &hc->chip)) 36038c2ecf20Sopenharmony_ci features->hfc_conf = 1; 36048c2ecf20Sopenharmony_ci features->hfc_loops = 0; 36058c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) { 36068c2ecf20Sopenharmony_ci features->hfc_echocanhw = 1; 36078c2ecf20Sopenharmony_ci } else { 36088c2ecf20Sopenharmony_ci features->pcm_id = hc->pcm; 36098c2ecf20Sopenharmony_ci features->pcm_slots = hc->slots; 36108c2ecf20Sopenharmony_ci features->pcm_banks = 2; 36118c2ecf20Sopenharmony_ci } 36128c2ecf20Sopenharmony_ci break; 36138c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ 36148c2ecf20Sopenharmony_ci slot_tx = cq->p1 & 0xff; 36158c2ecf20Sopenharmony_ci bank_tx = cq->p1 >> 8; 36168c2ecf20Sopenharmony_ci slot_rx = cq->p2 & 0xff; 36178c2ecf20Sopenharmony_ci bank_rx = cq->p2 >> 8; 36188c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36198c2ecf20Sopenharmony_ci printk(KERN_DEBUG 36208c2ecf20Sopenharmony_ci "%s: HFC_PCM_CONN slot %d bank %d (TX) " 36218c2ecf20Sopenharmony_ci "slot %d bank %d (RX)\n", 36228c2ecf20Sopenharmony_ci __func__, slot_tx, bank_tx, 36238c2ecf20Sopenharmony_ci slot_rx, bank_rx); 36248c2ecf20Sopenharmony_ci if (slot_tx < hc->slots && bank_tx <= 2 && 36258c2ecf20Sopenharmony_ci slot_rx < hc->slots && bank_rx <= 2) 36268c2ecf20Sopenharmony_ci hfcmulti_pcm(hc, bch->slot, 36278c2ecf20Sopenharmony_ci slot_tx, bank_tx, slot_rx, bank_rx); 36288c2ecf20Sopenharmony_ci else { 36298c2ecf20Sopenharmony_ci printk(KERN_WARNING 36308c2ecf20Sopenharmony_ci "%s: HFC_PCM_CONN slot %d bank %d (TX) " 36318c2ecf20Sopenharmony_ci "slot %d bank %d (RX) out of range\n", 36328c2ecf20Sopenharmony_ci __func__, slot_tx, bank_tx, 36338c2ecf20Sopenharmony_ci slot_rx, bank_rx); 36348c2ecf20Sopenharmony_ci ret = -EINVAL; 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci break; 36378c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ 36388c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36398c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", 36408c2ecf20Sopenharmony_ci __func__); 36418c2ecf20Sopenharmony_ci hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); 36428c2ecf20Sopenharmony_ci break; 36438c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ 36448c2ecf20Sopenharmony_ci num = cq->p1 & 0xff; 36458c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36468c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", 36478c2ecf20Sopenharmony_ci __func__, num); 36488c2ecf20Sopenharmony_ci if (num <= 7) 36498c2ecf20Sopenharmony_ci hfcmulti_conf(hc, bch->slot, num); 36508c2ecf20Sopenharmony_ci else { 36518c2ecf20Sopenharmony_ci printk(KERN_WARNING 36528c2ecf20Sopenharmony_ci "%s: HW_CONF_JOIN conf %d out of range\n", 36538c2ecf20Sopenharmony_ci __func__, num); 36548c2ecf20Sopenharmony_ci ret = -EINVAL; 36558c2ecf20Sopenharmony_ci } 36568c2ecf20Sopenharmony_ci break; 36578c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ 36588c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36598c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); 36608c2ecf20Sopenharmony_ci hfcmulti_conf(hc, bch->slot, -1); 36618c2ecf20Sopenharmony_ci break; 36628c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_ECHOCAN_ON: 36638c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36648c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); 36658c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 36668c2ecf20Sopenharmony_ci vpm_echocan_on(hc, bch->slot, cq->p1); 36678c2ecf20Sopenharmony_ci else 36688c2ecf20Sopenharmony_ci ret = -EINVAL; 36698c2ecf20Sopenharmony_ci break; 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_ECHOCAN_OFF: 36728c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 36738c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", 36748c2ecf20Sopenharmony_ci __func__); 36758c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 36768c2ecf20Sopenharmony_ci vpm_echocan_off(hc, bch->slot); 36778c2ecf20Sopenharmony_ci else 36788c2ecf20Sopenharmony_ci ret = -EINVAL; 36798c2ecf20Sopenharmony_ci break; 36808c2ecf20Sopenharmony_ci default: 36818c2ecf20Sopenharmony_ci ret = mISDN_ctrl_bchannel(bch, cq); 36828c2ecf20Sopenharmony_ci break; 36838c2ecf20Sopenharmony_ci } 36848c2ecf20Sopenharmony_ci return ret; 36858c2ecf20Sopenharmony_ci} 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_cistatic int 36888c2ecf20Sopenharmony_cihfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 36898c2ecf20Sopenharmony_ci{ 36908c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 36918c2ecf20Sopenharmony_ci struct hfc_multi *hc = bch->hw; 36928c2ecf20Sopenharmony_ci int err = -EINVAL; 36938c2ecf20Sopenharmony_ci u_long flags; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW) 36968c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 36978c2ecf20Sopenharmony_ci __func__, cmd, arg); 36988c2ecf20Sopenharmony_ci switch (cmd) { 36998c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 37008c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 37018c2ecf20Sopenharmony_ci deactivate_bchannel(bch); /* locked there */ 37028c2ecf20Sopenharmony_ci ch->protocol = ISDN_P_NONE; 37038c2ecf20Sopenharmony_ci ch->peer = NULL; 37048c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 37058c2ecf20Sopenharmony_ci err = 0; 37068c2ecf20Sopenharmony_ci break; 37078c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 37088c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 37098c2ecf20Sopenharmony_ci err = channel_bctrl(bch, arg); 37108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 37118c2ecf20Sopenharmony_ci break; 37128c2ecf20Sopenharmony_ci default: 37138c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unknown prim(%x)\n", 37148c2ecf20Sopenharmony_ci __func__, cmd); 37158c2ecf20Sopenharmony_ci } 37168c2ecf20Sopenharmony_ci return err; 37178c2ecf20Sopenharmony_ci} 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci/* 37208c2ecf20Sopenharmony_ci * handle D-channel events 37218c2ecf20Sopenharmony_ci * 37228c2ecf20Sopenharmony_ci * handle state change event 37238c2ecf20Sopenharmony_ci */ 37248c2ecf20Sopenharmony_cistatic void 37258c2ecf20Sopenharmony_ciph_state_change(struct dchannel *dch) 37268c2ecf20Sopenharmony_ci{ 37278c2ecf20Sopenharmony_ci struct hfc_multi *hc; 37288c2ecf20Sopenharmony_ci int ch, i; 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci if (!dch) { 37318c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); 37328c2ecf20Sopenharmony_ci return; 37338c2ecf20Sopenharmony_ci } 37348c2ecf20Sopenharmony_ci hc = dch->hw; 37358c2ecf20Sopenharmony_ci ch = dch->slot; 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 37388c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_E1) { 37398c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 37408c2ecf20Sopenharmony_ci printk(KERN_DEBUG 37418c2ecf20Sopenharmony_ci "%s: E1 TE (id=%d) newstate %x\n", 37428c2ecf20Sopenharmony_ci __func__, hc->id, dch->state); 37438c2ecf20Sopenharmony_ci } else { 37448c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 37458c2ecf20Sopenharmony_ci printk(KERN_DEBUG 37468c2ecf20Sopenharmony_ci "%s: E1 NT (id=%d) newstate %x\n", 37478c2ecf20Sopenharmony_ci __func__, hc->id, dch->state); 37488c2ecf20Sopenharmony_ci } 37498c2ecf20Sopenharmony_ci switch (dch->state) { 37508c2ecf20Sopenharmony_ci case (1): 37518c2ecf20Sopenharmony_ci if (hc->e1_state != 1) { 37528c2ecf20Sopenharmony_ci for (i = 1; i <= 31; i++) { 37538c2ecf20Sopenharmony_ci /* reset fifos on e1 activation */ 37548c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_FIFO, 37558c2ecf20Sopenharmony_ci (i << 1) | 1); 37568c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 37578c2ecf20Sopenharmony_ci HFC_outb_nodebug(hc, R_INC_RES_FIFO, 37588c2ecf20Sopenharmony_ci V_RES_F); 37598c2ecf20Sopenharmony_ci HFC_wait_nodebug(hc); 37608c2ecf20Sopenharmony_ci } 37618c2ecf20Sopenharmony_ci } 37628c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 37638c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 37648c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 37658c2ecf20Sopenharmony_ci break; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci default: 37688c2ecf20Sopenharmony_ci if (hc->e1_state != 1) 37698c2ecf20Sopenharmony_ci return; 37708c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 37718c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 37728c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 37738c2ecf20Sopenharmony_ci } 37748c2ecf20Sopenharmony_ci hc->e1_state = dch->state; 37758c2ecf20Sopenharmony_ci } else { 37768c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_S0) { 37778c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 37788c2ecf20Sopenharmony_ci printk(KERN_DEBUG 37798c2ecf20Sopenharmony_ci "%s: S/T TE newstate %x\n", 37808c2ecf20Sopenharmony_ci __func__, dch->state); 37818c2ecf20Sopenharmony_ci switch (dch->state) { 37828c2ecf20Sopenharmony_ci case (0): 37838c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 37848c2ecf20Sopenharmony_ci break; 37858c2ecf20Sopenharmony_ci case (3): 37868c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 37878c2ecf20Sopenharmony_ci break; 37888c2ecf20Sopenharmony_ci case (5): 37898c2ecf20Sopenharmony_ci case (8): 37908c2ecf20Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 37918c2ecf20Sopenharmony_ci break; 37928c2ecf20Sopenharmony_ci case (6): 37938c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO2); 37948c2ecf20Sopenharmony_ci break; 37958c2ecf20Sopenharmony_ci case (7): 37968c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 37978c2ecf20Sopenharmony_ci break; 37988c2ecf20Sopenharmony_ci } 37998c2ecf20Sopenharmony_ci } else { 38008c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_STATE) 38018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: S/T NT newstate %x\n", 38028c2ecf20Sopenharmony_ci __func__, dch->state); 38038c2ecf20Sopenharmony_ci switch (dch->state) { 38048c2ecf20Sopenharmony_ci case (2): 38058c2ecf20Sopenharmony_ci if (hc->chan[ch].nt_timer == 0) { 38068c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer = -1; 38078c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 38088c2ecf20Sopenharmony_ci hc->chan[ch].port); 38098c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 38108c2ecf20Sopenharmony_ci udelay(1); 38118c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 4 | 38128c2ecf20Sopenharmony_ci V_ST_LD_STA); /* G4 */ 38138c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 38148c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 4); 38158c2ecf20Sopenharmony_ci dch->state = 4; 38168c2ecf20Sopenharmony_ci } else { 38178c2ecf20Sopenharmony_ci /* one extra count for the next event */ 38188c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer = 38198c2ecf20Sopenharmony_ci nt_t1_count[poll_timer] + 1; 38208c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, 38218c2ecf20Sopenharmony_ci hc->chan[ch].port); 38228c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 38238c2ecf20Sopenharmony_ci udelay(1); 38248c2ecf20Sopenharmony_ci /* allow G2 -> G3 transition */ 38258c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, 2 | 38268c2ecf20Sopenharmony_ci V_SET_G2_G3); 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci break; 38298c2ecf20Sopenharmony_ci case (1): 38308c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer = -1; 38318c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 38328c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, 38338c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 38348c2ecf20Sopenharmony_ci break; 38358c2ecf20Sopenharmony_ci case (4): 38368c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer = -1; 38378c2ecf20Sopenharmony_ci break; 38388c2ecf20Sopenharmony_ci case (3): 38398c2ecf20Sopenharmony_ci hc->chan[ch].nt_timer = -1; 38408c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 38418c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 38428c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 38438c2ecf20Sopenharmony_ci break; 38448c2ecf20Sopenharmony_ci } 38458c2ecf20Sopenharmony_ci } 38468c2ecf20Sopenharmony_ci } 38478c2ecf20Sopenharmony_ci} 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci/* 38508c2ecf20Sopenharmony_ci * called for card mode init message 38518c2ecf20Sopenharmony_ci */ 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_cistatic void 38548c2ecf20Sopenharmony_cihfcmulti_initmode(struct dchannel *dch) 38558c2ecf20Sopenharmony_ci{ 38568c2ecf20Sopenharmony_ci struct hfc_multi *hc = dch->hw; 38578c2ecf20Sopenharmony_ci u_char a_st_wr_state, r_e1_wr_sta; 38588c2ecf20Sopenharmony_ci int i, pt; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 38618c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci i = dch->slot; 38648c2ecf20Sopenharmony_ci pt = hc->chan[i].port; 38658c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 38668c2ecf20Sopenharmony_ci /* E1 */ 38678c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].slot_tx = -1; 38688c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].slot_rx = -1; 38698c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].conf = -1; 38708c2ecf20Sopenharmony_ci if (hc->dnum[pt]) { 38718c2ecf20Sopenharmony_ci mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol, 38728c2ecf20Sopenharmony_ci -1, 0, -1, 0); 38738c2ecf20Sopenharmony_ci timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); 38748c2ecf20Sopenharmony_ci } 38758c2ecf20Sopenharmony_ci for (i = 1; i <= 31; i++) { 38768c2ecf20Sopenharmony_ci if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ 38778c2ecf20Sopenharmony_ci continue; 38788c2ecf20Sopenharmony_ci hc->chan[i].slot_tx = -1; 38798c2ecf20Sopenharmony_ci hc->chan[i].slot_rx = -1; 38808c2ecf20Sopenharmony_ci hc->chan[i].conf = -1; 38818c2ecf20Sopenharmony_ci mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); 38828c2ecf20Sopenharmony_ci } 38838c2ecf20Sopenharmony_ci } 38848c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && pt == 0) { 38858c2ecf20Sopenharmony_ci /* E1, port 0 */ 38868c2ecf20Sopenharmony_ci dch = hc->chan[hc->dnum[0]].dch; 38878c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { 38888c2ecf20Sopenharmony_ci HFC_outb(hc, R_LOS0, 255); /* 2 ms */ 38898c2ecf20Sopenharmony_ci HFC_outb(hc, R_LOS1, 255); /* 512 ms */ 38908c2ecf20Sopenharmony_ci } 38918c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) { 38928c2ecf20Sopenharmony_ci HFC_outb(hc, R_RX0, 0); 38938c2ecf20Sopenharmony_ci hc->hw.r_tx0 = 0 | V_OUT_EN; 38948c2ecf20Sopenharmony_ci } else { 38958c2ecf20Sopenharmony_ci HFC_outb(hc, R_RX0, 1); 38968c2ecf20Sopenharmony_ci hc->hw.r_tx0 = 1 | V_OUT_EN; 38978c2ecf20Sopenharmony_ci } 38988c2ecf20Sopenharmony_ci hc->hw.r_tx1 = V_ATX | V_NTRI; 38998c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX0, hc->hw.r_tx0); 39008c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX1, hc->hw.r_tx1); 39018c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX_FR0, 0x00); 39028c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX_FR1, 0xf8); 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) 39058c2ecf20Sopenharmony_ci HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) 39108c2ecf20Sopenharmony_ci HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_E1) { 39138c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39148c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is NT-mode\n", 39158c2ecf20Sopenharmony_ci __func__); 39168c2ecf20Sopenharmony_ci r_e1_wr_sta = 0; /* G0 */ 39178c2ecf20Sopenharmony_ci hc->e1_getclock = 0; 39188c2ecf20Sopenharmony_ci } else { 39198c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is TE-mode\n", 39218c2ecf20Sopenharmony_ci __func__); 39228c2ecf20Sopenharmony_ci r_e1_wr_sta = 0; /* F0 */ 39238c2ecf20Sopenharmony_ci hc->e1_getclock = 1; 39248c2ecf20Sopenharmony_ci } 39258c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) 39268c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); 39278c2ecf20Sopenharmony_ci else 39288c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 39298c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) 39308c2ecf20Sopenharmony_ci hc->e1_getclock = 1; 39318c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) 39328c2ecf20Sopenharmony_ci hc->e1_getclock = 0; 39338c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 39348c2ecf20Sopenharmony_ci /* SLAVE (clock master) */ 39358c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39368c2ecf20Sopenharmony_ci printk(KERN_DEBUG 39378c2ecf20Sopenharmony_ci "%s: E1 port is clock master " 39388c2ecf20Sopenharmony_ci "(clock from PCM)\n", __func__); 39398c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); 39408c2ecf20Sopenharmony_ci } else { 39418c2ecf20Sopenharmony_ci if (hc->e1_getclock) { 39428c2ecf20Sopenharmony_ci /* MASTER (clock slave) */ 39438c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39448c2ecf20Sopenharmony_ci printk(KERN_DEBUG 39458c2ecf20Sopenharmony_ci "%s: E1 port is clock slave " 39468c2ecf20Sopenharmony_ci "(clock to PCM)\n", __func__); 39478c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); 39488c2ecf20Sopenharmony_ci } else { 39498c2ecf20Sopenharmony_ci /* MASTER (clock master) */ 39508c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39518c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: E1 port is " 39528c2ecf20Sopenharmony_ci "clock master " 39538c2ecf20Sopenharmony_ci "(clock from QUARTZ)\n", 39548c2ecf20Sopenharmony_ci __func__); 39558c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | 39568c2ecf20Sopenharmony_ci V_PCM_SYNC | V_JATT_OFF); 39578c2ecf20Sopenharmony_ci HFC_outb(hc, R_SYNC_OUT, 0); 39588c2ecf20Sopenharmony_ci } 39598c2ecf20Sopenharmony_ci } 39608c2ecf20Sopenharmony_ci HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ 39618c2ecf20Sopenharmony_ci HFC_outb(hc, R_PWM_MD, V_PWM0_MD); 39628c2ecf20Sopenharmony_ci HFC_outb(hc, R_PWM0, 0x50); 39638c2ecf20Sopenharmony_ci HFC_outb(hc, R_PWM1, 0xff); 39648c2ecf20Sopenharmony_ci /* state machine setup */ 39658c2ecf20Sopenharmony_ci HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); 39668c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 39678c2ecf20Sopenharmony_ci HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); 39688c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 39698c2ecf20Sopenharmony_ci hc->syncronized = 0; 39708c2ecf20Sopenharmony_ci plxsd_checksync(hc, 0); 39718c2ecf20Sopenharmony_ci } 39728c2ecf20Sopenharmony_ci } 39738c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 39748c2ecf20Sopenharmony_ci /* ST */ 39758c2ecf20Sopenharmony_ci hc->chan[i].slot_tx = -1; 39768c2ecf20Sopenharmony_ci hc->chan[i].slot_rx = -1; 39778c2ecf20Sopenharmony_ci hc->chan[i].conf = -1; 39788c2ecf20Sopenharmony_ci mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); 39798c2ecf20Sopenharmony_ci timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0); 39808c2ecf20Sopenharmony_ci hc->chan[i - 2].slot_tx = -1; 39818c2ecf20Sopenharmony_ci hc->chan[i - 2].slot_rx = -1; 39828c2ecf20Sopenharmony_ci hc->chan[i - 2].conf = -1; 39838c2ecf20Sopenharmony_ci mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); 39848c2ecf20Sopenharmony_ci hc->chan[i - 1].slot_tx = -1; 39858c2ecf20Sopenharmony_ci hc->chan[i - 1].slot_rx = -1; 39868c2ecf20Sopenharmony_ci hc->chan[i - 1].conf = -1; 39878c2ecf20Sopenharmony_ci mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); 39888c2ecf20Sopenharmony_ci /* select interface */ 39898c2ecf20Sopenharmony_ci HFC_outb(hc, R_ST_SEL, pt); 39908c2ecf20Sopenharmony_ci /* undocumented: delay after R_ST_SEL */ 39918c2ecf20Sopenharmony_ci udelay(1); 39928c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_NT_S0) { 39938c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 39948c2ecf20Sopenharmony_ci printk(KERN_DEBUG 39958c2ecf20Sopenharmony_ci "%s: ST port %d is NT-mode\n", 39968c2ecf20Sopenharmony_ci __func__, pt); 39978c2ecf20Sopenharmony_ci /* clock delay */ 39988c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); 39998c2ecf20Sopenharmony_ci a_st_wr_state = 1; /* G1 */ 40008c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[pt] = V_ST_MD; 40018c2ecf20Sopenharmony_ci } else { 40028c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 40038c2ecf20Sopenharmony_ci printk(KERN_DEBUG 40048c2ecf20Sopenharmony_ci "%s: ST port %d is TE-mode\n", 40058c2ecf20Sopenharmony_ci __func__, pt); 40068c2ecf20Sopenharmony_ci /* clock delay */ 40078c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); 40088c2ecf20Sopenharmony_ci a_st_wr_state = 2; /* F2 */ 40098c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[pt] = 0; 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) 40128c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[pt] |= V_TX_LI; 40138c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 40148c2ecf20Sopenharmony_ci hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; 40158c2ecf20Sopenharmony_ci HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, 40168c2ecf20Sopenharmony_ci 0x7c << 1 /* V_ST_PULSE */); 40178c2ecf20Sopenharmony_ci } 40188c2ecf20Sopenharmony_ci /* line setup */ 40198c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); 40208c2ecf20Sopenharmony_ci /* disable E-channel */ 40218c2ecf20Sopenharmony_ci if ((dch->dev.D.protocol == ISDN_P_NT_S0) || 40228c2ecf20Sopenharmony_ci test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) 40238c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); 40248c2ecf20Sopenharmony_ci else 40258c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL1, 0); 40268c2ecf20Sopenharmony_ci /* enable B-channel receive */ 40278c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); 40288c2ecf20Sopenharmony_ci /* state machine setup */ 40298c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); 40308c2ecf20Sopenharmony_ci udelay(6); /* wait at least 5,21us */ 40318c2ecf20Sopenharmony_ci HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); 40328c2ecf20Sopenharmony_ci hc->hw.r_sci_msk |= 1 << pt; 40338c2ecf20Sopenharmony_ci /* state machine interrupts */ 40348c2ecf20Sopenharmony_ci HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); 40358c2ecf20Sopenharmony_ci /* unset sync on port */ 40368c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 40378c2ecf20Sopenharmony_ci hc->syncronized &= 40388c2ecf20Sopenharmony_ci ~(1 << hc->chan[dch->slot].port); 40398c2ecf20Sopenharmony_ci plxsd_checksync(hc, 0); 40408c2ecf20Sopenharmony_ci } 40418c2ecf20Sopenharmony_ci } 40428c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 40438c2ecf20Sopenharmony_ci printk("%s: done\n", __func__); 40448c2ecf20Sopenharmony_ci} 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_cistatic int 40488c2ecf20Sopenharmony_ciopen_dchannel(struct hfc_multi *hc, struct dchannel *dch, 40498c2ecf20Sopenharmony_ci struct channel_req *rq) 40508c2ecf20Sopenharmony_ci{ 40518c2ecf20Sopenharmony_ci int err = 0; 40528c2ecf20Sopenharmony_ci u_long flags; 40538c2ecf20Sopenharmony_ci 40548c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 40558c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, 40568c2ecf20Sopenharmony_ci dch->dev.id, __builtin_return_address(0)); 40578c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 40588c2ecf20Sopenharmony_ci return -EINVAL; 40598c2ecf20Sopenharmony_ci if ((dch->dev.D.protocol != ISDN_P_NONE) && 40608c2ecf20Sopenharmony_ci (dch->dev.D.protocol != rq->protocol)) { 40618c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MODE) 40628c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: change protocol %x to %x\n", 40638c2ecf20Sopenharmony_ci __func__, dch->dev.D.protocol, rq->protocol); 40648c2ecf20Sopenharmony_ci } 40658c2ecf20Sopenharmony_ci if ((dch->dev.D.protocol == ISDN_P_TE_S0) && 40668c2ecf20Sopenharmony_ci (rq->protocol != ISDN_P_TE_S0)) 40678c2ecf20Sopenharmony_ci l1_event(dch->l1, CLOSE_CHANNEL); 40688c2ecf20Sopenharmony_ci if (dch->dev.D.protocol != rq->protocol) { 40698c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 40708c2ecf20Sopenharmony_ci err = create_l1(dch, hfcm_l1callback); 40718c2ecf20Sopenharmony_ci if (err) 40728c2ecf20Sopenharmony_ci return err; 40738c2ecf20Sopenharmony_ci } 40748c2ecf20Sopenharmony_ci dch->dev.D.protocol = rq->protocol; 40758c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 40768c2ecf20Sopenharmony_ci hfcmulti_initmode(dch); 40778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 40788c2ecf20Sopenharmony_ci } 40798c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &dch->Flags)) 40808c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 40818c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 40828c2ecf20Sopenharmony_ci rq->ch = &dch->dev.D; 40838c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 40848c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 40858c2ecf20Sopenharmony_ci return 0; 40868c2ecf20Sopenharmony_ci} 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_cistatic int 40898c2ecf20Sopenharmony_ciopen_bchannel(struct hfc_multi *hc, struct dchannel *dch, 40908c2ecf20Sopenharmony_ci struct channel_req *rq) 40918c2ecf20Sopenharmony_ci{ 40928c2ecf20Sopenharmony_ci struct bchannel *bch; 40938c2ecf20Sopenharmony_ci int ch; 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) 40968c2ecf20Sopenharmony_ci return -EINVAL; 40978c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 40988c2ecf20Sopenharmony_ci return -EINVAL; 40998c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 41008c2ecf20Sopenharmony_ci ch = rq->adr.channel; 41018c2ecf20Sopenharmony_ci else 41028c2ecf20Sopenharmony_ci ch = (rq->adr.channel - 1) + (dch->slot - 2); 41038c2ecf20Sopenharmony_ci bch = hc->chan[ch].bch; 41048c2ecf20Sopenharmony_ci if (!bch) { 41058c2ecf20Sopenharmony_ci printk(KERN_ERR "%s:internal error ch %d has no bch\n", 41068c2ecf20Sopenharmony_ci __func__, ch); 41078c2ecf20Sopenharmony_ci return -EINVAL; 41088c2ecf20Sopenharmony_ci } 41098c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 41108c2ecf20Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 41118c2ecf20Sopenharmony_ci bch->ch.protocol = rq->protocol; 41128c2ecf20Sopenharmony_ci hc->chan[ch].rx_off = 0; 41138c2ecf20Sopenharmony_ci rq->ch = &bch->ch; 41148c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 41158c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s:cannot get module\n", __func__); 41168c2ecf20Sopenharmony_ci return 0; 41178c2ecf20Sopenharmony_ci} 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci/* 41208c2ecf20Sopenharmony_ci * device control function 41218c2ecf20Sopenharmony_ci */ 41228c2ecf20Sopenharmony_cistatic int 41238c2ecf20Sopenharmony_cichannel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) 41248c2ecf20Sopenharmony_ci{ 41258c2ecf20Sopenharmony_ci struct hfc_multi *hc = dch->hw; 41268c2ecf20Sopenharmony_ci int ret = 0; 41278c2ecf20Sopenharmony_ci int wd_mode, wd_cnt; 41288c2ecf20Sopenharmony_ci 41298c2ecf20Sopenharmony_ci switch (cq->op) { 41308c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 41318c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3; 41328c2ecf20Sopenharmony_ci break; 41338c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ 41348c2ecf20Sopenharmony_ci wd_cnt = cq->p1 & 0xf; 41358c2ecf20Sopenharmony_ci wd_mode = !!(cq->p1 >> 4); 41368c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 41378c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" 41388c2ecf20Sopenharmony_ci ", counter 0x%x\n", __func__, 41398c2ecf20Sopenharmony_ci wd_mode ? "AUTO" : "MANUAL", wd_cnt); 41408c2ecf20Sopenharmony_ci /* set the watchdog timer */ 41418c2ecf20Sopenharmony_ci HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); 41428c2ecf20Sopenharmony_ci hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); 41438c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) 41448c2ecf20Sopenharmony_ci hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; 41458c2ecf20Sopenharmony_ci /* init the watchdog register and reset the counter */ 41468c2ecf20Sopenharmony_ci HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); 41478c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 41488c2ecf20Sopenharmony_ci /* enable the watchdog output for Speech-Design */ 41498c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); 41508c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); 41518c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, 0); 41528c2ecf20Sopenharmony_ci HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); 41538c2ecf20Sopenharmony_ci } 41548c2ecf20Sopenharmony_ci break; 41558c2ecf20Sopenharmony_ci case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ 41568c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_MSG) 41578c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", 41588c2ecf20Sopenharmony_ci __func__); 41598c2ecf20Sopenharmony_ci HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); 41608c2ecf20Sopenharmony_ci break; 41618c2ecf20Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 41628c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); 41638c2ecf20Sopenharmony_ci break; 41648c2ecf20Sopenharmony_ci default: 41658c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unknown Op %x\n", 41668c2ecf20Sopenharmony_ci __func__, cq->op); 41678c2ecf20Sopenharmony_ci ret = -EINVAL; 41688c2ecf20Sopenharmony_ci break; 41698c2ecf20Sopenharmony_ci } 41708c2ecf20Sopenharmony_ci return ret; 41718c2ecf20Sopenharmony_ci} 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_cistatic int 41748c2ecf20Sopenharmony_cihfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 41758c2ecf20Sopenharmony_ci{ 41768c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 41778c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 41788c2ecf20Sopenharmony_ci struct hfc_multi *hc = dch->hw; 41798c2ecf20Sopenharmony_ci struct channel_req *rq; 41808c2ecf20Sopenharmony_ci int err = 0; 41818c2ecf20Sopenharmony_ci u_long flags; 41828c2ecf20Sopenharmony_ci 41838c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 41848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", 41858c2ecf20Sopenharmony_ci __func__, cmd, arg); 41868c2ecf20Sopenharmony_ci switch (cmd) { 41878c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 41888c2ecf20Sopenharmony_ci rq = arg; 41898c2ecf20Sopenharmony_ci switch (rq->protocol) { 41908c2ecf20Sopenharmony_ci case ISDN_P_TE_S0: 41918c2ecf20Sopenharmony_ci case ISDN_P_NT_S0: 41928c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 41938c2ecf20Sopenharmony_ci err = -EINVAL; 41948c2ecf20Sopenharmony_ci break; 41958c2ecf20Sopenharmony_ci } 41968c2ecf20Sopenharmony_ci err = open_dchannel(hc, dch, rq); /* locked there */ 41978c2ecf20Sopenharmony_ci break; 41988c2ecf20Sopenharmony_ci case ISDN_P_TE_E1: 41998c2ecf20Sopenharmony_ci case ISDN_P_NT_E1: 42008c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) { 42018c2ecf20Sopenharmony_ci err = -EINVAL; 42028c2ecf20Sopenharmony_ci break; 42038c2ecf20Sopenharmony_ci } 42048c2ecf20Sopenharmony_ci err = open_dchannel(hc, dch, rq); /* locked there */ 42058c2ecf20Sopenharmony_ci break; 42068c2ecf20Sopenharmony_ci default: 42078c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 42088c2ecf20Sopenharmony_ci err = open_bchannel(hc, dch, rq); 42098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 42108c2ecf20Sopenharmony_ci } 42118c2ecf20Sopenharmony_ci break; 42128c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 42138c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 42148c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: dev(%d) close from %p\n", 42158c2ecf20Sopenharmony_ci __func__, dch->dev.id, 42168c2ecf20Sopenharmony_ci __builtin_return_address(0)); 42178c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 42188c2ecf20Sopenharmony_ci break; 42198c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 42208c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 42218c2ecf20Sopenharmony_ci err = channel_dctrl(dch, arg); 42228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 42238c2ecf20Sopenharmony_ci break; 42248c2ecf20Sopenharmony_ci default: 42258c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 42268c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: unknown command %x\n", 42278c2ecf20Sopenharmony_ci __func__, cmd); 42288c2ecf20Sopenharmony_ci err = -EINVAL; 42298c2ecf20Sopenharmony_ci } 42308c2ecf20Sopenharmony_ci return err; 42318c2ecf20Sopenharmony_ci} 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_cistatic int 42348c2ecf20Sopenharmony_ciclockctl(void *priv, int enable) 42358c2ecf20Sopenharmony_ci{ 42368c2ecf20Sopenharmony_ci struct hfc_multi *hc = priv; 42378c2ecf20Sopenharmony_ci 42388c2ecf20Sopenharmony_ci hc->iclock_on = enable; 42398c2ecf20Sopenharmony_ci return 0; 42408c2ecf20Sopenharmony_ci} 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_ci/* 42438c2ecf20Sopenharmony_ci * initialize the card 42448c2ecf20Sopenharmony_ci */ 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci/* 42478c2ecf20Sopenharmony_ci * start timer irq, wait some time and check if we have interrupts. 42488c2ecf20Sopenharmony_ci * if not, reset chip and try again. 42498c2ecf20Sopenharmony_ci */ 42508c2ecf20Sopenharmony_cistatic int 42518c2ecf20Sopenharmony_ciinit_card(struct hfc_multi *hc) 42528c2ecf20Sopenharmony_ci{ 42538c2ecf20Sopenharmony_ci int err = -EIO; 42548c2ecf20Sopenharmony_ci u_long flags; 42558c2ecf20Sopenharmony_ci void __iomem *plx_acc; 42568c2ecf20Sopenharmony_ci u_long plx_flags; 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 42598c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: entered\n", __func__); 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 42628c2ecf20Sopenharmony_ci /* set interrupts but leave global interrupt disabled */ 42638c2ecf20Sopenharmony_ci hc->hw.r_irq_ctrl = V_FIFO_IRQ; 42648c2ecf20Sopenharmony_ci disable_hwirq(hc); 42658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, 42688c2ecf20Sopenharmony_ci "HFC-multi", hc)) { 42698c2ecf20Sopenharmony_ci printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", 42708c2ecf20Sopenharmony_ci hc->irq); 42718c2ecf20Sopenharmony_ci hc->irq = 0; 42728c2ecf20Sopenharmony_ci return -EIO; 42738c2ecf20Sopenharmony_ci } 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 42768c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 42778c2ecf20Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 42788c2ecf20Sopenharmony_ci writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), 42798c2ecf20Sopenharmony_ci plx_acc); /* enable PCI & LINT1 irq */ 42808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 42818c2ecf20Sopenharmony_ci } 42828c2ecf20Sopenharmony_ci 42838c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 42848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ %d count %d\n", 42858c2ecf20Sopenharmony_ci __func__, hc->irq, hc->irqcnt); 42868c2ecf20Sopenharmony_ci err = init_chip(hc); 42878c2ecf20Sopenharmony_ci if (err) 42888c2ecf20Sopenharmony_ci goto error; 42898c2ecf20Sopenharmony_ci /* 42908c2ecf20Sopenharmony_ci * Finally enable IRQ output 42918c2ecf20Sopenharmony_ci * this is only allowed, if an IRQ routine is already 42928c2ecf20Sopenharmony_ci * established for this HFC, so don't do that earlier 42938c2ecf20Sopenharmony_ci */ 42948c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 42958c2ecf20Sopenharmony_ci enable_hwirq(hc); 42968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 42978c2ecf20Sopenharmony_ci /* printk(KERN_DEBUG "no master irq set!!!\n"); */ 42988c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 42998c2ecf20Sopenharmony_ci schedule_timeout((100 * HZ) / 1000); /* Timeout 100ms */ 43008c2ecf20Sopenharmony_ci /* turn IRQ off until chip is completely initialized */ 43018c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 43028c2ecf20Sopenharmony_ci disable_hwirq(hc); 43038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 43048c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 43058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ %d count %d\n", 43068c2ecf20Sopenharmony_ci __func__, hc->irq, hc->irqcnt); 43078c2ecf20Sopenharmony_ci if (hc->irqcnt) { 43088c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 43098c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: done\n", __func__); 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci return 0; 43128c2ecf20Sopenharmony_ci } 43138c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { 43148c2ecf20Sopenharmony_ci printk(KERN_INFO "ignoring missing interrupts\n"); 43158c2ecf20Sopenharmony_ci return 0; 43168c2ecf20Sopenharmony_ci } 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", 43198c2ecf20Sopenharmony_ci hc->irq); 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci err = -EIO; 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_cierror: 43248c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 43258c2ecf20Sopenharmony_ci spin_lock_irqsave(&plx_lock, plx_flags); 43268c2ecf20Sopenharmony_ci plx_acc = hc->plx_membase + PLX_INTCSR; 43278c2ecf20Sopenharmony_ci writew(0x00, plx_acc); /*disable IRQs*/ 43288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&plx_lock, plx_flags); 43298c2ecf20Sopenharmony_ci } 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 43328c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); 43338c2ecf20Sopenharmony_ci if (hc->irq) { 43348c2ecf20Sopenharmony_ci free_irq(hc->irq, hc); 43358c2ecf20Sopenharmony_ci hc->irq = 0; 43368c2ecf20Sopenharmony_ci } 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 43398c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); 43408c2ecf20Sopenharmony_ci return err; 43418c2ecf20Sopenharmony_ci} 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_ci/* 43448c2ecf20Sopenharmony_ci * find pci device and set it up 43458c2ecf20Sopenharmony_ci */ 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_cistatic int 43488c2ecf20Sopenharmony_cisetup_pci(struct hfc_multi *hc, struct pci_dev *pdev, 43498c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 43508c2ecf20Sopenharmony_ci{ 43518c2ecf20Sopenharmony_ci struct hm_map *m = (struct hm_map *)ent->driver_data; 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci printk(KERN_INFO 43548c2ecf20Sopenharmony_ci "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", 43558c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci hc->pci_dev = pdev; 43588c2ecf20Sopenharmony_ci if (m->clock2) 43598c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); 43608c2ecf20Sopenharmony_ci 43618c2ecf20Sopenharmony_ci if (ent->vendor == PCI_VENDOR_ID_DIGIUM && 43628c2ecf20Sopenharmony_ci ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) { 43638c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_B410P, &hc->chip); 43648c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); 43658c2ecf20Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 43668c2ecf20Sopenharmony_ci hc->slots = 32; 43678c2ecf20Sopenharmony_ci } 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci if (hc->pci_dev->irq <= 0) { 43708c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); 43718c2ecf20Sopenharmony_ci return -EIO; 43728c2ecf20Sopenharmony_ci } 43738c2ecf20Sopenharmony_ci if (pci_enable_device(hc->pci_dev)) { 43748c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); 43758c2ecf20Sopenharmony_ci return -EIO; 43768c2ecf20Sopenharmony_ci } 43778c2ecf20Sopenharmony_ci hc->leds = m->leds; 43788c2ecf20Sopenharmony_ci hc->ledstate = 0xAFFEAFFE; 43798c2ecf20Sopenharmony_ci hc->opticalsupport = m->opticalsupport; 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ci hc->pci_iobase = 0; 43828c2ecf20Sopenharmony_ci hc->pci_membase = NULL; 43838c2ecf20Sopenharmony_ci hc->plx_membase = NULL; 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci /* set memory access methods */ 43868c2ecf20Sopenharmony_ci if (m->io_mode) /* use mode from card config */ 43878c2ecf20Sopenharmony_ci hc->io_mode = m->io_mode; 43888c2ecf20Sopenharmony_ci switch (hc->io_mode) { 43898c2ecf20Sopenharmony_ci case HFC_IO_MODE_PLXSD: 43908c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); 43918c2ecf20Sopenharmony_ci hc->slots = 128; /* required */ 43928c2ecf20Sopenharmony_ci hc->HFC_outb = HFC_outb_pcimem; 43938c2ecf20Sopenharmony_ci hc->HFC_inb = HFC_inb_pcimem; 43948c2ecf20Sopenharmony_ci hc->HFC_inw = HFC_inw_pcimem; 43958c2ecf20Sopenharmony_ci hc->HFC_wait = HFC_wait_pcimem; 43968c2ecf20Sopenharmony_ci hc->read_fifo = read_fifo_pcimem; 43978c2ecf20Sopenharmony_ci hc->write_fifo = write_fifo_pcimem; 43988c2ecf20Sopenharmony_ci hc->plx_origmembase = hc->pci_dev->resource[0].start; 43998c2ecf20Sopenharmony_ci /* MEMBASE 1 is PLX PCI Bridge */ 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci if (!hc->plx_origmembase) { 44028c2ecf20Sopenharmony_ci printk(KERN_WARNING 44038c2ecf20Sopenharmony_ci "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); 44048c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44058c2ecf20Sopenharmony_ci return -EIO; 44068c2ecf20Sopenharmony_ci } 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); 44098c2ecf20Sopenharmony_ci if (!hc->plx_membase) { 44108c2ecf20Sopenharmony_ci printk(KERN_WARNING 44118c2ecf20Sopenharmony_ci "HFC-multi: failed to remap plx address space. " 44128c2ecf20Sopenharmony_ci "(internal error)\n"); 44138c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44148c2ecf20Sopenharmony_ci return -EIO; 44158c2ecf20Sopenharmony_ci } 44168c2ecf20Sopenharmony_ci printk(KERN_INFO 44178c2ecf20Sopenharmony_ci "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", 44188c2ecf20Sopenharmony_ci (u_long)hc->plx_membase, hc->plx_origmembase); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci hc->pci_origmembase = hc->pci_dev->resource[2].start; 44218c2ecf20Sopenharmony_ci /* MEMBASE 1 is PLX PCI Bridge */ 44228c2ecf20Sopenharmony_ci if (!hc->pci_origmembase) { 44238c2ecf20Sopenharmony_ci printk(KERN_WARNING 44248c2ecf20Sopenharmony_ci "HFC-multi: No IO-Memory for PCI card found\n"); 44258c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44268c2ecf20Sopenharmony_ci return -EIO; 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); 44308c2ecf20Sopenharmony_ci if (!hc->pci_membase) { 44318c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-multi: failed to remap io " 44328c2ecf20Sopenharmony_ci "address space. (internal error)\n"); 44338c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44348c2ecf20Sopenharmony_ci return -EIO; 44358c2ecf20Sopenharmony_ci } 44368c2ecf20Sopenharmony_ci 44378c2ecf20Sopenharmony_ci printk(KERN_INFO 44388c2ecf20Sopenharmony_ci "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " 44398c2ecf20Sopenharmony_ci "leds-type %d\n", 44408c2ecf20Sopenharmony_ci hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, 44418c2ecf20Sopenharmony_ci hc->pci_dev->irq, HZ, hc->leds); 44428c2ecf20Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); 44438c2ecf20Sopenharmony_ci break; 44448c2ecf20Sopenharmony_ci case HFC_IO_MODE_PCIMEM: 44458c2ecf20Sopenharmony_ci hc->HFC_outb = HFC_outb_pcimem; 44468c2ecf20Sopenharmony_ci hc->HFC_inb = HFC_inb_pcimem; 44478c2ecf20Sopenharmony_ci hc->HFC_inw = HFC_inw_pcimem; 44488c2ecf20Sopenharmony_ci hc->HFC_wait = HFC_wait_pcimem; 44498c2ecf20Sopenharmony_ci hc->read_fifo = read_fifo_pcimem; 44508c2ecf20Sopenharmony_ci hc->write_fifo = write_fifo_pcimem; 44518c2ecf20Sopenharmony_ci hc->pci_origmembase = hc->pci_dev->resource[1].start; 44528c2ecf20Sopenharmony_ci if (!hc->pci_origmembase) { 44538c2ecf20Sopenharmony_ci printk(KERN_WARNING 44548c2ecf20Sopenharmony_ci "HFC-multi: No IO-Memory for PCI card found\n"); 44558c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44568c2ecf20Sopenharmony_ci return -EIO; 44578c2ecf20Sopenharmony_ci } 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ci hc->pci_membase = ioremap(hc->pci_origmembase, 256); 44608c2ecf20Sopenharmony_ci if (!hc->pci_membase) { 44618c2ecf20Sopenharmony_ci printk(KERN_WARNING 44628c2ecf20Sopenharmony_ci "HFC-multi: failed to remap io address space. " 44638c2ecf20Sopenharmony_ci "(internal error)\n"); 44648c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44658c2ecf20Sopenharmony_ci return -EIO; 44668c2ecf20Sopenharmony_ci } 44678c2ecf20Sopenharmony_ci printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " 44688c2ecf20Sopenharmony_ci "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, 44698c2ecf20Sopenharmony_ci hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); 44708c2ecf20Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); 44718c2ecf20Sopenharmony_ci break; 44728c2ecf20Sopenharmony_ci case HFC_IO_MODE_REGIO: 44738c2ecf20Sopenharmony_ci hc->HFC_outb = HFC_outb_regio; 44748c2ecf20Sopenharmony_ci hc->HFC_inb = HFC_inb_regio; 44758c2ecf20Sopenharmony_ci hc->HFC_inw = HFC_inw_regio; 44768c2ecf20Sopenharmony_ci hc->HFC_wait = HFC_wait_regio; 44778c2ecf20Sopenharmony_ci hc->read_fifo = read_fifo_regio; 44788c2ecf20Sopenharmony_ci hc->write_fifo = write_fifo_regio; 44798c2ecf20Sopenharmony_ci hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; 44808c2ecf20Sopenharmony_ci if (!hc->pci_iobase) { 44818c2ecf20Sopenharmony_ci printk(KERN_WARNING 44828c2ecf20Sopenharmony_ci "HFC-multi: No IO for PCI card found\n"); 44838c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44848c2ecf20Sopenharmony_ci return -EIO; 44858c2ecf20Sopenharmony_ci } 44868c2ecf20Sopenharmony_ci 44878c2ecf20Sopenharmony_ci if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { 44888c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-multi: failed to request " 44898c2ecf20Sopenharmony_ci "address space at 0x%08lx (internal error)\n", 44908c2ecf20Sopenharmony_ci hc->pci_iobase); 44918c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 44928c2ecf20Sopenharmony_ci return -EIO; 44938c2ecf20Sopenharmony_ci } 44948c2ecf20Sopenharmony_ci 44958c2ecf20Sopenharmony_ci printk(KERN_INFO 44968c2ecf20Sopenharmony_ci "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", 44978c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, (u_int) hc->pci_iobase, 44988c2ecf20Sopenharmony_ci hc->pci_dev->irq, HZ, hc->leds); 44998c2ecf20Sopenharmony_ci pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); 45008c2ecf20Sopenharmony_ci break; 45018c2ecf20Sopenharmony_ci default: 45028c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); 45038c2ecf20Sopenharmony_ci pci_disable_device(hc->pci_dev); 45048c2ecf20Sopenharmony_ci return -EIO; 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci pci_set_drvdata(hc->pci_dev, hc); 45088c2ecf20Sopenharmony_ci 45098c2ecf20Sopenharmony_ci /* At this point the needed PCI config is done */ 45108c2ecf20Sopenharmony_ci /* fifos are still not enabled */ 45118c2ecf20Sopenharmony_ci return 0; 45128c2ecf20Sopenharmony_ci} 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci/* 45168c2ecf20Sopenharmony_ci * remove port 45178c2ecf20Sopenharmony_ci */ 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_cistatic void 45208c2ecf20Sopenharmony_cirelease_port(struct hfc_multi *hc, struct dchannel *dch) 45218c2ecf20Sopenharmony_ci{ 45228c2ecf20Sopenharmony_ci int pt, ci, i = 0; 45238c2ecf20Sopenharmony_ci u_long flags; 45248c2ecf20Sopenharmony_ci struct bchannel *pb; 45258c2ecf20Sopenharmony_ci 45268c2ecf20Sopenharmony_ci ci = dch->slot; 45278c2ecf20Sopenharmony_ci pt = hc->chan[ci].port; 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 45308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: entered for port %d\n", 45318c2ecf20Sopenharmony_ci __func__, pt + 1); 45328c2ecf20Sopenharmony_ci 45338c2ecf20Sopenharmony_ci if (pt >= hc->ports) { 45348c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", 45358c2ecf20Sopenharmony_ci __func__, pt + 1); 45368c2ecf20Sopenharmony_ci return; 45378c2ecf20Sopenharmony_ci } 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 45408c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: releasing port=%d\n", 45418c2ecf20Sopenharmony_ci __func__, pt + 1); 45428c2ecf20Sopenharmony_ci 45438c2ecf20Sopenharmony_ci if (dch->dev.D.protocol == ISDN_P_TE_S0) 45448c2ecf20Sopenharmony_ci l1_event(dch->l1, CLOSE_CHANNEL); 45458c2ecf20Sopenharmony_ci 45468c2ecf20Sopenharmony_ci hc->chan[ci].dch = NULL; 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci if (hc->created[pt]) { 45498c2ecf20Sopenharmony_ci hc->created[pt] = 0; 45508c2ecf20Sopenharmony_ci mISDN_unregister_device(&dch->dev); 45518c2ecf20Sopenharmony_ci } 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci if (dch->timer.function) { 45568c2ecf20Sopenharmony_ci del_timer(&dch->timer); 45578c2ecf20Sopenharmony_ci dch->timer.function = NULL; 45588c2ecf20Sopenharmony_ci } 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { /* E1 */ 45618c2ecf20Sopenharmony_ci /* remove sync */ 45628c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 45638c2ecf20Sopenharmony_ci hc->syncronized = 0; 45648c2ecf20Sopenharmony_ci plxsd_checksync(hc, 1); 45658c2ecf20Sopenharmony_ci } 45668c2ecf20Sopenharmony_ci /* free channels */ 45678c2ecf20Sopenharmony_ci for (i = 0; i <= 31; i++) { 45688c2ecf20Sopenharmony_ci if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ 45698c2ecf20Sopenharmony_ci continue; 45708c2ecf20Sopenharmony_ci if (hc->chan[i].bch) { 45718c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 45728c2ecf20Sopenharmony_ci printk(KERN_DEBUG 45738c2ecf20Sopenharmony_ci "%s: free port %d channel %d\n", 45748c2ecf20Sopenharmony_ci __func__, hc->chan[i].port + 1, i); 45758c2ecf20Sopenharmony_ci pb = hc->chan[i].bch; 45768c2ecf20Sopenharmony_ci hc->chan[i].bch = NULL; 45778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 45788c2ecf20Sopenharmony_ci mISDN_freebchannel(pb); 45798c2ecf20Sopenharmony_ci kfree(pb); 45808c2ecf20Sopenharmony_ci kfree(hc->chan[i].coeff); 45818c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 45828c2ecf20Sopenharmony_ci } 45838c2ecf20Sopenharmony_ci } 45848c2ecf20Sopenharmony_ci } else { 45858c2ecf20Sopenharmony_ci /* remove sync */ 45868c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { 45878c2ecf20Sopenharmony_ci hc->syncronized &= 45888c2ecf20Sopenharmony_ci ~(1 << hc->chan[ci].port); 45898c2ecf20Sopenharmony_ci plxsd_checksync(hc, 1); 45908c2ecf20Sopenharmony_ci } 45918c2ecf20Sopenharmony_ci /* free channels */ 45928c2ecf20Sopenharmony_ci if (hc->chan[ci - 2].bch) { 45938c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 45948c2ecf20Sopenharmony_ci printk(KERN_DEBUG 45958c2ecf20Sopenharmony_ci "%s: free port %d channel %d\n", 45968c2ecf20Sopenharmony_ci __func__, hc->chan[ci - 2].port + 1, 45978c2ecf20Sopenharmony_ci ci - 2); 45988c2ecf20Sopenharmony_ci pb = hc->chan[ci - 2].bch; 45998c2ecf20Sopenharmony_ci hc->chan[ci - 2].bch = NULL; 46008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 46018c2ecf20Sopenharmony_ci mISDN_freebchannel(pb); 46028c2ecf20Sopenharmony_ci kfree(pb); 46038c2ecf20Sopenharmony_ci kfree(hc->chan[ci - 2].coeff); 46048c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 46058c2ecf20Sopenharmony_ci } 46068c2ecf20Sopenharmony_ci if (hc->chan[ci - 1].bch) { 46078c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46088c2ecf20Sopenharmony_ci printk(KERN_DEBUG 46098c2ecf20Sopenharmony_ci "%s: free port %d channel %d\n", 46108c2ecf20Sopenharmony_ci __func__, hc->chan[ci - 1].port + 1, 46118c2ecf20Sopenharmony_ci ci - 1); 46128c2ecf20Sopenharmony_ci pb = hc->chan[ci - 1].bch; 46138c2ecf20Sopenharmony_ci hc->chan[ci - 1].bch = NULL; 46148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 46158c2ecf20Sopenharmony_ci mISDN_freebchannel(pb); 46168c2ecf20Sopenharmony_ci kfree(pb); 46178c2ecf20Sopenharmony_ci kfree(hc->chan[ci - 1].coeff); 46188c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 46198c2ecf20Sopenharmony_ci } 46208c2ecf20Sopenharmony_ci } 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 46238c2ecf20Sopenharmony_ci 46248c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46258c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__, 46268c2ecf20Sopenharmony_ci pt+1, ci); 46278c2ecf20Sopenharmony_ci mISDN_freedchannel(dch); 46288c2ecf20Sopenharmony_ci kfree(dch); 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46318c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: done!\n", __func__); 46328c2ecf20Sopenharmony_ci} 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_cistatic void 46358c2ecf20Sopenharmony_cirelease_card(struct hfc_multi *hc) 46368c2ecf20Sopenharmony_ci{ 46378c2ecf20Sopenharmony_ci u_long flags; 46388c2ecf20Sopenharmony_ci int ch; 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: release card (%d) entered\n", 46428c2ecf20Sopenharmony_ci __func__, hc->id); 46438c2ecf20Sopenharmony_ci 46448c2ecf20Sopenharmony_ci /* unregister clock source */ 46458c2ecf20Sopenharmony_ci if (hc->iclock) 46468c2ecf20Sopenharmony_ci mISDN_unregister_clock(hc->iclock); 46478c2ecf20Sopenharmony_ci 46488c2ecf20Sopenharmony_ci /* disable and free irq */ 46498c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 46508c2ecf20Sopenharmony_ci disable_hwirq(hc); 46518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 46528c2ecf20Sopenharmony_ci udelay(1000); 46538c2ecf20Sopenharmony_ci if (hc->irq) { 46548c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46558c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n", 46568c2ecf20Sopenharmony_ci __func__, hc->irq, hc); 46578c2ecf20Sopenharmony_ci free_irq(hc->irq, hc); 46588c2ecf20Sopenharmony_ci hc->irq = 0; 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_ci } 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci /* disable D-channels & B-channels */ 46638c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46648c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: disable all channels (d and b)\n", 46658c2ecf20Sopenharmony_ci __func__); 46668c2ecf20Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 46678c2ecf20Sopenharmony_ci if (hc->chan[ch].dch) 46688c2ecf20Sopenharmony_ci release_port(hc, hc->chan[ch].dch); 46698c2ecf20Sopenharmony_ci } 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci /* dimm leds */ 46728c2ecf20Sopenharmony_ci if (hc->leds) 46738c2ecf20Sopenharmony_ci hfcmulti_leds(hc); 46748c2ecf20Sopenharmony_ci 46758c2ecf20Sopenharmony_ci /* release hardware */ 46768c2ecf20Sopenharmony_ci release_io_hfcmulti(hc); 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46798c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: remove instance from list\n", 46808c2ecf20Sopenharmony_ci __func__); 46818c2ecf20Sopenharmony_ci list_del(&hc->list); 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: delete instance\n", __func__); 46858c2ecf20Sopenharmony_ci if (hc == syncmaster) 46868c2ecf20Sopenharmony_ci syncmaster = NULL; 46878c2ecf20Sopenharmony_ci kfree(hc); 46888c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 46898c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: card successfully removed\n", 46908c2ecf20Sopenharmony_ci __func__); 46918c2ecf20Sopenharmony_ci} 46928c2ecf20Sopenharmony_ci 46938c2ecf20Sopenharmony_cistatic void 46948c2ecf20Sopenharmony_ciinit_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) 46958c2ecf20Sopenharmony_ci{ 46968c2ecf20Sopenharmony_ci /* set optical line type */ 46978c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x001) { 46988c2ecf20Sopenharmony_ci if (!m->opticalsupport) { 46998c2ecf20Sopenharmony_ci printk(KERN_INFO 47008c2ecf20Sopenharmony_ci "This board has no optical " 47018c2ecf20Sopenharmony_ci "support\n"); 47028c2ecf20Sopenharmony_ci } else { 47038c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47048c2ecf20Sopenharmony_ci printk(KERN_DEBUG 47058c2ecf20Sopenharmony_ci "%s: PORT set optical " 47068c2ecf20Sopenharmony_ci "interfacs: card(%d) " 47078c2ecf20Sopenharmony_ci "port(%d)\n", 47088c2ecf20Sopenharmony_ci __func__, 47098c2ecf20Sopenharmony_ci HFC_cnt + 1, 1); 47108c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_OPTICAL, 47118c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47128c2ecf20Sopenharmony_ci } 47138c2ecf20Sopenharmony_ci } 47148c2ecf20Sopenharmony_ci /* set LOS report */ 47158c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x004) { 47168c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47178c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT set " 47188c2ecf20Sopenharmony_ci "LOS report: card(%d) port(%d)\n", 47198c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47208c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_LOS, 47218c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47228c2ecf20Sopenharmony_ci } 47238c2ecf20Sopenharmony_ci /* set AIS report */ 47248c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x008) { 47258c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47268c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT set " 47278c2ecf20Sopenharmony_ci "AIS report: card(%d) port(%d)\n", 47288c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47298c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_AIS, 47308c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47318c2ecf20Sopenharmony_ci } 47328c2ecf20Sopenharmony_ci /* set SLIP report */ 47338c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x010) { 47348c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47358c2ecf20Sopenharmony_ci printk(KERN_DEBUG 47368c2ecf20Sopenharmony_ci "%s: PORT set SLIP report: " 47378c2ecf20Sopenharmony_ci "card(%d) port(%d)\n", 47388c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47398c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_SLIP, 47408c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47418c2ecf20Sopenharmony_ci } 47428c2ecf20Sopenharmony_ci /* set RDI report */ 47438c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x020) { 47448c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47458c2ecf20Sopenharmony_ci printk(KERN_DEBUG 47468c2ecf20Sopenharmony_ci "%s: PORT set RDI report: " 47478c2ecf20Sopenharmony_ci "card(%d) port(%d)\n", 47488c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47498c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_REPORT_RDI, 47508c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47518c2ecf20Sopenharmony_ci } 47528c2ecf20Sopenharmony_ci /* set CRC-4 Mode */ 47538c2ecf20Sopenharmony_ci if (!(port[Port_cnt] & 0x100)) { 47548c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47558c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" 47568c2ecf20Sopenharmony_ci " card(%d) port(%d)\n", 47578c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47588c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_CRC4, 47598c2ecf20Sopenharmony_ci &hc->chan[hc->dnum[0]].cfg); 47608c2ecf20Sopenharmony_ci } else { 47618c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47628c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT turn off CRC4" 47638c2ecf20Sopenharmony_ci " report: card(%d) port(%d)\n", 47648c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47658c2ecf20Sopenharmony_ci } 47668c2ecf20Sopenharmony_ci /* set forced clock */ 47678c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x0200) { 47688c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47698c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT force getting clock from " 47708c2ecf20Sopenharmony_ci "E1: card(%d) port(%d)\n", 47718c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47728c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); 47738c2ecf20Sopenharmony_ci } else 47748c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x0400) { 47758c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47768c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT force putting clock to " 47778c2ecf20Sopenharmony_ci "E1: card(%d) port(%d)\n", 47788c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47798c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); 47808c2ecf20Sopenharmony_ci } 47818c2ecf20Sopenharmony_ci /* set JATT PLL */ 47828c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x0800) { 47838c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PORT disable JATT PLL on " 47858c2ecf20Sopenharmony_ci "E1: card(%d) port(%d)\n", 47868c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, 1); 47878c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); 47888c2ecf20Sopenharmony_ci } 47898c2ecf20Sopenharmony_ci /* set elastic jitter buffer */ 47908c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x3000) { 47918c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3; 47928c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 47938c2ecf20Sopenharmony_ci printk(KERN_DEBUG 47948c2ecf20Sopenharmony_ci "%s: PORT set elastic " 47958c2ecf20Sopenharmony_ci "buffer to %d: card(%d) port(%d)\n", 47968c2ecf20Sopenharmony_ci __func__, hc->chan[hc->dnum[0]].jitter, 47978c2ecf20Sopenharmony_ci HFC_cnt + 1, 1); 47988c2ecf20Sopenharmony_ci } else 47998c2ecf20Sopenharmony_ci hc->chan[hc->dnum[0]].jitter = 2; /* default */ 48008c2ecf20Sopenharmony_ci} 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_cistatic int 48038c2ecf20Sopenharmony_ciinit_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) 48048c2ecf20Sopenharmony_ci{ 48058c2ecf20Sopenharmony_ci struct dchannel *dch; 48068c2ecf20Sopenharmony_ci struct bchannel *bch; 48078c2ecf20Sopenharmony_ci int ch, ret = 0; 48088c2ecf20Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 48098c2ecf20Sopenharmony_ci int bcount = 0; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); 48128c2ecf20Sopenharmony_ci if (!dch) 48138c2ecf20Sopenharmony_ci return -ENOMEM; 48148c2ecf20Sopenharmony_ci dch->debug = debug; 48158c2ecf20Sopenharmony_ci mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); 48168c2ecf20Sopenharmony_ci dch->hw = hc; 48178c2ecf20Sopenharmony_ci dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); 48188c2ecf20Sopenharmony_ci dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 48198c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 48208c2ecf20Sopenharmony_ci dch->dev.D.send = handle_dmsg; 48218c2ecf20Sopenharmony_ci dch->dev.D.ctrl = hfcm_dctrl; 48228c2ecf20Sopenharmony_ci dch->slot = hc->dnum[pt]; 48238c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].dch = dch; 48248c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].port = pt; 48258c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].nt_timer = -1; 48268c2ecf20Sopenharmony_ci for (ch = 1; ch <= 31; ch++) { 48278c2ecf20Sopenharmony_ci if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ 48288c2ecf20Sopenharmony_ci continue; 48298c2ecf20Sopenharmony_ci bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); 48308c2ecf20Sopenharmony_ci if (!bch) { 48318c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no memory for bchannel\n", 48328c2ecf20Sopenharmony_ci __func__); 48338c2ecf20Sopenharmony_ci ret = -ENOMEM; 48348c2ecf20Sopenharmony_ci goto free_chan; 48358c2ecf20Sopenharmony_ci } 48368c2ecf20Sopenharmony_ci hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); 48378c2ecf20Sopenharmony_ci if (!hc->chan[ch].coeff) { 48388c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no memory for coeffs\n", 48398c2ecf20Sopenharmony_ci __func__); 48408c2ecf20Sopenharmony_ci ret = -ENOMEM; 48418c2ecf20Sopenharmony_ci kfree(bch); 48428c2ecf20Sopenharmony_ci goto free_chan; 48438c2ecf20Sopenharmony_ci } 48448c2ecf20Sopenharmony_ci bch->nr = ch; 48458c2ecf20Sopenharmony_ci bch->slot = ch; 48468c2ecf20Sopenharmony_ci bch->debug = debug; 48478c2ecf20Sopenharmony_ci mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); 48488c2ecf20Sopenharmony_ci bch->hw = hc; 48498c2ecf20Sopenharmony_ci bch->ch.send = handle_bmsg; 48508c2ecf20Sopenharmony_ci bch->ch.ctrl = hfcm_bctrl; 48518c2ecf20Sopenharmony_ci bch->ch.nr = ch; 48528c2ecf20Sopenharmony_ci list_add(&bch->ch.list, &dch->dev.bchannels); 48538c2ecf20Sopenharmony_ci hc->chan[ch].bch = bch; 48548c2ecf20Sopenharmony_ci hc->chan[ch].port = pt; 48558c2ecf20Sopenharmony_ci set_channelmap(bch->nr, dch->dev.channelmap); 48568c2ecf20Sopenharmony_ci bcount++; 48578c2ecf20Sopenharmony_ci } 48588c2ecf20Sopenharmony_ci dch->dev.nrbchan = bcount; 48598c2ecf20Sopenharmony_ci if (pt == 0) 48608c2ecf20Sopenharmony_ci init_e1_port_hw(hc, m); 48618c2ecf20Sopenharmony_ci if (hc->ports > 1) 48628c2ecf20Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d", 48638c2ecf20Sopenharmony_ci HFC_cnt + 1, pt+1); 48648c2ecf20Sopenharmony_ci else 48658c2ecf20Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); 48668c2ecf20Sopenharmony_ci ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); 48678c2ecf20Sopenharmony_ci if (ret) 48688c2ecf20Sopenharmony_ci goto free_chan; 48698c2ecf20Sopenharmony_ci hc->created[pt] = 1; 48708c2ecf20Sopenharmony_ci return ret; 48718c2ecf20Sopenharmony_cifree_chan: 48728c2ecf20Sopenharmony_ci release_port(hc, dch); 48738c2ecf20Sopenharmony_ci return ret; 48748c2ecf20Sopenharmony_ci} 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_cistatic int 48778c2ecf20Sopenharmony_ciinit_multi_port(struct hfc_multi *hc, int pt) 48788c2ecf20Sopenharmony_ci{ 48798c2ecf20Sopenharmony_ci struct dchannel *dch; 48808c2ecf20Sopenharmony_ci struct bchannel *bch; 48818c2ecf20Sopenharmony_ci int ch, i, ret = 0; 48828c2ecf20Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 48838c2ecf20Sopenharmony_ci 48848c2ecf20Sopenharmony_ci dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); 48858c2ecf20Sopenharmony_ci if (!dch) 48868c2ecf20Sopenharmony_ci return -ENOMEM; 48878c2ecf20Sopenharmony_ci dch->debug = debug; 48888c2ecf20Sopenharmony_ci mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); 48898c2ecf20Sopenharmony_ci dch->hw = hc; 48908c2ecf20Sopenharmony_ci dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); 48918c2ecf20Sopenharmony_ci dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 48928c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 48938c2ecf20Sopenharmony_ci dch->dev.D.send = handle_dmsg; 48948c2ecf20Sopenharmony_ci dch->dev.D.ctrl = hfcm_dctrl; 48958c2ecf20Sopenharmony_ci dch->dev.nrbchan = 2; 48968c2ecf20Sopenharmony_ci i = pt << 2; 48978c2ecf20Sopenharmony_ci dch->slot = i + 2; 48988c2ecf20Sopenharmony_ci hc->chan[i + 2].dch = dch; 48998c2ecf20Sopenharmony_ci hc->chan[i + 2].port = pt; 49008c2ecf20Sopenharmony_ci hc->chan[i + 2].nt_timer = -1; 49018c2ecf20Sopenharmony_ci for (ch = 0; ch < dch->dev.nrbchan; ch++) { 49028c2ecf20Sopenharmony_ci bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); 49038c2ecf20Sopenharmony_ci if (!bch) { 49048c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no memory for bchannel\n", 49058c2ecf20Sopenharmony_ci __func__); 49068c2ecf20Sopenharmony_ci ret = -ENOMEM; 49078c2ecf20Sopenharmony_ci goto free_chan; 49088c2ecf20Sopenharmony_ci } 49098c2ecf20Sopenharmony_ci hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); 49108c2ecf20Sopenharmony_ci if (!hc->chan[i + ch].coeff) { 49118c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no memory for coeffs\n", 49128c2ecf20Sopenharmony_ci __func__); 49138c2ecf20Sopenharmony_ci ret = -ENOMEM; 49148c2ecf20Sopenharmony_ci kfree(bch); 49158c2ecf20Sopenharmony_ci goto free_chan; 49168c2ecf20Sopenharmony_ci } 49178c2ecf20Sopenharmony_ci bch->nr = ch + 1; 49188c2ecf20Sopenharmony_ci bch->slot = i + ch; 49198c2ecf20Sopenharmony_ci bch->debug = debug; 49208c2ecf20Sopenharmony_ci mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); 49218c2ecf20Sopenharmony_ci bch->hw = hc; 49228c2ecf20Sopenharmony_ci bch->ch.send = handle_bmsg; 49238c2ecf20Sopenharmony_ci bch->ch.ctrl = hfcm_bctrl; 49248c2ecf20Sopenharmony_ci bch->ch.nr = ch + 1; 49258c2ecf20Sopenharmony_ci list_add(&bch->ch.list, &dch->dev.bchannels); 49268c2ecf20Sopenharmony_ci hc->chan[i + ch].bch = bch; 49278c2ecf20Sopenharmony_ci hc->chan[i + ch].port = pt; 49288c2ecf20Sopenharmony_ci set_channelmap(bch->nr, dch->dev.channelmap); 49298c2ecf20Sopenharmony_ci } 49308c2ecf20Sopenharmony_ci /* set master clock */ 49318c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x001) { 49328c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 49338c2ecf20Sopenharmony_ci printk(KERN_DEBUG 49348c2ecf20Sopenharmony_ci "%s: PROTOCOL set master clock: " 49358c2ecf20Sopenharmony_ci "card(%d) port(%d)\n", 49368c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 49378c2ecf20Sopenharmony_ci if (dch->dev.D.protocol != ISDN_P_TE_S0) { 49388c2ecf20Sopenharmony_ci printk(KERN_ERR "Error: Master clock " 49398c2ecf20Sopenharmony_ci "for port(%d) of card(%d) is only" 49408c2ecf20Sopenharmony_ci " possible with TE-mode\n", 49418c2ecf20Sopenharmony_ci pt + 1, HFC_cnt + 1); 49428c2ecf20Sopenharmony_ci ret = -EINVAL; 49438c2ecf20Sopenharmony_ci goto free_chan; 49448c2ecf20Sopenharmony_ci } 49458c2ecf20Sopenharmony_ci if (hc->masterclk >= 0) { 49468c2ecf20Sopenharmony_ci printk(KERN_ERR "Error: Master clock " 49478c2ecf20Sopenharmony_ci "for port(%d) of card(%d) already " 49488c2ecf20Sopenharmony_ci "defined for port(%d)\n", 49498c2ecf20Sopenharmony_ci pt + 1, HFC_cnt + 1, hc->masterclk + 1); 49508c2ecf20Sopenharmony_ci ret = -EINVAL; 49518c2ecf20Sopenharmony_ci goto free_chan; 49528c2ecf20Sopenharmony_ci } 49538c2ecf20Sopenharmony_ci hc->masterclk = pt; 49548c2ecf20Sopenharmony_ci } 49558c2ecf20Sopenharmony_ci /* set transmitter line to non capacitive */ 49568c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x002) { 49578c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 49588c2ecf20Sopenharmony_ci printk(KERN_DEBUG 49598c2ecf20Sopenharmony_ci "%s: PROTOCOL set non capacitive " 49608c2ecf20Sopenharmony_ci "transmitter: card(%d) port(%d)\n", 49618c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 49628c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_NONCAP_TX, 49638c2ecf20Sopenharmony_ci &hc->chan[i + 2].cfg); 49648c2ecf20Sopenharmony_ci } 49658c2ecf20Sopenharmony_ci /* disable E-channel */ 49668c2ecf20Sopenharmony_ci if (port[Port_cnt] & 0x004) { 49678c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 49688c2ecf20Sopenharmony_ci printk(KERN_DEBUG 49698c2ecf20Sopenharmony_ci "%s: PROTOCOL disable E-channel: " 49708c2ecf20Sopenharmony_ci "card(%d) port(%d)\n", 49718c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1); 49728c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CFG_DIS_ECHANNEL, 49738c2ecf20Sopenharmony_ci &hc->chan[i + 2].cfg); 49748c2ecf20Sopenharmony_ci } 49758c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_XHFC) { 49768c2ecf20Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", 49778c2ecf20Sopenharmony_ci HFC_cnt + 1, pt + 1); 49788c2ecf20Sopenharmony_ci ret = mISDN_register_device(&dch->dev, NULL, name); 49798c2ecf20Sopenharmony_ci } else { 49808c2ecf20Sopenharmony_ci snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", 49818c2ecf20Sopenharmony_ci hc->ctype, HFC_cnt + 1, pt + 1); 49828c2ecf20Sopenharmony_ci ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); 49838c2ecf20Sopenharmony_ci } 49848c2ecf20Sopenharmony_ci if (ret) 49858c2ecf20Sopenharmony_ci goto free_chan; 49868c2ecf20Sopenharmony_ci hc->created[pt] = 1; 49878c2ecf20Sopenharmony_ci return ret; 49888c2ecf20Sopenharmony_cifree_chan: 49898c2ecf20Sopenharmony_ci release_port(hc, dch); 49908c2ecf20Sopenharmony_ci return ret; 49918c2ecf20Sopenharmony_ci} 49928c2ecf20Sopenharmony_ci 49938c2ecf20Sopenharmony_cistatic int 49948c2ecf20Sopenharmony_cihfcmulti_init(struct hm_map *m, struct pci_dev *pdev, 49958c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 49968c2ecf20Sopenharmony_ci{ 49978c2ecf20Sopenharmony_ci int ret_err = 0; 49988c2ecf20Sopenharmony_ci int pt; 49998c2ecf20Sopenharmony_ci struct hfc_multi *hc; 50008c2ecf20Sopenharmony_ci u_long flags; 50018c2ecf20Sopenharmony_ci u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ 50028c2ecf20Sopenharmony_ci int i, ch; 50038c2ecf20Sopenharmony_ci u_int maskcheck; 50048c2ecf20Sopenharmony_ci 50058c2ecf20Sopenharmony_ci if (HFC_cnt >= MAX_CARDS) { 50068c2ecf20Sopenharmony_ci printk(KERN_ERR "too many cards (max=%d).\n", 50078c2ecf20Sopenharmony_ci MAX_CARDS); 50088c2ecf20Sopenharmony_ci return -EINVAL; 50098c2ecf20Sopenharmony_ci } 50108c2ecf20Sopenharmony_ci if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { 50118c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " 50128c2ecf20Sopenharmony_ci "type[%d] %d was supplied as module parameter\n", 50138c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, m->type, HFC_cnt, 50148c2ecf20Sopenharmony_ci type[HFC_cnt] & 0xff); 50158c2ecf20Sopenharmony_ci printk(KERN_WARNING "HFC-MULTI: Load module without parameters " 50168c2ecf20Sopenharmony_ci "first, to see cards and their types."); 50178c2ecf20Sopenharmony_ci return -EINVAL; 50188c2ecf20Sopenharmony_ci } 50198c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 50208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", 50218c2ecf20Sopenharmony_ci __func__, m->vendor_name, m->card_name, m->type, 50228c2ecf20Sopenharmony_ci type[HFC_cnt]); 50238c2ecf20Sopenharmony_ci 50248c2ecf20Sopenharmony_ci /* allocate card+fifo structure */ 50258c2ecf20Sopenharmony_ci hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL); 50268c2ecf20Sopenharmony_ci if (!hc) { 50278c2ecf20Sopenharmony_ci printk(KERN_ERR "No kmem for HFC-Multi card\n"); 50288c2ecf20Sopenharmony_ci return -ENOMEM; 50298c2ecf20Sopenharmony_ci } 50308c2ecf20Sopenharmony_ci spin_lock_init(&hc->lock); 50318c2ecf20Sopenharmony_ci hc->mtyp = m; 50328c2ecf20Sopenharmony_ci hc->ctype = m->type; 50338c2ecf20Sopenharmony_ci hc->ports = m->ports; 50348c2ecf20Sopenharmony_ci hc->id = HFC_cnt; 50358c2ecf20Sopenharmony_ci hc->pcm = pcm[HFC_cnt]; 50368c2ecf20Sopenharmony_ci hc->io_mode = iomode[HFC_cnt]; 50378c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) { 50388c2ecf20Sopenharmony_ci /* fragment card */ 50398c2ecf20Sopenharmony_ci pt = 0; 50408c2ecf20Sopenharmony_ci maskcheck = 0; 50418c2ecf20Sopenharmony_ci for (ch = 0; ch <= 31; ch++) { 50428c2ecf20Sopenharmony_ci if (!((1 << ch) & dmask[E1_cnt])) 50438c2ecf20Sopenharmony_ci continue; 50448c2ecf20Sopenharmony_ci hc->dnum[pt] = ch; 50458c2ecf20Sopenharmony_ci hc->bmask[pt] = bmask[bmask_cnt++]; 50468c2ecf20Sopenharmony_ci if ((maskcheck & hc->bmask[pt]) 50478c2ecf20Sopenharmony_ci || (dmask[E1_cnt] & hc->bmask[pt])) { 50488c2ecf20Sopenharmony_ci printk(KERN_INFO 50498c2ecf20Sopenharmony_ci "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", 50508c2ecf20Sopenharmony_ci E1_cnt + 1, pt); 50518c2ecf20Sopenharmony_ci kfree(hc); 50528c2ecf20Sopenharmony_ci return -EINVAL; 50538c2ecf20Sopenharmony_ci } 50548c2ecf20Sopenharmony_ci maskcheck |= hc->bmask[pt]; 50558c2ecf20Sopenharmony_ci printk(KERN_INFO 50568c2ecf20Sopenharmony_ci "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n", 50578c2ecf20Sopenharmony_ci E1_cnt + 1, ch, hc->bmask[pt]); 50588c2ecf20Sopenharmony_ci pt++; 50598c2ecf20Sopenharmony_ci } 50608c2ecf20Sopenharmony_ci hc->ports = pt; 50618c2ecf20Sopenharmony_ci } 50628c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) { 50638c2ecf20Sopenharmony_ci /* default card layout */ 50648c2ecf20Sopenharmony_ci hc->dnum[0] = 16; 50658c2ecf20Sopenharmony_ci hc->bmask[0] = 0xfffefffe; 50668c2ecf20Sopenharmony_ci hc->ports = 1; 50678c2ecf20Sopenharmony_ci } 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci /* set chip specific features */ 50708c2ecf20Sopenharmony_ci hc->masterclk = -1; 50718c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x100) { 50728c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); 50738c2ecf20Sopenharmony_ci hc->silence = 0xff; /* ulaw silence */ 50748c2ecf20Sopenharmony_ci } else 50758c2ecf20Sopenharmony_ci hc->silence = 0x2a; /* alaw silence */ 50768c2ecf20Sopenharmony_ci if ((poll >> 1) > sizeof(hc->silence_data)) { 50778c2ecf20Sopenharmony_ci printk(KERN_ERR "HFCMULTI error: silence_data too small, " 50788c2ecf20Sopenharmony_ci "please fix\n"); 50798c2ecf20Sopenharmony_ci kfree(hc); 50808c2ecf20Sopenharmony_ci return -EINVAL; 50818c2ecf20Sopenharmony_ci } 50828c2ecf20Sopenharmony_ci for (i = 0; i < (poll >> 1); i++) 50838c2ecf20Sopenharmony_ci hc->silence_data[i] = hc->silence; 50848c2ecf20Sopenharmony_ci 50858c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_XHFC) { 50868c2ecf20Sopenharmony_ci if (!(type[HFC_cnt] & 0x200)) 50878c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); 50888c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_CONF, &hc->chip); 50898c2ecf20Sopenharmony_ci } 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x800) 50928c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 50938c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x1000) { 50948c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); 50958c2ecf20Sopenharmony_ci test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); 50968c2ecf20Sopenharmony_ci } 50978c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x4000) 50988c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); 50998c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x8000) 51008c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); 51018c2ecf20Sopenharmony_ci hc->slots = 32; 51028c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x10000) 51038c2ecf20Sopenharmony_ci hc->slots = 64; 51048c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x20000) 51058c2ecf20Sopenharmony_ci hc->slots = 128; 51068c2ecf20Sopenharmony_ci if (type[HFC_cnt] & 0x80000) { 51078c2ecf20Sopenharmony_ci test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); 51088c2ecf20Sopenharmony_ci hc->wdcount = 0; 51098c2ecf20Sopenharmony_ci hc->wdbyte = V_GPIO_OUT2; 51108c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Watchdog enabled\n"); 51118c2ecf20Sopenharmony_ci } 51128c2ecf20Sopenharmony_ci 51138c2ecf20Sopenharmony_ci if (pdev && ent) 51148c2ecf20Sopenharmony_ci /* setup pci, hc->slots may change due to PLXSD */ 51158c2ecf20Sopenharmony_ci ret_err = setup_pci(hc, pdev, ent); 51168c2ecf20Sopenharmony_ci else 51178c2ecf20Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx 51188c2ecf20Sopenharmony_ci ret_err = setup_embedded(hc, m); 51198c2ecf20Sopenharmony_ci#else 51208c2ecf20Sopenharmony_ci { 51218c2ecf20Sopenharmony_ci printk(KERN_WARNING "Embedded IO Mode not selected\n"); 51228c2ecf20Sopenharmony_ci ret_err = -EIO; 51238c2ecf20Sopenharmony_ci } 51248c2ecf20Sopenharmony_ci#endif 51258c2ecf20Sopenharmony_ci if (ret_err) { 51268c2ecf20Sopenharmony_ci if (hc == syncmaster) 51278c2ecf20Sopenharmony_ci syncmaster = NULL; 51288c2ecf20Sopenharmony_ci kfree(hc); 51298c2ecf20Sopenharmony_ci return ret_err; 51308c2ecf20Sopenharmony_ci } 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci hc->HFC_outb_nodebug = hc->HFC_outb; 51338c2ecf20Sopenharmony_ci hc->HFC_inb_nodebug = hc->HFC_inb; 51348c2ecf20Sopenharmony_ci hc->HFC_inw_nodebug = hc->HFC_inw; 51358c2ecf20Sopenharmony_ci hc->HFC_wait_nodebug = hc->HFC_wait; 51368c2ecf20Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG 51378c2ecf20Sopenharmony_ci hc->HFC_outb = HFC_outb_debug; 51388c2ecf20Sopenharmony_ci hc->HFC_inb = HFC_inb_debug; 51398c2ecf20Sopenharmony_ci hc->HFC_inw = HFC_inw_debug; 51408c2ecf20Sopenharmony_ci hc->HFC_wait = HFC_wait_debug; 51418c2ecf20Sopenharmony_ci#endif 51428c2ecf20Sopenharmony_ci /* create channels */ 51438c2ecf20Sopenharmony_ci for (pt = 0; pt < hc->ports; pt++) { 51448c2ecf20Sopenharmony_ci if (Port_cnt >= MAX_PORTS) { 51458c2ecf20Sopenharmony_ci printk(KERN_ERR "too many ports (max=%d).\n", 51468c2ecf20Sopenharmony_ci MAX_PORTS); 51478c2ecf20Sopenharmony_ci ret_err = -EINVAL; 51488c2ecf20Sopenharmony_ci goto free_card; 51498c2ecf20Sopenharmony_ci } 51508c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 51518c2ecf20Sopenharmony_ci ret_err = init_e1_port(hc, m, pt); 51528c2ecf20Sopenharmony_ci else 51538c2ecf20Sopenharmony_ci ret_err = init_multi_port(hc, pt); 51548c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 51558c2ecf20Sopenharmony_ci printk(KERN_DEBUG 51568c2ecf20Sopenharmony_ci "%s: Registering D-channel, card(%d) port(%d) " 51578c2ecf20Sopenharmony_ci "result %d\n", 51588c2ecf20Sopenharmony_ci __func__, HFC_cnt + 1, pt + 1, ret_err); 51598c2ecf20Sopenharmony_ci 51608c2ecf20Sopenharmony_ci if (ret_err) { 51618c2ecf20Sopenharmony_ci while (pt) { /* release already registered ports */ 51628c2ecf20Sopenharmony_ci pt--; 51638c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) 51648c2ecf20Sopenharmony_ci release_port(hc, 51658c2ecf20Sopenharmony_ci hc->chan[hc->dnum[pt]].dch); 51668c2ecf20Sopenharmony_ci else 51678c2ecf20Sopenharmony_ci release_port(hc, 51688c2ecf20Sopenharmony_ci hc->chan[(pt << 2) + 2].dch); 51698c2ecf20Sopenharmony_ci } 51708c2ecf20Sopenharmony_ci goto free_card; 51718c2ecf20Sopenharmony_ci } 51728c2ecf20Sopenharmony_ci if (hc->ctype != HFC_TYPE_E1) 51738c2ecf20Sopenharmony_ci Port_cnt++; /* for each S0 port */ 51748c2ecf20Sopenharmony_ci } 51758c2ecf20Sopenharmony_ci if (hc->ctype == HFC_TYPE_E1) { 51768c2ecf20Sopenharmony_ci Port_cnt++; /* for each E1 port */ 51778c2ecf20Sopenharmony_ci E1_cnt++; 51788c2ecf20Sopenharmony_ci } 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci /* disp switches */ 51818c2ecf20Sopenharmony_ci switch (m->dip_type) { 51828c2ecf20Sopenharmony_ci case DIP_4S: 51838c2ecf20Sopenharmony_ci /* 51848c2ecf20Sopenharmony_ci * Get DIP setting for beroNet 1S/2S/4S cards 51858c2ecf20Sopenharmony_ci * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + 51868c2ecf20Sopenharmony_ci * GPI 19/23 (R_GPI_IN2)) 51878c2ecf20Sopenharmony_ci */ 51888c2ecf20Sopenharmony_ci dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | 51898c2ecf20Sopenharmony_ci ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | 51908c2ecf20Sopenharmony_ci (~HFC_inb(hc, R_GPI_IN2) & 0x08); 51918c2ecf20Sopenharmony_ci 51928c2ecf20Sopenharmony_ci /* Port mode (TE/NT) jumpers */ 51938c2ecf20Sopenharmony_ci pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf); 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci if (test_bit(HFC_CHIP_B410P, &hc->chip)) 51968c2ecf20Sopenharmony_ci pmj = ~pmj & 0xf; 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", 51998c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, dips, pmj); 52008c2ecf20Sopenharmony_ci break; 52018c2ecf20Sopenharmony_ci case DIP_8S: 52028c2ecf20Sopenharmony_ci /* 52038c2ecf20Sopenharmony_ci * Get DIP Setting for beroNet 8S0+ cards 52048c2ecf20Sopenharmony_ci * Enable PCI auxbridge function 52058c2ecf20Sopenharmony_ci */ 52068c2ecf20Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); 52078c2ecf20Sopenharmony_ci /* prepare access to auxport */ 52088c2ecf20Sopenharmony_ci outw(0x4000, hc->pci_iobase + 4); 52098c2ecf20Sopenharmony_ci /* 52108c2ecf20Sopenharmony_ci * some dummy reads are required to 52118c2ecf20Sopenharmony_ci * read valid DIP switch data 52128c2ecf20Sopenharmony_ci */ 52138c2ecf20Sopenharmony_ci dips = inb(hc->pci_iobase); 52148c2ecf20Sopenharmony_ci dips = inb(hc->pci_iobase); 52158c2ecf20Sopenharmony_ci dips = inb(hc->pci_iobase); 52168c2ecf20Sopenharmony_ci dips = ~inb(hc->pci_iobase) & 0x3F; 52178c2ecf20Sopenharmony_ci outw(0x0, hc->pci_iobase + 4); 52188c2ecf20Sopenharmony_ci /* disable PCI auxbridge function */ 52198c2ecf20Sopenharmony_ci HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); 52208c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x)\n", 52218c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, dips); 52228c2ecf20Sopenharmony_ci break; 52238c2ecf20Sopenharmony_ci case DIP_E1: 52248c2ecf20Sopenharmony_ci /* 52258c2ecf20Sopenharmony_ci * get DIP Setting for beroNet E1 cards 52268c2ecf20Sopenharmony_ci * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) 52278c2ecf20Sopenharmony_ci */ 52288c2ecf20Sopenharmony_ci dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0) >> 4; 52298c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s DIPs(0x%x)\n", 52308c2ecf20Sopenharmony_ci m->vendor_name, m->card_name, dips); 52318c2ecf20Sopenharmony_ci break; 52328c2ecf20Sopenharmony_ci } 52338c2ecf20Sopenharmony_ci 52348c2ecf20Sopenharmony_ci /* add to list */ 52358c2ecf20Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 52368c2ecf20Sopenharmony_ci list_add_tail(&hc->list, &HFClist); 52378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_ci /* use as clock source */ 52408c2ecf20Sopenharmony_ci if (clock == HFC_cnt + 1) 52418c2ecf20Sopenharmony_ci hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_ci /* initialize hardware */ 52448c2ecf20Sopenharmony_ci hc->irq = (m->irq) ? : hc->pci_dev->irq; 52458c2ecf20Sopenharmony_ci ret_err = init_card(hc); 52468c2ecf20Sopenharmony_ci if (ret_err) { 52478c2ecf20Sopenharmony_ci printk(KERN_ERR "init card returns %d\n", ret_err); 52488c2ecf20Sopenharmony_ci release_card(hc); 52498c2ecf20Sopenharmony_ci return ret_err; 52508c2ecf20Sopenharmony_ci } 52518c2ecf20Sopenharmony_ci 52528c2ecf20Sopenharmony_ci /* start IRQ and return */ 52538c2ecf20Sopenharmony_ci spin_lock_irqsave(&hc->lock, flags); 52548c2ecf20Sopenharmony_ci enable_hwirq(hc); 52558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hc->lock, flags); 52568c2ecf20Sopenharmony_ci return 0; 52578c2ecf20Sopenharmony_ci 52588c2ecf20Sopenharmony_cifree_card: 52598c2ecf20Sopenharmony_ci release_io_hfcmulti(hc); 52608c2ecf20Sopenharmony_ci if (hc == syncmaster) 52618c2ecf20Sopenharmony_ci syncmaster = NULL; 52628c2ecf20Sopenharmony_ci kfree(hc); 52638c2ecf20Sopenharmony_ci return ret_err; 52648c2ecf20Sopenharmony_ci} 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_cistatic void hfc_remove_pci(struct pci_dev *pdev) 52678c2ecf20Sopenharmony_ci{ 52688c2ecf20Sopenharmony_ci struct hfc_multi *card = pci_get_drvdata(pdev); 52698c2ecf20Sopenharmony_ci u_long flags; 52708c2ecf20Sopenharmony_ci 52718c2ecf20Sopenharmony_ci if (debug) 52728c2ecf20Sopenharmony_ci printk(KERN_INFO "removing hfc_multi card vendor:%x " 52738c2ecf20Sopenharmony_ci "device:%x subvendor:%x subdevice:%x\n", 52748c2ecf20Sopenharmony_ci pdev->vendor, pdev->device, 52758c2ecf20Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device); 52768c2ecf20Sopenharmony_ci 52778c2ecf20Sopenharmony_ci if (card) { 52788c2ecf20Sopenharmony_ci spin_lock_irqsave(&HFClock, flags); 52798c2ecf20Sopenharmony_ci release_card(card); 52808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&HFClock, flags); 52818c2ecf20Sopenharmony_ci } else { 52828c2ecf20Sopenharmony_ci if (debug) 52838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: drvdata already removed\n", 52848c2ecf20Sopenharmony_ci __func__); 52858c2ecf20Sopenharmony_ci } 52868c2ecf20Sopenharmony_ci} 52878c2ecf20Sopenharmony_ci 52888c2ecf20Sopenharmony_ci#define VENDOR_CCD "Cologne Chip AG" 52898c2ecf20Sopenharmony_ci#define VENDOR_BN "beroNet GmbH" 52908c2ecf20Sopenharmony_ci#define VENDOR_DIG "Digium Inc." 52918c2ecf20Sopenharmony_ci#define VENDOR_JH "Junghanns.NET GmbH" 52928c2ecf20Sopenharmony_ci#define VENDOR_PRIM "PrimuX" 52938c2ecf20Sopenharmony_ci 52948c2ecf20Sopenharmony_cistatic const struct hm_map hfcm_map[] = { 52958c2ecf20Sopenharmony_ci /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, 52968c2ecf20Sopenharmony_ci /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 52978c2ecf20Sopenharmony_ci /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 52988c2ecf20Sopenharmony_ci /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 52998c2ecf20Sopenharmony_ci /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, 53008c2ecf20Sopenharmony_ci /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, 53018c2ecf20Sopenharmony_ci /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 53028c2ecf20Sopenharmony_ci /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, 53038c2ecf20Sopenharmony_ci /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, 53048c2ecf20Sopenharmony_ci /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, 53058c2ecf20Sopenharmony_ci /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, 53068c2ecf20Sopenharmony_ci /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, 53078c2ecf20Sopenharmony_ci 53088c2ecf20Sopenharmony_ci /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, 53098c2ecf20Sopenharmony_ci /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, 53108c2ecf20Sopenharmony_ci HFC_IO_MODE_REGIO, 0}, 53118c2ecf20Sopenharmony_ci /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, 53128c2ecf20Sopenharmony_ci /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, 53138c2ecf20Sopenharmony_ci 53148c2ecf20Sopenharmony_ci /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, 53158c2ecf20Sopenharmony_ci /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, 53168c2ecf20Sopenharmony_ci /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 53198c2ecf20Sopenharmony_ci /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, 53208c2ecf20Sopenharmony_ci /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 53218c2ecf20Sopenharmony_ci /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, 53228c2ecf20Sopenharmony_ci 53238c2ecf20Sopenharmony_ci /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, 53248c2ecf20Sopenharmony_ci /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, 53258c2ecf20Sopenharmony_ci /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, 53268c2ecf20Sopenharmony_ci 53278c2ecf20Sopenharmony_ci /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, 53288c2ecf20Sopenharmony_ci HFC_IO_MODE_PLXSD, 0}, 53298c2ecf20Sopenharmony_ci /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, 53308c2ecf20Sopenharmony_ci HFC_IO_MODE_PLXSD, 0}, 53318c2ecf20Sopenharmony_ci /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, 53328c2ecf20Sopenharmony_ci /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, 53338c2ecf20Sopenharmony_ci /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, 53348c2ecf20Sopenharmony_ci /*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, 53358c2ecf20Sopenharmony_ci HFC_IO_MODE_EMBSD, XHFC_IRQ}, 53368c2ecf20Sopenharmony_ci /*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, 53378c2ecf20Sopenharmony_ci /*33*/ {VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, 53388c2ecf20Sopenharmony_ci /*34*/ {VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, 53398c2ecf20Sopenharmony_ci}; 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci#undef H 53428c2ecf20Sopenharmony_ci#define H(x) ((unsigned long)&hfcm_map[x]) 53438c2ecf20Sopenharmony_cistatic const struct pci_device_id hfmultipci_ids[] = { 53448c2ecf20Sopenharmony_ci 53458c2ecf20Sopenharmony_ci /* Cards with HFC-4S Chip */ 53468c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53478c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ 53488c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53498c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ 53508c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53518c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ 53528c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53538c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ 53548c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53558c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ 53568c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53578c2ecf20Sopenharmony_ci PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ 53588c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53598c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ 53608c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53618c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ 53628c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 53638c2ecf20Sopenharmony_ci PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, 53648c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53658c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ 53668c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53678c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, 53688c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53698c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ 53708c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53718c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ 53728c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53738c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ 53748c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53758c2ecf20Sopenharmony_ci 0xb761, 0, 0, H(33)}, /* BN2S PCIe */ 53768c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, 53778c2ecf20Sopenharmony_ci 0xb762, 0, 0, H(34)}, /* BN4S PCIe */ 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci /* Cards with HFC-8S Chip */ 53808c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53818c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ 53828c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53838c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ 53848c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53858c2ecf20Sopenharmony_ci PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ 53868c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53878c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ 53888c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53898c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ 53908c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53918c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */ 53928c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53938c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ 53948c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53958c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ 53968c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, 53978c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */ 53988c2ecf20Sopenharmony_ci 53998c2ecf20Sopenharmony_ci 54008c2ecf20Sopenharmony_ci /* Cards with HFC-E1 Chip */ 54018c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54028c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ 54038c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54048c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ 54058c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54068c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ 54078c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54088c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ 54098c2ecf20Sopenharmony_ci 54108c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54118c2ecf20Sopenharmony_ci PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ 54128c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54138c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ 54148c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54158c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ 54168c2ecf20Sopenharmony_ci 54178c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, 54188c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ 54198c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, 54208c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ 54218c2ecf20Sopenharmony_ci 54228c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, 54238c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ 54248c2ecf20Sopenharmony_ci 54258c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 }, 54268c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 }, 54278c2ecf20Sopenharmony_ci { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 }, 54288c2ecf20Sopenharmony_ci {0, } 54298c2ecf20Sopenharmony_ci}; 54308c2ecf20Sopenharmony_ci#undef H 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfmultipci_ids); 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_cistatic int 54358c2ecf20Sopenharmony_cihfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 54368c2ecf20Sopenharmony_ci{ 54378c2ecf20Sopenharmony_ci struct hm_map *m = (struct hm_map *)ent->driver_data; 54388c2ecf20Sopenharmony_ci int ret; 54398c2ecf20Sopenharmony_ci 54408c2ecf20Sopenharmony_ci if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( 54418c2ecf20Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFC4S || 54428c2ecf20Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFC8S || 54438c2ecf20Sopenharmony_ci ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { 54448c2ecf20Sopenharmony_ci printk(KERN_ERR 54458c2ecf20Sopenharmony_ci "Unknown HFC multiport controller (vendor:%04x device:%04x " 54468c2ecf20Sopenharmony_ci "subvendor:%04x subdevice:%04x)\n", pdev->vendor, 54478c2ecf20Sopenharmony_ci pdev->device, pdev->subsystem_vendor, 54488c2ecf20Sopenharmony_ci pdev->subsystem_device); 54498c2ecf20Sopenharmony_ci printk(KERN_ERR 54508c2ecf20Sopenharmony_ci "Please contact the driver maintainer for support.\n"); 54518c2ecf20Sopenharmony_ci return -ENODEV; 54528c2ecf20Sopenharmony_ci } 54538c2ecf20Sopenharmony_ci ret = hfcmulti_init(m, pdev, ent); 54548c2ecf20Sopenharmony_ci if (ret) 54558c2ecf20Sopenharmony_ci return ret; 54568c2ecf20Sopenharmony_ci HFC_cnt++; 54578c2ecf20Sopenharmony_ci printk(KERN_INFO "%d devices registered\n", HFC_cnt); 54588c2ecf20Sopenharmony_ci return 0; 54598c2ecf20Sopenharmony_ci} 54608c2ecf20Sopenharmony_ci 54618c2ecf20Sopenharmony_cistatic struct pci_driver hfcmultipci_driver = { 54628c2ecf20Sopenharmony_ci .name = "hfc_multi", 54638c2ecf20Sopenharmony_ci .probe = hfcmulti_probe, 54648c2ecf20Sopenharmony_ci .remove = hfc_remove_pci, 54658c2ecf20Sopenharmony_ci .id_table = hfmultipci_ids, 54668c2ecf20Sopenharmony_ci}; 54678c2ecf20Sopenharmony_ci 54688c2ecf20Sopenharmony_cistatic void __exit 54698c2ecf20Sopenharmony_ciHFCmulti_cleanup(void) 54708c2ecf20Sopenharmony_ci{ 54718c2ecf20Sopenharmony_ci struct hfc_multi *card, *next; 54728c2ecf20Sopenharmony_ci 54738c2ecf20Sopenharmony_ci /* get rid of all devices of this driver */ 54748c2ecf20Sopenharmony_ci list_for_each_entry_safe(card, next, &HFClist, list) 54758c2ecf20Sopenharmony_ci release_card(card); 54768c2ecf20Sopenharmony_ci pci_unregister_driver(&hfcmultipci_driver); 54778c2ecf20Sopenharmony_ci} 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_cistatic int __init 54808c2ecf20Sopenharmony_ciHFCmulti_init(void) 54818c2ecf20Sopenharmony_ci{ 54828c2ecf20Sopenharmony_ci int err; 54838c2ecf20Sopenharmony_ci int i, xhfc = 0; 54848c2ecf20Sopenharmony_ci struct hm_map m; 54858c2ecf20Sopenharmony_ci 54868c2ecf20Sopenharmony_ci printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); 54878c2ecf20Sopenharmony_ci 54888c2ecf20Sopenharmony_ci#ifdef IRQ_DEBUG 54898c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); 54908c2ecf20Sopenharmony_ci#endif 54918c2ecf20Sopenharmony_ci 54928c2ecf20Sopenharmony_ci spin_lock_init(&HFClock); 54938c2ecf20Sopenharmony_ci spin_lock_init(&plx_lock); 54948c2ecf20Sopenharmony_ci 54958c2ecf20Sopenharmony_ci if (debug & DEBUG_HFCMULTI_INIT) 54968c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: init entered\n", __func__); 54978c2ecf20Sopenharmony_ci 54988c2ecf20Sopenharmony_ci switch (poll) { 54998c2ecf20Sopenharmony_ci case 0: 55008c2ecf20Sopenharmony_ci poll_timer = 6; 55018c2ecf20Sopenharmony_ci poll = 128; 55028c2ecf20Sopenharmony_ci break; 55038c2ecf20Sopenharmony_ci case 8: 55048c2ecf20Sopenharmony_ci poll_timer = 2; 55058c2ecf20Sopenharmony_ci break; 55068c2ecf20Sopenharmony_ci case 16: 55078c2ecf20Sopenharmony_ci poll_timer = 3; 55088c2ecf20Sopenharmony_ci break; 55098c2ecf20Sopenharmony_ci case 32: 55108c2ecf20Sopenharmony_ci poll_timer = 4; 55118c2ecf20Sopenharmony_ci break; 55128c2ecf20Sopenharmony_ci case 64: 55138c2ecf20Sopenharmony_ci poll_timer = 5; 55148c2ecf20Sopenharmony_ci break; 55158c2ecf20Sopenharmony_ci case 128: 55168c2ecf20Sopenharmony_ci poll_timer = 6; 55178c2ecf20Sopenharmony_ci break; 55188c2ecf20Sopenharmony_ci case 256: 55198c2ecf20Sopenharmony_ci poll_timer = 7; 55208c2ecf20Sopenharmony_ci break; 55218c2ecf20Sopenharmony_ci default: 55228c2ecf20Sopenharmony_ci printk(KERN_ERR 55238c2ecf20Sopenharmony_ci "%s: Wrong poll value (%d).\n", __func__, poll); 55248c2ecf20Sopenharmony_ci err = -EINVAL; 55258c2ecf20Sopenharmony_ci return err; 55268c2ecf20Sopenharmony_ci 55278c2ecf20Sopenharmony_ci } 55288c2ecf20Sopenharmony_ci 55298c2ecf20Sopenharmony_ci if (!clock) 55308c2ecf20Sopenharmony_ci clock = 1; 55318c2ecf20Sopenharmony_ci 55328c2ecf20Sopenharmony_ci /* Register the embedded devices. 55338c2ecf20Sopenharmony_ci * This should be done before the PCI cards registration */ 55348c2ecf20Sopenharmony_ci switch (hwid) { 55358c2ecf20Sopenharmony_ci case HWID_MINIP4: 55368c2ecf20Sopenharmony_ci xhfc = 1; 55378c2ecf20Sopenharmony_ci m = hfcm_map[31]; 55388c2ecf20Sopenharmony_ci break; 55398c2ecf20Sopenharmony_ci case HWID_MINIP8: 55408c2ecf20Sopenharmony_ci xhfc = 2; 55418c2ecf20Sopenharmony_ci m = hfcm_map[31]; 55428c2ecf20Sopenharmony_ci break; 55438c2ecf20Sopenharmony_ci case HWID_MINIP16: 55448c2ecf20Sopenharmony_ci xhfc = 4; 55458c2ecf20Sopenharmony_ci m = hfcm_map[31]; 55468c2ecf20Sopenharmony_ci break; 55478c2ecf20Sopenharmony_ci default: 55488c2ecf20Sopenharmony_ci xhfc = 0; 55498c2ecf20Sopenharmony_ci } 55508c2ecf20Sopenharmony_ci 55518c2ecf20Sopenharmony_ci for (i = 0; i < xhfc; ++i) { 55528c2ecf20Sopenharmony_ci err = hfcmulti_init(&m, NULL, NULL); 55538c2ecf20Sopenharmony_ci if (err) { 55548c2ecf20Sopenharmony_ci printk(KERN_ERR "error registering embedded driver: " 55558c2ecf20Sopenharmony_ci "%x\n", err); 55568c2ecf20Sopenharmony_ci return err; 55578c2ecf20Sopenharmony_ci } 55588c2ecf20Sopenharmony_ci HFC_cnt++; 55598c2ecf20Sopenharmony_ci printk(KERN_INFO "%d devices registered\n", HFC_cnt); 55608c2ecf20Sopenharmony_ci } 55618c2ecf20Sopenharmony_ci 55628c2ecf20Sopenharmony_ci /* Register the PCI cards */ 55638c2ecf20Sopenharmony_ci err = pci_register_driver(&hfcmultipci_driver); 55648c2ecf20Sopenharmony_ci if (err < 0) { 55658c2ecf20Sopenharmony_ci printk(KERN_ERR "error registering pci driver: %x\n", err); 55668c2ecf20Sopenharmony_ci return err; 55678c2ecf20Sopenharmony_ci } 55688c2ecf20Sopenharmony_ci 55698c2ecf20Sopenharmony_ci return 0; 55708c2ecf20Sopenharmony_ci} 55718c2ecf20Sopenharmony_ci 55728c2ecf20Sopenharmony_ci 55738c2ecf20Sopenharmony_cimodule_init(HFCmulti_init); 55748c2ecf20Sopenharmony_cimodule_exit(HFCmulti_cleanup); 5575