1/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $ 2 * 3 * low level stuff for hfcs based cards (Teles3c, ACER P10) 4 * 5 * Author Karsten Keil 6 * Copyright by Karsten Keil <keil@isdn4linux.de> 7 * 8 * This software may be used and distributed according to the terms 9 * of the GNU General Public License, incorporated herein by reference. 10 * 11 */ 12 13#include <linux/init.h> 14#include <linux/isapnp.h> 15#include "hisax.h" 16#include "hfc_2bds0.h" 17#include "isdnl1.h" 18 19static const char *hfcs_revision = "$Revision: 1.10.2.4 $"; 20 21static irqreturn_t 22hfcs_interrupt(int intno, void *dev_id) 23{ 24 struct IsdnCardState *cs = dev_id; 25 u_char val, stat; 26 u_long flags; 27 28 spin_lock_irqsave(&cs->lock, flags); 29 if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & 30 (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { 31 val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); 32 if (cs->debug & L1_DEB_ISAC) 33 debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); 34 hfc2bds0_interrupt(cs, val); 35 } else { 36 if (cs->debug & L1_DEB_ISAC) 37 debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); 38 } 39 spin_unlock_irqrestore(&cs->lock, flags); 40 return IRQ_HANDLED; 41} 42 43static void 44hfcs_Timer(struct IsdnCardState *cs) 45{ 46 cs->hw.hfcD.timer.expires = jiffies + 75; 47 /* WD RESET */ 48/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); 49 add_timer(&cs->hw.hfcD.timer); 50*/ 51} 52 53static void 54release_io_hfcs(struct IsdnCardState *cs) 55{ 56 release2bds0(cs); 57 del_timer(&cs->hw.hfcD.timer); 58 if (cs->hw.hfcD.addr) 59 release_region(cs->hw.hfcD.addr, 2); 60} 61 62static void 63reset_hfcs(struct IsdnCardState *cs) 64{ 65 printk(KERN_INFO "HFCS: resetting card\n"); 66 cs->hw.hfcD.cirm = HFCD_RESET; 67 if (cs->typ == ISDN_CTYPE_TELES3C) 68 cs->hw.hfcD.cirm |= HFCD_MEM8K; 69 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ 70 mdelay(10); 71 cs->hw.hfcD.cirm = 0; 72 if (cs->typ == ISDN_CTYPE_TELES3C) 73 cs->hw.hfcD.cirm |= HFCD_MEM8K; 74 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ 75 mdelay(10); 76 if (cs->typ == ISDN_CTYPE_TELES3C) 77 cs->hw.hfcD.cirm |= HFCD_INTB; 78 else if (cs->typ == ISDN_CTYPE_ACERP10) 79 cs->hw.hfcD.cirm |= HFCD_INTA; 80 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); 81 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); 82 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ 83 cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; 84 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 85 cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; 86 cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | 87 HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | 88 HFCD_INTS_DREC | HFCD_INTS_L1STATE; 89 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); 90 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); 91 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ 92 udelay(10); 93 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ 94 cs->hw.hfcD.mst_m = HFCD_MASTER; 95 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ 96 cs->hw.hfcD.sctrl = 0; 97 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); 98} 99 100static int 101hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) 102{ 103 u_long flags; 104 int delay; 105 106 if (cs->debug & L1_DEB_ISAC) 107 debugl1(cs, "HFCS: card_msg %x", mt); 108 switch (mt) { 109 case CARD_RESET: 110 spin_lock_irqsave(&cs->lock, flags); 111 reset_hfcs(cs); 112 spin_unlock_irqrestore(&cs->lock, flags); 113 return (0); 114 case CARD_RELEASE: 115 release_io_hfcs(cs); 116 return (0); 117 case CARD_INIT: 118 delay = (75 * HZ) / 100 + 1; 119 mod_timer(&cs->hw.hfcD.timer, jiffies + delay); 120 spin_lock_irqsave(&cs->lock, flags); 121 reset_hfcs(cs); 122 init2bds0(cs); 123 spin_unlock_irqrestore(&cs->lock, flags); 124 delay = (80 * HZ) / 1000 + 1; 125 msleep(80); 126 spin_lock_irqsave(&cs->lock, flags); 127 cs->hw.hfcD.ctmt |= HFCD_TIM800; 128 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 129 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); 130 spin_unlock_irqrestore(&cs->lock, flags); 131 return (0); 132 case CARD_TEST: 133 return (0); 134 } 135 return (0); 136} 137 138#ifdef __ISAPNP__ 139static struct isapnp_device_id hfc_ids[] __devinitdata = { 140 { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 141 ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 142 (unsigned long) "Acer P10" }, 143 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 144 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 145 (unsigned long) "Billion 2" }, 146 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 147 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 148 (unsigned long) "Billion 1" }, 149 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 150 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 151 (unsigned long) "IStar PnP" }, 152 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 153 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 154 (unsigned long) "Teles 16.3c" }, 155 { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 156 ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 157 (unsigned long) "Tornado Tipa C" }, 158 { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 159 ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 160 (unsigned long) "Genius Speed Surfer" }, 161 { 0, } 162}; 163 164static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0]; 165static struct pnp_card *pnp_c __devinitdata = NULL; 166#endif 167 168int __devinit 169setup_hfcs(struct IsdnCard *card) 170{ 171 struct IsdnCardState *cs = card->cs; 172 char tmp[64]; 173 174 strcpy(tmp, hfcs_revision); 175 printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); 176 177#ifdef __ISAPNP__ 178 if (!card->para[1] && isapnp_present()) { 179 struct pnp_dev *pnp_d; 180 while (ipid->card_vendor) { 181 if ((pnp_c = pnp_find_card(ipid->card_vendor, 182 ipid->card_device, pnp_c))) { 183 pnp_d = NULL; 184 if ((pnp_d = pnp_find_dev(pnp_c, 185 ipid->vendor, ipid->function, pnp_d))) { 186 int err; 187 188 printk(KERN_INFO "HiSax: %s detected\n", 189 (char *)ipid->driver_data); 190 pnp_disable_dev(pnp_d); 191 err = pnp_activate_dev(pnp_d); 192 if (err < 0) { 193 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", 194 __func__, err); 195 return (0); 196 } 197 card->para[1] = pnp_port_start(pnp_d, 0); 198 card->para[0] = pnp_irq(pnp_d, 0); 199 if (!card->para[0] || !card->para[1]) { 200 printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", 201 card->para[0], card->para[1]); 202 pnp_disable_dev(pnp_d); 203 return (0); 204 } 205 break; 206 } else { 207 printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); 208 } 209 } 210 ipid++; 211 pnp_c = NULL; 212 } 213 if (!ipid->card_vendor) { 214 printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); 215 return (0); 216 } 217 } 218#endif 219 cs->hw.hfcD.addr = card->para[1] & 0xfffe; 220 cs->irq = card->para[0]; 221 cs->hw.hfcD.cip = 0; 222 cs->hw.hfcD.int_s1 = 0; 223 cs->hw.hfcD.send = NULL; 224 cs->bcs[0].hw.hfc.send = NULL; 225 cs->bcs[1].hw.hfc.send = NULL; 226 cs->hw.hfcD.dfifosize = 512; 227 cs->dc.hfcd.ph_state = 0; 228 cs->hw.hfcD.fifo = 255; 229 if (cs->typ == ISDN_CTYPE_TELES3C) { 230 cs->hw.hfcD.bfifosize = 1024 + 512; 231 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 232 cs->hw.hfcD.bfifosize = 7 * 1024 + 512; 233 } else 234 return (0); 235 if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { 236 printk(KERN_WARNING 237 "HiSax: %s config port %x-%x already in use\n", 238 CardType[card->typ], 239 cs->hw.hfcD.addr, 240 cs->hw.hfcD.addr + 2); 241 return (0); 242 } 243 printk(KERN_INFO 244 "HFCS: defined at 0x%x IRQ %d HZ %d\n", 245 cs->hw.hfcD.addr, 246 cs->irq, HZ); 247 if (cs->typ == ISDN_CTYPE_TELES3C) { 248 /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ 249 outb(0x00, cs->hw.hfcD.addr); 250 outb(0x56, cs->hw.hfcD.addr | 1); 251 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 252 /* Acer P10 IO ADR is 0x300 */ 253 outb(0x00, cs->hw.hfcD.addr); 254 outb(0x57, cs->hw.hfcD.addr | 1); 255 } 256 set_cs_func(cs); 257 cs->hw.hfcD.timer.function = (void *) hfcs_Timer; 258 cs->hw.hfcD.timer.data = (long) cs; 259 init_timer(&cs->hw.hfcD.timer); 260 cs->cardmsg = &hfcs_card_msg; 261 cs->irq_func = &hfcs_interrupt; 262 return (1); 263} 264