| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | * hfcmulti.c  low level driver for hfc-4s/hfc-8s/hfc-e1 based cards | 
|  | 3 | * | 
|  | 4 | * Author	Andreas Eversberg (jolly@eversberg.eu) | 
|  | 5 | * ported to mqueue mechanism: | 
|  | 6 | *		Peter Sprenger (sprengermoving-bytes.de) | 
|  | 7 | * | 
|  | 8 | * inspired by existing hfc-pci driver: | 
|  | 9 | * Copyright 1999  by Werner Cornelius (werner@isdn-development.de) | 
|  | 10 | * Copyright 2008  by Karsten Keil (kkeil@suse.de) | 
|  | 11 | * Copyright 2008  by Andreas Eversberg (jolly@eversberg.eu) | 
|  | 12 | * | 
|  | 13 | * This program is free software; you can redistribute it and/or modify | 
|  | 14 | * it under the terms of the GNU General Public License as published by | 
|  | 15 | * the Free Software Foundation; either version 2, or (at your option) | 
|  | 16 | * any later version. | 
|  | 17 | * | 
|  | 18 | * This program is distributed in the hope that it will be useful, | 
|  | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 21 | * GNU General Public License for more details. | 
|  | 22 | * | 
|  | 23 | * You should have received a copy of the GNU General Public License | 
|  | 24 | * along with this program; if not, write to the Free Software | 
|  | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
|  | 26 | * | 
|  | 27 | * | 
|  | 28 | * Thanks to Cologne Chip AG for this great controller! | 
|  | 29 | */ | 
|  | 30 |  | 
|  | 31 | /* | 
|  | 32 | * module parameters: | 
|  | 33 | * type: | 
|  | 34 | *	By default (0), the card is automatically detected. | 
|  | 35 | *	Or use the following combinations: | 
|  | 36 | *	Bit 0-7   = 0x00001 = HFC-E1 (1 port) | 
|  | 37 | * or	Bit 0-7   = 0x00004 = HFC-4S (4 ports) | 
|  | 38 | * or	Bit 0-7   = 0x00008 = HFC-8S (8 ports) | 
|  | 39 | *	Bit 8     = 0x00100 = uLaw (instead of aLaw) | 
|  | 40 | *	Bit 9     = 0x00200 = Disable DTMF detect on all B-channels via hardware | 
|  | 41 | *	Bit 10    = spare | 
|  | 42 | *	Bit 11    = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) | 
|  | 43 | * or   Bit 12    = 0x01000 = Force PCM bus into master mode. (otherwhise auto) | 
|  | 44 | *	Bit 13	  = spare | 
|  | 45 | *	Bit 14    = 0x04000 = Use external ram (128K) | 
|  | 46 | *	Bit 15    = 0x08000 = Use external ram (512K) | 
|  | 47 | *	Bit 16    = 0x10000 = Use 64 timeslots instead of 32 | 
|  | 48 | * or	Bit 17    = 0x20000 = Use 128 timeslots instead of anything else | 
|  | 49 | *	Bit 18    = spare | 
|  | 50 | *	Bit 19    = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) | 
|  | 51 | * (all other bits are reserved and shall be 0) | 
|  | 52 | *	example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM | 
|  | 53 | *		 bus (PCM master) | 
|  | 54 | * | 
|  | 55 | * port: (optional or required for all ports on all installed cards) | 
|  | 56 | *	HFC-4S/HFC-8S only bits: | 
|  | 57 | *	Bit 0	  = 0x001 = Use master clock for this S/T interface | 
|  | 58 | *			    (ony once per chip). | 
|  | 59 | *	Bit 1     = 0x002 = transmitter line setup (non capacitive mode) | 
|  | 60 | *			    Don't use this unless you know what you are doing! | 
|  | 61 | *	Bit 2     = 0x004 = Disable E-channel. (No E-channel processing) | 
|  | 62 | *	example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock | 
|  | 63 | *		 received from port 1 | 
|  | 64 | * | 
|  | 65 | *	HFC-E1 only bits: | 
|  | 66 | *	Bit 0     = 0x0001 = interface: 0=copper, 1=optical | 
|  | 67 | *	Bit 1     = 0x0002 = reserved (later for 32 B-channels transparent mode) | 
|  | 68 | *	Bit 2     = 0x0004 = Report LOS | 
|  | 69 | *	Bit 3     = 0x0008 = Report AIS | 
|  | 70 | *	Bit 4     = 0x0010 = Report SLIP | 
|  | 71 | *	Bit 5     = 0x0020 = Report RDI | 
|  | 72 | *	Bit 8     = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame | 
|  | 73 | *			     mode instead. | 
|  | 74 | *	Bit 9	  = 0x0200 = Force get clock from interface, even in NT mode. | 
|  | 75 | * or	Bit 10	  = 0x0400 = Force put clock to interface, even in TE mode. | 
|  | 76 | *	Bit 11    = 0x0800 = Use direct RX clock for PCM sync rather than PLL. | 
|  | 77 | *			     (E1 only) | 
|  | 78 | *	Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 | 
|  | 79 | *			     for default. | 
|  | 80 | * (all other bits are reserved and shall be 0) | 
|  | 81 | * | 
|  | 82 | * debug: | 
|  | 83 | *	NOTE: only one debug value must be given for all cards | 
|  | 84 | *	enable debugging (see hfc_multi.h for debug options) | 
|  | 85 | * | 
|  | 86 | * poll: | 
|  | 87 | *	NOTE: only one poll value must be given for all cards | 
|  | 88 | *	Give the number of samples for each fifo process. | 
|  | 89 | *	By default 128 is used. Decrease to reduce delay, increase to | 
|  | 90 | *	reduce cpu load. If unsure, don't mess with it! | 
|  | 91 | *	Valid is 8, 16, 32, 64, 128, 256. | 
|  | 92 | * | 
|  | 93 | * pcm: | 
|  | 94 | *	NOTE: only one pcm value must be given for every card. | 
|  | 95 | *	The PCM bus id tells the mISDNdsp module about the connected PCM bus. | 
|  | 96 | *	By default (0), the PCM bus id is 100 for the card that is PCM master. | 
|  | 97 | *	If multiple cards are PCM master (because they are not interconnected), | 
|  | 98 | *	each card with PCM master will have increasing PCM id. | 
|  | 99 | *	All PCM busses with the same ID are expected to be connected and have | 
|  | 100 | *	common time slots slots. | 
|  | 101 | *	Only one chip of the PCM bus must be master, the others slave. | 
|  | 102 | *	-1 means no support of PCM bus not even. | 
|  | 103 | *	Omit this value, if all cards are interconnected or none is connected. | 
|  | 104 | *	If unsure, don't give this parameter. | 
|  | 105 | * | 
|  | 106 | * dslot: | 
| Frank Seidel | 44e0958 | 2009-05-22 11:04:47 +0000 | [diff] [blame] | 107 | *	NOTE: only one dslot value must be given for every card. | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 108 | *	Also this value must be given for non-E1 cards. If omitted, the E1 | 
|  | 109 | *	card has D-channel on time slot 16, which is default. | 
|  | 110 | *	If 1..15 or 17..31, an alternate time slot is used for D-channel. | 
|  | 111 | *	In this case, the application must be able to handle this. | 
|  | 112 | *	If -1 is given, the D-channel is disabled and all 31 slots can be used | 
|  | 113 | *	for B-channel. (only for specific applications) | 
|  | 114 | *	If you don't know how to use it, you don't need it! | 
|  | 115 | * | 
|  | 116 | * iomode: | 
|  | 117 | *	NOTE: only one mode value must be given for every card. | 
|  | 118 | *	-> See hfc_multi.h for HFC_IO_MODE_* values | 
|  | 119 | *	By default, the IO mode is pci memory IO (MEMIO). | 
| Gilles Espinasse | f77f13e | 2010-03-29 15:41:47 +0200 | [diff] [blame] | 120 | *	Some cards require specific IO mode, so it cannot be changed. | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 121 | *	It may be usefull to set IO mode to register io (REGIO) to solve | 
|  | 122 | *	PCI bridge problems. | 
|  | 123 | *	If unsure, don't give this parameter. | 
|  | 124 | * | 
|  | 125 | * clockdelay_nt: | 
|  | 126 | *	NOTE: only one clockdelay_nt value must be given once for all cards. | 
|  | 127 | *	Give the value of the clock control register (A_ST_CLK_DLY) | 
|  | 128 | *	of the S/T interfaces in NT mode. | 
|  | 129 | *	This register is needed for the TBR3 certification, so don't change it. | 
|  | 130 | * | 
|  | 131 | * clockdelay_te: | 
|  | 132 | *	NOTE: only one clockdelay_te value must be given once | 
|  | 133 | *	Give the value of the clock control register (A_ST_CLK_DLY) | 
|  | 134 | *	of the S/T interfaces in TE mode. | 
|  | 135 | *	This register is needed for the TBR3 certification, so don't change it. | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 136 | * | 
|  | 137 | * clock: | 
| Andreas Eversberg | 1b36c78 | 2008-09-20 13:43:28 +0200 | [diff] [blame] | 138 | *	NOTE: only one clock value must be given once | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 139 | *	Selects interface with clock source for mISDN and applications. | 
|  | 140 | *	Set to card number starting with 1. Set to -1 to disable. | 
|  | 141 | *	By default, the first card is used as clock source. | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 142 | * | 
|  | 143 | * hwid: | 
|  | 144 | *	NOTE: only one hwid value must be given once | 
|  | 145 | * 	Enable special embedded devices with XHFC controllers. | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 146 | */ | 
|  | 147 |  | 
|  | 148 | /* | 
|  | 149 | * debug register access (never use this, it will flood your system log) | 
|  | 150 | * #define HFC_REGISTER_DEBUG | 
|  | 151 | */ | 
|  | 152 |  | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 153 | #define HFC_MULTI_VERSION	"2.03" | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 154 |  | 
|  | 155 | #include <linux/module.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 156 | #include <linux/slab.h> | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 157 | #include <linux/pci.h> | 
|  | 158 | #include <linux/delay.h> | 
|  | 159 | #include <linux/mISDNhw.h> | 
|  | 160 | #include <linux/mISDNdsp.h> | 
|  | 161 |  | 
|  | 162 | /* | 
|  | 163 | #define IRQCOUNT_DEBUG | 
|  | 164 | #define IRQ_DEBUG | 
|  | 165 | */ | 
|  | 166 |  | 
|  | 167 | #include "hfc_multi.h" | 
|  | 168 | #ifdef ECHOPREP | 
|  | 169 | #include "gaintab.h" | 
|  | 170 | #endif | 
|  | 171 |  | 
|  | 172 | #define	MAX_CARDS	8 | 
|  | 173 | #define	MAX_PORTS	(8 * MAX_CARDS) | 
|  | 174 |  | 
|  | 175 | static LIST_HEAD(HFClist); | 
|  | 176 | static spinlock_t HFClock; /* global hfc list lock */ | 
|  | 177 |  | 
|  | 178 | static void ph_state_change(struct dchannel *); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 179 |  | 
|  | 180 | static struct hfc_multi *syncmaster; | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 181 | static int plxsd_master; /* if we have a master card (yet) */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 182 | static spinlock_t plx_lock; /* may not acquire other lock inside */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 183 |  | 
|  | 184 | #define	TYP_E1		1 | 
|  | 185 | #define	TYP_4S		4 | 
|  | 186 | #define TYP_8S		8 | 
|  | 187 |  | 
|  | 188 | static int poll_timer = 6;	/* default = 128 samples = 16ms */ | 
|  | 189 | /* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ | 
|  | 190 | static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30  }; | 
|  | 191 | #define	CLKDEL_TE	0x0f	/* CLKDEL in TE mode */ | 
|  | 192 | #define	CLKDEL_NT	0x6c	/* CLKDEL in NT mode | 
|  | 193 | (0x60 MUST be included!) */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 194 |  | 
|  | 195 | #define	DIP_4S	0x1		/* DIP Switches for Beronet 1S/2S/4S cards */ | 
|  | 196 | #define	DIP_8S	0x2		/* DIP Switches for Beronet 8S+ cards */ | 
|  | 197 | #define	DIP_E1	0x3		/* DIP Switches for Beronet E1 cards */ | 
|  | 198 |  | 
|  | 199 | /* | 
|  | 200 | * module stuff | 
|  | 201 | */ | 
|  | 202 |  | 
|  | 203 | static uint	type[MAX_CARDS]; | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 204 | static int	pcm[MAX_CARDS]; | 
|  | 205 | static int	dslot[MAX_CARDS]; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 206 | static uint	iomode[MAX_CARDS]; | 
|  | 207 | static uint	port[MAX_PORTS]; | 
|  | 208 | static uint	debug; | 
|  | 209 | static uint	poll; | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 210 | static int	clock; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 211 | static uint	timer; | 
|  | 212 | static uint	clockdelay_te = CLKDEL_TE; | 
|  | 213 | static uint	clockdelay_nt = CLKDEL_NT; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 214 | #define HWID_NONE	0 | 
|  | 215 | #define HWID_MINIP4	1 | 
|  | 216 | #define HWID_MINIP8	2 | 
|  | 217 | #define HWID_MINIP16	3 | 
|  | 218 | static uint	hwid = HWID_NONE; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 219 |  | 
|  | 220 | static int	HFC_cnt, Port_cnt, PCM_cnt = 99; | 
|  | 221 |  | 
|  | 222 | MODULE_AUTHOR("Andreas Eversberg"); | 
|  | 223 | MODULE_LICENSE("GPL"); | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 224 | MODULE_VERSION(HFC_MULTI_VERSION); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 225 | module_param(debug, uint, S_IRUGO | S_IWUSR); | 
|  | 226 | module_param(poll, uint, S_IRUGO | S_IWUSR); | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 227 | module_param(clock, int, S_IRUGO | S_IWUSR); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 228 | module_param(timer, uint, S_IRUGO | S_IWUSR); | 
|  | 229 | module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); | 
|  | 230 | module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); | 
|  | 231 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 232 | module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); | 
|  | 233 | module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 234 | module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); | 
|  | 235 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 236 | module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 237 |  | 
|  | 238 | #ifdef HFC_REGISTER_DEBUG | 
|  | 239 | #define HFC_outb(hc, reg, val) \ | 
|  | 240 | (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) | 
|  | 241 | #define HFC_outb_nodebug(hc, reg, val) \ | 
|  | 242 | (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) | 
|  | 243 | #define HFC_inb(hc, reg) \ | 
|  | 244 | (hc->HFC_inb(hc, reg, __func__, __LINE__)) | 
|  | 245 | #define HFC_inb_nodebug(hc, reg) \ | 
|  | 246 | (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) | 
|  | 247 | #define HFC_inw(hc, reg) \ | 
|  | 248 | (hc->HFC_inw(hc, reg, __func__, __LINE__)) | 
|  | 249 | #define HFC_inw_nodebug(hc, reg) \ | 
|  | 250 | (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) | 
|  | 251 | #define HFC_wait(hc) \ | 
|  | 252 | (hc->HFC_wait(hc, __func__, __LINE__)) | 
|  | 253 | #define HFC_wait_nodebug(hc) \ | 
|  | 254 | (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) | 
|  | 255 | #else | 
|  | 256 | #define HFC_outb(hc, reg, val)		(hc->HFC_outb(hc, reg, val)) | 
|  | 257 | #define HFC_outb_nodebug(hc, reg, val)	(hc->HFC_outb_nodebug(hc, reg, val)) | 
|  | 258 | #define HFC_inb(hc, reg)		(hc->HFC_inb(hc, reg)) | 
|  | 259 | #define HFC_inb_nodebug(hc, reg)	(hc->HFC_inb_nodebug(hc, reg)) | 
|  | 260 | #define HFC_inw(hc, reg)		(hc->HFC_inw(hc, reg)) | 
|  | 261 | #define HFC_inw_nodebug(hc, reg)	(hc->HFC_inw_nodebug(hc, reg)) | 
|  | 262 | #define HFC_wait(hc)			(hc->HFC_wait(hc)) | 
|  | 263 | #define HFC_wait_nodebug(hc)		(hc->HFC_wait_nodebug(hc)) | 
|  | 264 | #endif | 
|  | 265 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 266 | #ifdef CONFIG_MISDN_HFCMULTI_8xx | 
|  | 267 | #include "hfc_multi_8xx.h" | 
|  | 268 | #endif | 
|  | 269 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 270 | /* HFC_IO_MODE_PCIMEM */ | 
|  | 271 | static void | 
|  | 272 | #ifdef HFC_REGISTER_DEBUG | 
|  | 273 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, | 
|  | 274 | const char *function, int line) | 
|  | 275 | #else | 
|  | 276 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) | 
|  | 277 | #endif | 
|  | 278 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 279 | writeb(val, hc->pci_membase + reg); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 280 | } | 
|  | 281 | static u_char | 
|  | 282 | #ifdef HFC_REGISTER_DEBUG | 
|  | 283 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 284 | #else | 
|  | 285 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) | 
|  | 286 | #endif | 
|  | 287 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 288 | return readb(hc->pci_membase + reg); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 289 | } | 
|  | 290 | static u_short | 
|  | 291 | #ifdef HFC_REGISTER_DEBUG | 
|  | 292 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 293 | #else | 
|  | 294 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) | 
|  | 295 | #endif | 
|  | 296 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 297 | return readw(hc->pci_membase + reg); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 298 | } | 
|  | 299 | static void | 
|  | 300 | #ifdef HFC_REGISTER_DEBUG | 
|  | 301 | HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) | 
|  | 302 | #else | 
|  | 303 | HFC_wait_pcimem(struct hfc_multi *hc) | 
|  | 304 | #endif | 
|  | 305 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 306 | while (readb(hc->pci_membase + R_STATUS) & V_BUSY) | 
|  | 307 | cpu_relax(); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 308 | } | 
|  | 309 |  | 
|  | 310 | /* HFC_IO_MODE_REGIO */ | 
|  | 311 | static void | 
|  | 312 | #ifdef HFC_REGISTER_DEBUG | 
|  | 313 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, | 
|  | 314 | const char *function, int line) | 
|  | 315 | #else | 
|  | 316 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) | 
|  | 317 | #endif | 
|  | 318 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 319 | outb(reg, hc->pci_iobase + 4); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 320 | outb(val, hc->pci_iobase); | 
|  | 321 | } | 
|  | 322 | static u_char | 
|  | 323 | #ifdef HFC_REGISTER_DEBUG | 
|  | 324 | HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 325 | #else | 
|  | 326 | HFC_inb_regio(struct hfc_multi *hc, u_char reg) | 
|  | 327 | #endif | 
|  | 328 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 329 | outb(reg, hc->pci_iobase + 4); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 330 | return inb(hc->pci_iobase); | 
|  | 331 | } | 
|  | 332 | static u_short | 
|  | 333 | #ifdef HFC_REGISTER_DEBUG | 
|  | 334 | HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 335 | #else | 
|  | 336 | HFC_inw_regio(struct hfc_multi *hc, u_char reg) | 
|  | 337 | #endif | 
|  | 338 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 339 | outb(reg, hc->pci_iobase + 4); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 340 | return inw(hc->pci_iobase); | 
|  | 341 | } | 
|  | 342 | static void | 
|  | 343 | #ifdef HFC_REGISTER_DEBUG | 
|  | 344 | HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) | 
|  | 345 | #else | 
|  | 346 | HFC_wait_regio(struct hfc_multi *hc) | 
|  | 347 | #endif | 
|  | 348 | { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 349 | outb(R_STATUS, hc->pci_iobase + 4); | 
|  | 350 | while (inb(hc->pci_iobase) & V_BUSY) | 
|  | 351 | cpu_relax(); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 352 | } | 
|  | 353 |  | 
|  | 354 | #ifdef HFC_REGISTER_DEBUG | 
|  | 355 | static void | 
|  | 356 | HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, | 
|  | 357 | const char *function, int line) | 
|  | 358 | { | 
|  | 359 | char regname[256] = "", bits[9] = "xxxxxxxx"; | 
|  | 360 | int i; | 
|  | 361 |  | 
|  | 362 | i = -1; | 
|  | 363 | while (hfc_register_names[++i].name) { | 
|  | 364 | if (hfc_register_names[i].reg == reg) | 
|  | 365 | strcat(regname, hfc_register_names[i].name); | 
|  | 366 | } | 
|  | 367 | if (regname[0] == '\0') | 
|  | 368 | strcpy(regname, "register"); | 
|  | 369 |  | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 370 | bits[7] = '0' + (!!(val & 1)); | 
|  | 371 | bits[6] = '0' + (!!(val & 2)); | 
|  | 372 | bits[5] = '0' + (!!(val & 4)); | 
|  | 373 | bits[4] = '0' + (!!(val & 8)); | 
|  | 374 | bits[3] = '0' + (!!(val & 16)); | 
|  | 375 | bits[2] = '0' + (!!(val & 32)); | 
|  | 376 | bits[1] = '0' + (!!(val & 64)); | 
|  | 377 | bits[0] = '0' + (!!(val & 128)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 378 | printk(KERN_DEBUG | 
|  | 379 | "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", | 
|  | 380 | hc->id, reg, regname, val, bits, function, line); | 
|  | 381 | HFC_outb_nodebug(hc, reg, val); | 
|  | 382 | } | 
|  | 383 | static u_char | 
|  | 384 | HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 385 | { | 
|  | 386 | char regname[256] = "", bits[9] = "xxxxxxxx"; | 
|  | 387 | u_char val = HFC_inb_nodebug(hc, reg); | 
|  | 388 | int i; | 
|  | 389 |  | 
|  | 390 | i = 0; | 
|  | 391 | while (hfc_register_names[i++].name) | 
|  | 392 | ; | 
|  | 393 | while (hfc_register_names[++i].name) { | 
|  | 394 | if (hfc_register_names[i].reg == reg) | 
|  | 395 | strcat(regname, hfc_register_names[i].name); | 
|  | 396 | } | 
|  | 397 | if (regname[0] == '\0') | 
|  | 398 | strcpy(regname, "register"); | 
|  | 399 |  | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 400 | bits[7] = '0' + (!!(val & 1)); | 
|  | 401 | bits[6] = '0' + (!!(val & 2)); | 
|  | 402 | bits[5] = '0' + (!!(val & 4)); | 
|  | 403 | bits[4] = '0' + (!!(val & 8)); | 
|  | 404 | bits[3] = '0' + (!!(val & 16)); | 
|  | 405 | bits[2] = '0' + (!!(val & 32)); | 
|  | 406 | bits[1] = '0' + (!!(val & 64)); | 
|  | 407 | bits[0] = '0' + (!!(val & 128)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 408 | printk(KERN_DEBUG | 
|  | 409 | "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", | 
|  | 410 | hc->id, reg, regname, val, bits, function, line); | 
|  | 411 | return val; | 
|  | 412 | } | 
|  | 413 | static u_short | 
|  | 414 | HFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | 
|  | 415 | { | 
|  | 416 | char regname[256] = ""; | 
|  | 417 | u_short val = HFC_inw_nodebug(hc, reg); | 
|  | 418 | int i; | 
|  | 419 |  | 
|  | 420 | i = 0; | 
|  | 421 | while (hfc_register_names[i++].name) | 
|  | 422 | ; | 
|  | 423 | while (hfc_register_names[++i].name) { | 
|  | 424 | if (hfc_register_names[i].reg == reg) | 
|  | 425 | strcat(regname, hfc_register_names[i].name); | 
|  | 426 | } | 
|  | 427 | if (regname[0] == '\0') | 
|  | 428 | strcpy(regname, "register"); | 
|  | 429 |  | 
|  | 430 | printk(KERN_DEBUG | 
|  | 431 | "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", | 
|  | 432 | hc->id, reg, regname, val, function, line); | 
|  | 433 | return val; | 
|  | 434 | } | 
|  | 435 | static void | 
|  | 436 | HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) | 
|  | 437 | { | 
|  | 438 | printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", | 
|  | 439 | hc->id, function, line); | 
|  | 440 | HFC_wait_nodebug(hc); | 
|  | 441 | } | 
|  | 442 | #endif | 
|  | 443 |  | 
|  | 444 | /* write fifo data (REGIO) */ | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 445 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 446 | write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | 
|  | 447 | { | 
|  | 448 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | 
|  | 449 | while (len>>2) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 450 | outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 451 | data += 4; | 
|  | 452 | len -= 4; | 
|  | 453 | } | 
|  | 454 | while (len>>1) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 455 | outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 456 | data += 2; | 
|  | 457 | len -= 2; | 
|  | 458 | } | 
|  | 459 | while (len) { | 
|  | 460 | outb(*data, hc->pci_iobase); | 
|  | 461 | data++; | 
|  | 462 | len--; | 
|  | 463 | } | 
|  | 464 | } | 
|  | 465 | /* write fifo data (PCIMEM) */ | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 466 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 467 | write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | 
|  | 468 | { | 
|  | 469 | while (len>>2) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 470 | writel(cpu_to_le32(*(u32 *)data), | 
|  | 471 | hc->pci_membase + A_FIFO_DATA0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 472 | data += 4; | 
|  | 473 | len -= 4; | 
|  | 474 | } | 
|  | 475 | while (len>>1) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 476 | writew(cpu_to_le16(*(u16 *)data), | 
|  | 477 | hc->pci_membase + A_FIFO_DATA0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 478 | data += 2; | 
|  | 479 | len -= 2; | 
|  | 480 | } | 
|  | 481 | while (len) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 482 | writeb(*data, hc->pci_membase + A_FIFO_DATA0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 483 | data++; | 
|  | 484 | len--; | 
|  | 485 | } | 
|  | 486 | } | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 487 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 488 | /* read fifo data (REGIO) */ | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 489 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 490 | read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | 
|  | 491 | { | 
|  | 492 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | 
|  | 493 | while (len>>2) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 494 | *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 495 | data += 4; | 
|  | 496 | len -= 4; | 
|  | 497 | } | 
|  | 498 | while (len>>1) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 499 | *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 500 | data += 2; | 
|  | 501 | len -= 2; | 
|  | 502 | } | 
|  | 503 | while (len) { | 
|  | 504 | *data = inb(hc->pci_iobase); | 
|  | 505 | data++; | 
|  | 506 | len--; | 
|  | 507 | } | 
|  | 508 | } | 
|  | 509 |  | 
|  | 510 | /* read fifo data (PCIMEM) */ | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 511 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 512 | read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | 
|  | 513 | { | 
|  | 514 | while (len>>2) { | 
|  | 515 | *(u32 *)data = | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 516 | le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 517 | data += 4; | 
|  | 518 | len -= 4; | 
|  | 519 | } | 
|  | 520 | while (len>>1) { | 
|  | 521 | *(u16 *)data = | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 522 | le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 523 | data += 2; | 
|  | 524 | len -= 2; | 
|  | 525 | } | 
|  | 526 | while (len) { | 
| Karsten Keil | b3e0aee | 2008-08-02 16:35:53 +0200 | [diff] [blame] | 527 | *data = readb(hc->pci_membase + A_FIFO_DATA0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 528 | data++; | 
|  | 529 | len--; | 
|  | 530 | } | 
|  | 531 | } | 
|  | 532 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 533 | static void | 
|  | 534 | enable_hwirq(struct hfc_multi *hc) | 
|  | 535 | { | 
|  | 536 | hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; | 
|  | 537 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | 
|  | 538 | } | 
|  | 539 |  | 
|  | 540 | static void | 
|  | 541 | disable_hwirq(struct hfc_multi *hc) | 
|  | 542 | { | 
|  | 543 | hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); | 
|  | 544 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | 
|  | 545 | } | 
|  | 546 |  | 
|  | 547 | #define	NUM_EC 2 | 
|  | 548 | #define	MAX_TDM_CHAN 32 | 
|  | 549 |  | 
|  | 550 |  | 
|  | 551 | inline void | 
|  | 552 | enablepcibridge(struct hfc_multi *c) | 
|  | 553 | { | 
|  | 554 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | inline void | 
|  | 558 | disablepcibridge(struct hfc_multi *c) | 
|  | 559 | { | 
|  | 560 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | inline unsigned char | 
|  | 564 | readpcibridge(struct hfc_multi *hc, unsigned char address) | 
|  | 565 | { | 
|  | 566 | unsigned short cipv; | 
|  | 567 | unsigned char data; | 
|  | 568 |  | 
|  | 569 | if (!hc->pci_iobase) | 
|  | 570 | return 0; | 
|  | 571 |  | 
|  | 572 | /* slow down a PCI read access by 1 PCI clock cycle */ | 
|  | 573 | HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ | 
|  | 574 |  | 
|  | 575 | if (address == 0) | 
|  | 576 | cipv = 0x4000; | 
|  | 577 | else | 
|  | 578 | cipv = 0x5800; | 
|  | 579 |  | 
|  | 580 | /* select local bridge port address by writing to CIP port */ | 
|  | 581 | /* data = HFC_inb(c, cipv); * was _io before */ | 
|  | 582 | outw(cipv, hc->pci_iobase + 4); | 
|  | 583 | data = inb(hc->pci_iobase); | 
|  | 584 |  | 
|  | 585 | /* restore R_CTRL for normal PCI read cycle speed */ | 
|  | 586 | HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ | 
|  | 587 |  | 
|  | 588 | return data; | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | inline void | 
|  | 592 | writepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) | 
|  | 593 | { | 
|  | 594 | unsigned short cipv; | 
|  | 595 | unsigned int datav; | 
|  | 596 |  | 
|  | 597 | if (!hc->pci_iobase) | 
|  | 598 | return; | 
|  | 599 |  | 
|  | 600 | if (address == 0) | 
|  | 601 | cipv = 0x4000; | 
|  | 602 | else | 
|  | 603 | cipv = 0x5800; | 
|  | 604 |  | 
|  | 605 | /* select local bridge port address by writing to CIP port */ | 
|  | 606 | outw(cipv, hc->pci_iobase + 4); | 
|  | 607 | /* define a 32 bit dword with 4 identical bytes for write sequence */ | 
|  | 608 | datav = data | ((__u32) data << 8) | ((__u32) data << 16) | | 
|  | 609 | ((__u32) data << 24); | 
|  | 610 |  | 
|  | 611 | /* | 
|  | 612 | * write this 32 bit dword to the bridge data port | 
|  | 613 | * this will initiate a write sequence of up to 4 writes to the same | 
|  | 614 | * address on the local bus interface the number of write accesses | 
|  | 615 | * is undefined but >=1 and depends on the next PCI transaction | 
|  | 616 | * during write sequence on the local bus | 
|  | 617 | */ | 
|  | 618 | outl(datav, hc->pci_iobase); | 
|  | 619 | } | 
|  | 620 |  | 
|  | 621 | inline void | 
|  | 622 | cpld_set_reg(struct hfc_multi *hc, unsigned char reg) | 
|  | 623 | { | 
|  | 624 | /* Do data pin read low byte */ | 
|  | 625 | HFC_outb(hc, R_GPIO_OUT1, reg); | 
|  | 626 | } | 
|  | 627 |  | 
|  | 628 | inline void | 
|  | 629 | cpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) | 
|  | 630 | { | 
|  | 631 | cpld_set_reg(hc, reg); | 
|  | 632 |  | 
|  | 633 | enablepcibridge(hc); | 
|  | 634 | writepcibridge(hc, 1, val); | 
|  | 635 | disablepcibridge(hc); | 
|  | 636 |  | 
|  | 637 | return; | 
|  | 638 | } | 
|  | 639 |  | 
|  | 640 | inline unsigned char | 
|  | 641 | cpld_read_reg(struct hfc_multi *hc, unsigned char reg) | 
|  | 642 | { | 
|  | 643 | unsigned char bytein; | 
|  | 644 |  | 
|  | 645 | cpld_set_reg(hc, reg); | 
|  | 646 |  | 
|  | 647 | /* Do data pin read low byte */ | 
|  | 648 | HFC_outb(hc, R_GPIO_OUT1, reg); | 
|  | 649 |  | 
|  | 650 | enablepcibridge(hc); | 
|  | 651 | bytein = readpcibridge(hc, 1); | 
|  | 652 | disablepcibridge(hc); | 
|  | 653 |  | 
|  | 654 | return bytein; | 
|  | 655 | } | 
|  | 656 |  | 
|  | 657 | inline void | 
|  | 658 | vpm_write_address(struct hfc_multi *hc, unsigned short addr) | 
|  | 659 | { | 
|  | 660 | cpld_write_reg(hc, 0, 0xff & addr); | 
|  | 661 | cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); | 
|  | 662 | } | 
|  | 663 |  | 
|  | 664 | inline unsigned short | 
|  | 665 | vpm_read_address(struct hfc_multi *c) | 
|  | 666 | { | 
|  | 667 | unsigned short addr; | 
|  | 668 | unsigned short highbit; | 
|  | 669 |  | 
|  | 670 | addr = cpld_read_reg(c, 0); | 
|  | 671 | highbit = cpld_read_reg(c, 1); | 
|  | 672 |  | 
|  | 673 | addr = addr | (highbit << 8); | 
|  | 674 |  | 
|  | 675 | return addr & 0x1ff; | 
|  | 676 | } | 
|  | 677 |  | 
|  | 678 | inline unsigned char | 
|  | 679 | vpm_in(struct hfc_multi *c, int which, unsigned short addr) | 
|  | 680 | { | 
|  | 681 | unsigned char res; | 
|  | 682 |  | 
|  | 683 | vpm_write_address(c, addr); | 
|  | 684 |  | 
|  | 685 | if (!which) | 
|  | 686 | cpld_set_reg(c, 2); | 
|  | 687 | else | 
|  | 688 | cpld_set_reg(c, 3); | 
|  | 689 |  | 
|  | 690 | enablepcibridge(c); | 
|  | 691 | res = readpcibridge(c, 1); | 
|  | 692 | disablepcibridge(c); | 
|  | 693 |  | 
|  | 694 | cpld_set_reg(c, 0); | 
|  | 695 |  | 
|  | 696 | return res; | 
|  | 697 | } | 
|  | 698 |  | 
|  | 699 | inline void | 
|  | 700 | vpm_out(struct hfc_multi *c, int which, unsigned short addr, | 
|  | 701 | unsigned char data) | 
|  | 702 | { | 
|  | 703 | vpm_write_address(c, addr); | 
|  | 704 |  | 
|  | 705 | enablepcibridge(c); | 
|  | 706 |  | 
|  | 707 | if (!which) | 
|  | 708 | cpld_set_reg(c, 2); | 
|  | 709 | else | 
|  | 710 | cpld_set_reg(c, 3); | 
|  | 711 |  | 
|  | 712 | writepcibridge(c, 1, data); | 
|  | 713 |  | 
|  | 714 | cpld_set_reg(c, 0); | 
|  | 715 |  | 
|  | 716 | disablepcibridge(c); | 
|  | 717 |  | 
|  | 718 | { | 
|  | 719 | unsigned char regin; | 
|  | 720 | regin = vpm_in(c, which, addr); | 
|  | 721 | if (regin != data) | 
|  | 722 | printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " | 
|  | 723 | "0x%x\n", data, addr, regin); | 
|  | 724 | } | 
|  | 725 |  | 
|  | 726 | } | 
|  | 727 |  | 
|  | 728 |  | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 729 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 730 | vpm_init(struct hfc_multi *wc) | 
|  | 731 | { | 
|  | 732 | unsigned char reg; | 
|  | 733 | unsigned int mask; | 
|  | 734 | unsigned int i, x, y; | 
|  | 735 | unsigned int ver; | 
|  | 736 |  | 
|  | 737 | for (x = 0; x < NUM_EC; x++) { | 
|  | 738 | /* Setup GPIO's */ | 
|  | 739 | if (!x) { | 
|  | 740 | ver = vpm_in(wc, x, 0x1a0); | 
|  | 741 | printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); | 
|  | 742 | } | 
|  | 743 |  | 
|  | 744 | for (y = 0; y < 4; y++) { | 
|  | 745 | vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ | 
|  | 746 | vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ | 
|  | 747 | vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ | 
|  | 748 | } | 
|  | 749 |  | 
|  | 750 | /* Setup TDM path - sets fsync and tdm_clk as inputs */ | 
|  | 751 | reg = vpm_in(wc, x, 0x1a3); /* misc_con */ | 
|  | 752 | vpm_out(wc, x, 0x1a3, reg & ~2); | 
|  | 753 |  | 
|  | 754 | /* Setup Echo length (256 taps) */ | 
|  | 755 | vpm_out(wc, x, 0x022, 1); | 
|  | 756 | vpm_out(wc, x, 0x023, 0xff); | 
|  | 757 |  | 
|  | 758 | /* Setup timeslots */ | 
|  | 759 | vpm_out(wc, x, 0x02f, 0x00); | 
|  | 760 | mask = 0x02020202 << (x * 4); | 
|  | 761 |  | 
|  | 762 | /* Setup the tdm channel masks for all chips */ | 
|  | 763 | for (i = 0; i < 4; i++) | 
|  | 764 | vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); | 
|  | 765 |  | 
|  | 766 | /* Setup convergence rate */ | 
|  | 767 | printk(KERN_DEBUG "VPM: A-law mode\n"); | 
|  | 768 | reg = 0x00 | 0x10 | 0x01; | 
|  | 769 | vpm_out(wc, x, 0x20, reg); | 
|  | 770 | printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); | 
|  | 771 | /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ | 
|  | 772 |  | 
|  | 773 | vpm_out(wc, x, 0x24, 0x02); | 
|  | 774 | reg = vpm_in(wc, x, 0x24); | 
|  | 775 | printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); | 
|  | 776 |  | 
|  | 777 | /* Initialize echo cans */ | 
|  | 778 | for (i = 0; i < MAX_TDM_CHAN; i++) { | 
|  | 779 | if (mask & (0x00000001 << i)) | 
|  | 780 | vpm_out(wc, x, i, 0x00); | 
|  | 781 | } | 
|  | 782 |  | 
|  | 783 | /* | 
|  | 784 | * ARM arch at least disallows a udelay of | 
|  | 785 | * more than 2ms... it gives a fake "__bad_udelay" | 
|  | 786 | * reference at link-time. | 
|  | 787 | * long delays in kernel code are pretty sucky anyway | 
|  | 788 | * for now work around it using 5 x 2ms instead of 1 x 10ms | 
|  | 789 | */ | 
|  | 790 |  | 
|  | 791 | udelay(2000); | 
|  | 792 | udelay(2000); | 
|  | 793 | udelay(2000); | 
|  | 794 | udelay(2000); | 
|  | 795 | udelay(2000); | 
|  | 796 |  | 
|  | 797 | /* Put in bypass mode */ | 
|  | 798 | for (i = 0; i < MAX_TDM_CHAN; i++) { | 
|  | 799 | if (mask & (0x00000001 << i)) | 
|  | 800 | vpm_out(wc, x, i, 0x01); | 
|  | 801 | } | 
|  | 802 |  | 
|  | 803 | /* Enable bypass */ | 
|  | 804 | for (i = 0; i < MAX_TDM_CHAN; i++) { | 
|  | 805 | if (mask & (0x00000001 << i)) | 
|  | 806 | vpm_out(wc, x, 0x78 + i, 0x01); | 
|  | 807 | } | 
|  | 808 |  | 
|  | 809 | } | 
|  | 810 | } | 
|  | 811 |  | 
| Hannes Eder | 047ce8f | 2008-12-12 21:18:32 -0800 | [diff] [blame] | 812 | #ifdef UNUSED | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 813 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 814 | vpm_check(struct hfc_multi *hctmp) | 
|  | 815 | { | 
|  | 816 | unsigned char gpi2; | 
|  | 817 |  | 
|  | 818 | gpi2 = HFC_inb(hctmp, R_GPI_IN2); | 
|  | 819 |  | 
|  | 820 | if ((gpi2 & 0x3) != 0x3) | 
|  | 821 | printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); | 
|  | 822 | } | 
| Hannes Eder | 047ce8f | 2008-12-12 21:18:32 -0800 | [diff] [blame] | 823 | #endif /* UNUSED */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 824 |  | 
|  | 825 |  | 
|  | 826 | /* | 
|  | 827 | * Interface to enable/disable the HW Echocan | 
|  | 828 | * | 
|  | 829 | * these functions are called within a spin_lock_irqsave on | 
|  | 830 | * the channel instance lock, so we are not disturbed by irqs | 
|  | 831 | * | 
|  | 832 | * we can later easily change the interface to make  other | 
|  | 833 | * things configurable, for now we configure the taps | 
|  | 834 | * | 
|  | 835 | */ | 
|  | 836 |  | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 837 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 838 | vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) | 
|  | 839 | { | 
|  | 840 | unsigned int timeslot; | 
|  | 841 | unsigned int unit; | 
|  | 842 | struct bchannel *bch = hc->chan[ch].bch; | 
|  | 843 | #ifdef TXADJ | 
|  | 844 | int txadj = -4; | 
|  | 845 | struct sk_buff *skb; | 
|  | 846 | #endif | 
|  | 847 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | 
|  | 848 | return; | 
|  | 849 |  | 
|  | 850 | if (!bch) | 
|  | 851 | return; | 
|  | 852 |  | 
|  | 853 | #ifdef TXADJ | 
|  | 854 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | 
|  | 855 | sizeof(int), &txadj, GFP_ATOMIC); | 
|  | 856 | if (skb) | 
|  | 857 | recv_Bchannel_skb(bch, skb); | 
|  | 858 | #endif | 
|  | 859 |  | 
|  | 860 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | 
|  | 861 | unit = ch % 4; | 
|  | 862 |  | 
|  | 863 | printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", | 
|  | 864 | taps, timeslot); | 
|  | 865 |  | 
|  | 866 | vpm_out(hc, unit, timeslot, 0x7e); | 
|  | 867 | } | 
|  | 868 |  | 
| Hannes Eder | 5b83435 | 2008-12-12 21:15:17 -0800 | [diff] [blame] | 869 | static void | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 870 | vpm_echocan_off(struct hfc_multi *hc, int ch) | 
|  | 871 | { | 
|  | 872 | unsigned int timeslot; | 
|  | 873 | unsigned int unit; | 
|  | 874 | struct bchannel *bch = hc->chan[ch].bch; | 
|  | 875 | #ifdef TXADJ | 
|  | 876 | int txadj = 0; | 
|  | 877 | struct sk_buff *skb; | 
|  | 878 | #endif | 
|  | 879 |  | 
|  | 880 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | 
|  | 881 | return; | 
|  | 882 |  | 
|  | 883 | if (!bch) | 
|  | 884 | return; | 
|  | 885 |  | 
|  | 886 | #ifdef TXADJ | 
|  | 887 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | 
|  | 888 | sizeof(int), &txadj, GFP_ATOMIC); | 
|  | 889 | if (skb) | 
|  | 890 | recv_Bchannel_skb(bch, skb); | 
|  | 891 | #endif | 
|  | 892 |  | 
|  | 893 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | 
|  | 894 | unit = ch % 4; | 
|  | 895 |  | 
|  | 896 | printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", | 
|  | 897 | timeslot); | 
|  | 898 | /* FILLME */ | 
|  | 899 | vpm_out(hc, unit, timeslot, 0x01); | 
|  | 900 | } | 
|  | 901 |  | 
|  | 902 |  | 
|  | 903 | /* | 
|  | 904 | * Speech Design resync feature | 
|  | 905 | * NOTE: This is called sometimes outside interrupt handler. | 
|  | 906 | * We must lock irqsave, so no other interrupt (other card) will occurr! | 
|  | 907 | * Also multiple interrupts may nest, so must lock each access (lists, card)! | 
|  | 908 | */ | 
|  | 909 | static inline void | 
|  | 910 | hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) | 
|  | 911 | { | 
| Hannes Eder | bcf9174 | 2008-12-12 21:11:28 -0800 | [diff] [blame] | 912 | struct hfc_multi *hc, *next, *pcmmaster = NULL; | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 913 | void __iomem *plx_acc_32; | 
|  | 914 | u_int pv; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 915 | u_long flags; | 
|  | 916 |  | 
|  | 917 | spin_lock_irqsave(&HFClock, flags); | 
|  | 918 | spin_lock(&plx_lock); /* must be locked inside other locks */ | 
|  | 919 |  | 
|  | 920 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 921 | printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", | 
|  | 922 | __func__, syncmaster); | 
|  | 923 |  | 
|  | 924 | /* select new master */ | 
|  | 925 | if (newmaster) { | 
|  | 926 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 927 | printk(KERN_DEBUG "using provided controller\n"); | 
|  | 928 | } else { | 
|  | 929 | list_for_each_entry_safe(hc, next, &HFClist, list) { | 
|  | 930 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 931 | if (hc->syncronized) { | 
|  | 932 | newmaster = hc; | 
|  | 933 | break; | 
|  | 934 | } | 
|  | 935 | } | 
|  | 936 | } | 
|  | 937 | } | 
|  | 938 |  | 
|  | 939 | /* Disable sync of all cards */ | 
|  | 940 | list_for_each_entry_safe(hc, next, &HFClist, list) { | 
|  | 941 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 942 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 943 | pv = readl(plx_acc_32); | 
|  | 944 | pv &= ~PLX_SYNC_O_EN; | 
|  | 945 | writel(pv, plx_acc_32); | 
|  | 946 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | 
|  | 947 | pcmmaster = hc; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 948 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 949 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 950 | printk(KERN_DEBUG | 
|  | 951 | "Schedule SYNC_I\n"); | 
|  | 952 | hc->e1_resync |= 1; /* get SYNC_I */ | 
|  | 953 | } | 
|  | 954 | } | 
|  | 955 | } | 
|  | 956 | } | 
|  | 957 |  | 
|  | 958 | if (newmaster) { | 
|  | 959 | hc = newmaster; | 
|  | 960 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 961 | printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " | 
|  | 962 | "interface.\n", hc->id, hc); | 
|  | 963 | /* Enable new sync master */ | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 964 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 965 | pv = readl(plx_acc_32); | 
|  | 966 | pv |= PLX_SYNC_O_EN; | 
|  | 967 | writel(pv, plx_acc_32); | 
|  | 968 | /* switch to jatt PLL, if not disabled by RX_SYNC */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 969 | if (hc->ctype == HFC_TYPE_E1 | 
|  | 970 | && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 971 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 972 | printk(KERN_DEBUG "Schedule jatt PLL\n"); | 
|  | 973 | hc->e1_resync |= 2; /* switch to jatt */ | 
|  | 974 | } | 
|  | 975 | } else { | 
|  | 976 | if (pcmmaster) { | 
|  | 977 | hc = pcmmaster; | 
|  | 978 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 979 | printk(KERN_DEBUG | 
|  | 980 | "id=%d (0x%p) = PCM master syncronized " | 
|  | 981 | "with QUARTZ\n", hc->id, hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 982 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 983 | /* Use the crystal clock for the PCM | 
|  | 984 | master card */ | 
|  | 985 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 986 | printk(KERN_DEBUG | 
|  | 987 | "Schedule QUARTZ for HFC-E1\n"); | 
|  | 988 | hc->e1_resync |= 4; /* switch quartz */ | 
|  | 989 | } else { | 
|  | 990 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 991 | printk(KERN_DEBUG | 
|  | 992 | "QUARTZ is automatically " | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 993 | "enabled by HFC-%dS\n", hc->ctype); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 994 | } | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 995 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 996 | pv = readl(plx_acc_32); | 
|  | 997 | pv |= PLX_SYNC_O_EN; | 
|  | 998 | writel(pv, plx_acc_32); | 
|  | 999 | } else | 
|  | 1000 | if (!rm) | 
|  | 1001 | printk(KERN_ERR "%s no pcm master, this MUST " | 
|  | 1002 | "not happen!\n", __func__); | 
|  | 1003 | } | 
|  | 1004 | syncmaster = newmaster; | 
|  | 1005 |  | 
|  | 1006 | spin_unlock(&plx_lock); | 
|  | 1007 | spin_unlock_irqrestore(&HFClock, flags); | 
|  | 1008 | } | 
|  | 1009 |  | 
|  | 1010 | /* This must be called AND hc must be locked irqsave!!! */ | 
|  | 1011 | inline void | 
|  | 1012 | plxsd_checksync(struct hfc_multi *hc, int rm) | 
|  | 1013 | { | 
|  | 1014 | if (hc->syncronized) { | 
|  | 1015 | if (syncmaster == NULL) { | 
|  | 1016 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1017 | printk(KERN_DEBUG "%s: GOT sync on card %d" | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1018 | " (id=%d)\n", __func__, hc->id + 1, | 
|  | 1019 | hc->id); | 
|  | 1020 | hfcmulti_resync(hc, hc, rm); | 
|  | 1021 | } | 
|  | 1022 | } else { | 
|  | 1023 | if (syncmaster == hc) { | 
|  | 1024 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1025 | printk(KERN_DEBUG "%s: LOST sync on card %d" | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1026 | " (id=%d)\n", __func__, hc->id + 1, | 
|  | 1027 | hc->id); | 
|  | 1028 | hfcmulti_resync(hc, NULL, rm); | 
|  | 1029 | } | 
|  | 1030 | } | 
|  | 1031 | } | 
|  | 1032 |  | 
|  | 1033 |  | 
|  | 1034 | /* | 
|  | 1035 | * free hardware resources used by driver | 
|  | 1036 | */ | 
|  | 1037 | static void | 
|  | 1038 | release_io_hfcmulti(struct hfc_multi *hc) | 
|  | 1039 | { | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1040 | void __iomem *plx_acc_32; | 
|  | 1041 | u_int	pv; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1042 | u_long	plx_flags; | 
|  | 1043 |  | 
|  | 1044 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1045 | printk(KERN_DEBUG "%s: entered\n", __func__); | 
|  | 1046 |  | 
|  | 1047 | /* soft reset also masks all interrupts */ | 
|  | 1048 | hc->hw.r_cirm |= V_SRES; | 
|  | 1049 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | 
|  | 1050 | udelay(1000); | 
|  | 1051 | hc->hw.r_cirm &= ~V_SRES; | 
|  | 1052 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | 
|  | 1053 | udelay(1000); /* instead of 'wait' that may cause locking */ | 
|  | 1054 |  | 
|  | 1055 | /* release Speech Design card, if PLX was initialized */ | 
|  | 1056 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { | 
|  | 1057 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 1058 | printk(KERN_DEBUG "%s: release PLXSD card %d\n", | 
|  | 1059 | __func__, hc->id + 1); | 
|  | 1060 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1061 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1062 | writel(PLX_GPIOC_INIT, plx_acc_32); | 
|  | 1063 | pv = readl(plx_acc_32); | 
|  | 1064 | /* Termination off */ | 
|  | 1065 | pv &= ~PLX_TERM_ON; | 
|  | 1066 | /* Disconnect the PCM */ | 
|  | 1067 | pv |= PLX_SLAVE_EN_N; | 
|  | 1068 | pv &= ~PLX_MASTER_EN; | 
|  | 1069 | pv &= ~PLX_SYNC_O_EN; | 
|  | 1070 | /* Put the DSP in Reset */ | 
|  | 1071 | pv &= ~PLX_DSP_RES_N; | 
|  | 1072 | writel(pv, plx_acc_32); | 
|  | 1073 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1074 | printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1075 | __func__, pv); | 
|  | 1076 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1077 | } | 
|  | 1078 |  | 
|  | 1079 | /* disable memory mapped ports / io ports */ | 
|  | 1080 | test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1081 | if (hc->pci_dev) | 
|  | 1082 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1083 | if (hc->pci_membase) | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1084 | iounmap(hc->pci_membase); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1085 | if (hc->plx_membase) | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1086 | iounmap(hc->plx_membase); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1087 | if (hc->pci_iobase) | 
|  | 1088 | release_region(hc->pci_iobase, 8); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1089 | if (hc->xhfc_membase) | 
|  | 1090 | iounmap((void *)hc->xhfc_membase); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1091 |  | 
|  | 1092 | if (hc->pci_dev) { | 
|  | 1093 | pci_disable_device(hc->pci_dev); | 
|  | 1094 | pci_set_drvdata(hc->pci_dev, NULL); | 
|  | 1095 | } | 
|  | 1096 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1097 | printk(KERN_DEBUG "%s: done\n", __func__); | 
|  | 1098 | } | 
|  | 1099 |  | 
|  | 1100 | /* | 
|  | 1101 | * function called to reset the HFC chip. A complete software reset of chip | 
|  | 1102 | * and fifos is done. All configuration of the chip is done. | 
|  | 1103 | */ | 
|  | 1104 |  | 
|  | 1105 | static int | 
|  | 1106 | init_chip(struct hfc_multi *hc) | 
|  | 1107 | { | 
|  | 1108 | u_long			flags, val, val2 = 0, rev; | 
|  | 1109 | int			i, err = 0; | 
|  | 1110 | u_char			r_conf_en, rval; | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1111 | void __iomem		*plx_acc_32; | 
|  | 1112 | u_int			pv; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1113 | u_long			plx_flags, hfc_flags; | 
|  | 1114 | int			plx_count; | 
|  | 1115 | struct hfc_multi	*pos, *next, *plx_last_hc; | 
|  | 1116 |  | 
|  | 1117 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 1118 | /* reset all registers */ | 
|  | 1119 | memset(&hc->hw, 0, sizeof(struct hfcm_hw)); | 
|  | 1120 |  | 
|  | 1121 | /* revision check */ | 
|  | 1122 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1123 | printk(KERN_DEBUG "%s: entered\n", __func__); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1124 | val = HFC_inb(hc, R_CHIP_ID); | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1125 | if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && | 
|  | 1126 | (val >> 1) != 0x31) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1127 | printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); | 
|  | 1128 | err = -EIO; | 
|  | 1129 | goto out; | 
|  | 1130 | } | 
|  | 1131 | rev = HFC_inb(hc, R_CHIP_RV); | 
|  | 1132 | printk(KERN_INFO | 
|  | 1133 | "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1134 | val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? | 
|  | 1135 | " (old FIFO handling)" : ""); | 
|  | 1136 | if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1137 | test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); | 
|  | 1138 | printk(KERN_WARNING | 
|  | 1139 | "HFC_multi: NOTE: Your chip is revision 0, " | 
|  | 1140 | "ask Cologne Chip for update. Newer chips " | 
|  | 1141 | "have a better FIFO handling. Old chips " | 
|  | 1142 | "still work but may have slightly lower " | 
|  | 1143 | "HDLC transmit performance.\n"); | 
|  | 1144 | } | 
|  | 1145 | if (rev > 1) { | 
|  | 1146 | printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " | 
|  | 1147 | "consider chip revision = %ld. The chip / " | 
|  | 1148 | "bridge may not work.\n", rev); | 
|  | 1149 | } | 
|  | 1150 |  | 
|  | 1151 | /* set s-ram size */ | 
|  | 1152 | hc->Flen = 0x10; | 
|  | 1153 | hc->Zmin = 0x80; | 
|  | 1154 | hc->Zlen = 384; | 
|  | 1155 | hc->DTMFbase = 0x1000; | 
|  | 1156 | if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { | 
|  | 1157 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1158 | printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", | 
|  | 1159 | __func__); | 
|  | 1160 | hc->hw.r_ctrl |= V_EXT_RAM; | 
|  | 1161 | hc->hw.r_ram_sz = 1; | 
|  | 1162 | hc->Flen = 0x20; | 
|  | 1163 | hc->Zmin = 0xc0; | 
|  | 1164 | hc->Zlen = 1856; | 
|  | 1165 | hc->DTMFbase = 0x2000; | 
|  | 1166 | } | 
|  | 1167 | if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { | 
|  | 1168 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1169 | printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", | 
|  | 1170 | __func__); | 
|  | 1171 | hc->hw.r_ctrl |= V_EXT_RAM; | 
|  | 1172 | hc->hw.r_ram_sz = 2; | 
|  | 1173 | hc->Flen = 0x20; | 
|  | 1174 | hc->Zmin = 0xc0; | 
|  | 1175 | hc->Zlen = 8000; | 
|  | 1176 | hc->DTMFbase = 0x2000; | 
|  | 1177 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1178 | if (hc->ctype == HFC_TYPE_XHFC) { | 
|  | 1179 | hc->Flen = 0x8; | 
|  | 1180 | hc->Zmin = 0x0; | 
|  | 1181 | hc->Zlen = 64; | 
|  | 1182 | hc->DTMFbase = 0x0; | 
|  | 1183 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1184 | hc->max_trans = poll << 1; | 
|  | 1185 | if (hc->max_trans > hc->Zlen) | 
|  | 1186 | hc->max_trans = hc->Zlen; | 
|  | 1187 |  | 
|  | 1188 | /* Speech Design PLX bridge */ | 
|  | 1189 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 1190 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 1191 | printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", | 
|  | 1192 | __func__, hc->id + 1); | 
|  | 1193 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1194 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1195 | writel(PLX_GPIOC_INIT, plx_acc_32); | 
|  | 1196 | pv = readl(plx_acc_32); | 
|  | 1197 | /* The first and the last cards are terminating the PCM bus */ | 
|  | 1198 | pv |= PLX_TERM_ON; /* hc is currently the last */ | 
|  | 1199 | /* Disconnect the PCM */ | 
|  | 1200 | pv |= PLX_SLAVE_EN_N; | 
|  | 1201 | pv &= ~PLX_MASTER_EN; | 
|  | 1202 | pv &= ~PLX_SYNC_O_EN; | 
|  | 1203 | /* Put the DSP in Reset */ | 
|  | 1204 | pv &= ~PLX_DSP_RES_N; | 
|  | 1205 | writel(pv, plx_acc_32); | 
|  | 1206 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1207 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1208 | printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1209 | __func__, pv); | 
|  | 1210 | /* | 
|  | 1211 | * If we are the 3rd PLXSD card or higher, we must turn | 
|  | 1212 | * termination of last PLXSD card off. | 
|  | 1213 | */ | 
|  | 1214 | spin_lock_irqsave(&HFClock, hfc_flags); | 
|  | 1215 | plx_count = 0; | 
|  | 1216 | plx_last_hc = NULL; | 
|  | 1217 | list_for_each_entry_safe(pos, next, &HFClist, list) { | 
|  | 1218 | if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { | 
|  | 1219 | plx_count++; | 
|  | 1220 | if (pos != hc) | 
|  | 1221 | plx_last_hc = pos; | 
|  | 1222 | } | 
|  | 1223 | } | 
|  | 1224 | if (plx_count >= 3) { | 
|  | 1225 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 1226 | printk(KERN_DEBUG "%s: card %d is between, so " | 
|  | 1227 | "we disable termination\n", | 
|  | 1228 | __func__, plx_last_hc->id + 1); | 
|  | 1229 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1230 | plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1231 | pv = readl(plx_acc_32); | 
|  | 1232 | pv &= ~PLX_TERM_ON; | 
|  | 1233 | writel(pv, plx_acc_32); | 
|  | 1234 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1235 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1236 | printk(KERN_DEBUG | 
|  | 1237 | "%s: term off: PLX_GPIO=%x\n", | 
|  | 1238 | __func__, pv); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1239 | } | 
|  | 1240 | spin_unlock_irqrestore(&HFClock, hfc_flags); | 
|  | 1241 | hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ | 
|  | 1242 | } | 
|  | 1243 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1244 | if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) | 
|  | 1245 | hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ | 
|  | 1246 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1247 | /* we only want the real Z2 read-pointer for revision > 0 */ | 
|  | 1248 | if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) | 
|  | 1249 | hc->hw.r_ram_sz |= V_FZ_MD; | 
|  | 1250 |  | 
|  | 1251 | /* select pcm mode */ | 
|  | 1252 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | 
|  | 1253 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1254 | printk(KERN_DEBUG "%s: setting PCM into slave mode\n", | 
|  | 1255 | __func__); | 
|  | 1256 | } else | 
|  | 1257 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { | 
|  | 1258 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1259 | printk(KERN_DEBUG "%s: setting PCM into master mode\n", | 
|  | 1260 | __func__); | 
|  | 1261 | hc->hw.r_pcm_md0 |= V_PCM_MD; | 
|  | 1262 | } else { | 
|  | 1263 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1264 | printk(KERN_DEBUG "%s: performing PCM auto detect\n", | 
|  | 1265 | __func__); | 
|  | 1266 | } | 
|  | 1267 |  | 
|  | 1268 | /* soft reset */ | 
|  | 1269 | HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1270 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 1271 | HFC_outb(hc, 0x0C /* R_FIFO_THRES */, | 
|  | 1272 | 0x11 /* 16 Bytes TX/RX */); | 
|  | 1273 | else | 
|  | 1274 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1275 | HFC_outb(hc, R_FIFO_MD, 0); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1276 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 1277 | hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; | 
|  | 1278 | else | 
|  | 1279 | hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | 
|  | 1280 | | V_RLD_EPR; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1281 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | 
|  | 1282 | udelay(100); | 
|  | 1283 | hc->hw.r_cirm = 0; | 
|  | 1284 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | 
|  | 1285 | udelay(100); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1286 | if (hc->ctype != HFC_TYPE_XHFC) | 
|  | 1287 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1288 |  | 
|  | 1289 | /* Speech Design PLX bridge pcm and sync mode */ | 
|  | 1290 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 1291 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1292 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1293 | pv = readl(plx_acc_32); | 
|  | 1294 | /* Connect PCM */ | 
|  | 1295 | if (hc->hw.r_pcm_md0 & V_PCM_MD) { | 
|  | 1296 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | 
|  | 1297 | pv |= PLX_SYNC_O_EN; | 
|  | 1298 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1299 | printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1300 | __func__, pv); | 
|  | 1301 | } else { | 
|  | 1302 | pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); | 
|  | 1303 | pv &= ~PLX_SYNC_O_EN; | 
|  | 1304 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1305 | printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1306 | __func__, pv); | 
|  | 1307 | } | 
|  | 1308 | writel(pv, plx_acc_32); | 
|  | 1309 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1310 | } | 
|  | 1311 |  | 
|  | 1312 | /* PCM setup */ | 
|  | 1313 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); | 
|  | 1314 | if (hc->slots == 32) | 
|  | 1315 | HFC_outb(hc, R_PCM_MD1, 0x00); | 
|  | 1316 | if (hc->slots == 64) | 
|  | 1317 | HFC_outb(hc, R_PCM_MD1, 0x10); | 
|  | 1318 | if (hc->slots == 128) | 
|  | 1319 | HFC_outb(hc, R_PCM_MD1, 0x20); | 
|  | 1320 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); | 
|  | 1321 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | 
|  | 1322 | HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1323 | else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) | 
|  | 1324 | HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1325 | else | 
|  | 1326 | HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ | 
|  | 1327 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | 
|  | 1328 | for (i = 0; i < 256; i++) { | 
|  | 1329 | HFC_outb_nodebug(hc, R_SLOT, i); | 
|  | 1330 | HFC_outb_nodebug(hc, A_SL_CFG, 0); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1331 | if (hc->ctype != HFC_TYPE_XHFC) | 
|  | 1332 | HFC_outb_nodebug(hc, A_CONF, 0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1333 | hc->slot_owner[i] = -1; | 
|  | 1334 | } | 
|  | 1335 |  | 
|  | 1336 | /* set clock speed */ | 
|  | 1337 | if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { | 
|  | 1338 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1339 | printk(KERN_DEBUG | 
|  | 1340 | "%s: setting double clock\n", __func__); | 
|  | 1341 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | 
|  | 1342 | } | 
|  | 1343 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1344 | if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) | 
|  | 1345 | HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); | 
|  | 1346 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1347 | /* B410P GPIO */ | 
|  | 1348 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | 
|  | 1349 | printk(KERN_NOTICE "Setting GPIOs\n"); | 
|  | 1350 | HFC_outb(hc, R_GPIO_SEL, 0x30); | 
|  | 1351 | HFC_outb(hc, R_GPIO_EN1, 0x3); | 
|  | 1352 | udelay(1000); | 
|  | 1353 | printk(KERN_NOTICE "calling vpm_init\n"); | 
|  | 1354 | vpm_init(hc); | 
|  | 1355 | } | 
|  | 1356 |  | 
|  | 1357 | /* check if R_F0_CNT counts (8 kHz frame count) */ | 
|  | 1358 | val = HFC_inb(hc, R_F0_CNTL); | 
|  | 1359 | val += HFC_inb(hc, R_F0_CNTH) << 8; | 
|  | 1360 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1361 | printk(KERN_DEBUG | 
|  | 1362 | "HFC_multi F0_CNT %ld after reset\n", val); | 
|  | 1363 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 1364 | set_current_state(TASK_UNINTERRUPTIBLE); | 
|  | 1365 | schedule_timeout((HZ/100)?:1); /* Timeout minimum 10ms */ | 
|  | 1366 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 1367 | val2 = HFC_inb(hc, R_F0_CNTL); | 
|  | 1368 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | 
|  | 1369 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1370 | printk(KERN_DEBUG | 
|  | 1371 | "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", | 
|  | 1372 | val2); | 
|  | 1373 | if (val2 >= val+8) { /* 1 ms */ | 
|  | 1374 | /* it counts, so we keep the pcm mode */ | 
|  | 1375 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | 
|  | 1376 | printk(KERN_INFO "controller is PCM bus MASTER\n"); | 
|  | 1377 | else | 
|  | 1378 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) | 
|  | 1379 | printk(KERN_INFO "controller is PCM bus SLAVE\n"); | 
|  | 1380 | else { | 
|  | 1381 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | 
|  | 1382 | printk(KERN_INFO "controller is PCM bus SLAVE " | 
|  | 1383 | "(auto detected)\n"); | 
|  | 1384 | } | 
|  | 1385 | } else { | 
|  | 1386 | /* does not count */ | 
|  | 1387 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | 
|  | 1388 | controller_fail: | 
|  | 1389 | printk(KERN_ERR "HFC_multi ERROR, getting no 125us " | 
|  | 1390 | "pulse. Seems that controller fails.\n"); | 
|  | 1391 | err = -EIO; | 
|  | 1392 | goto out; | 
|  | 1393 | } | 
|  | 1394 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | 
|  | 1395 | printk(KERN_INFO "controller is PCM bus SLAVE " | 
|  | 1396 | "(ignoring missing PCM clock)\n"); | 
|  | 1397 | } else { | 
|  | 1398 | /* only one pcm master */ | 
|  | 1399 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | 
|  | 1400 | && plxsd_master) { | 
|  | 1401 | printk(KERN_ERR "HFC_multi ERROR, no clock " | 
|  | 1402 | "on another Speech Design card found. " | 
|  | 1403 | "Please be sure to connect PCM cable.\n"); | 
|  | 1404 | err = -EIO; | 
|  | 1405 | goto out; | 
|  | 1406 | } | 
|  | 1407 | /* retry with master clock */ | 
|  | 1408 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 1409 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1410 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1411 | pv = readl(plx_acc_32); | 
|  | 1412 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | 
|  | 1413 | pv |= PLX_SYNC_O_EN; | 
|  | 1414 | writel(pv, plx_acc_32); | 
|  | 1415 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1416 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1417 | printk(KERN_DEBUG "%s: master: " | 
|  | 1418 | "PLX_GPIO=%x\n", __func__, pv); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1419 | } | 
|  | 1420 | hc->hw.r_pcm_md0 |= V_PCM_MD; | 
|  | 1421 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | 
|  | 1422 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 1423 | set_current_state(TASK_UNINTERRUPTIBLE); | 
|  | 1424 | schedule_timeout((HZ/100)?:1); /* Timeout min. 10ms */ | 
|  | 1425 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 1426 | val2 = HFC_inb(hc, R_F0_CNTL); | 
|  | 1427 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | 
|  | 1428 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1429 | printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " | 
|  | 1430 | "10 ms (2nd try)\n", val2); | 
|  | 1431 | if (val2 >= val+8) { /* 1 ms */ | 
|  | 1432 | test_and_set_bit(HFC_CHIP_PCM_MASTER, | 
|  | 1433 | &hc->chip); | 
|  | 1434 | printk(KERN_INFO "controller is PCM bus MASTER " | 
|  | 1435 | "(auto detected)\n"); | 
|  | 1436 | } else | 
|  | 1437 | goto controller_fail; | 
|  | 1438 | } | 
|  | 1439 | } | 
|  | 1440 |  | 
|  | 1441 | /* Release the DSP Reset */ | 
|  | 1442 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 1443 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | 
|  | 1444 | plxsd_master = 1; | 
|  | 1445 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 1446 | plx_acc_32 = hc->plx_membase + PLX_GPIOC; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1447 | pv = readl(plx_acc_32); | 
|  | 1448 | pv |=  PLX_DSP_RES_N; | 
|  | 1449 | writel(pv, plx_acc_32); | 
|  | 1450 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 1451 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1452 | printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1453 | __func__, pv); | 
|  | 1454 | } | 
|  | 1455 |  | 
|  | 1456 | /* pcm id */ | 
|  | 1457 | if (hc->pcm) | 
|  | 1458 | printk(KERN_INFO "controller has given PCM BUS ID %d\n", | 
|  | 1459 | hc->pcm); | 
|  | 1460 | else { | 
|  | 1461 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) | 
|  | 1462 | || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 1463 | PCM_cnt++; /* SD has proprietary bridging */ | 
|  | 1464 | } | 
|  | 1465 | hc->pcm = PCM_cnt; | 
|  | 1466 | printk(KERN_INFO "controller has PCM BUS ID %d " | 
|  | 1467 | "(auto selected)\n", hc->pcm); | 
|  | 1468 | } | 
|  | 1469 |  | 
|  | 1470 | /* set up timer */ | 
|  | 1471 | HFC_outb(hc, R_TI_WD, poll_timer); | 
|  | 1472 | hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; | 
|  | 1473 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1474 | /* set E1 state machine IRQ */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1475 | if (hc->ctype == HFC_TYPE_E1) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1476 | hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; | 
|  | 1477 |  | 
|  | 1478 | /* set DTMF detection */ | 
|  | 1479 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { | 
|  | 1480 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1481 | printk(KERN_DEBUG "%s: enabling DTMF detection " | 
|  | 1482 | "for all B-channel\n", __func__); | 
|  | 1483 | hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; | 
|  | 1484 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | 
|  | 1485 | hc->hw.r_dtmf |= V_ULAW_SEL; | 
|  | 1486 | HFC_outb(hc, R_DTMF_N, 102 - 1); | 
|  | 1487 | hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; | 
|  | 1488 | } | 
|  | 1489 |  | 
|  | 1490 | /* conference engine */ | 
|  | 1491 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | 
|  | 1492 | r_conf_en = V_CONF_EN | V_ULAW; | 
|  | 1493 | else | 
|  | 1494 | r_conf_en = V_CONF_EN; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1495 | if (hc->ctype != HFC_TYPE_XHFC) | 
|  | 1496 | HFC_outb(hc, R_CONF_EN, r_conf_en); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1497 |  | 
|  | 1498 | /* setting leds */ | 
|  | 1499 | switch (hc->leds) { | 
|  | 1500 | case 1: /* HFC-E1 OEM */ | 
|  | 1501 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | 
|  | 1502 | HFC_outb(hc, R_GPIO_SEL, 0x32); | 
|  | 1503 | else | 
|  | 1504 | HFC_outb(hc, R_GPIO_SEL, 0x30); | 
|  | 1505 |  | 
|  | 1506 | HFC_outb(hc, R_GPIO_EN1, 0x0f); | 
|  | 1507 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | 
|  | 1508 |  | 
|  | 1509 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | 
|  | 1510 | break; | 
|  | 1511 |  | 
|  | 1512 | case 2: /* HFC-4S OEM */ | 
|  | 1513 | case 3: | 
|  | 1514 | HFC_outb(hc, R_GPIO_SEL, 0xf0); | 
|  | 1515 | HFC_outb(hc, R_GPIO_EN1, 0xff); | 
|  | 1516 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | 
|  | 1517 | break; | 
|  | 1518 | } | 
|  | 1519 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1520 | if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { | 
|  | 1521 | hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ | 
|  | 1522 | HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); | 
|  | 1523 | } | 
|  | 1524 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1525 | /* set master clock */ | 
|  | 1526 | if (hc->masterclk >= 0) { | 
|  | 1527 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1528 | printk(KERN_DEBUG "%s: setting ST master clock " | 
|  | 1529 | "to port %d (0..%d)\n", | 
|  | 1530 | __func__, hc->masterclk, hc->ports-1); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1531 | hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1532 | HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); | 
|  | 1533 | } | 
|  | 1534 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1535 |  | 
|  | 1536 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1537 | /* setting misc irq */ | 
|  | 1538 | HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); | 
|  | 1539 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1540 | printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", | 
|  | 1541 | hc->hw.r_irqmsk_misc); | 
|  | 1542 |  | 
|  | 1543 | /* RAM access test */ | 
|  | 1544 | HFC_outb(hc, R_RAM_ADDR0, 0); | 
|  | 1545 | HFC_outb(hc, R_RAM_ADDR1, 0); | 
|  | 1546 | HFC_outb(hc, R_RAM_ADDR2, 0); | 
|  | 1547 | for (i = 0; i < 256; i++) { | 
|  | 1548 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | 
|  | 1549 | HFC_outb_nodebug(hc, R_RAM_DATA, ((i*3)&0xff)); | 
|  | 1550 | } | 
|  | 1551 | for (i = 0; i < 256; i++) { | 
|  | 1552 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | 
|  | 1553 | HFC_inb_nodebug(hc, R_RAM_DATA); | 
|  | 1554 | rval = HFC_inb_nodebug(hc, R_INT_DATA); | 
|  | 1555 | if (rval != ((i * 3) & 0xff)) { | 
|  | 1556 | printk(KERN_DEBUG | 
|  | 1557 | "addr:%x val:%x should:%x\n", i, rval, | 
|  | 1558 | (i * 3) & 0xff); | 
|  | 1559 | err++; | 
|  | 1560 | } | 
|  | 1561 | } | 
|  | 1562 | if (err) { | 
|  | 1563 | printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); | 
|  | 1564 | err = -EIO; | 
|  | 1565 | goto out; | 
|  | 1566 | } | 
|  | 1567 |  | 
|  | 1568 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 1569 | printk(KERN_DEBUG "%s: done\n", __func__); | 
|  | 1570 | out: | 
|  | 1571 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 1572 | return err; | 
|  | 1573 | } | 
|  | 1574 |  | 
|  | 1575 |  | 
|  | 1576 | /* | 
|  | 1577 | * control the watchdog | 
|  | 1578 | */ | 
|  | 1579 | static void | 
|  | 1580 | hfcmulti_watchdog(struct hfc_multi *hc) | 
|  | 1581 | { | 
|  | 1582 | hc->wdcount++; | 
|  | 1583 |  | 
|  | 1584 | if (hc->wdcount > 10) { | 
|  | 1585 | hc->wdcount = 0; | 
|  | 1586 | hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? | 
|  | 1587 | V_GPIO_OUT3 : V_GPIO_OUT2; | 
|  | 1588 |  | 
|  | 1589 | /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ | 
|  | 1590 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | 
|  | 1591 | HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); | 
|  | 1592 | } | 
|  | 1593 | } | 
|  | 1594 |  | 
|  | 1595 |  | 
|  | 1596 |  | 
|  | 1597 | /* | 
|  | 1598 | * output leds | 
|  | 1599 | */ | 
|  | 1600 | static void | 
|  | 1601 | hfcmulti_leds(struct hfc_multi *hc) | 
|  | 1602 | { | 
|  | 1603 | unsigned long lled; | 
|  | 1604 | unsigned long leddw; | 
|  | 1605 | int i, state, active, leds; | 
|  | 1606 | struct dchannel *dch; | 
|  | 1607 | int led[4]; | 
|  | 1608 |  | 
|  | 1609 | hc->ledcount += poll; | 
|  | 1610 | if (hc->ledcount > 4096) { | 
|  | 1611 | hc->ledcount -= 4096; | 
|  | 1612 | hc->ledstate = 0xAFFEAFFE; | 
|  | 1613 | } | 
|  | 1614 |  | 
|  | 1615 | switch (hc->leds) { | 
|  | 1616 | case 1: /* HFC-E1 OEM */ | 
|  | 1617 | /* 2 red blinking: NT mode deactivate | 
|  | 1618 | * 2 red steady:   TE mode deactivate | 
|  | 1619 | * left green:     L1 active | 
|  | 1620 | * left red:       frame sync, but no L1 | 
|  | 1621 | * right green:    L2 active | 
|  | 1622 | */ | 
|  | 1623 | if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ | 
|  | 1624 | if (hc->chan[hc->dslot].dch->dev.D.protocol | 
|  | 1625 | != ISDN_P_NT_E1) { | 
|  | 1626 | led[0] = 1; | 
|  | 1627 | led[1] = 1; | 
|  | 1628 | } else if (hc->ledcount>>11) { | 
|  | 1629 | led[0] = 1; | 
|  | 1630 | led[1] = 1; | 
|  | 1631 | } else { | 
|  | 1632 | led[0] = 0; | 
|  | 1633 | led[1] = 0; | 
|  | 1634 | } | 
|  | 1635 | led[2] = 0; | 
|  | 1636 | led[3] = 0; | 
|  | 1637 | } else { /* with frame sync */ | 
|  | 1638 | /* TODO make it work */ | 
|  | 1639 | led[0] = 0; | 
|  | 1640 | led[1] = 0; | 
|  | 1641 | led[2] = 0; | 
|  | 1642 | led[3] = 1; | 
|  | 1643 | } | 
|  | 1644 | leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; | 
|  | 1645 | /* leds are inverted */ | 
|  | 1646 | if (leds != (int)hc->ledstate) { | 
|  | 1647 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); | 
|  | 1648 | hc->ledstate = leds; | 
|  | 1649 | } | 
|  | 1650 | break; | 
|  | 1651 |  | 
|  | 1652 | case 2: /* HFC-4S OEM */ | 
|  | 1653 | /* red blinking = PH_DEACTIVATE NT Mode | 
|  | 1654 | * red steady   = PH_DEACTIVATE TE Mode | 
|  | 1655 | * green steady = PH_ACTIVATE | 
|  | 1656 | */ | 
|  | 1657 | for (i = 0; i < 4; i++) { | 
|  | 1658 | state = 0; | 
|  | 1659 | active = -1; | 
|  | 1660 | dch = hc->chan[(i << 2) | 2].dch; | 
|  | 1661 | if (dch) { | 
|  | 1662 | state = dch->state; | 
|  | 1663 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | 
|  | 1664 | active = 3; | 
|  | 1665 | else | 
|  | 1666 | active = 7; | 
|  | 1667 | } | 
|  | 1668 | if (state) { | 
|  | 1669 | if (state == active) { | 
|  | 1670 | led[i] = 1; /* led green */ | 
|  | 1671 | } else | 
|  | 1672 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | 
|  | 1673 | /* TE mode: led red */ | 
|  | 1674 | led[i] = 2; | 
|  | 1675 | else | 
|  | 1676 | if (hc->ledcount>>11) | 
|  | 1677 | /* led red */ | 
|  | 1678 | led[i] = 2; | 
|  | 1679 | else | 
|  | 1680 | /* led off */ | 
|  | 1681 | led[i] = 0; | 
|  | 1682 | } else | 
|  | 1683 | led[i] = 0; /* led off */ | 
|  | 1684 | } | 
|  | 1685 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | 
|  | 1686 | leds = 0; | 
|  | 1687 | for (i = 0; i < 4; i++) { | 
|  | 1688 | if (led[i] == 1) { | 
|  | 1689 | /*green*/ | 
|  | 1690 | leds |= (0x2 << (i * 2)); | 
|  | 1691 | } else if (led[i] == 2) { | 
|  | 1692 | /*red*/ | 
|  | 1693 | leds |= (0x1 << (i * 2)); | 
|  | 1694 | } | 
|  | 1695 | } | 
|  | 1696 | if (leds != (int)hc->ledstate) { | 
|  | 1697 | vpm_out(hc, 0, 0x1a8 + 3, leds); | 
|  | 1698 | hc->ledstate = leds; | 
|  | 1699 | } | 
|  | 1700 | } else { | 
|  | 1701 | leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | | 
|  | 1702 | ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | | 
|  | 1703 | ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | | 
|  | 1704 | ((led[0] & 1) << 6) | ((led[2] & 1) << 7); | 
|  | 1705 | if (leds != (int)hc->ledstate) { | 
|  | 1706 | HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); | 
|  | 1707 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); | 
|  | 1708 | hc->ledstate = leds; | 
|  | 1709 | } | 
|  | 1710 | } | 
|  | 1711 | break; | 
|  | 1712 |  | 
|  | 1713 | case 3: /* HFC 1S/2S Beronet */ | 
|  | 1714 | /* red blinking = PH_DEACTIVATE NT Mode | 
|  | 1715 | * red steady   = PH_DEACTIVATE TE Mode | 
|  | 1716 | * green steady = PH_ACTIVATE | 
|  | 1717 | */ | 
|  | 1718 | for (i = 0; i < 2; i++) { | 
|  | 1719 | state = 0; | 
|  | 1720 | active = -1; | 
|  | 1721 | dch = hc->chan[(i << 2) | 2].dch; | 
|  | 1722 | if (dch) { | 
|  | 1723 | state = dch->state; | 
|  | 1724 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | 
|  | 1725 | active = 3; | 
|  | 1726 | else | 
|  | 1727 | active = 7; | 
|  | 1728 | } | 
|  | 1729 | if (state) { | 
|  | 1730 | if (state == active) { | 
|  | 1731 | led[i] = 1; /* led green */ | 
|  | 1732 | } else | 
|  | 1733 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | 
|  | 1734 | /* TE mode: led red */ | 
|  | 1735 | led[i] = 2; | 
|  | 1736 | else | 
|  | 1737 | if (hc->ledcount >> 11) | 
|  | 1738 | /* led red */ | 
|  | 1739 | led[i] = 2; | 
|  | 1740 | else | 
|  | 1741 | /* led off */ | 
|  | 1742 | led[i] = 0; | 
|  | 1743 | } else | 
|  | 1744 | led[i] = 0; /* led off */ | 
|  | 1745 | } | 
|  | 1746 |  | 
|  | 1747 |  | 
|  | 1748 | leds = (led[0] > 0) | ((led[1] > 0)<<1) | ((led[0]&1)<<2) | 
|  | 1749 | | ((led[1]&1)<<3); | 
|  | 1750 | if (leds != (int)hc->ledstate) { | 
|  | 1751 | HFC_outb_nodebug(hc, R_GPIO_EN1, | 
|  | 1752 | ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); | 
|  | 1753 | HFC_outb_nodebug(hc, R_GPIO_OUT1, | 
|  | 1754 | ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); | 
|  | 1755 | hc->ledstate = leds; | 
|  | 1756 | } | 
|  | 1757 | break; | 
|  | 1758 | case 8: /* HFC 8S+ Beronet */ | 
|  | 1759 | lled = 0; | 
|  | 1760 |  | 
|  | 1761 | for (i = 0; i < 8; i++) { | 
|  | 1762 | state = 0; | 
|  | 1763 | active = -1; | 
|  | 1764 | dch = hc->chan[(i << 2) | 2].dch; | 
|  | 1765 | if (dch) { | 
|  | 1766 | state = dch->state; | 
|  | 1767 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | 
|  | 1768 | active = 3; | 
|  | 1769 | else | 
|  | 1770 | active = 7; | 
|  | 1771 | } | 
|  | 1772 | if (state) { | 
|  | 1773 | if (state == active) { | 
|  | 1774 | lled |= 0 << i; | 
|  | 1775 | } else | 
|  | 1776 | if (hc->ledcount >> 11) | 
|  | 1777 | lled |= 0 << i; | 
|  | 1778 | else | 
|  | 1779 | lled |= 1 << i; | 
|  | 1780 | } else | 
|  | 1781 | lled |= 1 << i; | 
|  | 1782 | } | 
|  | 1783 | leddw = lled << 24 | lled << 16 | lled << 8 | lled; | 
|  | 1784 | if (leddw != hc->ledstate) { | 
|  | 1785 | /* HFC_outb(hc, R_BRG_PCM_CFG, 1); | 
|  | 1786 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ | 
|  | 1787 | /* was _io before */ | 
|  | 1788 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | 
|  | 1789 | outw(0x4000, hc->pci_iobase + 4); | 
|  | 1790 | outl(leddw, hc->pci_iobase); | 
|  | 1791 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); | 
|  | 1792 | hc->ledstate = leddw; | 
|  | 1793 | } | 
|  | 1794 | break; | 
|  | 1795 | } | 
|  | 1796 | } | 
|  | 1797 | /* | 
|  | 1798 | * read dtmf coefficients | 
|  | 1799 | */ | 
|  | 1800 |  | 
|  | 1801 | static void | 
|  | 1802 | hfcmulti_dtmf(struct hfc_multi *hc) | 
|  | 1803 | { | 
|  | 1804 | s32		*coeff; | 
|  | 1805 | u_int		mantissa; | 
|  | 1806 | int		co, ch; | 
|  | 1807 | struct bchannel	*bch = NULL; | 
|  | 1808 | u8		exponent; | 
|  | 1809 | int		dtmf = 0; | 
|  | 1810 | int		addr; | 
|  | 1811 | u16		w_float; | 
|  | 1812 | struct sk_buff	*skb; | 
|  | 1813 | struct mISDNhead *hh; | 
|  | 1814 |  | 
|  | 1815 | if (debug & DEBUG_HFCMULTI_DTMF) | 
|  | 1816 | printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); | 
|  | 1817 | for (ch = 0; ch <= 31; ch++) { | 
|  | 1818 | /* only process enabled B-channels */ | 
|  | 1819 | bch = hc->chan[ch].bch; | 
|  | 1820 | if (!bch) | 
|  | 1821 | continue; | 
|  | 1822 | if (!hc->created[hc->chan[ch].port]) | 
|  | 1823 | continue; | 
|  | 1824 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | 
|  | 1825 | continue; | 
|  | 1826 | if (debug & DEBUG_HFCMULTI_DTMF) | 
|  | 1827 | printk(KERN_DEBUG "%s: dtmf channel %d:", | 
|  | 1828 | __func__, ch); | 
|  | 1829 | coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); | 
|  | 1830 | dtmf = 1; | 
|  | 1831 | for (co = 0; co < 8; co++) { | 
|  | 1832 | /* read W(n-1) coefficient */ | 
|  | 1833 | addr = hc->DTMFbase + ((co<<7) | (ch<<2)); | 
|  | 1834 | HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); | 
|  | 1835 | HFC_outb_nodebug(hc, R_RAM_ADDR1, addr>>8); | 
|  | 1836 | HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr>>16) | 
|  | 1837 | | V_ADDR_INC); | 
|  | 1838 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | 
|  | 1839 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | 
|  | 1840 | if (debug & DEBUG_HFCMULTI_DTMF) | 
|  | 1841 | printk(" %04x", w_float); | 
|  | 1842 |  | 
|  | 1843 | /* decode float (see chip doc) */ | 
|  | 1844 | mantissa = w_float & 0x0fff; | 
|  | 1845 | if (w_float & 0x8000) | 
|  | 1846 | mantissa |= 0xfffff000; | 
|  | 1847 | exponent = (w_float>>12) & 0x7; | 
|  | 1848 | if (exponent) { | 
|  | 1849 | mantissa ^= 0x1000; | 
|  | 1850 | mantissa <<= (exponent-1); | 
|  | 1851 | } | 
|  | 1852 |  | 
|  | 1853 | /* store coefficient */ | 
|  | 1854 | coeff[co<<1] = mantissa; | 
|  | 1855 |  | 
|  | 1856 | /* read W(n) coefficient */ | 
|  | 1857 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | 
|  | 1858 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | 
|  | 1859 | if (debug & DEBUG_HFCMULTI_DTMF) | 
|  | 1860 | printk(" %04x", w_float); | 
|  | 1861 |  | 
|  | 1862 | /* decode float (see chip doc) */ | 
|  | 1863 | mantissa = w_float & 0x0fff; | 
|  | 1864 | if (w_float & 0x8000) | 
|  | 1865 | mantissa |= 0xfffff000; | 
|  | 1866 | exponent = (w_float>>12) & 0x7; | 
|  | 1867 | if (exponent) { | 
|  | 1868 | mantissa ^= 0x1000; | 
|  | 1869 | mantissa <<= (exponent-1); | 
|  | 1870 | } | 
|  | 1871 |  | 
|  | 1872 | /* store coefficient */ | 
|  | 1873 | coeff[(co<<1)|1] = mantissa; | 
|  | 1874 | } | 
|  | 1875 | if (debug & DEBUG_HFCMULTI_DTMF) | 
| Andreas Eversberg | b5df5a5 | 2009-05-22 11:04:48 +0000 | [diff] [blame] | 1876 | printk(" DTMF ready %08x %08x %08x %08x " | 
|  | 1877 | "%08x %08x %08x %08x\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1878 | coeff[0], coeff[1], coeff[2], coeff[3], | 
|  | 1879 | coeff[4], coeff[5], coeff[6], coeff[7]); | 
|  | 1880 | hc->chan[ch].coeff_count++; | 
|  | 1881 | if (hc->chan[ch].coeff_count == 8) { | 
|  | 1882 | hc->chan[ch].coeff_count = 0; | 
|  | 1883 | skb = mI_alloc_skb(512, GFP_ATOMIC); | 
|  | 1884 | if (!skb) { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 1885 | printk(KERN_DEBUG "%s: No memory for skb\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1886 | __func__); | 
|  | 1887 | continue; | 
|  | 1888 | } | 
|  | 1889 | hh = mISDN_HEAD_P(skb); | 
|  | 1890 | hh->prim = PH_CONTROL_IND; | 
|  | 1891 | hh->id = DTMF_HFC_COEF; | 
|  | 1892 | memcpy(skb_put(skb, 512), hc->chan[ch].coeff, 512); | 
|  | 1893 | recv_Bchannel_skb(bch, skb); | 
|  | 1894 | } | 
|  | 1895 | } | 
|  | 1896 |  | 
|  | 1897 | /* restart DTMF processing */ | 
|  | 1898 | hc->dtmf = dtmf; | 
|  | 1899 | if (dtmf) | 
|  | 1900 | HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); | 
|  | 1901 | } | 
|  | 1902 |  | 
|  | 1903 |  | 
|  | 1904 | /* | 
|  | 1905 | * fill fifo as much as possible | 
|  | 1906 | */ | 
|  | 1907 |  | 
|  | 1908 | static void | 
|  | 1909 | hfcmulti_tx(struct hfc_multi *hc, int ch) | 
|  | 1910 | { | 
|  | 1911 | int i, ii, temp, len = 0; | 
|  | 1912 | int Zspace, z1, z2; /* must be int for calculation */ | 
|  | 1913 | int Fspace, f1, f2; | 
|  | 1914 | u_char *d; | 
|  | 1915 | int *txpending, slot_tx; | 
|  | 1916 | struct	bchannel *bch; | 
|  | 1917 | struct  dchannel *dch; | 
|  | 1918 | struct  sk_buff **sp = NULL; | 
|  | 1919 | int *idxp; | 
|  | 1920 |  | 
|  | 1921 | bch = hc->chan[ch].bch; | 
|  | 1922 | dch = hc->chan[ch].dch; | 
|  | 1923 | if ((!dch) && (!bch)) | 
|  | 1924 | return; | 
|  | 1925 |  | 
|  | 1926 | txpending = &hc->chan[ch].txpending; | 
|  | 1927 | slot_tx = hc->chan[ch].slot_tx; | 
|  | 1928 | if (dch) { | 
|  | 1929 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | 
|  | 1930 | return; | 
|  | 1931 | sp = &dch->tx_skb; | 
|  | 1932 | idxp = &dch->tx_idx; | 
|  | 1933 | } else { | 
|  | 1934 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | 
|  | 1935 | return; | 
|  | 1936 | sp = &bch->tx_skb; | 
|  | 1937 | idxp = &bch->tx_idx; | 
|  | 1938 | } | 
|  | 1939 | if (*sp) | 
|  | 1940 | len = (*sp)->len; | 
|  | 1941 |  | 
|  | 1942 | if ((!len) && *txpending != 1) | 
|  | 1943 | return; /* no data */ | 
|  | 1944 |  | 
|  | 1945 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | 
|  | 1946 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | 
|  | 1947 | (hc->chan[ch].slot_rx < 0) && | 
|  | 1948 | (hc->chan[ch].slot_tx < 0)) | 
|  | 1949 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); | 
|  | 1950 | else | 
|  | 1951 | HFC_outb_nodebug(hc, R_FIFO, ch << 1); | 
|  | 1952 | HFC_wait_nodebug(hc); | 
|  | 1953 |  | 
|  | 1954 | if (*txpending == 2) { | 
|  | 1955 | /* reset fifo */ | 
|  | 1956 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 1957 | HFC_wait_nodebug(hc); | 
|  | 1958 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 1959 | *txpending = 1; | 
|  | 1960 | } | 
|  | 1961 | next_frame: | 
|  | 1962 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | 
|  | 1963 | f1 = HFC_inb_nodebug(hc, A_F1); | 
|  | 1964 | f2 = HFC_inb_nodebug(hc, A_F2); | 
|  | 1965 | while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { | 
|  | 1966 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 1967 | printk(KERN_DEBUG | 
|  | 1968 | "%s(card %d): reread f2 because %d!=%d\n", | 
|  | 1969 | __func__, hc->id + 1, temp, f2); | 
|  | 1970 | f2 = temp; /* repeat until F2 is equal */ | 
|  | 1971 | } | 
|  | 1972 | Fspace = f2 - f1 - 1; | 
|  | 1973 | if (Fspace < 0) | 
|  | 1974 | Fspace += hc->Flen; | 
|  | 1975 | /* | 
|  | 1976 | * Old FIFO handling doesn't give us the current Z2 read | 
|  | 1977 | * pointer, so we cannot send the next frame before the fifo | 
|  | 1978 | * is empty. It makes no difference except for a slightly | 
|  | 1979 | * lower performance. | 
|  | 1980 | */ | 
|  | 1981 | if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { | 
|  | 1982 | if (f1 != f2) | 
|  | 1983 | Fspace = 0; | 
|  | 1984 | else | 
|  | 1985 | Fspace = 1; | 
|  | 1986 | } | 
|  | 1987 | /* one frame only for ST D-channels, to allow resending */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 1988 | if (hc->ctype != HFC_TYPE_E1 && dch) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 1989 | if (f1 != f2) | 
|  | 1990 | Fspace = 0; | 
|  | 1991 | } | 
|  | 1992 | /* F-counter full condition */ | 
|  | 1993 | if (Fspace == 0) | 
|  | 1994 | return; | 
|  | 1995 | } | 
|  | 1996 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | 
|  | 1997 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | 
|  | 1998 | while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { | 
|  | 1999 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2000 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | 
|  | 2001 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | 
|  | 2002 | z2 = temp; /* repeat unti Z2 is equal */ | 
|  | 2003 | } | 
| Andreas Eversberg | 7cfa153 | 2009-05-22 11:04:46 +0000 | [diff] [blame] | 2004 | hc->chan[ch].Zfill = z1 - z2; | 
|  | 2005 | if (hc->chan[ch].Zfill < 0) | 
|  | 2006 | hc->chan[ch].Zfill += hc->Zlen; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2007 | Zspace = z2 - z1; | 
|  | 2008 | if (Zspace <= 0) | 
|  | 2009 | Zspace += hc->Zlen; | 
|  | 2010 | Zspace -= 4; /* keep not too full, so pointers will not overrun */ | 
|  | 2011 | /* fill transparent data only to maxinum transparent load (minus 4) */ | 
|  | 2012 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | 
|  | 2013 | Zspace = Zspace - hc->Zlen + hc->max_trans; | 
|  | 2014 | if (Zspace <= 0) /* no space of 4 bytes */ | 
|  | 2015 | return; | 
|  | 2016 |  | 
|  | 2017 | /* if no data */ | 
|  | 2018 | if (!len) { | 
|  | 2019 | if (z1 == z2) { /* empty */ | 
|  | 2020 | /* if done with FIFO audio data during PCM connection */ | 
|  | 2021 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && | 
|  | 2022 | *txpending && slot_tx >= 0) { | 
|  | 2023 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2024 | printk(KERN_DEBUG | 
|  | 2025 | "%s: reconnecting PCM due to no " | 
|  | 2026 | "more FIFO data: channel %d " | 
|  | 2027 | "slot_tx %d\n", | 
|  | 2028 | __func__, ch, slot_tx); | 
|  | 2029 | /* connect slot */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2030 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 2031 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 
|  | 2032 | | 0x07 << 2 | V_HDLC_TRP | V_IFF); | 
|  | 2033 | /* Enable FIFO, no interrupt */ | 
|  | 2034 | else | 
|  | 2035 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | 
|  | 2036 | V_HDLC_TRP | V_IFF); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2037 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | 
|  | 2038 | HFC_wait_nodebug(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2039 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 2040 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 
|  | 2041 | | 0x07 << 2 | V_HDLC_TRP | V_IFF); | 
|  | 2042 | /* Enable FIFO, no interrupt */ | 
|  | 2043 | else | 
|  | 2044 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | 
|  | 2045 | V_HDLC_TRP | V_IFF); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2046 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | 
|  | 2047 | HFC_wait_nodebug(hc); | 
|  | 2048 | } | 
|  | 2049 | *txpending = 0; | 
|  | 2050 | } | 
|  | 2051 | return; /* no data */ | 
|  | 2052 | } | 
|  | 2053 |  | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 2054 | /* "fill fifo if empty" feature */ | 
|  | 2055 | if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) | 
|  | 2056 | && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { | 
|  | 2057 | if (debug & DEBUG_HFCMULTI_FILL) | 
|  | 2058 | printk(KERN_DEBUG "%s: buffer empty, so we have " | 
|  | 2059 | "underrun\n", __func__); | 
|  | 2060 | /* fill buffer, to prevent future underrun */ | 
|  | 2061 | hc->write_fifo(hc, hc->silence_data, poll >> 1); | 
|  | 2062 | Zspace -= (poll >> 1); | 
|  | 2063 | } | 
|  | 2064 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2065 | /* if audio data and connected slot */ | 
|  | 2066 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) | 
|  | 2067 | && slot_tx >= 0) { | 
|  | 2068 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2069 | printk(KERN_DEBUG "%s: disconnecting PCM due to " | 
|  | 2070 | "FIFO data: channel %d slot_tx %d\n", | 
|  | 2071 | __func__, ch, slot_tx); | 
|  | 2072 | /* disconnect slot */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2073 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 2074 | HFC_outb(hc, A_CON_HDLC, 0x80 | 
|  | 2075 | | 0x07 << 2 | V_HDLC_TRP | V_IFF); | 
|  | 2076 | /* Enable FIFO, no interrupt */ | 
|  | 2077 | else | 
|  | 2078 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | | 
|  | 2079 | V_HDLC_TRP | V_IFF); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2080 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | 
|  | 2081 | HFC_wait_nodebug(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2082 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 2083 | HFC_outb(hc, A_CON_HDLC, 0x80 | 
|  | 2084 | | 0x07 << 2 | V_HDLC_TRP | V_IFF); | 
|  | 2085 | /* Enable FIFO, no interrupt */ | 
|  | 2086 | else | 
|  | 2087 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | | 
|  | 2088 | V_HDLC_TRP | V_IFF); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2089 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | 
|  | 2090 | HFC_wait_nodebug(hc); | 
|  | 2091 | } | 
|  | 2092 | *txpending = 1; | 
|  | 2093 |  | 
|  | 2094 | /* show activity */ | 
|  | 2095 | hc->activity[hc->chan[ch].port] = 1; | 
|  | 2096 |  | 
|  | 2097 | /* fill fifo to what we have left */ | 
|  | 2098 | ii = len; | 
|  | 2099 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) | 
|  | 2100 | temp = 1; | 
|  | 2101 | else | 
|  | 2102 | temp = 0; | 
|  | 2103 | i = *idxp; | 
|  | 2104 | d = (*sp)->data + i; | 
|  | 2105 | if (ii - i > Zspace) | 
|  | 2106 | ii = Zspace + i; | 
|  | 2107 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2108 | printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " | 
|  | 2109 | "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", | 
|  | 2110 | __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2111 | temp ? "HDLC" : "TRANS"); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2112 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2113 | /* Have to prep the audio data */ | 
|  | 2114 | hc->write_fifo(hc, d, ii - i); | 
| Andreas Eversberg | 7cfa153 | 2009-05-22 11:04:46 +0000 | [diff] [blame] | 2115 | hc->chan[ch].Zfill += ii - i; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2116 | *idxp = ii; | 
|  | 2117 |  | 
|  | 2118 | /* if not all data has been written */ | 
|  | 2119 | if (ii != len) { | 
|  | 2120 | /* NOTE: fifo is started by the calling function */ | 
|  | 2121 | return; | 
|  | 2122 | } | 
|  | 2123 |  | 
|  | 2124 | /* if all data has been written, terminate frame */ | 
|  | 2125 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | 
|  | 2126 | /* increment f-counter */ | 
|  | 2127 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | 
|  | 2128 | HFC_wait_nodebug(hc); | 
|  | 2129 | } | 
|  | 2130 |  | 
|  | 2131 | /* send confirm, since get_net_bframe will not do it with trans */ | 
|  | 2132 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | 
|  | 2133 | confirm_Bsend(bch); | 
|  | 2134 |  | 
|  | 2135 | /* check for next frame */ | 
|  | 2136 | dev_kfree_skb(*sp); | 
|  | 2137 | if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */ | 
|  | 2138 | len = (*sp)->len; | 
|  | 2139 | goto next_frame; | 
|  | 2140 | } | 
|  | 2141 | if (dch && get_next_dframe(dch)) { | 
|  | 2142 | len = (*sp)->len; | 
|  | 2143 | goto next_frame; | 
|  | 2144 | } | 
|  | 2145 |  | 
|  | 2146 | /* | 
|  | 2147 | * now we have no more data, so in case of transparent, | 
|  | 2148 | * we set the last byte in fifo to 'silence' in case we will get | 
|  | 2149 | * no more data at all. this prevents sending an undefined value. | 
|  | 2150 | */ | 
|  | 2151 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 2152 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2153 | } | 
|  | 2154 |  | 
|  | 2155 |  | 
|  | 2156 | /* NOTE: only called if E1 card is in active state */ | 
|  | 2157 | static void | 
|  | 2158 | hfcmulti_rx(struct hfc_multi *hc, int ch) | 
|  | 2159 | { | 
|  | 2160 | int temp; | 
|  | 2161 | int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ | 
|  | 2162 | int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ | 
|  | 2163 | int again = 0; | 
|  | 2164 | struct	bchannel *bch; | 
|  | 2165 | struct  dchannel *dch; | 
|  | 2166 | struct sk_buff	*skb, **sp = NULL; | 
|  | 2167 | int	maxlen; | 
|  | 2168 |  | 
|  | 2169 | bch = hc->chan[ch].bch; | 
|  | 2170 | dch = hc->chan[ch].dch; | 
|  | 2171 | if ((!dch) && (!bch)) | 
|  | 2172 | return; | 
|  | 2173 | if (dch) { | 
|  | 2174 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | 
|  | 2175 | return; | 
|  | 2176 | sp = &dch->rx_skb; | 
|  | 2177 | maxlen = dch->maxlen; | 
|  | 2178 | } else { | 
|  | 2179 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | 
|  | 2180 | return; | 
|  | 2181 | sp = &bch->rx_skb; | 
|  | 2182 | maxlen = bch->maxlen; | 
|  | 2183 | } | 
|  | 2184 | next_frame: | 
|  | 2185 | /* on first AND before getting next valid frame, R_FIFO must be written | 
|  | 2186 | to. */ | 
|  | 2187 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | 
|  | 2188 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | 
|  | 2189 | (hc->chan[ch].slot_rx < 0) && | 
|  | 2190 | (hc->chan[ch].slot_tx < 0)) | 
|  | 2191 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch<<1) | 1); | 
|  | 2192 | else | 
|  | 2193 | HFC_outb_nodebug(hc, R_FIFO, (ch<<1)|1); | 
|  | 2194 | HFC_wait_nodebug(hc); | 
|  | 2195 |  | 
|  | 2196 | /* ignore if rx is off BUT change fifo (above) to start pending TX */ | 
|  | 2197 | if (hc->chan[ch].rx_off) | 
|  | 2198 | return; | 
|  | 2199 |  | 
|  | 2200 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | 
|  | 2201 | f1 = HFC_inb_nodebug(hc, A_F1); | 
|  | 2202 | while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { | 
|  | 2203 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2204 | printk(KERN_DEBUG | 
|  | 2205 | "%s(card %d): reread f1 because %d!=%d\n", | 
|  | 2206 | __func__, hc->id + 1, temp, f1); | 
|  | 2207 | f1 = temp; /* repeat until F1 is equal */ | 
|  | 2208 | } | 
|  | 2209 | f2 = HFC_inb_nodebug(hc, A_F2); | 
|  | 2210 | } | 
|  | 2211 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | 
|  | 2212 | while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { | 
|  | 2213 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2214 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | 
|  | 2215 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | 
|  | 2216 | z1 = temp; /* repeat until Z1 is equal */ | 
|  | 2217 | } | 
|  | 2218 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | 
|  | 2219 | Zsize = z1 - z2; | 
|  | 2220 | if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) | 
|  | 2221 | /* complete hdlc frame */ | 
|  | 2222 | Zsize++; | 
|  | 2223 | if (Zsize < 0) | 
|  | 2224 | Zsize += hc->Zlen; | 
|  | 2225 | /* if buffer is empty */ | 
|  | 2226 | if (Zsize <= 0) | 
|  | 2227 | return; | 
|  | 2228 |  | 
|  | 2229 | if (*sp == NULL) { | 
|  | 2230 | *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); | 
|  | 2231 | if (*sp == NULL) { | 
|  | 2232 | printk(KERN_DEBUG "%s: No mem for rx_skb\n", | 
|  | 2233 | __func__); | 
|  | 2234 | return; | 
|  | 2235 | } | 
|  | 2236 | } | 
|  | 2237 | /* show activity */ | 
|  | 2238 | hc->activity[hc->chan[ch].port] = 1; | 
|  | 2239 |  | 
|  | 2240 | /* empty fifo with what we have */ | 
|  | 2241 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | 
|  | 2242 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2243 | printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " | 
|  | 2244 | "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " | 
|  | 2245 | "got=%d (again %d)\n", __func__, hc->id + 1, ch, | 
|  | 2246 | Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", | 
|  | 2247 | f1, f2, Zsize + (*sp)->len, again); | 
|  | 2248 | /* HDLC */ | 
|  | 2249 | if ((Zsize + (*sp)->len) > (maxlen + 3)) { | 
|  | 2250 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2251 | printk(KERN_DEBUG | 
|  | 2252 | "%s(card %d): hdlc-frame too large.\n", | 
|  | 2253 | __func__, hc->id + 1); | 
|  | 2254 | skb_trim(*sp, 0); | 
|  | 2255 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 2256 | HFC_wait_nodebug(hc); | 
|  | 2257 | return; | 
|  | 2258 | } | 
|  | 2259 |  | 
|  | 2260 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | 
|  | 2261 |  | 
|  | 2262 | if (f1 != f2) { | 
|  | 2263 | /* increment Z2,F2-counter */ | 
|  | 2264 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | 
|  | 2265 | HFC_wait_nodebug(hc); | 
|  | 2266 | /* check size */ | 
|  | 2267 | if ((*sp)->len < 4) { | 
|  | 2268 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2269 | printk(KERN_DEBUG | 
|  | 2270 | "%s(card %d): Frame below minimum " | 
|  | 2271 | "size\n", __func__, hc->id + 1); | 
|  | 2272 | skb_trim(*sp, 0); | 
|  | 2273 | goto next_frame; | 
|  | 2274 | } | 
|  | 2275 | /* there is at least one complete frame, check crc */ | 
|  | 2276 | if ((*sp)->data[(*sp)->len - 1]) { | 
|  | 2277 | if (debug & DEBUG_HFCMULTI_CRC) | 
|  | 2278 | printk(KERN_DEBUG | 
|  | 2279 | "%s: CRC-error\n", __func__); | 
|  | 2280 | skb_trim(*sp, 0); | 
|  | 2281 | goto next_frame; | 
|  | 2282 | } | 
|  | 2283 | skb_trim(*sp, (*sp)->len - 3); | 
|  | 2284 | if ((*sp)->len < MISDN_COPY_SIZE) { | 
|  | 2285 | skb = *sp; | 
|  | 2286 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | 
|  | 2287 | if (*sp) { | 
|  | 2288 | memcpy(skb_put(*sp, skb->len), | 
|  | 2289 | skb->data, skb->len); | 
|  | 2290 | skb_trim(skb, 0); | 
|  | 2291 | } else { | 
|  | 2292 | printk(KERN_DEBUG "%s: No mem\n", | 
|  | 2293 | __func__); | 
|  | 2294 | *sp = skb; | 
|  | 2295 | skb = NULL; | 
|  | 2296 | } | 
|  | 2297 | } else { | 
|  | 2298 | skb = NULL; | 
|  | 2299 | } | 
|  | 2300 | if (debug & DEBUG_HFCMULTI_FIFO) { | 
|  | 2301 | printk(KERN_DEBUG "%s(card %d):", | 
|  | 2302 | __func__, hc->id + 1); | 
|  | 2303 | temp = 0; | 
|  | 2304 | while (temp < (*sp)->len) | 
|  | 2305 | printk(" %02x", (*sp)->data[temp++]); | 
|  | 2306 | printk("\n"); | 
|  | 2307 | } | 
|  | 2308 | if (dch) | 
|  | 2309 | recv_Dchannel(dch); | 
|  | 2310 | else | 
| Andreas Eversberg | 7cfa153 | 2009-05-22 11:04:46 +0000 | [diff] [blame] | 2311 | recv_Bchannel(bch, MISDN_ID_ANY); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2312 | *sp = skb; | 
|  | 2313 | again++; | 
|  | 2314 | goto next_frame; | 
|  | 2315 | } | 
|  | 2316 | /* there is an incomplete frame */ | 
|  | 2317 | } else { | 
|  | 2318 | /* transparent */ | 
|  | 2319 | if (Zsize > skb_tailroom(*sp)) | 
|  | 2320 | Zsize = skb_tailroom(*sp); | 
|  | 2321 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | 
|  | 2322 | if (((*sp)->len) < MISDN_COPY_SIZE) { | 
|  | 2323 | skb = *sp; | 
|  | 2324 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | 
|  | 2325 | if (*sp) { | 
|  | 2326 | memcpy(skb_put(*sp, skb->len), | 
|  | 2327 | skb->data, skb->len); | 
|  | 2328 | skb_trim(skb, 0); | 
|  | 2329 | } else { | 
|  | 2330 | printk(KERN_DEBUG "%s: No mem\n", __func__); | 
|  | 2331 | *sp = skb; | 
|  | 2332 | skb = NULL; | 
|  | 2333 | } | 
|  | 2334 | } else { | 
|  | 2335 | skb = NULL; | 
|  | 2336 | } | 
|  | 2337 | if (debug & DEBUG_HFCMULTI_FIFO) | 
|  | 2338 | printk(KERN_DEBUG | 
|  | 2339 | "%s(card %d): fifo(%d) reading %d bytes " | 
|  | 2340 | "(z1=%04x, z2=%04x) TRANS\n", | 
|  | 2341 | __func__, hc->id + 1, ch, Zsize, z1, z2); | 
|  | 2342 | /* only bch is transparent */ | 
| Andreas Eversberg | 7cfa153 | 2009-05-22 11:04:46 +0000 | [diff] [blame] | 2343 | recv_Bchannel(bch, hc->chan[ch].Zfill); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2344 | *sp = skb; | 
|  | 2345 | } | 
|  | 2346 | } | 
|  | 2347 |  | 
|  | 2348 |  | 
|  | 2349 | /* | 
|  | 2350 | * Interrupt handler | 
|  | 2351 | */ | 
|  | 2352 | static void | 
|  | 2353 | signal_state_up(struct dchannel *dch, int info, char *msg) | 
|  | 2354 | { | 
|  | 2355 | struct sk_buff	*skb; | 
|  | 2356 | int		id, data = info; | 
|  | 2357 |  | 
|  | 2358 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 2359 | printk(KERN_DEBUG "%s: %s\n", __func__, msg); | 
|  | 2360 |  | 
|  | 2361 | id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ | 
|  | 2362 |  | 
|  | 2363 | skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, | 
|  | 2364 | GFP_ATOMIC); | 
|  | 2365 | if (!skb) | 
|  | 2366 | return; | 
|  | 2367 | recv_Dchannel_skb(dch, skb); | 
|  | 2368 | } | 
|  | 2369 |  | 
|  | 2370 | static inline void | 
|  | 2371 | handle_timer_irq(struct hfc_multi *hc) | 
|  | 2372 | { | 
|  | 2373 | int		ch, temp; | 
|  | 2374 | struct dchannel	*dch; | 
|  | 2375 | u_long		flags; | 
|  | 2376 |  | 
|  | 2377 | /* process queued resync jobs */ | 
|  | 2378 | if (hc->e1_resync) { | 
|  | 2379 | /* lock, so e1_resync gets not changed */ | 
|  | 2380 | spin_lock_irqsave(&HFClock, flags); | 
|  | 2381 | if (hc->e1_resync & 1) { | 
|  | 2382 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 2383 | printk(KERN_DEBUG "Enable SYNC_I\n"); | 
|  | 2384 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); | 
|  | 2385 | /* disable JATT, if RX_SYNC is set */ | 
|  | 2386 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | 
|  | 2387 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | 
|  | 2388 | } | 
|  | 2389 | if (hc->e1_resync & 2) { | 
|  | 2390 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 2391 | printk(KERN_DEBUG "Enable jatt PLL\n"); | 
|  | 2392 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | 
|  | 2393 | } | 
|  | 2394 | if (hc->e1_resync & 4) { | 
|  | 2395 | if (debug & DEBUG_HFCMULTI_PLXSD) | 
|  | 2396 | printk(KERN_DEBUG | 
|  | 2397 | "Enable QUARTZ for HFC-E1\n"); | 
|  | 2398 | /* set jatt to quartz */ | 
|  | 2399 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | 
|  | 2400 | | V_JATT_OFF); | 
|  | 2401 | /* switch to JATT, in case it is not already */ | 
|  | 2402 | HFC_outb(hc, R_SYNC_OUT, 0); | 
|  | 2403 | } | 
|  | 2404 | hc->e1_resync = 0; | 
|  | 2405 | spin_unlock_irqrestore(&HFClock, flags); | 
|  | 2406 | } | 
|  | 2407 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2408 | if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2409 | for (ch = 0; ch <= 31; ch++) { | 
|  | 2410 | if (hc->created[hc->chan[ch].port]) { | 
|  | 2411 | hfcmulti_tx(hc, ch); | 
|  | 2412 | /* fifo is started when switching to rx-fifo */ | 
|  | 2413 | hfcmulti_rx(hc, ch); | 
|  | 2414 | if (hc->chan[ch].dch && | 
|  | 2415 | hc->chan[ch].nt_timer > -1) { | 
|  | 2416 | dch = hc->chan[ch].dch; | 
|  | 2417 | if (!(--hc->chan[ch].nt_timer)) { | 
|  | 2418 | schedule_event(dch, | 
|  | 2419 | FLG_PHCHANGE); | 
|  | 2420 | if (debug & | 
|  | 2421 | DEBUG_HFCMULTI_STATE) | 
|  | 2422 | printk(KERN_DEBUG | 
|  | 2423 | "%s: nt_timer at " | 
|  | 2424 | "state %x\n", | 
|  | 2425 | __func__, | 
|  | 2426 | dch->state); | 
|  | 2427 | } | 
|  | 2428 | } | 
|  | 2429 | } | 
|  | 2430 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2431 | if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2432 | dch = hc->chan[hc->dslot].dch; | 
|  | 2433 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | 
|  | 2434 | /* LOS */ | 
|  | 2435 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; | 
|  | 2436 | if (!temp && hc->chan[hc->dslot].los) | 
|  | 2437 | signal_state_up(dch, L1_SIGNAL_LOS_ON, | 
|  | 2438 | "LOS detected"); | 
|  | 2439 | if (temp && !hc->chan[hc->dslot].los) | 
|  | 2440 | signal_state_up(dch, L1_SIGNAL_LOS_OFF, | 
|  | 2441 | "LOS gone"); | 
|  | 2442 | hc->chan[hc->dslot].los = temp; | 
|  | 2443 | } | 
|  | 2444 | if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) { | 
|  | 2445 | /* AIS */ | 
|  | 2446 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; | 
|  | 2447 | if (!temp && hc->chan[hc->dslot].ais) | 
|  | 2448 | signal_state_up(dch, L1_SIGNAL_AIS_ON, | 
|  | 2449 | "AIS detected"); | 
|  | 2450 | if (temp && !hc->chan[hc->dslot].ais) | 
|  | 2451 | signal_state_up(dch, L1_SIGNAL_AIS_OFF, | 
|  | 2452 | "AIS gone"); | 
|  | 2453 | hc->chan[hc->dslot].ais = temp; | 
|  | 2454 | } | 
|  | 2455 | if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) { | 
|  | 2456 | /* SLIP */ | 
|  | 2457 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; | 
|  | 2458 | if (!temp && hc->chan[hc->dslot].slip_rx) | 
|  | 2459 | signal_state_up(dch, L1_SIGNAL_SLIP_RX, | 
|  | 2460 | " bit SLIP detected RX"); | 
|  | 2461 | hc->chan[hc->dslot].slip_rx = temp; | 
|  | 2462 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; | 
|  | 2463 | if (!temp && hc->chan[hc->dslot].slip_tx) | 
|  | 2464 | signal_state_up(dch, L1_SIGNAL_SLIP_TX, | 
|  | 2465 | " bit SLIP detected TX"); | 
|  | 2466 | hc->chan[hc->dslot].slip_tx = temp; | 
|  | 2467 | } | 
|  | 2468 | if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) { | 
|  | 2469 | /* RDI */ | 
|  | 2470 | temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; | 
|  | 2471 | if (!temp && hc->chan[hc->dslot].rdi) | 
|  | 2472 | signal_state_up(dch, L1_SIGNAL_RDI_ON, | 
|  | 2473 | "RDI detected"); | 
|  | 2474 | if (temp && !hc->chan[hc->dslot].rdi) | 
|  | 2475 | signal_state_up(dch, L1_SIGNAL_RDI_OFF, | 
|  | 2476 | "RDI gone"); | 
|  | 2477 | hc->chan[hc->dslot].rdi = temp; | 
|  | 2478 | } | 
|  | 2479 | temp = HFC_inb_nodebug(hc, R_JATT_DIR); | 
|  | 2480 | switch (hc->chan[hc->dslot].sync) { | 
|  | 2481 | case 0: | 
|  | 2482 | if ((temp & 0x60) == 0x60) { | 
|  | 2483 | if (debug & DEBUG_HFCMULTI_SYNC) | 
|  | 2484 | printk(KERN_DEBUG | 
|  | 2485 | "%s: (id=%d) E1 now " | 
|  | 2486 | "in clock sync\n", | 
|  | 2487 | __func__, hc->id); | 
|  | 2488 | HFC_outb(hc, R_RX_OFF, | 
|  | 2489 | hc->chan[hc->dslot].jitter | V_RX_INIT); | 
|  | 2490 | HFC_outb(hc, R_TX_OFF, | 
|  | 2491 | hc->chan[hc->dslot].jitter | V_RX_INIT); | 
|  | 2492 | hc->chan[hc->dslot].sync = 1; | 
|  | 2493 | goto check_framesync; | 
|  | 2494 | } | 
|  | 2495 | break; | 
|  | 2496 | case 1: | 
|  | 2497 | if ((temp & 0x60) != 0x60) { | 
|  | 2498 | if (debug & DEBUG_HFCMULTI_SYNC) | 
|  | 2499 | printk(KERN_DEBUG | 
|  | 2500 | "%s: (id=%d) E1 " | 
|  | 2501 | "lost clock sync\n", | 
|  | 2502 | __func__, hc->id); | 
|  | 2503 | hc->chan[hc->dslot].sync = 0; | 
|  | 2504 | break; | 
|  | 2505 | } | 
|  | 2506 | check_framesync: | 
|  | 2507 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | 
|  | 2508 | if (temp == 0x27) { | 
|  | 2509 | if (debug & DEBUG_HFCMULTI_SYNC) | 
|  | 2510 | printk(KERN_DEBUG | 
|  | 2511 | "%s: (id=%d) E1 " | 
|  | 2512 | "now in frame sync\n", | 
|  | 2513 | __func__, hc->id); | 
|  | 2514 | hc->chan[hc->dslot].sync = 2; | 
|  | 2515 | } | 
|  | 2516 | break; | 
|  | 2517 | case 2: | 
|  | 2518 | if ((temp & 0x60) != 0x60) { | 
|  | 2519 | if (debug & DEBUG_HFCMULTI_SYNC) | 
|  | 2520 | printk(KERN_DEBUG | 
|  | 2521 | "%s: (id=%d) E1 lost " | 
|  | 2522 | "clock & frame sync\n", | 
|  | 2523 | __func__, hc->id); | 
|  | 2524 | hc->chan[hc->dslot].sync = 0; | 
|  | 2525 | break; | 
|  | 2526 | } | 
|  | 2527 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | 
|  | 2528 | if (temp != 0x27) { | 
|  | 2529 | if (debug & DEBUG_HFCMULTI_SYNC) | 
|  | 2530 | printk(KERN_DEBUG | 
|  | 2531 | "%s: (id=%d) E1 " | 
|  | 2532 | "lost frame sync\n", | 
|  | 2533 | __func__, hc->id); | 
|  | 2534 | hc->chan[hc->dslot].sync = 1; | 
|  | 2535 | } | 
|  | 2536 | break; | 
|  | 2537 | } | 
|  | 2538 | } | 
|  | 2539 |  | 
|  | 2540 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | 
|  | 2541 | hfcmulti_watchdog(hc); | 
|  | 2542 |  | 
|  | 2543 | if (hc->leds) | 
|  | 2544 | hfcmulti_leds(hc); | 
|  | 2545 | } | 
|  | 2546 |  | 
|  | 2547 | static void | 
|  | 2548 | ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) | 
|  | 2549 | { | 
|  | 2550 | struct dchannel	*dch; | 
|  | 2551 | int		ch; | 
|  | 2552 | int		active; | 
|  | 2553 | u_char		st_status, temp; | 
|  | 2554 |  | 
|  | 2555 | /* state machine */ | 
|  | 2556 | for (ch = 0; ch <= 31; ch++) { | 
|  | 2557 | if (hc->chan[ch].dch) { | 
|  | 2558 | dch = hc->chan[ch].dch; | 
|  | 2559 | if (r_irq_statech & 1) { | 
|  | 2560 | HFC_outb_nodebug(hc, R_ST_SEL, | 
|  | 2561 | hc->chan[ch].port); | 
|  | 2562 | /* undocumented: delay after R_ST_SEL */ | 
|  | 2563 | udelay(1); | 
|  | 2564 | /* undocumented: status changes during read */ | 
|  | 2565 | st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); | 
|  | 2566 | while (st_status != (temp = | 
|  | 2567 | HFC_inb_nodebug(hc, A_ST_RD_STATE))) { | 
|  | 2568 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 2569 | printk(KERN_DEBUG "%s: reread " | 
|  | 2570 | "STATE because %d!=%d\n", | 
|  | 2571 | __func__, temp, | 
|  | 2572 | st_status); | 
|  | 2573 | st_status = temp; /* repeat */ | 
|  | 2574 | } | 
|  | 2575 |  | 
|  | 2576 | /* Speech Design TE-sync indication */ | 
|  | 2577 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && | 
|  | 2578 | dch->dev.D.protocol == ISDN_P_TE_S0) { | 
|  | 2579 | if (st_status & V_FR_SYNC_ST) | 
|  | 2580 | hc->syncronized |= | 
|  | 2581 | (1 << hc->chan[ch].port); | 
|  | 2582 | else | 
|  | 2583 | hc->syncronized &= | 
|  | 2584 | ~(1 << hc->chan[ch].port); | 
|  | 2585 | } | 
|  | 2586 | dch->state = st_status & 0x0f; | 
|  | 2587 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | 
|  | 2588 | active = 3; | 
|  | 2589 | else | 
|  | 2590 | active = 7; | 
|  | 2591 | if (dch->state == active) { | 
|  | 2592 | HFC_outb_nodebug(hc, R_FIFO, | 
|  | 2593 | (ch << 1) | 1); | 
|  | 2594 | HFC_wait_nodebug(hc); | 
|  | 2595 | HFC_outb_nodebug(hc, | 
|  | 2596 | R_INC_RES_FIFO, V_RES_F); | 
|  | 2597 | HFC_wait_nodebug(hc); | 
|  | 2598 | dch->tx_idx = 0; | 
|  | 2599 | } | 
|  | 2600 | schedule_event(dch, FLG_PHCHANGE); | 
|  | 2601 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 2602 | printk(KERN_DEBUG | 
|  | 2603 | "%s: S/T newstate %x port %d\n", | 
|  | 2604 | __func__, dch->state, | 
|  | 2605 | hc->chan[ch].port); | 
|  | 2606 | } | 
|  | 2607 | r_irq_statech >>= 1; | 
|  | 2608 | } | 
|  | 2609 | } | 
|  | 2610 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | 
|  | 2611 | plxsd_checksync(hc, 0); | 
|  | 2612 | } | 
|  | 2613 |  | 
|  | 2614 | static void | 
|  | 2615 | fifo_irq(struct hfc_multi *hc, int block) | 
|  | 2616 | { | 
|  | 2617 | int	ch, j; | 
|  | 2618 | struct dchannel	*dch; | 
|  | 2619 | struct bchannel	*bch; | 
|  | 2620 | u_char r_irq_fifo_bl; | 
|  | 2621 |  | 
|  | 2622 | r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); | 
|  | 2623 | j = 0; | 
|  | 2624 | while (j < 8) { | 
|  | 2625 | ch = (block << 2) + (j >> 1); | 
|  | 2626 | dch = hc->chan[ch].dch; | 
|  | 2627 | bch = hc->chan[ch].bch; | 
|  | 2628 | if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { | 
|  | 2629 | j += 2; | 
|  | 2630 | continue; | 
|  | 2631 | } | 
|  | 2632 | if (dch && (r_irq_fifo_bl & (1 << j)) && | 
|  | 2633 | test_bit(FLG_ACTIVE, &dch->Flags)) { | 
|  | 2634 | hfcmulti_tx(hc, ch); | 
|  | 2635 | /* start fifo */ | 
|  | 2636 | HFC_outb_nodebug(hc, R_FIFO, 0); | 
|  | 2637 | HFC_wait_nodebug(hc); | 
|  | 2638 | } | 
|  | 2639 | if (bch && (r_irq_fifo_bl & (1 << j)) && | 
|  | 2640 | test_bit(FLG_ACTIVE, &bch->Flags)) { | 
|  | 2641 | hfcmulti_tx(hc, ch); | 
|  | 2642 | /* start fifo */ | 
|  | 2643 | HFC_outb_nodebug(hc, R_FIFO, 0); | 
|  | 2644 | HFC_wait_nodebug(hc); | 
|  | 2645 | } | 
|  | 2646 | j++; | 
|  | 2647 | if (dch && (r_irq_fifo_bl & (1 << j)) && | 
|  | 2648 | test_bit(FLG_ACTIVE, &dch->Flags)) { | 
|  | 2649 | hfcmulti_rx(hc, ch); | 
|  | 2650 | } | 
|  | 2651 | if (bch && (r_irq_fifo_bl & (1 << j)) && | 
|  | 2652 | test_bit(FLG_ACTIVE, &bch->Flags)) { | 
|  | 2653 | hfcmulti_rx(hc, ch); | 
|  | 2654 | } | 
|  | 2655 | j++; | 
|  | 2656 | } | 
|  | 2657 | } | 
|  | 2658 |  | 
|  | 2659 | #ifdef IRQ_DEBUG | 
|  | 2660 | int irqsem; | 
|  | 2661 | #endif | 
|  | 2662 | static irqreturn_t | 
|  | 2663 | hfcmulti_interrupt(int intno, void *dev_id) | 
|  | 2664 | { | 
|  | 2665 | #ifdef IRQCOUNT_DEBUG | 
|  | 2666 | static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, | 
|  | 2667 | iq5 = 0, iq6 = 0, iqcnt = 0; | 
|  | 2668 | #endif | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2669 | struct hfc_multi	*hc = dev_id; | 
|  | 2670 | struct dchannel		*dch; | 
|  | 2671 | u_char			r_irq_statech, status, r_irq_misc, r_irq_oview; | 
|  | 2672 | int			i; | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 2673 | void __iomem		*plx_acc; | 
|  | 2674 | u_short			wval; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2675 | u_char			e1_syncsta, temp; | 
|  | 2676 | u_long			flags; | 
|  | 2677 |  | 
|  | 2678 | if (!hc) { | 
|  | 2679 | printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); | 
|  | 2680 | return IRQ_NONE; | 
|  | 2681 | } | 
|  | 2682 |  | 
|  | 2683 | spin_lock(&hc->lock); | 
|  | 2684 |  | 
|  | 2685 | #ifdef IRQ_DEBUG | 
|  | 2686 | if (irqsem) | 
|  | 2687 | printk(KERN_ERR "irq for card %d during irq from " | 
|  | 2688 | "card %d, this is no bug.\n", hc->id + 1, irqsem); | 
|  | 2689 | irqsem = hc->id + 1; | 
|  | 2690 | #endif | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2691 | #ifdef CONFIG_MISDN_HFCMULTI_8xx | 
|  | 2692 | if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) | 
|  | 2693 | goto irq_notforus; | 
|  | 2694 | #endif | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2695 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 2696 | spin_lock_irqsave(&plx_lock, flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 2697 | plx_acc = hc->plx_membase + PLX_INTCSR; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2698 | wval = readw(plx_acc); | 
|  | 2699 | spin_unlock_irqrestore(&plx_lock, flags); | 
|  | 2700 | if (!(wval & PLX_INTCSR_LINTI1_STATUS)) | 
|  | 2701 | goto irq_notforus; | 
|  | 2702 | } | 
|  | 2703 |  | 
|  | 2704 | status = HFC_inb_nodebug(hc, R_STATUS); | 
|  | 2705 | r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); | 
|  | 2706 | #ifdef IRQCOUNT_DEBUG | 
|  | 2707 | if (r_irq_statech) | 
|  | 2708 | iq1++; | 
|  | 2709 | if (status & V_DTMF_STA) | 
|  | 2710 | iq2++; | 
|  | 2711 | if (status & V_LOST_STA) | 
|  | 2712 | iq3++; | 
|  | 2713 | if (status & V_EXT_IRQSTA) | 
|  | 2714 | iq4++; | 
|  | 2715 | if (status & V_MISC_IRQSTA) | 
|  | 2716 | iq5++; | 
|  | 2717 | if (status & V_FR_IRQSTA) | 
|  | 2718 | iq6++; | 
|  | 2719 | if (iqcnt++ > 5000) { | 
|  | 2720 | printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", | 
|  | 2721 | iq1, iq2, iq3, iq4, iq5, iq6); | 
|  | 2722 | iqcnt = 0; | 
|  | 2723 | } | 
|  | 2724 | #endif | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 2725 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2726 | if (!r_irq_statech && | 
|  | 2727 | !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | | 
|  | 2728 | V_MISC_IRQSTA | V_FR_IRQSTA))) { | 
|  | 2729 | /* irq is not for us */ | 
|  | 2730 | goto irq_notforus; | 
|  | 2731 | } | 
|  | 2732 | hc->irqcnt++; | 
|  | 2733 | if (r_irq_statech) { | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2734 | if (hc->ctype != HFC_TYPE_E1) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2735 | ph_state_irq(hc, r_irq_statech); | 
|  | 2736 | } | 
|  | 2737 | if (status & V_EXT_IRQSTA) | 
|  | 2738 | ; /* external IRQ */ | 
|  | 2739 | if (status & V_LOST_STA) { | 
|  | 2740 | /* LOST IRQ */ | 
|  | 2741 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ | 
|  | 2742 | } | 
|  | 2743 | if (status & V_MISC_IRQSTA) { | 
|  | 2744 | /* misc IRQ */ | 
|  | 2745 | r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); | 
| Andreas Eversberg | 9e6115f | 2008-09-06 09:11:03 +0200 | [diff] [blame] | 2746 | r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2747 | if (r_irq_misc & V_STA_IRQ) { | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2748 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2749 | /* state machine */ | 
|  | 2750 | dch = hc->chan[hc->dslot].dch; | 
|  | 2751 | e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); | 
|  | 2752 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | 
|  | 2753 | && hc->e1_getclock) { | 
|  | 2754 | if (e1_syncsta & V_FR_SYNC_E1) | 
|  | 2755 | hc->syncronized = 1; | 
|  | 2756 | else | 
|  | 2757 | hc->syncronized = 0; | 
|  | 2758 | } | 
|  | 2759 | /* undocumented: status changes during read */ | 
|  | 2760 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA); | 
|  | 2761 | while (dch->state != (temp = | 
|  | 2762 | HFC_inb_nodebug(hc, R_E1_RD_STA))) { | 
|  | 2763 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 2764 | printk(KERN_DEBUG "%s: reread " | 
|  | 2765 | "STATE because %d!=%d\n", | 
|  | 2766 | __func__, temp, | 
|  | 2767 | dch->state); | 
|  | 2768 | dch->state = temp; /* repeat */ | 
|  | 2769 | } | 
|  | 2770 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) | 
|  | 2771 | & 0x7; | 
|  | 2772 | schedule_event(dch, FLG_PHCHANGE); | 
|  | 2773 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 2774 | printk(KERN_DEBUG | 
|  | 2775 | "%s: E1 (id=%d) newstate %x\n", | 
|  | 2776 | __func__, hc->id, dch->state); | 
|  | 2777 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | 
|  | 2778 | plxsd_checksync(hc, 0); | 
|  | 2779 | } | 
|  | 2780 | } | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 2781 | if (r_irq_misc & V_TI_IRQ) { | 
|  | 2782 | if (hc->iclock_on) | 
|  | 2783 | mISDN_clock_update(hc->iclock, poll, NULL); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2784 | handle_timer_irq(hc); | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 2785 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2786 |  | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2787 | if (r_irq_misc & V_DTMF_IRQ) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2788 | hfcmulti_dtmf(hc); | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2789 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2790 | if (r_irq_misc & V_IRQ_PROC) { | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 2791 | static int irq_proc_cnt; | 
|  | 2792 | if (!irq_proc_cnt++) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2793 | printk(KERN_DEBUG "%s: got V_IRQ_PROC -" | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 2794 | " this should not happen\n", __func__); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2795 | } | 
|  | 2796 |  | 
|  | 2797 | } | 
|  | 2798 | if (status & V_FR_IRQSTA) { | 
|  | 2799 | /* FIFO IRQ */ | 
|  | 2800 | r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); | 
|  | 2801 | for (i = 0; i < 8; i++) { | 
|  | 2802 | if (r_irq_oview & (1 << i)) | 
|  | 2803 | fifo_irq(hc, i); | 
|  | 2804 | } | 
|  | 2805 | } | 
|  | 2806 |  | 
|  | 2807 | #ifdef IRQ_DEBUG | 
|  | 2808 | irqsem = 0; | 
|  | 2809 | #endif | 
|  | 2810 | spin_unlock(&hc->lock); | 
|  | 2811 | return IRQ_HANDLED; | 
|  | 2812 |  | 
|  | 2813 | irq_notforus: | 
|  | 2814 | #ifdef IRQ_DEBUG | 
|  | 2815 | irqsem = 0; | 
|  | 2816 | #endif | 
|  | 2817 | spin_unlock(&hc->lock); | 
|  | 2818 | return IRQ_NONE; | 
|  | 2819 | } | 
|  | 2820 |  | 
|  | 2821 |  | 
|  | 2822 | /* | 
|  | 2823 | * timer callback for D-chan busy resolution. Currently no function | 
|  | 2824 | */ | 
|  | 2825 |  | 
|  | 2826 | static void | 
|  | 2827 | hfcmulti_dbusy_timer(struct hfc_multi *hc) | 
|  | 2828 | { | 
|  | 2829 | } | 
|  | 2830 |  | 
|  | 2831 |  | 
|  | 2832 | /* | 
|  | 2833 | * activate/deactivate hardware for selected channels and mode | 
|  | 2834 | * | 
|  | 2835 | * configure B-channel with the given protocol | 
|  | 2836 | * ch eqals to the HFC-channel (0-31) | 
|  | 2837 | * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 | 
|  | 2838 | * for S/T, 1-31 for E1) | 
|  | 2839 | * the hdlc interrupts will be set/unset | 
|  | 2840 | */ | 
|  | 2841 | static int | 
|  | 2842 | mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, | 
|  | 2843 | int bank_tx, int slot_rx, int bank_rx) | 
|  | 2844 | { | 
|  | 2845 | int flow_tx = 0, flow_rx = 0, routing = 0; | 
|  | 2846 | int oslot_tx, oslot_rx; | 
|  | 2847 | int conf; | 
|  | 2848 |  | 
|  | 2849 | if (ch < 0 || ch > 31) | 
| Roel Kluin | 650b2ef | 2010-02-02 12:43:47 +0000 | [diff] [blame] | 2850 | return -EINVAL; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2851 | oslot_tx = hc->chan[ch].slot_tx; | 
|  | 2852 | oslot_rx = hc->chan[ch].slot_rx; | 
|  | 2853 | conf = hc->chan[ch].conf; | 
|  | 2854 |  | 
|  | 2855 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2856 | printk(KERN_DEBUG | 
|  | 2857 | "%s: card %d channel %d protocol %x slot old=%d new=%d " | 
|  | 2858 | "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", | 
|  | 2859 | __func__, hc->id, ch, protocol, oslot_tx, slot_tx, | 
|  | 2860 | bank_tx, oslot_rx, slot_rx, bank_rx); | 
|  | 2861 |  | 
|  | 2862 | if (oslot_tx >= 0 && slot_tx != oslot_tx) { | 
|  | 2863 | /* remove from slot */ | 
|  | 2864 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2865 | printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", | 
|  | 2866 | __func__, oslot_tx); | 
|  | 2867 | if (hc->slot_owner[oslot_tx<<1] == ch) { | 
|  | 2868 | HFC_outb(hc, R_SLOT, oslot_tx << 1); | 
|  | 2869 | HFC_outb(hc, A_SL_CFG, 0); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2870 | if (hc->ctype != HFC_TYPE_XHFC) | 
|  | 2871 | HFC_outb(hc, A_CONF, 0); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2872 | hc->slot_owner[oslot_tx<<1] = -1; | 
|  | 2873 | } else { | 
|  | 2874 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2875 | printk(KERN_DEBUG | 
|  | 2876 | "%s: we are not owner of this tx slot " | 
|  | 2877 | "anymore, channel %d is.\n", | 
|  | 2878 | __func__, hc->slot_owner[oslot_tx<<1]); | 
|  | 2879 | } | 
|  | 2880 | } | 
|  | 2881 |  | 
|  | 2882 | if (oslot_rx >= 0 && slot_rx != oslot_rx) { | 
|  | 2883 | /* remove from slot */ | 
|  | 2884 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2885 | printk(KERN_DEBUG | 
|  | 2886 | "%s: remove from slot %d (RX)\n", | 
|  | 2887 | __func__, oslot_rx); | 
|  | 2888 | if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { | 
|  | 2889 | HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); | 
|  | 2890 | HFC_outb(hc, A_SL_CFG, 0); | 
|  | 2891 | hc->slot_owner[(oslot_rx << 1) | 1] = -1; | 
|  | 2892 | } else { | 
|  | 2893 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2894 | printk(KERN_DEBUG | 
|  | 2895 | "%s: we are not owner of this rx slot " | 
|  | 2896 | "anymore, channel %d is.\n", | 
|  | 2897 | __func__, | 
|  | 2898 | hc->slot_owner[(oslot_rx << 1) | 1]); | 
|  | 2899 | } | 
|  | 2900 | } | 
|  | 2901 |  | 
|  | 2902 | if (slot_tx < 0) { | 
|  | 2903 | flow_tx = 0x80; /* FIFO->ST */ | 
|  | 2904 | /* disable pcm slot */ | 
|  | 2905 | hc->chan[ch].slot_tx = -1; | 
|  | 2906 | hc->chan[ch].bank_tx = 0; | 
|  | 2907 | } else { | 
|  | 2908 | /* set pcm slot */ | 
|  | 2909 | if (hc->chan[ch].txpending) | 
|  | 2910 | flow_tx = 0x80; /* FIFO->ST */ | 
|  | 2911 | else | 
|  | 2912 | flow_tx = 0xc0; /* PCM->ST */ | 
|  | 2913 | /* put on slot */ | 
|  | 2914 | routing = bank_tx ? 0xc0 : 0x80; | 
|  | 2915 | if (conf >= 0 || bank_tx > 1) | 
|  | 2916 | routing = 0x40; /* loop */ | 
|  | 2917 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2918 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | 
|  | 2919 | " %d flow %02x routing %02x conf %d (TX)\n", | 
|  | 2920 | __func__, ch, slot_tx, bank_tx, | 
|  | 2921 | flow_tx, routing, conf); | 
|  | 2922 | HFC_outb(hc, R_SLOT, slot_tx << 1); | 
|  | 2923 | HFC_outb(hc, A_SL_CFG, (ch<<1) | routing); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2924 | if (hc->ctype != HFC_TYPE_XHFC) | 
|  | 2925 | HFC_outb(hc, A_CONF, | 
|  | 2926 | (conf < 0) ? 0 : (conf | V_CONF_SL)); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2927 | hc->slot_owner[slot_tx << 1] = ch; | 
|  | 2928 | hc->chan[ch].slot_tx = slot_tx; | 
|  | 2929 | hc->chan[ch].bank_tx = bank_tx; | 
|  | 2930 | } | 
|  | 2931 | if (slot_rx < 0) { | 
|  | 2932 | /* disable pcm slot */ | 
|  | 2933 | flow_rx = 0x80; /* ST->FIFO */ | 
|  | 2934 | hc->chan[ch].slot_rx = -1; | 
|  | 2935 | hc->chan[ch].bank_rx = 0; | 
|  | 2936 | } else { | 
|  | 2937 | /* set pcm slot */ | 
|  | 2938 | if (hc->chan[ch].txpending) | 
|  | 2939 | flow_rx = 0x80; /* ST->FIFO */ | 
|  | 2940 | else | 
|  | 2941 | flow_rx = 0xc0; /* ST->(FIFO,PCM) */ | 
|  | 2942 | /* put on slot */ | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2943 | routing = bank_rx ? 0x80 : 0xc0; /* reversed */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2944 | if (conf >= 0 || bank_rx > 1) | 
|  | 2945 | routing = 0x40; /* loop */ | 
|  | 2946 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 2947 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | 
|  | 2948 | " %d flow %02x routing %02x conf %d (RX)\n", | 
|  | 2949 | __func__, ch, slot_rx, bank_rx, | 
|  | 2950 | flow_rx, routing, conf); | 
|  | 2951 | HFC_outb(hc, R_SLOT, (slot_rx<<1) | V_SL_DIR); | 
|  | 2952 | HFC_outb(hc, A_SL_CFG, (ch<<1) | V_CH_DIR | routing); | 
|  | 2953 | hc->slot_owner[(slot_rx<<1)|1] = ch; | 
|  | 2954 | hc->chan[ch].slot_rx = slot_rx; | 
|  | 2955 | hc->chan[ch].bank_rx = bank_rx; | 
|  | 2956 | } | 
|  | 2957 |  | 
|  | 2958 | switch (protocol) { | 
|  | 2959 | case (ISDN_P_NONE): | 
|  | 2960 | /* disable TX fifo */ | 
|  | 2961 | HFC_outb(hc, R_FIFO, ch << 1); | 
|  | 2962 | HFC_wait(hc); | 
|  | 2963 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); | 
|  | 2964 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 2965 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 2966 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 2967 | HFC_wait(hc); | 
|  | 2968 | /* disable RX fifo */ | 
|  | 2969 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | 
|  | 2970 | HFC_wait(hc); | 
|  | 2971 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); | 
|  | 2972 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 2973 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 2974 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 2975 | HFC_wait(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 2976 | if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2977 | hc->hw.a_st_ctrl0[hc->chan[ch].port] &= | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 2978 | ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 2979 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | 
|  | 2980 | /* undocumented: delay after R_ST_SEL */ | 
|  | 2981 | udelay(1); | 
|  | 2982 | HFC_outb(hc, A_ST_CTRL0, | 
|  | 2983 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | 
|  | 2984 | } | 
|  | 2985 | if (hc->chan[ch].bch) { | 
|  | 2986 | test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | 
|  | 2987 | test_and_clear_bit(FLG_TRANSPARENT, | 
|  | 2988 | &hc->chan[ch].bch->Flags); | 
|  | 2989 | } | 
|  | 2990 | break; | 
|  | 2991 | case (ISDN_P_B_RAW): /* B-channel */ | 
|  | 2992 |  | 
|  | 2993 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | 
|  | 2994 | (hc->chan[ch].slot_rx < 0) && | 
|  | 2995 | (hc->chan[ch].slot_tx < 0)) { | 
|  | 2996 |  | 
|  | 2997 | printk(KERN_DEBUG | 
|  | 2998 | "Setting B-channel %d to echo cancelable " | 
|  | 2999 | "state on PCM slot %d\n", ch, | 
|  | 3000 | ((ch / 4) * 8) + ((ch % 4) * 4) + 1); | 
|  | 3001 | printk(KERN_DEBUG | 
|  | 3002 | "Enabling pass through for channel\n"); | 
|  | 3003 | vpm_out(hc, ch, ((ch / 4) * 8) + | 
|  | 3004 | ((ch % 4) * 4) + 1, 0x01); | 
|  | 3005 | /* rx path */ | 
|  | 3006 | /* S/T -> PCM */ | 
|  | 3007 | HFC_outb(hc, R_FIFO, (ch << 1)); | 
|  | 3008 | HFC_wait(hc); | 
|  | 3009 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | 
|  | 3010 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | 
|  | 3011 | ((ch % 4) * 4) + 1) << 1); | 
|  | 3012 | HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); | 
|  | 3013 |  | 
|  | 3014 | /* PCM -> FIFO */ | 
|  | 3015 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); | 
|  | 3016 | HFC_wait(hc); | 
|  | 3017 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | 
|  | 3018 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 3019 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 3020 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3021 | HFC_wait(hc); | 
|  | 3022 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | 
|  | 3023 | ((ch % 4) * 4) + 1) << 1) | 1); | 
|  | 3024 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); | 
|  | 3025 |  | 
|  | 3026 | /* tx path */ | 
|  | 3027 | /* PCM -> S/T */ | 
|  | 3028 | HFC_outb(hc, R_FIFO, (ch << 1) | 1); | 
|  | 3029 | HFC_wait(hc); | 
|  | 3030 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | 
|  | 3031 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | 
|  | 3032 | ((ch % 4) * 4)) << 1) | 1); | 
|  | 3033 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); | 
|  | 3034 |  | 
|  | 3035 | /* FIFO -> PCM */ | 
|  | 3036 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); | 
|  | 3037 | HFC_wait(hc); | 
|  | 3038 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | 
|  | 3039 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 3040 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 3041 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3042 | HFC_wait(hc); | 
|  | 3043 | /* tx silence */ | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 3044 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3045 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | 
|  | 3046 | ((ch % 4) * 4)) << 1); | 
|  | 3047 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); | 
|  | 3048 | } else { | 
|  | 3049 | /* enable TX fifo */ | 
|  | 3050 | HFC_outb(hc, R_FIFO, ch << 1); | 
|  | 3051 | HFC_wait(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3052 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 3053 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | | 
|  | 3054 | V_HDLC_TRP | V_IFF); | 
|  | 3055 | /* Enable FIFO, no interrupt */ | 
|  | 3056 | else | 
|  | 3057 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | | 
|  | 3058 | V_HDLC_TRP | V_IFF); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3059 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 3060 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 3061 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3062 | HFC_wait(hc); | 
|  | 3063 | /* tx silence */ | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 3064 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3065 | /* enable RX fifo */ | 
|  | 3066 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | 
|  | 3067 | HFC_wait(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3068 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 3069 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | | 
|  | 3070 | V_HDLC_TRP); | 
|  | 3071 | /* Enable FIFO, no interrupt*/ | 
|  | 3072 | else | 
|  | 3073 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | | 
|  | 3074 | V_HDLC_TRP); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3075 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 3076 | HFC_outb(hc, A_IRQ_MSK, 0); | 
|  | 3077 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3078 | HFC_wait(hc); | 
|  | 3079 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3080 | if (hc->ctype != HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3081 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | 
|  | 3082 | ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; | 
|  | 3083 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | 
|  | 3084 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3085 | udelay(1); | 
|  | 3086 | HFC_outb(hc, A_ST_CTRL0, | 
|  | 3087 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | 
|  | 3088 | } | 
|  | 3089 | if (hc->chan[ch].bch) | 
|  | 3090 | test_and_set_bit(FLG_TRANSPARENT, | 
|  | 3091 | &hc->chan[ch].bch->Flags); | 
|  | 3092 | break; | 
|  | 3093 | case (ISDN_P_B_HDLC): /* B-channel */ | 
|  | 3094 | case (ISDN_P_TE_S0): /* D-channel */ | 
|  | 3095 | case (ISDN_P_NT_S0): | 
|  | 3096 | case (ISDN_P_TE_E1): | 
|  | 3097 | case (ISDN_P_NT_E1): | 
|  | 3098 | /* enable TX fifo */ | 
|  | 3099 | HFC_outb(hc, R_FIFO, ch<<1); | 
|  | 3100 | HFC_wait(hc); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3101 | if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3102 | /* E1 or B-channel */ | 
|  | 3103 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); | 
|  | 3104 | HFC_outb(hc, A_SUBCH_CFG, 0); | 
|  | 3105 | } else { | 
|  | 3106 | /* D-Channel without HDLC fill flags */ | 
|  | 3107 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); | 
|  | 3108 | HFC_outb(hc, A_SUBCH_CFG, 2); | 
|  | 3109 | } | 
|  | 3110 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | 
|  | 3111 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3112 | HFC_wait(hc); | 
|  | 3113 | /* enable RX fifo */ | 
|  | 3114 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | 
|  | 3115 | HFC_wait(hc); | 
|  | 3116 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3117 | if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3118 | HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ | 
|  | 3119 | else | 
|  | 3120 | HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ | 
|  | 3121 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | 
|  | 3122 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3123 | HFC_wait(hc); | 
|  | 3124 | if (hc->chan[ch].bch) { | 
|  | 3125 | test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3126 | if (hc->ctype != HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3127 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | 
|  | 3128 | ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN; | 
|  | 3129 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | 
|  | 3130 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3131 | udelay(1); | 
|  | 3132 | HFC_outb(hc, A_ST_CTRL0, | 
|  | 3133 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | 
|  | 3134 | } | 
|  | 3135 | } | 
|  | 3136 | break; | 
|  | 3137 | default: | 
|  | 3138 | printk(KERN_DEBUG "%s: protocol not known %x\n", | 
|  | 3139 | __func__, protocol); | 
|  | 3140 | hc->chan[ch].protocol = ISDN_P_NONE; | 
|  | 3141 | return -ENOPROTOOPT; | 
|  | 3142 | } | 
|  | 3143 | hc->chan[ch].protocol = protocol; | 
|  | 3144 | return 0; | 
|  | 3145 | } | 
|  | 3146 |  | 
|  | 3147 |  | 
|  | 3148 | /* | 
|  | 3149 | * connect/disconnect PCM | 
|  | 3150 | */ | 
|  | 3151 |  | 
|  | 3152 | static void | 
|  | 3153 | hfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, | 
|  | 3154 | int slot_rx, int bank_rx) | 
|  | 3155 | { | 
| Julia Lawall | 073bd90 | 2009-12-21 14:25:32 +0000 | [diff] [blame] | 3156 | if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3157 | /* disable PCM */ | 
|  | 3158 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); | 
|  | 3159 | return; | 
|  | 3160 | } | 
|  | 3161 |  | 
|  | 3162 | /* enable pcm */ | 
|  | 3163 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, | 
|  | 3164 | slot_rx, bank_rx); | 
|  | 3165 | } | 
|  | 3166 |  | 
|  | 3167 | /* | 
|  | 3168 | * set/disable conference | 
|  | 3169 | */ | 
|  | 3170 |  | 
|  | 3171 | static void | 
|  | 3172 | hfcmulti_conf(struct hfc_multi *hc, int ch, int num) | 
|  | 3173 | { | 
|  | 3174 | if (num >= 0 && num <= 7) | 
|  | 3175 | hc->chan[ch].conf = num; | 
|  | 3176 | else | 
|  | 3177 | hc->chan[ch].conf = -1; | 
|  | 3178 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, | 
|  | 3179 | hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, | 
|  | 3180 | hc->chan[ch].bank_rx); | 
|  | 3181 | } | 
|  | 3182 |  | 
|  | 3183 |  | 
|  | 3184 | /* | 
|  | 3185 | * set/disable sample loop | 
|  | 3186 | */ | 
|  | 3187 |  | 
|  | 3188 | /* NOTE: this function is experimental and therefore disabled */ | 
|  | 3189 |  | 
|  | 3190 | /* | 
|  | 3191 | * Layer 1 callback function | 
|  | 3192 | */ | 
|  | 3193 | static int | 
|  | 3194 | hfcm_l1callback(struct dchannel *dch, u_int cmd) | 
|  | 3195 | { | 
|  | 3196 | struct hfc_multi	*hc = dch->hw; | 
|  | 3197 | u_long	flags; | 
|  | 3198 |  | 
|  | 3199 | switch (cmd) { | 
|  | 3200 | case INFO3_P8: | 
|  | 3201 | case INFO3_P10: | 
|  | 3202 | break; | 
|  | 3203 | case HW_RESET_REQ: | 
|  | 3204 | /* start activation */ | 
|  | 3205 | spin_lock_irqsave(&hc->lock, flags); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3206 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3207 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3208 | printk(KERN_DEBUG | 
|  | 3209 | "%s: HW_RESET_REQ no BRI\n", | 
|  | 3210 | __func__); | 
|  | 3211 | } else { | 
|  | 3212 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | 
|  | 3213 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3214 | udelay(1); | 
|  | 3215 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ | 
|  | 3216 | udelay(6); /* wait at least 5,21us */ | 
|  | 3217 | HFC_outb(hc, A_ST_WR_STATE, 3); | 
|  | 3218 | HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); | 
|  | 3219 | /* activate */ | 
|  | 3220 | } | 
|  | 3221 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3222 | l1_event(dch->l1, HW_POWERUP_IND); | 
|  | 3223 | break; | 
|  | 3224 | case HW_DEACT_REQ: | 
|  | 3225 | /* start deactivation */ | 
|  | 3226 | spin_lock_irqsave(&hc->lock, flags); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3227 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3228 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3229 | printk(KERN_DEBUG | 
|  | 3230 | "%s: HW_DEACT_REQ no BRI\n", | 
|  | 3231 | __func__); | 
|  | 3232 | } else { | 
|  | 3233 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | 
|  | 3234 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3235 | udelay(1); | 
|  | 3236 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); | 
|  | 3237 | /* deactivate */ | 
|  | 3238 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 3239 | hc->syncronized &= | 
|  | 3240 | ~(1 << hc->chan[dch->slot].port); | 
|  | 3241 | plxsd_checksync(hc, 0); | 
|  | 3242 | } | 
|  | 3243 | } | 
|  | 3244 | skb_queue_purge(&dch->squeue); | 
|  | 3245 | if (dch->tx_skb) { | 
|  | 3246 | dev_kfree_skb(dch->tx_skb); | 
|  | 3247 | dch->tx_skb = NULL; | 
|  | 3248 | } | 
|  | 3249 | dch->tx_idx = 0; | 
|  | 3250 | if (dch->rx_skb) { | 
|  | 3251 | dev_kfree_skb(dch->rx_skb); | 
|  | 3252 | dch->rx_skb = NULL; | 
|  | 3253 | } | 
|  | 3254 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | 
|  | 3255 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | 
|  | 3256 | del_timer(&dch->timer); | 
|  | 3257 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3258 | break; | 
|  | 3259 | case HW_POWERUP_REQ: | 
|  | 3260 | spin_lock_irqsave(&hc->lock, flags); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3261 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3262 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3263 | printk(KERN_DEBUG | 
|  | 3264 | "%s: HW_POWERUP_REQ no BRI\n", | 
|  | 3265 | __func__); | 
|  | 3266 | } else { | 
|  | 3267 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | 
|  | 3268 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3269 | udelay(1); | 
|  | 3270 | HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ | 
|  | 3271 | udelay(6); /* wait at least 5,21us */ | 
|  | 3272 | HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ | 
|  | 3273 | } | 
|  | 3274 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3275 | break; | 
|  | 3276 | case PH_ACTIVATE_IND: | 
|  | 3277 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3278 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | 
|  | 3279 | GFP_ATOMIC); | 
|  | 3280 | break; | 
|  | 3281 | case PH_DEACTIVATE_IND: | 
|  | 3282 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3283 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | 
|  | 3284 | GFP_ATOMIC); | 
|  | 3285 | break; | 
|  | 3286 | default: | 
|  | 3287 | if (dch->debug & DEBUG_HW) | 
|  | 3288 | printk(KERN_DEBUG "%s: unknown command %x\n", | 
|  | 3289 | __func__, cmd); | 
|  | 3290 | return -1; | 
|  | 3291 | } | 
|  | 3292 | return 0; | 
|  | 3293 | } | 
|  | 3294 |  | 
|  | 3295 | /* | 
|  | 3296 | * Layer2 -> Layer 1 Transfer | 
|  | 3297 | */ | 
|  | 3298 |  | 
|  | 3299 | static int | 
|  | 3300 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | 
|  | 3301 | { | 
|  | 3302 | struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D); | 
|  | 3303 | struct dchannel		*dch = container_of(dev, struct dchannel, dev); | 
|  | 3304 | struct hfc_multi	*hc = dch->hw; | 
|  | 3305 | struct mISDNhead	*hh = mISDN_HEAD_P(skb); | 
|  | 3306 | int			ret = -EINVAL; | 
|  | 3307 | unsigned int		id; | 
|  | 3308 | u_long			flags; | 
|  | 3309 |  | 
|  | 3310 | switch (hh->prim) { | 
|  | 3311 | case PH_DATA_REQ: | 
|  | 3312 | if (skb->len < 1) | 
|  | 3313 | break; | 
|  | 3314 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3315 | ret = dchannel_senddata(dch, skb); | 
|  | 3316 | if (ret > 0) { /* direct TX */ | 
|  | 3317 | id = hh->id; /* skb can be freed */ | 
|  | 3318 | hfcmulti_tx(hc, dch->slot); | 
|  | 3319 | ret = 0; | 
|  | 3320 | /* start fifo */ | 
|  | 3321 | HFC_outb(hc, R_FIFO, 0); | 
|  | 3322 | HFC_wait(hc); | 
|  | 3323 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3324 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | 
|  | 3325 | } else | 
|  | 3326 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3327 | return ret; | 
|  | 3328 | case PH_ACTIVATE_REQ: | 
|  | 3329 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | 
|  | 3330 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3331 | ret = 0; | 
|  | 3332 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3333 | printk(KERN_DEBUG | 
|  | 3334 | "%s: PH_ACTIVATE port %d (0..%d)\n", | 
|  | 3335 | __func__, hc->chan[dch->slot].port, | 
|  | 3336 | hc->ports-1); | 
|  | 3337 | /* start activation */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3338 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3339 | ph_state_change(dch); | 
|  | 3340 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 3341 | printk(KERN_DEBUG | 
|  | 3342 | "%s: E1 report state %x \n", | 
|  | 3343 | __func__, dch->state); | 
|  | 3344 | } else { | 
|  | 3345 | HFC_outb(hc, R_ST_SEL, | 
|  | 3346 | hc->chan[dch->slot].port); | 
|  | 3347 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3348 | udelay(1); | 
|  | 3349 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); | 
|  | 3350 | /* G1 */ | 
|  | 3351 | udelay(6); /* wait at least 5,21us */ | 
|  | 3352 | HFC_outb(hc, A_ST_WR_STATE, 1); | 
|  | 3353 | HFC_outb(hc, A_ST_WR_STATE, 1 | | 
|  | 3354 | (V_ST_ACT*3)); /* activate */ | 
|  | 3355 | dch->state = 1; | 
|  | 3356 | } | 
|  | 3357 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3358 | } else | 
|  | 3359 | ret = l1_event(dch->l1, hh->prim); | 
|  | 3360 | break; | 
|  | 3361 | case PH_DEACTIVATE_REQ: | 
|  | 3362 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | 
|  | 3363 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | 
|  | 3364 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3365 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3366 | printk(KERN_DEBUG | 
|  | 3367 | "%s: PH_DEACTIVATE port %d (0..%d)\n", | 
|  | 3368 | __func__, hc->chan[dch->slot].port, | 
|  | 3369 | hc->ports-1); | 
|  | 3370 | /* start deactivation */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3371 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3372 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3373 | printk(KERN_DEBUG | 
|  | 3374 | "%s: PH_DEACTIVATE no BRI\n", | 
|  | 3375 | __func__); | 
|  | 3376 | } else { | 
|  | 3377 | HFC_outb(hc, R_ST_SEL, | 
|  | 3378 | hc->chan[dch->slot].port); | 
|  | 3379 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3380 | udelay(1); | 
|  | 3381 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); | 
|  | 3382 | /* deactivate */ | 
|  | 3383 | dch->state = 1; | 
|  | 3384 | } | 
|  | 3385 | skb_queue_purge(&dch->squeue); | 
|  | 3386 | if (dch->tx_skb) { | 
|  | 3387 | dev_kfree_skb(dch->tx_skb); | 
|  | 3388 | dch->tx_skb = NULL; | 
|  | 3389 | } | 
|  | 3390 | dch->tx_idx = 0; | 
|  | 3391 | if (dch->rx_skb) { | 
|  | 3392 | dev_kfree_skb(dch->rx_skb); | 
|  | 3393 | dch->rx_skb = NULL; | 
|  | 3394 | } | 
|  | 3395 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | 
|  | 3396 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | 
|  | 3397 | del_timer(&dch->timer); | 
|  | 3398 | #ifdef FIXME | 
|  | 3399 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | 
|  | 3400 | dchannel_sched_event(&hc->dch, D_CLEARBUSY); | 
|  | 3401 | #endif | 
|  | 3402 | ret = 0; | 
|  | 3403 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3404 | } else | 
|  | 3405 | ret = l1_event(dch->l1, hh->prim); | 
|  | 3406 | break; | 
|  | 3407 | } | 
|  | 3408 | if (!ret) | 
|  | 3409 | dev_kfree_skb(skb); | 
|  | 3410 | return ret; | 
|  | 3411 | } | 
|  | 3412 |  | 
|  | 3413 | static void | 
|  | 3414 | deactivate_bchannel(struct bchannel *bch) | 
|  | 3415 | { | 
|  | 3416 | struct hfc_multi	*hc = bch->hw; | 
|  | 3417 | u_long			flags; | 
|  | 3418 |  | 
|  | 3419 | spin_lock_irqsave(&hc->lock, flags); | 
| Karsten Keil | fb286f0 | 2009-07-09 10:02:29 +0200 | [diff] [blame] | 3420 | mISDN_clear_bchannel(bch); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3421 | hc->chan[bch->slot].coeff_count = 0; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3422 | hc->chan[bch->slot].rx_off = 0; | 
|  | 3423 | hc->chan[bch->slot].conf = -1; | 
|  | 3424 | mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); | 
|  | 3425 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3426 | } | 
|  | 3427 |  | 
|  | 3428 | static int | 
|  | 3429 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | 
|  | 3430 | { | 
|  | 3431 | struct bchannel		*bch = container_of(ch, struct bchannel, ch); | 
|  | 3432 | struct hfc_multi	*hc = bch->hw; | 
|  | 3433 | int			ret = -EINVAL; | 
|  | 3434 | struct mISDNhead	*hh = mISDN_HEAD_P(skb); | 
|  | 3435 | unsigned int		id; | 
|  | 3436 | u_long			flags; | 
|  | 3437 |  | 
|  | 3438 | switch (hh->prim) { | 
|  | 3439 | case PH_DATA_REQ: | 
|  | 3440 | if (!skb->len) | 
|  | 3441 | break; | 
|  | 3442 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3443 | ret = bchannel_senddata(bch, skb); | 
|  | 3444 | if (ret > 0) { /* direct TX */ | 
|  | 3445 | id = hh->id; /* skb can be freed */ | 
|  | 3446 | hfcmulti_tx(hc, bch->slot); | 
|  | 3447 | ret = 0; | 
|  | 3448 | /* start fifo */ | 
|  | 3449 | HFC_outb_nodebug(hc, R_FIFO, 0); | 
|  | 3450 | HFC_wait_nodebug(hc); | 
|  | 3451 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { | 
|  | 3452 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3453 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | 
|  | 3454 | } else | 
|  | 3455 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3456 | } else | 
|  | 3457 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3458 | return ret; | 
|  | 3459 | case PH_ACTIVATE_REQ: | 
|  | 3460 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3461 | printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", | 
|  | 3462 | __func__, bch->slot); | 
|  | 3463 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3464 | /* activate B-channel if not already activated */ | 
|  | 3465 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { | 
|  | 3466 | hc->chan[bch->slot].txpending = 0; | 
|  | 3467 | ret = mode_hfcmulti(hc, bch->slot, | 
|  | 3468 | ch->protocol, | 
|  | 3469 | hc->chan[bch->slot].slot_tx, | 
|  | 3470 | hc->chan[bch->slot].bank_tx, | 
|  | 3471 | hc->chan[bch->slot].slot_rx, | 
|  | 3472 | hc->chan[bch->slot].bank_rx); | 
|  | 3473 | if (!ret) { | 
|  | 3474 | if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf | 
|  | 3475 | && test_bit(HFC_CHIP_DTMF, &hc->chip)) { | 
|  | 3476 | /* start decoder */ | 
|  | 3477 | hc->dtmf = 1; | 
|  | 3478 | if (debug & DEBUG_HFCMULTI_DTMF) | 
|  | 3479 | printk(KERN_DEBUG | 
|  | 3480 | "%s: start dtmf decoder\n", | 
|  | 3481 | __func__); | 
|  | 3482 | HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | | 
|  | 3483 | V_RST_DTMF); | 
|  | 3484 | } | 
|  | 3485 | } | 
|  | 3486 | } else | 
|  | 3487 | ret = 0; | 
|  | 3488 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3489 | if (!ret) | 
|  | 3490 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | 
|  | 3491 | GFP_KERNEL); | 
|  | 3492 | break; | 
|  | 3493 | case PH_CONTROL_REQ: | 
|  | 3494 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3495 | switch (hh->id) { | 
|  | 3496 | case HFC_SPL_LOOP_ON: /* set sample loop */ | 
|  | 3497 | if (debug & DEBUG_HFCMULTI_MSG) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 3498 | printk(KERN_DEBUG | 
|  | 3499 | "%s: HFC_SPL_LOOP_ON (len = %d)\n", | 
|  | 3500 | __func__, skb->len); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3501 | ret = 0; | 
|  | 3502 | break; | 
|  | 3503 | case HFC_SPL_LOOP_OFF: /* set silence */ | 
|  | 3504 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3505 | printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", | 
|  | 3506 | __func__); | 
|  | 3507 | ret = 0; | 
|  | 3508 | break; | 
|  | 3509 | default: | 
|  | 3510 | printk(KERN_ERR | 
|  | 3511 | "%s: unknown PH_CONTROL_REQ info %x\n", | 
|  | 3512 | __func__, hh->id); | 
|  | 3513 | ret = -EINVAL; | 
|  | 3514 | } | 
|  | 3515 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3516 | break; | 
|  | 3517 | case PH_DEACTIVATE_REQ: | 
|  | 3518 | deactivate_bchannel(bch); /* locked there */ | 
|  | 3519 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | 
|  | 3520 | GFP_KERNEL); | 
|  | 3521 | ret = 0; | 
|  | 3522 | break; | 
|  | 3523 | } | 
|  | 3524 | if (!ret) | 
|  | 3525 | dev_kfree_skb(skb); | 
|  | 3526 | return ret; | 
|  | 3527 | } | 
|  | 3528 |  | 
|  | 3529 | /* | 
|  | 3530 | * bchannel control function | 
|  | 3531 | */ | 
|  | 3532 | static int | 
|  | 3533 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | 
|  | 3534 | { | 
|  | 3535 | int			ret = 0; | 
|  | 3536 | struct dsp_features	*features = | 
|  | 3537 | (struct dsp_features *)(*((u_long *)&cq->p1)); | 
|  | 3538 | struct hfc_multi	*hc = bch->hw; | 
|  | 3539 | int			slot_tx; | 
|  | 3540 | int			bank_tx; | 
|  | 3541 | int			slot_rx; | 
|  | 3542 | int			bank_rx; | 
|  | 3543 | int			num; | 
|  | 3544 |  | 
|  | 3545 | switch (cq->op) { | 
|  | 3546 | case MISDN_CTRL_GETOP: | 
|  | 3547 | cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 3548 | | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3549 | break; | 
|  | 3550 | case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ | 
|  | 3551 | hc->chan[bch->slot].rx_off = !!cq->p1; | 
|  | 3552 | if (!hc->chan[bch->slot].rx_off) { | 
|  | 3553 | /* reset fifo on rx on */ | 
|  | 3554 | HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); | 
|  | 3555 | HFC_wait_nodebug(hc); | 
|  | 3556 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | 
|  | 3557 | HFC_wait_nodebug(hc); | 
|  | 3558 | } | 
|  | 3559 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3560 | printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", | 
|  | 3561 | __func__, bch->nr, hc->chan[bch->slot].rx_off); | 
|  | 3562 | break; | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 3563 | case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ | 
|  | 3564 | test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); | 
|  | 3565 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3566 | printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " | 
|  | 3567 | "off=%d)\n", __func__, bch->nr, !!cq->p1); | 
|  | 3568 | break; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3569 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | 
|  | 3570 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3571 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | 
|  | 3572 | __func__); | 
|  | 3573 | /* create confirm */ | 
|  | 3574 | features->hfc_id = hc->id; | 
|  | 3575 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) | 
|  | 3576 | features->hfc_dtmf = 1; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3577 | if (test_bit(HFC_CHIP_CONF, &hc->chip)) | 
|  | 3578 | features->hfc_conf = 1; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3579 | features->hfc_loops = 0; | 
|  | 3580 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | 
|  | 3581 | features->hfc_echocanhw = 1; | 
|  | 3582 | } else { | 
|  | 3583 | features->pcm_id = hc->pcm; | 
|  | 3584 | features->pcm_slots = hc->slots; | 
|  | 3585 | features->pcm_banks = 2; | 
|  | 3586 | } | 
|  | 3587 | break; | 
|  | 3588 | case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ | 
|  | 3589 | slot_tx = cq->p1 & 0xff; | 
|  | 3590 | bank_tx = cq->p1 >> 8; | 
|  | 3591 | slot_rx = cq->p2 & 0xff; | 
|  | 3592 | bank_rx = cq->p2 >> 8; | 
|  | 3593 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3594 | printk(KERN_DEBUG | 
|  | 3595 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | 
|  | 3596 | "slot %d bank %d (RX)\n", | 
|  | 3597 | __func__, slot_tx, bank_tx, | 
|  | 3598 | slot_rx, bank_rx); | 
|  | 3599 | if (slot_tx < hc->slots && bank_tx <= 2 && | 
|  | 3600 | slot_rx < hc->slots && bank_rx <= 2) | 
|  | 3601 | hfcmulti_pcm(hc, bch->slot, | 
|  | 3602 | slot_tx, bank_tx, slot_rx, bank_rx); | 
|  | 3603 | else { | 
|  | 3604 | printk(KERN_WARNING | 
|  | 3605 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | 
|  | 3606 | "slot %d bank %d (RX) out of range\n", | 
|  | 3607 | __func__, slot_tx, bank_tx, | 
|  | 3608 | slot_rx, bank_rx); | 
|  | 3609 | ret = -EINVAL; | 
|  | 3610 | } | 
|  | 3611 | break; | 
|  | 3612 | case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ | 
|  | 3613 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3614 | printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", | 
|  | 3615 | __func__); | 
|  | 3616 | hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); | 
|  | 3617 | break; | 
|  | 3618 | case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ | 
|  | 3619 | num = cq->p1 & 0xff; | 
|  | 3620 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3621 | printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", | 
|  | 3622 | __func__, num); | 
|  | 3623 | if (num <= 7) | 
|  | 3624 | hfcmulti_conf(hc, bch->slot, num); | 
|  | 3625 | else { | 
|  | 3626 | printk(KERN_WARNING | 
|  | 3627 | "%s: HW_CONF_JOIN conf %d out of range\n", | 
|  | 3628 | __func__, num); | 
|  | 3629 | ret = -EINVAL; | 
|  | 3630 | } | 
|  | 3631 | break; | 
|  | 3632 | case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ | 
|  | 3633 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3634 | printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); | 
|  | 3635 | hfcmulti_conf(hc, bch->slot, -1); | 
|  | 3636 | break; | 
|  | 3637 | case MISDN_CTRL_HFC_ECHOCAN_ON: | 
|  | 3638 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3639 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); | 
|  | 3640 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | 
|  | 3641 | vpm_echocan_on(hc, bch->slot, cq->p1); | 
|  | 3642 | else | 
|  | 3643 | ret = -EINVAL; | 
|  | 3644 | break; | 
|  | 3645 |  | 
|  | 3646 | case MISDN_CTRL_HFC_ECHOCAN_OFF: | 
|  | 3647 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 3648 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", | 
|  | 3649 | __func__); | 
|  | 3650 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | 
|  | 3651 | vpm_echocan_off(hc, bch->slot); | 
|  | 3652 | else | 
|  | 3653 | ret = -EINVAL; | 
|  | 3654 | break; | 
|  | 3655 | default: | 
|  | 3656 | printk(KERN_WARNING "%s: unknown Op %x\n", | 
|  | 3657 | __func__, cq->op); | 
|  | 3658 | ret = -EINVAL; | 
|  | 3659 | break; | 
|  | 3660 | } | 
|  | 3661 | return ret; | 
|  | 3662 | } | 
|  | 3663 |  | 
|  | 3664 | static int | 
|  | 3665 | hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | 
|  | 3666 | { | 
|  | 3667 | struct bchannel		*bch = container_of(ch, struct bchannel, ch); | 
|  | 3668 | struct hfc_multi	*hc = bch->hw; | 
|  | 3669 | int			err = -EINVAL; | 
|  | 3670 | u_long	flags; | 
|  | 3671 |  | 
|  | 3672 | if (bch->debug & DEBUG_HW) | 
|  | 3673 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | 
|  | 3674 | __func__, cmd, arg); | 
|  | 3675 | switch (cmd) { | 
|  | 3676 | case CLOSE_CHANNEL: | 
|  | 3677 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | 
|  | 3678 | if (test_bit(FLG_ACTIVE, &bch->Flags)) | 
|  | 3679 | deactivate_bchannel(bch); /* locked there */ | 
|  | 3680 | ch->protocol = ISDN_P_NONE; | 
|  | 3681 | ch->peer = NULL; | 
|  | 3682 | module_put(THIS_MODULE); | 
|  | 3683 | err = 0; | 
|  | 3684 | break; | 
|  | 3685 | case CONTROL_CHANNEL: | 
|  | 3686 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 3687 | err = channel_bctrl(bch, arg); | 
|  | 3688 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 3689 | break; | 
|  | 3690 | default: | 
|  | 3691 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | 
|  | 3692 | __func__, cmd); | 
|  | 3693 | } | 
|  | 3694 | return err; | 
|  | 3695 | } | 
|  | 3696 |  | 
|  | 3697 | /* | 
|  | 3698 | * handle D-channel events | 
|  | 3699 | * | 
|  | 3700 | * handle state change event | 
|  | 3701 | */ | 
|  | 3702 | static void | 
|  | 3703 | ph_state_change(struct dchannel *dch) | 
|  | 3704 | { | 
| Julia Lawall | 20b7880 | 2009-01-09 12:22:53 -0800 | [diff] [blame] | 3705 | struct hfc_multi *hc; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3706 | int ch, i; | 
|  | 3707 |  | 
|  | 3708 | if (!dch) { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 3709 | printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3710 | return; | 
|  | 3711 | } | 
| Julia Lawall | 20b7880 | 2009-01-09 12:22:53 -0800 | [diff] [blame] | 3712 | hc = dch->hw; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3713 | ch = dch->slot; | 
|  | 3714 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3715 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3716 | if (dch->dev.D.protocol == ISDN_P_TE_E1) { | 
|  | 3717 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 3718 | printk(KERN_DEBUG | 
|  | 3719 | "%s: E1 TE (id=%d) newstate %x\n", | 
|  | 3720 | __func__, hc->id, dch->state); | 
|  | 3721 | } else { | 
|  | 3722 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 3723 | printk(KERN_DEBUG | 
|  | 3724 | "%s: E1 NT (id=%d) newstate %x\n", | 
|  | 3725 | __func__, hc->id, dch->state); | 
|  | 3726 | } | 
|  | 3727 | switch (dch->state) { | 
|  | 3728 | case (1): | 
|  | 3729 | if (hc->e1_state != 1) { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 3730 | for (i = 1; i <= 31; i++) { | 
|  | 3731 | /* reset fifos on e1 activation */ | 
|  | 3732 | HFC_outb_nodebug(hc, R_FIFO, | 
|  | 3733 | (i << 1) | 1); | 
|  | 3734 | HFC_wait_nodebug(hc); | 
|  | 3735 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, | 
|  | 3736 | V_RES_F); | 
|  | 3737 | HFC_wait_nodebug(hc); | 
|  | 3738 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3739 | } | 
|  | 3740 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3741 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | 
|  | 3742 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | 
|  | 3743 | break; | 
|  | 3744 |  | 
|  | 3745 | default: | 
|  | 3746 | if (hc->e1_state != 1) | 
|  | 3747 | return; | 
|  | 3748 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3749 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | 
|  | 3750 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | 
|  | 3751 | } | 
|  | 3752 | hc->e1_state = dch->state; | 
|  | 3753 | } else { | 
|  | 3754 | if (dch->dev.D.protocol == ISDN_P_TE_S0) { | 
|  | 3755 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 3756 | printk(KERN_DEBUG | 
|  | 3757 | "%s: S/T TE newstate %x\n", | 
|  | 3758 | __func__, dch->state); | 
|  | 3759 | switch (dch->state) { | 
|  | 3760 | case (0): | 
|  | 3761 | l1_event(dch->l1, HW_RESET_IND); | 
|  | 3762 | break; | 
|  | 3763 | case (3): | 
|  | 3764 | l1_event(dch->l1, HW_DEACT_IND); | 
|  | 3765 | break; | 
|  | 3766 | case (5): | 
|  | 3767 | case (8): | 
|  | 3768 | l1_event(dch->l1, ANYSIGNAL); | 
|  | 3769 | break; | 
|  | 3770 | case (6): | 
|  | 3771 | l1_event(dch->l1, INFO2); | 
|  | 3772 | break; | 
|  | 3773 | case (7): | 
|  | 3774 | l1_event(dch->l1, INFO4_P8); | 
|  | 3775 | break; | 
|  | 3776 | } | 
|  | 3777 | } else { | 
|  | 3778 | if (debug & DEBUG_HFCMULTI_STATE) | 
|  | 3779 | printk(KERN_DEBUG "%s: S/T NT newstate %x\n", | 
|  | 3780 | __func__, dch->state); | 
|  | 3781 | switch (dch->state) { | 
|  | 3782 | case (2): | 
|  | 3783 | if (hc->chan[ch].nt_timer == 0) { | 
|  | 3784 | hc->chan[ch].nt_timer = -1; | 
|  | 3785 | HFC_outb(hc, R_ST_SEL, | 
|  | 3786 | hc->chan[ch].port); | 
|  | 3787 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3788 | udelay(1); | 
|  | 3789 | HFC_outb(hc, A_ST_WR_STATE, 4 | | 
|  | 3790 | V_ST_LD_STA); /* G4 */ | 
|  | 3791 | udelay(6); /* wait at least 5,21us */ | 
|  | 3792 | HFC_outb(hc, A_ST_WR_STATE, 4); | 
|  | 3793 | dch->state = 4; | 
|  | 3794 | } else { | 
|  | 3795 | /* one extra count for the next event */ | 
|  | 3796 | hc->chan[ch].nt_timer = | 
|  | 3797 | nt_t1_count[poll_timer] + 1; | 
|  | 3798 | HFC_outb(hc, R_ST_SEL, | 
|  | 3799 | hc->chan[ch].port); | 
|  | 3800 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3801 | udelay(1); | 
|  | 3802 | /* allow G2 -> G3 transition */ | 
|  | 3803 | HFC_outb(hc, A_ST_WR_STATE, 2 | | 
|  | 3804 | V_SET_G2_G3); | 
|  | 3805 | } | 
|  | 3806 | break; | 
|  | 3807 | case (1): | 
|  | 3808 | hc->chan[ch].nt_timer = -1; | 
|  | 3809 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3810 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | 
|  | 3811 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | 
|  | 3812 | break; | 
|  | 3813 | case (4): | 
|  | 3814 | hc->chan[ch].nt_timer = -1; | 
|  | 3815 | break; | 
|  | 3816 | case (3): | 
|  | 3817 | hc->chan[ch].nt_timer = -1; | 
|  | 3818 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | 
|  | 3819 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | 
|  | 3820 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | 
|  | 3821 | break; | 
|  | 3822 | } | 
|  | 3823 | } | 
|  | 3824 | } | 
|  | 3825 | } | 
|  | 3826 |  | 
|  | 3827 | /* | 
|  | 3828 | * called for card mode init message | 
|  | 3829 | */ | 
|  | 3830 |  | 
|  | 3831 | static void | 
|  | 3832 | hfcmulti_initmode(struct dchannel *dch) | 
|  | 3833 | { | 
|  | 3834 | struct hfc_multi *hc = dch->hw; | 
|  | 3835 | u_char		a_st_wr_state, r_e1_wr_sta; | 
|  | 3836 | int		i, pt; | 
|  | 3837 |  | 
|  | 3838 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3839 | printk(KERN_DEBUG "%s: entered\n", __func__); | 
|  | 3840 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3841 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3842 | hc->chan[hc->dslot].slot_tx = -1; | 
|  | 3843 | hc->chan[hc->dslot].slot_rx = -1; | 
|  | 3844 | hc->chan[hc->dslot].conf = -1; | 
|  | 3845 | if (hc->dslot) { | 
|  | 3846 | mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol, | 
|  | 3847 | -1, 0, -1, 0); | 
|  | 3848 | dch->timer.function = (void *) hfcmulti_dbusy_timer; | 
|  | 3849 | dch->timer.data = (long) dch; | 
|  | 3850 | init_timer(&dch->timer); | 
|  | 3851 | } | 
|  | 3852 | for (i = 1; i <= 31; i++) { | 
|  | 3853 | if (i == hc->dslot) | 
|  | 3854 | continue; | 
|  | 3855 | hc->chan[i].slot_tx = -1; | 
|  | 3856 | hc->chan[i].slot_rx = -1; | 
|  | 3857 | hc->chan[i].conf = -1; | 
|  | 3858 | mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); | 
|  | 3859 | } | 
|  | 3860 | /* E1 */ | 
|  | 3861 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | 
|  | 3862 | HFC_outb(hc, R_LOS0, 255); /* 2 ms */ | 
|  | 3863 | HFC_outb(hc, R_LOS1, 255); /* 512 ms */ | 
|  | 3864 | } | 
|  | 3865 | if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) { | 
|  | 3866 | HFC_outb(hc, R_RX0, 0); | 
|  | 3867 | hc->hw.r_tx0 = 0 | V_OUT_EN; | 
|  | 3868 | } else { | 
|  | 3869 | HFC_outb(hc, R_RX0, 1); | 
|  | 3870 | hc->hw.r_tx0 = 1 | V_OUT_EN; | 
|  | 3871 | } | 
|  | 3872 | hc->hw.r_tx1 = V_ATX | V_NTRI; | 
|  | 3873 | HFC_outb(hc, R_TX0, hc->hw.r_tx0); | 
|  | 3874 | HFC_outb(hc, R_TX1, hc->hw.r_tx1); | 
|  | 3875 | HFC_outb(hc, R_TX_FR0, 0x00); | 
|  | 3876 | HFC_outb(hc, R_TX_FR1, 0xf8); | 
|  | 3877 |  | 
|  | 3878 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | 
|  | 3879 | HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); | 
|  | 3880 |  | 
|  | 3881 | HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); | 
|  | 3882 |  | 
|  | 3883 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | 
|  | 3884 | HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); | 
|  | 3885 |  | 
|  | 3886 | if (dch->dev.D.protocol == ISDN_P_NT_E1) { | 
|  | 3887 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3888 | printk(KERN_DEBUG "%s: E1 port is NT-mode\n", | 
|  | 3889 | __func__); | 
|  | 3890 | r_e1_wr_sta = 0; /* G0 */ | 
|  | 3891 | hc->e1_getclock = 0; | 
|  | 3892 | } else { | 
|  | 3893 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3894 | printk(KERN_DEBUG "%s: E1 port is TE-mode\n", | 
|  | 3895 | __func__); | 
|  | 3896 | r_e1_wr_sta = 0; /* F0 */ | 
|  | 3897 | hc->e1_getclock = 1; | 
|  | 3898 | } | 
|  | 3899 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | 
|  | 3900 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | 
|  | 3901 | else | 
|  | 3902 | HFC_outb(hc, R_SYNC_OUT, 0); | 
|  | 3903 | if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) | 
|  | 3904 | hc->e1_getclock = 1; | 
|  | 3905 | if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) | 
|  | 3906 | hc->e1_getclock = 0; | 
|  | 3907 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | 
|  | 3908 | /* SLAVE (clock master) */ | 
|  | 3909 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3910 | printk(KERN_DEBUG | 
|  | 3911 | "%s: E1 port is clock master " | 
|  | 3912 | "(clock from PCM)\n", __func__); | 
|  | 3913 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); | 
|  | 3914 | } else { | 
|  | 3915 | if (hc->e1_getclock) { | 
|  | 3916 | /* MASTER (clock slave) */ | 
|  | 3917 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3918 | printk(KERN_DEBUG | 
|  | 3919 | "%s: E1 port is clock slave " | 
|  | 3920 | "(clock to PCM)\n", __func__); | 
|  | 3921 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | 
|  | 3922 | } else { | 
|  | 3923 | /* MASTER (clock master) */ | 
|  | 3924 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3925 | printk(KERN_DEBUG "%s: E1 port is " | 
|  | 3926 | "clock master " | 
|  | 3927 | "(clock from QUARTZ)\n", | 
|  | 3928 | __func__); | 
|  | 3929 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | | 
|  | 3930 | V_PCM_SYNC | V_JATT_OFF); | 
|  | 3931 | HFC_outb(hc, R_SYNC_OUT, 0); | 
|  | 3932 | } | 
|  | 3933 | } | 
|  | 3934 | HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ | 
|  | 3935 | HFC_outb(hc, R_PWM_MD, V_PWM0_MD); | 
|  | 3936 | HFC_outb(hc, R_PWM0, 0x50); | 
|  | 3937 | HFC_outb(hc, R_PWM1, 0xff); | 
|  | 3938 | /* state machine setup */ | 
|  | 3939 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); | 
|  | 3940 | udelay(6); /* wait at least 5,21us */ | 
|  | 3941 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); | 
|  | 3942 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 3943 | hc->syncronized = 0; | 
|  | 3944 | plxsd_checksync(hc, 0); | 
|  | 3945 | } | 
|  | 3946 | } else { | 
|  | 3947 | i = dch->slot; | 
|  | 3948 | hc->chan[i].slot_tx = -1; | 
|  | 3949 | hc->chan[i].slot_rx = -1; | 
|  | 3950 | hc->chan[i].conf = -1; | 
|  | 3951 | mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); | 
|  | 3952 | dch->timer.function = (void *)hfcmulti_dbusy_timer; | 
|  | 3953 | dch->timer.data = (long) dch; | 
|  | 3954 | init_timer(&dch->timer); | 
|  | 3955 | hc->chan[i - 2].slot_tx = -1; | 
|  | 3956 | hc->chan[i - 2].slot_rx = -1; | 
|  | 3957 | hc->chan[i - 2].conf = -1; | 
|  | 3958 | mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); | 
|  | 3959 | hc->chan[i - 1].slot_tx = -1; | 
|  | 3960 | hc->chan[i - 1].slot_rx = -1; | 
|  | 3961 | hc->chan[i - 1].conf = -1; | 
|  | 3962 | mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); | 
|  | 3963 | /* ST */ | 
|  | 3964 | pt = hc->chan[i].port; | 
|  | 3965 | /* select interface */ | 
|  | 3966 | HFC_outb(hc, R_ST_SEL, pt); | 
|  | 3967 | /* undocumented: delay after R_ST_SEL */ | 
|  | 3968 | udelay(1); | 
|  | 3969 | if (dch->dev.D.protocol == ISDN_P_NT_S0) { | 
|  | 3970 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3971 | printk(KERN_DEBUG | 
|  | 3972 | "%s: ST port %d is NT-mode\n", | 
|  | 3973 | __func__, pt); | 
|  | 3974 | /* clock delay */ | 
|  | 3975 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); | 
|  | 3976 | a_st_wr_state = 1; /* G1 */ | 
|  | 3977 | hc->hw.a_st_ctrl0[pt] = V_ST_MD; | 
|  | 3978 | } else { | 
|  | 3979 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 3980 | printk(KERN_DEBUG | 
|  | 3981 | "%s: ST port %d is TE-mode\n", | 
|  | 3982 | __func__, pt); | 
|  | 3983 | /* clock delay */ | 
|  | 3984 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); | 
|  | 3985 | a_st_wr_state = 2; /* F2 */ | 
|  | 3986 | hc->hw.a_st_ctrl0[pt] = 0; | 
|  | 3987 | } | 
|  | 3988 | if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) | 
|  | 3989 | hc->hw.a_st_ctrl0[pt] |= V_TX_LI; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 3990 | if (hc->ctype == HFC_TYPE_XHFC) { | 
|  | 3991 | hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; | 
|  | 3992 | HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, | 
|  | 3993 | 0x7c << 1 /* V_ST_PULSE */); | 
|  | 3994 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 3995 | /* line setup */ | 
|  | 3996 | HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[pt]); | 
|  | 3997 | /* disable E-channel */ | 
|  | 3998 | if ((dch->dev.D.protocol == ISDN_P_NT_S0) || | 
|  | 3999 | test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) | 
|  | 4000 | HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); | 
|  | 4001 | else | 
|  | 4002 | HFC_outb(hc, A_ST_CTRL1, 0); | 
|  | 4003 | /* enable B-channel receive */ | 
|  | 4004 | HFC_outb(hc, A_ST_CTRL2,  V_B1_RX_EN | V_B2_RX_EN); | 
|  | 4005 | /* state machine setup */ | 
|  | 4006 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); | 
|  | 4007 | udelay(6); /* wait at least 5,21us */ | 
|  | 4008 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); | 
|  | 4009 | hc->hw.r_sci_msk |= 1 << pt; | 
|  | 4010 | /* state machine interrupts */ | 
|  | 4011 | HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); | 
|  | 4012 | /* unset sync on port */ | 
|  | 4013 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4014 | hc->syncronized &= | 
|  | 4015 | ~(1 << hc->chan[dch->slot].port); | 
|  | 4016 | plxsd_checksync(hc, 0); | 
|  | 4017 | } | 
|  | 4018 | } | 
|  | 4019 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4020 | printk("%s: done\n", __func__); | 
|  | 4021 | } | 
|  | 4022 |  | 
|  | 4023 |  | 
|  | 4024 | static int | 
|  | 4025 | open_dchannel(struct hfc_multi *hc, struct dchannel *dch, | 
|  | 4026 | struct channel_req *rq) | 
|  | 4027 | { | 
|  | 4028 | int	err = 0; | 
|  | 4029 | u_long	flags; | 
|  | 4030 |  | 
|  | 4031 | if (debug & DEBUG_HW_OPEN) | 
|  | 4032 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | 
|  | 4033 | dch->dev.id, __builtin_return_address(0)); | 
|  | 4034 | if (rq->protocol == ISDN_P_NONE) | 
|  | 4035 | return -EINVAL; | 
|  | 4036 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | 
|  | 4037 | (dch->dev.D.protocol != rq->protocol)) { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4038 | if (debug & DEBUG_HFCMULTI_MODE) | 
|  | 4039 | printk(KERN_DEBUG "%s: change protocol %x to %x\n", | 
|  | 4040 | __func__, dch->dev.D.protocol, rq->protocol); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4041 | } | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4042 | if ((dch->dev.D.protocol == ISDN_P_TE_S0) && | 
|  | 4043 | (rq->protocol != ISDN_P_TE_S0)) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4044 | l1_event(dch->l1, CLOSE_CHANNEL); | 
|  | 4045 | if (dch->dev.D.protocol != rq->protocol) { | 
|  | 4046 | if (rq->protocol == ISDN_P_TE_S0) { | 
|  | 4047 | err = create_l1(dch, hfcm_l1callback); | 
|  | 4048 | if (err) | 
|  | 4049 | return err; | 
|  | 4050 | } | 
|  | 4051 | dch->dev.D.protocol = rq->protocol; | 
|  | 4052 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4053 | hfcmulti_initmode(dch); | 
|  | 4054 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4055 | } | 
|  | 4056 |  | 
|  | 4057 | if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) || | 
|  | 4058 | ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) || | 
|  | 4059 | ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) || | 
|  | 4060 | ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) { | 
|  | 4061 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | 
|  | 4062 | 0, NULL, GFP_KERNEL); | 
|  | 4063 | } | 
|  | 4064 | rq->ch = &dch->dev.D; | 
|  | 4065 | if (!try_module_get(THIS_MODULE)) | 
|  | 4066 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | 
|  | 4067 | return 0; | 
|  | 4068 | } | 
|  | 4069 |  | 
|  | 4070 | static int | 
|  | 4071 | open_bchannel(struct hfc_multi *hc, struct dchannel *dch, | 
|  | 4072 | struct channel_req *rq) | 
|  | 4073 | { | 
|  | 4074 | struct bchannel	*bch; | 
|  | 4075 | int		ch; | 
|  | 4076 |  | 
| Karsten Keil | ff4cc1d | 2008-07-30 18:26:58 +0200 | [diff] [blame] | 4077 | if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4078 | return -EINVAL; | 
|  | 4079 | if (rq->protocol == ISDN_P_NONE) | 
|  | 4080 | return -EINVAL; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4081 | if (hc->ctype == HFC_TYPE_E1) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4082 | ch = rq->adr.channel; | 
|  | 4083 | else | 
|  | 4084 | ch = (rq->adr.channel - 1) + (dch->slot - 2); | 
|  | 4085 | bch = hc->chan[ch].bch; | 
|  | 4086 | if (!bch) { | 
|  | 4087 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | 
|  | 4088 | __func__, ch); | 
|  | 4089 | return -EINVAL; | 
|  | 4090 | } | 
|  | 4091 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | 
|  | 4092 | return -EBUSY; /* b-channel can be only open once */ | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 4093 | test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4094 | bch->ch.protocol = rq->protocol; | 
|  | 4095 | hc->chan[ch].rx_off = 0; | 
|  | 4096 | rq->ch = &bch->ch; | 
|  | 4097 | if (!try_module_get(THIS_MODULE)) | 
|  | 4098 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | 
|  | 4099 | return 0; | 
|  | 4100 | } | 
|  | 4101 |  | 
|  | 4102 | /* | 
|  | 4103 | * device control function | 
|  | 4104 | */ | 
|  | 4105 | static int | 
|  | 4106 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | 
|  | 4107 | { | 
| Andreas Eversberg | 7df3bb8 | 2009-05-22 11:04:44 +0000 | [diff] [blame] | 4108 | struct hfc_multi	*hc = dch->hw; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4109 | int	ret = 0; | 
| Andreas Eversberg | 7df3bb8 | 2009-05-22 11:04:44 +0000 | [diff] [blame] | 4110 | int	wd_mode, wd_cnt; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4111 |  | 
|  | 4112 | switch (cq->op) { | 
|  | 4113 | case MISDN_CTRL_GETOP: | 
| Andreas Eversberg | 7df3bb8 | 2009-05-22 11:04:44 +0000 | [diff] [blame] | 4114 | cq->op = MISDN_CTRL_HFC_OP; | 
|  | 4115 | break; | 
|  | 4116 | case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ | 
|  | 4117 | wd_cnt = cq->p1 & 0xf; | 
|  | 4118 | wd_mode = !!(cq->p1 >> 4); | 
|  | 4119 | if (debug & DEBUG_HFCMULTI_MSG) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4120 | printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" | 
|  | 4121 | ", counter 0x%x\n", __func__, | 
|  | 4122 | wd_mode ? "AUTO" : "MANUAL", wd_cnt); | 
| Andreas Eversberg | 7df3bb8 | 2009-05-22 11:04:44 +0000 | [diff] [blame] | 4123 | /* set the watchdog timer */ | 
|  | 4124 | HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); | 
|  | 4125 | hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); | 
|  | 4126 | if (hc->ctype == HFC_TYPE_XHFC) | 
|  | 4127 | hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; | 
|  | 4128 | /* init the watchdog register and reset the counter */ | 
|  | 4129 | HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); | 
|  | 4130 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4131 | /* enable the watchdog output for Speech-Design */ | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4132 | HFC_outb(hc, R_GPIO_SEL,  V_GPIO_SEL7); | 
|  | 4133 | HFC_outb(hc, R_GPIO_EN1,  V_GPIO_EN15); | 
| Andreas Eversberg | 7df3bb8 | 2009-05-22 11:04:44 +0000 | [diff] [blame] | 4134 | HFC_outb(hc, R_GPIO_OUT1, 0); | 
|  | 4135 | HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); | 
|  | 4136 | } | 
|  | 4137 | break; | 
|  | 4138 | case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ | 
|  | 4139 | if (debug & DEBUG_HFCMULTI_MSG) | 
|  | 4140 | printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", | 
|  | 4141 | __func__); | 
|  | 4142 | HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4143 | break; | 
|  | 4144 | default: | 
|  | 4145 | printk(KERN_WARNING "%s: unknown Op %x\n", | 
|  | 4146 | __func__, cq->op); | 
|  | 4147 | ret = -EINVAL; | 
|  | 4148 | break; | 
|  | 4149 | } | 
|  | 4150 | return ret; | 
|  | 4151 | } | 
|  | 4152 |  | 
|  | 4153 | static int | 
|  | 4154 | hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | 
|  | 4155 | { | 
|  | 4156 | struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D); | 
|  | 4157 | struct dchannel		*dch = container_of(dev, struct dchannel, dev); | 
|  | 4158 | struct hfc_multi	*hc = dch->hw; | 
|  | 4159 | struct channel_req	*rq; | 
|  | 4160 | int			err = 0; | 
|  | 4161 | u_long			flags; | 
|  | 4162 |  | 
|  | 4163 | if (dch->debug & DEBUG_HW) | 
|  | 4164 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | 
|  | 4165 | __func__, cmd, arg); | 
|  | 4166 | switch (cmd) { | 
|  | 4167 | case OPEN_CHANNEL: | 
|  | 4168 | rq = arg; | 
|  | 4169 | switch (rq->protocol) { | 
|  | 4170 | case ISDN_P_TE_S0: | 
|  | 4171 | case ISDN_P_NT_S0: | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4172 | if (hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4173 | err = -EINVAL; | 
|  | 4174 | break; | 
|  | 4175 | } | 
|  | 4176 | err = open_dchannel(hc, dch, rq); /* locked there */ | 
|  | 4177 | break; | 
|  | 4178 | case ISDN_P_TE_E1: | 
|  | 4179 | case ISDN_P_NT_E1: | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4180 | if (hc->ctype != HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4181 | err = -EINVAL; | 
|  | 4182 | break; | 
|  | 4183 | } | 
|  | 4184 | err = open_dchannel(hc, dch, rq); /* locked there */ | 
|  | 4185 | break; | 
|  | 4186 | default: | 
|  | 4187 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4188 | err = open_bchannel(hc, dch, rq); | 
|  | 4189 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4190 | } | 
|  | 4191 | break; | 
|  | 4192 | case CLOSE_CHANNEL: | 
|  | 4193 | if (debug & DEBUG_HW_OPEN) | 
|  | 4194 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | 
|  | 4195 | __func__, dch->dev.id, | 
|  | 4196 | __builtin_return_address(0)); | 
|  | 4197 | module_put(THIS_MODULE); | 
|  | 4198 | break; | 
|  | 4199 | case CONTROL_CHANNEL: | 
|  | 4200 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4201 | err = channel_dctrl(dch, arg); | 
|  | 4202 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4203 | break; | 
|  | 4204 | default: | 
|  | 4205 | if (dch->debug & DEBUG_HW) | 
|  | 4206 | printk(KERN_DEBUG "%s: unknown command %x\n", | 
|  | 4207 | __func__, cmd); | 
|  | 4208 | err = -EINVAL; | 
|  | 4209 | } | 
|  | 4210 | return err; | 
|  | 4211 | } | 
|  | 4212 |  | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 4213 | static int | 
|  | 4214 | clockctl(void *priv, int enable) | 
|  | 4215 | { | 
|  | 4216 | struct hfc_multi *hc = priv; | 
|  | 4217 |  | 
|  | 4218 | hc->iclock_on = enable; | 
|  | 4219 | return 0; | 
|  | 4220 | } | 
|  | 4221 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4222 | /* | 
|  | 4223 | * initialize the card | 
|  | 4224 | */ | 
|  | 4225 |  | 
|  | 4226 | /* | 
|  | 4227 | * start timer irq, wait some time and check if we have interrupts. | 
|  | 4228 | * if not, reset chip and try again. | 
|  | 4229 | */ | 
|  | 4230 | static int | 
|  | 4231 | init_card(struct hfc_multi *hc) | 
|  | 4232 | { | 
|  | 4233 | int	err = -EIO; | 
|  | 4234 | u_long	flags; | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 4235 | void	__iomem *plx_acc; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4236 | u_long	plx_flags; | 
|  | 4237 |  | 
|  | 4238 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4239 | printk(KERN_DEBUG "%s: entered\n", __func__); | 
|  | 4240 |  | 
|  | 4241 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4242 | /* set interrupts but leave global interrupt disabled */ | 
|  | 4243 | hc->hw.r_irq_ctrl = V_FIFO_IRQ; | 
|  | 4244 | disable_hwirq(hc); | 
|  | 4245 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4246 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4247 | if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4248 | "HFC-multi", hc)) { | 
|  | 4249 | printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4250 | hc->irq); | 
|  | 4251 | hc->irq = 0; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4252 | return -EIO; | 
|  | 4253 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4254 |  | 
|  | 4255 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4256 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 4257 | plx_acc = hc->plx_membase + PLX_INTCSR; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4258 | writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), | 
|  | 4259 | plx_acc); /* enable PCI & LINT1 irq */ | 
|  | 4260 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 4261 | } | 
|  | 4262 |  | 
|  | 4263 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4264 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | 
|  | 4265 | __func__, hc->irq, hc->irqcnt); | 
|  | 4266 | err = init_chip(hc); | 
|  | 4267 | if (err) | 
|  | 4268 | goto error; | 
|  | 4269 | /* | 
|  | 4270 | * Finally enable IRQ output | 
| Uwe Kleine-König | 698f931 | 2010-07-02 20:41:51 +0200 | [diff] [blame] | 4271 | * this is only allowed, if an IRQ routine is already | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4272 | * established for this HFC, so don't do that earlier | 
|  | 4273 | */ | 
|  | 4274 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4275 | enable_hwirq(hc); | 
|  | 4276 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4277 | /* printk(KERN_DEBUG "no master irq set!!!\n"); */ | 
|  | 4278 | set_current_state(TASK_UNINTERRUPTIBLE); | 
|  | 4279 | schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ | 
|  | 4280 | /* turn IRQ off until chip is completely initialized */ | 
|  | 4281 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4282 | disable_hwirq(hc); | 
|  | 4283 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4284 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4285 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | 
|  | 4286 | __func__, hc->irq, hc->irqcnt); | 
|  | 4287 | if (hc->irqcnt) { | 
|  | 4288 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4289 | printk(KERN_DEBUG "%s: done\n", __func__); | 
|  | 4290 |  | 
|  | 4291 | return 0; | 
|  | 4292 | } | 
|  | 4293 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | 
|  | 4294 | printk(KERN_INFO "ignoring missing interrupts\n"); | 
|  | 4295 | return 0; | 
|  | 4296 | } | 
|  | 4297 |  | 
|  | 4298 | printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", | 
|  | 4299 | hc->irq); | 
|  | 4300 |  | 
|  | 4301 | err = -EIO; | 
|  | 4302 |  | 
|  | 4303 | error: | 
|  | 4304 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4305 | spin_lock_irqsave(&plx_lock, plx_flags); | 
| Hannes Eder | c31655f | 2008-12-12 21:20:03 -0800 | [diff] [blame] | 4306 | plx_acc = hc->plx_membase + PLX_INTCSR; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4307 | writew(0x00, plx_acc); /*disable IRQs*/ | 
|  | 4308 | spin_unlock_irqrestore(&plx_lock, plx_flags); | 
|  | 4309 | } | 
|  | 4310 |  | 
|  | 4311 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4312 | printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4313 | if (hc->irq) { | 
|  | 4314 | free_irq(hc->irq, hc); | 
|  | 4315 | hc->irq = 0; | 
|  | 4316 | } | 
|  | 4317 |  | 
|  | 4318 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4319 | printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); | 
|  | 4320 | return err; | 
|  | 4321 | } | 
|  | 4322 |  | 
|  | 4323 | /* | 
|  | 4324 | * find pci device and set it up | 
|  | 4325 | */ | 
|  | 4326 |  | 
|  | 4327 | static int | 
|  | 4328 | setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, | 
|  | 4329 | const struct pci_device_id *ent) | 
|  | 4330 | { | 
|  | 4331 | struct hm_map	*m = (struct hm_map *)ent->driver_data; | 
|  | 4332 |  | 
|  | 4333 | printk(KERN_INFO | 
|  | 4334 | "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", | 
|  | 4335 | m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); | 
|  | 4336 |  | 
|  | 4337 | hc->pci_dev = pdev; | 
|  | 4338 | if (m->clock2) | 
|  | 4339 | test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); | 
|  | 4340 |  | 
|  | 4341 | if (ent->device == 0xB410) { | 
|  | 4342 | test_and_set_bit(HFC_CHIP_B410P, &hc->chip); | 
|  | 4343 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | 
|  | 4344 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | 
|  | 4345 | hc->slots = 32; | 
|  | 4346 | } | 
|  | 4347 |  | 
|  | 4348 | if (hc->pci_dev->irq <= 0) { | 
|  | 4349 | printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); | 
|  | 4350 | return -EIO; | 
|  | 4351 | } | 
|  | 4352 | if (pci_enable_device(hc->pci_dev)) { | 
|  | 4353 | printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); | 
|  | 4354 | return -EIO; | 
|  | 4355 | } | 
|  | 4356 | hc->leds = m->leds; | 
|  | 4357 | hc->ledstate = 0xAFFEAFFE; | 
|  | 4358 | hc->opticalsupport = m->opticalsupport; | 
|  | 4359 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4360 | hc->pci_iobase = 0; | 
|  | 4361 | hc->pci_membase = NULL; | 
|  | 4362 | hc->plx_membase = NULL; | 
|  | 4363 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4364 | /* set memory access methods */ | 
|  | 4365 | if (m->io_mode) /* use mode from card config */ | 
|  | 4366 | hc->io_mode = m->io_mode; | 
|  | 4367 | switch (hc->io_mode) { | 
|  | 4368 | case HFC_IO_MODE_PLXSD: | 
|  | 4369 | test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); | 
|  | 4370 | hc->slots = 128; /* required */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4371 | hc->HFC_outb = HFC_outb_pcimem; | 
|  | 4372 | hc->HFC_inb = HFC_inb_pcimem; | 
|  | 4373 | hc->HFC_inw = HFC_inw_pcimem; | 
|  | 4374 | hc->HFC_wait = HFC_wait_pcimem; | 
|  | 4375 | hc->read_fifo = read_fifo_pcimem; | 
|  | 4376 | hc->write_fifo = write_fifo_pcimem; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4377 | hc->plx_origmembase =  hc->pci_dev->resource[0].start; | 
|  | 4378 | /* MEMBASE 1 is PLX PCI Bridge */ | 
|  | 4379 |  | 
|  | 4380 | if (!hc->plx_origmembase) { | 
|  | 4381 | printk(KERN_WARNING | 
|  | 4382 | "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); | 
|  | 4383 | pci_disable_device(hc->pci_dev); | 
|  | 4384 | return -EIO; | 
|  | 4385 | } | 
|  | 4386 |  | 
|  | 4387 | hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); | 
|  | 4388 | if (!hc->plx_membase) { | 
|  | 4389 | printk(KERN_WARNING | 
|  | 4390 | "HFC-multi: failed to remap plx address space. " | 
|  | 4391 | "(internal error)\n"); | 
|  | 4392 | pci_disable_device(hc->pci_dev); | 
|  | 4393 | return -EIO; | 
|  | 4394 | } | 
|  | 4395 | printk(KERN_INFO | 
|  | 4396 | "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", | 
|  | 4397 | (u_long)hc->plx_membase, hc->plx_origmembase); | 
|  | 4398 |  | 
|  | 4399 | hc->pci_origmembase =  hc->pci_dev->resource[2].start; | 
|  | 4400 | /* MEMBASE 1 is PLX PCI Bridge */ | 
|  | 4401 | if (!hc->pci_origmembase) { | 
|  | 4402 | printk(KERN_WARNING | 
|  | 4403 | "HFC-multi: No IO-Memory for PCI card found\n"); | 
|  | 4404 | pci_disable_device(hc->pci_dev); | 
|  | 4405 | return -EIO; | 
|  | 4406 | } | 
|  | 4407 |  | 
|  | 4408 | hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); | 
|  | 4409 | if (!hc->pci_membase) { | 
|  | 4410 | printk(KERN_WARNING "HFC-multi: failed to remap io " | 
|  | 4411 | "address space. (internal error)\n"); | 
|  | 4412 | pci_disable_device(hc->pci_dev); | 
|  | 4413 | return -EIO; | 
|  | 4414 | } | 
|  | 4415 |  | 
|  | 4416 | printk(KERN_INFO | 
|  | 4417 | "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " | 
|  | 4418 | "leds-type %d\n", | 
|  | 4419 | hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, | 
|  | 4420 | hc->pci_dev->irq, HZ, hc->leds); | 
|  | 4421 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | 
|  | 4422 | break; | 
|  | 4423 | case HFC_IO_MODE_PCIMEM: | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4424 | hc->HFC_outb = HFC_outb_pcimem; | 
|  | 4425 | hc->HFC_inb = HFC_inb_pcimem; | 
|  | 4426 | hc->HFC_inw = HFC_inw_pcimem; | 
|  | 4427 | hc->HFC_wait = HFC_wait_pcimem; | 
|  | 4428 | hc->read_fifo = read_fifo_pcimem; | 
|  | 4429 | hc->write_fifo = write_fifo_pcimem; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4430 | hc->pci_origmembase = hc->pci_dev->resource[1].start; | 
|  | 4431 | if (!hc->pci_origmembase) { | 
|  | 4432 | printk(KERN_WARNING | 
|  | 4433 | "HFC-multi: No IO-Memory for PCI card found\n"); | 
|  | 4434 | pci_disable_device(hc->pci_dev); | 
|  | 4435 | return -EIO; | 
|  | 4436 | } | 
|  | 4437 |  | 
|  | 4438 | hc->pci_membase = ioremap(hc->pci_origmembase, 256); | 
|  | 4439 | if (!hc->pci_membase) { | 
|  | 4440 | printk(KERN_WARNING | 
|  | 4441 | "HFC-multi: failed to remap io address space. " | 
|  | 4442 | "(internal error)\n"); | 
|  | 4443 | pci_disable_device(hc->pci_dev); | 
|  | 4444 | return -EIO; | 
|  | 4445 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4446 | printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " | 
|  | 4447 | "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4448 | hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); | 
|  | 4449 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | 
|  | 4450 | break; | 
|  | 4451 | case HFC_IO_MODE_REGIO: | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4452 | hc->HFC_outb = HFC_outb_regio; | 
|  | 4453 | hc->HFC_inb = HFC_inb_regio; | 
|  | 4454 | hc->HFC_inw = HFC_inw_regio; | 
|  | 4455 | hc->HFC_wait = HFC_wait_regio; | 
|  | 4456 | hc->read_fifo = read_fifo_regio; | 
|  | 4457 | hc->write_fifo = write_fifo_regio; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4458 | hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; | 
|  | 4459 | if (!hc->pci_iobase) { | 
|  | 4460 | printk(KERN_WARNING | 
|  | 4461 | "HFC-multi: No IO for PCI card found\n"); | 
|  | 4462 | pci_disable_device(hc->pci_dev); | 
|  | 4463 | return -EIO; | 
|  | 4464 | } | 
|  | 4465 |  | 
|  | 4466 | if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { | 
|  | 4467 | printk(KERN_WARNING "HFC-multi: failed to request " | 
|  | 4468 | "address space at 0x%08lx (internal error)\n", | 
|  | 4469 | hc->pci_iobase); | 
|  | 4470 | pci_disable_device(hc->pci_dev); | 
|  | 4471 | return -EIO; | 
|  | 4472 | } | 
|  | 4473 |  | 
|  | 4474 | printk(KERN_INFO | 
|  | 4475 | "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", | 
|  | 4476 | m->vendor_name, m->card_name, (u_int) hc->pci_iobase, | 
|  | 4477 | hc->pci_dev->irq, HZ, hc->leds); | 
|  | 4478 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); | 
|  | 4479 | break; | 
|  | 4480 | default: | 
|  | 4481 | printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); | 
|  | 4482 | pci_disable_device(hc->pci_dev); | 
|  | 4483 | return -EIO; | 
|  | 4484 | } | 
|  | 4485 |  | 
|  | 4486 | pci_set_drvdata(hc->pci_dev, hc); | 
|  | 4487 |  | 
|  | 4488 | /* At this point the needed PCI config is done */ | 
|  | 4489 | /* fifos are still not enabled */ | 
|  | 4490 | return 0; | 
|  | 4491 | } | 
|  | 4492 |  | 
|  | 4493 |  | 
|  | 4494 | /* | 
|  | 4495 | * remove port | 
|  | 4496 | */ | 
|  | 4497 |  | 
|  | 4498 | static void | 
|  | 4499 | release_port(struct hfc_multi *hc, struct dchannel *dch) | 
|  | 4500 | { | 
|  | 4501 | int	pt, ci, i = 0; | 
|  | 4502 | u_long	flags; | 
|  | 4503 | struct bchannel *pb; | 
|  | 4504 |  | 
|  | 4505 | ci = dch->slot; | 
|  | 4506 | pt = hc->chan[ci].port; | 
|  | 4507 |  | 
|  | 4508 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4509 | printk(KERN_DEBUG "%s: entered for port %d\n", | 
|  | 4510 | __func__, pt + 1); | 
|  | 4511 |  | 
|  | 4512 | if (pt >= hc->ports) { | 
|  | 4513 | printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", | 
|  | 4514 | __func__, pt + 1); | 
|  | 4515 | return; | 
|  | 4516 | } | 
|  | 4517 |  | 
|  | 4518 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4519 | printk(KERN_DEBUG "%s: releasing port=%d\n", | 
|  | 4520 | __func__, pt + 1); | 
|  | 4521 |  | 
|  | 4522 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | 
|  | 4523 | l1_event(dch->l1, CLOSE_CHANNEL); | 
|  | 4524 |  | 
|  | 4525 | hc->chan[ci].dch = NULL; | 
|  | 4526 |  | 
|  | 4527 | if (hc->created[pt]) { | 
|  | 4528 | hc->created[pt] = 0; | 
|  | 4529 | mISDN_unregister_device(&dch->dev); | 
|  | 4530 | } | 
|  | 4531 |  | 
|  | 4532 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4533 |  | 
|  | 4534 | if (dch->timer.function) { | 
|  | 4535 | del_timer(&dch->timer); | 
|  | 4536 | dch->timer.function = NULL; | 
|  | 4537 | } | 
|  | 4538 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4539 | if (hc->ctype == HFC_TYPE_E1) { /* E1 */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4540 | /* remove sync */ | 
|  | 4541 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4542 | hc->syncronized = 0; | 
|  | 4543 | plxsd_checksync(hc, 1); | 
|  | 4544 | } | 
|  | 4545 | /* free channels */ | 
|  | 4546 | for (i = 0; i <= 31; i++) { | 
|  | 4547 | if (hc->chan[i].bch) { | 
|  | 4548 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4549 | printk(KERN_DEBUG | 
|  | 4550 | "%s: free port %d channel %d\n", | 
|  | 4551 | __func__, hc->chan[i].port+1, i); | 
|  | 4552 | pb = hc->chan[i].bch; | 
|  | 4553 | hc->chan[i].bch = NULL; | 
|  | 4554 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4555 | mISDN_freebchannel(pb); | 
|  | 4556 | kfree(pb); | 
|  | 4557 | kfree(hc->chan[i].coeff); | 
|  | 4558 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4559 | } | 
|  | 4560 | } | 
|  | 4561 | } else { | 
|  | 4562 | /* remove sync */ | 
|  | 4563 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | 
|  | 4564 | hc->syncronized &= | 
|  | 4565 | ~(1 << hc->chan[ci].port); | 
|  | 4566 | plxsd_checksync(hc, 1); | 
|  | 4567 | } | 
|  | 4568 | /* free channels */ | 
|  | 4569 | if (hc->chan[ci - 2].bch) { | 
|  | 4570 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4571 | printk(KERN_DEBUG | 
|  | 4572 | "%s: free port %d channel %d\n", | 
|  | 4573 | __func__, hc->chan[ci - 2].port+1, | 
|  | 4574 | ci - 2); | 
|  | 4575 | pb = hc->chan[ci - 2].bch; | 
|  | 4576 | hc->chan[ci - 2].bch = NULL; | 
|  | 4577 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4578 | mISDN_freebchannel(pb); | 
|  | 4579 | kfree(pb); | 
|  | 4580 | kfree(hc->chan[ci - 2].coeff); | 
|  | 4581 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4582 | } | 
|  | 4583 | if (hc->chan[ci - 1].bch) { | 
|  | 4584 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4585 | printk(KERN_DEBUG | 
|  | 4586 | "%s: free port %d channel %d\n", | 
|  | 4587 | __func__, hc->chan[ci - 1].port+1, | 
|  | 4588 | ci - 1); | 
|  | 4589 | pb = hc->chan[ci - 1].bch; | 
|  | 4590 | hc->chan[ci - 1].bch = NULL; | 
|  | 4591 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4592 | mISDN_freebchannel(pb); | 
|  | 4593 | kfree(pb); | 
|  | 4594 | kfree(hc->chan[ci - 1].coeff); | 
|  | 4595 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4596 | } | 
|  | 4597 | } | 
|  | 4598 |  | 
|  | 4599 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 4600 |  | 
|  | 4601 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4602 | printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt); | 
|  | 4603 | mISDN_freedchannel(dch); | 
|  | 4604 | kfree(dch); | 
|  | 4605 |  | 
|  | 4606 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4607 | printk(KERN_DEBUG "%s: done!\n", __func__); | 
|  | 4608 | } | 
|  | 4609 |  | 
|  | 4610 | static void | 
|  | 4611 | release_card(struct hfc_multi *hc) | 
|  | 4612 | { | 
|  | 4613 | u_long	flags; | 
|  | 4614 | int	ch; | 
|  | 4615 |  | 
|  | 4616 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4617 | printk(KERN_DEBUG "%s: release card (%d) entered\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4618 | __func__, hc->id); | 
|  | 4619 |  | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 4620 | /* unregister clock source */ | 
|  | 4621 | if (hc->iclock) | 
|  | 4622 | mISDN_unregister_clock(hc->iclock); | 
|  | 4623 |  | 
|  | 4624 | /* disable irq */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4625 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 4626 | disable_hwirq(hc); | 
|  | 4627 | spin_unlock_irqrestore(&hc->lock, flags); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4628 | udelay(1000); | 
|  | 4629 |  | 
|  | 4630 | /* dimm leds */ | 
|  | 4631 | if (hc->leds) | 
|  | 4632 | hfcmulti_leds(hc); | 
|  | 4633 |  | 
|  | 4634 | /* disable D-channels & B-channels */ | 
|  | 4635 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4636 | printk(KERN_DEBUG "%s: disable all channels (d and b)\n", | 
|  | 4637 | __func__); | 
|  | 4638 | for (ch = 0; ch <= 31; ch++) { | 
|  | 4639 | if (hc->chan[ch].dch) | 
|  | 4640 | release_port(hc, hc->chan[ch].dch); | 
|  | 4641 | } | 
|  | 4642 |  | 
|  | 4643 | /* release hardware & irq */ | 
|  | 4644 | if (hc->irq) { | 
|  | 4645 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4646 | printk(KERN_DEBUG "%s: free irq %d\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4647 | __func__, hc->irq); | 
|  | 4648 | free_irq(hc->irq, hc); | 
|  | 4649 | hc->irq = 0; | 
|  | 4650 |  | 
|  | 4651 | } | 
|  | 4652 | release_io_hfcmulti(hc); | 
|  | 4653 |  | 
|  | 4654 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4655 | printk(KERN_DEBUG "%s: remove instance from list\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4656 | __func__); | 
|  | 4657 | list_del(&hc->list); | 
|  | 4658 |  | 
|  | 4659 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4660 | printk(KERN_DEBUG "%s: delete instance\n", __func__); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4661 | if (hc == syncmaster) | 
|  | 4662 | syncmaster = NULL; | 
|  | 4663 | kfree(hc); | 
|  | 4664 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4665 | printk(KERN_DEBUG "%s: card successfully removed\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4666 | __func__); | 
|  | 4667 | } | 
|  | 4668 |  | 
|  | 4669 | static int | 
|  | 4670 | init_e1_port(struct hfc_multi *hc, struct hm_map *m) | 
|  | 4671 | { | 
|  | 4672 | struct dchannel	*dch; | 
|  | 4673 | struct bchannel	*bch; | 
|  | 4674 | int		ch, ret = 0; | 
|  | 4675 | char		name[MISDN_MAX_IDLEN]; | 
|  | 4676 |  | 
|  | 4677 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | 
|  | 4678 | if (!dch) | 
|  | 4679 | return -ENOMEM; | 
|  | 4680 | dch->debug = debug; | 
|  | 4681 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | 
|  | 4682 | dch->hw = hc; | 
|  | 4683 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | 
|  | 4684 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | 
|  | 4685 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | 
|  | 4686 | dch->dev.D.send = handle_dmsg; | 
|  | 4687 | dch->dev.D.ctrl = hfcm_dctrl; | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4688 | dch->dev.nrbchan = (hc->dslot) ? 30 : 31; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4689 | dch->slot = hc->dslot; | 
|  | 4690 | hc->chan[hc->dslot].dch = dch; | 
|  | 4691 | hc->chan[hc->dslot].port = 0; | 
|  | 4692 | hc->chan[hc->dslot].nt_timer = -1; | 
|  | 4693 | for (ch = 1; ch <= 31; ch++) { | 
|  | 4694 | if (ch == hc->dslot) /* skip dchannel */ | 
|  | 4695 | continue; | 
|  | 4696 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | 
|  | 4697 | if (!bch) { | 
|  | 4698 | printk(KERN_ERR "%s: no memory for bchannel\n", | 
|  | 4699 | __func__); | 
|  | 4700 | ret = -ENOMEM; | 
|  | 4701 | goto free_chan; | 
|  | 4702 | } | 
|  | 4703 | hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); | 
|  | 4704 | if (!hc->chan[ch].coeff) { | 
|  | 4705 | printk(KERN_ERR "%s: no memory for coeffs\n", | 
|  | 4706 | __func__); | 
|  | 4707 | ret = -ENOMEM; | 
| Julia Lawall | 23b904f | 2009-02-08 17:00:49 -0800 | [diff] [blame] | 4708 | kfree(bch); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4709 | goto free_chan; | 
|  | 4710 | } | 
|  | 4711 | bch->nr = ch; | 
|  | 4712 | bch->slot = ch; | 
|  | 4713 | bch->debug = debug; | 
|  | 4714 | mISDN_initbchannel(bch, MAX_DATA_MEM); | 
|  | 4715 | bch->hw = hc; | 
|  | 4716 | bch->ch.send = handle_bmsg; | 
|  | 4717 | bch->ch.ctrl = hfcm_bctrl; | 
|  | 4718 | bch->ch.nr = ch; | 
|  | 4719 | list_add(&bch->ch.list, &dch->dev.bchannels); | 
|  | 4720 | hc->chan[ch].bch = bch; | 
|  | 4721 | hc->chan[ch].port = 0; | 
| Karsten Keil | ff4cc1d | 2008-07-30 18:26:58 +0200 | [diff] [blame] | 4722 | set_channelmap(bch->nr, dch->dev.channelmap); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4723 | } | 
|  | 4724 | /* set optical line type */ | 
|  | 4725 | if (port[Port_cnt] & 0x001) { | 
|  | 4726 | if (!m->opticalsupport)  { | 
|  | 4727 | printk(KERN_INFO | 
|  | 4728 | "This board has no optical " | 
|  | 4729 | "support\n"); | 
|  | 4730 | } else { | 
|  | 4731 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4732 | printk(KERN_DEBUG | 
|  | 4733 | "%s: PORT set optical " | 
|  | 4734 | "interfacs: card(%d) " | 
|  | 4735 | "port(%d)\n", | 
|  | 4736 | __func__, | 
|  | 4737 | HFC_cnt + 1, 1); | 
|  | 4738 | test_and_set_bit(HFC_CFG_OPTICAL, | 
|  | 4739 | &hc->chan[hc->dslot].cfg); | 
|  | 4740 | } | 
|  | 4741 | } | 
|  | 4742 | /* set LOS report */ | 
|  | 4743 | if (port[Port_cnt] & 0x004) { | 
|  | 4744 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4745 | printk(KERN_DEBUG "%s: PORT set " | 
|  | 4746 | "LOS report: card(%d) port(%d)\n", | 
|  | 4747 | __func__, HFC_cnt + 1, 1); | 
|  | 4748 | test_and_set_bit(HFC_CFG_REPORT_LOS, | 
|  | 4749 | &hc->chan[hc->dslot].cfg); | 
|  | 4750 | } | 
|  | 4751 | /* set AIS report */ | 
|  | 4752 | if (port[Port_cnt] & 0x008) { | 
|  | 4753 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4754 | printk(KERN_DEBUG "%s: PORT set " | 
|  | 4755 | "AIS report: card(%d) port(%d)\n", | 
|  | 4756 | __func__, HFC_cnt + 1, 1); | 
|  | 4757 | test_and_set_bit(HFC_CFG_REPORT_AIS, | 
|  | 4758 | &hc->chan[hc->dslot].cfg); | 
|  | 4759 | } | 
|  | 4760 | /* set SLIP report */ | 
|  | 4761 | if (port[Port_cnt] & 0x010) { | 
|  | 4762 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4763 | printk(KERN_DEBUG | 
|  | 4764 | "%s: PORT set SLIP report: " | 
|  | 4765 | "card(%d) port(%d)\n", | 
|  | 4766 | __func__, HFC_cnt + 1, 1); | 
|  | 4767 | test_and_set_bit(HFC_CFG_REPORT_SLIP, | 
|  | 4768 | &hc->chan[hc->dslot].cfg); | 
|  | 4769 | } | 
|  | 4770 | /* set RDI report */ | 
|  | 4771 | if (port[Port_cnt] & 0x020) { | 
|  | 4772 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4773 | printk(KERN_DEBUG | 
|  | 4774 | "%s: PORT set RDI report: " | 
|  | 4775 | "card(%d) port(%d)\n", | 
|  | 4776 | __func__, HFC_cnt + 1, 1); | 
|  | 4777 | test_and_set_bit(HFC_CFG_REPORT_RDI, | 
|  | 4778 | &hc->chan[hc->dslot].cfg); | 
|  | 4779 | } | 
|  | 4780 | /* set CRC-4 Mode */ | 
|  | 4781 | if (!(port[Port_cnt] & 0x100)) { | 
|  | 4782 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4783 | printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" | 
|  | 4784 | " card(%d) port(%d)\n", | 
|  | 4785 | __func__, HFC_cnt + 1, 1); | 
|  | 4786 | test_and_set_bit(HFC_CFG_CRC4, | 
|  | 4787 | &hc->chan[hc->dslot].cfg); | 
|  | 4788 | } else { | 
|  | 4789 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4790 | printk(KERN_DEBUG "%s: PORT turn off CRC4" | 
|  | 4791 | " report: card(%d) port(%d)\n", | 
|  | 4792 | __func__, HFC_cnt + 1, 1); | 
|  | 4793 | } | 
|  | 4794 | /* set forced clock */ | 
|  | 4795 | if (port[Port_cnt] & 0x0200) { | 
|  | 4796 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4797 | printk(KERN_DEBUG "%s: PORT force getting clock from " | 
|  | 4798 | "E1: card(%d) port(%d)\n", | 
|  | 4799 | __func__, HFC_cnt + 1, 1); | 
|  | 4800 | test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); | 
|  | 4801 | } else | 
|  | 4802 | if (port[Port_cnt] & 0x0400) { | 
|  | 4803 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4804 | printk(KERN_DEBUG "%s: PORT force putting clock to " | 
|  | 4805 | "E1: card(%d) port(%d)\n", | 
|  | 4806 | __func__, HFC_cnt + 1, 1); | 
|  | 4807 | test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); | 
|  | 4808 | } | 
|  | 4809 | /* set JATT PLL */ | 
|  | 4810 | if (port[Port_cnt] & 0x0800) { | 
|  | 4811 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4812 | printk(KERN_DEBUG "%s: PORT disable JATT PLL on " | 
|  | 4813 | "E1: card(%d) port(%d)\n", | 
|  | 4814 | __func__, HFC_cnt + 1, 1); | 
|  | 4815 | test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); | 
|  | 4816 | } | 
|  | 4817 | /* set elastic jitter buffer */ | 
|  | 4818 | if (port[Port_cnt] & 0x3000) { | 
|  | 4819 | hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3; | 
|  | 4820 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4821 | printk(KERN_DEBUG | 
|  | 4822 | "%s: PORT set elastic " | 
|  | 4823 | "buffer to %d: card(%d) port(%d)\n", | 
|  | 4824 | __func__, hc->chan[hc->dslot].jitter, | 
|  | 4825 | HFC_cnt + 1, 1); | 
|  | 4826 | } else | 
|  | 4827 | hc->chan[hc->dslot].jitter = 2; /* default */ | 
|  | 4828 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); | 
| Matthias Urlichs | b36b654 | 2008-08-16 00:09:24 +0200 | [diff] [blame] | 4829 | ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4830 | if (ret) | 
|  | 4831 | goto free_chan; | 
|  | 4832 | hc->created[0] = 1; | 
|  | 4833 | return ret; | 
|  | 4834 | free_chan: | 
|  | 4835 | release_port(hc, dch); | 
|  | 4836 | return ret; | 
|  | 4837 | } | 
|  | 4838 |  | 
|  | 4839 | static int | 
|  | 4840 | init_multi_port(struct hfc_multi *hc, int pt) | 
|  | 4841 | { | 
|  | 4842 | struct dchannel	*dch; | 
|  | 4843 | struct bchannel	*bch; | 
|  | 4844 | int		ch, i, ret = 0; | 
|  | 4845 | char		name[MISDN_MAX_IDLEN]; | 
|  | 4846 |  | 
|  | 4847 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | 
|  | 4848 | if (!dch) | 
|  | 4849 | return -ENOMEM; | 
|  | 4850 | dch->debug = debug; | 
|  | 4851 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | 
|  | 4852 | dch->hw = hc; | 
|  | 4853 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | 
|  | 4854 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | 
|  | 4855 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | 
|  | 4856 | dch->dev.D.send = handle_dmsg; | 
|  | 4857 | dch->dev.D.ctrl = hfcm_dctrl; | 
|  | 4858 | dch->dev.nrbchan = 2; | 
|  | 4859 | i = pt << 2; | 
|  | 4860 | dch->slot = i + 2; | 
|  | 4861 | hc->chan[i + 2].dch = dch; | 
|  | 4862 | hc->chan[i + 2].port = pt; | 
|  | 4863 | hc->chan[i + 2].nt_timer = -1; | 
|  | 4864 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | 
|  | 4865 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | 
|  | 4866 | if (!bch) { | 
|  | 4867 | printk(KERN_ERR "%s: no memory for bchannel\n", | 
|  | 4868 | __func__); | 
|  | 4869 | ret = -ENOMEM; | 
|  | 4870 | goto free_chan; | 
|  | 4871 | } | 
|  | 4872 | hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); | 
|  | 4873 | if (!hc->chan[i + ch].coeff) { | 
|  | 4874 | printk(KERN_ERR "%s: no memory for coeffs\n", | 
|  | 4875 | __func__); | 
|  | 4876 | ret = -ENOMEM; | 
| Julia Lawall | 23b904f | 2009-02-08 17:00:49 -0800 | [diff] [blame] | 4877 | kfree(bch); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4878 | goto free_chan; | 
|  | 4879 | } | 
|  | 4880 | bch->nr = ch + 1; | 
|  | 4881 | bch->slot = i + ch; | 
|  | 4882 | bch->debug = debug; | 
|  | 4883 | mISDN_initbchannel(bch, MAX_DATA_MEM); | 
|  | 4884 | bch->hw = hc; | 
|  | 4885 | bch->ch.send = handle_bmsg; | 
|  | 4886 | bch->ch.ctrl = hfcm_bctrl; | 
|  | 4887 | bch->ch.nr = ch + 1; | 
|  | 4888 | list_add(&bch->ch.list, &dch->dev.bchannels); | 
|  | 4889 | hc->chan[i + ch].bch = bch; | 
|  | 4890 | hc->chan[i + ch].port = pt; | 
| Karsten Keil | ff4cc1d | 2008-07-30 18:26:58 +0200 | [diff] [blame] | 4891 | set_channelmap(bch->nr, dch->dev.channelmap); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4892 | } | 
|  | 4893 | /* set master clock */ | 
|  | 4894 | if (port[Port_cnt] & 0x001) { | 
|  | 4895 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4896 | printk(KERN_DEBUG | 
|  | 4897 | "%s: PROTOCOL set master clock: " | 
|  | 4898 | "card(%d) port(%d)\n", | 
|  | 4899 | __func__, HFC_cnt + 1, pt + 1); | 
|  | 4900 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | 
|  | 4901 | printk(KERN_ERR "Error: Master clock " | 
|  | 4902 | "for port(%d) of card(%d) is only" | 
|  | 4903 | " possible with TE-mode\n", | 
|  | 4904 | pt + 1, HFC_cnt + 1); | 
|  | 4905 | ret = -EINVAL; | 
|  | 4906 | goto free_chan; | 
|  | 4907 | } | 
|  | 4908 | if (hc->masterclk >= 0) { | 
|  | 4909 | printk(KERN_ERR "Error: Master clock " | 
|  | 4910 | "for port(%d) of card(%d) already " | 
|  | 4911 | "defined for port(%d)\n", | 
|  | 4912 | pt + 1, HFC_cnt + 1, hc->masterclk+1); | 
|  | 4913 | ret = -EINVAL; | 
|  | 4914 | goto free_chan; | 
|  | 4915 | } | 
|  | 4916 | hc->masterclk = pt; | 
|  | 4917 | } | 
|  | 4918 | /* set transmitter line to non capacitive */ | 
|  | 4919 | if (port[Port_cnt] & 0x002) { | 
|  | 4920 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4921 | printk(KERN_DEBUG | 
|  | 4922 | "%s: PROTOCOL set non capacitive " | 
|  | 4923 | "transmitter: card(%d) port(%d)\n", | 
|  | 4924 | __func__, HFC_cnt + 1, pt + 1); | 
|  | 4925 | test_and_set_bit(HFC_CFG_NONCAP_TX, | 
|  | 4926 | &hc->chan[i + 2].cfg); | 
|  | 4927 | } | 
|  | 4928 | /* disable E-channel */ | 
|  | 4929 | if (port[Port_cnt] & 0x004) { | 
| Karsten Keil | eac74af | 2009-05-22 11:04:56 +0000 | [diff] [blame] | 4930 | if (debug & DEBUG_HFCMULTI_INIT) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4931 | printk(KERN_DEBUG | 
|  | 4932 | "%s: PROTOCOL disable E-channel: " | 
|  | 4933 | "card(%d) port(%d)\n", | 
|  | 4934 | __func__, HFC_cnt + 1, pt + 1); | 
|  | 4935 | test_and_set_bit(HFC_CFG_DIS_ECHANNEL, | 
|  | 4936 | &hc->chan[i + 2].cfg); | 
|  | 4937 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4938 | if (hc->ctype == HFC_TYPE_XHFC) { | 
|  | 4939 | snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", | 
|  | 4940 | HFC_cnt + 1, pt + 1); | 
|  | 4941 | ret = mISDN_register_device(&dch->dev, NULL, name); | 
|  | 4942 | } else { | 
|  | 4943 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", | 
|  | 4944 | hc->ctype, HFC_cnt + 1, pt + 1); | 
|  | 4945 | ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); | 
|  | 4946 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4947 | if (ret) | 
|  | 4948 | goto free_chan; | 
|  | 4949 | hc->created[pt] = 1; | 
|  | 4950 | return ret; | 
|  | 4951 | free_chan: | 
|  | 4952 | release_port(hc, dch); | 
|  | 4953 | return ret; | 
|  | 4954 | } | 
|  | 4955 |  | 
|  | 4956 | static int | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4957 | hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, | 
|  | 4958 | const struct pci_device_id *ent) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4959 | { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4960 | int		ret_err = 0; | 
|  | 4961 | int		pt; | 
|  | 4962 | struct hfc_multi	*hc; | 
|  | 4963 | u_long		flags; | 
|  | 4964 | u_char		dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 4965 | int		i; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4966 |  | 
|  | 4967 | if (HFC_cnt >= MAX_CARDS) { | 
|  | 4968 | printk(KERN_ERR "too many cards (max=%d).\n", | 
|  | 4969 | MAX_CARDS); | 
|  | 4970 | return -EINVAL; | 
|  | 4971 | } | 
|  | 4972 | if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { | 
|  | 4973 | printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " | 
|  | 4974 | "type[%d] %d was supplied as module parameter\n", | 
|  | 4975 | m->vendor_name, m->card_name, m->type, HFC_cnt, | 
|  | 4976 | type[HFC_cnt] & 0xff); | 
|  | 4977 | printk(KERN_WARNING "HFC-MULTI: Load module without parameters " | 
|  | 4978 | "first, to see cards and their types."); | 
|  | 4979 | return -EINVAL; | 
|  | 4980 | } | 
|  | 4981 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 4982 | printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", | 
|  | 4983 | __func__, m->vendor_name, m->card_name, m->type, | 
|  | 4984 | type[HFC_cnt]); | 
|  | 4985 |  | 
|  | 4986 | /* allocate card+fifo structure */ | 
|  | 4987 | hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL); | 
|  | 4988 | if (!hc) { | 
|  | 4989 | printk(KERN_ERR "No kmem for HFC-Multi card\n"); | 
|  | 4990 | return -ENOMEM; | 
|  | 4991 | } | 
|  | 4992 | spin_lock_init(&hc->lock); | 
|  | 4993 | hc->mtyp = m; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4994 | hc->ctype =  m->type; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 4995 | hc->ports = m->ports; | 
|  | 4996 | hc->id = HFC_cnt; | 
|  | 4997 | hc->pcm = pcm[HFC_cnt]; | 
|  | 4998 | hc->io_mode = iomode[HFC_cnt]; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 4999 | if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5000 | hc->dslot = 0; | 
|  | 5001 | printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " | 
|  | 5002 | "31 B-channels\n"); | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5003 | } | 
|  | 5004 | if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 | 
|  | 5005 | && hc->ctype == HFC_TYPE_E1) { | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5006 | hc->dslot = dslot[HFC_cnt]; | 
|  | 5007 | printk(KERN_INFO "HFC-E1 card has alternating D-channel on " | 
|  | 5008 | "time slot %d\n", dslot[HFC_cnt]); | 
|  | 5009 | } else | 
|  | 5010 | hc->dslot = 16; | 
|  | 5011 |  | 
|  | 5012 | /* set chip specific features */ | 
|  | 5013 | hc->masterclk = -1; | 
|  | 5014 | if (type[HFC_cnt] & 0x100) { | 
|  | 5015 | test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 5016 | hc->silence = 0xff; /* ulaw silence */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5017 | } else | 
| Andreas Eversberg | 8dd2f36 | 2008-08-02 22:51:52 +0200 | [diff] [blame] | 5018 | hc->silence = 0x2a; /* alaw silence */ | 
|  | 5019 | if ((poll >> 1) > sizeof(hc->silence_data)) { | 
|  | 5020 | printk(KERN_ERR "HFCMULTI error: silence_data too small, " | 
|  | 5021 | "please fix\n"); | 
|  | 5022 | return -EINVAL; | 
|  | 5023 | } | 
|  | 5024 | for (i = 0; i < (poll >> 1); i++) | 
|  | 5025 | hc->silence_data[i] = hc->silence; | 
|  | 5026 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5027 | if (hc->ctype != HFC_TYPE_XHFC) { | 
|  | 5028 | if (!(type[HFC_cnt] & 0x200)) | 
|  | 5029 | test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); | 
|  | 5030 | test_and_set_bit(HFC_CHIP_CONF, &hc->chip); | 
|  | 5031 | } | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5032 |  | 
|  | 5033 | if (type[HFC_cnt] & 0x800) | 
|  | 5034 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | 
|  | 5035 | if (type[HFC_cnt] & 0x1000) { | 
|  | 5036 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | 
|  | 5037 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | 
|  | 5038 | } | 
|  | 5039 | if (type[HFC_cnt] & 0x4000) | 
|  | 5040 | test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); | 
|  | 5041 | if (type[HFC_cnt] & 0x8000) | 
|  | 5042 | test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); | 
|  | 5043 | hc->slots = 32; | 
|  | 5044 | if (type[HFC_cnt] & 0x10000) | 
|  | 5045 | hc->slots = 64; | 
|  | 5046 | if (type[HFC_cnt] & 0x20000) | 
|  | 5047 | hc->slots = 128; | 
|  | 5048 | if (type[HFC_cnt] & 0x80000) { | 
|  | 5049 | test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); | 
|  | 5050 | hc->wdcount = 0; | 
|  | 5051 | hc->wdbyte = V_GPIO_OUT2; | 
|  | 5052 | printk(KERN_NOTICE "Watchdog enabled\n"); | 
|  | 5053 | } | 
|  | 5054 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5055 | if (pdev && ent) | 
|  | 5056 | /* setup pci, hc->slots may change due to PLXSD */ | 
|  | 5057 | ret_err = setup_pci(hc, pdev, ent); | 
|  | 5058 | else | 
|  | 5059 | #ifdef CONFIG_MISDN_HFCMULTI_8xx | 
|  | 5060 | ret_err = setup_embedded(hc, m); | 
|  | 5061 | #else | 
|  | 5062 | { | 
|  | 5063 | printk(KERN_WARNING "Embedded IO Mode not selected\n"); | 
|  | 5064 | ret_err = -EIO; | 
|  | 5065 | } | 
|  | 5066 | #endif | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5067 | if (ret_err) { | 
|  | 5068 | if (hc == syncmaster) | 
|  | 5069 | syncmaster = NULL; | 
|  | 5070 | kfree(hc); | 
|  | 5071 | return ret_err; | 
|  | 5072 | } | 
|  | 5073 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5074 | hc->HFC_outb_nodebug = hc->HFC_outb; | 
|  | 5075 | hc->HFC_inb_nodebug = hc->HFC_inb; | 
|  | 5076 | hc->HFC_inw_nodebug = hc->HFC_inw; | 
|  | 5077 | hc->HFC_wait_nodebug = hc->HFC_wait; | 
|  | 5078 | #ifdef HFC_REGISTER_DEBUG | 
|  | 5079 | hc->HFC_outb = HFC_outb_debug; | 
|  | 5080 | hc->HFC_inb = HFC_inb_debug; | 
|  | 5081 | hc->HFC_inw = HFC_inw_debug; | 
|  | 5082 | hc->HFC_wait = HFC_wait_debug; | 
|  | 5083 | #endif | 
|  | 5084 | /* create channels */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5085 | for (pt = 0; pt < hc->ports; pt++) { | 
|  | 5086 | if (Port_cnt >= MAX_PORTS) { | 
|  | 5087 | printk(KERN_ERR "too many ports (max=%d).\n", | 
|  | 5088 | MAX_PORTS); | 
|  | 5089 | ret_err = -EINVAL; | 
|  | 5090 | goto free_card; | 
|  | 5091 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5092 | if (hc->ctype == HFC_TYPE_E1) | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5093 | ret_err = init_e1_port(hc, m); | 
|  | 5094 | else | 
|  | 5095 | ret_err = init_multi_port(hc, pt); | 
|  | 5096 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 5097 | printk(KERN_DEBUG | 
|  | 5098 | "%s: Registering D-channel, card(%d) port(%d)" | 
|  | 5099 | "result %d\n", | 
|  | 5100 | __func__, HFC_cnt + 1, pt, ret_err); | 
|  | 5101 |  | 
|  | 5102 | if (ret_err) { | 
|  | 5103 | while (pt) { /* release already registered ports */ | 
|  | 5104 | pt--; | 
|  | 5105 | release_port(hc, hc->chan[(pt << 2) + 2].dch); | 
|  | 5106 | } | 
|  | 5107 | goto free_card; | 
|  | 5108 | } | 
|  | 5109 | Port_cnt++; | 
|  | 5110 | } | 
|  | 5111 |  | 
|  | 5112 | /* disp switches */ | 
|  | 5113 | switch (m->dip_type) { | 
|  | 5114 | case DIP_4S: | 
|  | 5115 | /* | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5116 | * Get DIP setting for beroNet 1S/2S/4S cards | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5117 | * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + | 
|  | 5118 | * GPI 19/23 (R_GPI_IN2)) | 
|  | 5119 | */ | 
|  | 5120 | dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | | 
|  | 5121 | ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | | 
|  | 5122 | (~HFC_inb(hc, R_GPI_IN2) & 0x08); | 
|  | 5123 |  | 
|  | 5124 | /* Port mode (TE/NT) jumpers */ | 
|  | 5125 | pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4)  & 0xf); | 
|  | 5126 |  | 
|  | 5127 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | 
|  | 5128 | pmj = ~pmj & 0xf; | 
|  | 5129 |  | 
|  | 5130 | printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", | 
|  | 5131 | m->vendor_name, m->card_name, dips, pmj); | 
|  | 5132 | break; | 
|  | 5133 | case DIP_8S: | 
|  | 5134 | /* | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5135 | * Get DIP Setting for beroNet 8S0+ cards | 
|  | 5136 | * Enable PCI auxbridge function | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5137 | */ | 
|  | 5138 | HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | 
|  | 5139 | /* prepare access to auxport */ | 
|  | 5140 | outw(0x4000, hc->pci_iobase + 4); | 
|  | 5141 | /* | 
|  | 5142 | * some dummy reads are required to | 
|  | 5143 | * read valid DIP switch data | 
|  | 5144 | */ | 
|  | 5145 | dips = inb(hc->pci_iobase); | 
|  | 5146 | dips = inb(hc->pci_iobase); | 
|  | 5147 | dips = inb(hc->pci_iobase); | 
|  | 5148 | dips = ~inb(hc->pci_iobase) & 0x3F; | 
|  | 5149 | outw(0x0, hc->pci_iobase + 4); | 
|  | 5150 | /* disable PCI auxbridge function */ | 
|  | 5151 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | 
|  | 5152 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | 
|  | 5153 | m->vendor_name, m->card_name, dips); | 
|  | 5154 | break; | 
|  | 5155 | case DIP_E1: | 
|  | 5156 | /* | 
|  | 5157 | * get DIP Setting for beroNet E1 cards | 
|  | 5158 | * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) | 
|  | 5159 | */ | 
|  | 5160 | dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0)>>4; | 
|  | 5161 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | 
|  | 5162 | m->vendor_name, m->card_name, dips); | 
|  | 5163 | break; | 
|  | 5164 | } | 
|  | 5165 |  | 
|  | 5166 | /* add to list */ | 
|  | 5167 | spin_lock_irqsave(&HFClock, flags); | 
|  | 5168 | list_add_tail(&hc->list, &HFClist); | 
|  | 5169 | spin_unlock_irqrestore(&HFClock, flags); | 
|  | 5170 |  | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 5171 | /* use as clock source */ | 
|  | 5172 | if (clock == HFC_cnt + 1) | 
|  | 5173 | hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); | 
|  | 5174 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5175 | /* initialize hardware */ | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5176 | hc->irq = (m->irq) ? : hc->pci_dev->irq; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5177 | ret_err = init_card(hc); | 
|  | 5178 | if (ret_err) { | 
|  | 5179 | printk(KERN_ERR "init card returns %d\n", ret_err); | 
|  | 5180 | release_card(hc); | 
|  | 5181 | return ret_err; | 
|  | 5182 | } | 
|  | 5183 |  | 
|  | 5184 | /* start IRQ and return */ | 
|  | 5185 | spin_lock_irqsave(&hc->lock, flags); | 
|  | 5186 | enable_hwirq(hc); | 
|  | 5187 | spin_unlock_irqrestore(&hc->lock, flags); | 
|  | 5188 | return 0; | 
|  | 5189 |  | 
|  | 5190 | free_card: | 
|  | 5191 | release_io_hfcmulti(hc); | 
|  | 5192 | if (hc == syncmaster) | 
|  | 5193 | syncmaster = NULL; | 
|  | 5194 | kfree(hc); | 
|  | 5195 | return ret_err; | 
|  | 5196 | } | 
|  | 5197 |  | 
|  | 5198 | static void __devexit hfc_remove_pci(struct pci_dev *pdev) | 
|  | 5199 | { | 
|  | 5200 | struct hfc_multi	*card = pci_get_drvdata(pdev); | 
|  | 5201 | u_long			flags; | 
|  | 5202 |  | 
|  | 5203 | if (debug) | 
|  | 5204 | printk(KERN_INFO "removing hfc_multi card vendor:%x " | 
|  | 5205 | "device:%x subvendor:%x subdevice:%x\n", | 
|  | 5206 | pdev->vendor, pdev->device, | 
|  | 5207 | pdev->subsystem_vendor, pdev->subsystem_device); | 
|  | 5208 |  | 
|  | 5209 | if (card) { | 
|  | 5210 | spin_lock_irqsave(&HFClock, flags); | 
|  | 5211 | release_card(card); | 
|  | 5212 | spin_unlock_irqrestore(&HFClock, flags); | 
|  | 5213 | }  else { | 
|  | 5214 | if (debug) | 
| Uwe Kleine-König | 698f931 | 2010-07-02 20:41:51 +0200 | [diff] [blame] | 5215 | printk(KERN_DEBUG "%s: drvdata already removed\n", | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5216 | __func__); | 
|  | 5217 | } | 
|  | 5218 | } | 
|  | 5219 |  | 
|  | 5220 | #define	VENDOR_CCD	"Cologne Chip AG" | 
|  | 5221 | #define	VENDOR_BN	"beroNet GmbH" | 
|  | 5222 | #define	VENDOR_DIG	"Digium Inc." | 
|  | 5223 | #define VENDOR_JH	"Junghanns.NET GmbH" | 
|  | 5224 | #define VENDOR_PRIM	"PrimuX" | 
|  | 5225 |  | 
|  | 5226 | static const struct hm_map hfcm_map[] = { | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5227 | /*0*/	{VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, | 
|  | 5228 | /*1*/	{VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, | 
|  | 5229 | /*2*/	{VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, | 
|  | 5230 | /*3*/	{VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, | 
|  | 5231 | /*4*/	{VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, | 
|  | 5232 | /*5*/	{VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, | 
|  | 5233 | /*6*/	{VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, | 
|  | 5234 | /*7*/	{VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, | 
|  | 5235 | /*8*/	{VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, | 
|  | 5236 | /*9*/	{VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, | 
|  | 5237 | /*10*/	{VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, | 
|  | 5238 | /*11*/	{VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5239 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5240 | /*12*/	{VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5241 | /*13*/	{VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5242 | HFC_IO_MODE_REGIO, 0}, | 
|  | 5243 | /*14*/	{VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, | 
|  | 5244 | /*15*/	{VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5245 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5246 | /*16*/	{VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, | 
|  | 5247 | /*17*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, | 
|  | 5248 | /*18*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5249 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5250 | /*19*/	{VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, | 
|  | 5251 | /*20*/	{VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, | 
|  | 5252 | /*21*/	{VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, | 
|  | 5253 | /*22*/	{VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5254 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5255 | /*23*/	{VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, | 
|  | 5256 | /*24*/	{VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, | 
|  | 5257 | /*25*/	{VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5258 |  | 
|  | 5259 | /*26*/	{VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5260 | HFC_IO_MODE_PLXSD, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5261 | /*27*/	{VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5262 | HFC_IO_MODE_PLXSD, 0}, | 
|  | 5263 | /*28*/	{VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, | 
|  | 5264 | /*29*/	{VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, | 
|  | 5265 | /*30*/	{VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, | 
|  | 5266 | /*31*/	{VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, | 
|  | 5267 | HFC_IO_MODE_EMBSD, XHFC_IRQ}, | 
| Andreas Eversberg | 7245a2f | 2009-05-22 11:04:55 +0000 | [diff] [blame] | 5268 | /*32*/	{VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, | 
| Lars Ellenberg | d00561a | 2010-03-15 19:09:28 -0700 | [diff] [blame] | 5269 | /*33*/	{VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, | 
|  | 5270 | /*34*/	{VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5271 | }; | 
|  | 5272 |  | 
|  | 5273 | #undef H | 
|  | 5274 | #define H(x)	((unsigned long)&hfcm_map[x]) | 
|  | 5275 | static struct pci_device_id hfmultipci_ids[] __devinitdata = { | 
|  | 5276 |  | 
|  | 5277 | /* Cards with HFC-4S Chip */ | 
|  | 5278 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5279 | PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ | 
|  | 5280 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5281 | PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ | 
|  | 5282 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5283 | PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ | 
|  | 5284 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5285 | PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ | 
|  | 5286 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5287 | PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ | 
|  | 5288 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5289 | PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ | 
|  | 5290 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5291 | PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ | 
|  | 5292 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5293 | PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ | 
|  | 5294 | { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, | 
|  | 5295 | PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, | 
|  | 5296 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5297 | PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ | 
|  | 5298 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5299 | PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, | 
|  | 5300 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5301 | PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ | 
|  | 5302 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5303 | PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ | 
|  | 5304 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5305 | PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ | 
| Lars Ellenberg | d00561a | 2010-03-15 19:09:28 -0700 | [diff] [blame] | 5306 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5307 | 0xb761, 0, 0, H(33)}, /* BN2S PCIe */ | 
|  | 5308 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | 
|  | 5309 | 0xb762, 0, 0, H(34)}, /* BN4S PCIe */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5310 |  | 
|  | 5311 | /* Cards with HFC-8S Chip */ | 
|  | 5312 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5313 | PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ | 
|  | 5314 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5315 | PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ | 
|  | 5316 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5317 | PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ | 
|  | 5318 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5319 | PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5320 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5321 | PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST  */ | 
|  | 5322 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5323 | PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST  */ | 
|  | 5324 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5325 | PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ | 
|  | 5326 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5327 | PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ | 
| Andreas Eversberg | 7245a2f | 2009-05-22 11:04:55 +0000 | [diff] [blame] | 5328 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | 
|  | 5329 | PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S  */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5330 |  | 
|  | 5331 |  | 
|  | 5332 | /* Cards with HFC-E1 Chip */ | 
|  | 5333 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5334 | PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ | 
|  | 5335 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5336 | PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ | 
|  | 5337 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5338 | PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ | 
|  | 5339 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5340 | PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ | 
|  | 5341 |  | 
|  | 5342 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5343 | PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ | 
|  | 5344 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5345 | PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ | 
|  | 5346 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5347 | PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ | 
|  | 5348 |  | 
|  | 5349 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | 
|  | 5350 | PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ | 
|  | 5351 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | 
|  | 5352 | PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ | 
| Andreas Eversberg | daebafe | 2009-05-25 00:56:56 -0700 | [diff] [blame] | 5353 |  | 
|  | 5354 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | 
|  | 5355 | PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ | 
|  | 5356 |  | 
| Peter Huewe | 9db9f27 | 2010-07-15 09:05:38 +0000 | [diff] [blame] | 5357 | { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 }, | 
|  | 5358 | { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 }, | 
|  | 5359 | { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 }, | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5360 | {0, } | 
|  | 5361 | }; | 
|  | 5362 | #undef H | 
|  | 5363 |  | 
|  | 5364 | MODULE_DEVICE_TABLE(pci, hfmultipci_ids); | 
|  | 5365 |  | 
|  | 5366 | static int | 
|  | 5367 | hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 
|  | 5368 | { | 
|  | 5369 | struct hm_map	*m = (struct hm_map *)ent->driver_data; | 
|  | 5370 | int		ret; | 
|  | 5371 |  | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5372 | if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( | 
|  | 5373 | ent->device == PCI_DEVICE_ID_CCD_HFC4S || | 
|  | 5374 | ent->device == PCI_DEVICE_ID_CCD_HFC8S || | 
|  | 5375 | ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { | 
|  | 5376 | printk(KERN_ERR | 
| Karsten Keil | f70e75e | 2009-07-24 18:41:23 +0200 | [diff] [blame] | 5377 | "Unknown HFC multiport controller (vendor:%04x device:%04x " | 
|  | 5378 | "subvendor:%04x subdevice:%04x)\n", pdev->vendor, | 
|  | 5379 | pdev->device, pdev->subsystem_vendor, | 
|  | 5380 | pdev->subsystem_device); | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5381 | printk(KERN_ERR | 
|  | 5382 | "Please contact the driver maintainer for support.\n"); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5383 | return -ENODEV; | 
|  | 5384 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5385 | ret = hfcmulti_init(m, pdev, ent); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5386 | if (ret) | 
|  | 5387 | return ret; | 
|  | 5388 | HFC_cnt++; | 
|  | 5389 | printk(KERN_INFO "%d devices registered\n", HFC_cnt); | 
|  | 5390 | return 0; | 
|  | 5391 | } | 
|  | 5392 |  | 
|  | 5393 | static struct pci_driver hfcmultipci_driver = { | 
|  | 5394 | .name		= "hfc_multi", | 
|  | 5395 | .probe		= hfcmulti_probe, | 
|  | 5396 | .remove		= __devexit_p(hfc_remove_pci), | 
|  | 5397 | .id_table	= hfmultipci_ids, | 
|  | 5398 | }; | 
|  | 5399 |  | 
|  | 5400 | static void __exit | 
|  | 5401 | HFCmulti_cleanup(void) | 
|  | 5402 | { | 
|  | 5403 | struct hfc_multi *card, *next; | 
|  | 5404 |  | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5405 | /* get rid of all devices of this driver */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5406 | list_for_each_entry_safe(card, next, &HFClist, list) | 
|  | 5407 | release_card(card); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5408 | pci_unregister_driver(&hfcmultipci_driver); | 
|  | 5409 | } | 
|  | 5410 |  | 
|  | 5411 | static int __init | 
|  | 5412 | HFCmulti_init(void) | 
|  | 5413 | { | 
|  | 5414 | int err; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5415 | int i, xhfc = 0; | 
|  | 5416 | struct hm_map m; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5417 |  | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5418 | printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); | 
|  | 5419 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5420 | #ifdef IRQ_DEBUG | 
| Karsten Keil | 69e656c | 2009-01-07 00:00:59 +0100 | [diff] [blame] | 5421 | printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5422 | #endif | 
|  | 5423 |  | 
|  | 5424 | spin_lock_init(&HFClock); | 
|  | 5425 | spin_lock_init(&plx_lock); | 
|  | 5426 |  | 
|  | 5427 | if (debug & DEBUG_HFCMULTI_INIT) | 
|  | 5428 | printk(KERN_DEBUG "%s: init entered\n", __func__); | 
|  | 5429 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5430 | switch (poll) { | 
|  | 5431 | case 0: | 
|  | 5432 | poll_timer = 6; | 
|  | 5433 | poll = 128; | 
|  | 5434 | break; | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5435 | case 8: | 
|  | 5436 | poll_timer = 2; | 
|  | 5437 | break; | 
|  | 5438 | case 16: | 
|  | 5439 | poll_timer = 3; | 
|  | 5440 | break; | 
|  | 5441 | case 32: | 
|  | 5442 | poll_timer = 4; | 
|  | 5443 | break; | 
|  | 5444 | case 64: | 
|  | 5445 | poll_timer = 5; | 
|  | 5446 | break; | 
|  | 5447 | case 128: | 
|  | 5448 | poll_timer = 6; | 
|  | 5449 | break; | 
|  | 5450 | case 256: | 
|  | 5451 | poll_timer = 7; | 
|  | 5452 | break; | 
|  | 5453 | default: | 
|  | 5454 | printk(KERN_ERR | 
|  | 5455 | "%s: Wrong poll value (%d).\n", __func__, poll); | 
|  | 5456 | err = -EINVAL; | 
|  | 5457 | return err; | 
|  | 5458 |  | 
|  | 5459 | } | 
|  | 5460 |  | 
| Andreas Eversberg | 3bd69ad | 2008-09-06 09:03:46 +0200 | [diff] [blame] | 5461 | if (!clock) | 
|  | 5462 | clock = 1; | 
|  | 5463 |  | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5464 | /* Register the embedded devices. | 
|  | 5465 | * This should be done before the PCI cards registration */ | 
|  | 5466 | switch (hwid) { | 
|  | 5467 | case HWID_MINIP4: | 
|  | 5468 | xhfc = 1; | 
|  | 5469 | m = hfcm_map[31]; | 
|  | 5470 | break; | 
|  | 5471 | case HWID_MINIP8: | 
|  | 5472 | xhfc = 2; | 
|  | 5473 | m = hfcm_map[31]; | 
|  | 5474 | break; | 
|  | 5475 | case HWID_MINIP16: | 
|  | 5476 | xhfc = 4; | 
|  | 5477 | m = hfcm_map[31]; | 
|  | 5478 | break; | 
|  | 5479 | default: | 
|  | 5480 | xhfc = 0; | 
|  | 5481 | } | 
|  | 5482 |  | 
|  | 5483 | for (i = 0; i < xhfc; ++i) { | 
|  | 5484 | err = hfcmulti_init(&m, NULL, NULL); | 
|  | 5485 | if (err) { | 
|  | 5486 | printk(KERN_ERR "error registering embedded driver: " | 
|  | 5487 | "%x\n", err); | 
| Roel Kluin | 2c554e1 | 2009-11-15 21:18:13 -0800 | [diff] [blame] | 5488 | return err; | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5489 | } | 
|  | 5490 | HFC_cnt++; | 
|  | 5491 | printk(KERN_INFO "%d devices registered\n", HFC_cnt); | 
|  | 5492 | } | 
|  | 5493 |  | 
|  | 5494 | /* Register the PCI cards */ | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5495 | err = pci_register_driver(&hfcmultipci_driver); | 
|  | 5496 | if (err < 0) { | 
|  | 5497 | printk(KERN_ERR "error registering pci driver: %x\n", err); | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5498 | return err; | 
|  | 5499 | } | 
| Karsten Keil | db9bb63 | 2009-05-22 11:04:53 +0000 | [diff] [blame] | 5500 |  | 
| Karsten Keil | af69fb3 | 2008-07-27 02:00:43 +0200 | [diff] [blame] | 5501 | return 0; | 
|  | 5502 | } | 
|  | 5503 |  | 
|  | 5504 |  | 
|  | 5505 | module_init(HFCmulti_init); | 
|  | 5506 | module_exit(HFCmulti_cleanup); |