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[] = { 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 = &hfc_ids[0]; 165static struct pnp_card *pnp_c = NULL; 166#endif 167 168int setup_hfcs(struct IsdnCard *card) 169{ 170 struct IsdnCardState *cs = card->cs; 171 char tmp[64]; 172 173 strcpy(tmp, hfcs_revision); 174 printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); 175 176#ifdef __ISAPNP__ 177 if (!card->para[1] && isapnp_present()) { 178 struct pnp_dev *pnp_d; 179 while (ipid->card_vendor) { 180 if ((pnp_c = pnp_find_card(ipid->card_vendor, 181 ipid->card_device, pnp_c))) { 182 pnp_d = NULL; 183 if ((pnp_d = pnp_find_dev(pnp_c, 184 ipid->vendor, ipid->function, pnp_d))) { 185 int err; 186 187 printk(KERN_INFO "HiSax: %s detected\n", 188 (char *)ipid->driver_data); 189 pnp_disable_dev(pnp_d); 190 err = pnp_activate_dev(pnp_d); 191 if (err < 0) { 192 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", 193 __func__, err); 194 return (0); 195 } 196 card->para[1] = pnp_port_start(pnp_d, 0); 197 card->para[0] = pnp_irq(pnp_d, 0); 198 if (!card->para[0] || !card->para[1]) { 199 printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", 200 card->para[0], card->para[1]); 201 pnp_disable_dev(pnp_d); 202 return (0); 203 } 204 break; 205 } else { 206 printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); 207 } 208 } 209 ipid++; 210 pnp_c = NULL; 211 } 212 if (!ipid->card_vendor) { 213 printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); 214 return (0); 215 } 216 } 217#endif 218 cs->hw.hfcD.addr = card->para[1] & 0xfffe; 219 cs->irq = card->para[0]; 220 cs->hw.hfcD.cip = 0; 221 cs->hw.hfcD.int_s1 = 0; 222 cs->hw.hfcD.send = NULL; 223 cs->bcs[0].hw.hfc.send = NULL; 224 cs->bcs[1].hw.hfc.send = NULL; 225 cs->hw.hfcD.dfifosize = 512; 226 cs->dc.hfcd.ph_state = 0; 227 cs->hw.hfcD.fifo = 255; 228 if (cs->typ == ISDN_CTYPE_TELES3C) { 229 cs->hw.hfcD.bfifosize = 1024 + 512; 230 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 231 cs->hw.hfcD.bfifosize = 7 * 1024 + 512; 232 } else 233 return (0); 234 if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { 235 printk(KERN_WARNING 236 "HiSax: %s config port %x-%x already in use\n", 237 CardType[card->typ], 238 cs->hw.hfcD.addr, 239 cs->hw.hfcD.addr + 2); 240 return (0); 241 } 242 printk(KERN_INFO 243 "HFCS: defined at 0x%x IRQ %d HZ %d\n", 244 cs->hw.hfcD.addr, 245 cs->irq, HZ); 246 if (cs->typ == ISDN_CTYPE_TELES3C) { 247 /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ 248 outb(0x00, cs->hw.hfcD.addr); 249 outb(0x56, cs->hw.hfcD.addr | 1); 250 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 251 /* Acer P10 IO ADR is 0x300 */ 252 outb(0x00, cs->hw.hfcD.addr); 253 outb(0x57, cs->hw.hfcD.addr | 1); 254 } 255 set_cs_func(cs); 256 cs->hw.hfcD.timer.function = (void *) hfcs_Timer; 257 cs->hw.hfcD.timer.data = (long) cs; 258 init_timer(&cs->hw.hfcD.timer); 259 cs->cardmsg = &hfcs_card_msg; 260 cs->irq_func = &hfcs_interrupt; 261 return (1); 262} 263